1 /*- 2 * Copyright (c) 1992, 1993 Erik Forsberg. 3 * Copyright (c) 1996, 1997 Kazutaka YOKOTA. 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 12 * THIS SOFTWARE IS PROVIDED BY ``AS IS'' AND ANY EXPRESS OR IMPLIED 13 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 14 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN 15 * NO EVENT SHALL I BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 16 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 17 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 18 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 19 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 20 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 21 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 22 */ 23 /* 24 * Ported to 386bsd Oct 17, 1992 25 * Sandi Donno, Computer Science, University of Cape Town, South Africa 26 * Please send bug reports to [email protected] 27 * 28 * Thanks are also due to Rick Macklem, [email protected] - 29 * although I was only partially successful in getting the alpha release 30 * of his "driver for the Logitech and ATI Inport Bus mice for use with 31 * 386bsd and the X386 port" to work with my Microsoft mouse, I nevertheless 32 * found his code to be an invaluable reference when porting this driver 33 * to 386bsd. 34 * 35 * Further modifications for latest 386BSD+patchkit and port to NetBSD, 36 * Andrew Herbert <[email protected]> - 8 June 1993 37 * 38 * Cloned from the Microsoft Bus Mouse driver, also by Erik Forsberg, by 39 * Andrew Herbert - 12 June 1993 40 * 41 * Modified for PS/2 mouse by Charles Hannum <[email protected]> 42 * - 13 June 1993 43 * 44 * Modified for PS/2 AUX mouse by Shoji Yuen <[email protected]> 45 * - 24 October 1993 46 * 47 * Hardware access routines and probe logic rewritten by 48 * Kazutaka Yokota <[email protected]> 49 * - 3, 14, 22 October 1996. 50 * - 12 November 1996. IOCTLs and rearranging `psmread', `psmioctl'... 51 * - 14, 30 November 1996. Uses `kbdio.c'. 52 * - 13 December 1996. Uses queuing version of `kbdio.c'. 53 * - January/February 1997. Tweaked probe logic for 54 * HiNote UltraII/Latitude/Armada laptops. 55 * - 30 July 1997. Added APM support. 56 * - 5 March 1997. Defined driver configuration flags (PSM_CONFIG_XXX). 57 * Improved sync check logic. 58 * Vendor specific support routines. 59 */ 60 61 #include <sys/cdefs.h> 62 __FBSDID("$FreeBSD$"); 63 64 #include "opt_isa.h" 65 #include "opt_psm.h" 66 #include "opt_evdev.h" 67 68 #include <sys/param.h> 69 #include <sys/systm.h> 70 #include <sys/kernel.h> 71 #include <sys/module.h> 72 #include <sys/bus.h> 73 #include <sys/conf.h> 74 #include <sys/filio.h> 75 #include <sys/poll.h> 76 #include <sys/sigio.h> 77 #include <sys/signalvar.h> 78 #include <sys/syslog.h> 79 #include <machine/bus.h> 80 #include <sys/rman.h> 81 #include <sys/selinfo.h> 82 #include <sys/sysctl.h> 83 #include <sys/time.h> 84 #include <sys/uio.h> 85 86 #include <sys/limits.h> 87 #include <sys/mouse.h> 88 #include <machine/resource.h> 89 90 #ifdef DEV_ISA 91 #include <isa/isavar.h> 92 #endif 93 94 #ifdef EVDEV_SUPPORT 95 #include <dev/evdev/evdev.h> 96 #include <dev/evdev/input.h> 97 #endif 98 99 #include <dev/atkbdc/atkbdcreg.h> 100 #include <dev/atkbdc/psm.h> 101 102 /* 103 * Driver specific options: the following options may be set by 104 * `options' statements in the kernel configuration file. 105 */ 106 107 /* debugging */ 108 #ifndef PSM_DEBUG 109 #define PSM_DEBUG 0 /* 110 * logging: 0: none, 1: brief, 2: verbose 111 * 3: sync errors, 4: all packets 112 */ 113 #endif 114 #define VLOG(level, args) do { \ 115 if (verbose >= level) \ 116 log args; \ 117 } while (0) 118 119 #ifndef PSM_INPUT_TIMEOUT 120 #define PSM_INPUT_TIMEOUT 2000000 /* 2 sec */ 121 #endif 122 123 #ifndef PSM_TAP_TIMEOUT 124 #define PSM_TAP_TIMEOUT 125000 125 #endif 126 127 #ifndef PSM_TAP_THRESHOLD 128 #define PSM_TAP_THRESHOLD 25 129 #endif 130 131 /* end of driver specific options */ 132 133 #define PSMCPNP_DRIVER_NAME "psmcpnp" 134 135 struct psmcpnp_softc { 136 enum { 137 PSMCPNP_GENERIC, 138 PSMCPNP_FORCEPAD, 139 PSMCPNP_TOPBUTTONPAD, 140 } type; /* Based on PnP ID */ 141 }; 142 143 /* input queue */ 144 #define PSM_BUFSIZE 960 145 #define PSM_SMALLBUFSIZE 240 146 147 /* operation levels */ 148 #define PSM_LEVEL_BASE 0 149 #define PSM_LEVEL_STANDARD 1 150 #define PSM_LEVEL_NATIVE 2 151 #define PSM_LEVEL_MIN PSM_LEVEL_BASE 152 #define PSM_LEVEL_MAX PSM_LEVEL_NATIVE 153 154 /* Active PS/2 multiplexing */ 155 #define PSM_NOMUX (-1) 156 157 /* Logitech PS2++ protocol */ 158 #define MOUSE_PS2PLUS_CHECKBITS(b) \ 159 ((((b[2] & 0x03) << 2) | 0x02) == (b[1] & 0x0f)) 160 #define MOUSE_PS2PLUS_PACKET_TYPE(b) \ 161 (((b[0] & 0x30) >> 2) | ((b[1] & 0x30) >> 4)) 162 163 /* ring buffer */ 164 typedef struct ringbuf { 165 int count; /* # of valid elements in the buffer */ 166 int head; /* head pointer */ 167 int tail; /* tail poiner */ 168 u_char buf[PSM_BUFSIZE]; 169 } ringbuf_t; 170 171 /* data buffer */ 172 typedef struct packetbuf { 173 u_char ipacket[16]; /* interim input buffer */ 174 int inputbytes; /* # of bytes in the input buffer */ 175 } packetbuf_t; 176 177 #ifndef PSM_PACKETQUEUE 178 #define PSM_PACKETQUEUE 128 179 #endif 180 181 /* 182 * Synaptics command definitions. 183 */ 184 #define SYNAPTICS_READ_IDENTITY 0x00 185 #define SYNAPTICS_READ_MODES 0x01 186 #define SYNAPTICS_READ_CAPABILITIES 0x02 187 #define SYNAPTICS_READ_MODEL_ID 0x03 188 #define SYNAPTICS_READ_SERIAL_PREFIX 0x06 189 #define SYNAPTICS_READ_SERIAL_SUFFIX 0x07 190 #define SYNAPTICS_READ_RESOLUTIONS 0x08 191 #define SYNAPTICS_READ_EXTENDED 0x09 192 #define SYNAPTICS_READ_CAPABILITIES_CONT 0x0c 193 #define SYNAPTICS_READ_MAX_COORDS 0x0d 194 #define SYNAPTICS_READ_DELUXE_LED 0x0e 195 #define SYNAPTICS_READ_MIN_COORDS 0x0f 196 197 typedef struct synapticsinfo { 198 struct sysctl_ctx_list sysctl_ctx; 199 struct sysctl_oid *sysctl_tree; 200 int directional_scrolls; 201 int two_finger_scroll; 202 int min_pressure; 203 int max_pressure; 204 int max_width; 205 int margin_top; 206 int margin_right; 207 int margin_bottom; 208 int margin_left; 209 int na_top; 210 int na_right; 211 int na_bottom; 212 int na_left; 213 int window_min; 214 int window_max; 215 int multiplicator; 216 int weight_current; 217 int weight_previous; 218 int weight_previous_na; 219 int weight_len_squared; 220 int div_min; 221 int div_max; 222 int div_max_na; 223 int div_len; 224 int tap_max_delta; 225 int tap_min_queue; 226 int taphold_timeout; 227 int vscroll_ver_area; 228 int vscroll_hor_area; 229 int vscroll_min_delta; 230 int vscroll_div_min; 231 int vscroll_div_max; 232 int touchpad_off; 233 int softbuttons_y; 234 int softbutton2_x; 235 int softbutton3_x; 236 int max_x; 237 int max_y; 238 int three_finger_drag; 239 int natural_scroll; 240 } synapticsinfo_t; 241 242 typedef struct synapticspacket { 243 int x; 244 int y; 245 } synapticspacket_t; 246 247 #define SYNAPTICS_PACKETQUEUE 10 248 #define SYNAPTICS_QUEUE_CURSOR(x) \ 249 (x + SYNAPTICS_PACKETQUEUE) % SYNAPTICS_PACKETQUEUE 250 251 #define SYNAPTICS_VERSION_GE(synhw, major, minor) \ 252 ((synhw).infoMajor > (major) || \ 253 ((synhw).infoMajor == (major) && (synhw).infoMinor >= (minor))) 254 255 typedef struct smoother { 256 synapticspacket_t queue[SYNAPTICS_PACKETQUEUE]; 257 int queue_len; 258 int queue_cursor; 259 int start_x; 260 int start_y; 261 int avg_dx; 262 int avg_dy; 263 int squelch_x; 264 int squelch_y; 265 int is_fuzzy; 266 int active; 267 } smoother_t; 268 269 typedef struct gesture { 270 int window_min; 271 int fingers_nb; 272 int tap_button; 273 int in_taphold; 274 int in_vscroll; 275 int zmax; /* maximum pressure value */ 276 struct timeval taptimeout; /* tap timeout for touchpads */ 277 } gesture_t; 278 279 enum { 280 TRACKPOINT_SYSCTL_SENSITIVITY, 281 TRACKPOINT_SYSCTL_NEGATIVE_INERTIA, 282 TRACKPOINT_SYSCTL_UPPER_PLATEAU, 283 TRACKPOINT_SYSCTL_BACKUP_RANGE, 284 TRACKPOINT_SYSCTL_DRAG_HYSTERESIS, 285 TRACKPOINT_SYSCTL_MINIMUM_DRAG, 286 TRACKPOINT_SYSCTL_UP_THRESHOLD, 287 TRACKPOINT_SYSCTL_THRESHOLD, 288 TRACKPOINT_SYSCTL_JENKS_CURVATURE, 289 TRACKPOINT_SYSCTL_Z_TIME, 290 TRACKPOINT_SYSCTL_PRESS_TO_SELECT, 291 TRACKPOINT_SYSCTL_SKIP_BACKUPS 292 }; 293 294 typedef struct trackpointinfo { 295 struct sysctl_ctx_list sysctl_ctx; 296 struct sysctl_oid *sysctl_tree; 297 int sensitivity; 298 int inertia; 299 int uplateau; 300 int reach; 301 int draghys; 302 int mindrag; 303 int upthresh; 304 int threshold; 305 int jenks; 306 int ztime; 307 int pts; 308 int skipback; 309 } trackpointinfo_t; 310 311 typedef struct finger { 312 int x; 313 int y; 314 int p; 315 int w; 316 int flags; 317 } finger_t; 318 #define PSM_FINGERS 2 /* # of processed fingers */ 319 #define PSM_FINGER_IS_PEN (1<<0) 320 #define PSM_FINGER_FUZZY (1<<1) 321 #define PSM_FINGER_DEFAULT_P tap_threshold 322 #define PSM_FINGER_DEFAULT_W 1 323 #define PSM_FINGER_IS_SET(f) ((f).x != -1 && (f).y != -1 && (f).p != 0) 324 #define PSM_FINGER_RESET(f) do { \ 325 (f) = (finger_t) { .x = -1, .y = -1, .p = 0, .w = 0, .flags = 0 }; \ 326 } while (0) 327 328 typedef struct elantechhw { 329 int hwversion; 330 int fwversion; 331 int sizex; 332 int sizey; 333 int dpmmx; 334 int dpmmy; 335 int ntracesx; 336 int ntracesy; 337 int dptracex; 338 int dptracey; 339 int issemimt; 340 int isclickpad; 341 int hascrc; 342 int hastrackpoint; 343 int haspressure; 344 } elantechhw_t; 345 346 /* minimum versions supported by this driver */ 347 #define ELANTECH_HW_IS_V1(fwver) ((fwver) < 0x020030 || (fwver) == 0x020600) 348 349 #define ELANTECH_MAGIC(magic) \ 350 ((magic)[0] == 0x3c && (magic)[1] == 0x03 && \ 351 ((magic)[2] == 0xc8 || (magic)[2] == 0x00)) 352 353 #define ELANTECH_FW_ID 0x00 354 #define ELANTECH_FW_VERSION 0x01 355 #define ELANTECH_CAPABILITIES 0x02 356 #define ELANTECH_SAMPLE 0x03 357 #define ELANTECH_RESOLUTION 0x04 358 #define ELANTECH_REG_READ 0x10 359 #define ELANTECH_REG_WRITE 0x11 360 #define ELANTECH_REG_RDWR 0x00 361 #define ELANTECH_CUSTOM_CMD 0xf8 362 363 #ifdef EVDEV_SUPPORT 364 #define ELANTECH_MAX_FINGERS 5 365 #else 366 #define ELANTECH_MAX_FINGERS PSM_FINGERS 367 #endif 368 369 #define ELANTECH_FINGER_MAX_P 255 370 #define ELANTECH_FINGER_MAX_W 15 371 #define ELANTECH_FINGER_SET_XYP(pb) (finger_t) { \ 372 .x = (((pb)->ipacket[1] & 0x0f) << 8) | (pb)->ipacket[2], \ 373 .y = (((pb)->ipacket[4] & 0x0f) << 8) | (pb)->ipacket[5], \ 374 .p = ((pb)->ipacket[1] & 0xf0) | (((pb)->ipacket[4] >> 4) & 0x0f), \ 375 .w = PSM_FINGER_DEFAULT_W, \ 376 .flags = 0 \ 377 } 378 379 enum { 380 ELANTECH_PKT_NOP, 381 ELANTECH_PKT_TRACKPOINT, 382 ELANTECH_PKT_V2_COMMON, 383 ELANTECH_PKT_V2_2FINGER, 384 ELANTECH_PKT_V3, 385 ELANTECH_PKT_V4_STATUS, 386 ELANTECH_PKT_V4_HEAD, 387 ELANTECH_PKT_V4_MOTION 388 }; 389 390 #define ELANTECH_PKT_IS_TRACKPOINT(pb) (((pb)->ipacket[3] & 0x0f) == 0x06) 391 #define ELANTECH_PKT_IS_DEBOUNCE(pb, hwversion) ((hwversion) == 4 ? 0 : \ 392 (pb)->ipacket[0] == ((hwversion) == 2 ? 0x84 : 0xc4) && \ 393 (pb)->ipacket[1] == 0xff && (pb)->ipacket[2] == 0xff && \ 394 (pb)->ipacket[3] == 0x02 && (pb)->ipacket[4] == 0xff && \ 395 (pb)->ipacket[5] == 0xff) 396 #define ELANTECH_PKT_IS_V2(pb) \ 397 (((pb)->ipacket[0] & 0x0c) == 0x04 && ((pb)->ipacket[3] & 0x0f) == 0x02) 398 #define ELANTECH_PKT_IS_V3_HEAD(pb, hascrc) ((hascrc) ? \ 399 ((pb)->ipacket[3] & 0x09) == 0x08 : \ 400 ((pb)->ipacket[0] & 0x0c) == 0x04 && ((pb)->ipacket[3] & 0xcf) == 0x02) 401 #define ELANTECH_PKT_IS_V3_TAIL(pb, hascrc) ((hascrc) ? \ 402 ((pb)->ipacket[3] & 0x09) == 0x09 : \ 403 ((pb)->ipacket[0] & 0x0c) == 0x0c && ((pb)->ipacket[3] & 0xce) == 0x0c) 404 #define ELANTECH_PKT_IS_V4(pb, hascrc) ((hascrc) ? \ 405 ((pb)->ipacket[3] & 0x08) == 0x00 : \ 406 ((pb)->ipacket[0] & 0x0c) == 0x04 && ((pb)->ipacket[3] & 0x1c) == 0x10) 407 408 typedef struct elantechaction { 409 finger_t fingers[ELANTECH_MAX_FINGERS]; 410 int mask; 411 int mask_v4wait; 412 } elantechaction_t; 413 414 /* driver control block */ 415 struct psm_softc { /* Driver status information */ 416 int unit; 417 struct selinfo rsel; /* Process selecting for Input */ 418 u_char state; /* Mouse driver state */ 419 int config; /* driver configuration flags */ 420 int flags; /* other flags */ 421 KBDC kbdc; /* handle to access kbd controller */ 422 struct resource *intr; /* IRQ resource */ 423 void *ih; /* interrupt handle */ 424 mousehw_t hw; /* hardware information */ 425 synapticshw_t synhw; /* Synaptics hardware information */ 426 synapticsinfo_t syninfo; /* Synaptics configuration */ 427 smoother_t smoother[PSM_FINGERS]; /* Motion smoothing */ 428 gesture_t gesture; /* Gesture context */ 429 elantechhw_t elanhw; /* Elantech hardware information */ 430 elantechaction_t elanaction; /* Elantech action context */ 431 int tphw; /* TrackPoint hardware information */ 432 trackpointinfo_t tpinfo; /* TrackPoint configuration */ 433 mousemode_t mode; /* operation mode */ 434 mousemode_t dflt_mode; /* default operation mode */ 435 mousestatus_t status; /* accumulated mouse movement */ 436 ringbuf_t queue; /* mouse status queue */ 437 packetbuf_t pqueue[PSM_PACKETQUEUE]; /* mouse data queue */ 438 int pqueue_start; /* start of data in queue */ 439 int pqueue_end; /* end of data in queue */ 440 int button; /* the latest button state */ 441 int xold; /* previous absolute X position */ 442 int yold; /* previous absolute Y position */ 443 int xaverage; /* average X position */ 444 int yaverage; /* average Y position */ 445 int squelch; /* level to filter movement at low speed */ 446 int syncerrors; /* # of bytes discarded to synchronize */ 447 int pkterrors; /* # of packets failed during quaranteen. */ 448 int fpcount; /* forcePad valid packet counter */ 449 struct timeval inputtimeout; 450 struct timeval lastsoftintr; /* time of last soft interrupt */ 451 struct timeval lastinputerr; /* time last sync error happened */ 452 struct timeval idletimeout; 453 packetbuf_t idlepacket; /* packet to send after idle timeout */ 454 int watchdog; /* watchdog timer flag */ 455 struct callout callout; /* watchdog timer call out */ 456 struct callout softcallout; /* buffer timer call out */ 457 struct cdev *dev; 458 struct cdev *bdev; 459 int lasterr; 460 int cmdcount; 461 struct sigio *async; /* Processes waiting for SIGIO */ 462 int extended_buttons; 463 int muxport; /* MUX port with attached Synaptics */ 464 u_char muxsave[3]; /* 3->6 byte proto conversion buffer */ 465 int muxtpbuttons; /* Touchpad button state */ 466 int muxmsbuttons; /* Mouse (trackpoint) button state */ 467 struct timeval muxmidtimeout; /* middle button supression timeout */ 468 #ifdef EVDEV_SUPPORT 469 struct evdev_dev *evdev_a; /* Absolute reporting device */ 470 struct evdev_dev *evdev_r; /* Relative reporting device */ 471 #endif 472 }; 473 static devclass_t psm_devclass; 474 475 /* driver state flags (state) */ 476 #define PSM_VALID 0x80 477 #define PSM_OPEN 1 /* Device is open */ 478 #define PSM_ASLP 2 /* Waiting for mouse data */ 479 #define PSM_SOFTARMED 4 /* Software interrupt armed */ 480 #define PSM_NEED_SYNCBITS 8 /* Set syncbits using next data pkt */ 481 #define PSM_EV_OPEN_R 0x10 /* Relative evdev device is open */ 482 #define PSM_EV_OPEN_A 0x20 /* Absolute evdev device is open */ 483 484 /* driver configuration flags (config) */ 485 #define PSM_CONFIG_RESOLUTION 0x000f /* resolution */ 486 #define PSM_CONFIG_ACCEL 0x00f0 /* acceleration factor */ 487 #define PSM_CONFIG_NOCHECKSYNC 0x0100 /* disable sync. test */ 488 #define PSM_CONFIG_NOIDPROBE 0x0200 /* disable mouse model probe */ 489 #define PSM_CONFIG_NORESET 0x0400 /* don't reset the mouse */ 490 #define PSM_CONFIG_FORCETAP 0x0800 /* assume `tap' action exists */ 491 #define PSM_CONFIG_IGNPORTERROR 0x1000 /* ignore error in aux port test */ 492 #define PSM_CONFIG_HOOKRESUME 0x2000 /* hook the system resume event */ 493 #define PSM_CONFIG_INITAFTERSUSPEND 0x4000 /* init the device at the resume event */ 494 495 #define PSM_CONFIG_FLAGS \ 496 (PSM_CONFIG_RESOLUTION | \ 497 PSM_CONFIG_ACCEL | \ 498 PSM_CONFIG_NOCHECKSYNC | \ 499 PSM_CONFIG_NOIDPROBE | \ 500 PSM_CONFIG_NORESET | \ 501 PSM_CONFIG_FORCETAP | \ 502 PSM_CONFIG_IGNPORTERROR | \ 503 PSM_CONFIG_HOOKRESUME | \ 504 PSM_CONFIG_INITAFTERSUSPEND) 505 506 /* other flags (flags) */ 507 #define PSM_FLAGS_FINGERDOWN 0x0001 /* VersaPad finger down */ 508 509 #define kbdcp(p) ((atkbdc_softc_t *)(p)) 510 #define ALWAYS_RESTORE_CONTROLLER(kbdc) !(kbdcp(kbdc)->quirks \ 511 & KBDC_QUIRK_KEEP_ACTIVATED) 512 513 /* Tunables */ 514 static int tap_enabled = -1; 515 static int verbose = PSM_DEBUG; 516 static int synaptics_support = 0; 517 static int trackpoint_support = 0; 518 static int elantech_support = 0; 519 520 /* for backward compatibility */ 521 #define OLD_MOUSE_GETHWINFO _IOR('M', 1, old_mousehw_t) 522 #define OLD_MOUSE_GETMODE _IOR('M', 2, old_mousemode_t) 523 #define OLD_MOUSE_SETMODE _IOW('M', 3, old_mousemode_t) 524 525 typedef struct old_mousehw { 526 int buttons; 527 int iftype; 528 int type; 529 int hwid; 530 } old_mousehw_t; 531 532 typedef struct old_mousemode { 533 int protocol; 534 int rate; 535 int resolution; 536 int accelfactor; 537 } old_mousemode_t; 538 539 #define SYN_OFFSET(field) offsetof(struct psm_softc, syninfo.field) 540 enum { 541 SYNAPTICS_SYSCTL_MIN_PRESSURE = SYN_OFFSET(min_pressure), 542 SYNAPTICS_SYSCTL_MAX_PRESSURE = SYN_OFFSET(max_pressure), 543 SYNAPTICS_SYSCTL_MAX_WIDTH = SYN_OFFSET(max_width), 544 SYNAPTICS_SYSCTL_MARGIN_TOP = SYN_OFFSET(margin_top), 545 SYNAPTICS_SYSCTL_MARGIN_RIGHT = SYN_OFFSET(margin_right), 546 SYNAPTICS_SYSCTL_MARGIN_BOTTOM = SYN_OFFSET(margin_bottom), 547 SYNAPTICS_SYSCTL_MARGIN_LEFT = SYN_OFFSET(margin_left), 548 SYNAPTICS_SYSCTL_NA_TOP = SYN_OFFSET(na_top), 549 SYNAPTICS_SYSCTL_NA_RIGHT = SYN_OFFSET(na_right), 550 SYNAPTICS_SYSCTL_NA_BOTTOM = SYN_OFFSET(na_bottom), 551 SYNAPTICS_SYSCTL_NA_LEFT = SYN_OFFSET(na_left), 552 SYNAPTICS_SYSCTL_WINDOW_MIN = SYN_OFFSET(window_min), 553 SYNAPTICS_SYSCTL_WINDOW_MAX = SYN_OFFSET(window_max), 554 SYNAPTICS_SYSCTL_MULTIPLICATOR = SYN_OFFSET(multiplicator), 555 SYNAPTICS_SYSCTL_WEIGHT_CURRENT = SYN_OFFSET(weight_current), 556 SYNAPTICS_SYSCTL_WEIGHT_PREVIOUS = SYN_OFFSET(weight_previous), 557 SYNAPTICS_SYSCTL_WEIGHT_PREVIOUS_NA = SYN_OFFSET(weight_previous_na), 558 SYNAPTICS_SYSCTL_WEIGHT_LEN_SQUARED = SYN_OFFSET(weight_len_squared), 559 SYNAPTICS_SYSCTL_DIV_MIN = SYN_OFFSET(div_min), 560 SYNAPTICS_SYSCTL_DIV_MAX = SYN_OFFSET(div_max), 561 SYNAPTICS_SYSCTL_DIV_MAX_NA = SYN_OFFSET(div_max_na), 562 SYNAPTICS_SYSCTL_DIV_LEN = SYN_OFFSET(div_len), 563 SYNAPTICS_SYSCTL_TAP_MAX_DELTA = SYN_OFFSET(tap_max_delta), 564 SYNAPTICS_SYSCTL_TAP_MIN_QUEUE = SYN_OFFSET(tap_min_queue), 565 SYNAPTICS_SYSCTL_TAPHOLD_TIMEOUT = SYN_OFFSET(taphold_timeout), 566 SYNAPTICS_SYSCTL_VSCROLL_HOR_AREA = SYN_OFFSET(vscroll_hor_area), 567 SYNAPTICS_SYSCTL_VSCROLL_VER_AREA = SYN_OFFSET(vscroll_ver_area), 568 SYNAPTICS_SYSCTL_VSCROLL_MIN_DELTA = SYN_OFFSET(vscroll_min_delta), 569 SYNAPTICS_SYSCTL_VSCROLL_DIV_MIN = SYN_OFFSET(vscroll_div_min), 570 SYNAPTICS_SYSCTL_VSCROLL_DIV_MAX = SYN_OFFSET(vscroll_div_max), 571 SYNAPTICS_SYSCTL_TOUCHPAD_OFF = SYN_OFFSET(touchpad_off), 572 SYNAPTICS_SYSCTL_SOFTBUTTONS_Y = SYN_OFFSET(softbuttons_y), 573 SYNAPTICS_SYSCTL_SOFTBUTTON2_X = SYN_OFFSET(softbutton2_x), 574 SYNAPTICS_SYSCTL_SOFTBUTTON3_X = SYN_OFFSET(softbutton3_x), 575 SYNAPTICS_SYSCTL_THREE_FINGER_DRAG = SYN_OFFSET(three_finger_drag), 576 SYNAPTICS_SYSCTL_NATURAL_SCROLL = SYN_OFFSET(natural_scroll), 577 #define SYNAPTICS_SYSCTL_LAST SYNAPTICS_SYSCTL_NATURAL_SCROLL 578 }; 579 580 /* packet formatting function */ 581 typedef int packetfunc_t(struct psm_softc *, u_char *, int *, int, 582 mousestatus_t *); 583 584 /* function prototypes */ 585 static void psmidentify(driver_t *, device_t); 586 static int psmprobe(device_t); 587 static int psmattach(device_t); 588 static int psmdetach(device_t); 589 static int psmresume(device_t); 590 591 static d_open_t psm_cdev_open; 592 static d_close_t psm_cdev_close; 593 static d_read_t psmread; 594 static d_write_t psmwrite; 595 static d_ioctl_t psmioctl; 596 static d_poll_t psmpoll; 597 598 static int psmopen(struct psm_softc *); 599 static int psmclose(struct psm_softc *); 600 601 #ifdef EVDEV_SUPPORT 602 static evdev_open_t psm_ev_open_r; 603 static evdev_close_t psm_ev_close_r; 604 static evdev_open_t psm_ev_open_a; 605 static evdev_close_t psm_ev_close_a; 606 #endif 607 608 static int enable_aux_dev(KBDC); 609 static int disable_aux_dev(KBDC); 610 static int get_mouse_status(KBDC, int *, int, int); 611 static int get_aux_id(KBDC); 612 static int set_mouse_sampling_rate(KBDC, int); 613 static int set_mouse_scaling(KBDC, int); 614 static int set_mouse_resolution(KBDC, int); 615 static int set_mouse_mode(KBDC); 616 static int get_mouse_buttons(KBDC); 617 static int is_a_mouse(int); 618 static void recover_from_error(KBDC); 619 static int restore_controller(KBDC, int); 620 static int doinitialize(struct psm_softc *, mousemode_t *); 621 static int doopen(struct psm_softc *, int); 622 static int reinitialize(struct psm_softc *, int); 623 static char *model_name(int); 624 static void psmsoftintr(void *); 625 static void psmsoftintridle(void *); 626 static void psmintr(void *); 627 static void psmtimeout(void *); 628 static int timeelapsed(const struct timeval *, int, int, 629 const struct timeval *); 630 static void dropqueue(struct psm_softc *); 631 static void flushpackets(struct psm_softc *); 632 static void proc_mmanplus(struct psm_softc *, packetbuf_t *, 633 mousestatus_t *, int *, int *, int *); 634 static int proc_synaptics(struct psm_softc *, packetbuf_t *, 635 mousestatus_t *, int *, int *, int *); 636 static int proc_synaptics_mux(struct psm_softc *, packetbuf_t *); 637 static void proc_versapad(struct psm_softc *, packetbuf_t *, 638 mousestatus_t *, int *, int *, int *); 639 static int proc_elantech(struct psm_softc *, packetbuf_t *, 640 mousestatus_t *, int *, int *, int *); 641 static int psmpalmdetect(struct psm_softc *, finger_t *, int); 642 static void psmgestures(struct psm_softc *, finger_t *, int, 643 mousestatus_t *); 644 static void psmsmoother(struct psm_softc *, finger_t *, int, 645 mousestatus_t *, int *, int *); 646 static int tame_mouse(struct psm_softc *, packetbuf_t *, mousestatus_t *, 647 u_char *); 648 649 /* vendor specific features */ 650 enum probearg { PROBE, REINIT }; 651 typedef int probefunc_t(struct psm_softc *, enum probearg); 652 653 static int mouse_id_proc1(KBDC, int, int, int *); 654 static int mouse_ext_command(KBDC, int); 655 656 static probefunc_t enable_groller; 657 static probefunc_t enable_gmouse; 658 static probefunc_t enable_aglide; 659 static probefunc_t enable_kmouse; 660 static probefunc_t enable_msexplorer; 661 static probefunc_t enable_msintelli; 662 static probefunc_t enable_4dmouse; 663 static probefunc_t enable_4dplus; 664 static probefunc_t enable_mmanplus; 665 static probefunc_t enable_synaptics; 666 static probefunc_t enable_synaptics_mux; 667 static probefunc_t enable_trackpoint; 668 static probefunc_t enable_versapad; 669 static probefunc_t enable_elantech; 670 671 static void set_trackpoint_parameters(struct psm_softc *sc); 672 static void synaptics_passthrough_on(struct psm_softc *sc); 673 static void synaptics_passthrough_off(struct psm_softc *sc); 674 static int synaptics_preferred_mode(struct psm_softc *sc); 675 static void synaptics_set_mode(struct psm_softc *sc, int mode_byte); 676 677 static struct { 678 int model; 679 u_char syncmask; 680 int packetsize; 681 probefunc_t *probefunc; 682 } vendortype[] = { 683 /* 684 * WARNING: the order of probe is very important. Don't mess it 685 * unless you know what you are doing. 686 */ 687 { MOUSE_MODEL_SYNAPTICS, /* Synaptics Touchpad on Active Mux */ 688 0x00, MOUSE_PS2_PACKETSIZE, enable_synaptics_mux }, 689 { MOUSE_MODEL_NET, /* Genius NetMouse */ 690 0x08, MOUSE_PS2INTELLI_PACKETSIZE, enable_gmouse }, 691 { MOUSE_MODEL_NETSCROLL, /* Genius NetScroll */ 692 0xc8, 6, enable_groller }, 693 { MOUSE_MODEL_MOUSEMANPLUS, /* Logitech MouseMan+ */ 694 0x08, MOUSE_PS2_PACKETSIZE, enable_mmanplus }, 695 { MOUSE_MODEL_EXPLORER, /* Microsoft IntelliMouse Explorer */ 696 0x08, MOUSE_PS2INTELLI_PACKETSIZE, enable_msexplorer }, 697 { MOUSE_MODEL_4D, /* A4 Tech 4D Mouse */ 698 0x08, MOUSE_4D_PACKETSIZE, enable_4dmouse }, 699 { MOUSE_MODEL_4DPLUS, /* A4 Tech 4D+ Mouse */ 700 0xc8, MOUSE_4DPLUS_PACKETSIZE, enable_4dplus }, 701 { MOUSE_MODEL_SYNAPTICS, /* Synaptics Touchpad */ 702 0xc0, MOUSE_SYNAPTICS_PACKETSIZE, enable_synaptics }, 703 { MOUSE_MODEL_ELANTECH, /* Elantech Touchpad */ 704 0x04, MOUSE_ELANTECH_PACKETSIZE, enable_elantech }, 705 { MOUSE_MODEL_INTELLI, /* Microsoft IntelliMouse */ 706 0x08, MOUSE_PS2INTELLI_PACKETSIZE, enable_msintelli }, 707 { MOUSE_MODEL_GLIDEPOINT, /* ALPS GlidePoint */ 708 0xc0, MOUSE_PS2_PACKETSIZE, enable_aglide }, 709 { MOUSE_MODEL_THINK, /* Kensington ThinkingMouse */ 710 0x80, MOUSE_PS2_PACKETSIZE, enable_kmouse }, 711 { MOUSE_MODEL_VERSAPAD, /* Interlink electronics VersaPad */ 712 0xe8, MOUSE_PS2VERSA_PACKETSIZE, enable_versapad }, 713 { MOUSE_MODEL_TRACKPOINT, /* IBM/Lenovo TrackPoint */ 714 0xc0, MOUSE_PS2_PACKETSIZE, enable_trackpoint }, 715 { MOUSE_MODEL_GENERIC, 716 0xc0, MOUSE_PS2_PACKETSIZE, NULL }, 717 }; 718 #define GENERIC_MOUSE_ENTRY (nitems(vendortype) - 1) 719 720 /* device driver declarateion */ 721 static device_method_t psm_methods[] = { 722 /* Device interface */ 723 DEVMETHOD(device_identify, psmidentify), 724 DEVMETHOD(device_probe, psmprobe), 725 DEVMETHOD(device_attach, psmattach), 726 DEVMETHOD(device_detach, psmdetach), 727 DEVMETHOD(device_resume, psmresume), 728 729 { 0, 0 } 730 }; 731 732 static driver_t psm_driver = { 733 PSM_DRIVER_NAME, 734 psm_methods, 735 sizeof(struct psm_softc), 736 }; 737 738 static struct cdevsw psm_cdevsw = { 739 .d_version = D_VERSION, 740 .d_flags = D_NEEDGIANT, 741 .d_open = psm_cdev_open, 742 .d_close = psm_cdev_close, 743 .d_read = psmread, 744 .d_write = psmwrite, 745 .d_ioctl = psmioctl, 746 .d_poll = psmpoll, 747 .d_name = PSM_DRIVER_NAME, 748 }; 749 750 #ifdef EVDEV_SUPPORT 751 static const struct evdev_methods psm_ev_methods_r = { 752 .ev_open = psm_ev_open_r, 753 .ev_close = psm_ev_close_r, 754 }; 755 static const struct evdev_methods psm_ev_methods_a = { 756 .ev_open = psm_ev_open_a, 757 .ev_close = psm_ev_close_a, 758 }; 759 #endif 760 761 /* device I/O routines */ 762 static int 763 enable_aux_dev(KBDC kbdc) 764 { 765 int res; 766 767 res = send_aux_command(kbdc, PSMC_ENABLE_DEV); 768 VLOG(2, (LOG_DEBUG, "psm: ENABLE_DEV return code:%04x\n", res)); 769 770 return (res == PSM_ACK); 771 } 772 773 static int 774 disable_aux_dev(KBDC kbdc) 775 { 776 int res; 777 778 res = send_aux_command(kbdc, PSMC_DISABLE_DEV); 779 VLOG(2, (LOG_DEBUG, "psm: DISABLE_DEV return code:%04x\n", res)); 780 781 return (res == PSM_ACK); 782 } 783 784 static int 785 get_mouse_status(KBDC kbdc, int *status, int flag, int len) 786 { 787 int cmd; 788 int res; 789 int i; 790 791 switch (flag) { 792 case 0: 793 default: 794 cmd = PSMC_SEND_DEV_STATUS; 795 break; 796 case 1: 797 cmd = PSMC_SEND_DEV_DATA; 798 break; 799 } 800 empty_aux_buffer(kbdc, 5); 801 res = send_aux_command(kbdc, cmd); 802 VLOG(2, (LOG_DEBUG, "psm: SEND_AUX_DEV_%s return code:%04x\n", 803 (flag == 1) ? "DATA" : "STATUS", res)); 804 if (res != PSM_ACK) 805 return (0); 806 807 for (i = 0; i < len; ++i) { 808 status[i] = read_aux_data(kbdc); 809 if (status[i] < 0) 810 break; 811 } 812 if (len >= 3) { 813 for (; i < 3; ++i) 814 status[i] = 0; 815 VLOG(1, (LOG_DEBUG, "psm: %s %02x %02x %02x\n", 816 (flag == 1) ? "data" : "status", status[0], status[1], status[2])); 817 } 818 819 return (i); 820 } 821 822 static int 823 get_aux_id(KBDC kbdc) 824 { 825 int res; 826 int id; 827 828 empty_aux_buffer(kbdc, 5); 829 res = send_aux_command(kbdc, PSMC_SEND_DEV_ID); 830 VLOG(2, (LOG_DEBUG, "psm: SEND_DEV_ID return code:%04x\n", res)); 831 if (res != PSM_ACK) 832 return (-1); 833 834 /* 10ms delay */ 835 DELAY(10000); 836 837 id = read_aux_data(kbdc); 838 VLOG(2, (LOG_DEBUG, "psm: device ID: %04x\n", id)); 839 840 return (id); 841 } 842 843 static int 844 set_mouse_sampling_rate(KBDC kbdc, int rate) 845 { 846 int res; 847 848 res = send_aux_command_and_data(kbdc, PSMC_SET_SAMPLING_RATE, rate); 849 VLOG(2, (LOG_DEBUG, "psm: SET_SAMPLING_RATE (%d) %04x\n", rate, res)); 850 851 return ((res == PSM_ACK) ? rate : -1); 852 } 853 854 static int 855 set_mouse_scaling(KBDC kbdc, int scale) 856 { 857 int res; 858 859 switch (scale) { 860 case 1: 861 default: 862 scale = PSMC_SET_SCALING11; 863 break; 864 case 2: 865 scale = PSMC_SET_SCALING21; 866 break; 867 } 868 res = send_aux_command(kbdc, scale); 869 VLOG(2, (LOG_DEBUG, "psm: SET_SCALING%s return code:%04x\n", 870 (scale == PSMC_SET_SCALING21) ? "21" : "11", res)); 871 872 return (res == PSM_ACK); 873 } 874 875 /* `val' must be 0 through PSMD_MAX_RESOLUTION */ 876 static int 877 set_mouse_resolution(KBDC kbdc, int val) 878 { 879 int res; 880 881 res = send_aux_command_and_data(kbdc, PSMC_SET_RESOLUTION, val); 882 VLOG(2, (LOG_DEBUG, "psm: SET_RESOLUTION (%d) %04x\n", val, res)); 883 884 return ((res == PSM_ACK) ? val : -1); 885 } 886 887 /* 888 * NOTE: once `set_mouse_mode()' is called, the mouse device must be 889 * re-enabled by calling `enable_aux_dev()' 890 */ 891 static int 892 set_mouse_mode(KBDC kbdc) 893 { 894 int res; 895 896 res = send_aux_command(kbdc, PSMC_SET_STREAM_MODE); 897 VLOG(2, (LOG_DEBUG, "psm: SET_STREAM_MODE return code:%04x\n", res)); 898 899 return (res == PSM_ACK); 900 } 901 902 static int 903 get_mouse_buttons(KBDC kbdc) 904 { 905 int c = 2; /* assume two buttons by default */ 906 int status[3]; 907 908 /* 909 * NOTE: a special sequence to obtain Logitech Mouse specific 910 * information: set resolution to 25 ppi, set scaling to 1:1, set 911 * scaling to 1:1, set scaling to 1:1. Then the second byte of the 912 * mouse status bytes is the number of available buttons. 913 * Some manufactures also support this sequence. 914 */ 915 if (set_mouse_resolution(kbdc, PSMD_RES_LOW) != PSMD_RES_LOW) 916 return (c); 917 if (set_mouse_scaling(kbdc, 1) && set_mouse_scaling(kbdc, 1) && 918 set_mouse_scaling(kbdc, 1) && 919 get_mouse_status(kbdc, status, 0, 3) >= 3 && status[1] != 0) 920 return (status[1]); 921 return (c); 922 } 923 924 /* misc subroutines */ 925 /* 926 * Someday, I will get the complete list of valid pointing devices and 927 * their IDs... XXX 928 */ 929 static int 930 is_a_mouse(int id) 931 { 932 #if 0 933 static int valid_ids[] = { 934 PSM_MOUSE_ID, /* mouse */ 935 PSM_BALLPOINT_ID, /* ballpoint device */ 936 PSM_INTELLI_ID, /* Intellimouse */ 937 PSM_EXPLORER_ID, /* Intellimouse Explorer */ 938 -1 /* end of table */ 939 }; 940 int i; 941 942 for (i = 0; valid_ids[i] >= 0; ++i) 943 if (valid_ids[i] == id) 944 return (TRUE); 945 return (FALSE); 946 #else 947 return (TRUE); 948 #endif 949 } 950 951 static char * 952 model_name(int model) 953 { 954 static struct { 955 int model_code; 956 char *model_name; 957 } models[] = { 958 { MOUSE_MODEL_NETSCROLL, "NetScroll" }, 959 { MOUSE_MODEL_NET, "NetMouse/NetScroll Optical" }, 960 { MOUSE_MODEL_GLIDEPOINT, "GlidePoint" }, 961 { MOUSE_MODEL_THINK, "ThinkingMouse" }, 962 { MOUSE_MODEL_INTELLI, "IntelliMouse" }, 963 { MOUSE_MODEL_MOUSEMANPLUS, "MouseMan+" }, 964 { MOUSE_MODEL_VERSAPAD, "VersaPad" }, 965 { MOUSE_MODEL_EXPLORER, "IntelliMouse Explorer" }, 966 { MOUSE_MODEL_4D, "4D Mouse" }, 967 { MOUSE_MODEL_4DPLUS, "4D+ Mouse" }, 968 { MOUSE_MODEL_SYNAPTICS, "Synaptics Touchpad" }, 969 { MOUSE_MODEL_TRACKPOINT, "IBM/Lenovo TrackPoint" }, 970 { MOUSE_MODEL_ELANTECH, "Elantech Touchpad" }, 971 { MOUSE_MODEL_GENERIC, "Generic PS/2 mouse" }, 972 { MOUSE_MODEL_UNKNOWN, "Unknown" }, 973 }; 974 int i; 975 976 for (i = 0; models[i].model_code != MOUSE_MODEL_UNKNOWN; ++i) 977 if (models[i].model_code == model) 978 break; 979 return (models[i].model_name); 980 } 981 982 static void 983 recover_from_error(KBDC kbdc) 984 { 985 /* discard anything left in the output buffer */ 986 empty_both_buffers(kbdc, 10); 987 988 #if 0 989 /* 990 * NOTE: KBDC_RESET_KBD may not restore the communication between the 991 * keyboard and the controller. 992 */ 993 reset_kbd(kbdc); 994 #else 995 /* 996 * NOTE: somehow diagnostic and keyboard port test commands bring the 997 * keyboard back. 998 */ 999 if (!test_controller(kbdc)) 1000 log(LOG_ERR, "psm: keyboard controller failed.\n"); 1001 /* if there isn't a keyboard in the system, the following error is OK */ 1002 if (test_kbd_port(kbdc) != 0) 1003 VLOG(1, (LOG_ERR, "psm: keyboard port failed.\n")); 1004 #endif 1005 } 1006 1007 static int 1008 restore_controller(KBDC kbdc, int command_byte) 1009 { 1010 empty_both_buffers(kbdc, 10); 1011 1012 if (!set_controller_command_byte(kbdc, 0xff, command_byte)) { 1013 log(LOG_ERR, "psm: failed to restore the keyboard controller " 1014 "command byte.\n"); 1015 empty_both_buffers(kbdc, 10); 1016 return (FALSE); 1017 } else { 1018 empty_both_buffers(kbdc, 10); 1019 return (TRUE); 1020 } 1021 } 1022 1023 /* 1024 * Re-initialize the aux port and device. The aux port must be enabled 1025 * and its interrupt must be disabled before calling this routine. 1026 * The aux device will be disabled before returning. 1027 * The keyboard controller must be locked via `kbdc_lock()' before 1028 * calling this routine. 1029 */ 1030 static int 1031 doinitialize(struct psm_softc *sc, mousemode_t *mode) 1032 { 1033 KBDC kbdc = sc->kbdc; 1034 int stat[3]; 1035 int i; 1036 1037 switch((i = test_aux_port(kbdc))) { 1038 case 1: /* ignore these errors */ 1039 case 2: 1040 case 3: 1041 case PSM_ACK: 1042 if (verbose) 1043 log(LOG_DEBUG, 1044 "psm%d: strange result for test aux port (%d).\n", 1045 sc->unit, i); 1046 /* FALLTHROUGH */ 1047 case 0: /* no error */ 1048 break; 1049 case -1: /* time out */ 1050 default: /* error */ 1051 recover_from_error(kbdc); 1052 if (sc->config & PSM_CONFIG_IGNPORTERROR) 1053 break; 1054 log(LOG_ERR, "psm%d: the aux port is not functioning (%d).\n", 1055 sc->unit, i); 1056 return (FALSE); 1057 } 1058 1059 if (sc->config & PSM_CONFIG_NORESET) { 1060 /* 1061 * Don't try to reset the pointing device. It may possibly 1062 * be left in the unknown state, though... 1063 */ 1064 } else { 1065 /* 1066 * NOTE: some controllers appears to hang the `keyboard' when 1067 * the aux port doesn't exist and `PSMC_RESET_DEV' is issued. 1068 */ 1069 if (!reset_aux_dev(kbdc)) { 1070 recover_from_error(kbdc); 1071 log(LOG_ERR, "psm%d: failed to reset the aux device.\n", 1072 sc->unit); 1073 return (FALSE); 1074 } 1075 } 1076 1077 /* 1078 * both the aux port and the aux device is functioning, see 1079 * if the device can be enabled. 1080 */ 1081 if (!enable_aux_dev(kbdc) || !disable_aux_dev(kbdc)) { 1082 log(LOG_ERR, "psm%d: failed to enable the aux device.\n", 1083 sc->unit); 1084 return (FALSE); 1085 } 1086 empty_both_buffers(kbdc, 10); /* remove stray data if any */ 1087 1088 /* Re-enable the mouse. */ 1089 for (i = 0; vendortype[i].probefunc != NULL; ++i) 1090 if (vendortype[i].model == sc->hw.model) 1091 (*vendortype[i].probefunc)(sc, REINIT); 1092 1093 /* set mouse parameters */ 1094 if (mode != (mousemode_t *)NULL) { 1095 if (mode->rate > 0) 1096 mode->rate = set_mouse_sampling_rate(kbdc, mode->rate); 1097 if (mode->resolution >= 0) 1098 mode->resolution = 1099 set_mouse_resolution(kbdc, mode->resolution); 1100 set_mouse_scaling(kbdc, 1); 1101 set_mouse_mode(kbdc); 1102 } 1103 1104 /* Record sync on the next data packet we see. */ 1105 sc->flags |= PSM_NEED_SYNCBITS; 1106 1107 /* just check the status of the mouse */ 1108 if (get_mouse_status(kbdc, stat, 0, 3) < 3) 1109 log(LOG_DEBUG, "psm%d: failed to get status (doinitialize).\n", 1110 sc->unit); 1111 1112 return (TRUE); 1113 } 1114 1115 static int 1116 doopen(struct psm_softc *sc, int command_byte) 1117 { 1118 int stat[3]; 1119 int mux_enabled = FALSE; 1120 1121 /* 1122 * FIXME: Synaptics TouchPad seems to go back to Relative Mode with 1123 * no obvious reason. Thus we check the current mode and restore the 1124 * Absolute Mode if it was cleared. 1125 * 1126 * The previous hack at the end of psmprobe() wasn't efficient when 1127 * moused(8) was restarted. 1128 * 1129 * A Reset (FF) or Set Defaults (F6) command would clear the 1130 * Absolute Mode bit. But a verbose boot or debug.psm.loglevel=5 1131 * doesn't show any evidence of such a command. 1132 */ 1133 if (sc->hw.model == MOUSE_MODEL_SYNAPTICS) { 1134 if (sc->muxport != PSM_NOMUX) { 1135 mux_enabled = enable_aux_mux(sc->kbdc) >= 0; 1136 if (mux_enabled) 1137 set_active_aux_mux_port(sc->kbdc, sc->muxport); 1138 else 1139 log(LOG_ERR, "psm%d: failed to enable " 1140 "active multiplexing mode.\n", 1141 sc->unit); 1142 } 1143 mouse_ext_command(sc->kbdc, SYNAPTICS_READ_MODES); 1144 get_mouse_status(sc->kbdc, stat, 0, 3); 1145 if ((SYNAPTICS_VERSION_GE(sc->synhw, 7, 5) || 1146 stat[1] == 0x47) && 1147 stat[2] == 0x40) { 1148 synaptics_set_mode(sc, synaptics_preferred_mode(sc)); 1149 VLOG(5, (LOG_DEBUG, "psm%d: Synaptis Absolute Mode " 1150 "hopefully restored\n", 1151 sc->unit)); 1152 } 1153 if (mux_enabled) 1154 disable_aux_mux(sc->kbdc); 1155 } 1156 1157 /* 1158 * A user may want to disable tap and drag gestures on a Synaptics 1159 * TouchPad when it operates in Relative Mode. 1160 */ 1161 if (sc->hw.model == MOUSE_MODEL_GENERIC) { 1162 if (tap_enabled > 0) { 1163 VLOG(2, (LOG_DEBUG, 1164 "psm%d: enable tap and drag gestures\n", 1165 sc->unit)); 1166 synaptics_set_mode(sc, synaptics_preferred_mode(sc)); 1167 } else if (tap_enabled == 0) { 1168 VLOG(2, (LOG_DEBUG, 1169 "psm%d: disable tap and drag gestures\n", 1170 sc->unit)); 1171 synaptics_set_mode(sc, synaptics_preferred_mode(sc)); 1172 } 1173 } 1174 1175 /* enable the mouse device */ 1176 if (!enable_aux_dev(sc->kbdc)) { 1177 /* MOUSE ERROR: failed to enable the mouse because: 1178 * 1) the mouse is faulty, 1179 * 2) the mouse has been removed(!?) 1180 * In the latter case, the keyboard may have hung, and need 1181 * recovery procedure... 1182 */ 1183 recover_from_error(sc->kbdc); 1184 #if 0 1185 /* FIXME: we could reset the mouse here and try to enable 1186 * it again. But it will take long time and it's not a good 1187 * idea to disable the keyboard that long... 1188 */ 1189 if (!doinitialize(sc, &sc->mode) || !enable_aux_dev(sc->kbdc)) { 1190 recover_from_error(sc->kbdc); 1191 #else 1192 { 1193 #endif 1194 restore_controller(sc->kbdc, command_byte); 1195 /* mark this device is no longer available */ 1196 sc->state &= ~PSM_VALID; 1197 log(LOG_ERR, 1198 "psm%d: failed to enable the device (doopen).\n", 1199 sc->unit); 1200 return (EIO); 1201 } 1202 } 1203 1204 if (get_mouse_status(sc->kbdc, stat, 0, 3) < 3) 1205 log(LOG_DEBUG, "psm%d: failed to get status (doopen).\n", 1206 sc->unit); 1207 1208 /* enable the aux port and interrupt */ 1209 if (!set_controller_command_byte(sc->kbdc, 1210 kbdc_get_device_mask(sc->kbdc), 1211 (command_byte & KBD_KBD_CONTROL_BITS) | 1212 KBD_ENABLE_AUX_PORT | KBD_ENABLE_AUX_INT)) { 1213 /* CONTROLLER ERROR */ 1214 disable_aux_dev(sc->kbdc); 1215 restore_controller(sc->kbdc, command_byte); 1216 log(LOG_ERR, 1217 "psm%d: failed to enable the aux interrupt (doopen).\n", 1218 sc->unit); 1219 return (EIO); 1220 } 1221 1222 /* start the watchdog timer */ 1223 sc->watchdog = FALSE; 1224 callout_reset(&sc->callout, hz * 2, psmtimeout, sc); 1225 1226 return (0); 1227 } 1228 1229 static int 1230 reinitialize(struct psm_softc *sc, int doinit) 1231 { 1232 int err; 1233 int c; 1234 int s; 1235 1236 /* don't let anybody mess with the aux device */ 1237 if (!kbdc_lock(sc->kbdc, TRUE)) 1238 return (EIO); 1239 s = spltty(); 1240 1241 /* block our watchdog timer */ 1242 sc->watchdog = FALSE; 1243 callout_stop(&sc->callout); 1244 1245 /* save the current controller command byte */ 1246 empty_both_buffers(sc->kbdc, 10); 1247 c = get_controller_command_byte(sc->kbdc); 1248 VLOG(2, (LOG_DEBUG, 1249 "psm%d: current command byte: %04x (reinitialize).\n", 1250 sc->unit, c)); 1251 1252 /* enable the aux port but disable the aux interrupt and the keyboard */ 1253 if ((c == -1) || !set_controller_command_byte(sc->kbdc, 1254 kbdc_get_device_mask(sc->kbdc), 1255 KBD_DISABLE_KBD_PORT | KBD_DISABLE_KBD_INT | 1256 KBD_ENABLE_AUX_PORT | KBD_DISABLE_AUX_INT)) { 1257 /* CONTROLLER ERROR */ 1258 splx(s); 1259 kbdc_lock(sc->kbdc, FALSE); 1260 log(LOG_ERR, 1261 "psm%d: unable to set the command byte (reinitialize).\n", 1262 sc->unit); 1263 return (EIO); 1264 } 1265 1266 /* flush any data */ 1267 if (sc->state & PSM_VALID) { 1268 /* this may fail; but never mind... */ 1269 disable_aux_dev(sc->kbdc); 1270 empty_aux_buffer(sc->kbdc, 10); 1271 } 1272 flushpackets(sc); 1273 sc->syncerrors = 0; 1274 sc->pkterrors = 0; 1275 memset(&sc->lastinputerr, 0, sizeof(sc->lastinputerr)); 1276 1277 /* try to detect the aux device; are you still there? */ 1278 err = 0; 1279 if (doinit) { 1280 if (doinitialize(sc, &sc->mode)) { 1281 /* yes */ 1282 sc->state |= PSM_VALID; 1283 } else { 1284 /* the device has gone! */ 1285 restore_controller(sc->kbdc, c); 1286 sc->state &= ~PSM_VALID; 1287 log(LOG_ERR, 1288 "psm%d: the aux device has gone! (reinitialize).\n", 1289 sc->unit); 1290 err = ENXIO; 1291 } 1292 } 1293 splx(s); 1294 1295 /* restore the driver state */ 1296 if ((sc->state & (PSM_OPEN | PSM_EV_OPEN_R | PSM_EV_OPEN_A)) && 1297 (err == 0)) { 1298 /* enable the aux device and the port again */ 1299 err = doopen(sc, c); 1300 if (err != 0) 1301 log(LOG_ERR, "psm%d: failed to enable the device " 1302 "(reinitialize).\n", sc->unit); 1303 } else { 1304 /* restore the keyboard port and disable the aux port */ 1305 if (!set_controller_command_byte(sc->kbdc, 1306 kbdc_get_device_mask(sc->kbdc), 1307 (c & KBD_KBD_CONTROL_BITS) | 1308 KBD_DISABLE_AUX_PORT | KBD_DISABLE_AUX_INT)) { 1309 /* CONTROLLER ERROR */ 1310 log(LOG_ERR, "psm%d: failed to disable the aux port " 1311 "(reinitialize).\n", sc->unit); 1312 err = EIO; 1313 } 1314 } 1315 1316 kbdc_lock(sc->kbdc, FALSE); 1317 return (err); 1318 } 1319 1320 /* psm driver entry points */ 1321 1322 static void 1323 psmidentify(driver_t *driver, device_t parent) 1324 { 1325 device_t psmc; 1326 device_t psm; 1327 u_long irq; 1328 int unit; 1329 1330 unit = device_get_unit(parent); 1331 1332 /* always add at least one child */ 1333 psm = BUS_ADD_CHILD(parent, KBDC_RID_AUX, driver->name, unit); 1334 if (psm == NULL) 1335 return; 1336 1337 irq = bus_get_resource_start(psm, SYS_RES_IRQ, KBDC_RID_AUX); 1338 if (irq > 0) 1339 return; 1340 1341 /* 1342 * If the PS/2 mouse device has already been reported by ACPI or 1343 * PnP BIOS, obtain the IRQ resource from it. 1344 * (See psmcpnp_attach() below.) 1345 */ 1346 psmc = device_find_child(device_get_parent(parent), 1347 PSMCPNP_DRIVER_NAME, unit); 1348 if (psmc == NULL) 1349 return; 1350 irq = bus_get_resource_start(psmc, SYS_RES_IRQ, 0); 1351 if (irq <= 0) 1352 return; 1353 bus_delete_resource(psmc, SYS_RES_IRQ, 0); 1354 bus_set_resource(psm, SYS_RES_IRQ, KBDC_RID_AUX, irq, 1); 1355 } 1356 1357 #define endprobe(v) do { \ 1358 if (bootverbose) \ 1359 --verbose; \ 1360 kbdc_set_device_mask(sc->kbdc, mask); \ 1361 kbdc_lock(sc->kbdc, FALSE); \ 1362 return (v); \ 1363 } while (0) 1364 1365 static int 1366 psmprobe(device_t dev) 1367 { 1368 int unit = device_get_unit(dev); 1369 struct psm_softc *sc = device_get_softc(dev); 1370 int stat[3]; 1371 int command_byte; 1372 int mask; 1373 int rid; 1374 int i; 1375 1376 #if 0 1377 kbdc_debug(TRUE); 1378 #endif 1379 1380 /* see if IRQ is available */ 1381 rid = KBDC_RID_AUX; 1382 sc->intr = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_ACTIVE); 1383 if (sc->intr == NULL) { 1384 if (bootverbose) 1385 device_printf(dev, "unable to allocate IRQ\n"); 1386 return (ENXIO); 1387 } 1388 bus_release_resource(dev, SYS_RES_IRQ, rid, sc->intr); 1389 1390 sc->unit = unit; 1391 sc->kbdc = atkbdc_open(device_get_unit(device_get_parent(dev))); 1392 sc->config = device_get_flags(dev) & PSM_CONFIG_FLAGS; 1393 /* XXX: for backward compatibility */ 1394 #if defined(PSM_HOOKRESUME) || defined(PSM_HOOKAPM) 1395 sc->config |= 1396 #ifdef PSM_RESETAFTERSUSPEND 1397 PSM_CONFIG_INITAFTERSUSPEND; 1398 #else 1399 PSM_CONFIG_HOOKRESUME; 1400 #endif 1401 #endif /* PSM_HOOKRESUME | PSM_HOOKAPM */ 1402 sc->flags = 0; 1403 sc->muxport = PSM_NOMUX; 1404 if (bootverbose) 1405 ++verbose; 1406 1407 device_set_desc(dev, "PS/2 Mouse"); 1408 1409 if (!kbdc_lock(sc->kbdc, TRUE)) { 1410 printf("psm%d: unable to lock the controller.\n", unit); 1411 if (bootverbose) 1412 --verbose; 1413 return (ENXIO); 1414 } 1415 1416 /* 1417 * NOTE: two bits in the command byte controls the operation of the 1418 * aux port (mouse port): the aux port disable bit (bit 5) and the aux 1419 * port interrupt (IRQ 12) enable bit (bit 2). 1420 */ 1421 1422 /* discard anything left after the keyboard initialization */ 1423 empty_both_buffers(sc->kbdc, 10); 1424 1425 /* save the current command byte; it will be used later */ 1426 mask = kbdc_get_device_mask(sc->kbdc) & ~KBD_AUX_CONTROL_BITS; 1427 command_byte = get_controller_command_byte(sc->kbdc); 1428 if (verbose) 1429 printf("psm%d: current command byte:%04x\n", unit, 1430 command_byte); 1431 if (command_byte == -1) { 1432 /* CONTROLLER ERROR */ 1433 printf("psm%d: unable to get the current command byte value.\n", 1434 unit); 1435 endprobe(ENXIO); 1436 } 1437 1438 /* 1439 * disable the keyboard port while probing the aux port, which must be 1440 * enabled during this routine 1441 */ 1442 if (!set_controller_command_byte(sc->kbdc, 1443 KBD_KBD_CONTROL_BITS | KBD_AUX_CONTROL_BITS, 1444 KBD_DISABLE_KBD_PORT | KBD_DISABLE_KBD_INT | 1445 KBD_ENABLE_AUX_PORT | KBD_DISABLE_AUX_INT)) { 1446 /* 1447 * this is CONTROLLER ERROR; I don't know how to recover 1448 * from this error... 1449 */ 1450 if (ALWAYS_RESTORE_CONTROLLER(sc->kbdc)) 1451 restore_controller(sc->kbdc, command_byte); 1452 printf("psm%d: unable to set the command byte.\n", unit); 1453 endprobe(ENXIO); 1454 } 1455 write_controller_command(sc->kbdc, KBDC_ENABLE_AUX_PORT); 1456 1457 /* 1458 * NOTE: `test_aux_port()' is designed to return with zero if the aux 1459 * port exists and is functioning. However, some controllers appears 1460 * to respond with zero even when the aux port doesn't exist. (It may 1461 * be that this is only the case when the controller DOES have the aux 1462 * port but the port is not wired on the motherboard.) The keyboard 1463 * controllers without the port, such as the original AT, are 1464 * supposed to return with an error code or simply time out. In any 1465 * case, we have to continue probing the port even when the controller 1466 * passes this test. 1467 * 1468 * XXX: some controllers erroneously return the error code 1, 2 or 3 1469 * when it has a perfectly functional aux port. We have to ignore 1470 * this error code. Even if the controller HAS error with the aux 1471 * port, it will be detected later... 1472 * XXX: another incompatible controller returns PSM_ACK (0xfa)... 1473 */ 1474 switch ((i = test_aux_port(sc->kbdc))) { 1475 case 1: /* ignore these errors */ 1476 case 2: 1477 case 3: 1478 case PSM_ACK: 1479 if (verbose) 1480 printf("psm%d: strange result for test aux port " 1481 "(%d).\n", unit, i); 1482 /* FALLTHROUGH */ 1483 case 0: /* no error */ 1484 break; 1485 case -1: /* time out */ 1486 default: /* error */ 1487 recover_from_error(sc->kbdc); 1488 if (sc->config & PSM_CONFIG_IGNPORTERROR) 1489 break; 1490 if (ALWAYS_RESTORE_CONTROLLER(sc->kbdc)) 1491 restore_controller(sc->kbdc, command_byte); 1492 if (verbose) 1493 printf("psm%d: the aux port is not functioning (%d).\n", 1494 unit, i); 1495 endprobe(ENXIO); 1496 } 1497 1498 if (sc->config & PSM_CONFIG_NORESET) { 1499 /* 1500 * Don't try to reset the pointing device. It may possibly be 1501 * left in an unknown state, though... 1502 */ 1503 } else { 1504 /* 1505 * NOTE: some controllers appears to hang the `keyboard' when 1506 * the aux port doesn't exist and `PSMC_RESET_DEV' is issued. 1507 * 1508 * Attempt to reset the controller twice -- this helps 1509 * pierce through some KVM switches. The second reset 1510 * is non-fatal. 1511 */ 1512 if (!reset_aux_dev(sc->kbdc)) { 1513 recover_from_error(sc->kbdc); 1514 if (ALWAYS_RESTORE_CONTROLLER(sc->kbdc)) 1515 restore_controller(sc->kbdc, command_byte); 1516 if (verbose) 1517 printf("psm%d: failed to reset the aux " 1518 "device.\n", unit); 1519 endprobe(ENXIO); 1520 } else if (!reset_aux_dev(sc->kbdc)) { 1521 recover_from_error(sc->kbdc); 1522 if (verbose >= 2) 1523 printf("psm%d: failed to reset the aux device " 1524 "(2).\n", unit); 1525 } 1526 } 1527 1528 /* 1529 * both the aux port and the aux device are functioning, see if the 1530 * device can be enabled. NOTE: when enabled, the device will start 1531 * sending data; we shall immediately disable the device once we know 1532 * the device can be enabled. 1533 */ 1534 if (!enable_aux_dev(sc->kbdc) || !disable_aux_dev(sc->kbdc)) { 1535 /* MOUSE ERROR */ 1536 recover_from_error(sc->kbdc); 1537 if (ALWAYS_RESTORE_CONTROLLER(sc->kbdc)) 1538 restore_controller(sc->kbdc, command_byte); 1539 if (verbose) 1540 printf("psm%d: failed to enable the aux device.\n", 1541 unit); 1542 endprobe(ENXIO); 1543 } 1544 1545 /* save the default values after reset */ 1546 if (get_mouse_status(sc->kbdc, stat, 0, 3) >= 3) { 1547 sc->dflt_mode.rate = sc->mode.rate = stat[2]; 1548 sc->dflt_mode.resolution = sc->mode.resolution = stat[1]; 1549 } else { 1550 sc->dflt_mode.rate = sc->mode.rate = -1; 1551 sc->dflt_mode.resolution = sc->mode.resolution = -1; 1552 } 1553 1554 /* hardware information */ 1555 sc->hw.iftype = MOUSE_IF_PS2; 1556 1557 /* verify the device is a mouse */ 1558 sc->hw.hwid = get_aux_id(sc->kbdc); 1559 if (!is_a_mouse(sc->hw.hwid)) { 1560 if (ALWAYS_RESTORE_CONTROLLER(sc->kbdc)) 1561 restore_controller(sc->kbdc, command_byte); 1562 if (verbose) 1563 printf("psm%d: unknown device type (%d).\n", unit, 1564 sc->hw.hwid); 1565 endprobe(ENXIO); 1566 } 1567 switch (sc->hw.hwid) { 1568 case PSM_BALLPOINT_ID: 1569 sc->hw.type = MOUSE_TRACKBALL; 1570 break; 1571 case PSM_MOUSE_ID: 1572 case PSM_INTELLI_ID: 1573 case PSM_EXPLORER_ID: 1574 case PSM_4DMOUSE_ID: 1575 case PSM_4DPLUS_ID: 1576 sc->hw.type = MOUSE_MOUSE; 1577 break; 1578 default: 1579 sc->hw.type = MOUSE_UNKNOWN; 1580 break; 1581 } 1582 1583 if (sc->config & PSM_CONFIG_NOIDPROBE) { 1584 sc->hw.buttons = 2; 1585 i = GENERIC_MOUSE_ENTRY; 1586 } else { 1587 /* # of buttons */ 1588 sc->hw.buttons = get_mouse_buttons(sc->kbdc); 1589 1590 /* other parameters */ 1591 for (i = 0; vendortype[i].probefunc != NULL; ++i) 1592 if ((*vendortype[i].probefunc)(sc, PROBE)) { 1593 if (verbose >= 2) 1594 printf("psm%d: found %s\n", unit, 1595 model_name(vendortype[i].model)); 1596 break; 1597 } 1598 } 1599 1600 sc->hw.model = vendortype[i].model; 1601 1602 sc->dflt_mode.level = PSM_LEVEL_BASE; 1603 sc->dflt_mode.packetsize = MOUSE_PS2_PACKETSIZE; 1604 sc->dflt_mode.accelfactor = (sc->config & PSM_CONFIG_ACCEL) >> 4; 1605 if (sc->config & PSM_CONFIG_NOCHECKSYNC) 1606 sc->dflt_mode.syncmask[0] = 0; 1607 else 1608 sc->dflt_mode.syncmask[0] = vendortype[i].syncmask; 1609 if (sc->config & PSM_CONFIG_FORCETAP) 1610 sc->dflt_mode.syncmask[0] &= ~MOUSE_PS2_TAP; 1611 sc->dflt_mode.syncmask[1] = 0; /* syncbits */ 1612 sc->mode = sc->dflt_mode; 1613 sc->mode.packetsize = vendortype[i].packetsize; 1614 1615 /* set mouse parameters */ 1616 #if 0 1617 /* 1618 * A version of Logitech FirstMouse+ won't report wheel movement, 1619 * if SET_DEFAULTS is sent... Don't use this command. 1620 * This fix was found by Takashi Nishida. 1621 */ 1622 i = send_aux_command(sc->kbdc, PSMC_SET_DEFAULTS); 1623 if (verbose >= 2) 1624 printf("psm%d: SET_DEFAULTS return code:%04x\n", unit, i); 1625 #endif 1626 if (sc->config & PSM_CONFIG_RESOLUTION) 1627 sc->mode.resolution = 1628 set_mouse_resolution(sc->kbdc, 1629 (sc->config & PSM_CONFIG_RESOLUTION) - 1); 1630 else if (sc->mode.resolution >= 0) 1631 sc->mode.resolution = 1632 set_mouse_resolution(sc->kbdc, sc->dflt_mode.resolution); 1633 if (sc->mode.rate > 0) 1634 sc->mode.rate = 1635 set_mouse_sampling_rate(sc->kbdc, sc->dflt_mode.rate); 1636 set_mouse_scaling(sc->kbdc, 1); 1637 1638 /* Record sync on the next data packet we see. */ 1639 sc->flags |= PSM_NEED_SYNCBITS; 1640 1641 /* just check the status of the mouse */ 1642 /* 1643 * NOTE: XXX there are some arcane controller/mouse combinations out 1644 * there, which hung the controller unless there is data transmission 1645 * after ACK from the mouse. 1646 */ 1647 if (get_mouse_status(sc->kbdc, stat, 0, 3) < 3) 1648 printf("psm%d: failed to get status.\n", unit); 1649 else { 1650 /* 1651 * When in its native mode, some mice operate with different 1652 * default parameters than in the PS/2 compatible mode. 1653 */ 1654 sc->dflt_mode.rate = sc->mode.rate = stat[2]; 1655 sc->dflt_mode.resolution = sc->mode.resolution = stat[1]; 1656 } 1657 1658 /* disable the aux port for now... */ 1659 if (!set_controller_command_byte(sc->kbdc, 1660 KBD_KBD_CONTROL_BITS | KBD_AUX_CONTROL_BITS, 1661 (command_byte & KBD_KBD_CONTROL_BITS) | 1662 KBD_DISABLE_AUX_PORT | KBD_DISABLE_AUX_INT)) { 1663 /* 1664 * this is CONTROLLER ERROR; I don't know the proper way to 1665 * recover from this error... 1666 */ 1667 if (ALWAYS_RESTORE_CONTROLLER(sc->kbdc)) 1668 restore_controller(sc->kbdc, command_byte); 1669 printf("psm%d: unable to set the command byte.\n", unit); 1670 endprobe(ENXIO); 1671 } 1672 1673 /* done */ 1674 kbdc_set_device_mask(sc->kbdc, mask | KBD_AUX_CONTROL_BITS); 1675 kbdc_lock(sc->kbdc, FALSE); 1676 return (0); 1677 } 1678 1679 #ifdef EVDEV_SUPPORT 1680 /* Values are taken from Linux drivers for userland software compatibility */ 1681 #define PS2_MOUSE_VENDOR 0x0002 1682 #define PS2_MOUSE_GENERIC_PRODUCT 0x0001 1683 #define PS2_MOUSE_SYNAPTICS_NAME "SynPS/2 Synaptics TouchPad" 1684 #define PS2_MOUSE_SYNAPTICS_PRODUCT 0x0007 1685 #define PS2_MOUSE_TRACKPOINT_NAME "TPPS/2 IBM TrackPoint" 1686 #define PS2_MOUSE_TRACKPOINT_PRODUCT 0x000A 1687 #define PS2_MOUSE_ELANTECH_NAME "ETPS/2 Elantech Touchpad" 1688 #define PS2_MOUSE_ELANTECH_ST_NAME "ETPS/2 Elantech TrackPoint" 1689 #define PS2_MOUSE_ELANTECH_PRODUCT 0x000E 1690 1691 #define ABSINFO_END { ABS_CNT, 0, 0, 0 } 1692 1693 static void 1694 psm_support_abs_bulk(struct evdev_dev *evdev, const uint16_t info[][4]) 1695 { 1696 size_t i; 1697 1698 for (i = 0; info[i][0] != ABS_CNT; i++) 1699 evdev_support_abs(evdev, info[i][0], 0, info[i][1], info[i][2], 1700 0, 0, info[i][3]); 1701 } 1702 1703 static void 1704 psm_push_mt_finger(struct psm_softc *sc, int id, const finger_t *f) 1705 { 1706 int y = sc->synhw.minimumYCoord + sc->synhw.maximumYCoord - f->y; 1707 1708 evdev_push_abs(sc->evdev_a, ABS_MT_SLOT, id); 1709 evdev_push_abs(sc->evdev_a, ABS_MT_TRACKING_ID, id); 1710 evdev_push_abs(sc->evdev_a, ABS_MT_POSITION_X, f->x); 1711 evdev_push_abs(sc->evdev_a, ABS_MT_POSITION_Y, y); 1712 evdev_push_abs(sc->evdev_a, ABS_MT_PRESSURE, f->p); 1713 } 1714 1715 static void 1716 psm_push_st_finger(struct psm_softc *sc, const finger_t *f) 1717 { 1718 int y = sc->synhw.minimumYCoord + sc->synhw.maximumYCoord - f->y; 1719 1720 evdev_push_abs(sc->evdev_a, ABS_X, f->x); 1721 evdev_push_abs(sc->evdev_a, ABS_Y, y); 1722 evdev_push_abs(sc->evdev_a, ABS_PRESSURE, f->p); 1723 if (sc->synhw.capPalmDetect) 1724 evdev_push_abs(sc->evdev_a, ABS_TOOL_WIDTH, f->w); 1725 } 1726 1727 static void 1728 psm_release_mt_slot(struct evdev_dev *evdev, int32_t slot) 1729 { 1730 1731 evdev_push_abs(evdev, ABS_MT_SLOT, slot); 1732 evdev_push_abs(evdev, ABS_MT_TRACKING_ID, -1); 1733 } 1734 1735 static int 1736 psm_register(device_t dev, int model_code) 1737 { 1738 struct psm_softc *sc = device_get_softc(dev); 1739 struct evdev_dev *evdev_r; 1740 int error, i, nbuttons, nwheels, product; 1741 bool is_pointing_stick; 1742 const char *name; 1743 1744 name = model_name(model_code); 1745 nbuttons = sc->hw.buttons; 1746 product = PS2_MOUSE_GENERIC_PRODUCT; 1747 nwheels = 0; 1748 is_pointing_stick = false; 1749 1750 switch (model_code) { 1751 case MOUSE_MODEL_TRACKPOINT: 1752 name = PS2_MOUSE_TRACKPOINT_NAME; 1753 product = PS2_MOUSE_TRACKPOINT_PRODUCT; 1754 nbuttons = 3; 1755 is_pointing_stick = true; 1756 break; 1757 1758 case MOUSE_MODEL_ELANTECH: 1759 name = PS2_MOUSE_ELANTECH_ST_NAME; 1760 product = PS2_MOUSE_ELANTECH_PRODUCT; 1761 nbuttons = 3; 1762 is_pointing_stick = true; 1763 break; 1764 1765 case MOUSE_MODEL_MOUSEMANPLUS: 1766 case MOUSE_MODEL_4D: 1767 nwheels = 2; 1768 break; 1769 1770 case MOUSE_MODEL_EXPLORER: 1771 case MOUSE_MODEL_INTELLI: 1772 case MOUSE_MODEL_NET: 1773 case MOUSE_MODEL_NETSCROLL: 1774 case MOUSE_MODEL_4DPLUS: 1775 nwheels = 1; 1776 break; 1777 } 1778 1779 evdev_r = evdev_alloc(); 1780 evdev_set_name(evdev_r, name); 1781 evdev_set_phys(evdev_r, device_get_nameunit(dev)); 1782 evdev_set_id(evdev_r, BUS_I8042, PS2_MOUSE_VENDOR, product, 0); 1783 evdev_set_methods(evdev_r, sc, &psm_ev_methods_r); 1784 1785 evdev_support_prop(evdev_r, INPUT_PROP_POINTER); 1786 if (is_pointing_stick) 1787 evdev_support_prop(evdev_r, INPUT_PROP_POINTING_STICK); 1788 evdev_support_event(evdev_r, EV_SYN); 1789 evdev_support_event(evdev_r, EV_KEY); 1790 evdev_support_event(evdev_r, EV_REL); 1791 evdev_support_rel(evdev_r, REL_X); 1792 evdev_support_rel(evdev_r, REL_Y); 1793 switch (nwheels) { 1794 case 2: 1795 evdev_support_rel(evdev_r, REL_HWHEEL); 1796 /* FALLTHROUGH */ 1797 case 1: 1798 evdev_support_rel(evdev_r, REL_WHEEL); 1799 } 1800 for (i = 0; i < nbuttons; i++) 1801 evdev_support_key(evdev_r, BTN_MOUSE + i); 1802 1803 error = evdev_register_mtx(evdev_r, &Giant); 1804 if (error) 1805 evdev_free(evdev_r); 1806 else 1807 sc->evdev_r = evdev_r; 1808 return (error); 1809 } 1810 1811 static int 1812 psm_register_synaptics(device_t dev) 1813 { 1814 struct psm_softc *sc = device_get_softc(dev); 1815 const uint16_t synaptics_absinfo_st[][4] = { 1816 { ABS_X, sc->synhw.minimumXCoord, 1817 sc->synhw.maximumXCoord, sc->synhw.infoXupmm }, 1818 { ABS_Y, sc->synhw.minimumYCoord, 1819 sc->synhw.maximumYCoord, sc->synhw.infoYupmm }, 1820 { ABS_PRESSURE, 0, ELANTECH_FINGER_MAX_P, 0 }, 1821 ABSINFO_END, 1822 }; 1823 const uint16_t synaptics_absinfo_mt[][4] = { 1824 { ABS_MT_SLOT, 0, PSM_FINGERS-1, 0}, 1825 { ABS_MT_TRACKING_ID, -1, PSM_FINGERS-1, 0}, 1826 { ABS_MT_POSITION_X, sc->synhw.minimumXCoord, 1827 sc->synhw.maximumXCoord, sc->synhw.infoXupmm }, 1828 { ABS_MT_POSITION_Y, sc->synhw.minimumYCoord, 1829 sc->synhw.maximumYCoord, sc->synhw.infoYupmm }, 1830 { ABS_MT_PRESSURE, 0, ELANTECH_FINGER_MAX_P, 0 }, 1831 ABSINFO_END, 1832 }; 1833 struct evdev_dev *evdev_a; 1834 int error, i, guest_model; 1835 1836 evdev_a = evdev_alloc(); 1837 evdev_set_name(evdev_a, PS2_MOUSE_SYNAPTICS_NAME); 1838 evdev_set_phys(evdev_a, device_get_nameunit(dev)); 1839 evdev_set_id(evdev_a, BUS_I8042, PS2_MOUSE_VENDOR, 1840 PS2_MOUSE_SYNAPTICS_PRODUCT, 0); 1841 evdev_set_methods(evdev_a, sc, &psm_ev_methods_a); 1842 1843 evdev_support_event(evdev_a, EV_SYN); 1844 evdev_support_event(evdev_a, EV_KEY); 1845 evdev_support_event(evdev_a, EV_ABS); 1846 evdev_support_prop(evdev_a, INPUT_PROP_POINTER); 1847 if (sc->synhw.capAdvancedGestures) 1848 evdev_support_prop(evdev_a, INPUT_PROP_SEMI_MT); 1849 if (sc->synhw.capClickPad) 1850 evdev_support_prop(evdev_a, INPUT_PROP_BUTTONPAD); 1851 if (sc->synhw.capClickPad && sc->synhw.topButtonPad) 1852 evdev_support_prop(evdev_a, INPUT_PROP_TOPBUTTONPAD); 1853 evdev_support_key(evdev_a, BTN_TOUCH); 1854 evdev_support_nfingers(evdev_a, sc->synhw.capReportsV ? 5 : 3); 1855 psm_support_abs_bulk(evdev_a, synaptics_absinfo_st); 1856 if (sc->synhw.capAdvancedGestures || sc->synhw.capReportsV) 1857 psm_support_abs_bulk(evdev_a, synaptics_absinfo_mt); 1858 if (sc->synhw.capPalmDetect) 1859 evdev_support_abs(evdev_a, ABS_TOOL_WIDTH, 0, 0, 15, 0, 0, 0); 1860 evdev_support_key(evdev_a, BTN_LEFT); 1861 if (!sc->synhw.capClickPad) { 1862 evdev_support_key(evdev_a, BTN_RIGHT); 1863 if (sc->synhw.capExtended && sc->synhw.capMiddle) 1864 evdev_support_key(evdev_a, BTN_MIDDLE); 1865 } 1866 if (sc->synhw.capExtended && sc->synhw.capFourButtons) { 1867 evdev_support_key(evdev_a, BTN_BACK); 1868 evdev_support_key(evdev_a, BTN_FORWARD); 1869 } 1870 if (sc->synhw.capExtended && (sc->synhw.nExtendedButtons > 0)) 1871 for (i = 0; i < sc->synhw.nExtendedButtons; i++) 1872 evdev_support_key(evdev_a, BTN_0 + i); 1873 1874 error = evdev_register_mtx(evdev_a, &Giant); 1875 if (!error && (sc->synhw.capPassthrough || sc->muxport != PSM_NOMUX)) { 1876 guest_model = sc->tpinfo.sysctl_tree != NULL ? 1877 MOUSE_MODEL_TRACKPOINT : MOUSE_MODEL_GENERIC; 1878 error = psm_register(dev, guest_model); 1879 } 1880 if (error) 1881 evdev_free(evdev_a); 1882 else 1883 sc->evdev_a = evdev_a; 1884 return (error); 1885 } 1886 1887 static int 1888 psm_register_elantech(device_t dev) 1889 { 1890 struct psm_softc *sc = device_get_softc(dev); 1891 const uint16_t elantech_absinfo[][4] = { 1892 { ABS_X, 0, sc->elanhw.sizex, 1893 sc->elanhw.dpmmx }, 1894 { ABS_Y, 0, sc->elanhw.sizey, 1895 sc->elanhw.dpmmy }, 1896 { ABS_PRESSURE, 0, ELANTECH_FINGER_MAX_P, 0 }, 1897 { ABS_TOOL_WIDTH, 0, ELANTECH_FINGER_MAX_W, 0 }, 1898 { ABS_MT_SLOT, 0, ELANTECH_MAX_FINGERS - 1, 0 }, 1899 { ABS_MT_TRACKING_ID, -1, ELANTECH_MAX_FINGERS - 1, 0 }, 1900 { ABS_MT_POSITION_X, 0, sc->elanhw.sizex, 1901 sc->elanhw.dpmmx }, 1902 { ABS_MT_POSITION_Y, 0, sc->elanhw.sizey, 1903 sc->elanhw.dpmmy }, 1904 { ABS_MT_PRESSURE, 0, ELANTECH_FINGER_MAX_P, 0 }, 1905 { ABS_MT_TOUCH_MAJOR, 0, ELANTECH_FINGER_MAX_W * 1906 sc->elanhw.dptracex, 0 }, 1907 ABSINFO_END, 1908 }; 1909 struct evdev_dev *evdev_a; 1910 int error; 1911 1912 evdev_a = evdev_alloc(); 1913 evdev_set_name(evdev_a, PS2_MOUSE_ELANTECH_NAME); 1914 evdev_set_phys(evdev_a, device_get_nameunit(dev)); 1915 evdev_set_id(evdev_a, BUS_I8042, PS2_MOUSE_VENDOR, 1916 PS2_MOUSE_ELANTECH_PRODUCT, 0); 1917 evdev_set_methods(evdev_a, sc, &psm_ev_methods_a); 1918 1919 evdev_support_event(evdev_a, EV_SYN); 1920 evdev_support_event(evdev_a, EV_KEY); 1921 evdev_support_event(evdev_a, EV_ABS); 1922 evdev_support_prop(evdev_a, INPUT_PROP_POINTER); 1923 if (sc->elanhw.issemimt) 1924 evdev_support_prop(evdev_a, INPUT_PROP_SEMI_MT); 1925 if (sc->elanhw.isclickpad) 1926 evdev_support_prop(evdev_a, INPUT_PROP_BUTTONPAD); 1927 evdev_support_key(evdev_a, BTN_TOUCH); 1928 evdev_support_nfingers(evdev_a, ELANTECH_MAX_FINGERS); 1929 evdev_support_key(evdev_a, BTN_LEFT); 1930 if (!sc->elanhw.isclickpad) 1931 evdev_support_key(evdev_a, BTN_RIGHT); 1932 psm_support_abs_bulk(evdev_a, elantech_absinfo); 1933 1934 error = evdev_register_mtx(evdev_a, &Giant); 1935 if (!error && sc->elanhw.hastrackpoint) 1936 error = psm_register(dev, MOUSE_MODEL_ELANTECH); 1937 if (error) 1938 evdev_free(evdev_a); 1939 else 1940 sc->evdev_a = evdev_a; 1941 return (error); 1942 } 1943 #endif 1944 1945 static int 1946 psmattach(device_t dev) 1947 { 1948 int unit = device_get_unit(dev); 1949 struct psm_softc *sc = device_get_softc(dev); 1950 int error; 1951 int rid; 1952 1953 /* Setup initial state */ 1954 sc->state = PSM_VALID; 1955 callout_init(&sc->callout, 0); 1956 callout_init(&sc->softcallout, 0); 1957 1958 /* Setup our interrupt handler */ 1959 rid = KBDC_RID_AUX; 1960 sc->intr = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_ACTIVE); 1961 if (sc->intr == NULL) 1962 return (ENXIO); 1963 error = bus_setup_intr(dev, sc->intr, INTR_TYPE_TTY, NULL, psmintr, sc, 1964 &sc->ih); 1965 if (error) { 1966 bus_release_resource(dev, SYS_RES_IRQ, rid, sc->intr); 1967 return (error); 1968 } 1969 1970 /* Done */ 1971 sc->dev = make_dev(&psm_cdevsw, 0, 0, 0, 0666, "psm%d", unit); 1972 sc->dev->si_drv1 = sc; 1973 sc->bdev = make_dev(&psm_cdevsw, 0, 0, 0, 0666, "bpsm%d", unit); 1974 sc->bdev->si_drv1 = sc; 1975 1976 #ifdef EVDEV_SUPPORT 1977 switch (sc->hw.model) { 1978 case MOUSE_MODEL_SYNAPTICS: 1979 error = psm_register_synaptics(dev); 1980 break; 1981 1982 case MOUSE_MODEL_ELANTECH: 1983 error = psm_register_elantech(dev); 1984 break; 1985 1986 default: 1987 error = psm_register(dev, sc->hw.model); 1988 } 1989 1990 if (error) 1991 return (error); 1992 #endif 1993 1994 /* Some touchpad devices need full reinitialization after suspend. */ 1995 switch (sc->hw.model) { 1996 case MOUSE_MODEL_SYNAPTICS: 1997 case MOUSE_MODEL_GLIDEPOINT: 1998 case MOUSE_MODEL_VERSAPAD: 1999 case MOUSE_MODEL_ELANTECH: 2000 sc->config |= PSM_CONFIG_INITAFTERSUSPEND; 2001 break; 2002 default: 2003 if (sc->synhw.infoMajor >= 4 || sc->tphw > 0) 2004 sc->config |= PSM_CONFIG_INITAFTERSUSPEND; 2005 break; 2006 } 2007 2008 /* Elantech trackpad`s sync bit differs from touchpad`s one */ 2009 if (sc->hw.model == MOUSE_MODEL_ELANTECH && 2010 (sc->elanhw.hascrc || sc->elanhw.hastrackpoint)) { 2011 sc->config |= PSM_CONFIG_NOCHECKSYNC; 2012 sc->flags &= ~PSM_NEED_SYNCBITS; 2013 } 2014 2015 if (!verbose) 2016 printf("psm%d: model %s, device ID %d\n", 2017 unit, model_name(sc->hw.model), sc->hw.hwid & 0x00ff); 2018 else { 2019 printf("psm%d: model %s, device ID %d-%02x, %d buttons\n", 2020 unit, model_name(sc->hw.model), sc->hw.hwid & 0x00ff, 2021 sc->hw.hwid >> 8, sc->hw.buttons); 2022 printf("psm%d: config:%08x, flags:%08x, packet size:%d\n", 2023 unit, sc->config, sc->flags, sc->mode.packetsize); 2024 printf("psm%d: syncmask:%02x, syncbits:%02x%s\n", 2025 unit, sc->mode.syncmask[0], sc->mode.syncmask[1], 2026 sc->config & PSM_CONFIG_NOCHECKSYNC ? " (sync not checked)" : ""); 2027 } 2028 2029 if (bootverbose) 2030 --verbose; 2031 2032 return (0); 2033 } 2034 2035 static int 2036 psmdetach(device_t dev) 2037 { 2038 struct psm_softc *sc; 2039 int rid; 2040 2041 sc = device_get_softc(dev); 2042 if (sc->state & PSM_OPEN) 2043 return (EBUSY); 2044 2045 #ifdef EVDEV_SUPPORT 2046 evdev_free(sc->evdev_r); 2047 evdev_free(sc->evdev_a); 2048 #endif 2049 2050 rid = KBDC_RID_AUX; 2051 bus_teardown_intr(dev, sc->intr, sc->ih); 2052 bus_release_resource(dev, SYS_RES_IRQ, rid, sc->intr); 2053 2054 destroy_dev(sc->dev); 2055 destroy_dev(sc->bdev); 2056 2057 callout_drain(&sc->callout); 2058 callout_drain(&sc->softcallout); 2059 2060 return (0); 2061 } 2062 2063 #ifdef EVDEV_SUPPORT 2064 static int 2065 psm_ev_open_r(struct evdev_dev *evdev) 2066 { 2067 struct psm_softc *sc = evdev_get_softc(evdev); 2068 int err = 0; 2069 2070 /* Get device data */ 2071 if ((sc->state & PSM_VALID) == 0) { 2072 /* the device is no longer valid/functioning */ 2073 return (ENXIO); 2074 } 2075 2076 if (!(sc->state & (PSM_OPEN | PSM_EV_OPEN_A))) 2077 err = psmopen(sc); 2078 2079 if (err == 0) 2080 sc->state |= PSM_EV_OPEN_R; 2081 2082 return (err); 2083 } 2084 2085 static int 2086 psm_ev_close_r(struct evdev_dev *evdev) 2087 { 2088 struct psm_softc *sc = evdev_get_softc(evdev); 2089 int err = 0; 2090 2091 sc->state &= ~PSM_EV_OPEN_R; 2092 2093 if (sc->state & (PSM_OPEN | PSM_EV_OPEN_A)) 2094 return (0); 2095 2096 if (sc->state & PSM_VALID) 2097 err = psmclose(sc); 2098 2099 return (err); 2100 } 2101 2102 static int 2103 psm_ev_open_a(struct evdev_dev *evdev) 2104 { 2105 struct psm_softc *sc = evdev_get_softc(evdev); 2106 int err = 0; 2107 2108 /* Get device data */ 2109 if ((sc->state & PSM_VALID) == 0) { 2110 /* the device is no longer valid/functioning */ 2111 return (ENXIO); 2112 } 2113 2114 if (!(sc->state & (PSM_OPEN | PSM_EV_OPEN_R))) 2115 err = psmopen(sc); 2116 2117 if (err == 0) 2118 sc->state |= PSM_EV_OPEN_A; 2119 2120 return (err); 2121 } 2122 2123 static int 2124 psm_ev_close_a(struct evdev_dev *evdev) 2125 { 2126 struct psm_softc *sc = evdev_get_softc(evdev); 2127 int err = 0; 2128 2129 sc->state &= ~PSM_EV_OPEN_A; 2130 2131 if (sc->state & (PSM_OPEN | PSM_EV_OPEN_R)) 2132 return (0); 2133 2134 if (sc->state & PSM_VALID) 2135 err = psmclose(sc); 2136 2137 return (err); 2138 } 2139 #endif 2140 2141 static int 2142 psm_cdev_open(struct cdev *dev, int flag, int fmt, struct thread *td) 2143 { 2144 struct psm_softc *sc; 2145 int err = 0; 2146 2147 /* Get device data */ 2148 sc = dev->si_drv1; 2149 if ((sc == NULL) || (sc->state & PSM_VALID) == 0) { 2150 /* the device is no longer valid/functioning */ 2151 return (ENXIO); 2152 } 2153 2154 /* Disallow multiple opens */ 2155 if (sc->state & PSM_OPEN) 2156 return (EBUSY); 2157 2158 device_busy(devclass_get_device(psm_devclass, sc->unit)); 2159 2160 #ifdef EVDEV_SUPPORT 2161 /* Already opened by evdev */ 2162 if (!(sc->state & (PSM_EV_OPEN_R | PSM_EV_OPEN_A))) 2163 #endif 2164 err = psmopen(sc); 2165 2166 if (err == 0) 2167 sc->state |= PSM_OPEN; 2168 else 2169 device_unbusy(devclass_get_device(psm_devclass, sc->unit)); 2170 2171 return (err); 2172 } 2173 2174 static int 2175 psm_cdev_close(struct cdev *dev, int flag, int fmt, struct thread *td) 2176 { 2177 struct psm_softc *sc; 2178 int err = 0; 2179 2180 /* Get device data */ 2181 sc = dev->si_drv1; 2182 if ((sc == NULL) || (sc->state & PSM_VALID) == 0) { 2183 /* the device is no longer valid/functioning */ 2184 return (ENXIO); 2185 } 2186 2187 #ifdef EVDEV_SUPPORT 2188 /* Still opened by evdev */ 2189 if (!(sc->state & (PSM_EV_OPEN_R | PSM_EV_OPEN_A))) 2190 #endif 2191 err = psmclose(sc); 2192 2193 if (err == 0) { 2194 sc->state &= ~PSM_OPEN; 2195 /* clean up and sigio requests */ 2196 if (sc->async != NULL) { 2197 funsetown(&sc->async); 2198 sc->async = NULL; 2199 } 2200 device_unbusy(devclass_get_device(psm_devclass, sc->unit)); 2201 } 2202 2203 return (err); 2204 } 2205 2206 static int 2207 psmopen(struct psm_softc *sc) 2208 { 2209 int command_byte; 2210 int err; 2211 int s; 2212 2213 /* Initialize state */ 2214 sc->mode.level = sc->dflt_mode.level; 2215 sc->mode.protocol = sc->dflt_mode.protocol; 2216 sc->watchdog = FALSE; 2217 sc->async = NULL; 2218 2219 /* flush the event queue */ 2220 sc->queue.count = 0; 2221 sc->queue.head = 0; 2222 sc->queue.tail = 0; 2223 sc->status.flags = 0; 2224 sc->status.button = 0; 2225 sc->status.obutton = 0; 2226 sc->status.dx = 0; 2227 sc->status.dy = 0; 2228 sc->status.dz = 0; 2229 sc->button = 0; 2230 sc->pqueue_start = 0; 2231 sc->pqueue_end = 0; 2232 2233 /* empty input buffer */ 2234 flushpackets(sc); 2235 sc->syncerrors = 0; 2236 sc->pkterrors = 0; 2237 2238 /* don't let timeout routines in the keyboard driver to poll the kbdc */ 2239 if (!kbdc_lock(sc->kbdc, TRUE)) 2240 return (EIO); 2241 2242 /* save the current controller command byte */ 2243 s = spltty(); 2244 command_byte = get_controller_command_byte(sc->kbdc); 2245 2246 /* enable the aux port and temporalily disable the keyboard */ 2247 if (command_byte == -1 || !set_controller_command_byte(sc->kbdc, 2248 kbdc_get_device_mask(sc->kbdc), 2249 KBD_DISABLE_KBD_PORT | KBD_DISABLE_KBD_INT | 2250 KBD_ENABLE_AUX_PORT | KBD_DISABLE_AUX_INT)) { 2251 /* CONTROLLER ERROR; do you know how to get out of this? */ 2252 kbdc_lock(sc->kbdc, FALSE); 2253 splx(s); 2254 log(LOG_ERR, 2255 "psm%d: unable to set the command byte (psmopen).\n", 2256 sc->unit); 2257 return (EIO); 2258 } 2259 /* 2260 * Now that the keyboard controller is told not to generate 2261 * the keyboard and mouse interrupts, call `splx()' to allow 2262 * the other tty interrupts. The clock interrupt may also occur, 2263 * but timeout routines will be blocked by the poll flag set 2264 * via `kbdc_lock()' 2265 */ 2266 splx(s); 2267 2268 /* enable the mouse device */ 2269 err = doopen(sc, command_byte); 2270 2271 /* done */ 2272 kbdc_lock(sc->kbdc, FALSE); 2273 return (err); 2274 } 2275 2276 static int 2277 psmclose(struct psm_softc *sc) 2278 { 2279 int stat[3]; 2280 int command_byte; 2281 int s; 2282 2283 /* don't let timeout routines in the keyboard driver to poll the kbdc */ 2284 if (!kbdc_lock(sc->kbdc, TRUE)) 2285 return (EIO); 2286 2287 /* save the current controller command byte */ 2288 s = spltty(); 2289 command_byte = get_controller_command_byte(sc->kbdc); 2290 if (command_byte == -1) { 2291 kbdc_lock(sc->kbdc, FALSE); 2292 splx(s); 2293 return (EIO); 2294 } 2295 2296 /* disable the aux interrupt and temporalily disable the keyboard */ 2297 if (!set_controller_command_byte(sc->kbdc, 2298 kbdc_get_device_mask(sc->kbdc), 2299 KBD_DISABLE_KBD_PORT | KBD_DISABLE_KBD_INT | 2300 KBD_ENABLE_AUX_PORT | KBD_DISABLE_AUX_INT)) { 2301 log(LOG_ERR, 2302 "psm%d: failed to disable the aux int (psmclose).\n", 2303 sc->unit); 2304 /* CONTROLLER ERROR; 2305 * NOTE: we shall force our way through. Because the only 2306 * ill effect we shall see is that we may not be able 2307 * to read ACK from the mouse, and it doesn't matter much 2308 * so long as the mouse will accept the DISABLE command. 2309 */ 2310 } 2311 splx(s); 2312 2313 /* stop the watchdog timer */ 2314 callout_stop(&sc->callout); 2315 2316 /* remove anything left in the output buffer */ 2317 empty_aux_buffer(sc->kbdc, 10); 2318 2319 /* disable the aux device, port and interrupt */ 2320 if (sc->state & PSM_VALID) { 2321 if (!disable_aux_dev(sc->kbdc)) { 2322 /* MOUSE ERROR; 2323 * NOTE: we don't return (error) and continue, 2324 * pretending we have successfully disabled the device. 2325 * It's OK because the interrupt routine will discard 2326 * any data from the mouse hereafter. 2327 */ 2328 log(LOG_ERR, 2329 "psm%d: failed to disable the device (psmclose).\n", 2330 sc->unit); 2331 } 2332 2333 if (get_mouse_status(sc->kbdc, stat, 0, 3) < 3) 2334 log(LOG_DEBUG, 2335 "psm%d: failed to get status (psmclose).\n", 2336 sc->unit); 2337 } 2338 2339 if (!set_controller_command_byte(sc->kbdc, 2340 kbdc_get_device_mask(sc->kbdc), 2341 (command_byte & KBD_KBD_CONTROL_BITS) | 2342 KBD_DISABLE_AUX_PORT | KBD_DISABLE_AUX_INT)) { 2343 /* 2344 * CONTROLLER ERROR; 2345 * we shall ignore this error; see the above comment. 2346 */ 2347 log(LOG_ERR, 2348 "psm%d: failed to disable the aux port (psmclose).\n", 2349 sc->unit); 2350 } 2351 2352 /* remove anything left in the output buffer */ 2353 empty_aux_buffer(sc->kbdc, 10); 2354 2355 /* close is almost always successful */ 2356 kbdc_lock(sc->kbdc, FALSE); 2357 return (0); 2358 } 2359 2360 static int 2361 tame_mouse(struct psm_softc *sc, packetbuf_t *pb, mousestatus_t *status, 2362 u_char *buf) 2363 { 2364 static u_char butmapps2[8] = { 2365 0, 2366 MOUSE_PS2_BUTTON1DOWN, 2367 MOUSE_PS2_BUTTON2DOWN, 2368 MOUSE_PS2_BUTTON1DOWN | MOUSE_PS2_BUTTON2DOWN, 2369 MOUSE_PS2_BUTTON3DOWN, 2370 MOUSE_PS2_BUTTON1DOWN | MOUSE_PS2_BUTTON3DOWN, 2371 MOUSE_PS2_BUTTON2DOWN | MOUSE_PS2_BUTTON3DOWN, 2372 MOUSE_PS2_BUTTON1DOWN | MOUSE_PS2_BUTTON2DOWN | 2373 MOUSE_PS2_BUTTON3DOWN, 2374 }; 2375 static u_char butmapmsc[8] = { 2376 MOUSE_MSC_BUTTON1UP | MOUSE_MSC_BUTTON2UP | 2377 MOUSE_MSC_BUTTON3UP, 2378 MOUSE_MSC_BUTTON2UP | MOUSE_MSC_BUTTON3UP, 2379 MOUSE_MSC_BUTTON1UP | MOUSE_MSC_BUTTON3UP, 2380 MOUSE_MSC_BUTTON3UP, 2381 MOUSE_MSC_BUTTON1UP | MOUSE_MSC_BUTTON2UP, 2382 MOUSE_MSC_BUTTON2UP, 2383 MOUSE_MSC_BUTTON1UP, 2384 0, 2385 }; 2386 int mapped; 2387 int i; 2388 2389 if (sc->mode.level == PSM_LEVEL_BASE) { 2390 mapped = status->button & ~MOUSE_BUTTON4DOWN; 2391 if (status->button & MOUSE_BUTTON4DOWN) 2392 mapped |= MOUSE_BUTTON1DOWN; 2393 status->button = mapped; 2394 buf[0] = MOUSE_PS2_SYNC | butmapps2[mapped & MOUSE_STDBUTTONS]; 2395 i = imax(imin(status->dx, 255), -256); 2396 if (i < 0) 2397 buf[0] |= MOUSE_PS2_XNEG; 2398 buf[1] = i; 2399 i = imax(imin(status->dy, 255), -256); 2400 if (i < 0) 2401 buf[0] |= MOUSE_PS2_YNEG; 2402 buf[2] = i; 2403 return (MOUSE_PS2_PACKETSIZE); 2404 } else if (sc->mode.level == PSM_LEVEL_STANDARD) { 2405 buf[0] = MOUSE_MSC_SYNC | 2406 butmapmsc[status->button & MOUSE_STDBUTTONS]; 2407 i = imax(imin(status->dx, 255), -256); 2408 buf[1] = i >> 1; 2409 buf[3] = i - buf[1]; 2410 i = imax(imin(status->dy, 255), -256); 2411 buf[2] = i >> 1; 2412 buf[4] = i - buf[2]; 2413 i = imax(imin(status->dz, 127), -128); 2414 buf[5] = (i >> 1) & 0x7f; 2415 buf[6] = (i - (i >> 1)) & 0x7f; 2416 buf[7] = (~status->button >> 3) & 0x7f; 2417 return (MOUSE_SYS_PACKETSIZE); 2418 } 2419 return (pb->inputbytes); 2420 } 2421 2422 static int 2423 psmread(struct cdev *dev, struct uio *uio, int flag) 2424 { 2425 struct psm_softc *sc = dev->si_drv1; 2426 u_char buf[PSM_SMALLBUFSIZE]; 2427 int error = 0; 2428 int s; 2429 int l; 2430 2431 if ((sc->state & PSM_VALID) == 0) 2432 return (EIO); 2433 2434 /* block until mouse activity occurred */ 2435 s = spltty(); 2436 while (sc->queue.count <= 0) { 2437 if (dev != sc->bdev) { 2438 splx(s); 2439 return (EWOULDBLOCK); 2440 } 2441 sc->state |= PSM_ASLP; 2442 error = tsleep(sc, PZERO | PCATCH, "psmrea", 0); 2443 sc->state &= ~PSM_ASLP; 2444 if (error) { 2445 splx(s); 2446 return (error); 2447 } else if ((sc->state & PSM_VALID) == 0) { 2448 /* the device disappeared! */ 2449 splx(s); 2450 return (EIO); 2451 } 2452 } 2453 splx(s); 2454 2455 /* copy data to the user land */ 2456 while ((sc->queue.count > 0) && (uio->uio_resid > 0)) { 2457 s = spltty(); 2458 l = imin(sc->queue.count, uio->uio_resid); 2459 if (l > sizeof(buf)) 2460 l = sizeof(buf); 2461 if (l > sizeof(sc->queue.buf) - sc->queue.head) { 2462 bcopy(&sc->queue.buf[sc->queue.head], &buf[0], 2463 sizeof(sc->queue.buf) - sc->queue.head); 2464 bcopy(&sc->queue.buf[0], 2465 &buf[sizeof(sc->queue.buf) - sc->queue.head], 2466 l - (sizeof(sc->queue.buf) - sc->queue.head)); 2467 } else 2468 bcopy(&sc->queue.buf[sc->queue.head], &buf[0], l); 2469 sc->queue.count -= l; 2470 sc->queue.head = (sc->queue.head + l) % sizeof(sc->queue.buf); 2471 splx(s); 2472 error = uiomove(buf, l, uio); 2473 if (error) 2474 break; 2475 } 2476 2477 return (error); 2478 } 2479 2480 static int 2481 block_mouse_data(struct psm_softc *sc, int *c) 2482 { 2483 int s; 2484 2485 if (!kbdc_lock(sc->kbdc, TRUE)) 2486 return (EIO); 2487 2488 s = spltty(); 2489 *c = get_controller_command_byte(sc->kbdc); 2490 if ((*c == -1) || !set_controller_command_byte(sc->kbdc, 2491 kbdc_get_device_mask(sc->kbdc), 2492 KBD_DISABLE_KBD_PORT | KBD_DISABLE_KBD_INT | 2493 KBD_ENABLE_AUX_PORT | KBD_DISABLE_AUX_INT)) { 2494 /* this is CONTROLLER ERROR */ 2495 splx(s); 2496 kbdc_lock(sc->kbdc, FALSE); 2497 return (EIO); 2498 } 2499 2500 /* 2501 * The device may be in the middle of status data transmission. 2502 * The transmission will be interrupted, thus, incomplete status 2503 * data must be discarded. Although the aux interrupt is disabled 2504 * at the keyboard controller level, at most one aux interrupt 2505 * may have already been pending and a data byte is in the 2506 * output buffer; throw it away. Note that the second argument 2507 * to `empty_aux_buffer()' is zero, so that the call will just 2508 * flush the internal queue. 2509 * `psmintr()' will be invoked after `splx()' if an interrupt is 2510 * pending; it will see no data and returns immediately. 2511 */ 2512 empty_aux_buffer(sc->kbdc, 0); /* flush the queue */ 2513 read_aux_data_no_wait(sc->kbdc); /* throw away data if any */ 2514 flushpackets(sc); 2515 splx(s); 2516 2517 return (0); 2518 } 2519 2520 static void 2521 dropqueue(struct psm_softc *sc) 2522 { 2523 2524 sc->queue.count = 0; 2525 sc->queue.head = 0; 2526 sc->queue.tail = 0; 2527 if ((sc->state & PSM_SOFTARMED) != 0) { 2528 sc->state &= ~PSM_SOFTARMED; 2529 callout_stop(&sc->softcallout); 2530 } 2531 sc->pqueue_start = sc->pqueue_end; 2532 } 2533 2534 static void 2535 flushpackets(struct psm_softc *sc) 2536 { 2537 2538 dropqueue(sc); 2539 bzero(&sc->pqueue, sizeof(sc->pqueue)); 2540 } 2541 2542 static int 2543 unblock_mouse_data(struct psm_softc *sc, int c) 2544 { 2545 int error = 0; 2546 2547 /* 2548 * We may have seen a part of status data during `set_mouse_XXX()'. 2549 * they have been queued; flush it. 2550 */ 2551 empty_aux_buffer(sc->kbdc, 0); 2552 2553 /* restore ports and interrupt */ 2554 if (!set_controller_command_byte(sc->kbdc, 2555 kbdc_get_device_mask(sc->kbdc), 2556 c & (KBD_KBD_CONTROL_BITS | KBD_AUX_CONTROL_BITS))) { 2557 /* 2558 * CONTROLLER ERROR; this is serious, we may have 2559 * been left with the inaccessible keyboard and 2560 * the disabled mouse interrupt. 2561 */ 2562 error = EIO; 2563 } 2564 2565 kbdc_lock(sc->kbdc, FALSE); 2566 return (error); 2567 } 2568 2569 static int 2570 psmwrite(struct cdev *dev, struct uio *uio, int flag) 2571 { 2572 struct psm_softc *sc = dev->si_drv1; 2573 u_char buf[PSM_SMALLBUFSIZE]; 2574 int error = 0, i, l; 2575 2576 if ((sc->state & PSM_VALID) == 0) 2577 return (EIO); 2578 2579 if (sc->mode.level < PSM_LEVEL_NATIVE) 2580 return (ENODEV); 2581 2582 /* copy data from the user land */ 2583 while (uio->uio_resid > 0) { 2584 l = imin(PSM_SMALLBUFSIZE, uio->uio_resid); 2585 error = uiomove(buf, l, uio); 2586 if (error) 2587 break; 2588 for (i = 0; i < l; i++) { 2589 VLOG(4, (LOG_DEBUG, "psm: cmd 0x%x\n", buf[i])); 2590 if (!write_aux_command(sc->kbdc, buf[i])) { 2591 VLOG(2, (LOG_DEBUG, 2592 "psm: cmd 0x%x failed.\n", buf[i])); 2593 return (reinitialize(sc, FALSE)); 2594 } 2595 } 2596 } 2597 2598 return (error); 2599 } 2600 2601 static int 2602 psmioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag, 2603 struct thread *td) 2604 { 2605 struct psm_softc *sc = dev->si_drv1; 2606 mousemode_t mode; 2607 mousestatus_t status; 2608 mousedata_t *data; 2609 int stat[3]; 2610 int command_byte; 2611 int error = 0; 2612 int s; 2613 2614 /* Perform IOCTL command */ 2615 switch (cmd) { 2616 2617 case OLD_MOUSE_GETHWINFO: 2618 s = spltty(); 2619 ((old_mousehw_t *)addr)->buttons = sc->hw.buttons; 2620 ((old_mousehw_t *)addr)->iftype = sc->hw.iftype; 2621 ((old_mousehw_t *)addr)->type = sc->hw.type; 2622 ((old_mousehw_t *)addr)->hwid = sc->hw.hwid & 0x00ff; 2623 splx(s); 2624 break; 2625 2626 case MOUSE_GETHWINFO: 2627 s = spltty(); 2628 *(mousehw_t *)addr = sc->hw; 2629 if (sc->mode.level == PSM_LEVEL_BASE) 2630 ((mousehw_t *)addr)->model = MOUSE_MODEL_GENERIC; 2631 splx(s); 2632 break; 2633 2634 case MOUSE_SYN_GETHWINFO: 2635 s = spltty(); 2636 if (sc->synhw.infoMajor >= 4) 2637 *(synapticshw_t *)addr = sc->synhw; 2638 else 2639 error = EINVAL; 2640 splx(s); 2641 break; 2642 2643 case OLD_MOUSE_GETMODE: 2644 s = spltty(); 2645 switch (sc->mode.level) { 2646 case PSM_LEVEL_BASE: 2647 ((old_mousemode_t *)addr)->protocol = MOUSE_PROTO_PS2; 2648 break; 2649 case PSM_LEVEL_STANDARD: 2650 ((old_mousemode_t *)addr)->protocol = 2651 MOUSE_PROTO_SYSMOUSE; 2652 break; 2653 case PSM_LEVEL_NATIVE: 2654 ((old_mousemode_t *)addr)->protocol = MOUSE_PROTO_PS2; 2655 break; 2656 } 2657 ((old_mousemode_t *)addr)->rate = sc->mode.rate; 2658 ((old_mousemode_t *)addr)->resolution = sc->mode.resolution; 2659 ((old_mousemode_t *)addr)->accelfactor = sc->mode.accelfactor; 2660 splx(s); 2661 break; 2662 2663 case MOUSE_GETMODE: 2664 s = spltty(); 2665 *(mousemode_t *)addr = sc->mode; 2666 if ((sc->flags & PSM_NEED_SYNCBITS) != 0) { 2667 ((mousemode_t *)addr)->syncmask[0] = 0; 2668 ((mousemode_t *)addr)->syncmask[1] = 0; 2669 } 2670 ((mousemode_t *)addr)->resolution = 2671 MOUSE_RES_LOW - sc->mode.resolution; 2672 switch (sc->mode.level) { 2673 case PSM_LEVEL_BASE: 2674 ((mousemode_t *)addr)->protocol = MOUSE_PROTO_PS2; 2675 ((mousemode_t *)addr)->packetsize = 2676 MOUSE_PS2_PACKETSIZE; 2677 break; 2678 case PSM_LEVEL_STANDARD: 2679 ((mousemode_t *)addr)->protocol = MOUSE_PROTO_SYSMOUSE; 2680 ((mousemode_t *)addr)->packetsize = 2681 MOUSE_SYS_PACKETSIZE; 2682 ((mousemode_t *)addr)->syncmask[0] = MOUSE_SYS_SYNCMASK; 2683 ((mousemode_t *)addr)->syncmask[1] = MOUSE_SYS_SYNC; 2684 break; 2685 case PSM_LEVEL_NATIVE: 2686 /* FIXME: this isn't quite correct... XXX */ 2687 ((mousemode_t *)addr)->protocol = MOUSE_PROTO_PS2; 2688 break; 2689 } 2690 splx(s); 2691 break; 2692 2693 case OLD_MOUSE_SETMODE: 2694 case MOUSE_SETMODE: 2695 if (cmd == OLD_MOUSE_SETMODE) { 2696 mode.rate = ((old_mousemode_t *)addr)->rate; 2697 /* 2698 * resolution old I/F new I/F 2699 * default 0 0 2700 * low 1 -2 2701 * medium low 2 -3 2702 * medium high 3 -4 2703 * high 4 -5 2704 */ 2705 if (((old_mousemode_t *)addr)->resolution > 0) 2706 mode.resolution = 2707 -((old_mousemode_t *)addr)->resolution - 1; 2708 else 2709 mode.resolution = 0; 2710 mode.accelfactor = 2711 ((old_mousemode_t *)addr)->accelfactor; 2712 mode.level = -1; 2713 } else 2714 mode = *(mousemode_t *)addr; 2715 2716 /* adjust and validate parameters. */ 2717 if (mode.rate > UCHAR_MAX) 2718 return (EINVAL); 2719 if (mode.rate == 0) 2720 mode.rate = sc->dflt_mode.rate; 2721 else if (mode.rate == -1) 2722 /* don't change the current setting */ 2723 ; 2724 else if (mode.rate < 0) 2725 return (EINVAL); 2726 if (mode.resolution >= UCHAR_MAX) 2727 return (EINVAL); 2728 if (mode.resolution >= 200) 2729 mode.resolution = MOUSE_RES_HIGH; 2730 else if (mode.resolution >= 100) 2731 mode.resolution = MOUSE_RES_MEDIUMHIGH; 2732 else if (mode.resolution >= 50) 2733 mode.resolution = MOUSE_RES_MEDIUMLOW; 2734 else if (mode.resolution > 0) 2735 mode.resolution = MOUSE_RES_LOW; 2736 if (mode.resolution == MOUSE_RES_DEFAULT) 2737 mode.resolution = sc->dflt_mode.resolution; 2738 else if (mode.resolution == -1) 2739 /* don't change the current setting */ 2740 ; 2741 else if (mode.resolution < 0) /* MOUSE_RES_LOW/MEDIUM/HIGH */ 2742 mode.resolution = MOUSE_RES_LOW - mode.resolution; 2743 if (mode.level == -1) 2744 /* don't change the current setting */ 2745 mode.level = sc->mode.level; 2746 else if ((mode.level < PSM_LEVEL_MIN) || 2747 (mode.level > PSM_LEVEL_MAX)) 2748 return (EINVAL); 2749 if (mode.accelfactor == -1) 2750 /* don't change the current setting */ 2751 mode.accelfactor = sc->mode.accelfactor; 2752 else if (mode.accelfactor < 0) 2753 return (EINVAL); 2754 2755 /* don't allow anybody to poll the keyboard controller */ 2756 error = block_mouse_data(sc, &command_byte); 2757 if (error) 2758 return (error); 2759 2760 /* set mouse parameters */ 2761 if (mode.rate > 0) 2762 mode.rate = set_mouse_sampling_rate(sc->kbdc, 2763 mode.rate); 2764 if (mode.resolution >= 0) 2765 mode.resolution = 2766 set_mouse_resolution(sc->kbdc, mode.resolution); 2767 set_mouse_scaling(sc->kbdc, 1); 2768 get_mouse_status(sc->kbdc, stat, 0, 3); 2769 2770 s = spltty(); 2771 sc->mode.rate = mode.rate; 2772 sc->mode.resolution = mode.resolution; 2773 sc->mode.accelfactor = mode.accelfactor; 2774 sc->mode.level = mode.level; 2775 splx(s); 2776 2777 unblock_mouse_data(sc, command_byte); 2778 break; 2779 2780 case MOUSE_GETLEVEL: 2781 *(int *)addr = sc->mode.level; 2782 break; 2783 2784 case MOUSE_SETLEVEL: 2785 if ((*(int *)addr < PSM_LEVEL_MIN) || 2786 (*(int *)addr > PSM_LEVEL_MAX)) 2787 return (EINVAL); 2788 sc->mode.level = *(int *)addr; 2789 break; 2790 2791 case MOUSE_GETSTATUS: 2792 s = spltty(); 2793 status = sc->status; 2794 sc->status.flags = 0; 2795 sc->status.obutton = sc->status.button; 2796 sc->status.button = 0; 2797 sc->status.dx = 0; 2798 sc->status.dy = 0; 2799 sc->status.dz = 0; 2800 splx(s); 2801 *(mousestatus_t *)addr = status; 2802 break; 2803 2804 case MOUSE_READSTATE: 2805 case MOUSE_READDATA: 2806 data = (mousedata_t *)addr; 2807 if (data->len > sizeof(data->buf)/sizeof(data->buf[0])) 2808 return (EINVAL); 2809 2810 error = block_mouse_data(sc, &command_byte); 2811 if (error) 2812 return (error); 2813 if ((data->len = get_mouse_status(sc->kbdc, data->buf, 2814 (cmd == MOUSE_READDATA) ? 1 : 0, data->len)) <= 0) 2815 error = EIO; 2816 unblock_mouse_data(sc, command_byte); 2817 break; 2818 2819 #if (defined(MOUSE_SETRESOLUTION)) 2820 case MOUSE_SETRESOLUTION: 2821 mode.resolution = *(int *)addr; 2822 if (mode.resolution >= UCHAR_MAX) 2823 return (EINVAL); 2824 else if (mode.resolution >= 200) 2825 mode.resolution = MOUSE_RES_HIGH; 2826 else if (mode.resolution >= 100) 2827 mode.resolution = MOUSE_RES_MEDIUMHIGH; 2828 else if (mode.resolution >= 50) 2829 mode.resolution = MOUSE_RES_MEDIUMLOW; 2830 else if (mode.resolution > 0) 2831 mode.resolution = MOUSE_RES_LOW; 2832 if (mode.resolution == MOUSE_RES_DEFAULT) 2833 mode.resolution = sc->dflt_mode.resolution; 2834 else if (mode.resolution == -1) 2835 mode.resolution = sc->mode.resolution; 2836 else if (mode.resolution < 0) /* MOUSE_RES_LOW/MEDIUM/HIGH */ 2837 mode.resolution = MOUSE_RES_LOW - mode.resolution; 2838 2839 error = block_mouse_data(sc, &command_byte); 2840 if (error) 2841 return (error); 2842 sc->mode.resolution = 2843 set_mouse_resolution(sc->kbdc, mode.resolution); 2844 if (sc->mode.resolution != mode.resolution) 2845 error = EIO; 2846 unblock_mouse_data(sc, command_byte); 2847 break; 2848 #endif /* MOUSE_SETRESOLUTION */ 2849 2850 #if (defined(MOUSE_SETRATE)) 2851 case MOUSE_SETRATE: 2852 mode.rate = *(int *)addr; 2853 if (mode.rate > UCHAR_MAX) 2854 return (EINVAL); 2855 if (mode.rate == 0) 2856 mode.rate = sc->dflt_mode.rate; 2857 else if (mode.rate < 0) 2858 mode.rate = sc->mode.rate; 2859 2860 error = block_mouse_data(sc, &command_byte); 2861 if (error) 2862 return (error); 2863 sc->mode.rate = set_mouse_sampling_rate(sc->kbdc, mode.rate); 2864 if (sc->mode.rate != mode.rate) 2865 error = EIO; 2866 unblock_mouse_data(sc, command_byte); 2867 break; 2868 #endif /* MOUSE_SETRATE */ 2869 2870 #if (defined(MOUSE_SETSCALING)) 2871 case MOUSE_SETSCALING: 2872 if ((*(int *)addr <= 0) || (*(int *)addr > 2)) 2873 return (EINVAL); 2874 2875 error = block_mouse_data(sc, &command_byte); 2876 if (error) 2877 return (error); 2878 if (!set_mouse_scaling(sc->kbdc, *(int *)addr)) 2879 error = EIO; 2880 unblock_mouse_data(sc, command_byte); 2881 break; 2882 #endif /* MOUSE_SETSCALING */ 2883 2884 #if (defined(MOUSE_GETHWID)) 2885 case MOUSE_GETHWID: 2886 error = block_mouse_data(sc, &command_byte); 2887 if (error) 2888 return (error); 2889 sc->hw.hwid &= ~0x00ff; 2890 sc->hw.hwid |= get_aux_id(sc->kbdc); 2891 *(int *)addr = sc->hw.hwid & 0x00ff; 2892 unblock_mouse_data(sc, command_byte); 2893 break; 2894 #endif /* MOUSE_GETHWID */ 2895 2896 case FIONBIO: 2897 case FIOASYNC: 2898 break; 2899 case FIOSETOWN: 2900 error = fsetown(*(int *)addr, &sc->async); 2901 break; 2902 case FIOGETOWN: 2903 *(int *) addr = fgetown(&sc->async); 2904 break; 2905 default: 2906 return (ENOTTY); 2907 } 2908 2909 return (error); 2910 } 2911 2912 static void 2913 psmtimeout(void *arg) 2914 { 2915 struct psm_softc *sc; 2916 int s; 2917 2918 sc = (struct psm_softc *)arg; 2919 s = spltty(); 2920 if (sc->watchdog && kbdc_lock(sc->kbdc, TRUE)) { 2921 VLOG(6, (LOG_DEBUG, "psm%d: lost interrupt?\n", sc->unit)); 2922 psmintr(sc); 2923 kbdc_lock(sc->kbdc, FALSE); 2924 } 2925 sc->watchdog = TRUE; 2926 splx(s); 2927 callout_reset(&sc->callout, hz, psmtimeout, sc); 2928 } 2929 2930 /* Add all sysctls under the debug.psm and hw.psm nodes */ 2931 static SYSCTL_NODE(_debug, OID_AUTO, psm, CTLFLAG_RD, 0, "ps/2 mouse"); 2932 static SYSCTL_NODE(_hw, OID_AUTO, psm, CTLFLAG_RD, 0, "ps/2 mouse"); 2933 2934 SYSCTL_INT(_debug_psm, OID_AUTO, loglevel, CTLFLAG_RWTUN, &verbose, 0, 2935 "Verbosity level"); 2936 2937 static int psmhz = 20; 2938 SYSCTL_INT(_debug_psm, OID_AUTO, hz, CTLFLAG_RW, &psmhz, 0, 2939 "Frequency of the softcallout (in hz)"); 2940 static int psmerrsecs = 2; 2941 SYSCTL_INT(_debug_psm, OID_AUTO, errsecs, CTLFLAG_RW, &psmerrsecs, 0, 2942 "Number of seconds during which packets will dropped after a sync error"); 2943 static int psmerrusecs = 0; 2944 SYSCTL_INT(_debug_psm, OID_AUTO, errusecs, CTLFLAG_RW, &psmerrusecs, 0, 2945 "Microseconds to add to psmerrsecs"); 2946 static int psmsecs = 0; 2947 SYSCTL_INT(_debug_psm, OID_AUTO, secs, CTLFLAG_RW, &psmsecs, 0, 2948 "Max number of seconds between soft interrupts"); 2949 static int psmusecs = 500000; 2950 SYSCTL_INT(_debug_psm, OID_AUTO, usecs, CTLFLAG_RW, &psmusecs, 0, 2951 "Microseconds to add to psmsecs"); 2952 static int pkterrthresh = 2; 2953 SYSCTL_INT(_debug_psm, OID_AUTO, pkterrthresh, CTLFLAG_RW, &pkterrthresh, 0, 2954 "Number of error packets allowed before reinitializing the mouse"); 2955 2956 SYSCTL_INT(_hw_psm, OID_AUTO, tap_enabled, CTLFLAG_RWTUN, &tap_enabled, 0, 2957 "Enable tap and drag gestures"); 2958 static int tap_threshold = PSM_TAP_THRESHOLD; 2959 SYSCTL_INT(_hw_psm, OID_AUTO, tap_threshold, CTLFLAG_RW, &tap_threshold, 0, 2960 "Button tap threshold"); 2961 static int tap_timeout = PSM_TAP_TIMEOUT; 2962 SYSCTL_INT(_hw_psm, OID_AUTO, tap_timeout, CTLFLAG_RW, &tap_timeout, 0, 2963 "Tap timeout for touchpads"); 2964 2965 /* Tunables */ 2966 SYSCTL_INT(_hw_psm, OID_AUTO, synaptics_support, CTLFLAG_RDTUN, 2967 &synaptics_support, 0, "Enable support for Synaptics touchpads"); 2968 2969 SYSCTL_INT(_hw_psm, OID_AUTO, trackpoint_support, CTLFLAG_RDTUN, 2970 &trackpoint_support, 0, "Enable support for IBM/Lenovo TrackPoint"); 2971 2972 SYSCTL_INT(_hw_psm, OID_AUTO, elantech_support, CTLFLAG_RDTUN, 2973 &elantech_support, 0, "Enable support for Elantech touchpads"); 2974 2975 static void 2976 psmintr(void *arg) 2977 { 2978 struct psm_softc *sc = arg; 2979 struct timeval now; 2980 int c; 2981 packetbuf_t *pb; 2982 2983 if (aux_mux_is_enabled(sc->kbdc)) 2984 VLOG(2, (LOG_DEBUG, "psmintr: active multiplexing mode is not " 2985 "supported!\n")); 2986 2987 /* read until there is nothing to read */ 2988 while((c = read_aux_data_no_wait(sc->kbdc)) != -1) { 2989 pb = &sc->pqueue[sc->pqueue_end]; 2990 2991 /* discard the byte if the device is not open */ 2992 if (!(sc->state & (PSM_OPEN | PSM_EV_OPEN_R | PSM_EV_OPEN_A))) 2993 continue; 2994 2995 getmicrouptime(&now); 2996 if ((pb->inputbytes > 0) && 2997 timevalcmp(&now, &sc->inputtimeout, >)) { 2998 VLOG(3, (LOG_DEBUG, "psmintr: delay too long; " 2999 "resetting byte count\n")); 3000 pb->inputbytes = 0; 3001 sc->syncerrors = 0; 3002 sc->pkterrors = 0; 3003 } 3004 sc->inputtimeout.tv_sec = PSM_INPUT_TIMEOUT / 1000000; 3005 sc->inputtimeout.tv_usec = PSM_INPUT_TIMEOUT % 1000000; 3006 timevaladd(&sc->inputtimeout, &now); 3007 3008 pb->ipacket[pb->inputbytes++] = c; 3009 3010 if (sc->mode.level == PSM_LEVEL_NATIVE) { 3011 VLOG(4, (LOG_DEBUG, "psmintr: %02x\n", pb->ipacket[0])); 3012 sc->syncerrors = 0; 3013 sc->pkterrors = 0; 3014 goto next; 3015 } else { 3016 if (pb->inputbytes < sc->mode.packetsize) 3017 continue; 3018 3019 VLOG(4, (LOG_DEBUG, 3020 "psmintr: %02x %02x %02x %02x %02x %02x\n", 3021 pb->ipacket[0], pb->ipacket[1], pb->ipacket[2], 3022 pb->ipacket[3], pb->ipacket[4], pb->ipacket[5])); 3023 } 3024 3025 c = pb->ipacket[0]; 3026 3027 if ((sc->flags & PSM_NEED_SYNCBITS) != 0) { 3028 sc->mode.syncmask[1] = (c & sc->mode.syncmask[0]); 3029 sc->flags &= ~PSM_NEED_SYNCBITS; 3030 VLOG(2, (LOG_DEBUG, 3031 "psmintr: Sync bytes now %04x,%04x\n", 3032 sc->mode.syncmask[0], sc->mode.syncmask[1])); 3033 } else if ((sc->config & PSM_CONFIG_NOCHECKSYNC) == 0 && 3034 (c & sc->mode.syncmask[0]) != sc->mode.syncmask[1]) { 3035 VLOG(3, (LOG_DEBUG, "psmintr: out of sync " 3036 "(%04x != %04x) %d cmds since last error.\n", 3037 c & sc->mode.syncmask[0], sc->mode.syncmask[1], 3038 sc->cmdcount - sc->lasterr)); 3039 sc->lasterr = sc->cmdcount; 3040 /* 3041 * The sync byte test is a weak measure of packet 3042 * validity. Conservatively discard any input yet 3043 * to be seen by userland when we detect a sync 3044 * error since there is a good chance some of 3045 * the queued packets have undetected errors. 3046 */ 3047 dropqueue(sc); 3048 if (sc->syncerrors == 0) 3049 sc->pkterrors++; 3050 ++sc->syncerrors; 3051 sc->lastinputerr = now; 3052 if (sc->syncerrors >= sc->mode.packetsize * 2 || 3053 sc->pkterrors >= pkterrthresh) { 3054 /* 3055 * If we've failed to find a single sync byte 3056 * in 2 packets worth of data, or we've seen 3057 * persistent packet errors during the 3058 * validation period, reinitialize the mouse 3059 * in hopes of returning it to the expected 3060 * mode. 3061 */ 3062 VLOG(3, (LOG_DEBUG, 3063 "psmintr: reset the mouse.\n")); 3064 reinitialize(sc, TRUE); 3065 } else if (sc->syncerrors == sc->mode.packetsize) { 3066 /* 3067 * Try a soft reset after searching for a sync 3068 * byte through a packet length of bytes. 3069 */ 3070 VLOG(3, (LOG_DEBUG, 3071 "psmintr: re-enable the mouse.\n")); 3072 pb->inputbytes = 0; 3073 disable_aux_dev(sc->kbdc); 3074 enable_aux_dev(sc->kbdc); 3075 } else { 3076 VLOG(3, (LOG_DEBUG, 3077 "psmintr: discard a byte (%d)\n", 3078 sc->syncerrors)); 3079 pb->inputbytes--; 3080 bcopy(&pb->ipacket[1], &pb->ipacket[0], 3081 pb->inputbytes); 3082 } 3083 continue; 3084 } 3085 3086 /* 3087 * We have what appears to be a valid packet. 3088 * Reset the error counters. 3089 */ 3090 sc->syncerrors = 0; 3091 3092 /* 3093 * Drop even good packets if they occur within a timeout 3094 * period of a sync error. This allows the detection of 3095 * a change in the mouse's packet mode without exposing 3096 * erratic mouse behavior to the user. Some KVMs forget 3097 * enhanced mouse modes during switch events. 3098 */ 3099 if (!timeelapsed(&sc->lastinputerr, psmerrsecs, psmerrusecs, 3100 &now)) { 3101 pb->inputbytes = 0; 3102 continue; 3103 } 3104 3105 /* 3106 * Now that we're out of the validation period, reset 3107 * the packet error count. 3108 */ 3109 sc->pkterrors = 0; 3110 3111 sc->cmdcount++; 3112 next: 3113 if (++sc->pqueue_end >= PSM_PACKETQUEUE) 3114 sc->pqueue_end = 0; 3115 /* 3116 * If we've filled the queue then call the softintr ourselves, 3117 * otherwise schedule the interrupt for later. 3118 */ 3119 if (!timeelapsed(&sc->lastsoftintr, psmsecs, psmusecs, &now) || 3120 (sc->pqueue_end == sc->pqueue_start)) { 3121 if ((sc->state & PSM_SOFTARMED) != 0) { 3122 sc->state &= ~PSM_SOFTARMED; 3123 callout_stop(&sc->softcallout); 3124 } 3125 psmsoftintr(arg); 3126 } else if ((sc->state & PSM_SOFTARMED) == 0) { 3127 sc->state |= PSM_SOFTARMED; 3128 callout_reset(&sc->softcallout, 3129 psmhz < 1 ? 1 : (hz/psmhz), psmsoftintr, arg); 3130 } 3131 } 3132 } 3133 3134 static void 3135 proc_mmanplus(struct psm_softc *sc, packetbuf_t *pb, mousestatus_t *ms, 3136 int *x, int *y, int *z) 3137 { 3138 3139 /* 3140 * PS2++ protocol packet 3141 * 3142 * b7 b6 b5 b4 b3 b2 b1 b0 3143 * byte 1: * 1 p3 p2 1 * * * 3144 * byte 2: c1 c2 p1 p0 d1 d0 1 0 3145 * 3146 * p3-p0: packet type 3147 * c1, c2: c1 & c2 == 1, if p2 == 0 3148 * c1 & c2 == 0, if p2 == 1 3149 * 3150 * packet type: 0 (device type) 3151 * See comments in enable_mmanplus() below. 3152 * 3153 * packet type: 1 (wheel data) 3154 * 3155 * b7 b6 b5 b4 b3 b2 b1 b0 3156 * byte 3: h * B5 B4 s d2 d1 d0 3157 * 3158 * h: 1, if horizontal roller data 3159 * 0, if vertical roller data 3160 * B4, B5: button 4 and 5 3161 * s: sign bit 3162 * d2-d0: roller data 3163 * 3164 * packet type: 2 (reserved) 3165 */ 3166 if (((pb->ipacket[0] & MOUSE_PS2PLUS_SYNCMASK) == MOUSE_PS2PLUS_SYNC) && 3167 (abs(*x) > 191) && MOUSE_PS2PLUS_CHECKBITS(pb->ipacket)) { 3168 /* 3169 * the extended data packet encodes button 3170 * and wheel events 3171 */ 3172 switch (MOUSE_PS2PLUS_PACKET_TYPE(pb->ipacket)) { 3173 case 1: 3174 /* wheel data packet */ 3175 *x = *y = 0; 3176 if (pb->ipacket[2] & 0x80) { 3177 /* XXX horizontal roller count - ignore it */ 3178 ; 3179 } else { 3180 /* vertical roller count */ 3181 *z = (pb->ipacket[2] & MOUSE_PS2PLUS_ZNEG) ? 3182 (pb->ipacket[2] & 0x0f) - 16 : 3183 (pb->ipacket[2] & 0x0f); 3184 } 3185 ms->button |= (pb->ipacket[2] & 3186 MOUSE_PS2PLUS_BUTTON4DOWN) ? 3187 MOUSE_BUTTON4DOWN : 0; 3188 ms->button |= (pb->ipacket[2] & 3189 MOUSE_PS2PLUS_BUTTON5DOWN) ? 3190 MOUSE_BUTTON5DOWN : 0; 3191 break; 3192 case 2: 3193 /* 3194 * this packet type is reserved by 3195 * Logitech... 3196 */ 3197 /* 3198 * IBM ScrollPoint Mouse uses this 3199 * packet type to encode both vertical 3200 * and horizontal scroll movement. 3201 */ 3202 *x = *y = 0; 3203 /* horizontal count */ 3204 if (pb->ipacket[2] & 0x0f) 3205 *z = (pb->ipacket[2] & MOUSE_SPOINT_WNEG) ? 3206 -2 : 2; 3207 /* vertical count */ 3208 if (pb->ipacket[2] & 0xf0) 3209 *z = (pb->ipacket[2] & MOUSE_SPOINT_ZNEG) ? 3210 -1 : 1; 3211 break; 3212 case 0: 3213 /* device type packet - shouldn't happen */ 3214 /* FALLTHROUGH */ 3215 default: 3216 *x = *y = 0; 3217 ms->button = ms->obutton; 3218 VLOG(1, (LOG_DEBUG, "psmintr: unknown PS2++ packet " 3219 "type %d: 0x%02x 0x%02x 0x%02x\n", 3220 MOUSE_PS2PLUS_PACKET_TYPE(pb->ipacket), 3221 pb->ipacket[0], pb->ipacket[1], pb->ipacket[2])); 3222 break; 3223 } 3224 } else { 3225 /* preserve button states */ 3226 ms->button |= ms->obutton & MOUSE_EXTBUTTONS; 3227 } 3228 } 3229 3230 static int 3231 proc_synaptics(struct psm_softc *sc, packetbuf_t *pb, mousestatus_t *ms, 3232 int *x, int *y, int *z) 3233 { 3234 static int touchpad_buttons; 3235 static int guest_buttons; 3236 static int ew_finger_count; 3237 static finger_t f[PSM_FINGERS]; 3238 int w, id, nfingers, palm, ewcode, extended_buttons, clickpad_pressed; 3239 3240 extended_buttons = 0; 3241 3242 /* TouchPad PS/2 absolute mode message format with capFourButtons: 3243 * 3244 * Bits: 7 6 5 4 3 2 1 0 (LSB) 3245 * ------------------------------------------------ 3246 * ipacket[0]: 1 0 W3 W2 0 W1 R L 3247 * ipacket[1]: Yb Ya Y9 Y8 Xb Xa X9 X8 3248 * ipacket[2]: Z7 Z6 Z5 Z4 Z3 Z2 Z1 Z0 3249 * ipacket[3]: 1 1 Yc Xc 0 W0 D^R U^L 3250 * ipacket[4]: X7 X6 X5 X4 X3 X2 X1 X0 3251 * ipacket[5]: Y7 Y6 Y5 Y4 Y3 Y2 Y1 Y0 3252 * 3253 * Legend: 3254 * L: left physical mouse button 3255 * R: right physical mouse button 3256 * D: down button 3257 * U: up button 3258 * W: "wrist" value 3259 * X: x position 3260 * Y: y position 3261 * Z: pressure 3262 * 3263 * Without capFourButtons but with nExtendeButtons and/or capMiddle 3264 * 3265 * Bits: 7 6 5 4 3 2 1 0 (LSB) 3266 * ------------------------------------------------------ 3267 * ipacket[3]: 1 1 Yc Xc 0 W0 E^R M^L 3268 * ipacket[4]: X7 X6 X5 X4 X3|b7 X2|b5 X1|b3 X0|b1 3269 * ipacket[5]: Y7 Y6 Y5 Y4 Y3|b8 Y2|b6 Y1|b4 Y0|b2 3270 * 3271 * Legend: 3272 * M: Middle physical mouse button 3273 * E: Extended mouse buttons reported instead of low bits of X and Y 3274 * b1-b8: Extended mouse buttons 3275 * Only ((nExtendedButtons + 1) >> 1) bits are used in packet 3276 * 4 and 5, for reading X and Y value they should be zeroed. 3277 * 3278 * Absolute reportable limits: 0 - 6143. 3279 * Typical bezel limits: 1472 - 5472. 3280 * Typical edge marings: 1632 - 5312. 3281 * 3282 * w = 3 Passthrough Packet 3283 * 3284 * Byte 2,5,6 == Byte 1,2,3 of "Guest" 3285 */ 3286 3287 if (!synaptics_support) 3288 return (0); 3289 3290 /* Sanity check for out of sync packets. */ 3291 if ((pb->ipacket[0] & 0xc8) != 0x80 || 3292 (pb->ipacket[3] & 0xc8) != 0xc0) 3293 return (-1); 3294 3295 *x = *y = 0; 3296 ms->button = ms->obutton; 3297 3298 /* 3299 * Pressure value. 3300 * Interpretation: 3301 * z = 0 No finger contact 3302 * z = 10 Finger hovering near the pad 3303 * z = 30 Very light finger contact 3304 * z = 80 Normal finger contact 3305 * z = 110 Very heavy finger contact 3306 * z = 200 Finger lying flat on pad surface 3307 * z = 255 Maximum reportable Z 3308 */ 3309 *z = pb->ipacket[2]; 3310 3311 /* 3312 * Finger width value 3313 * Interpretation: 3314 * w = 0 Two finger on the pad (capMultiFinger needed) 3315 * w = 1 Three or more fingers (capMultiFinger needed) 3316 * w = 2 Pen (instead of finger) (capPen needed) 3317 * w = 3 Reserved (passthrough?) 3318 * w = 4-7 Finger of normal width (capPalmDetect needed) 3319 * w = 8-14 Very wide finger or palm (capPalmDetect needed) 3320 * w = 15 Maximum reportable width (capPalmDetect needed) 3321 */ 3322 /* XXX Is checking capExtended enough? */ 3323 if (sc->synhw.capExtended) 3324 w = ((pb->ipacket[0] & 0x30) >> 2) | 3325 ((pb->ipacket[0] & 0x04) >> 1) | 3326 ((pb->ipacket[3] & 0x04) >> 2); 3327 else { 3328 /* Assume a finger of regular width. */ 3329 w = 4; 3330 } 3331 3332 switch (w) { 3333 case 3: 3334 /* 3335 * Handle packets from the guest device. See: 3336 * Synaptics PS/2 TouchPad Interfacing Guide, Section 5.1 3337 */ 3338 if (sc->synhw.capPassthrough || sc->muxport != PSM_NOMUX) { 3339 *x = ((pb->ipacket[1] & 0x10) ? 3340 pb->ipacket[4] - 256 : pb->ipacket[4]); 3341 *y = ((pb->ipacket[1] & 0x20) ? 3342 pb->ipacket[5] - 256 : pb->ipacket[5]); 3343 *z = 0; 3344 3345 guest_buttons = 0; 3346 if (pb->ipacket[1] & 0x01) 3347 guest_buttons |= MOUSE_BUTTON1DOWN; 3348 if (pb->ipacket[1] & 0x04) 3349 guest_buttons |= MOUSE_BUTTON2DOWN; 3350 if (pb->ipacket[1] & 0x02) 3351 guest_buttons |= MOUSE_BUTTON3DOWN; 3352 #ifdef EVDEV_SUPPORT 3353 if (evdev_rcpt_mask & EVDEV_RCPT_HW_MOUSE) { 3354 evdev_push_rel(sc->evdev_r, REL_X, *x); 3355 evdev_push_rel(sc->evdev_r, REL_Y, -*y); 3356 evdev_push_mouse_btn(sc->evdev_r, 3357 guest_buttons); 3358 evdev_sync(sc->evdev_r); 3359 } 3360 #endif 3361 ms->button = touchpad_buttons | guest_buttons | 3362 sc->extended_buttons; 3363 } 3364 goto SYNAPTICS_END; 3365 3366 case 2: 3367 /* Handle Extended W mode packets */ 3368 ewcode = (pb->ipacket[5] & 0xf0) >> 4; 3369 #if PSM_FINGERS > 1 3370 switch (ewcode) { 3371 case 1: 3372 /* Secondary finger */ 3373 if (sc->synhw.capAdvancedGestures) 3374 f[1] = (finger_t) { 3375 .x = (((pb->ipacket[4] & 0x0f) << 8) | 3376 pb->ipacket[1]) << 1, 3377 .y = (((pb->ipacket[4] & 0xf0) << 4) | 3378 pb->ipacket[2]) << 1, 3379 .p = ((pb->ipacket[3] & 0x30) | 3380 (pb->ipacket[5] & 0x0f)) << 1, 3381 .w = PSM_FINGER_DEFAULT_W, 3382 .flags = PSM_FINGER_FUZZY, 3383 }; 3384 else if (sc->synhw.capReportsV) 3385 f[1] = (finger_t) { 3386 .x = (((pb->ipacket[4] & 0x0f) << 8) | 3387 (pb->ipacket[1] & 0xfe)) << 1, 3388 .y = (((pb->ipacket[4] & 0xf0) << 4) | 3389 (pb->ipacket[2] & 0xfe)) << 1, 3390 .p = ((pb->ipacket[3] & 0x30) | 3391 (pb->ipacket[5] & 0x0e)) << 1, 3392 .w = (((pb->ipacket[5] & 0x01) << 2) | 3393 ((pb->ipacket[2] & 0x01) << 1) | 3394 (pb->ipacket[1] & 0x01)) + 8, 3395 .flags = PSM_FINGER_FUZZY, 3396 }; 3397 break; 3398 case 2: 3399 ew_finger_count = pb->ipacket[1] & 0x0f; 3400 default: 3401 break; 3402 } 3403 #endif 3404 goto SYNAPTICS_END; 3405 3406 case 1: 3407 if (sc->synhw.capReportsV && ew_finger_count > 3) { 3408 nfingers = ew_finger_count; 3409 break; 3410 } 3411 /* FALLTHROUGH */ 3412 case 0: 3413 nfingers = w + 2; 3414 break; 3415 3416 default: 3417 nfingers = 1; 3418 } 3419 3420 if (sc->syninfo.touchpad_off) 3421 goto SYNAPTICS_END; 3422 3423 /* Button presses */ 3424 touchpad_buttons = 0; 3425 if (pb->ipacket[0] & 0x01) 3426 touchpad_buttons |= MOUSE_BUTTON1DOWN; 3427 if (pb->ipacket[0] & 0x02) 3428 touchpad_buttons |= MOUSE_BUTTON3DOWN; 3429 3430 if (sc->synhw.capExtended && sc->synhw.capFourButtons) { 3431 if ((pb->ipacket[3] ^ pb->ipacket[0]) & 0x01) 3432 touchpad_buttons |= MOUSE_BUTTON4DOWN; 3433 if ((pb->ipacket[3] ^ pb->ipacket[0]) & 0x02) 3434 touchpad_buttons |= MOUSE_BUTTON5DOWN; 3435 } else if (sc->synhw.capExtended && sc->synhw.capMiddle && 3436 !sc->synhw.capClickPad) { 3437 /* Middle Button */ 3438 if ((pb->ipacket[0] ^ pb->ipacket[3]) & 0x01) 3439 touchpad_buttons |= MOUSE_BUTTON2DOWN; 3440 } else if (sc->synhw.capExtended && (sc->synhw.nExtendedButtons > 0)) { 3441 /* Extended Buttons */ 3442 if ((pb->ipacket[0] ^ pb->ipacket[3]) & 0x02) { 3443 if (sc->syninfo.directional_scrolls) { 3444 if (pb->ipacket[4] & 0x01) 3445 extended_buttons |= MOUSE_BUTTON4DOWN; 3446 if (pb->ipacket[5] & 0x01) 3447 extended_buttons |= MOUSE_BUTTON5DOWN; 3448 if (pb->ipacket[4] & 0x02) 3449 extended_buttons |= MOUSE_BUTTON6DOWN; 3450 if (pb->ipacket[5] & 0x02) 3451 extended_buttons |= MOUSE_BUTTON7DOWN; 3452 } else { 3453 if (pb->ipacket[4] & 0x01) 3454 extended_buttons |= MOUSE_BUTTON1DOWN; 3455 if (pb->ipacket[5] & 0x01) 3456 extended_buttons |= MOUSE_BUTTON3DOWN; 3457 if (pb->ipacket[4] & 0x02) 3458 extended_buttons |= MOUSE_BUTTON2DOWN; 3459 sc->extended_buttons = extended_buttons; 3460 } 3461 3462 /* 3463 * Zero out bits used by extended buttons to avoid 3464 * misinterpretation of the data absolute position. 3465 * 3466 * The bits represented by 3467 * 3468 * (nExtendedButtons + 1) >> 1 3469 * 3470 * will be masked out in both bytes. 3471 * The mask for n bits is computed with the formula 3472 * 3473 * (1 << n) - 1 3474 */ 3475 int maskedbits = 0; 3476 int mask = 0; 3477 maskedbits = (sc->synhw.nExtendedButtons + 1) >> 1; 3478 mask = (1 << maskedbits) - 1; 3479 #ifdef EVDEV_SUPPORT 3480 int i; 3481 if (evdev_rcpt_mask & EVDEV_RCPT_HW_MOUSE) { 3482 if (sc->synhw.capPassthrough) { 3483 evdev_push_mouse_btn(sc->evdev_r, 3484 extended_buttons); 3485 evdev_sync(sc->evdev_r); 3486 } 3487 for (i = 0; i < maskedbits; i++) { 3488 evdev_push_key(sc->evdev_a, 3489 BTN_0 + i * 2, 3490 pb->ipacket[4] & (1 << i)); 3491 evdev_push_key(sc->evdev_a, 3492 BTN_0 + i * 2 + 1, 3493 pb->ipacket[5] & (1 << i)); 3494 } 3495 } 3496 #endif 3497 pb->ipacket[4] &= ~(mask); 3498 pb->ipacket[5] &= ~(mask); 3499 } else if (!sc->syninfo.directional_scrolls && 3500 !sc->gesture.in_vscroll) { 3501 /* 3502 * Keep reporting MOUSE DOWN until we get a new packet 3503 * indicating otherwise. 3504 */ 3505 extended_buttons |= sc->extended_buttons; 3506 } 3507 } 3508 3509 if (sc->synhw.capReportsV && nfingers > 1) 3510 f[0] = (finger_t) { 3511 .x = ((pb->ipacket[3] & 0x10) << 8) | 3512 ((pb->ipacket[1] & 0x0f) << 8) | 3513 (pb->ipacket[4] & 0xfd), 3514 .y = ((pb->ipacket[3] & 0x20) << 7) | 3515 ((pb->ipacket[1] & 0xf0) << 4) | 3516 (pb->ipacket[5] & 0xfd), 3517 .p = *z & 0xfe, 3518 .w = (((pb->ipacket[2] & 0x01) << 2) | 3519 (pb->ipacket[5] & 0x02) | 3520 ((pb->ipacket[4] & 0x02) >> 1)) + 8, 3521 .flags = PSM_FINGER_FUZZY, 3522 }; 3523 else 3524 f[0] = (finger_t) { 3525 .x = ((pb->ipacket[3] & 0x10) << 8) | 3526 ((pb->ipacket[1] & 0x0f) << 8) | 3527 pb->ipacket[4], 3528 .y = ((pb->ipacket[3] & 0x20) << 7) | 3529 ((pb->ipacket[1] & 0xf0) << 4) | 3530 pb->ipacket[5], 3531 .p = *z, 3532 .w = w, 3533 .flags = nfingers > 1 ? PSM_FINGER_FUZZY : 0, 3534 }; 3535 3536 /* Ignore hovering and unmeasurable touches */ 3537 if (f[0].p < sc->syninfo.min_pressure || f[0].x < 2) 3538 nfingers = 0; 3539 3540 /* Handle ClickPad */ 3541 if (sc->synhw.capClickPad) { 3542 clickpad_pressed = (pb->ipacket[0] ^ pb->ipacket[3]) & 0x01; 3543 if (sc->synhw.forcePad) { 3544 /* 3545 * Forcepads erroneously report button click if there 3546 * are 2 or more fingers on the touchpad breaking 3547 * multifinger gestures. To workaround this start 3548 * reporting a click only after 4 consecutive single 3549 * touch packets has been received. 3550 * Skip these packets in case more contacts appear. 3551 */ 3552 switch (nfingers) { 3553 case 0: 3554 sc->fpcount = 0; 3555 break; 3556 case 1: 3557 if (clickpad_pressed && sc->fpcount < INT_MAX) 3558 ++sc->fpcount; 3559 /* FALLTHROUGH */ 3560 default: 3561 if (!clickpad_pressed) 3562 sc->fpcount = 0; 3563 if (sc->fpcount >= sc->syninfo.window_min) 3564 touchpad_buttons |= MOUSE_BUTTON1DOWN; 3565 } 3566 } else if (clickpad_pressed) 3567 touchpad_buttons |= MOUSE_BUTTON1DOWN; 3568 } 3569 3570 for (id = 0; id < PSM_FINGERS; id++) 3571 if (id >= nfingers) 3572 PSM_FINGER_RESET(f[id]); 3573 3574 #ifdef EVDEV_SUPPORT 3575 if (evdev_rcpt_mask & EVDEV_RCPT_HW_MOUSE) { 3576 for (id = 0; id < PSM_FINGERS; id++) { 3577 if (PSM_FINGER_IS_SET(f[id])) 3578 psm_push_mt_finger(sc, id, &f[id]); 3579 else 3580 psm_release_mt_slot(sc->evdev_a, id); 3581 } 3582 evdev_push_key(sc->evdev_a, BTN_TOUCH, nfingers > 0); 3583 evdev_push_nfingers(sc->evdev_a, nfingers); 3584 if (nfingers > 0) 3585 psm_push_st_finger(sc, &f[0]); 3586 else 3587 evdev_push_abs(sc->evdev_a, ABS_PRESSURE, 0); 3588 evdev_push_mouse_btn(sc->evdev_a, touchpad_buttons); 3589 if (sc->synhw.capExtended && sc->synhw.capFourButtons) { 3590 evdev_push_key(sc->evdev_a, BTN_FORWARD, 3591 touchpad_buttons & MOUSE_BUTTON4DOWN); 3592 evdev_push_key(sc->evdev_a, BTN_BACK, 3593 touchpad_buttons & MOUSE_BUTTON5DOWN); 3594 } 3595 evdev_sync(sc->evdev_a); 3596 } 3597 #endif 3598 3599 ms->button = touchpad_buttons; 3600 3601 palm = psmpalmdetect(sc, &f[0], nfingers); 3602 3603 /* Palm detection doesn't terminate the current action. */ 3604 if (!palm) 3605 psmgestures(sc, &f[0], nfingers, ms); 3606 3607 for (id = 0; id < PSM_FINGERS; id++) 3608 psmsmoother(sc, &f[id], id, ms, x, y); 3609 3610 if (palm) { 3611 *x = *y = *z = 0; 3612 ms->button = ms->obutton; 3613 return (0); 3614 } 3615 3616 ms->button |= extended_buttons | guest_buttons; 3617 3618 SYNAPTICS_END: 3619 /* 3620 * Use the extra buttons as a scrollwheel 3621 * 3622 * XXX X.Org uses the Z axis for vertical wheel only, 3623 * whereas moused(8) understands special values to differ 3624 * vertical and horizontal wheels. 3625 * 3626 * xf86-input-mouse needs therefore a small patch to 3627 * understand these special values. Without it, the 3628 * horizontal wheel acts as a vertical wheel in X.Org. 3629 * 3630 * That's why the horizontal wheel is disabled by 3631 * default for now. 3632 */ 3633 if (ms->button & MOUSE_BUTTON4DOWN) 3634 *z = -1; 3635 else if (ms->button & MOUSE_BUTTON5DOWN) 3636 *z = 1; 3637 else if (ms->button & MOUSE_BUTTON6DOWN) 3638 *z = -2; 3639 else if (ms->button & MOUSE_BUTTON7DOWN) 3640 *z = 2; 3641 else 3642 *z = 0; 3643 ms->button &= ~(MOUSE_BUTTON4DOWN | MOUSE_BUTTON5DOWN | 3644 MOUSE_BUTTON6DOWN | MOUSE_BUTTON7DOWN); 3645 3646 return (0); 3647 } 3648 3649 static int 3650 proc_synaptics_mux(struct psm_softc *sc, packetbuf_t *pb) 3651 { 3652 int butt; 3653 3654 /* 3655 * Convert 3-byte interleaved mixture of Synaptics and generic mouse 3656 * packets into plain 6-byte Synaptics packet protocol. 3657 * While in hidden multiplexing mode KBC does some editing of the 3658 * packet stream. It remembers the button bits from the last packet 3659 * received from each device, and replaces the button bits of every 3660 * packet with the logical OR of all devices’ most recent button bits. 3661 * This button crosstalk should be filtered out as Synaptics and 3662 * generic mouse encode middle button presses in a different way. 3663 */ 3664 switch (pb->ipacket[0] & 0xc0) { 3665 case 0x80: /* First 3 bytes of Synaptics packet */ 3666 bcopy(pb->ipacket, sc->muxsave, 3); 3667 /* Compute middle mouse button supression timeout. */ 3668 sc->muxmidtimeout.tv_sec = 0; 3669 sc->muxmidtimeout.tv_usec = 50000; /* ~2-3 ints */ 3670 timevaladd(&sc->muxmidtimeout, &sc->lastsoftintr); 3671 return (1); 3672 3673 case 0xc0: /* Second 3 bytes of Synaptics packet */ 3674 /* Join two 3-bytes absolute packets */ 3675 bcopy(pb->ipacket, pb->ipacket + 3, 3); 3676 bcopy(sc->muxsave, pb->ipacket, 3); 3677 /* Prefer trackpoint buttons over touchpad's */ 3678 pb->ipacket[0] &= ~(0x08 | sc->muxmsbuttons); 3679 pb->ipacket[3] &= ~(0x08 | sc->muxmsbuttons); 3680 butt = (pb->ipacket[3] & 0x03) << 2 | (pb->ipacket[0] & 0x03); 3681 /* Add hysteresis to remove spurious middle button events */ 3682 if (butt != sc->muxtpbuttons && sc->fpcount < 1) { 3683 pb->ipacket[0] &= 0xfc; 3684 pb->ipacket[0] |= sc->muxtpbuttons & 0x03; 3685 pb->ipacket[3] &= 0xfc; 3686 pb->ipacket[3] |= sc->muxtpbuttons >> 2 & 0x03; 3687 ++sc->fpcount; 3688 } else { 3689 sc->fpcount = 0; 3690 sc->muxtpbuttons = butt; 3691 } 3692 /* Filter out impossible w induced by middle trackpoint btn */ 3693 if (sc->synhw.capExtended && !sc->synhw.capPassthrough && 3694 (pb->ipacket[0] & 0x34) == 0x04 && 3695 (pb->ipacket[3] & 0x04) == 0x04) { 3696 pb->ipacket[0] &= 0xfb; 3697 pb->ipacket[3] &= 0xfb; 3698 } 3699 sc->muxsave[0] &= 0x30; 3700 break; 3701 3702 default: /* Generic mouse (Trackpoint) packet */ 3703 /* Filter out middle button events induced by some w values */ 3704 if (sc->muxmsbuttons & 0x03 || pb->ipacket[0] & 0x03 || 3705 (timevalcmp(&sc->lastsoftintr, &sc->muxmidtimeout, <=) && 3706 (sc->muxsave[0] & 0x30 || sc->muxsave[2] > 8))) 3707 pb->ipacket[0] &= 0xfb; 3708 sc->muxmsbuttons = pb->ipacket[0] & 0x07; 3709 /* Convert to Synaptics pass-through protocol */ 3710 pb->ipacket[4] = pb->ipacket[1]; 3711 pb->ipacket[5] = pb->ipacket[2]; 3712 pb->ipacket[1] = pb->ipacket[0]; 3713 pb->ipacket[2] = 0; 3714 pb->ipacket[0] = 0x84 | (sc->muxtpbuttons & 0x03); 3715 pb->ipacket[3] = 0xc4 | (sc->muxtpbuttons >> 2 & 0x03); 3716 } 3717 3718 VLOG(4, (LOG_DEBUG, "synaptics: %02x %02x %02x %02x %02x %02x\n", 3719 pb->ipacket[0], pb->ipacket[1], pb->ipacket[2], 3720 pb->ipacket[3], pb->ipacket[4], pb->ipacket[5])); 3721 3722 pb->inputbytes = MOUSE_SYNAPTICS_PACKETSIZE; 3723 return (0); 3724 } 3725 3726 static int 3727 psmpalmdetect(struct psm_softc *sc, finger_t *f, int nfingers) 3728 { 3729 if (!( 3730 ((sc->synhw.capMultiFinger || sc->synhw.capAdvancedGestures) && 3731 !sc->synhw.capReportsV && nfingers > 1) || 3732 (sc->synhw.capReportsV && nfingers > 2) || 3733 (sc->synhw.capPalmDetect && f->w <= sc->syninfo.max_width) || 3734 (!sc->synhw.capPalmDetect && f->p <= sc->syninfo.max_pressure) || 3735 (sc->synhw.capPen && f->flags & PSM_FINGER_IS_PEN))) { 3736 /* 3737 * We consider the packet irrelevant for the current 3738 * action when: 3739 * - the width isn't comprised in: 3740 * [1; max_width] 3741 * - the pressure isn't comprised in: 3742 * [min_pressure; max_pressure] 3743 * - pen aren't supported but PSM_FINGER_IS_PEN is set 3744 */ 3745 VLOG(2, (LOG_DEBUG, "synaptics: palm detected! (%d)\n", f->w)); 3746 return (1); 3747 } 3748 return (0); 3749 } 3750 3751 static void 3752 psmgestures(struct psm_softc *sc, finger_t *fingers, int nfingers, 3753 mousestatus_t *ms) 3754 { 3755 smoother_t *smoother; 3756 gesture_t *gest; 3757 finger_t *f; 3758 int y_ok, center_button, center_x, right_button, right_x, i; 3759 3760 f = &fingers[0]; 3761 smoother = &sc->smoother[0]; 3762 gest = &sc->gesture; 3763 3764 /* Find first active finger. */ 3765 if (nfingers > 0) { 3766 for (i = 0; i < PSM_FINGERS; i++) { 3767 if (PSM_FINGER_IS_SET(fingers[i])) { 3768 f = &fingers[i]; 3769 smoother = &sc->smoother[i]; 3770 break; 3771 } 3772 } 3773 } 3774 3775 /* 3776 * Check pressure to detect a real wanted action on the 3777 * touchpad. 3778 */ 3779 if (f->p >= sc->syninfo.min_pressure) { 3780 int x0, y0; 3781 int dxp, dyp; 3782 int start_x, start_y; 3783 int queue_len; 3784 int margin_top, margin_right, margin_bottom, margin_left; 3785 int window_min, window_max; 3786 int vscroll_hor_area, vscroll_ver_area; 3787 int two_finger_scroll; 3788 int max_x, max_y; 3789 int three_finger_drag; 3790 3791 /* Read sysctl. */ 3792 /* XXX Verify values? */ 3793 margin_top = sc->syninfo.margin_top; 3794 margin_right = sc->syninfo.margin_right; 3795 margin_bottom = sc->syninfo.margin_bottom; 3796 margin_left = sc->syninfo.margin_left; 3797 window_min = sc->syninfo.window_min; 3798 window_max = sc->syninfo.window_max; 3799 vscroll_hor_area = sc->syninfo.vscroll_hor_area; 3800 vscroll_ver_area = sc->syninfo.vscroll_ver_area; 3801 two_finger_scroll = sc->syninfo.two_finger_scroll; 3802 max_x = sc->syninfo.max_x; 3803 max_y = sc->syninfo.max_y; 3804 three_finger_drag = sc->syninfo.three_finger_drag; 3805 /* Read current absolute position. */ 3806 x0 = f->x; 3807 y0 = f->y; 3808 3809 /* 3810 * Limit the coordinates to the specified margins because 3811 * this area isn't very reliable. 3812 */ 3813 if (x0 <= margin_left) 3814 x0 = margin_left; 3815 else if (x0 >= max_x - margin_right) 3816 x0 = max_x - margin_right; 3817 if (y0 <= margin_bottom) 3818 y0 = margin_bottom; 3819 else if (y0 >= max_y - margin_top) 3820 y0 = max_y - margin_top; 3821 3822 VLOG(3, (LOG_DEBUG, "synaptics: ipacket: [%d, %d], %d, %d\n", 3823 x0, y0, f->p, f->w)); 3824 3825 /* 3826 * If the action is just beginning, init the structure and 3827 * compute tap timeout. 3828 */ 3829 if (!(sc->flags & PSM_FLAGS_FINGERDOWN)) { 3830 VLOG(3, (LOG_DEBUG, "synaptics: ----\n")); 3831 3832 /* Initialize queue. */ 3833 gest->window_min = window_min; 3834 3835 /* Reset pressure peak. */ 3836 gest->zmax = 0; 3837 3838 /* Reset fingers count. */ 3839 gest->fingers_nb = 0; 3840 3841 /* Reset virtual scrolling state. */ 3842 gest->in_vscroll = 0; 3843 3844 /* Compute tap timeout. */ 3845 if (tap_enabled != 0) { 3846 gest->taptimeout = (struct timeval) { 3847 .tv_sec = tap_timeout / 1000000, 3848 .tv_usec = tap_timeout % 1000000, 3849 }; 3850 timevaladd( 3851 &gest->taptimeout, &sc->lastsoftintr); 3852 } else 3853 timevalclear(&gest->taptimeout); 3854 3855 sc->flags |= PSM_FLAGS_FINGERDOWN; 3856 3857 /* Smoother has not been reset yet */ 3858 queue_len = 1; 3859 start_x = x0; 3860 start_y = y0; 3861 } else { 3862 queue_len = smoother->queue_len + 1; 3863 start_x = smoother->start_x; 3864 start_y = smoother->start_y; 3865 } 3866 3867 /* Process ClickPad softbuttons */ 3868 if (sc->synhw.capClickPad && ms->button & MOUSE_BUTTON1DOWN) { 3869 y_ok = sc->syninfo.softbuttons_y >= 0 ? 3870 start_y < sc->syninfo.softbuttons_y : 3871 start_y > max_y + sc->syninfo.softbuttons_y; 3872 3873 center_button = MOUSE_BUTTON2DOWN; 3874 center_x = sc->syninfo.softbutton2_x; 3875 right_button = MOUSE_BUTTON3DOWN; 3876 right_x = sc->syninfo.softbutton3_x; 3877 3878 if (center_x > 0 && right_x > 0 && center_x > right_x) { 3879 center_button = MOUSE_BUTTON3DOWN; 3880 center_x = sc->syninfo.softbutton3_x; 3881 right_button = MOUSE_BUTTON2DOWN; 3882 right_x = sc->syninfo.softbutton2_x; 3883 } 3884 3885 if (right_x > 0 && start_x > right_x && y_ok) 3886 ms->button = (ms->button & 3887 ~MOUSE_BUTTON1DOWN) | right_button; 3888 else if (center_x > 0 && start_x > center_x && y_ok) 3889 ms->button = (ms->button & 3890 ~MOUSE_BUTTON1DOWN) | center_button; 3891 } 3892 3893 /* If in tap-hold or three fingers, add the recorded button. */ 3894 if (gest->in_taphold || (nfingers == 3 && three_finger_drag)) 3895 ms->button |= gest->tap_button; 3896 3897 /* 3898 * For tap, we keep the maximum number of fingers and the 3899 * pressure peak. Also with multiple fingers, we increase 3900 * the minimum window. 3901 */ 3902 if (nfingers > 1) 3903 gest->window_min = window_max; 3904 gest->fingers_nb = imax(nfingers, gest->fingers_nb); 3905 gest->zmax = imax(f->p, gest->zmax); 3906 3907 /* Do we have enough packets to consider this a gesture? */ 3908 if (queue_len < gest->window_min) 3909 return; 3910 3911 dyp = -1; 3912 dxp = -1; 3913 3914 /* Is a scrolling action occurring? */ 3915 if (!gest->in_taphold && !ms->button && 3916 (!gest->in_vscroll || two_finger_scroll)) { 3917 /* 3918 * A scrolling action must not conflict with a tap 3919 * action. Here are the conditions to consider a 3920 * scrolling action: 3921 * - the action in a configurable area 3922 * - one of the following: 3923 * . the distance between the last packet and the 3924 * first should be above a configurable minimum 3925 * . tap timed out 3926 */ 3927 dxp = abs(x0 - start_x); 3928 dyp = abs(y0 - start_y); 3929 3930 if (timevalcmp(&sc->lastsoftintr, &gest->taptimeout, >) || 3931 dxp >= sc->syninfo.vscroll_min_delta || 3932 dyp >= sc->syninfo.vscroll_min_delta) { 3933 /* 3934 * Handle two finger scrolling. 3935 * Note that we don't rely on fingers_nb 3936 * as that keeps the maximum number of fingers. 3937 */ 3938 if (two_finger_scroll) { 3939 if (nfingers == 2) { 3940 gest->in_vscroll += 3941 dyp ? 2 : 0; 3942 gest->in_vscroll += 3943 dxp ? 1 : 0; 3944 } 3945 } else { 3946 /* Check for horizontal scrolling. */ 3947 if ((vscroll_hor_area > 0 && 3948 start_y <= vscroll_hor_area) || 3949 (vscroll_hor_area < 0 && 3950 start_y >= 3951 max_y + vscroll_hor_area)) 3952 gest->in_vscroll += 2; 3953 3954 /* Check for vertical scrolling. */ 3955 if ((vscroll_ver_area > 0 && 3956 start_x <= vscroll_ver_area) || 3957 (vscroll_ver_area < 0 && 3958 start_x >= 3959 max_x + vscroll_ver_area)) 3960 gest->in_vscroll += 1; 3961 } 3962 3963 /* Avoid conflicts if area overlaps. */ 3964 if (gest->in_vscroll >= 3) 3965 gest->in_vscroll = 3966 (dxp > dyp) ? 2 : 1; 3967 } 3968 } 3969 /* 3970 * Reset two finger scrolling when the number of fingers 3971 * is different from two or any button is pressed. 3972 */ 3973 if (two_finger_scroll && gest->in_vscroll != 0 && 3974 (nfingers != 2 || ms->button)) 3975 gest->in_vscroll = 0; 3976 3977 VLOG(5, (LOG_DEBUG, 3978 "synaptics: virtual scrolling: %s " 3979 "(direction=%d, dxp=%d, dyp=%d, fingers=%d)\n", 3980 gest->in_vscroll ? "YES" : "NO", 3981 gest->in_vscroll, dxp, dyp, 3982 gest->fingers_nb)); 3983 3984 } else if (sc->flags & PSM_FLAGS_FINGERDOWN) { 3985 /* 3986 * An action is currently taking place but the pressure 3987 * dropped under the minimum, putting an end to it. 3988 */ 3989 int taphold_timeout, dx, dy, tap_max_delta; 3990 3991 dx = abs(smoother->queue[smoother->queue_cursor].x - 3992 smoother->start_x); 3993 dy = abs(smoother->queue[smoother->queue_cursor].y - 3994 smoother->start_y); 3995 3996 /* Max delta is disabled for multi-fingers tap. */ 3997 if (gest->fingers_nb > 1) 3998 tap_max_delta = imax(dx, dy); 3999 else 4000 tap_max_delta = sc->syninfo.tap_max_delta; 4001 4002 sc->flags &= ~PSM_FLAGS_FINGERDOWN; 4003 4004 /* Check for tap. */ 4005 VLOG(3, (LOG_DEBUG, 4006 "synaptics: zmax=%d, dx=%d, dy=%d, " 4007 "delta=%d, fingers=%d, queue=%d\n", 4008 gest->zmax, dx, dy, tap_max_delta, gest->fingers_nb, 4009 smoother->queue_len)); 4010 if (!gest->in_vscroll && gest->zmax >= tap_threshold && 4011 timevalcmp(&sc->lastsoftintr, &gest->taptimeout, <=) && 4012 dx <= tap_max_delta && dy <= tap_max_delta && 4013 smoother->queue_len >= sc->syninfo.tap_min_queue) { 4014 /* 4015 * We have a tap if: 4016 * - the maximum pressure went over tap_threshold 4017 * - the action ended before tap_timeout 4018 * 4019 * To handle tap-hold, we must delay any button push to 4020 * the next action. 4021 */ 4022 if (gest->in_taphold) { 4023 /* 4024 * This is the second and last tap of a 4025 * double tap action, not a tap-hold. 4026 */ 4027 gest->in_taphold = 0; 4028 4029 /* 4030 * For double-tap to work: 4031 * - no button press is emitted (to 4032 * simulate a button release) 4033 * - PSM_FLAGS_FINGERDOWN is set to 4034 * force the next packet to emit a 4035 * button press) 4036 */ 4037 VLOG(2, (LOG_DEBUG, 4038 "synaptics: button RELEASE: %d\n", 4039 gest->tap_button)); 4040 sc->flags |= PSM_FLAGS_FINGERDOWN; 4041 4042 /* Schedule button press on next interrupt */ 4043 sc->idletimeout.tv_sec = psmhz > 1 ? 4044 0 : 1; 4045 sc->idletimeout.tv_usec = psmhz > 1 ? 4046 1000000 / psmhz : 0; 4047 } else { 4048 /* 4049 * This is the first tap: we set the 4050 * tap-hold state and notify the button 4051 * down event. 4052 */ 4053 gest->in_taphold = 1; 4054 taphold_timeout = sc->syninfo.taphold_timeout; 4055 gest->taptimeout.tv_sec = taphold_timeout / 4056 1000000; 4057 gest->taptimeout.tv_usec = taphold_timeout % 4058 1000000; 4059 sc->idletimeout = gest->taptimeout; 4060 timevaladd(&gest->taptimeout, 4061 &sc->lastsoftintr); 4062 4063 switch (gest->fingers_nb) { 4064 case 3: 4065 gest->tap_button = 4066 MOUSE_BUTTON2DOWN; 4067 break; 4068 case 2: 4069 gest->tap_button = 4070 MOUSE_BUTTON3DOWN; 4071 break; 4072 default: 4073 gest->tap_button = 4074 MOUSE_BUTTON1DOWN; 4075 } 4076 VLOG(2, (LOG_DEBUG, 4077 "synaptics: button PRESS: %d\n", 4078 gest->tap_button)); 4079 ms->button |= gest->tap_button; 4080 } 4081 } else { 4082 /* 4083 * Not enough pressure or timeout: reset 4084 * tap-hold state. 4085 */ 4086 if (gest->in_taphold) { 4087 VLOG(2, (LOG_DEBUG, 4088 "synaptics: button RELEASE: %d\n", 4089 gest->tap_button)); 4090 gest->in_taphold = 0; 4091 } else { 4092 VLOG(2, (LOG_DEBUG, 4093 "synaptics: not a tap-hold\n")); 4094 } 4095 } 4096 } else if (!(sc->flags & PSM_FLAGS_FINGERDOWN) && gest->in_taphold) { 4097 /* 4098 * For a tap-hold to work, the button must remain down at 4099 * least until timeout (where the in_taphold flags will be 4100 * cleared) or during the next action. 4101 */ 4102 if (timevalcmp(&sc->lastsoftintr, &gest->taptimeout, <=)) { 4103 ms->button |= gest->tap_button; 4104 } else { 4105 VLOG(2, (LOG_DEBUG, "synaptics: button RELEASE: %d\n", 4106 gest->tap_button)); 4107 gest->in_taphold = 0; 4108 } 4109 } 4110 4111 return; 4112 } 4113 4114 static void 4115 psmsmoother(struct psm_softc *sc, finger_t *f, int smoother_id, 4116 mousestatus_t *ms, int *x, int *y) 4117 { 4118 smoother_t *smoother = &sc->smoother[smoother_id]; 4119 gesture_t *gest = &(sc->gesture); 4120 4121 /* 4122 * Check pressure to detect a real wanted action on the 4123 * touchpad. 4124 */ 4125 if (f->p >= sc->syninfo.min_pressure) { 4126 int x0, y0; 4127 int cursor, peer, window; 4128 int dx, dy, dxp, dyp; 4129 int max_width, max_pressure; 4130 int margin_top, margin_right, margin_bottom, margin_left; 4131 int na_top, na_right, na_bottom, na_left; 4132 int window_min, window_max; 4133 int multiplicator; 4134 int weight_current, weight_previous, weight_len_squared; 4135 int div_min, div_max, div_len; 4136 int vscroll_hor_area, vscroll_ver_area; 4137 int two_finger_scroll; 4138 int max_x, max_y; 4139 int len, weight_prev_x, weight_prev_y; 4140 int div_max_x, div_max_y, div_x, div_y; 4141 int is_fuzzy; 4142 int natural_scroll; 4143 4144 /* Read sysctl. */ 4145 /* XXX Verify values? */ 4146 max_width = sc->syninfo.max_width; 4147 max_pressure = sc->syninfo.max_pressure; 4148 margin_top = sc->syninfo.margin_top; 4149 margin_right = sc->syninfo.margin_right; 4150 margin_bottom = sc->syninfo.margin_bottom; 4151 margin_left = sc->syninfo.margin_left; 4152 na_top = sc->syninfo.na_top; 4153 na_right = sc->syninfo.na_right; 4154 na_bottom = sc->syninfo.na_bottom; 4155 na_left = sc->syninfo.na_left; 4156 window_min = sc->syninfo.window_min; 4157 window_max = sc->syninfo.window_max; 4158 multiplicator = sc->syninfo.multiplicator; 4159 weight_current = sc->syninfo.weight_current; 4160 weight_previous = sc->syninfo.weight_previous; 4161 weight_len_squared = sc->syninfo.weight_len_squared; 4162 div_min = sc->syninfo.div_min; 4163 div_max = sc->syninfo.div_max; 4164 div_len = sc->syninfo.div_len; 4165 vscroll_hor_area = sc->syninfo.vscroll_hor_area; 4166 vscroll_ver_area = sc->syninfo.vscroll_ver_area; 4167 two_finger_scroll = sc->syninfo.two_finger_scroll; 4168 max_x = sc->syninfo.max_x; 4169 max_y = sc->syninfo.max_y; 4170 natural_scroll = sc->syninfo.natural_scroll; 4171 4172 is_fuzzy = (f->flags & PSM_FINGER_FUZZY) != 0; 4173 4174 /* Read current absolute position. */ 4175 x0 = f->x; 4176 y0 = f->y; 4177 4178 /* 4179 * Limit the coordinates to the specified margins because 4180 * this area isn't very reliable. 4181 */ 4182 if (x0 <= margin_left) 4183 x0 = margin_left; 4184 else if (x0 >= max_x - margin_right) 4185 x0 = max_x - margin_right; 4186 if (y0 <= margin_bottom) 4187 y0 = margin_bottom; 4188 else if (y0 >= max_y - margin_top) 4189 y0 = max_y - margin_top; 4190 4191 /* If the action is just beginning, init the structure. */ 4192 if (smoother->active == 0) { 4193 VLOG(3, (LOG_DEBUG, "smoother%d: ---\n", smoother_id)); 4194 4195 /* Store the first point of this action. */ 4196 smoother->start_x = x0; 4197 smoother->start_y = y0; 4198 dx = dy = 0; 4199 4200 /* Initialize queue. */ 4201 smoother->queue_cursor = SYNAPTICS_PACKETQUEUE; 4202 smoother->queue_len = 0; 4203 4204 /* Reset average. */ 4205 smoother->avg_dx = 0; 4206 smoother->avg_dy = 0; 4207 4208 /* Reset squelch. */ 4209 smoother->squelch_x = 0; 4210 smoother->squelch_y = 0; 4211 4212 /* Activate queue */ 4213 smoother->active = 1; 4214 } else { 4215 /* Calculate the current delta. */ 4216 cursor = smoother->queue_cursor; 4217 dx = x0 - smoother->queue[cursor].x; 4218 dy = y0 - smoother->queue[cursor].y; 4219 } 4220 4221 VLOG(3, (LOG_DEBUG, "smoother%d: ipacket: [%d, %d], %d, %d\n", 4222 smoother_id, x0, y0, f->p, f->w)); 4223 4224 /* Queue this new packet. */ 4225 cursor = SYNAPTICS_QUEUE_CURSOR(smoother->queue_cursor - 1); 4226 smoother->queue[cursor].x = x0; 4227 smoother->queue[cursor].y = y0; 4228 smoother->queue_cursor = cursor; 4229 if (smoother->queue_len < SYNAPTICS_PACKETQUEUE) 4230 smoother->queue_len++; 4231 VLOG(5, (LOG_DEBUG, 4232 "smoother%d: cursor[%d]: x=%d, y=%d, dx=%d, dy=%d\n", 4233 smoother_id, cursor, x0, y0, dx, dy)); 4234 4235 /* Do we have enough packets to consider this a movement? */ 4236 if (smoother->queue_len < gest->window_min) 4237 return; 4238 4239 weight_prev_x = weight_prev_y = weight_previous; 4240 div_max_x = div_max_y = div_max; 4241 4242 if (gest->in_vscroll) { 4243 /* Dividers are different with virtual scrolling. */ 4244 div_min = sc->syninfo.vscroll_div_min; 4245 div_max_x = div_max_y = sc->syninfo.vscroll_div_max; 4246 } else { 4247 /* 4248 * There's a lot of noise in coordinates when 4249 * the finger is on the touchpad's borders. When 4250 * using this area, we apply a special weight and 4251 * div. 4252 */ 4253 if (x0 <= na_left || x0 >= max_x - na_right) { 4254 weight_prev_x = sc->syninfo.weight_previous_na; 4255 div_max_x = sc->syninfo.div_max_na; 4256 } 4257 4258 if (y0 <= na_bottom || y0 >= max_y - na_top) { 4259 weight_prev_y = sc->syninfo.weight_previous_na; 4260 div_max_y = sc->syninfo.div_max_na; 4261 } 4262 } 4263 4264 /* 4265 * Calculate weights for the average operands and 4266 * the divisor. Both depend on the distance between 4267 * the current packet and a previous one (based on the 4268 * window width). 4269 */ 4270 window = imin(smoother->queue_len, window_max); 4271 peer = SYNAPTICS_QUEUE_CURSOR(cursor + window - 1); 4272 dxp = abs(x0 - smoother->queue[peer].x) + 1; 4273 dyp = abs(y0 - smoother->queue[peer].y) + 1; 4274 len = (dxp * dxp) + (dyp * dyp); 4275 weight_prev_x = imin(weight_prev_x, 4276 weight_len_squared * weight_prev_x / len); 4277 weight_prev_y = imin(weight_prev_y, 4278 weight_len_squared * weight_prev_y / len); 4279 4280 len = (dxp + dyp) / 2; 4281 div_x = div_len * div_max_x / len; 4282 div_x = imin(div_max_x, div_x); 4283 div_x = imax(div_min, div_x); 4284 div_y = div_len * div_max_y / len; 4285 div_y = imin(div_max_y, div_y); 4286 div_y = imax(div_min, div_y); 4287 4288 VLOG(3, (LOG_DEBUG, 4289 "smoother%d: peer=%d, len=%d, weight=%d/%d, div=%d/%d\n", 4290 smoother_id, peer, len, weight_prev_x, weight_prev_y, 4291 div_x, div_y)); 4292 4293 /* Compute averages. */ 4294 smoother->avg_dx = 4295 (weight_current * dx * multiplicator + 4296 weight_prev_x * smoother->avg_dx) / 4297 (weight_current + weight_prev_x); 4298 4299 smoother->avg_dy = 4300 (weight_current * dy * multiplicator + 4301 weight_prev_y * smoother->avg_dy) / 4302 (weight_current + weight_prev_y); 4303 4304 VLOG(5, (LOG_DEBUG, 4305 "smoother%d: avg_dx~=%d, avg_dy~=%d\n", smoother_id, 4306 smoother->avg_dx / multiplicator, 4307 smoother->avg_dy / multiplicator)); 4308 4309 /* Use these averages to calculate x & y. */ 4310 smoother->squelch_x += smoother->avg_dx; 4311 dxp = smoother->squelch_x / (div_x * multiplicator); 4312 smoother->squelch_x = smoother->squelch_x % 4313 (div_x * multiplicator); 4314 4315 smoother->squelch_y += smoother->avg_dy; 4316 dyp = smoother->squelch_y / (div_y * multiplicator); 4317 smoother->squelch_y = smoother->squelch_y % 4318 (div_y * multiplicator); 4319 4320 switch(gest->in_vscroll) { 4321 case 0: /* Pointer movement. */ 4322 /* On real<->fuzzy finger switch the x/y pos jumps */ 4323 if (is_fuzzy == smoother->is_fuzzy) { 4324 *x += dxp; 4325 *y += dyp; 4326 } 4327 4328 VLOG(3, (LOG_DEBUG, "smoother%d: [%d, %d] -> [%d, %d]\n", 4329 smoother_id, dx, dy, dxp, dyp)); 4330 break; 4331 case 1: /* Vertical scrolling. */ 4332 if (dyp != 0) { 4333 if (two_finger_scroll && natural_scroll) 4334 ms->button |= (dyp > 0) ? 4335 MOUSE_BUTTON5DOWN : MOUSE_BUTTON4DOWN; 4336 else 4337 ms->button |= (dyp > 0) ? 4338 MOUSE_BUTTON4DOWN : MOUSE_BUTTON5DOWN; 4339 } 4340 break; 4341 case 2: /* Horizontal scrolling. */ 4342 if (dxp != 0) { 4343 if (two_finger_scroll && natural_scroll) 4344 ms->button |= (dxp > 0) ? 4345 MOUSE_BUTTON6DOWN : MOUSE_BUTTON7DOWN; 4346 else 4347 ms->button |= (dxp > 0) ? 4348 MOUSE_BUTTON7DOWN : MOUSE_BUTTON6DOWN; 4349 } 4350 break; 4351 } 4352 4353 smoother->is_fuzzy = is_fuzzy; 4354 4355 } else { 4356 /* 4357 * Deactivate queue. Note: We can not just reset queue here 4358 * as these values are still used by gesture processor. 4359 * So postpone reset till next touch. 4360 */ 4361 smoother->active = 0; 4362 } 4363 } 4364 4365 static int 4366 proc_elantech(struct psm_softc *sc, packetbuf_t *pb, mousestatus_t *ms, 4367 int *x, int *y, int *z) 4368 { 4369 static int touchpad_button, trackpoint_button; 4370 finger_t fn, f[ELANTECH_MAX_FINGERS]; 4371 int pkt, id, scale, i, nfingers, mask, palm; 4372 4373 if (!elantech_support) 4374 return (0); 4375 4376 /* Determine packet format and do a sanity check for out of sync packets. */ 4377 if (ELANTECH_PKT_IS_DEBOUNCE(pb, sc->elanhw.hwversion)) 4378 pkt = ELANTECH_PKT_NOP; 4379 else if (sc->elanhw.hastrackpoint && ELANTECH_PKT_IS_TRACKPOINT(pb)) 4380 pkt = ELANTECH_PKT_TRACKPOINT; 4381 else 4382 switch (sc->elanhw.hwversion) { 4383 case 2: 4384 if (!ELANTECH_PKT_IS_V2(pb)) 4385 return (-1); 4386 4387 pkt = (pb->ipacket[0] & 0xc0) == 0x80 ? 4388 ELANTECH_PKT_V2_2FINGER : ELANTECH_PKT_V2_COMMON; 4389 break; 4390 case 3: 4391 if (!ELANTECH_PKT_IS_V3_HEAD(pb, sc->elanhw.hascrc) && 4392 !ELANTECH_PKT_IS_V3_TAIL(pb, sc->elanhw.hascrc)) 4393 return (-1); 4394 4395 pkt = ELANTECH_PKT_V3; 4396 break; 4397 case 4: 4398 if (!ELANTECH_PKT_IS_V4(pb, sc->elanhw.hascrc)) 4399 return (-1); 4400 4401 switch (pb->ipacket[3] & 0x03) { 4402 case 0x00: 4403 pkt = ELANTECH_PKT_V4_STATUS; 4404 break; 4405 case 0x01: 4406 pkt = ELANTECH_PKT_V4_HEAD; 4407 break; 4408 case 0x02: 4409 pkt = ELANTECH_PKT_V4_MOTION; 4410 break; 4411 default: 4412 return (-1); 4413 } 4414 break; 4415 default: 4416 return (-1); 4417 } 4418 4419 VLOG(5, (LOG_DEBUG, "elantech: ipacket format: %d\n", pkt)); 4420 4421 for (id = 0; id < ELANTECH_MAX_FINGERS; id++) 4422 PSM_FINGER_RESET(f[id]); 4423 4424 *x = *y = *z = 0; 4425 ms->button = ms->obutton; 4426 4427 if (sc->syninfo.touchpad_off) 4428 return (0); 4429 4430 /* Common legend 4431 * L: Left mouse button pressed 4432 * R: Right mouse button pressed 4433 * N: number of fingers on touchpad 4434 * X: absolute x value (horizontal) 4435 * Y: absolute y value (vertical) 4436 * W; width of the finger touch 4437 * P: pressure 4438 */ 4439 switch (pkt) { 4440 case ELANTECH_PKT_V2_COMMON: /* HW V2. One/Three finger touch */ 4441 /* 7 6 5 4 3 2 1 0 (LSB) 4442 * ------------------------------------------- 4443 * ipacket[0]: N1 N0 W3 W2 . . R L 4444 * ipacket[1]: P7 P6 P5 P4 X11 X10 X9 X8 4445 * ipacket[2]: X7 X6 X5 X4 X3 X2 X1 X0 4446 * ipacket[3]: N4 VF W1 W0 . . . B2 4447 * ipacket[4]: P3 P1 P2 P0 Y11 Y10 Y9 Y8 4448 * ipacket[5]: Y7 Y6 Y5 Y4 Y3 Y2 Y1 Y0 4449 * ------------------------------------------- 4450 * N4: set if more than 3 fingers (only in 3 fingers mode) 4451 * VF: a kind of flag? (only on EF123, 0 when finger 4452 * is over one of the buttons, 1 otherwise) 4453 * B2: (on EF113 only, 0 otherwise), one button pressed 4454 * P & W is not reported on EF113 touchpads 4455 */ 4456 nfingers = (pb->ipacket[0] & 0xc0) >> 6; 4457 if (nfingers == 3 && (pb->ipacket[3] & 0x80)) 4458 nfingers = 4; 4459 4460 if (nfingers == 0) { 4461 mask = (1 << nfingers) - 1; /* = 0x00 */ 4462 break; 4463 } 4464 4465 /* Map 3-rd and 4-th fingers to first finger */ 4466 mask = (1 << 1) - 1; /* = 0x01 */ 4467 f[0] = ELANTECH_FINGER_SET_XYP(pb); 4468 if (sc->elanhw.haspressure) { 4469 f[0].w = ((pb->ipacket[0] & 0x30) >> 2) | 4470 ((pb->ipacket[3] & 0x30) >> 4); 4471 } else { 4472 f[0].p = PSM_FINGER_DEFAULT_P; 4473 f[0].w = PSM_FINGER_DEFAULT_W; 4474 } 4475 4476 /* 4477 * HW v2 dont report exact finger positions when 3 or more 4478 * fingers are on touchpad. 4479 */ 4480 if (nfingers > 2) 4481 f[0].flags = PSM_FINGER_FUZZY; 4482 4483 break; 4484 4485 case ELANTECH_PKT_V2_2FINGER: /*HW V2. Two finger touch */ 4486 /* 7 6 5 4 3 2 1 0 (LSB) 4487 * ------------------------------------------- 4488 * ipacket[0]: N1 N0 AY8 AX8 . . R L 4489 * ipacket[1]: AX7 AX6 AX5 AX4 AX3 AX2 AX1 AX0 4490 * ipacket[2]: AY7 AY6 AY5 AY4 AY3 AY2 AY1 AY0 4491 * ipacket[3]: . . BY8 BX8 . . . . 4492 * ipacket[4]: BX7 BX6 BX5 BX4 BX3 BX2 BX1 BX0 4493 * ipacket[5]: BY7 BY6 BY5 BY4 BY3 BY2 BY1 BY0 4494 * ------------------------------------------- 4495 * AX: lower-left finger absolute x value 4496 * AY: lower-left finger absolute y value 4497 * BX: upper-right finger absolute x value 4498 * BY: upper-right finger absolute y value 4499 */ 4500 nfingers = 2; 4501 mask = (1 << nfingers) - 1; 4502 4503 for (id = 0; id < imin(2, ELANTECH_MAX_FINGERS); id ++) 4504 f[id] = (finger_t) { 4505 .x = (((pb->ipacket[id * 3] & 0x10) << 4) | 4506 pb->ipacket[id * 3 + 1]) << 2, 4507 .y = (((pb->ipacket[id * 3] & 0x20) << 3) | 4508 pb->ipacket[id * 3 + 2]) << 2, 4509 .p = PSM_FINGER_DEFAULT_P, 4510 .w = PSM_FINGER_DEFAULT_W, 4511 /* HW ver.2 sends bounding box */ 4512 .flags = PSM_FINGER_FUZZY 4513 }; 4514 break; 4515 4516 case ELANTECH_PKT_V3: /* HW Version 3 */ 4517 /* 7 6 5 4 3 2 1 0 (LSB) 4518 * ------------------------------------------- 4519 * ipacket[0]: N1 N0 W3 W2 0 1 R L 4520 * ipacket[1]: P7 P6 P5 P4 X11 X10 X9 X8 4521 * ipacket[2]: X7 X6 X5 X4 X3 X2 X1 X0 4522 * ipacket[3]: 0 0 W1 W0 0 0 1 0 4523 * ipacket[4]: P3 P1 P2 P0 Y11 Y10 Y9 Y8 4524 * ipacket[5]: Y7 Y6 Y5 Y4 Y3 Y2 Y1 Y0 4525 * ------------------------------------------- 4526 */ 4527 nfingers = (pb->ipacket[0] & 0xc0) >> 6; 4528 /* Map 3-rd finger to first finger */ 4529 id = nfingers > 2 ? 0 : nfingers - 1; 4530 mask = (1 << (id + 1)) - 1; 4531 4532 if (nfingers == 0) 4533 break; 4534 4535 fn = ELANTECH_FINGER_SET_XYP(pb); 4536 fn.w = ((pb->ipacket[0] & 0x30) >> 2) | 4537 ((pb->ipacket[3] & 0x30) >> 4); 4538 4539 /* 4540 * HW v3 dont report exact finger positions when 3 or more 4541 * fingers are on touchpad. 4542 */ 4543 if (nfingers > 1) 4544 fn.flags = PSM_FINGER_FUZZY; 4545 4546 if (nfingers == 2) { 4547 if (ELANTECH_PKT_IS_V3_HEAD(pb, sc->elanhw.hascrc)) { 4548 sc->elanaction.fingers[0] = fn; 4549 return (0); 4550 } else 4551 f[0] = sc->elanaction.fingers[0]; 4552 } 4553 f[id] = fn; 4554 break; 4555 4556 case ELANTECH_PKT_V4_STATUS: /* HW Version 4. Status packet */ 4557 /* 7 6 5 4 3 2 1 0 (LSB) 4558 * ------------------------------------------- 4559 * ipacket[0]: . . . . 0 1 R L 4560 * ipacket[1]: . . . F4 F3 F2 F1 F0 4561 * ipacket[2]: . . . . . . . . 4562 * ipacket[3]: . . . 1 0 0 0 0 4563 * ipacket[4]: PL . . . . . . . 4564 * ipacket[5]: . . . . . . . . 4565 * ------------------------------------------- 4566 * Fn: finger n is on touchpad 4567 * PL: palm 4568 * HV ver4 sends a status packet to indicate that the numbers 4569 * or identities of the fingers has been changed 4570 */ 4571 4572 mask = pb->ipacket[1] & 0x1f; 4573 nfingers = bitcount(mask); 4574 4575 if (sc->elanaction.mask_v4wait != 0) 4576 VLOG(3, (LOG_DEBUG, "elantech: HW v4 status packet" 4577 " when not all previous head packets received\n")); 4578 4579 /* Bitmap of fingers to receive before gesture processing */ 4580 sc->elanaction.mask_v4wait = mask & ~sc->elanaction.mask; 4581 4582 /* Skip "new finger is on touchpad" packets */ 4583 if (sc->elanaction.mask_v4wait) { 4584 sc->elanaction.mask = mask; 4585 return (0); 4586 } 4587 4588 break; 4589 4590 case ELANTECH_PKT_V4_HEAD: /* HW Version 4. Head packet */ 4591 /* 7 6 5 4 3 2 1 0 (LSB) 4592 * ------------------------------------------- 4593 * ipacket[0]: W3 W2 W1 W0 0 1 R L 4594 * ipacket[1]: P7 P6 P5 P4 X11 X10 X9 X8 4595 * ipacket[2]: X7 X6 X5 X4 X3 X2 X1 X0 4596 * ipacket[3]: ID2 ID1 ID0 1 0 0 0 1 4597 * ipacket[4]: P3 P1 P2 P0 Y11 Y10 Y9 Y8 4598 * ipacket[5]: Y7 Y6 Y5 Y4 Y3 Y2 Y1 Y0 4599 * ------------------------------------------- 4600 * ID: finger id 4601 * HW ver 4 sends head packets in two cases: 4602 * 1. One finger touch and movement. 4603 * 2. Next after status packet to tell new finger positions. 4604 */ 4605 mask = sc->elanaction.mask; 4606 nfingers = bitcount(mask); 4607 id = ((pb->ipacket[3] & 0xe0) >> 5) - 1; 4608 fn = ELANTECH_FINGER_SET_XYP(pb); 4609 fn.w =(pb->ipacket[0] & 0xf0) >> 4; 4610 4611 if (id < 0) 4612 return (0); 4613 4614 /* Packet is finger position update. Report it */ 4615 if (sc->elanaction.mask_v4wait == 0) { 4616 if (id < ELANTECH_MAX_FINGERS) 4617 f[id] = fn; 4618 break; 4619 } 4620 4621 /* Remove finger from waiting bitmap and store into context */ 4622 sc->elanaction.mask_v4wait &= ~(1 << id); 4623 if (id < ELANTECH_MAX_FINGERS) 4624 sc->elanaction.fingers[id] = fn; 4625 4626 /* Wait for other fingers if needed */ 4627 if (sc->elanaction.mask_v4wait != 0) 4628 return (0); 4629 4630 /* All new fingers are received. Report them from context */ 4631 for (id = 0; id < ELANTECH_MAX_FINGERS; id++) 4632 if (sc->elanaction.mask & (1 << id)) 4633 f[id] = sc->elanaction.fingers[id]; 4634 4635 break; 4636 4637 case ELANTECH_PKT_V4_MOTION: /* HW Version 4. Motion packet */ 4638 /* 7 6 5 4 3 2 1 0 (LSB) 4639 * ------------------------------------------- 4640 * ipacket[0]: ID2 ID1 ID0 OF 0 1 R L 4641 * ipacket[1]: DX7 DX6 DX5 DX4 DX3 DX2 DX1 DX0 4642 * ipacket[2]: DY7 DY6 DY5 DY4 DY3 DY2 DY1 DY0 4643 * ipacket[3]: ID2 ID1 ID0 1 0 0 1 0 4644 * ipacket[4]: DX7 DX6 DX5 DX4 DX3 DX2 DX1 DX0 4645 * ipacket[5]: DY7 DY6 DY5 DY4 DY3 DY2 DY1 DY0 4646 * ------------------------------------------- 4647 * OF: delta overflows (> 127 or < -128), in this case 4648 * firmware sends us (delta x / 5) and (delta y / 5) 4649 * ID: finger id 4650 * DX: delta x (two's complement) 4651 * XY: delta y (two's complement) 4652 * byte 0 ~ 2 for one finger 4653 * byte 3 ~ 5 for another finger 4654 */ 4655 mask = sc->elanaction.mask; 4656 nfingers = bitcount(mask); 4657 4658 scale = (pb->ipacket[0] & 0x10) ? 5 : 1; 4659 for (i = 0; i <= 3; i += 3) { 4660 id = ((pb->ipacket[i] & 0xe0) >> 5) - 1; 4661 if (id < 0 || id >= ELANTECH_MAX_FINGERS) 4662 continue; 4663 4664 if (PSM_FINGER_IS_SET(sc->elanaction.fingers[id])) { 4665 f[id] = sc->elanaction.fingers[id]; 4666 f[id].x += imax(-f[id].x, 4667 (signed char)pb->ipacket[i+1] * scale); 4668 f[id].y += imax(-f[id].y, 4669 (signed char)pb->ipacket[i+2] * scale); 4670 } else { 4671 VLOG(3, (LOG_DEBUG, "elantech: " 4672 "HW v4 motion packet skipped\n")); 4673 } 4674 } 4675 4676 break; 4677 4678 case ELANTECH_PKT_TRACKPOINT: 4679 /* 7 6 5 4 3 2 1 0 (LSB) 4680 * ------------------------------------------- 4681 * ipacket[0]: 0 0 SY SX 0 M R L 4682 * ipacket[1]: ~SX 0 0 0 0 0 0 0 4683 * ipacket[2]: ~SY 0 0 0 0 0 0 0 4684 * ipacket[3]: 0 0 ~SY ~SX 0 1 1 0 4685 * ipacket[4]: X7 X6 X5 X4 X3 X2 X1 X0 4686 * ipacket[5]: Y7 Y6 Y5 Y4 Y3 Y2 Y1 Y0 4687 * ------------------------------------------- 4688 * X and Y are written in two's complement spread 4689 * over 9 bits with SX/SY the relative top bit and 4690 * X7..X0 and Y7..Y0 the lower bits. 4691 */ 4692 if (!(pb->ipacket[0] & 0xC8) && !(pb->ipacket[1] & 0x7F) && 4693 !(pb->ipacket[2] & 0x7F) && !(pb->ipacket[3] & 0xC9) && 4694 !(pb->ipacket[0] & 0x10) != !(pb->ipacket[1] & 0x80) && 4695 !(pb->ipacket[0] & 0x10) != !(pb->ipacket[3] & 0x10) && 4696 !(pb->ipacket[0] & 0x20) != !(pb->ipacket[2] & 0x80) && 4697 !(pb->ipacket[0] & 0x20) != !(pb->ipacket[3] & 0x20)) { 4698 4699 *x = (pb->ipacket[0] & MOUSE_PS2_XNEG) ? 4700 pb->ipacket[4] - 256 : pb->ipacket[4]; 4701 *y = (pb->ipacket[0] & MOUSE_PS2_YNEG) ? 4702 pb->ipacket[5] - 256 : pb->ipacket[5]; 4703 4704 trackpoint_button = 4705 ((pb->ipacket[0] & 0x01) ? MOUSE_BUTTON1DOWN : 0) | 4706 ((pb->ipacket[0] & 0x02) ? MOUSE_BUTTON3DOWN : 0) | 4707 ((pb->ipacket[0] & 0x04) ? MOUSE_BUTTON2DOWN : 0); 4708 #ifdef EVDEV_SUPPORT 4709 evdev_push_rel(sc->evdev_r, REL_X, *x); 4710 evdev_push_rel(sc->evdev_r, REL_Y, -*y); 4711 evdev_push_mouse_btn(sc->evdev_r, trackpoint_button); 4712 evdev_sync(sc->evdev_r); 4713 #endif 4714 ms->button = touchpad_button | trackpoint_button; 4715 } else 4716 VLOG(3, (LOG_DEBUG, "elantech: " 4717 "unexpected trackpoint packet skipped\n")); 4718 return (0); 4719 4720 case ELANTECH_PKT_NOP: 4721 return (0); 4722 4723 default: 4724 return (-1); 4725 } 4726 4727 for (id = 0; id < ELANTECH_MAX_FINGERS; id++) 4728 if (PSM_FINGER_IS_SET(f[id])) 4729 VLOG(2, (LOG_DEBUG, "elantech: " 4730 "finger %d: down [%d, %d], %d, %d, %d\n", id + 1, 4731 f[id].x, f[id].y, f[id].p, f[id].w, f[id].flags)); 4732 4733 /* Touchpad button presses */ 4734 if (sc->elanhw.isclickpad) { 4735 touchpad_button = 4736 ((pb->ipacket[0] & 0x03) ? MOUSE_BUTTON1DOWN : 0); 4737 } else { 4738 touchpad_button = 4739 ((pb->ipacket[0] & 0x01) ? MOUSE_BUTTON1DOWN : 0) | 4740 ((pb->ipacket[0] & 0x02) ? MOUSE_BUTTON3DOWN : 0); 4741 } 4742 4743 #ifdef EVDEV_SUPPORT 4744 if (evdev_rcpt_mask & EVDEV_RCPT_HW_MOUSE) { 4745 for (id = 0; id < ELANTECH_MAX_FINGERS; id++) { 4746 if (PSM_FINGER_IS_SET(f[id])) { 4747 psm_push_mt_finger(sc, id, &f[id]); 4748 /* Convert touch width to surface units */ 4749 evdev_push_abs(sc->evdev_a, ABS_MT_TOUCH_MAJOR, 4750 f[id].w * sc->elanhw.dptracex); 4751 } 4752 if (sc->elanaction.mask & (1 << id) && 4753 !(mask & (1 << id))) 4754 psm_release_mt_slot(sc->evdev_a, id); 4755 } 4756 evdev_push_key(sc->evdev_a, BTN_TOUCH, nfingers > 0); 4757 evdev_push_nfingers(sc->evdev_a, nfingers); 4758 if (nfingers > 0) { 4759 if (PSM_FINGER_IS_SET(f[0])) 4760 psm_push_st_finger(sc, &f[0]); 4761 } else 4762 evdev_push_abs(sc->evdev_a, ABS_PRESSURE, 0); 4763 evdev_push_mouse_btn(sc->evdev_a, touchpad_button); 4764 evdev_sync(sc->evdev_a); 4765 } 4766 #endif 4767 4768 ms->button = touchpad_button | trackpoint_button; 4769 4770 /* Palm detection doesn't terminate the current action. */ 4771 palm = psmpalmdetect(sc, &f[0], nfingers); 4772 4773 /* Send finger 1 position to gesture processor */ 4774 if ((PSM_FINGER_IS_SET(f[0]) || PSM_FINGER_IS_SET(f[1]) || 4775 nfingers == 0) && !palm) 4776 psmgestures(sc, &f[0], imin(nfingers, 3), ms); 4777 4778 /* Send fingers positions to movement smoothers */ 4779 for (id = 0; id < PSM_FINGERS; id++) 4780 if (PSM_FINGER_IS_SET(f[id]) || !(mask & (1 << id))) 4781 psmsmoother(sc, &f[id], id, ms, x, y); 4782 4783 /* Store current finger positions in action context */ 4784 for (id = 0; id < ELANTECH_MAX_FINGERS; id++) { 4785 if (PSM_FINGER_IS_SET(f[id])) 4786 sc->elanaction.fingers[id] = f[id]; 4787 if ((sc->elanaction.mask & (1 << id)) && !(mask & (1 << id))) 4788 PSM_FINGER_RESET(sc->elanaction.fingers[id]); 4789 } 4790 sc->elanaction.mask = mask; 4791 4792 if (palm) { 4793 *x = *y = *z = 0; 4794 ms->button = ms->obutton; 4795 return (0); 4796 } 4797 4798 /* Use the extra buttons as a scrollwheel */ 4799 if (ms->button & MOUSE_BUTTON4DOWN) 4800 *z = -1; 4801 else if (ms->button & MOUSE_BUTTON5DOWN) 4802 *z = 1; 4803 else if (ms->button & MOUSE_BUTTON6DOWN) 4804 *z = -2; 4805 else if (ms->button & MOUSE_BUTTON7DOWN) 4806 *z = 2; 4807 else 4808 *z = 0; 4809 ms->button &= ~(MOUSE_BUTTON4DOWN | MOUSE_BUTTON5DOWN | 4810 MOUSE_BUTTON6DOWN | MOUSE_BUTTON7DOWN); 4811 4812 return (0); 4813 } 4814 4815 static void 4816 proc_versapad(struct psm_softc *sc, packetbuf_t *pb, mousestatus_t *ms, 4817 int *x, int *y, int *z) 4818 { 4819 static int butmap_versapad[8] = { 4820 0, 4821 MOUSE_BUTTON3DOWN, 4822 0, 4823 MOUSE_BUTTON3DOWN, 4824 MOUSE_BUTTON1DOWN, 4825 MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN, 4826 MOUSE_BUTTON1DOWN, 4827 MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN 4828 }; 4829 int c, x0, y0; 4830 4831 /* VersaPad PS/2 absolute mode message format 4832 * 4833 * [packet1] 7 6 5 4 3 2 1 0(LSB) 4834 * ipacket[0]: 1 1 0 A 1 L T R 4835 * ipacket[1]: H7 H6 H5 H4 H3 H2 H1 H0 4836 * ipacket[2]: V7 V6 V5 V4 V3 V2 V1 V0 4837 * ipacket[3]: 1 1 1 A 1 L T R 4838 * ipacket[4]:V11 V10 V9 V8 H11 H10 H9 H8 4839 * ipacket[5]: 0 P6 P5 P4 P3 P2 P1 P0 4840 * 4841 * [note] 4842 * R: right physical mouse button (1=on) 4843 * T: touch pad virtual button (1=tapping) 4844 * L: left physical mouse button (1=on) 4845 * A: position data is valid (1=valid) 4846 * H: horizontal data (12bit signed integer. H11 is sign bit.) 4847 * V: vertical data (12bit signed integer. V11 is sign bit.) 4848 * P: pressure data 4849 * 4850 * Tapping is mapped to MOUSE_BUTTON4. 4851 */ 4852 c = pb->ipacket[0]; 4853 *x = *y = 0; 4854 ms->button = butmap_versapad[c & MOUSE_PS2VERSA_BUTTONS]; 4855 ms->button |= (c & MOUSE_PS2VERSA_TAP) ? MOUSE_BUTTON4DOWN : 0; 4856 if (c & MOUSE_PS2VERSA_IN_USE) { 4857 x0 = pb->ipacket[1] | (((pb->ipacket[4]) & 0x0f) << 8); 4858 y0 = pb->ipacket[2] | (((pb->ipacket[4]) & 0xf0) << 4); 4859 if (x0 & 0x800) 4860 x0 -= 0x1000; 4861 if (y0 & 0x800) 4862 y0 -= 0x1000; 4863 if (sc->flags & PSM_FLAGS_FINGERDOWN) { 4864 *x = sc->xold - x0; 4865 *y = y0 - sc->yold; 4866 if (*x < 0) /* XXX */ 4867 ++*x; 4868 else if (*x) 4869 --*x; 4870 if (*y < 0) 4871 ++*y; 4872 else if (*y) 4873 --*y; 4874 } else 4875 sc->flags |= PSM_FLAGS_FINGERDOWN; 4876 sc->xold = x0; 4877 sc->yold = y0; 4878 } else 4879 sc->flags &= ~PSM_FLAGS_FINGERDOWN; 4880 } 4881 4882 static void 4883 psmsoftintridle(void *arg) 4884 { 4885 struct psm_softc *sc = arg; 4886 packetbuf_t *pb; 4887 4888 /* Invoke soft handler only when pqueue is empty. Otherwise it will be 4889 * invoked from psmintr soon with pqueue filled with real data */ 4890 if (sc->pqueue_start == sc->pqueue_end && 4891 sc->idlepacket.inputbytes > 0) { 4892 /* Grow circular queue backwards to avoid race with psmintr */ 4893 if (--sc->pqueue_start < 0) 4894 sc->pqueue_start = PSM_PACKETQUEUE - 1; 4895 4896 pb = &sc->pqueue[sc->pqueue_start]; 4897 memcpy(pb, &sc->idlepacket, sizeof(packetbuf_t)); 4898 VLOG(4, (LOG_DEBUG, 4899 "psmsoftintridle: %02x %02x %02x %02x %02x %02x\n", 4900 pb->ipacket[0], pb->ipacket[1], pb->ipacket[2], 4901 pb->ipacket[3], pb->ipacket[4], pb->ipacket[5])); 4902 4903 psmsoftintr(arg); 4904 } 4905 } 4906 4907 static void 4908 psmsoftintr(void *arg) 4909 { 4910 /* 4911 * the table to turn PS/2 mouse button bits (MOUSE_PS2_BUTTON?DOWN) 4912 * into `mousestatus' button bits (MOUSE_BUTTON?DOWN). 4913 */ 4914 static int butmap[8] = { 4915 0, 4916 MOUSE_BUTTON1DOWN, 4917 MOUSE_BUTTON3DOWN, 4918 MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN, 4919 MOUSE_BUTTON2DOWN, 4920 MOUSE_BUTTON1DOWN | MOUSE_BUTTON2DOWN, 4921 MOUSE_BUTTON2DOWN | MOUSE_BUTTON3DOWN, 4922 MOUSE_BUTTON1DOWN | MOUSE_BUTTON2DOWN | MOUSE_BUTTON3DOWN 4923 }; 4924 struct psm_softc *sc = arg; 4925 mousestatus_t ms; 4926 packetbuf_t *pb; 4927 int x, y, z, c, l, s; 4928 4929 getmicrouptime(&sc->lastsoftintr); 4930 4931 s = spltty(); 4932 4933 do { 4934 pb = &sc->pqueue[sc->pqueue_start]; 4935 4936 if (sc->mode.level == PSM_LEVEL_NATIVE) 4937 goto next_native; 4938 4939 c = pb->ipacket[0]; 4940 /* 4941 * A kludge for Kensington device! 4942 * The MSB of the horizontal count appears to be stored in 4943 * a strange place. 4944 */ 4945 if (sc->hw.model == MOUSE_MODEL_THINK) 4946 pb->ipacket[1] |= (c & MOUSE_PS2_XOVERFLOW) ? 0x80 : 0; 4947 4948 /* ignore the overflow bits... */ 4949 x = (c & MOUSE_PS2_XNEG) ? 4950 pb->ipacket[1] - 256 : pb->ipacket[1]; 4951 y = (c & MOUSE_PS2_YNEG) ? 4952 pb->ipacket[2] - 256 : pb->ipacket[2]; 4953 z = 0; 4954 ms.obutton = sc->button; /* previous button state */ 4955 ms.button = butmap[c & MOUSE_PS2_BUTTONS]; 4956 /* `tapping' action */ 4957 if (sc->config & PSM_CONFIG_FORCETAP) 4958 ms.button |= ((c & MOUSE_PS2_TAP)) ? 4959 0 : MOUSE_BUTTON4DOWN; 4960 timevalclear(&sc->idletimeout); 4961 sc->idlepacket.inputbytes = 0; 4962 4963 switch (sc->hw.model) { 4964 4965 case MOUSE_MODEL_EXPLORER: 4966 /* 4967 * b7 b6 b5 b4 b3 b2 b1 b0 4968 * byte 1: oy ox sy sx 1 M R L 4969 * byte 2: x x x x x x x x 4970 * byte 3: y y y y y y y y 4971 * byte 4: * * S2 S1 s d2 d1 d0 4972 * 4973 * L, M, R, S1, S2: left, middle, right and side buttons 4974 * s: wheel data sign bit 4975 * d2-d0: wheel data 4976 */ 4977 z = (pb->ipacket[3] & MOUSE_EXPLORER_ZNEG) ? 4978 (pb->ipacket[3] & 0x0f) - 16 : 4979 (pb->ipacket[3] & 0x0f); 4980 ms.button |= 4981 (pb->ipacket[3] & MOUSE_EXPLORER_BUTTON4DOWN) ? 4982 MOUSE_BUTTON4DOWN : 0; 4983 ms.button |= 4984 (pb->ipacket[3] & MOUSE_EXPLORER_BUTTON5DOWN) ? 4985 MOUSE_BUTTON5DOWN : 0; 4986 break; 4987 4988 case MOUSE_MODEL_INTELLI: 4989 case MOUSE_MODEL_NET: 4990 /* wheel data is in the fourth byte */ 4991 z = (char)pb->ipacket[3]; 4992 /* 4993 * XXX some mice may send 7 when there is no Z movement? */ 4994 if ((z >= 7) || (z <= -7)) 4995 z = 0; 4996 /* some compatible mice have additional buttons */ 4997 ms.button |= (c & MOUSE_PS2INTELLI_BUTTON4DOWN) ? 4998 MOUSE_BUTTON4DOWN : 0; 4999 ms.button |= (c & MOUSE_PS2INTELLI_BUTTON5DOWN) ? 5000 MOUSE_BUTTON5DOWN : 0; 5001 break; 5002 5003 case MOUSE_MODEL_MOUSEMANPLUS: 5004 proc_mmanplus(sc, pb, &ms, &x, &y, &z); 5005 break; 5006 5007 case MOUSE_MODEL_GLIDEPOINT: 5008 /* `tapping' action */ 5009 ms.button |= ((c & MOUSE_PS2_TAP)) ? 0 : 5010 MOUSE_BUTTON4DOWN; 5011 break; 5012 5013 case MOUSE_MODEL_NETSCROLL: 5014 /* 5015 * three additional bytes encode buttons and 5016 * wheel events 5017 */ 5018 ms.button |= (pb->ipacket[3] & MOUSE_PS2_BUTTON3DOWN) ? 5019 MOUSE_BUTTON4DOWN : 0; 5020 ms.button |= (pb->ipacket[3] & MOUSE_PS2_BUTTON1DOWN) ? 5021 MOUSE_BUTTON5DOWN : 0; 5022 z = (pb->ipacket[3] & MOUSE_PS2_XNEG) ? 5023 pb->ipacket[4] - 256 : pb->ipacket[4]; 5024 break; 5025 5026 case MOUSE_MODEL_THINK: 5027 /* the fourth button state in the first byte */ 5028 ms.button |= (c & MOUSE_PS2_TAP) ? 5029 MOUSE_BUTTON4DOWN : 0; 5030 break; 5031 5032 case MOUSE_MODEL_VERSAPAD: 5033 proc_versapad(sc, pb, &ms, &x, &y, &z); 5034 c = ((x < 0) ? MOUSE_PS2_XNEG : 0) | 5035 ((y < 0) ? MOUSE_PS2_YNEG : 0); 5036 break; 5037 5038 case MOUSE_MODEL_4D: 5039 /* 5040 * b7 b6 b5 b4 b3 b2 b1 b0 5041 * byte 1: s2 d2 s1 d1 1 M R L 5042 * byte 2: sx x x x x x x x 5043 * byte 3: sy y y y y y y y 5044 * 5045 * s1: wheel 1 direction 5046 * d1: wheel 1 data 5047 * s2: wheel 2 direction 5048 * d2: wheel 2 data 5049 */ 5050 x = (pb->ipacket[1] & 0x80) ? 5051 pb->ipacket[1] - 256 : pb->ipacket[1]; 5052 y = (pb->ipacket[2] & 0x80) ? 5053 pb->ipacket[2] - 256 : pb->ipacket[2]; 5054 switch (c & MOUSE_4D_WHEELBITS) { 5055 case 0x10: 5056 z = 1; 5057 break; 5058 case 0x30: 5059 z = -1; 5060 break; 5061 case 0x40: /* XXX 2nd wheel turning right */ 5062 z = 2; 5063 break; 5064 case 0xc0: /* XXX 2nd wheel turning left */ 5065 z = -2; 5066 break; 5067 } 5068 break; 5069 5070 case MOUSE_MODEL_4DPLUS: 5071 if ((x < 16 - 256) && (y < 16 - 256)) { 5072 /* 5073 * b7 b6 b5 b4 b3 b2 b1 b0 5074 * byte 1: 0 0 1 1 1 M R L 5075 * byte 2: 0 0 0 0 1 0 0 0 5076 * byte 3: 0 0 0 0 S s d1 d0 5077 * 5078 * L, M, R, S: left, middle, right, 5079 * and side buttons 5080 * s: wheel data sign bit 5081 * d1-d0: wheel data 5082 */ 5083 x = y = 0; 5084 if (pb->ipacket[2] & MOUSE_4DPLUS_BUTTON4DOWN) 5085 ms.button |= MOUSE_BUTTON4DOWN; 5086 z = (pb->ipacket[2] & MOUSE_4DPLUS_ZNEG) ? 5087 ((pb->ipacket[2] & 0x07) - 8) : 5088 (pb->ipacket[2] & 0x07) ; 5089 } else { 5090 /* preserve previous button states */ 5091 ms.button |= ms.obutton & MOUSE_EXTBUTTONS; 5092 } 5093 break; 5094 5095 case MOUSE_MODEL_SYNAPTICS: 5096 if (pb->inputbytes == MOUSE_PS2_PACKETSIZE) 5097 if (proc_synaptics_mux(sc, pb)) 5098 goto next; 5099 5100 if (proc_synaptics(sc, pb, &ms, &x, &y, &z) != 0) { 5101 VLOG(3, (LOG_DEBUG, "synaptics: " 5102 "packet rejected\n")); 5103 goto next; 5104 } 5105 break; 5106 5107 case MOUSE_MODEL_ELANTECH: 5108 if (proc_elantech(sc, pb, &ms, &x, &y, &z) != 0) { 5109 VLOG(3, (LOG_DEBUG, "elantech: " 5110 "packet rejected\n")); 5111 goto next; 5112 } 5113 break; 5114 5115 case MOUSE_MODEL_TRACKPOINT: 5116 case MOUSE_MODEL_GENERIC: 5117 default: 5118 break; 5119 } 5120 5121 #ifdef EVDEV_SUPPORT 5122 if (evdev_rcpt_mask & EVDEV_RCPT_HW_MOUSE && 5123 sc->hw.model != MOUSE_MODEL_ELANTECH && 5124 sc->hw.model != MOUSE_MODEL_SYNAPTICS) { 5125 evdev_push_rel(sc->evdev_r, REL_X, x); 5126 evdev_push_rel(sc->evdev_r, REL_Y, -y); 5127 5128 switch (sc->hw.model) { 5129 case MOUSE_MODEL_EXPLORER: 5130 case MOUSE_MODEL_INTELLI: 5131 case MOUSE_MODEL_NET: 5132 case MOUSE_MODEL_NETSCROLL: 5133 case MOUSE_MODEL_4DPLUS: 5134 evdev_push_rel(sc->evdev_r, REL_WHEEL, -z); 5135 break; 5136 case MOUSE_MODEL_MOUSEMANPLUS: 5137 case MOUSE_MODEL_4D: 5138 switch (z) { 5139 case 1: 5140 case -1: 5141 evdev_push_rel(sc->evdev_r, REL_WHEEL, -z); 5142 break; 5143 case 2: 5144 case -2: 5145 evdev_push_rel(sc->evdev_r, REL_HWHEEL, z / 2); 5146 break; 5147 } 5148 break; 5149 } 5150 5151 evdev_push_mouse_btn(sc->evdev_r, ms.button); 5152 evdev_sync(sc->evdev_r); 5153 } 5154 #endif 5155 5156 /* scale values */ 5157 if (sc->mode.accelfactor >= 1) { 5158 if (x != 0) { 5159 x = x * x / sc->mode.accelfactor; 5160 if (x == 0) 5161 x = 1; 5162 if (c & MOUSE_PS2_XNEG) 5163 x = -x; 5164 } 5165 if (y != 0) { 5166 y = y * y / sc->mode.accelfactor; 5167 if (y == 0) 5168 y = 1; 5169 if (c & MOUSE_PS2_YNEG) 5170 y = -y; 5171 } 5172 } 5173 5174 /* Store last packet for reinjection if it has not been set already */ 5175 if (timevalisset(&sc->idletimeout) && sc->idlepacket.inputbytes == 0) 5176 sc->idlepacket = *pb; 5177 5178 ms.dx = x; 5179 ms.dy = y; 5180 ms.dz = z; 5181 ms.flags = ((x || y || z) ? MOUSE_POSCHANGED : 0) | 5182 (ms.obutton ^ ms.button); 5183 5184 pb->inputbytes = tame_mouse(sc, pb, &ms, pb->ipacket); 5185 5186 sc->status.flags |= ms.flags; 5187 sc->status.dx += ms.dx; 5188 sc->status.dy += ms.dy; 5189 sc->status.dz += ms.dz; 5190 sc->status.button = ms.button; 5191 sc->button = ms.button; 5192 5193 next_native: 5194 sc->watchdog = FALSE; 5195 5196 /* queue data */ 5197 if (sc->queue.count + pb->inputbytes < sizeof(sc->queue.buf)) { 5198 l = imin(pb->inputbytes, 5199 sizeof(sc->queue.buf) - sc->queue.tail); 5200 bcopy(&pb->ipacket[0], &sc->queue.buf[sc->queue.tail], l); 5201 if (pb->inputbytes > l) 5202 bcopy(&pb->ipacket[l], &sc->queue.buf[0], 5203 pb->inputbytes - l); 5204 sc->queue.tail = (sc->queue.tail + pb->inputbytes) % 5205 sizeof(sc->queue.buf); 5206 sc->queue.count += pb->inputbytes; 5207 } 5208 5209 next: 5210 pb->inputbytes = 0; 5211 if (++sc->pqueue_start >= PSM_PACKETQUEUE) 5212 sc->pqueue_start = 0; 5213 } while (sc->pqueue_start != sc->pqueue_end); 5214 5215 if (sc->state & PSM_ASLP) { 5216 sc->state &= ~PSM_ASLP; 5217 wakeup(sc); 5218 } 5219 selwakeuppri(&sc->rsel, PZERO); 5220 if (sc->async != NULL) { 5221 pgsigio(&sc->async, SIGIO, 0); 5222 } 5223 sc->state &= ~PSM_SOFTARMED; 5224 5225 /* schedule injection of predefined packet after idletimeout 5226 * if no data packets have been received from psmintr */ 5227 if (timevalisset(&sc->idletimeout)) { 5228 sc->state |= PSM_SOFTARMED; 5229 callout_reset(&sc->softcallout, tvtohz(&sc->idletimeout), 5230 psmsoftintridle, sc); 5231 VLOG(2, (LOG_DEBUG, "softintr: callout set: %d ticks\n", 5232 tvtohz(&sc->idletimeout))); 5233 } 5234 splx(s); 5235 } 5236 5237 static int 5238 psmpoll(struct cdev *dev, int events, struct thread *td) 5239 { 5240 struct psm_softc *sc = dev->si_drv1; 5241 int s; 5242 int revents = 0; 5243 5244 /* Return true if a mouse event available */ 5245 s = spltty(); 5246 if (events & (POLLIN | POLLRDNORM)) { 5247 if (sc->queue.count > 0) 5248 revents |= events & (POLLIN | POLLRDNORM); 5249 else 5250 selrecord(td, &sc->rsel); 5251 } 5252 splx(s); 5253 5254 return (revents); 5255 } 5256 5257 /* vendor/model specific routines */ 5258 5259 static int mouse_id_proc1(KBDC kbdc, int res, int scale, int *status) 5260 { 5261 if (set_mouse_resolution(kbdc, res) != res) 5262 return (FALSE); 5263 if (set_mouse_scaling(kbdc, scale) && 5264 set_mouse_scaling(kbdc, scale) && 5265 set_mouse_scaling(kbdc, scale) && 5266 (get_mouse_status(kbdc, status, 0, 3) >= 3)) 5267 return (TRUE); 5268 return (FALSE); 5269 } 5270 5271 static int 5272 mouse_ext_command(KBDC kbdc, int command) 5273 { 5274 int c; 5275 5276 c = (command >> 6) & 0x03; 5277 if (set_mouse_resolution(kbdc, c) != c) 5278 return (FALSE); 5279 c = (command >> 4) & 0x03; 5280 if (set_mouse_resolution(kbdc, c) != c) 5281 return (FALSE); 5282 c = (command >> 2) & 0x03; 5283 if (set_mouse_resolution(kbdc, c) != c) 5284 return (FALSE); 5285 c = (command >> 0) & 0x03; 5286 if (set_mouse_resolution(kbdc, c) != c) 5287 return (FALSE); 5288 return (TRUE); 5289 } 5290 5291 #ifdef notyet 5292 /* Logitech MouseMan Cordless II */ 5293 static int 5294 enable_lcordless(struct psm_softc *sc, enum probearg arg) 5295 { 5296 KBDC kbdc = sc->kbdc; 5297 int status[3]; 5298 int ch; 5299 5300 if (!mouse_id_proc1(kbdc, PSMD_RES_HIGH, 2, status)) 5301 return (FALSE); 5302 if (status[1] == PSMD_RES_HIGH) 5303 return (FALSE); 5304 ch = (status[0] & 0x07) - 1; /* channel # */ 5305 if ((ch <= 0) || (ch > 4)) 5306 return (FALSE); 5307 /* 5308 * status[1]: always one? 5309 * status[2]: battery status? (0-100) 5310 */ 5311 return (TRUE); 5312 } 5313 #endif /* notyet */ 5314 5315 /* Genius NetScroll Mouse, MouseSystems SmartScroll Mouse */ 5316 static int 5317 enable_groller(struct psm_softc *sc, enum probearg arg) 5318 { 5319 KBDC kbdc = sc->kbdc; 5320 int status[3]; 5321 5322 /* 5323 * The special sequence to enable the fourth button and the 5324 * roller. Immediately after this sequence check status bytes. 5325 * if the mouse is NetScroll, the second and the third bytes are 5326 * '3' and 'D'. 5327 */ 5328 5329 /* 5330 * If the mouse is an ordinary PS/2 mouse, the status bytes should 5331 * look like the following. 5332 * 5333 * byte 1 bit 7 always 0 5334 * bit 6 stream mode (0) 5335 * bit 5 disabled (0) 5336 * bit 4 1:1 scaling (0) 5337 * bit 3 always 0 5338 * bit 0-2 button status 5339 * byte 2 resolution (PSMD_RES_HIGH) 5340 * byte 3 report rate (?) 5341 */ 5342 5343 if (!mouse_id_proc1(kbdc, PSMD_RES_HIGH, 1, status)) 5344 return (FALSE); 5345 if ((status[1] != '3') || (status[2] != 'D')) 5346 return (FALSE); 5347 /* FIXME: SmartScroll Mouse has 5 buttons! XXX */ 5348 if (arg == PROBE) 5349 sc->hw.buttons = 4; 5350 return (TRUE); 5351 } 5352 5353 /* Genius NetMouse/NetMouse Pro, ASCII Mie Mouse, NetScroll Optical */ 5354 static int 5355 enable_gmouse(struct psm_softc *sc, enum probearg arg) 5356 { 5357 KBDC kbdc = sc->kbdc; 5358 int status[3]; 5359 5360 /* 5361 * The special sequence to enable the middle, "rubber" button. 5362 * Immediately after this sequence check status bytes. 5363 * if the mouse is NetMouse, NetMouse Pro, or ASCII MIE Mouse, 5364 * the second and the third bytes are '3' and 'U'. 5365 * NOTE: NetMouse reports that it has three buttons although it has 5366 * two buttons and a rubber button. NetMouse Pro and MIE Mouse 5367 * say they have three buttons too and they do have a button on the 5368 * side... 5369 */ 5370 if (!mouse_id_proc1(kbdc, PSMD_RES_HIGH, 1, status)) 5371 return (FALSE); 5372 if ((status[1] != '3') || (status[2] != 'U')) 5373 return (FALSE); 5374 return (TRUE); 5375 } 5376 5377 /* ALPS GlidePoint */ 5378 static int 5379 enable_aglide(struct psm_softc *sc, enum probearg arg) 5380 { 5381 KBDC kbdc = sc->kbdc; 5382 int status[3]; 5383 5384 /* 5385 * The special sequence to obtain ALPS GlidePoint specific 5386 * information. Immediately after this sequence, status bytes will 5387 * contain something interesting. 5388 * NOTE: ALPS produces several models of GlidePoint. Some of those 5389 * do not respond to this sequence, thus, cannot be detected this way. 5390 */ 5391 if (set_mouse_sampling_rate(kbdc, 100) != 100) 5392 return (FALSE); 5393 if (!mouse_id_proc1(kbdc, PSMD_RES_LOW, 2, status)) 5394 return (FALSE); 5395 if ((status[1] == PSMD_RES_LOW) || (status[2] == 100)) 5396 return (FALSE); 5397 return (TRUE); 5398 } 5399 5400 /* Kensington ThinkingMouse/Trackball */ 5401 static int 5402 enable_kmouse(struct psm_softc *sc, enum probearg arg) 5403 { 5404 static u_char rate[] = { 20, 60, 40, 20, 20, 60, 40, 20, 20 }; 5405 KBDC kbdc = sc->kbdc; 5406 int status[3]; 5407 int id1; 5408 int id2; 5409 int i; 5410 5411 id1 = get_aux_id(kbdc); 5412 if (set_mouse_sampling_rate(kbdc, 10) != 10) 5413 return (FALSE); 5414 /* 5415 * The device is now in the native mode? It returns a different 5416 * ID value... 5417 */ 5418 id2 = get_aux_id(kbdc); 5419 if ((id1 == id2) || (id2 != 2)) 5420 return (FALSE); 5421 5422 if (set_mouse_resolution(kbdc, PSMD_RES_LOW) != PSMD_RES_LOW) 5423 return (FALSE); 5424 #if PSM_DEBUG >= 2 5425 /* at this point, resolution is LOW, sampling rate is 10/sec */ 5426 if (get_mouse_status(kbdc, status, 0, 3) < 3) 5427 return (FALSE); 5428 #endif 5429 5430 /* 5431 * The special sequence to enable the third and fourth buttons. 5432 * Otherwise they behave like the first and second buttons. 5433 */ 5434 for (i = 0; i < nitems(rate); ++i) 5435 if (set_mouse_sampling_rate(kbdc, rate[i]) != rate[i]) 5436 return (FALSE); 5437 5438 /* 5439 * At this point, the device is using default resolution and 5440 * sampling rate for the native mode. 5441 */ 5442 if (get_mouse_status(kbdc, status, 0, 3) < 3) 5443 return (FALSE); 5444 if ((status[1] == PSMD_RES_LOW) || (status[2] == rate[i - 1])) 5445 return (FALSE); 5446 5447 /* the device appears be enabled by this sequence, diable it for now */ 5448 disable_aux_dev(kbdc); 5449 empty_aux_buffer(kbdc, 5); 5450 5451 return (TRUE); 5452 } 5453 5454 /* Logitech MouseMan+/FirstMouse+, IBM ScrollPoint Mouse */ 5455 static int 5456 enable_mmanplus(struct psm_softc *sc, enum probearg arg) 5457 { 5458 KBDC kbdc = sc->kbdc; 5459 int data[3]; 5460 5461 /* the special sequence to enable the fourth button and the roller. */ 5462 /* 5463 * NOTE: for ScrollPoint to respond correctly, the SET_RESOLUTION 5464 * must be called exactly three times since the last RESET command 5465 * before this sequence. XXX 5466 */ 5467 if (!set_mouse_scaling(kbdc, 1)) 5468 return (FALSE); 5469 if (!mouse_ext_command(kbdc, 0x39) || !mouse_ext_command(kbdc, 0xdb)) 5470 return (FALSE); 5471 if (get_mouse_status(kbdc, data, 1, 3) < 3) 5472 return (FALSE); 5473 5474 /* 5475 * PS2++ protocol, packet type 0 5476 * 5477 * b7 b6 b5 b4 b3 b2 b1 b0 5478 * byte 1: * 1 p3 p2 1 * * * 5479 * byte 2: 1 1 p1 p0 m1 m0 1 0 5480 * byte 3: m7 m6 m5 m4 m3 m2 m1 m0 5481 * 5482 * p3-p0: packet type: 0 5483 * m7-m0: model ID: MouseMan+:0x50, 5484 * FirstMouse+:0x51, 5485 * ScrollPoint:0x58... 5486 */ 5487 /* check constant bits */ 5488 if ((data[0] & MOUSE_PS2PLUS_SYNCMASK) != MOUSE_PS2PLUS_SYNC) 5489 return (FALSE); 5490 if ((data[1] & 0xc3) != 0xc2) 5491 return (FALSE); 5492 /* check d3-d0 in byte 2 */ 5493 if (!MOUSE_PS2PLUS_CHECKBITS(data)) 5494 return (FALSE); 5495 /* check p3-p0 */ 5496 if (MOUSE_PS2PLUS_PACKET_TYPE(data) != 0) 5497 return (FALSE); 5498 5499 if (arg == PROBE) { 5500 sc->hw.hwid &= 0x00ff; 5501 sc->hw.hwid |= data[2] << 8; /* save model ID */ 5502 } 5503 5504 /* 5505 * MouseMan+ (or FirstMouse+) is now in its native mode, in which 5506 * the wheel and the fourth button events are encoded in the 5507 * special data packet. The mouse may be put in the IntelliMouse mode 5508 * if it is initialized by the IntelliMouse's method. 5509 */ 5510 return (TRUE); 5511 } 5512 5513 /* MS IntelliMouse Explorer */ 5514 static int 5515 enable_msexplorer(struct psm_softc *sc, enum probearg arg) 5516 { 5517 KBDC kbdc = sc->kbdc; 5518 static u_char rate0[] = { 200, 100, 80, }; 5519 static u_char rate1[] = { 200, 200, 80, }; 5520 int id; 5521 int i; 5522 5523 /* 5524 * This is needed for at least A4Tech X-7xx mice - they do not go 5525 * straight to Explorer mode, but need to be set to Intelli mode 5526 * first. 5527 */ 5528 enable_msintelli(sc, arg); 5529 5530 /* the special sequence to enable the extra buttons and the roller. */ 5531 for (i = 0; i < nitems(rate1); ++i) 5532 if (set_mouse_sampling_rate(kbdc, rate1[i]) != rate1[i]) 5533 return (FALSE); 5534 /* the device will give the genuine ID only after the above sequence */ 5535 id = get_aux_id(kbdc); 5536 if (id != PSM_EXPLORER_ID) 5537 return (FALSE); 5538 5539 if (arg == PROBE) { 5540 sc->hw.buttons = 5; /* IntelliMouse Explorer XXX */ 5541 sc->hw.hwid = id; 5542 } 5543 5544 /* 5545 * XXX: this is a kludge to fool some KVM switch products 5546 * which think they are clever enough to know the 4-byte IntelliMouse 5547 * protocol, and assume any other protocols use 3-byte packets. 5548 * They don't convey 4-byte data packets from the IntelliMouse Explorer 5549 * correctly to the host computer because of this! 5550 * The following sequence is actually IntelliMouse's "wake up" 5551 * sequence; it will make the KVM think the mouse is IntelliMouse 5552 * when it is in fact IntelliMouse Explorer. 5553 */ 5554 for (i = 0; i < nitems(rate0); ++i) 5555 if (set_mouse_sampling_rate(kbdc, rate0[i]) != rate0[i]) 5556 break; 5557 get_aux_id(kbdc); 5558 5559 return (TRUE); 5560 } 5561 5562 /* 5563 * MS IntelliMouse 5564 * Logitech MouseMan+ and FirstMouse+ will also respond to this 5565 * probe routine and act like IntelliMouse. 5566 */ 5567 static int 5568 enable_msintelli(struct psm_softc *sc, enum probearg arg) 5569 { 5570 KBDC kbdc = sc->kbdc; 5571 static u_char rate[] = { 200, 100, 80, }; 5572 int id; 5573 int i; 5574 5575 /* the special sequence to enable the third button and the roller. */ 5576 for (i = 0; i < nitems(rate); ++i) 5577 if (set_mouse_sampling_rate(kbdc, rate[i]) != rate[i]) 5578 return (FALSE); 5579 /* the device will give the genuine ID only after the above sequence */ 5580 id = get_aux_id(kbdc); 5581 if (id != PSM_INTELLI_ID) 5582 return (FALSE); 5583 5584 if (arg == PROBE) { 5585 sc->hw.buttons = 3; 5586 sc->hw.hwid = id; 5587 } 5588 5589 return (TRUE); 5590 } 5591 5592 /* 5593 * A4 Tech 4D Mouse 5594 * Newer wheel mice from A4 Tech may use the 4D+ protocol. 5595 */ 5596 static int 5597 enable_4dmouse(struct psm_softc *sc, enum probearg arg) 5598 { 5599 static u_char rate[] = { 200, 100, 80, 60, 40, 20 }; 5600 KBDC kbdc = sc->kbdc; 5601 int id; 5602 int i; 5603 5604 for (i = 0; i < nitems(rate); ++i) 5605 if (set_mouse_sampling_rate(kbdc, rate[i]) != rate[i]) 5606 return (FALSE); 5607 id = get_aux_id(kbdc); 5608 /* 5609 * WinEasy 4D, 4 Way Scroll 4D: 6 5610 * Cable-Free 4D: 8 (4DPLUS) 5611 * WinBest 4D+, 4 Way Scroll 4D+: 8 (4DPLUS) 5612 */ 5613 if (id != PSM_4DMOUSE_ID) 5614 return (FALSE); 5615 5616 if (arg == PROBE) { 5617 sc->hw.buttons = 3; /* XXX some 4D mice have 4? */ 5618 sc->hw.hwid = id; 5619 } 5620 5621 return (TRUE); 5622 } 5623 5624 /* 5625 * A4 Tech 4D+ Mouse 5626 * Newer wheel mice from A4 Tech seem to use this protocol. 5627 * Older models are recognized as either 4D Mouse or IntelliMouse. 5628 */ 5629 static int 5630 enable_4dplus(struct psm_softc *sc, enum probearg arg) 5631 { 5632 KBDC kbdc = sc->kbdc; 5633 int id; 5634 5635 /* 5636 * enable_4dmouse() already issued the following ID sequence... 5637 static u_char rate[] = { 200, 100, 80, 60, 40, 20 }; 5638 int i; 5639 5640 for (i = 0; i < sizeof(rate)/sizeof(rate[0]); ++i) 5641 if (set_mouse_sampling_rate(kbdc, rate[i]) != rate[i]) 5642 return (FALSE); 5643 */ 5644 5645 id = get_aux_id(kbdc); 5646 switch (id) { 5647 case PSM_4DPLUS_ID: 5648 break; 5649 case PSM_4DPLUS_RFSW35_ID: 5650 break; 5651 default: 5652 return (FALSE); 5653 } 5654 5655 if (arg == PROBE) { 5656 sc->hw.buttons = (id == PSM_4DPLUS_ID) ? 4 : 3; 5657 sc->hw.hwid = id; 5658 } 5659 5660 return (TRUE); 5661 } 5662 5663 /* Synaptics Touchpad */ 5664 static int 5665 synaptics_sysctl(SYSCTL_HANDLER_ARGS) 5666 { 5667 struct psm_softc *sc; 5668 int error, arg; 5669 5670 if (oidp->oid_arg1 == NULL || oidp->oid_arg2 < 0 || 5671 oidp->oid_arg2 > SYNAPTICS_SYSCTL_LAST) 5672 return (EINVAL); 5673 5674 sc = oidp->oid_arg1; 5675 5676 /* Read the current value. */ 5677 arg = *(int *)((char *)sc + oidp->oid_arg2); 5678 error = sysctl_handle_int(oidp, &arg, 0, req); 5679 5680 /* Sanity check. */ 5681 if (error || !req->newptr) 5682 return (error); 5683 5684 /* 5685 * Check that the new value is in the concerned node's range 5686 * of values. 5687 */ 5688 switch (oidp->oid_arg2) { 5689 case SYNAPTICS_SYSCTL_MIN_PRESSURE: 5690 case SYNAPTICS_SYSCTL_MAX_PRESSURE: 5691 if (arg < 0 || arg > 255) 5692 return (EINVAL); 5693 break; 5694 case SYNAPTICS_SYSCTL_MAX_WIDTH: 5695 if (arg < 4 || arg > 15) 5696 return (EINVAL); 5697 break; 5698 case SYNAPTICS_SYSCTL_MARGIN_TOP: 5699 case SYNAPTICS_SYSCTL_MARGIN_BOTTOM: 5700 case SYNAPTICS_SYSCTL_NA_TOP: 5701 case SYNAPTICS_SYSCTL_NA_BOTTOM: 5702 if (arg < 0 || arg > sc->synhw.maximumYCoord) 5703 return (EINVAL); 5704 break; 5705 case SYNAPTICS_SYSCTL_SOFTBUTTON2_X: 5706 case SYNAPTICS_SYSCTL_SOFTBUTTON3_X: 5707 /* Softbuttons is clickpad only feature */ 5708 if (!sc->synhw.capClickPad && arg != 0) 5709 return (EINVAL); 5710 /* FALLTHROUGH */ 5711 case SYNAPTICS_SYSCTL_MARGIN_RIGHT: 5712 case SYNAPTICS_SYSCTL_MARGIN_LEFT: 5713 case SYNAPTICS_SYSCTL_NA_RIGHT: 5714 case SYNAPTICS_SYSCTL_NA_LEFT: 5715 if (arg < 0 || arg > sc->synhw.maximumXCoord) 5716 return (EINVAL); 5717 break; 5718 case SYNAPTICS_SYSCTL_WINDOW_MIN: 5719 case SYNAPTICS_SYSCTL_WINDOW_MAX: 5720 case SYNAPTICS_SYSCTL_TAP_MIN_QUEUE: 5721 if (arg < 1 || arg > SYNAPTICS_PACKETQUEUE) 5722 return (EINVAL); 5723 break; 5724 case SYNAPTICS_SYSCTL_MULTIPLICATOR: 5725 case SYNAPTICS_SYSCTL_WEIGHT_CURRENT: 5726 case SYNAPTICS_SYSCTL_WEIGHT_PREVIOUS: 5727 case SYNAPTICS_SYSCTL_WEIGHT_PREVIOUS_NA: 5728 case SYNAPTICS_SYSCTL_WEIGHT_LEN_SQUARED: 5729 case SYNAPTICS_SYSCTL_DIV_MIN: 5730 case SYNAPTICS_SYSCTL_DIV_MAX: 5731 case SYNAPTICS_SYSCTL_DIV_MAX_NA: 5732 case SYNAPTICS_SYSCTL_DIV_LEN: 5733 case SYNAPTICS_SYSCTL_VSCROLL_DIV_MIN: 5734 case SYNAPTICS_SYSCTL_VSCROLL_DIV_MAX: 5735 if (arg < 1) 5736 return (EINVAL); 5737 break; 5738 case SYNAPTICS_SYSCTL_TAP_MAX_DELTA: 5739 case SYNAPTICS_SYSCTL_TAPHOLD_TIMEOUT: 5740 case SYNAPTICS_SYSCTL_VSCROLL_MIN_DELTA: 5741 if (arg < 0) 5742 return (EINVAL); 5743 break; 5744 case SYNAPTICS_SYSCTL_VSCROLL_HOR_AREA: 5745 if (arg < -sc->synhw.maximumXCoord || 5746 arg > sc->synhw.maximumXCoord) 5747 return (EINVAL); 5748 break; 5749 case SYNAPTICS_SYSCTL_SOFTBUTTONS_Y: 5750 /* Softbuttons is clickpad only feature */ 5751 if (!sc->synhw.capClickPad && arg != 0) 5752 return (EINVAL); 5753 /* FALLTHROUGH */ 5754 case SYNAPTICS_SYSCTL_VSCROLL_VER_AREA: 5755 if (arg < -sc->synhw.maximumYCoord || 5756 arg > sc->synhw.maximumYCoord) 5757 return (EINVAL); 5758 break; 5759 case SYNAPTICS_SYSCTL_TOUCHPAD_OFF: 5760 case SYNAPTICS_SYSCTL_THREE_FINGER_DRAG: 5761 case SYNAPTICS_SYSCTL_NATURAL_SCROLL: 5762 if (arg < 0 || arg > 1) 5763 return (EINVAL); 5764 break; 5765 default: 5766 return (EINVAL); 5767 } 5768 5769 /* Update. */ 5770 *(int *)((char *)sc + oidp->oid_arg2) = arg; 5771 5772 return (error); 5773 } 5774 5775 static void 5776 synaptics_sysctl_create_softbuttons_tree(struct psm_softc *sc) 5777 { 5778 /* 5779 * Set predefined sizes for softbuttons. 5780 * Values are taken to match HP Pavilion dv6 clickpad drawings 5781 * with thin middle softbutton placed on separator 5782 */ 5783 5784 /* hw.psm.synaptics.softbuttons_y */ 5785 sc->syninfo.softbuttons_y = sc->synhw.topButtonPad ? -1700 : 1700; 5786 SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx, 5787 SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO, 5788 "softbuttons_y", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY, 5789 sc, SYNAPTICS_SYSCTL_SOFTBUTTONS_Y, 5790 synaptics_sysctl, "I", 5791 "Vertical size of softbuttons area"); 5792 5793 /* hw.psm.synaptics.softbutton2_x */ 5794 sc->syninfo.softbutton2_x = 3100; 5795 SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx, 5796 SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO, 5797 "softbutton2_x", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY, 5798 sc, SYNAPTICS_SYSCTL_SOFTBUTTON2_X, 5799 synaptics_sysctl, "I", 5800 "Horisontal position of 2-nd softbutton left edge (0-disable)"); 5801 5802 /* hw.psm.synaptics.softbutton3_x */ 5803 sc->syninfo.softbutton3_x = 3900; 5804 SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx, 5805 SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO, 5806 "softbutton3_x", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY, 5807 sc, SYNAPTICS_SYSCTL_SOFTBUTTON3_X, 5808 synaptics_sysctl, "I", 5809 "Horisontal position of 3-rd softbutton left edge (0-disable)"); 5810 } 5811 5812 static void 5813 synaptics_sysctl_create_tree(struct psm_softc *sc, const char *name, 5814 const char *descr) 5815 { 5816 5817 if (sc->syninfo.sysctl_tree != NULL) 5818 return; 5819 5820 /* Attach extra synaptics sysctl nodes under hw.psm.synaptics */ 5821 sysctl_ctx_init(&sc->syninfo.sysctl_ctx); 5822 sc->syninfo.sysctl_tree = SYSCTL_ADD_NODE(&sc->syninfo.sysctl_ctx, 5823 SYSCTL_STATIC_CHILDREN(_hw_psm), OID_AUTO, name, CTLFLAG_RD, 5824 0, descr); 5825 5826 /* hw.psm.synaptics.directional_scrolls. */ 5827 sc->syninfo.directional_scrolls = 0; 5828 SYSCTL_ADD_INT(&sc->syninfo.sysctl_ctx, 5829 SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO, 5830 "directional_scrolls", CTLFLAG_RW|CTLFLAG_ANYBODY, 5831 &sc->syninfo.directional_scrolls, 0, 5832 "Enable hardware scrolling pad (if non-zero) or register it as " 5833 "extended buttons (if 0)"); 5834 5835 /* hw.psm.synaptics.max_x. */ 5836 sc->syninfo.max_x = 6143; 5837 SYSCTL_ADD_INT(&sc->syninfo.sysctl_ctx, 5838 SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO, 5839 "max_x", CTLFLAG_RD|CTLFLAG_ANYBODY, 5840 &sc->syninfo.max_x, 0, 5841 "Horizontal reporting range"); 5842 5843 /* hw.psm.synaptics.max_y. */ 5844 sc->syninfo.max_y = 6143; 5845 SYSCTL_ADD_INT(&sc->syninfo.sysctl_ctx, 5846 SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO, 5847 "max_y", CTLFLAG_RD|CTLFLAG_ANYBODY, 5848 &sc->syninfo.max_y, 0, 5849 "Vertical reporting range"); 5850 5851 /* 5852 * Turn off two finger scroll if we have a 5853 * physical area reserved for scrolling or when 5854 * there's no multi finger support. 5855 */ 5856 if (sc->synhw.verticalScroll || (sc->synhw.capMultiFinger == 0 && 5857 sc->synhw.capAdvancedGestures == 0)) 5858 sc->syninfo.two_finger_scroll = 0; 5859 else 5860 sc->syninfo.two_finger_scroll = 1; 5861 /* hw.psm.synaptics.two_finger_scroll. */ 5862 SYSCTL_ADD_INT(&sc->syninfo.sysctl_ctx, 5863 SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO, 5864 "two_finger_scroll", CTLFLAG_RW|CTLFLAG_ANYBODY, 5865 &sc->syninfo.two_finger_scroll, 0, 5866 "Enable two finger scrolling"); 5867 5868 /* hw.psm.synaptics.min_pressure. */ 5869 sc->syninfo.min_pressure = 32; 5870 SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx, 5871 SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO, 5872 "min_pressure", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY, 5873 sc, SYNAPTICS_SYSCTL_MIN_PRESSURE, 5874 synaptics_sysctl, "I", 5875 "Minimum pressure required to start an action"); 5876 5877 /* hw.psm.synaptics.max_pressure. */ 5878 sc->syninfo.max_pressure = 220; 5879 SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx, 5880 SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO, 5881 "max_pressure", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY, 5882 sc, SYNAPTICS_SYSCTL_MAX_PRESSURE, 5883 synaptics_sysctl, "I", 5884 "Maximum pressure to detect palm"); 5885 5886 /* hw.psm.synaptics.max_width. */ 5887 sc->syninfo.max_width = 10; 5888 SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx, 5889 SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO, 5890 "max_width", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY, 5891 sc, SYNAPTICS_SYSCTL_MAX_WIDTH, 5892 synaptics_sysctl, "I", 5893 "Maximum finger width to detect palm"); 5894 5895 /* hw.psm.synaptics.top_margin. */ 5896 sc->syninfo.margin_top = 200; 5897 SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx, 5898 SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO, 5899 "margin_top", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY, 5900 sc, SYNAPTICS_SYSCTL_MARGIN_TOP, 5901 synaptics_sysctl, "I", 5902 "Top margin"); 5903 5904 /* hw.psm.synaptics.right_margin. */ 5905 sc->syninfo.margin_right = 200; 5906 SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx, 5907 SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO, 5908 "margin_right", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY, 5909 sc, SYNAPTICS_SYSCTL_MARGIN_RIGHT, 5910 synaptics_sysctl, "I", 5911 "Right margin"); 5912 5913 /* hw.psm.synaptics.bottom_margin. */ 5914 sc->syninfo.margin_bottom = 200; 5915 SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx, 5916 SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO, 5917 "margin_bottom", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY, 5918 sc, SYNAPTICS_SYSCTL_MARGIN_BOTTOM, 5919 synaptics_sysctl, "I", 5920 "Bottom margin"); 5921 5922 /* hw.psm.synaptics.left_margin. */ 5923 sc->syninfo.margin_left = 200; 5924 SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx, 5925 SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO, 5926 "margin_left", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY, 5927 sc, SYNAPTICS_SYSCTL_MARGIN_LEFT, 5928 synaptics_sysctl, "I", 5929 "Left margin"); 5930 5931 /* hw.psm.synaptics.na_top. */ 5932 sc->syninfo.na_top = 1783; 5933 SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx, 5934 SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO, 5935 "na_top", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY, 5936 sc, SYNAPTICS_SYSCTL_NA_TOP, 5937 synaptics_sysctl, "I", 5938 "Top noisy area, where weight_previous_na is used instead " 5939 "of weight_previous"); 5940 5941 /* hw.psm.synaptics.na_right. */ 5942 sc->syninfo.na_right = 563; 5943 SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx, 5944 SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO, 5945 "na_right", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY, 5946 sc, SYNAPTICS_SYSCTL_NA_RIGHT, 5947 synaptics_sysctl, "I", 5948 "Right noisy area, where weight_previous_na is used instead " 5949 "of weight_previous"); 5950 5951 /* hw.psm.synaptics.na_bottom. */ 5952 sc->syninfo.na_bottom = 1408; 5953 SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx, 5954 SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO, 5955 "na_bottom", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY, 5956 sc, SYNAPTICS_SYSCTL_NA_BOTTOM, 5957 synaptics_sysctl, "I", 5958 "Bottom noisy area, where weight_previous_na is used instead " 5959 "of weight_previous"); 5960 5961 /* hw.psm.synaptics.na_left. */ 5962 sc->syninfo.na_left = 1600; 5963 SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx, 5964 SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO, 5965 "na_left", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY, 5966 sc, SYNAPTICS_SYSCTL_NA_LEFT, 5967 synaptics_sysctl, "I", 5968 "Left noisy area, where weight_previous_na is used instead " 5969 "of weight_previous"); 5970 5971 /* hw.psm.synaptics.window_min. */ 5972 sc->syninfo.window_min = 4; 5973 SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx, 5974 SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO, 5975 "window_min", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY, 5976 sc, SYNAPTICS_SYSCTL_WINDOW_MIN, 5977 synaptics_sysctl, "I", 5978 "Minimum window size to start an action"); 5979 5980 /* hw.psm.synaptics.window_max. */ 5981 sc->syninfo.window_max = 10; 5982 SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx, 5983 SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO, 5984 "window_max", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY, 5985 sc, SYNAPTICS_SYSCTL_WINDOW_MAX, 5986 synaptics_sysctl, "I", 5987 "Maximum window size"); 5988 5989 /* hw.psm.synaptics.multiplicator. */ 5990 sc->syninfo.multiplicator = 10000; 5991 SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx, 5992 SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO, 5993 "multiplicator", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY, 5994 sc, SYNAPTICS_SYSCTL_MULTIPLICATOR, 5995 synaptics_sysctl, "I", 5996 "Multiplicator to increase precision in averages and divisions"); 5997 5998 /* hw.psm.synaptics.weight_current. */ 5999 sc->syninfo.weight_current = 3; 6000 SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx, 6001 SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO, 6002 "weight_current", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY, 6003 sc, SYNAPTICS_SYSCTL_WEIGHT_CURRENT, 6004 synaptics_sysctl, "I", 6005 "Weight of the current movement in the new average"); 6006 6007 /* hw.psm.synaptics.weight_previous. */ 6008 sc->syninfo.weight_previous = 6; 6009 SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx, 6010 SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO, 6011 "weight_previous", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY, 6012 sc, SYNAPTICS_SYSCTL_WEIGHT_PREVIOUS, 6013 synaptics_sysctl, "I", 6014 "Weight of the previous average"); 6015 6016 /* hw.psm.synaptics.weight_previous_na. */ 6017 sc->syninfo.weight_previous_na = 20; 6018 SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx, 6019 SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO, 6020 "weight_previous_na", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY, 6021 sc, SYNAPTICS_SYSCTL_WEIGHT_PREVIOUS_NA, 6022 synaptics_sysctl, "I", 6023 "Weight of the previous average (inside the noisy area)"); 6024 6025 /* hw.psm.synaptics.weight_len_squared. */ 6026 sc->syninfo.weight_len_squared = 2000; 6027 SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx, 6028 SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO, 6029 "weight_len_squared", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY, 6030 sc, SYNAPTICS_SYSCTL_WEIGHT_LEN_SQUARED, 6031 synaptics_sysctl, "I", 6032 "Length (squared) of segments where weight_previous " 6033 "starts to decrease"); 6034 6035 /* hw.psm.synaptics.div_min. */ 6036 sc->syninfo.div_min = 9; 6037 SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx, 6038 SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO, 6039 "div_min", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY, 6040 sc, SYNAPTICS_SYSCTL_DIV_MIN, 6041 synaptics_sysctl, "I", 6042 "Divisor for fast movements"); 6043 6044 /* hw.psm.synaptics.div_max. */ 6045 sc->syninfo.div_max = 17; 6046 SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx, 6047 SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO, 6048 "div_max", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY, 6049 sc, SYNAPTICS_SYSCTL_DIV_MAX, 6050 synaptics_sysctl, "I", 6051 "Divisor for slow movements"); 6052 6053 /* hw.psm.synaptics.div_max_na. */ 6054 sc->syninfo.div_max_na = 30; 6055 SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx, 6056 SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO, 6057 "div_max_na", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY, 6058 sc, SYNAPTICS_SYSCTL_DIV_MAX_NA, 6059 synaptics_sysctl, "I", 6060 "Divisor with slow movements (inside the noisy area)"); 6061 6062 /* hw.psm.synaptics.div_len. */ 6063 sc->syninfo.div_len = 100; 6064 SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx, 6065 SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO, 6066 "div_len", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY, 6067 sc, SYNAPTICS_SYSCTL_DIV_LEN, 6068 synaptics_sysctl, "I", 6069 "Length of segments where div_max starts to decrease"); 6070 6071 /* hw.psm.synaptics.tap_max_delta. */ 6072 sc->syninfo.tap_max_delta = 80; 6073 SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx, 6074 SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO, 6075 "tap_max_delta", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY, 6076 sc, SYNAPTICS_SYSCTL_TAP_MAX_DELTA, 6077 synaptics_sysctl, "I", 6078 "Length of segments above which a tap is ignored"); 6079 6080 /* hw.psm.synaptics.tap_min_queue. */ 6081 sc->syninfo.tap_min_queue = 2; 6082 SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx, 6083 SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO, 6084 "tap_min_queue", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY, 6085 sc, SYNAPTICS_SYSCTL_TAP_MIN_QUEUE, 6086 synaptics_sysctl, "I", 6087 "Number of packets required to consider a tap"); 6088 6089 /* hw.psm.synaptics.taphold_timeout. */ 6090 sc->gesture.in_taphold = 0; 6091 sc->syninfo.taphold_timeout = tap_timeout; 6092 SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx, 6093 SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO, 6094 "taphold_timeout", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY, 6095 sc, SYNAPTICS_SYSCTL_TAPHOLD_TIMEOUT, 6096 synaptics_sysctl, "I", 6097 "Maximum elapsed time between two taps to consider a tap-hold " 6098 "action"); 6099 6100 /* hw.psm.synaptics.vscroll_hor_area. */ 6101 sc->syninfo.vscroll_hor_area = 0; /* 1300 */ 6102 SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx, 6103 SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO, 6104 "vscroll_hor_area", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY, 6105 sc, SYNAPTICS_SYSCTL_VSCROLL_HOR_AREA, 6106 synaptics_sysctl, "I", 6107 "Area reserved for horizontal virtual scrolling"); 6108 6109 /* hw.psm.synaptics.vscroll_ver_area. */ 6110 sc->syninfo.vscroll_ver_area = -400 - sc->syninfo.margin_right; 6111 SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx, 6112 SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO, 6113 "vscroll_ver_area", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY, 6114 sc, SYNAPTICS_SYSCTL_VSCROLL_VER_AREA, 6115 synaptics_sysctl, "I", 6116 "Area reserved for vertical virtual scrolling"); 6117 6118 /* hw.psm.synaptics.vscroll_min_delta. */ 6119 sc->syninfo.vscroll_min_delta = 50; 6120 SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx, 6121 SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO, 6122 "vscroll_min_delta", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY, 6123 sc, SYNAPTICS_SYSCTL_VSCROLL_MIN_DELTA, 6124 synaptics_sysctl, "I", 6125 "Minimum movement to consider virtual scrolling"); 6126 6127 /* hw.psm.synaptics.vscroll_div_min. */ 6128 sc->syninfo.vscroll_div_min = 100; 6129 SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx, 6130 SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO, 6131 "vscroll_div_min", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY, 6132 sc, SYNAPTICS_SYSCTL_VSCROLL_DIV_MIN, 6133 synaptics_sysctl, "I", 6134 "Divisor for fast scrolling"); 6135 6136 /* hw.psm.synaptics.vscroll_div_min. */ 6137 sc->syninfo.vscroll_div_max = 150; 6138 SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx, 6139 SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO, 6140 "vscroll_div_max", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY, 6141 sc, SYNAPTICS_SYSCTL_VSCROLL_DIV_MAX, 6142 synaptics_sysctl, "I", 6143 "Divisor for slow scrolling"); 6144 6145 /* hw.psm.synaptics.touchpad_off. */ 6146 sc->syninfo.touchpad_off = 0; 6147 SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx, 6148 SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO, 6149 "touchpad_off", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY, 6150 sc, SYNAPTICS_SYSCTL_TOUCHPAD_OFF, 6151 synaptics_sysctl, "I", 6152 "Turn off touchpad"); 6153 6154 sc->syninfo.three_finger_drag = 0; 6155 SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx, 6156 SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO, 6157 "three_finger_drag", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY, 6158 sc, SYNAPTICS_SYSCTL_THREE_FINGER_DRAG, 6159 synaptics_sysctl, "I", 6160 "Enable dragging with three fingers"); 6161 6162 /* hw.psm.synaptics.natural_scroll. */ 6163 sc->syninfo.natural_scroll = 0; 6164 SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx, 6165 SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO, 6166 "natural_scroll", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY, 6167 sc, SYNAPTICS_SYSCTL_NATURAL_SCROLL, 6168 synaptics_sysctl, "I", 6169 "Enable natural scrolling"); 6170 6171 sc->syninfo.softbuttons_y = 0; 6172 sc->syninfo.softbutton2_x = 0; 6173 sc->syninfo.softbutton3_x = 0; 6174 6175 /* skip softbuttons sysctl on not clickpads */ 6176 if (sc->synhw.capClickPad) 6177 synaptics_sysctl_create_softbuttons_tree(sc); 6178 } 6179 6180 static int 6181 synaptics_preferred_mode(struct psm_softc *sc) { 6182 int mode_byte; 6183 6184 /* Check if we are in relative mode */ 6185 if (sc->hw.model != MOUSE_MODEL_SYNAPTICS) { 6186 if (tap_enabled == 0) 6187 /* 6188 * Disable tap & drag gestures. We use a Mode Byte 6189 * and set the DisGest bit (see §2.5 of Synaptics 6190 * TouchPad Interfacing Guide). 6191 */ 6192 return (0x04); 6193 else 6194 /* 6195 * Enable tap & drag gestures. We use a Mode Byte 6196 * and clear the DisGest bit (see §2.5 of Synaptics 6197 * TouchPad Interfacing Guide). 6198 */ 6199 return (0x00); 6200 } 6201 6202 mode_byte = 0xc4; 6203 6204 /* request wmode where available */ 6205 if (sc->synhw.capExtended) 6206 mode_byte |= 1; 6207 6208 return mode_byte; 6209 } 6210 6211 static void 6212 synaptics_set_mode(struct psm_softc *sc, int mode_byte) { 6213 mouse_ext_command(sc->kbdc, mode_byte); 6214 6215 /* "Commit" the Set Mode Byte command sent above. */ 6216 set_mouse_sampling_rate(sc->kbdc, 20); 6217 6218 /* 6219 * Enable advanced gestures mode if supported and we are not entering 6220 * passthrough or relative mode. 6221 */ 6222 if ((sc->synhw.capAdvancedGestures || sc->synhw.capReportsV) && 6223 sc->hw.model == MOUSE_MODEL_SYNAPTICS && !(mode_byte & (1 << 5))) { 6224 mouse_ext_command(sc->kbdc, SYNAPTICS_READ_MODEL_ID); 6225 set_mouse_sampling_rate(sc->kbdc, 0xc8); 6226 } 6227 } 6228 6229 /* 6230 * AUX MUX detection code should be placed at very beginning of probe sequence 6231 * at least before 4-byte protocol mouse probes e.g. MS IntelliMouse probe as 6232 * latter can trigger switching the MUX to incompatible state. 6233 */ 6234 static int 6235 enable_synaptics_mux(struct psm_softc *sc, enum probearg arg) 6236 { 6237 KBDC kbdc = sc->kbdc; 6238 int port, version; 6239 int probe = FALSE; 6240 int active_ports_count = 0; 6241 int active_ports_mask = 0; 6242 6243 version = enable_aux_mux(kbdc); 6244 if (version == -1) 6245 return (FALSE); 6246 6247 for (port = 0; port < KBDC_AUX_MUX_NUM_PORTS; port++) { 6248 VLOG(3, (LOG_DEBUG, "aux_mux: ping port %d\n", port)); 6249 set_active_aux_mux_port(kbdc, port); 6250 if (enable_aux_dev(kbdc) && disable_aux_dev(kbdc)) { 6251 active_ports_count++; 6252 active_ports_mask |= 1 << port; 6253 } 6254 } 6255 6256 if (verbose >= 2) 6257 printf("Active Multiplexing PS/2 controller v%d.%d with %d " 6258 "active port(s)\n", version >> 4 & 0x0f, version & 0x0f, 6259 active_ports_count); 6260 6261 /* psm has a special support for GenMouse + SynTouchpad combination */ 6262 if (active_ports_count >= 2) { 6263 for (port = 0; port < KBDC_AUX_MUX_NUM_PORTS; port++) { 6264 if ((active_ports_mask & 1 << port) == 0) 6265 continue; 6266 VLOG(3, (LOG_DEBUG, "aux_mux: probe port %d\n", port)); 6267 set_active_aux_mux_port(kbdc, port); 6268 probe = enable_synaptics(sc, arg); 6269 if (probe) { 6270 if (arg == PROBE) 6271 sc->muxport = port; 6272 break; 6273 } 6274 } 6275 } 6276 6277 /* IRQ handler does not support active multiplexing mode */ 6278 disable_aux_mux(kbdc); 6279 6280 return (probe); 6281 } 6282 6283 static int 6284 enable_synaptics(struct psm_softc *sc, enum probearg arg) 6285 { 6286 device_t psmcpnp; 6287 struct psmcpnp_softc *psmcpnp_sc; 6288 KBDC kbdc = sc->kbdc; 6289 synapticshw_t synhw; 6290 int status[3]; 6291 int buttons; 6292 6293 VLOG(3, (LOG_DEBUG, "synaptics: BEGIN init\n")); 6294 6295 /* 6296 * Just to be on the safe side: this avoids troubles with 6297 * following mouse_ext_command() when the previous command 6298 * was PSMC_SET_RESOLUTION. Set Scaling has no effect on 6299 * Synaptics Touchpad behaviour. 6300 */ 6301 set_mouse_scaling(kbdc, 1); 6302 6303 /* Identify the Touchpad version. */ 6304 if (mouse_ext_command(kbdc, SYNAPTICS_READ_IDENTITY) == 0) 6305 return (FALSE); 6306 if (get_mouse_status(kbdc, status, 0, 3) != 3) 6307 return (FALSE); 6308 if (status[1] != 0x47) 6309 return (FALSE); 6310 6311 bzero(&synhw, sizeof(synhw)); 6312 synhw.infoMinor = status[0]; 6313 synhw.infoMajor = status[2] & 0x0f; 6314 6315 if (verbose >= 2) 6316 printf("Synaptics Touchpad v%d.%d\n", synhw.infoMajor, 6317 synhw.infoMinor); 6318 6319 if (synhw.infoMajor < 4) { 6320 printf(" Unsupported (pre-v4) Touchpad detected\n"); 6321 return (FALSE); 6322 } 6323 6324 /* Get the Touchpad model information. */ 6325 if (mouse_ext_command(kbdc, SYNAPTICS_READ_MODEL_ID) == 0) 6326 return (FALSE); 6327 if (get_mouse_status(kbdc, status, 0, 3) != 3) 6328 return (FALSE); 6329 if ((status[1] & 0x01) != 0) { 6330 printf(" Failed to read model information\n"); 6331 return (FALSE); 6332 } 6333 6334 synhw.infoRot180 = (status[0] & 0x80) != 0; 6335 synhw.infoPortrait = (status[0] & 0x40) != 0; 6336 synhw.infoSensor = status[0] & 0x3f; 6337 synhw.infoHardware = (status[1] & 0xfe) >> 1; 6338 synhw.infoNewAbs = (status[2] & 0x80) != 0; 6339 synhw.capPen = (status[2] & 0x40) != 0; 6340 synhw.infoSimplC = (status[2] & 0x20) != 0; 6341 synhw.infoGeometry = status[2] & 0x0f; 6342 6343 if (verbose >= 2) { 6344 printf(" Model information:\n"); 6345 printf(" infoRot180: %d\n", synhw.infoRot180); 6346 printf(" infoPortrait: %d\n", synhw.infoPortrait); 6347 printf(" infoSensor: %d\n", synhw.infoSensor); 6348 printf(" infoHardware: %d\n", synhw.infoHardware); 6349 printf(" infoNewAbs: %d\n", synhw.infoNewAbs); 6350 printf(" capPen: %d\n", synhw.capPen); 6351 printf(" infoSimplC: %d\n", synhw.infoSimplC); 6352 printf(" infoGeometry: %d\n", synhw.infoGeometry); 6353 } 6354 6355 /* Read the extended capability bits. */ 6356 if (mouse_ext_command(kbdc, SYNAPTICS_READ_CAPABILITIES) == 0) 6357 return (FALSE); 6358 if (get_mouse_status(kbdc, status, 0, 3) != 3) 6359 return (FALSE); 6360 if (!SYNAPTICS_VERSION_GE(synhw, 7, 5) && status[1] != 0x47) { 6361 printf(" Failed to read extended capability bits\n"); 6362 return (FALSE); 6363 } 6364 6365 psmcpnp = devclass_get_device(devclass_find(PSMCPNP_DRIVER_NAME), 6366 sc->unit); 6367 psmcpnp_sc = (psmcpnp != NULL) ? device_get_softc(psmcpnp) : NULL; 6368 6369 /* Set the different capabilities when they exist. */ 6370 buttons = 0; 6371 synhw.capExtended = (status[0] & 0x80) != 0; 6372 if (synhw.capExtended) { 6373 synhw.nExtendedQueries = (status[0] & 0x70) >> 4; 6374 synhw.capMiddle = (status[0] & 0x04) != 0; 6375 synhw.capPassthrough = (status[2] & 0x80) != 0; 6376 synhw.capLowPower = (status[2] & 0x40) != 0; 6377 synhw.capMultiFingerReport = 6378 (status[2] & 0x20) != 0; 6379 synhw.capSleep = (status[2] & 0x10) != 0; 6380 synhw.capFourButtons = (status[2] & 0x08) != 0; 6381 synhw.capBallistics = (status[2] & 0x04) != 0; 6382 synhw.capMultiFinger = (status[2] & 0x02) != 0; 6383 synhw.capPalmDetect = (status[2] & 0x01) != 0; 6384 6385 if (!set_mouse_scaling(kbdc, 1)) 6386 return (FALSE); 6387 if (mouse_ext_command(kbdc, SYNAPTICS_READ_RESOLUTIONS) == 0) 6388 return (FALSE); 6389 if (get_mouse_status(kbdc, status, 0, 3) != 3) 6390 return (FALSE); 6391 6392 if (status[0] != 0 && (status[1] & 0x80) && status[2] != 0) { 6393 synhw.infoXupmm = status[0]; 6394 synhw.infoYupmm = status[2]; 6395 } 6396 6397 if (verbose >= 2) { 6398 printf(" Extended capabilities:\n"); 6399 printf(" capExtended: %d\n", synhw.capExtended); 6400 printf(" capMiddle: %d\n", synhw.capMiddle); 6401 printf(" nExtendedQueries: %d\n", 6402 synhw.nExtendedQueries); 6403 printf(" capPassthrough: %d\n", synhw.capPassthrough); 6404 printf(" capLowPower: %d\n", synhw.capLowPower); 6405 printf(" capMultiFingerReport: %d\n", 6406 synhw.capMultiFingerReport); 6407 printf(" capSleep: %d\n", synhw.capSleep); 6408 printf(" capFourButtons: %d\n", synhw.capFourButtons); 6409 printf(" capBallistics: %d\n", synhw.capBallistics); 6410 printf(" capMultiFinger: %d\n", synhw.capMultiFinger); 6411 printf(" capPalmDetect: %d\n", synhw.capPalmDetect); 6412 printf(" infoXupmm: %d\n", synhw.infoXupmm); 6413 printf(" infoYupmm: %d\n", synhw.infoYupmm); 6414 } 6415 6416 /* 6417 * If nExtendedQueries is 1 or greater, then the TouchPad 6418 * supports this number of extended queries. We can load 6419 * more information about buttons using query 0x09. 6420 */ 6421 if (synhw.nExtendedQueries >= 1) { 6422 if (!set_mouse_scaling(kbdc, 1)) 6423 return (FALSE); 6424 if (mouse_ext_command(kbdc, 6425 SYNAPTICS_READ_EXTENDED) == 0) 6426 return (FALSE); 6427 if (get_mouse_status(kbdc, status, 0, 3) != 3) 6428 return (FALSE); 6429 synhw.verticalScroll = (status[0] & 0x01) != 0; 6430 synhw.horizontalScroll = (status[0] & 0x02) != 0; 6431 synhw.verticalWheel = (status[0] & 0x08) != 0; 6432 synhw.nExtendedButtons = (status[1] & 0xf0) >> 4; 6433 synhw.capEWmode = (status[0] & 0x04) != 0; 6434 if (verbose >= 2) { 6435 printf(" Extended model ID:\n"); 6436 printf(" verticalScroll: %d\n", 6437 synhw.verticalScroll); 6438 printf(" horizontalScroll: %d\n", 6439 synhw.horizontalScroll); 6440 printf(" verticalWheel: %d\n", 6441 synhw.verticalWheel); 6442 printf(" nExtendedButtons: %d\n", 6443 synhw.nExtendedButtons); 6444 printf(" capEWmode: %d\n", 6445 synhw.capEWmode); 6446 } 6447 /* 6448 * Add the number of extended buttons to the total 6449 * button support count, including the middle button 6450 * if capMiddle support bit is set. 6451 */ 6452 buttons = synhw.nExtendedButtons + synhw.capMiddle; 6453 } else 6454 /* 6455 * If the capFourButtons support bit is set, 6456 * add a fourth button to the total button count. 6457 */ 6458 buttons = synhw.capFourButtons ? 1 : 0; 6459 6460 /* Read the continued capabilities bits. */ 6461 if (synhw.nExtendedQueries >= 4) { 6462 if (!set_mouse_scaling(kbdc, 1)) 6463 return (FALSE); 6464 if (mouse_ext_command(kbdc, 6465 SYNAPTICS_READ_CAPABILITIES_CONT) == 0) 6466 return (FALSE); 6467 if (get_mouse_status(kbdc, status, 0, 3) != 3) 6468 return (FALSE); 6469 6470 synhw.capClickPad = (status[1] & 0x01) << 1; 6471 synhw.capClickPad |= (status[0] & 0x10) != 0; 6472 synhw.capDeluxeLEDs = (status[1] & 0x02) != 0; 6473 synhw.noAbsoluteFilter = (status[1] & 0x04) != 0; 6474 synhw.capReportsV = (status[1] & 0x08) != 0; 6475 synhw.capUniformClickPad = (status[1] & 0x10) != 0; 6476 synhw.capReportsMin = (status[1] & 0x20) != 0; 6477 synhw.capInterTouch = (status[1] & 0x40) != 0; 6478 synhw.capReportsMax = (status[0] & 0x02) != 0; 6479 synhw.capClearPad = (status[0] & 0x04) != 0; 6480 synhw.capAdvancedGestures = (status[0] & 0x08) != 0; 6481 synhw.capCoveredPad = (status[0] & 0x80) != 0; 6482 6483 if (synhw.capReportsMax) { 6484 if (!set_mouse_scaling(kbdc, 1)) 6485 return (FALSE); 6486 if (mouse_ext_command(kbdc, 6487 SYNAPTICS_READ_MAX_COORDS) == 0) 6488 return (FALSE); 6489 if (get_mouse_status(kbdc, status, 0, 3) != 3) 6490 return (FALSE); 6491 6492 synhw.maximumXCoord = (status[0] << 5) | 6493 ((status[1] & 0x0f) << 1); 6494 synhw.maximumYCoord = (status[2] << 5) | 6495 ((status[1] & 0xf0) >> 3); 6496 } else { 6497 /* 6498 * Typical bezel limits. Taken from 'Synaptics 6499 * PS/2 * TouchPad Interfacing Guide' p.3.2.3. 6500 */ 6501 synhw.maximumXCoord = 5472; 6502 synhw.maximumYCoord = 4448; 6503 } 6504 6505 if (synhw.capReportsMin) { 6506 if (!set_mouse_scaling(kbdc, 1)) 6507 return (FALSE); 6508 if (mouse_ext_command(kbdc, 6509 SYNAPTICS_READ_MIN_COORDS) == 0) 6510 return (FALSE); 6511 if (get_mouse_status(kbdc, status, 0, 3) != 3) 6512 return (FALSE); 6513 6514 synhw.minimumXCoord = (status[0] << 5) | 6515 ((status[1] & 0x0f) << 1); 6516 synhw.minimumYCoord = (status[2] << 5) | 6517 ((status[1] & 0xf0) >> 3); 6518 } else { 6519 /* 6520 * Typical bezel limits. Taken from 'Synaptics 6521 * PS/2 * TouchPad Interfacing Guide' p.3.2.3. 6522 */ 6523 synhw.minimumXCoord = 1472; 6524 synhw.minimumYCoord = 1408; 6525 } 6526 6527 /* 6528 * ClickPad properties are not exported through PS/2 6529 * protocol. Detection is based on controller's PnP ID. 6530 */ 6531 if (synhw.capClickPad && psmcpnp_sc != NULL) { 6532 switch (psmcpnp_sc->type) { 6533 case PSMCPNP_FORCEPAD: 6534 synhw.forcePad = 1; 6535 break; 6536 case PSMCPNP_TOPBUTTONPAD: 6537 synhw.topButtonPad = 1; 6538 break; 6539 default: 6540 break; 6541 } 6542 } 6543 6544 if (verbose >= 2) { 6545 printf(" Continued capabilities:\n"); 6546 printf(" capClickPad: %d\n", 6547 synhw.capClickPad); 6548 printf(" capDeluxeLEDs: %d\n", 6549 synhw.capDeluxeLEDs); 6550 printf(" noAbsoluteFilter: %d\n", 6551 synhw.noAbsoluteFilter); 6552 printf(" capReportsV: %d\n", 6553 synhw.capReportsV); 6554 printf(" capUniformClickPad: %d\n", 6555 synhw.capUniformClickPad); 6556 printf(" capReportsMin: %d\n", 6557 synhw.capReportsMin); 6558 printf(" capInterTouch: %d\n", 6559 synhw.capInterTouch); 6560 printf(" capReportsMax: %d\n", 6561 synhw.capReportsMax); 6562 printf(" capClearPad: %d\n", 6563 synhw.capClearPad); 6564 printf(" capAdvancedGestures: %d\n", 6565 synhw.capAdvancedGestures); 6566 printf(" capCoveredPad: %d\n", 6567 synhw.capCoveredPad); 6568 if (synhw.capReportsMax) { 6569 printf(" maximumXCoord: %d\n", 6570 synhw.maximumXCoord); 6571 printf(" maximumYCoord: %d\n", 6572 synhw.maximumYCoord); 6573 } 6574 if (synhw.capReportsMin) { 6575 printf(" minimumXCoord: %d\n", 6576 synhw.minimumXCoord); 6577 printf(" minimumYCoord: %d\n", 6578 synhw.minimumYCoord); 6579 } 6580 if (synhw.capClickPad) { 6581 printf(" Clickpad capabilities:\n"); 6582 printf(" forcePad: %d\n", 6583 synhw.forcePad); 6584 printf(" topButtonPad: %d\n", 6585 synhw.topButtonPad); 6586 } 6587 } 6588 buttons += synhw.capClickPad; 6589 } 6590 } 6591 6592 if (verbose >= 2) { 6593 if (synhw.capExtended) 6594 printf(" Additional Buttons: %d\n", buttons); 6595 else 6596 printf(" No extended capabilities\n"); 6597 } 6598 6599 /* 6600 * Add the default number of 3 buttons to the total 6601 * count of supported buttons reported above. 6602 */ 6603 buttons += 3; 6604 6605 /* 6606 * Read the mode byte. 6607 * 6608 * XXX: Note the Synaptics documentation also defines the first 6609 * byte of the response to this query to be a constant 0x3b, this 6610 * does not appear to be true for Touchpads with guest devices. 6611 */ 6612 if (mouse_ext_command(kbdc, SYNAPTICS_READ_MODES) == 0) 6613 return (FALSE); 6614 if (get_mouse_status(kbdc, status, 0, 3) != 3) 6615 return (FALSE); 6616 if (!SYNAPTICS_VERSION_GE(synhw, 7, 5) && status[1] != 0x47) { 6617 printf(" Failed to read mode byte\n"); 6618 return (FALSE); 6619 } 6620 6621 if (arg == PROBE) 6622 sc->synhw = synhw; 6623 if (!synaptics_support) 6624 return (FALSE); 6625 6626 /* Set mouse type just now for synaptics_set_mode() */ 6627 sc->hw.model = MOUSE_MODEL_SYNAPTICS; 6628 6629 synaptics_set_mode(sc, synaptics_preferred_mode(sc)); 6630 6631 if (trackpoint_support && synhw.capPassthrough) { 6632 enable_trackpoint(sc, arg); 6633 } 6634 6635 VLOG(3, (LOG_DEBUG, "synaptics: END init (%d buttons)\n", buttons)); 6636 6637 if (arg == PROBE) { 6638 /* Create sysctl tree. */ 6639 synaptics_sysctl_create_tree(sc, "synaptics", 6640 "Synaptics TouchPad"); 6641 sc->hw.buttons = buttons; 6642 } 6643 6644 return (TRUE); 6645 } 6646 6647 static void 6648 synaptics_passthrough_on(struct psm_softc *sc) 6649 { 6650 VLOG(2, (LOG_NOTICE, "psm: setting pass-through mode.\n")); 6651 synaptics_set_mode(sc, synaptics_preferred_mode(sc) | (1 << 5)); 6652 } 6653 6654 static void 6655 synaptics_passthrough_off(struct psm_softc *sc) 6656 { 6657 VLOG(2, (LOG_NOTICE, "psm: turning pass-through mode off.\n")); 6658 set_mouse_scaling(sc->kbdc, 2); 6659 set_mouse_scaling(sc->kbdc, 1); 6660 synaptics_set_mode(sc, synaptics_preferred_mode(sc)); 6661 } 6662 6663 /* IBM/Lenovo TrackPoint */ 6664 static int 6665 trackpoint_command(struct psm_softc *sc, int cmd, int loc, int val) 6666 { 6667 const int seq[] = { 0xe2, cmd, loc, val }; 6668 int i; 6669 6670 if (sc->synhw.capPassthrough) 6671 synaptics_passthrough_on(sc); 6672 6673 for (i = 0; i < nitems(seq); i++) { 6674 if (sc->synhw.capPassthrough && 6675 (seq[i] == 0xff || seq[i] == 0xe7)) 6676 if (send_aux_command(sc->kbdc, 0xe7) != PSM_ACK) { 6677 synaptics_passthrough_off(sc); 6678 return (EIO); 6679 } 6680 if (send_aux_command(sc->kbdc, seq[i]) != PSM_ACK) { 6681 if (sc->synhw.capPassthrough) 6682 synaptics_passthrough_off(sc); 6683 return (EIO); 6684 } 6685 } 6686 6687 if (sc->synhw.capPassthrough) 6688 synaptics_passthrough_off(sc); 6689 6690 return (0); 6691 } 6692 6693 #define PSM_TPINFO(x) offsetof(struct psm_softc, tpinfo.x) 6694 #define TPMASK 0 6695 #define TPLOC 1 6696 #define TPINFO 2 6697 6698 static int 6699 trackpoint_sysctl(SYSCTL_HANDLER_ARGS) 6700 { 6701 static const int data[][3] = { 6702 { 0x00, 0x4a, PSM_TPINFO(sensitivity) }, 6703 { 0x00, 0x4d, PSM_TPINFO(inertia) }, 6704 { 0x00, 0x60, PSM_TPINFO(uplateau) }, 6705 { 0x00, 0x57, PSM_TPINFO(reach) }, 6706 { 0x00, 0x58, PSM_TPINFO(draghys) }, 6707 { 0x00, 0x59, PSM_TPINFO(mindrag) }, 6708 { 0x00, 0x5a, PSM_TPINFO(upthresh) }, 6709 { 0x00, 0x5c, PSM_TPINFO(threshold) }, 6710 { 0x00, 0x5d, PSM_TPINFO(jenks) }, 6711 { 0x00, 0x5e, PSM_TPINFO(ztime) }, 6712 { 0x01, 0x2c, PSM_TPINFO(pts) }, 6713 { 0x08, 0x2d, PSM_TPINFO(skipback) } 6714 }; 6715 struct psm_softc *sc; 6716 int error, newval, *oldvalp; 6717 const int *tp; 6718 6719 if (arg1 == NULL || arg2 < 0 || arg2 >= nitems(data)) 6720 return (EINVAL); 6721 sc = arg1; 6722 tp = data[arg2]; 6723 oldvalp = (int *)((intptr_t)sc + tp[TPINFO]); 6724 newval = *oldvalp; 6725 error = sysctl_handle_int(oidp, &newval, 0, req); 6726 if (error != 0) 6727 return (error); 6728 if (newval == *oldvalp) 6729 return (0); 6730 if (newval < 0 || newval > (tp[TPMASK] == 0 ? 255 : 1)) 6731 return (EINVAL); 6732 error = trackpoint_command(sc, tp[TPMASK] == 0 ? 0x81 : 0x47, 6733 tp[TPLOC], tp[TPMASK] == 0 ? newval : tp[TPMASK]); 6734 if (error != 0) 6735 return (error); 6736 *oldvalp = newval; 6737 6738 return (0); 6739 } 6740 6741 static void 6742 trackpoint_sysctl_create_tree(struct psm_softc *sc) 6743 { 6744 6745 if (sc->tpinfo.sysctl_tree != NULL) 6746 return; 6747 6748 /* Attach extra trackpoint sysctl nodes under hw.psm.trackpoint */ 6749 sysctl_ctx_init(&sc->tpinfo.sysctl_ctx); 6750 sc->tpinfo.sysctl_tree = SYSCTL_ADD_NODE(&sc->tpinfo.sysctl_ctx, 6751 SYSCTL_STATIC_CHILDREN(_hw_psm), OID_AUTO, "trackpoint", CTLFLAG_RD, 6752 0, "IBM/Lenovo TrackPoint"); 6753 6754 /* hw.psm.trackpoint.sensitivity */ 6755 sc->tpinfo.sensitivity = 0x80; 6756 SYSCTL_ADD_PROC(&sc->tpinfo.sysctl_ctx, 6757 SYSCTL_CHILDREN(sc->tpinfo.sysctl_tree), OID_AUTO, 6758 "sensitivity", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY, 6759 sc, TRACKPOINT_SYSCTL_SENSITIVITY, 6760 trackpoint_sysctl, "I", 6761 "Sensitivity"); 6762 6763 /* hw.psm.trackpoint.negative_inertia */ 6764 sc->tpinfo.inertia = 0x06; 6765 SYSCTL_ADD_PROC(&sc->tpinfo.sysctl_ctx, 6766 SYSCTL_CHILDREN(sc->tpinfo.sysctl_tree), OID_AUTO, 6767 "negative_inertia", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY, 6768 sc, TRACKPOINT_SYSCTL_NEGATIVE_INERTIA, 6769 trackpoint_sysctl, "I", 6770 "Negative inertia factor"); 6771 6772 /* hw.psm.trackpoint.upper_plateau */ 6773 sc->tpinfo.uplateau = 0x61; 6774 SYSCTL_ADD_PROC(&sc->tpinfo.sysctl_ctx, 6775 SYSCTL_CHILDREN(sc->tpinfo.sysctl_tree), OID_AUTO, 6776 "upper_plateau", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY, 6777 sc, TRACKPOINT_SYSCTL_UPPER_PLATEAU, 6778 trackpoint_sysctl, "I", 6779 "Transfer function upper plateau speed"); 6780 6781 /* hw.psm.trackpoint.backup_range */ 6782 sc->tpinfo.reach = 0x0a; 6783 SYSCTL_ADD_PROC(&sc->tpinfo.sysctl_ctx, 6784 SYSCTL_CHILDREN(sc->tpinfo.sysctl_tree), OID_AUTO, 6785 "backup_range", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY, 6786 sc, TRACKPOINT_SYSCTL_BACKUP_RANGE, 6787 trackpoint_sysctl, "I", 6788 "Backup range"); 6789 6790 /* hw.psm.trackpoint.drag_hysteresis */ 6791 sc->tpinfo.draghys = 0xff; 6792 SYSCTL_ADD_PROC(&sc->tpinfo.sysctl_ctx, 6793 SYSCTL_CHILDREN(sc->tpinfo.sysctl_tree), OID_AUTO, 6794 "drag_hysteresis", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY, 6795 sc, TRACKPOINT_SYSCTL_DRAG_HYSTERESIS, 6796 trackpoint_sysctl, "I", 6797 "Drag hysteresis"); 6798 6799 /* hw.psm.trackpoint.minimum_drag */ 6800 sc->tpinfo.mindrag = 0x14; 6801 SYSCTL_ADD_PROC(&sc->tpinfo.sysctl_ctx, 6802 SYSCTL_CHILDREN(sc->tpinfo.sysctl_tree), OID_AUTO, 6803 "minimum_drag", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY, 6804 sc, TRACKPOINT_SYSCTL_MINIMUM_DRAG, 6805 trackpoint_sysctl, "I", 6806 "Minimum drag"); 6807 6808 /* hw.psm.trackpoint.up_threshold */ 6809 sc->tpinfo.upthresh = 0xff; 6810 SYSCTL_ADD_PROC(&sc->tpinfo.sysctl_ctx, 6811 SYSCTL_CHILDREN(sc->tpinfo.sysctl_tree), OID_AUTO, 6812 "up_threshold", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY, 6813 sc, TRACKPOINT_SYSCTL_UP_THRESHOLD, 6814 trackpoint_sysctl, "I", 6815 "Up threshold for release"); 6816 6817 /* hw.psm.trackpoint.threshold */ 6818 sc->tpinfo.threshold = 0x08; 6819 SYSCTL_ADD_PROC(&sc->tpinfo.sysctl_ctx, 6820 SYSCTL_CHILDREN(sc->tpinfo.sysctl_tree), OID_AUTO, 6821 "threshold", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY, 6822 sc, TRACKPOINT_SYSCTL_THRESHOLD, 6823 trackpoint_sysctl, "I", 6824 "Threshold"); 6825 6826 /* hw.psm.trackpoint.jenks_curvature */ 6827 sc->tpinfo.jenks = 0x87; 6828 SYSCTL_ADD_PROC(&sc->tpinfo.sysctl_ctx, 6829 SYSCTL_CHILDREN(sc->tpinfo.sysctl_tree), OID_AUTO, 6830 "jenks_curvature", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY, 6831 sc, TRACKPOINT_SYSCTL_JENKS_CURVATURE, 6832 trackpoint_sysctl, "I", 6833 "Jenks curvature"); 6834 6835 /* hw.psm.trackpoint.z_time */ 6836 sc->tpinfo.ztime = 0x26; 6837 SYSCTL_ADD_PROC(&sc->tpinfo.sysctl_ctx, 6838 SYSCTL_CHILDREN(sc->tpinfo.sysctl_tree), OID_AUTO, 6839 "z_time", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY, 6840 sc, TRACKPOINT_SYSCTL_Z_TIME, 6841 trackpoint_sysctl, "I", 6842 "Z time constant"); 6843 6844 /* hw.psm.trackpoint.press_to_select */ 6845 sc->tpinfo.pts = 0x00; 6846 SYSCTL_ADD_PROC(&sc->tpinfo.sysctl_ctx, 6847 SYSCTL_CHILDREN(sc->tpinfo.sysctl_tree), OID_AUTO, 6848 "press_to_select", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY, 6849 sc, TRACKPOINT_SYSCTL_PRESS_TO_SELECT, 6850 trackpoint_sysctl, "I", 6851 "Press to Select"); 6852 6853 /* hw.psm.trackpoint.skip_backups */ 6854 sc->tpinfo.skipback = 0x00; 6855 SYSCTL_ADD_PROC(&sc->tpinfo.sysctl_ctx, 6856 SYSCTL_CHILDREN(sc->tpinfo.sysctl_tree), OID_AUTO, 6857 "skip_backups", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY, 6858 sc, TRACKPOINT_SYSCTL_SKIP_BACKUPS, 6859 trackpoint_sysctl, "I", 6860 "Skip backups from drags"); 6861 } 6862 6863 static void 6864 set_trackpoint_parameters(struct psm_softc *sc) 6865 { 6866 trackpoint_command(sc, 0x81, 0x4a, sc->tpinfo.sensitivity); 6867 trackpoint_command(sc, 0x81, 0x60, sc->tpinfo.uplateau); 6868 trackpoint_command(sc, 0x81, 0x4d, sc->tpinfo.inertia); 6869 trackpoint_command(sc, 0x81, 0x57, sc->tpinfo.reach); 6870 trackpoint_command(sc, 0x81, 0x58, sc->tpinfo.draghys); 6871 trackpoint_command(sc, 0x81, 0x59, sc->tpinfo.mindrag); 6872 trackpoint_command(sc, 0x81, 0x5a, sc->tpinfo.upthresh); 6873 trackpoint_command(sc, 0x81, 0x5c, sc->tpinfo.threshold); 6874 trackpoint_command(sc, 0x81, 0x5d, sc->tpinfo.jenks); 6875 trackpoint_command(sc, 0x81, 0x5e, sc->tpinfo.ztime); 6876 if (sc->tpinfo.pts == 0x01) 6877 trackpoint_command(sc, 0x47, 0x2c, 0x01); 6878 if (sc->tpinfo.skipback == 0x01) 6879 trackpoint_command(sc, 0x47, 0x2d, 0x08); 6880 } 6881 6882 static int 6883 enable_trackpoint(struct psm_softc *sc, enum probearg arg) 6884 { 6885 KBDC kbdc = sc->kbdc; 6886 int id; 6887 6888 /* 6889 * If called from enable_synaptics(), make sure that passthrough 6890 * mode is enabled so we can reach the trackpoint. 6891 * However, passthrough mode must be disabled before setting the 6892 * trackpoint parameters, as rackpoint_command() enables and disables 6893 * passthrough mode on its own. 6894 */ 6895 if (sc->synhw.capPassthrough) 6896 synaptics_passthrough_on(sc); 6897 6898 if (send_aux_command(kbdc, 0xe1) != PSM_ACK || 6899 read_aux_data(kbdc) != 0x01) 6900 goto no_trackpoint; 6901 id = read_aux_data(kbdc); 6902 if (id < 0x01) 6903 goto no_trackpoint; 6904 if (arg == PROBE) 6905 sc->tphw = id; 6906 if (!trackpoint_support) 6907 goto no_trackpoint; 6908 6909 if (sc->synhw.capPassthrough) 6910 synaptics_passthrough_off(sc); 6911 6912 if (arg == PROBE) { 6913 trackpoint_sysctl_create_tree(sc); 6914 /* 6915 * Don't overwrite hwid and buttons when we are 6916 * a guest device. 6917 */ 6918 if (!sc->synhw.capPassthrough) { 6919 sc->hw.hwid = id; 6920 sc->hw.buttons = 3; 6921 } 6922 } 6923 6924 set_trackpoint_parameters(sc); 6925 6926 return (TRUE); 6927 6928 no_trackpoint: 6929 if (sc->synhw.capPassthrough) 6930 synaptics_passthrough_off(sc); 6931 6932 return (FALSE); 6933 } 6934 6935 /* Interlink electronics VersaPad */ 6936 static int 6937 enable_versapad(struct psm_softc *sc, enum probearg arg) 6938 { 6939 KBDC kbdc = sc->kbdc; 6940 int data[3]; 6941 6942 set_mouse_resolution(kbdc, PSMD_RES_MEDIUM_HIGH); /* set res. 2 */ 6943 set_mouse_sampling_rate(kbdc, 100); /* set rate 100 */ 6944 set_mouse_scaling(kbdc, 1); /* set scale 1:1 */ 6945 set_mouse_scaling(kbdc, 1); /* set scale 1:1 */ 6946 set_mouse_scaling(kbdc, 1); /* set scale 1:1 */ 6947 set_mouse_scaling(kbdc, 1); /* set scale 1:1 */ 6948 if (get_mouse_status(kbdc, data, 0, 3) < 3) /* get status */ 6949 return (FALSE); 6950 if (data[2] != 0xa || data[1] != 0 ) /* rate == 0xa && res. == 0 */ 6951 return (FALSE); 6952 set_mouse_scaling(kbdc, 1); /* set scale 1:1 */ 6953 6954 return (TRUE); /* PS/2 absolute mode */ 6955 } 6956 6957 /* Elantech Touchpad */ 6958 static int 6959 elantech_read_1(KBDC kbdc, int hwversion, int reg, int *val) 6960 { 6961 int res, readcmd, retidx; 6962 int resp[3]; 6963 6964 readcmd = hwversion == 2 ? ELANTECH_REG_READ : ELANTECH_REG_RDWR; 6965 retidx = hwversion == 4 ? 1 : 0; 6966 6967 res = send_aux_command(kbdc, ELANTECH_CUSTOM_CMD) != PSM_ACK; 6968 res |= send_aux_command(kbdc, readcmd) != PSM_ACK; 6969 res |= send_aux_command(kbdc, ELANTECH_CUSTOM_CMD) != PSM_ACK; 6970 res |= send_aux_command(kbdc, reg) != PSM_ACK; 6971 res |= get_mouse_status(kbdc, resp, 0, 3) != 3; 6972 6973 if (res == 0) 6974 *val = resp[retidx]; 6975 6976 return (res); 6977 } 6978 6979 static int 6980 elantech_write_1(KBDC kbdc, int hwversion, int reg, int val) 6981 { 6982 int res, writecmd; 6983 6984 writecmd = hwversion == 2 ? ELANTECH_REG_WRITE : ELANTECH_REG_RDWR; 6985 6986 res = send_aux_command(kbdc, ELANTECH_CUSTOM_CMD) != PSM_ACK; 6987 res |= send_aux_command(kbdc, writecmd) != PSM_ACK; 6988 res |= send_aux_command(kbdc, ELANTECH_CUSTOM_CMD) != PSM_ACK; 6989 res |= send_aux_command(kbdc, reg) != PSM_ACK; 6990 if (hwversion == 4) { 6991 res |= send_aux_command(kbdc, ELANTECH_CUSTOM_CMD) != PSM_ACK; 6992 res |= send_aux_command(kbdc, writecmd) != PSM_ACK; 6993 } 6994 res |= send_aux_command(kbdc, ELANTECH_CUSTOM_CMD) != PSM_ACK; 6995 res |= send_aux_command(kbdc, val) != PSM_ACK; 6996 res |= set_mouse_scaling(kbdc, 1) == 0; 6997 6998 return (res); 6999 } 7000 7001 static int 7002 elantech_cmd(KBDC kbdc, int hwversion, int cmd, int *resp) 7003 { 7004 int res; 7005 7006 if (hwversion == 2) { 7007 res = set_mouse_scaling(kbdc, 1) == 0; 7008 res |= mouse_ext_command(kbdc, cmd) == 0; 7009 } else { 7010 res = send_aux_command(kbdc, ELANTECH_CUSTOM_CMD) != PSM_ACK; 7011 res |= send_aux_command(kbdc, cmd) != PSM_ACK; 7012 } 7013 res |= get_mouse_status(kbdc, resp, 0, 3) != 3; 7014 7015 return (res); 7016 } 7017 7018 static int 7019 elantech_init(KBDC kbdc, elantechhw_t *elanhw) 7020 { 7021 int i, val, res, hwversion, reg10; 7022 7023 /* set absolute mode */ 7024 hwversion = elanhw->hwversion; 7025 reg10 = -1; 7026 switch (hwversion) { 7027 case 2: 7028 reg10 = elanhw->fwversion == 0x020030 ? 0x54 : 0xc4; 7029 res = elantech_write_1(kbdc, hwversion, 0x10, reg10); 7030 if (res) 7031 break; 7032 res = elantech_write_1(kbdc, hwversion, 0x11, 0x8A); 7033 break; 7034 case 3: 7035 reg10 = 0x0b; 7036 res = elantech_write_1(kbdc, hwversion, 0x10, reg10); 7037 break; 7038 case 4: 7039 res = elantech_write_1(kbdc, hwversion, 0x07, 0x01); 7040 break; 7041 default: 7042 res = 1; 7043 } 7044 7045 /* Read back reg 0x10 to ensure hardware is ready. */ 7046 if (res == 0 && reg10 >= 0) { 7047 for (i = 0; i < 5; i++) { 7048 if (elantech_read_1(kbdc, hwversion, 0x10, &val) == 0) 7049 break; 7050 DELAY(2000); 7051 } 7052 if (i == 5) 7053 res = 1; 7054 } 7055 7056 if (res) 7057 printf("couldn't set absolute mode\n"); 7058 7059 return (res); 7060 } 7061 7062 static void 7063 elantech_init_synaptics(struct psm_softc *sc) 7064 { 7065 7066 /* Set capabilites required by movement smother */ 7067 sc->synhw.infoMajor = sc->elanhw.hwversion; 7068 sc->synhw.infoMinor = sc->elanhw.fwversion; 7069 sc->synhw.infoXupmm = sc->elanhw.dpmmx; 7070 sc->synhw.infoYupmm = sc->elanhw.dpmmy; 7071 sc->synhw.verticalScroll = 0; 7072 sc->synhw.nExtendedQueries = 4; 7073 sc->synhw.capExtended = 1; 7074 sc->synhw.capPassthrough = sc->elanhw.hastrackpoint; 7075 sc->synhw.capClickPad = sc->elanhw.isclickpad; 7076 sc->synhw.capMultiFinger = 1; 7077 if (sc->elanhw.issemimt) 7078 sc->synhw.capAdvancedGestures = 1; 7079 else 7080 sc->synhw.capReportsV = 1; 7081 sc->synhw.capPalmDetect = 1; 7082 sc->synhw.capPen = 0; 7083 sc->synhw.capReportsMax = 1; 7084 sc->synhw.maximumXCoord = sc->elanhw.sizex; 7085 sc->synhw.maximumYCoord = sc->elanhw.sizey; 7086 sc->synhw.capReportsMin = 1; 7087 sc->synhw.minimumXCoord = 0; 7088 sc->synhw.minimumYCoord = 0; 7089 7090 if (sc->syninfo.sysctl_tree == NULL) { 7091 synaptics_sysctl_create_tree(sc, "elantech", 7092 "Elantech Touchpad"); 7093 7094 /* 7095 * Adjust synaptic smoother tunables 7096 * 1. Disable finger detection pressure threshold. Unlike 7097 * synaptics we assume the finger is acting when packet with 7098 * its X&Y arrives not when pressure exceedes some threshold 7099 * 2. Disable unrelated features like margins and noisy areas 7100 * 3. Disable virtual scroll areas as 2nd finger is preferable 7101 * 4. For clickpads set bottom quarter as 42% - 16% - 42% sized 7102 * softbuttons 7103 * 5. Scale down divisors and movement lengths by a factor of 3 7104 * where 3 is Synaptics to Elantech (~2200/800) dpi ratio 7105 */ 7106 7107 /* Set reporting range to be equal touchpad size */ 7108 sc->syninfo.max_x = sc->elanhw.sizex; 7109 sc->syninfo.max_y = sc->elanhw.sizey; 7110 7111 /* Disable finger detection pressure threshold */ 7112 sc->syninfo.min_pressure = 1; 7113 7114 /* Adjust palm width to nearly match synaptics w=10 */ 7115 sc->syninfo.max_width = 7; 7116 7117 /* Elans often report double & triple taps as single event */ 7118 sc->syninfo.tap_min_queue = 1; 7119 7120 /* Use full area of touchpad */ 7121 sc->syninfo.margin_top = 0; 7122 sc->syninfo.margin_right = 0; 7123 sc->syninfo.margin_bottom = 0; 7124 sc->syninfo.margin_left = 0; 7125 7126 /* Disable noisy area */ 7127 sc->syninfo.na_top = 0; 7128 sc->syninfo.na_right = 0; 7129 sc->syninfo.na_bottom = 0; 7130 sc->syninfo.na_left = 0; 7131 7132 /* Tune divisors and movement lengths */ 7133 sc->syninfo.weight_len_squared = 200; 7134 sc->syninfo.div_min = 3; 7135 sc->syninfo.div_max = 6; 7136 sc->syninfo.div_max_na = 10; 7137 sc->syninfo.div_len = 30; 7138 sc->syninfo.tap_max_delta = 25; 7139 7140 /* Disable virtual scrolling areas and tune its divisors */ 7141 sc->syninfo.vscroll_hor_area = 0; 7142 sc->syninfo.vscroll_ver_area = 0; 7143 sc->syninfo.vscroll_min_delta = 15; 7144 sc->syninfo.vscroll_div_min = 30; 7145 sc->syninfo.vscroll_div_max = 50; 7146 7147 /* Set bottom quarter as 42% - 16% - 42% sized softbuttons */ 7148 if (sc->elanhw.isclickpad) { 7149 sc->syninfo.softbuttons_y = sc->elanhw.sizey / 4; 7150 sc->syninfo.softbutton2_x = sc->elanhw.sizex * 11 / 25; 7151 sc->syninfo.softbutton3_x = sc->elanhw.sizex * 14 / 25; 7152 } 7153 } 7154 7155 return; 7156 } 7157 7158 static int 7159 enable_elantech(struct psm_softc *sc, enum probearg arg) 7160 { 7161 static const int ic2hw[] = 7162 /*IC: 0 1 2 3 4 5 6 7 8 9 a b c d e f */ 7163 { 0, 0, 2, 0, 2, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4 }; 7164 static const int fw_sizes[][3] = { 7165 /* FW.vers MaxX MaxY */ 7166 { 0x020030, 1152, 768 }, 7167 { 0x020800, 1152, 768 }, 7168 { 0x020b00, 1152, 768 }, 7169 { 0x040215, 900, 500 }, 7170 { 0x040216, 819, 405 }, 7171 { 0x040219, 900, 500 }, 7172 }; 7173 elantechhw_t elanhw; 7174 int icversion, hwversion, xtr, i, id, resp[3], dpix, dpiy; 7175 KBDC kbdc = sc->kbdc; 7176 7177 VLOG(3, (LOG_DEBUG, "elantech: BEGIN init\n")); 7178 7179 set_mouse_scaling(kbdc, 1); 7180 set_mouse_scaling(kbdc, 1); 7181 set_mouse_scaling(kbdc, 1); 7182 if (get_mouse_status(kbdc, resp, 0, 3) != 3) 7183 return (FALSE); 7184 7185 if (!ELANTECH_MAGIC(resp)) 7186 return (FALSE); 7187 7188 /* Identify the Touchpad version. */ 7189 if (elantech_cmd(kbdc, 2, ELANTECH_FW_VERSION, resp)) 7190 return (FALSE); 7191 7192 bzero(&elanhw, sizeof(elanhw)); 7193 7194 elanhw.fwversion = (resp[0] << 16) | (resp[1] << 8) | resp[2]; 7195 icversion = resp[0] & 0x0f; 7196 hwversion = ic2hw[icversion]; 7197 7198 if (verbose >= 2) 7199 printf("Elantech touchpad hardware v.%d firmware v.0x%06x\n", 7200 hwversion, elanhw.fwversion); 7201 7202 if (ELANTECH_HW_IS_V1(elanhw.fwversion)) { 7203 printf (" Unsupported touchpad hardware (v1)\n"); 7204 return (FALSE); 7205 } 7206 if (hwversion == 0) { 7207 printf (" Unknown touchpad hardware (firmware v.0x%06x)\n", 7208 elanhw.fwversion); 7209 return (FALSE); 7210 } 7211 7212 /* Get the Touchpad model information. */ 7213 elanhw.hwversion = hwversion; 7214 elanhw.issemimt = hwversion == 2; 7215 elanhw.isclickpad = (resp[1] & 0x10) != 0; 7216 elanhw.hascrc = (resp[1] & 0x40) != 0; 7217 elanhw.haspressure = elanhw.fwversion >= 0x020800; 7218 7219 /* Read the capability bits. */ 7220 if (elantech_cmd(kbdc, hwversion, ELANTECH_CAPABILITIES, resp) != 0) { 7221 printf(" Failed to read capability bits\n"); 7222 return (FALSE); 7223 } 7224 7225 elanhw.ntracesx = imax(resp[1], 3); 7226 elanhw.ntracesy = imax(resp[2], 3); 7227 elanhw.hastrackpoint = (resp[0] & 0x80) != 0; 7228 7229 /* Get the touchpad resolution */ 7230 switch (hwversion) { 7231 case 4: 7232 if (elantech_cmd(kbdc, hwversion, ELANTECH_RESOLUTION, resp) 7233 == 0) { 7234 dpix = (resp[1] & 0x0f) * 10 + 790; 7235 dpiy = ((resp[1] & 0xf0) >> 4) * 10 + 790; 7236 elanhw.dpmmx = (dpix * 10 + 5) / 254; 7237 elanhw.dpmmy = (dpiy * 10 + 5) / 254; 7238 break; 7239 } 7240 /* FALLTHROUGH */ 7241 case 2: 7242 case 3: 7243 elanhw.dpmmx = elanhw.dpmmy = 32; /* 800 dpi */ 7244 break; 7245 } 7246 7247 if (!elantech_support) 7248 return (FALSE); 7249 7250 if (elantech_init(kbdc, &elanhw)) { 7251 printf("couldn't initialize elantech touchpad\n"); 7252 return (FALSE); 7253 } 7254 7255 /* 7256 * Get the touchpad reporting range. 7257 * On HW v.3 touchpads it should be done after switching hardware 7258 * to real resolution mode (by setting bit 3 of reg10) 7259 */ 7260 elanhw.dptracex = elanhw.dptracey = 64; 7261 for (i = 0; i < nitems(fw_sizes); i++) { 7262 if (elanhw.fwversion == fw_sizes[i][0]) { 7263 elanhw.sizex = fw_sizes[i][1]; 7264 elanhw.sizey = fw_sizes[i][2]; 7265 goto found; 7266 } 7267 } 7268 if (elantech_cmd(kbdc, hwversion, ELANTECH_FW_ID, resp) != 0) { 7269 printf(" Failed to read touchpad size\n"); 7270 elanhw.sizex = 10000; /* Arbitrary high values to */ 7271 elanhw.sizey = 10000; /* prevent clipping in smoother */ 7272 } else if (hwversion == 2) { 7273 if ((elanhw.fwversion >> 16) == 0x14 && (resp[1] & 0x10) && 7274 !elantech_cmd(kbdc, hwversion, ELANTECH_SAMPLE, resp)) { 7275 elanhw.dptracex = resp[1] / 2; 7276 elanhw.dptracey = resp[2] / 2; 7277 } 7278 xtr = ((elanhw.fwversion >> 8) == 0x0208) ? 1 : 2; 7279 elanhw.sizex = (elanhw.ntracesx - xtr) * elanhw.dptracex; 7280 elanhw.sizey = (elanhw.ntracesy - xtr) * elanhw.dptracey; 7281 } else { 7282 elanhw.sizex = (resp[0] & 0x0f) << 8 | resp[1]; 7283 elanhw.sizey = (resp[0] & 0xf0) << 4 | resp[2]; 7284 xtr = (elanhw.sizex % (elanhw.ntracesx - 2) == 0) ? 2 : 1; 7285 elanhw.dptracex = elanhw.sizex / (elanhw.ntracesx - xtr); 7286 elanhw.dptracey = elanhw.sizey / (elanhw.ntracesy - xtr); 7287 } 7288 found: 7289 if (verbose >= 2) { 7290 printf(" Model information:\n"); 7291 printf(" MaxX: %d\n", elanhw.sizex); 7292 printf(" MaxY: %d\n", elanhw.sizey); 7293 printf(" DpmmX: %d\n", elanhw.dpmmx); 7294 printf(" DpmmY: %d\n", elanhw.dpmmy); 7295 printf(" TracesX: %d\n", elanhw.ntracesx); 7296 printf(" TracesY: %d\n", elanhw.ntracesy); 7297 printf(" DptraceX: %d\n", elanhw.dptracex); 7298 printf(" DptraceY: %d\n", elanhw.dptracey); 7299 printf(" SemiMT: %d\n", elanhw.issemimt); 7300 printf(" Clickpad: %d\n", elanhw.isclickpad); 7301 printf(" Trackpoint: %d\n", elanhw.hastrackpoint); 7302 printf(" CRC: %d\n", elanhw.hascrc); 7303 printf(" Pressure: %d\n", elanhw.haspressure); 7304 } 7305 7306 VLOG(3, (LOG_DEBUG, "elantech: END init\n")); 7307 7308 if (arg == PROBE) { 7309 sc->elanhw = elanhw; 7310 sc->hw.buttons = 3; 7311 7312 /* Initialize synaptics movement smoother */ 7313 elantech_init_synaptics(sc); 7314 7315 for (id = 0; id < ELANTECH_MAX_FINGERS; id++) 7316 PSM_FINGER_RESET(sc->elanaction.fingers[id]); 7317 } 7318 7319 return (TRUE); 7320 } 7321 7322 /* 7323 * Return true if 'now' is earlier than (start + (secs.usecs)). 7324 * Now may be NULL and the function will fetch the current time from 7325 * getmicrouptime(), or a cached 'now' can be passed in. 7326 * All values should be numbers derived from getmicrouptime(). 7327 */ 7328 static int 7329 timeelapsed(start, secs, usecs, now) 7330 const struct timeval *start, *now; 7331 int secs, usecs; 7332 { 7333 struct timeval snow, tv; 7334 7335 /* if there is no 'now' passed in, the get it as a convience. */ 7336 if (now == NULL) { 7337 getmicrouptime(&snow); 7338 now = &snow; 7339 } 7340 7341 tv.tv_sec = secs; 7342 tv.tv_usec = usecs; 7343 timevaladd(&tv, start); 7344 return (timevalcmp(&tv, now, <)); 7345 } 7346 7347 static int 7348 psmresume(device_t dev) 7349 { 7350 struct psm_softc *sc = device_get_softc(dev); 7351 int unit = device_get_unit(dev); 7352 int err; 7353 7354 VLOG(2, (LOG_NOTICE, "psm%d: system resume hook called.\n", unit)); 7355 7356 if ((sc->config & 7357 (PSM_CONFIG_HOOKRESUME | PSM_CONFIG_INITAFTERSUSPEND)) == 0) 7358 return (0); 7359 7360 err = reinitialize(sc, sc->config & PSM_CONFIG_INITAFTERSUSPEND); 7361 7362 if ((sc->state & PSM_ASLP) && !(sc->state & PSM_VALID)) { 7363 /* 7364 * Release the blocked process; it must be notified that 7365 * the device cannot be accessed anymore. 7366 */ 7367 sc->state &= ~PSM_ASLP; 7368 wakeup(sc); 7369 } 7370 7371 VLOG(2, (LOG_DEBUG, "psm%d: system resume hook exiting.\n", unit)); 7372 7373 return (err); 7374 } 7375 7376 DRIVER_MODULE(psm, atkbdc, psm_driver, psm_devclass, 0, 0); 7377 #ifdef EVDEV_SUPPORT 7378 MODULE_DEPEND(psm, evdev, 1, 1, 1); 7379 #endif 7380 7381 #ifdef DEV_ISA 7382 7383 /* 7384 * This sucks up assignments from PNPBIOS and ACPI. 7385 */ 7386 7387 /* 7388 * When the PS/2 mouse device is reported by ACPI or PnP BIOS, it may 7389 * appear BEFORE the AT keyboard controller. As the PS/2 mouse device 7390 * can be probed and attached only after the AT keyboard controller is 7391 * attached, we shall quietly reserve the IRQ resource for later use. 7392 * If the PS/2 mouse device is reported to us AFTER the keyboard controller, 7393 * copy the IRQ resource to the PS/2 mouse device instance hanging 7394 * under the keyboard controller, then probe and attach it. 7395 */ 7396 7397 static devclass_t psmcpnp_devclass; 7398 7399 static device_probe_t psmcpnp_probe; 7400 static device_attach_t psmcpnp_attach; 7401 7402 static device_method_t psmcpnp_methods[] = { 7403 DEVMETHOD(device_probe, psmcpnp_probe), 7404 DEVMETHOD(device_attach, psmcpnp_attach), 7405 7406 { 0, 0 } 7407 }; 7408 7409 static driver_t psmcpnp_driver = { 7410 PSMCPNP_DRIVER_NAME, 7411 psmcpnp_methods, 7412 sizeof(struct psmcpnp_softc), 7413 }; 7414 7415 static struct isa_pnp_id psmcpnp_ids[] = { 7416 { 0x030fd041, "PS/2 mouse port" }, /* PNP0F03 */ 7417 { 0x0e0fd041, "PS/2 mouse port" }, /* PNP0F0E */ 7418 { 0x120fd041, "PS/2 mouse port" }, /* PNP0F12 */ 7419 { 0x130fd041, "PS/2 mouse port" }, /* PNP0F13 */ 7420 { 0x1303d041, "PS/2 port" }, /* PNP0313, XXX */ 7421 { 0x02002e4f, "Dell PS/2 mouse port" }, /* Lat. X200, Dell */ 7422 { 0x0002a906, "ALPS Glide Point" }, /* ALPS Glide Point */ 7423 { 0x80374d24, "IBM PS/2 mouse port" }, /* IBM3780, ThinkPad */ 7424 { 0x81374d24, "IBM PS/2 mouse port" }, /* IBM3781, ThinkPad */ 7425 { 0x0190d94d, "SONY VAIO PS/2 mouse port"}, /* SNY9001, Vaio */ 7426 { 0x0290d94d, "SONY VAIO PS/2 mouse port"}, /* SNY9002, Vaio */ 7427 { 0x0390d94d, "SONY VAIO PS/2 mouse port"}, /* SNY9003, Vaio */ 7428 { 0x0490d94d, "SONY VAIO PS/2 mouse port"}, /* SNY9004, Vaio */ 7429 { 0 } 7430 }; 7431 7432 /* _HID list for quirk detection. Any device below has _CID from psmcpnp_ids */ 7433 static struct isa_pnp_id topbtpad_ids[] = { 7434 { 0x1700ae30, "Lenovo PS/2 clickpad port" }, /* LEN0017, ThinkPad */ 7435 { 0x1800ae30, "Lenovo PS/2 clickpad port" }, /* LEN0018, ThinkPad */ 7436 { 0x1900ae30, "Lenovo PS/2 clickpad port" }, /* LEN0019, ThinkPad */ 7437 { 0x2300ae30, "Lenovo PS/2 clickpad port" }, /* LEN0023, ThinkPad */ 7438 { 0x2a00ae30, "Lenovo PS/2 clickpad port" }, /* LEN002a, ThinkPad */ 7439 { 0x2b00ae30, "Lenovo PS/2 clickpad port" }, /* LEN002b, ThinkPad */ 7440 { 0x2c00ae30, "Lenovo PS/2 clickpad port" }, /* LEN002c, ThinkPad */ 7441 { 0x2d00ae30, "Lenovo PS/2 clickpad port" }, /* LEN002d, ThinkPad */ 7442 { 0x2e00ae30, "Lenovo PS/2 clickpad port" }, /* LEN002e, ThinkPad */ 7443 { 0x3300ae30, "Lenovo PS/2 clickpad port" }, /* LEN0033, ThinkPad */ 7444 { 0x3400ae30, "Lenovo PS/2 clickpad port" }, /* LEN0034, ThinkPad */ 7445 { 0x3500ae30, "Lenovo PS/2 clickpad port" }, /* LEN0035, ThinkPad */ 7446 { 0x3600ae30, "Lenovo PS/2 clickpad port" }, /* LEN0036, ThinkPad */ 7447 { 0x3700ae30, "Lenovo PS/2 clickpad port" }, /* LEN0037, ThinkPad */ 7448 { 0x3800ae30, "Lenovo PS/2 clickpad port" }, /* LEN0038, ThinkPad */ 7449 { 0x3900ae30, "Lenovo PS/2 clickpad port" }, /* LEN0039, ThinkPad */ 7450 { 0x4100ae30, "Lenovo PS/2 clickpad port" }, /* LEN0041, ThinkPad */ 7451 { 0x4200ae30, "Lenovo PS/2 clickpad port" }, /* LEN0042, ThinkPad */ 7452 { 0x4500ae30, "Lenovo PS/2 clickpad port" }, /* LEN0045, ThinkPad */ 7453 { 0x4700ae30, "Lenovo PS/2 clickpad port" }, /* LEN0047, ThinkPad */ 7454 { 0x4900ae30, "Lenovo PS/2 clickpad port" }, /* LEN0049, ThinkPad */ 7455 { 0x0020ae30, "Lenovo PS/2 clickpad port" }, /* LEN2000, ThinkPad */ 7456 { 0x0120ae30, "Lenovo PS/2 clickpad port" }, /* LEN2001, ThinkPad */ 7457 { 0x0220ae30, "Lenovo PS/2 clickpad port" }, /* LEN2002, ThinkPad */ 7458 { 0x0320ae30, "Lenovo PS/2 clickpad port" }, /* LEN2003, ThinkPad */ 7459 { 0x0420ae30, "Lenovo PS/2 clickpad port" }, /* LEN2004, ThinkPad */ 7460 { 0x0520ae30, "Lenovo PS/2 clickpad port" }, /* LEN2005, ThinkPad */ 7461 { 0x0620ae30, "Lenovo PS/2 clickpad port" }, /* LEN2006, ThinkPad */ 7462 { 0x0720ae30, "Lenovo PS/2 clickpad port" }, /* LEN2007, ThinkPad */ 7463 { 0x0820ae30, "Lenovo PS/2 clickpad port" }, /* LEN2008, ThinkPad */ 7464 { 0x0920ae30, "Lenovo PS/2 clickpad port" }, /* LEN2009, ThinkPad */ 7465 { 0x0a20ae30, "Lenovo PS/2 clickpad port" }, /* LEN200a, ThinkPad */ 7466 { 0x0b20ae30, "Lenovo PS/2 clickpad port" }, /* LEN200b, ThinkPad */ 7467 { 0 } 7468 }; 7469 7470 /* _HID list for quirk detection. Any device below has _CID from psmcpnp_ids */ 7471 static struct isa_pnp_id forcepad_ids[] = { 7472 { 0x0d302e4f, "HP PS/2 forcepad port" }, /* SYN300D, EB 1040 */ 7473 { 0x14302e4f, "HP PS/2 forcepad port" }, /* SYN3014, EB 1040 */ 7474 { 0 } 7475 }; 7476 7477 static int 7478 create_a_copy(device_t atkbdc, device_t me) 7479 { 7480 device_t psm; 7481 u_long irq; 7482 7483 /* find the PS/2 mouse device instance under the keyboard controller */ 7484 psm = device_find_child(atkbdc, PSM_DRIVER_NAME, 7485 device_get_unit(atkbdc)); 7486 if (psm == NULL) 7487 return (ENXIO); 7488 if (device_get_state(psm) != DS_NOTPRESENT) 7489 return (0); 7490 7491 /* move our resource to the found device */ 7492 irq = bus_get_resource_start(me, SYS_RES_IRQ, 0); 7493 bus_delete_resource(me, SYS_RES_IRQ, 0); 7494 bus_set_resource(psm, SYS_RES_IRQ, KBDC_RID_AUX, irq, 1); 7495 7496 /* ...then probe and attach it */ 7497 return (device_probe_and_attach(psm)); 7498 } 7499 7500 static int 7501 psmcpnp_probe(device_t dev) 7502 { 7503 struct psmcpnp_softc *sc = device_get_softc(dev); 7504 struct resource *res; 7505 u_long irq; 7506 int rid; 7507 7508 if (ISA_PNP_PROBE(device_get_parent(dev), dev, forcepad_ids) == 0) 7509 sc->type = PSMCPNP_FORCEPAD; 7510 else if (ISA_PNP_PROBE(device_get_parent(dev), dev, topbtpad_ids) == 0) 7511 sc->type = PSMCPNP_TOPBUTTONPAD; 7512 else if (ISA_PNP_PROBE(device_get_parent(dev), dev, psmcpnp_ids) == 0) 7513 sc->type = PSMCPNP_GENERIC; 7514 else 7515 return (ENXIO); 7516 7517 /* 7518 * The PnP BIOS and ACPI are supposed to assign an IRQ (12) 7519 * to the PS/2 mouse device node. But, some buggy PnP BIOS 7520 * declares the PS/2 mouse device node without an IRQ resource! 7521 * If this happens, we shall refer to device hints. 7522 * If we still don't find it there, use a hardcoded value... XXX 7523 */ 7524 rid = 0; 7525 irq = bus_get_resource_start(dev, SYS_RES_IRQ, rid); 7526 if (irq <= 0) { 7527 if (resource_long_value(PSM_DRIVER_NAME, 7528 device_get_unit(dev),"irq", &irq) != 0) 7529 irq = 12; /* XXX */ 7530 device_printf(dev, "irq resource info is missing; " 7531 "assuming irq %ld\n", irq); 7532 bus_set_resource(dev, SYS_RES_IRQ, rid, irq, 1); 7533 } 7534 res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 0); 7535 bus_release_resource(dev, SYS_RES_IRQ, rid, res); 7536 7537 /* keep quiet */ 7538 if (!bootverbose) 7539 device_quiet(dev); 7540 7541 return ((res == NULL) ? ENXIO : 0); 7542 } 7543 7544 static int 7545 psmcpnp_attach(device_t dev) 7546 { 7547 device_t atkbdc; 7548 7549 /* find the keyboard controller, which may be on acpi* or isa* bus */ 7550 atkbdc = devclass_get_device(devclass_find(ATKBDC_DRIVER_NAME), 7551 device_get_unit(dev)); 7552 if ((atkbdc != NULL) && (device_get_state(atkbdc) == DS_ATTACHED)) 7553 create_a_copy(atkbdc, dev); 7554 7555 return (0); 7556 } 7557 7558 DRIVER_MODULE(psmcpnp, isa, psmcpnp_driver, psmcpnp_devclass, 0, 0); 7559 DRIVER_MODULE(psmcpnp, acpi, psmcpnp_driver, psmcpnp_devclass, 0, 0); 7560 ISA_PNP_INFO(psmcpnp_ids); 7561 #endif /* DEV_ISA */ 7562