1 /* $NetBSD: synaptics.c,v 1.70 2020/10/01 17:13:19 nia Exp $ */ 2 3 /* 4 * Copyright (c) 2005, Steve C. Woodford 5 * Copyright (c) 2004, Ales Krenek 6 * Copyright (c) 2004, Kentaro A. Kurahone 7 * All rights reserved. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 13 * * Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * * Redistributions in binary form must reproduce the above 16 * copyright notice, this list of conditions and the following 17 * disclaimer in the documentation and/or other materials provided 18 * with the distribution. 19 * * Neither the name of the authors nor the names of its 20 * contributors may be used to endorse or promote products derived 21 * from this software without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 24 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 25 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 26 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 27 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 28 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 29 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 30 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 31 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 33 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 34 * POSSIBILITY OF SUCH DAMAGE. 35 * 36 */ 37 38 /* 39 * TODO: 40 * - Make the sysctl values per-instance instead of global. 41 * - Consider setting initial scaling factors at runtime according 42 * to the values returned by the 'Read Resolutions' command. 43 * - Support the serial protocol (we only support PS/2 for now) 44 * - Support auto-repeat for up/down button Z-axis emulation. 45 * - Maybe add some more gestures (can we use Palm support somehow?) 46 */ 47 48 #include "opt_pms.h" 49 50 #include <sys/cdefs.h> 51 __KERNEL_RCSID(0, "$NetBSD: synaptics.c,v 1.70 2020/10/01 17:13:19 nia Exp $"); 52 53 #include <sys/param.h> 54 #include <sys/systm.h> 55 #include <sys/device.h> 56 #include <sys/ioctl.h> 57 #include <sys/sysctl.h> 58 #include <sys/kernel.h> 59 #include <sys/proc.h> 60 61 #include <sys/bus.h> 62 63 #include <dev/pckbport/pckbportvar.h> 64 65 #include <dev/pckbport/synapticsreg.h> 66 #include <dev/pckbport/synapticsvar.h> 67 68 #include <dev/pckbport/pmsreg.h> 69 #include <dev/pckbport/pmsvar.h> 70 71 #include <dev/wscons/wsconsio.h> 72 #include <dev/wscons/wsmousevar.h> 73 74 /* 75 * Absolute-mode packets are decoded and passed around using 76 * the following structure. 77 */ 78 struct synaptics_packet { 79 signed short sp_x; /* Unscaled absolute X/Y coordinates */ 80 signed short sp_y; 81 u_char sp_z; /* Z (pressure) */ 82 u_char sp_w; /* W (contact patch width) */ 83 signed short sp_sx; /* Secondary finger unscaled absolute */ 84 /* X/Y coordinates */ 85 signed short sp_xy; 86 u_char sp_finger; /* 0 for primary, 1 for secondary */ 87 char sp_left; /* Left mouse button status */ 88 char sp_right; /* Right mouse button status */ 89 char sp_middle; /* Middle button status (possibly emulated) */ 90 char sp_up; /* Up button status */ 91 char sp_down; /* Down button status */ 92 }; 93 94 static void pms_synaptics_input(void *, int); 95 static void pms_synaptics_process_packet(struct pms_softc *, 96 struct synaptics_packet *); 97 static void pms_sysctl_synaptics(struct sysctllog **); 98 static int pms_sysctl_synaptics_verify(SYSCTLFN_ARGS); 99 100 /* Controlled by sysctl. */ 101 static int synaptics_up_down_emul = 3; 102 static int synaptics_up_down_motion_delta = 1; 103 static int synaptics_gesture_move = 200; 104 static int synaptics_gesture_length = 20; 105 static int synaptics_edge_left = SYNAPTICS_EDGE_LEFT; 106 static int synaptics_edge_right = SYNAPTICS_EDGE_RIGHT; 107 static int synaptics_edge_top = SYNAPTICS_EDGE_TOP; 108 static int synaptics_edge_bottom = SYNAPTICS_EDGE_BOTTOM; 109 static int synaptics_edge_motion_delta = 32; 110 static u_int synaptics_finger_high = SYNAPTICS_FINGER_LIGHT + 5; 111 static u_int synaptics_finger_low = SYNAPTICS_FINGER_LIGHT - 10; 112 static int synaptics_button_boundary = SYNAPTICS_EDGE_BOTTOM + 720; 113 static int synaptics_button2 = SYNAPTICS_EDGE_LEFT + (SYNAPTICS_EDGE_RIGHT - SYNAPTICS_EDGE_LEFT) / 3; 114 static int synaptics_button3 = SYNAPTICS_EDGE_LEFT + 2 * (SYNAPTICS_EDGE_RIGHT - SYNAPTICS_EDGE_LEFT) / 3; 115 static int synaptics_two_fingers_emul = 0; 116 static int synaptics_scale_x = 16; 117 static int synaptics_scale_y = 16; 118 static int synaptics_scale_z = 32; 119 static int synaptics_max_speed_x = 32; 120 static int synaptics_max_speed_y = 32; 121 static int synaptics_max_speed_z = 2; 122 static int synaptics_movement_threshold = 4; 123 static int synaptics_fscroll_min = 13; 124 static int synaptics_fscroll_max = 14; 125 static int synaptics_dz_hold = 30; 126 static int synaptics_movement_enable = 1; 127 static bool synaptics_aux_mid_button_scroll = TRUE; 128 129 /* Sysctl nodes. */ 130 static int synaptics_button_boundary_nodenum; 131 static int synaptics_button2_nodenum; 132 static int synaptics_button3_nodenum; 133 static int synaptics_up_down_emul_nodenum; 134 static int synaptics_up_down_motion_delta_nodenum; 135 static int synaptics_gesture_move_nodenum; 136 static int synaptics_gesture_length_nodenum; 137 static int synaptics_edge_left_nodenum; 138 static int synaptics_edge_right_nodenum; 139 static int synaptics_edge_top_nodenum; 140 static int synaptics_edge_bottom_nodenum; 141 static int synaptics_edge_motion_delta_nodenum; 142 static int synaptics_finger_high_nodenum; 143 static int synaptics_finger_low_nodenum; 144 static int synaptics_two_fingers_emul_nodenum; 145 static int synaptics_scale_x_nodenum; 146 static int synaptics_scale_y_nodenum; 147 static int synaptics_scale_z_nodenum; 148 static int synaptics_max_speed_x_nodenum; 149 static int synaptics_max_speed_y_nodenum; 150 static int synaptics_max_speed_z_nodenum; 151 static int synaptics_movement_threshold_nodenum; 152 static int synaptics_finger_scroll_min_nodenum; 153 static int synaptics_finger_scroll_max_nodenum; 154 static int synaptics_dz_hold_nodenum; 155 static int synaptics_movement_enable_nodenum; 156 static int synaptics_aux_mid_button_scroll_nodenum; 157 158 static int 159 synaptics_poll_cmd(struct pms_softc *psc, ...) 160 { 161 u_char cmd[4]; 162 size_t i; 163 va_list ap; 164 165 va_start(ap, psc); 166 167 for (i = 0; i < __arraycount(cmd); i++) 168 if ((cmd[i] = (u_char)va_arg(ap, int)) == 0) 169 break; 170 va_end(ap); 171 172 int res = pckbport_poll_cmd(psc->sc_kbctag, psc->sc_kbcslot, cmd, i, 0, 173 NULL, 0); 174 if (res) 175 aprint_error_dev(psc->sc_dev, "command error %#x\n", cmd[0]); 176 return res; 177 } 178 179 static int 180 synaptics_poll_reset(struct pms_softc *psc) 181 { 182 u_char resp[2]; 183 int res; 184 185 u_char cmd[1] = { PMS_RESET }; 186 res = pckbport_poll_cmd(psc->sc_kbctag, psc->sc_kbcslot, cmd, 1, 2, 187 resp, 1); 188 aprint_debug_dev(psc->sc_dev, "reset %d 0x%02x 0x%02x\n", 189 res, resp[0], resp[1]); 190 return res; 191 } 192 193 static int 194 synaptics_special_read(struct pms_softc *psc, u_char slice, u_char resp[3]) 195 { 196 u_char cmd[1] = { PMS_SEND_DEV_STATUS }; 197 int res = pms_sliced_command(psc->sc_kbctag, psc->sc_kbcslot, slice); 198 199 return res | pckbport_poll_cmd(psc->sc_kbctag, psc->sc_kbcslot, 200 cmd, 1, 3, resp, 0); 201 } 202 203 static int 204 synaptics_special_write(struct pms_softc *psc, u_char command, u_char arg) 205 { 206 int res = pms_sliced_command(psc->sc_kbctag, psc->sc_kbcslot, arg); 207 if (res) 208 return res; 209 210 u_char cmd[2]; 211 cmd[0] = PMS_SET_SAMPLE; 212 cmd[1] = command; 213 res = pckbport_poll_cmd(psc->sc_kbctag, psc->sc_kbcslot, 214 cmd, 2, 0, NULL, 0); 215 return res; 216 } 217 218 static void 219 pms_synaptics_probe_extended(struct pms_softc *psc) 220 { 221 struct synaptics_softc *sc = &psc->u.synaptics; 222 u_char resp[3]; 223 int res; 224 225 aprint_debug_dev(psc->sc_dev, 226 "synaptics_probe: Capabilities 0x%04x.\n", sc->caps); 227 if (sc->caps & SYNAPTICS_CAP_PASSTHROUGH) 228 sc->flags |= SYN_FLAG_HAS_PASSTHROUGH; 229 230 if (sc->caps & SYNAPTICS_CAP_PALMDETECT) 231 sc->flags |= SYN_FLAG_HAS_PALM_DETECT; 232 233 if (sc->caps & SYNAPTICS_CAP_MULTIDETECT) 234 sc->flags |= SYN_FLAG_HAS_MULTI_FINGER; 235 236 if (sc->caps & SYNAPTICS_CAP_MULTIFINGERREPORT) 237 sc->flags |= SYN_FLAG_HAS_MULTI_FINGER_REPORT; 238 239 /* Ask about extra buttons to detect up/down. */ 240 if (((sc->caps & SYNAPTICS_CAP_EXTNUM) + 0x08) 241 >= SYNAPTICS_EXTENDED_QUERY) 242 { 243 res = synaptics_special_read(psc, SYNAPTICS_EXTENDED_QUERY, resp); 244 if (res == 0) { 245 int buttons = (resp[1] >> 4); 246 aprint_debug_dev(psc->sc_dev, 247 "%s: Extended Buttons: %d.\n", __func__, buttons); 248 249 aprint_debug_dev(psc->sc_dev, "%s: Extended " 250 "Capabilities: 0x%02x 0x%02x 0x%02x.\n", __func__, 251 resp[0], resp[1], resp[2]); 252 if (buttons >= 2) { 253 /* Yes. */ 254 sc->flags |= SYN_FLAG_HAS_UP_DOWN_BUTTONS; 255 } 256 if (resp[0] & 0x1) { 257 /* Vertical scroll area */ 258 sc->flags |= SYN_FLAG_HAS_VERTICAL_SCROLL; 259 } 260 if (resp[0] & 0x2) { 261 /* Horizontal scroll area */ 262 sc->flags |= SYN_FLAG_HAS_HORIZONTAL_SCROLL; 263 } 264 if (resp[0] & 0x4) { 265 /* Extended W-Mode */ 266 sc->flags |= SYN_FLAG_HAS_EXTENDED_WMODE; 267 } 268 } 269 } 270 271 /* Ask about click pad */ 272 if (((sc->caps & SYNAPTICS_CAP_EXTNUM) + 0x08) >= 273 SYNAPTICS_CONTINUED_CAPABILITIES) 274 { 275 res = synaptics_special_read(psc, 276 SYNAPTICS_CONTINUED_CAPABILITIES, resp); 277 278 /* 279 * The following describes response for the 280 * SYNAPTICS_CONTINUED_CAPABILITIES query. 281 * 282 * byte mask name meaning 283 * ---- ---- ------- ------------ 284 * 0 0x01 adjustable threshold capacitive button sensitivity 285 * can be adjusted 286 * 0 0x02 report max query 0x0d gives max coord reported 287 * 0 0x04 clearpad sensor is ClearPad product 288 * 0 0x08 advanced gesture not particularly meaningful 289 * 0 0x10 clickpad bit 0 1-button ClickPad 290 * 0 0x60 multifinger mode identifies firmware finger counting 291 * (not reporting!) algorithm. 292 * Not particularly meaningful 293 * 0 0x80 covered pad W clipped to 14, 15 == pad mostly covered 294 * 1 0x01 clickpad bit 1 2-button ClickPad 295 * 1 0x02 deluxe LED controls touchpad support LED commands 296 * ala multimedia control bar 297 * 1 0x04 reduced filtering firmware does less filtering on 298 * position data, driver should watch 299 * for noise. 300 * 1 0x08 image sensor image sensor tracks 5 fingers, but only 301 * reports 2. 302 * 1 0x10 uniform clickpad whole clickpad moves instead of being 303 * hinged at the top. 304 * 1 0x20 report min query 0x0f gives min coord reported 305 */ 306 if (res == 0) { 307 uint val = SYN_CCAP_VALUE(resp); 308 309 aprint_debug_dev(psc->sc_dev, "%s: Continued " 310 "Capabilities 0x%02x 0x%02x 0x%02x.\n", __func__, 311 resp[0], resp[1], resp[2]); 312 switch (SYN_CCAP_CLICKPAD_TYPE(val)) { 313 case 0: /* not a clickpad */ 314 break; 315 case 1: 316 sc->flags |= SYN_FLAG_HAS_ONE_BUTTON_CLICKPAD; 317 break; 318 case 2: 319 sc->flags |= SYN_FLAG_HAS_TWO_BUTTON_CLICKPAD; 320 break; 321 case 3: /* reserved */ 322 default: 323 /* unreached */ 324 break; 325 } 326 327 if ((val & SYN_CCAP_HAS_ADV_GESTURE_MODE)) 328 sc->flags |= SYN_FLAG_HAS_ADV_GESTURE_MODE; 329 } 330 } 331 } 332 333 static const struct { 334 int bit; 335 const char *desc; 336 } syn_flags[] = { 337 { SYN_FLAG_HAS_EXTENDED_WMODE, "Extended W mode", }, 338 { SYN_FLAG_HAS_PASSTHROUGH, "Passthrough", }, 339 { SYN_FLAG_HAS_MIDDLE_BUTTON, "Middle button", }, 340 { SYN_FLAG_HAS_BUTTONS_4_5, "Buttons 4/5", }, 341 { SYN_FLAG_HAS_UP_DOWN_BUTTONS, "Up/down buttons", }, 342 { SYN_FLAG_HAS_PALM_DETECT, "Palm detect", }, 343 { SYN_FLAG_HAS_ONE_BUTTON_CLICKPAD, "One button click pad", }, 344 { SYN_FLAG_HAS_TWO_BUTTON_CLICKPAD, "Two button click pad", }, 345 { SYN_FLAG_HAS_VERTICAL_SCROLL, "Vertical scroll", }, 346 { SYN_FLAG_HAS_HORIZONTAL_SCROLL, "Horizontal scroll", }, 347 { SYN_FLAG_HAS_MULTI_FINGER_REPORT, "Multi-finger Report", }, 348 { SYN_FLAG_HAS_MULTI_FINGER, "Multi-finger", }, 349 }; 350 351 int 352 pms_synaptics_probe_init(void *vsc) 353 { 354 struct pms_softc *psc = vsc; 355 struct synaptics_softc *sc = &psc->u.synaptics; 356 u_char cmd[1], resp[3]; 357 int res, ver_minor, ver_major; 358 struct sysctllog *clog = NULL; 359 360 res = pms_sliced_command(psc->sc_kbctag, psc->sc_kbcslot, 361 SYNAPTICS_IDENTIFY_TOUCHPAD); 362 cmd[0] = PMS_SEND_DEV_STATUS; 363 res |= pckbport_poll_cmd(psc->sc_kbctag, psc->sc_kbcslot, cmd, 1, 3, 364 resp, 0); 365 if (res) { 366 aprint_debug_dev(psc->sc_dev, 367 "synaptics_probe: Identify Touchpad error.\n"); 368 /* 369 * Reset device in case the probe confused it. 370 */ 371 doreset: 372 (void)synaptics_poll_reset(psc); 373 return res; 374 } 375 376 if (resp[1] != SYNAPTICS_MAGIC_BYTE) { 377 aprint_debug_dev(psc->sc_dev, 378 "synaptics_probe: Not synaptics.\n"); 379 res = 1; 380 goto doreset; 381 } 382 383 sc->flags = 0; 384 385 /* Check for minimum version and print a nice message. */ 386 ver_major = resp[2] & 0x0f; 387 ver_minor = resp[0]; 388 aprint_normal_dev(psc->sc_dev, "Synaptics touchpad version %d.%d\n", 389 ver_major, ver_minor); 390 if (ver_major * 10 + ver_minor < SYNAPTICS_MIN_VERSION) { 391 /* No capability query support. */ 392 sc->caps = 0; 393 goto done; 394 } 395 396 397 /* Query the hardware capabilities. */ 398 res = synaptics_special_read(psc, SYNAPTICS_READ_CAPABILITIES, resp); 399 if (res) { 400 /* Hmm, failed to get capabilites. */ 401 aprint_error_dev(psc->sc_dev, 402 "synaptics_probe: Failed to query capabilities.\n"); 403 goto doreset; 404 } 405 406 sc->caps = SYNAPTICS_CAP_VALUE(resp); 407 408 if (sc->caps & SYNAPTICS_CAP_MBUTTON) 409 sc->flags |= SYN_FLAG_HAS_MIDDLE_BUTTON; 410 411 if (sc->caps & SYNAPTICS_CAP_4BUTTON) 412 sc->flags |= SYN_FLAG_HAS_BUTTONS_4_5; 413 414 if (sc->caps & SYNAPTICS_CAP_EXTENDED) { 415 pms_synaptics_probe_extended(psc); 416 } 417 418 if (sc->flags) { 419 const char comma[] = ", "; 420 const char *sep = ""; 421 aprint_normal_dev(psc->sc_dev, ""); 422 for (size_t f = 0; f < __arraycount(syn_flags); f++) { 423 if (sc->flags & syn_flags[f].bit) { 424 aprint_normal("%s%s", sep, syn_flags[f].desc); 425 sep = comma; 426 } 427 } 428 aprint_normal("\n"); 429 } 430 431 done: 432 pms_sysctl_synaptics(&clog); 433 pckbport_set_inputhandler(psc->sc_kbctag, psc->sc_kbcslot, 434 pms_synaptics_input, psc, device_xname(psc->sc_dev)); 435 436 return (0); 437 } 438 439 void 440 pms_synaptics_enable(void *vsc) 441 { 442 struct pms_softc *psc = vsc; 443 struct synaptics_softc *sc = &psc->u.synaptics; 444 u_char enable_modes; 445 int res, i; 446 447 if (sc->flags & SYN_FLAG_HAS_PASSTHROUGH) { 448 /* 449 * Extended capability probes can confuse the passthrough 450 * device; reset the touchpad now to cure that. 451 */ 452 res = synaptics_poll_reset(psc); 453 } 454 455 /* 456 * Enable Absolute mode with W (width) reporting, and set 457 * the packet rate to maximum (80 packets per second). Enable 458 * extended W mode if supported so we can report second finger 459 * position. 460 */ 461 enable_modes = 462 SYNAPTICS_MODE_ABSOLUTE | SYNAPTICS_MODE_W | SYNAPTICS_MODE_RATE; 463 464 if (sc->flags & SYN_FLAG_HAS_EXTENDED_WMODE) 465 enable_modes |= SYNAPTICS_MODE_EXTENDED_W; 466 467 /* 468 * Synaptics documentation says to disable device before 469 * setting mode. 470 */ 471 synaptics_poll_cmd(psc, PMS_DEV_DISABLE, 0); 472 /* a couple of set scales to clear out pending commands */ 473 for (i = 0; i < 2; i++) 474 synaptics_poll_cmd(psc, PMS_SET_SCALE11, 0); 475 476 res = synaptics_special_write(psc, SYNAPTICS_CMD_SET_MODE2, enable_modes); 477 if (res) 478 aprint_error("synaptics: set mode error\n"); 479 480 /* a couple of set scales to clear out pending commands */ 481 for (i = 0; i < 2; i++) 482 synaptics_poll_cmd(psc, PMS_SET_SCALE11, 0); 483 484 /* Set advanced gesture mode */ 485 if ((sc->flags & SYN_FLAG_HAS_EXTENDED_WMODE) || 486 (sc->flags & SYN_FLAG_HAS_ADV_GESTURE_MODE)) 487 synaptics_special_write(psc, SYNAPTICS_WRITE_DELUXE_3, 0x3); 488 489 sc->up_down = 0; 490 sc->prev_fingers = 0; 491 sc->gesture_start_x = sc->gesture_start_y = 0; 492 sc->gesture_start_packet = 0; 493 sc->gesture_tap_packet = 0; 494 sc->gesture_type = 0; 495 sc->gesture_buttons = 0; 496 sc->dz_hold = 0; 497 for (i = 0; i < SYN_MAX_FINGERS; i++) { 498 sc->rem_x[i] = sc->rem_y[i] = sc->rem_z[i] = 0; 499 sc->movement_history[i] = 0; 500 } 501 sc->button_history = 0; 502 } 503 504 void 505 pms_synaptics_resume(void *vsc) 506 { 507 (void)synaptics_poll_reset(vsc); 508 } 509 510 static void 511 pms_sysctl_synaptics(struct sysctllog **clog) 512 { 513 int rc, root_num; 514 const struct sysctlnode *node; 515 516 if ((rc = sysctl_createv(clog, 0, NULL, &node, 517 CTLFLAG_PERMANENT, CTLTYPE_NODE, "synaptics", 518 SYSCTL_DESCR("Synaptics touchpad controls"), 519 NULL, 0, NULL, 0, CTL_HW, CTL_CREATE, CTL_EOL)) != 0) 520 goto err; 521 522 root_num = node->sysctl_num; 523 524 if ((rc = sysctl_createv(clog, 0, NULL, &node, 525 CTLFLAG_PERMANENT | CTLFLAG_READWRITE, 526 CTLTYPE_INT, "up_down_emulation", 527 SYSCTL_DESCR("Middle button/Z-axis emulation with up/down buttons"), 528 pms_sysctl_synaptics_verify, 0, 529 &synaptics_up_down_emul, 530 0, CTL_HW, root_num, CTL_CREATE, 531 CTL_EOL)) != 0) 532 goto err; 533 534 synaptics_up_down_emul_nodenum = node->sysctl_num; 535 536 if ((rc = sysctl_createv(clog, 0, NULL, &node, 537 CTLFLAG_PERMANENT | CTLFLAG_READWRITE, 538 CTLTYPE_INT, "up_down_motion_delta", 539 SYSCTL_DESCR("Up/down button Z-axis emulation rate"), 540 pms_sysctl_synaptics_verify, 0, 541 &synaptics_up_down_motion_delta, 542 0, CTL_HW, root_num, CTL_CREATE, 543 CTL_EOL)) != 0) 544 goto err; 545 546 synaptics_up_down_motion_delta_nodenum = node->sysctl_num; 547 548 if ((rc = sysctl_createv(clog, 0, NULL, &node, 549 CTLFLAG_PERMANENT | CTLFLAG_READWRITE, 550 CTLTYPE_INT, "gesture_move", 551 SYSCTL_DESCR("Movement greater than this between taps cancels gesture"), 552 pms_sysctl_synaptics_verify, 0, 553 &synaptics_gesture_move, 554 0, CTL_HW, root_num, CTL_CREATE, 555 CTL_EOL)) != 0) 556 goto err; 557 558 synaptics_gesture_move_nodenum = node->sysctl_num; 559 560 if ((rc = sysctl_createv(clog, 0, NULL, &node, 561 CTLFLAG_PERMANENT | CTLFLAG_READWRITE, 562 CTLTYPE_INT, "gesture_length", 563 SYSCTL_DESCR("Time period in which tap is recognised as a gesture"), 564 pms_sysctl_synaptics_verify, 0, 565 &synaptics_gesture_length, 566 0, CTL_HW, root_num, CTL_CREATE, 567 CTL_EOL)) != 0) 568 goto err; 569 570 synaptics_gesture_length_nodenum = node->sysctl_num; 571 572 if ((rc = sysctl_createv(clog, 0, NULL, &node, 573 CTLFLAG_PERMANENT | CTLFLAG_READWRITE, 574 CTLTYPE_INT, "edge_left", 575 SYSCTL_DESCR("Define left edge of touchpad"), 576 pms_sysctl_synaptics_verify, 0, 577 &synaptics_edge_left, 578 0, CTL_HW, root_num, CTL_CREATE, 579 CTL_EOL)) != 0) 580 goto err; 581 582 synaptics_edge_left_nodenum = node->sysctl_num; 583 584 if ((rc = sysctl_createv(clog, 0, NULL, &node, 585 CTLFLAG_PERMANENT | CTLFLAG_READWRITE, 586 CTLTYPE_INT, "edge_right", 587 SYSCTL_DESCR("Define right edge of touchpad"), 588 pms_sysctl_synaptics_verify, 0, 589 &synaptics_edge_right, 590 0, CTL_HW, root_num, CTL_CREATE, 591 CTL_EOL)) != 0) 592 goto err; 593 594 synaptics_edge_right_nodenum = node->sysctl_num; 595 596 if ((rc = sysctl_createv(clog, 0, NULL, &node, 597 CTLFLAG_PERMANENT | CTLFLAG_READWRITE, 598 CTLTYPE_INT, "edge_top", 599 SYSCTL_DESCR("Define top edge of touchpad"), 600 pms_sysctl_synaptics_verify, 0, 601 &synaptics_edge_top, 602 0, CTL_HW, root_num, CTL_CREATE, 603 CTL_EOL)) != 0) 604 goto err; 605 606 synaptics_edge_top_nodenum = node->sysctl_num; 607 608 if ((rc = sysctl_createv(clog, 0, NULL, &node, 609 CTLFLAG_PERMANENT | CTLFLAG_READWRITE, 610 CTLTYPE_INT, "edge_bottom", 611 SYSCTL_DESCR("Define bottom edge of touchpad"), 612 pms_sysctl_synaptics_verify, 0, 613 &synaptics_edge_bottom, 614 0, CTL_HW, root_num, CTL_CREATE, 615 CTL_EOL)) != 0) 616 goto err; 617 618 synaptics_edge_bottom_nodenum = node->sysctl_num; 619 620 if ((rc = sysctl_createv(clog, 0, NULL, &node, 621 CTLFLAG_PERMANENT | CTLFLAG_READWRITE, 622 CTLTYPE_INT, "edge_motion_delta", 623 SYSCTL_DESCR("Define edge motion rate"), 624 pms_sysctl_synaptics_verify, 0, 625 &synaptics_edge_motion_delta, 626 0, CTL_HW, root_num, CTL_CREATE, 627 CTL_EOL)) != 0) 628 goto err; 629 630 synaptics_edge_motion_delta_nodenum = node->sysctl_num; 631 632 if ((rc = sysctl_createv(clog, 0, NULL, &node, 633 CTLFLAG_PERMANENT | CTLFLAG_READWRITE, 634 CTLTYPE_INT, "finger_high", 635 SYSCTL_DESCR("Define finger applied pressure threshold"), 636 pms_sysctl_synaptics_verify, 0, 637 &synaptics_finger_high, 638 0, CTL_HW, root_num, CTL_CREATE, 639 CTL_EOL)) != 0) 640 goto err; 641 642 synaptics_finger_high_nodenum = node->sysctl_num; 643 644 if ((rc = sysctl_createv(clog, 0, NULL, &node, 645 CTLFLAG_PERMANENT | CTLFLAG_READWRITE, 646 CTLTYPE_INT, "finger_low", 647 SYSCTL_DESCR("Define finger removed pressure threshold"), 648 pms_sysctl_synaptics_verify, 0, 649 &synaptics_finger_low, 650 0, CTL_HW, root_num, CTL_CREATE, 651 CTL_EOL)) != 0) 652 goto err; 653 654 synaptics_finger_low_nodenum = node->sysctl_num; 655 656 if ((rc = sysctl_createv(clog, 0, NULL, &node, 657 CTLFLAG_PERMANENT | CTLFLAG_READWRITE, 658 CTLTYPE_INT, "two_fingers_emulation", 659 SYSCTL_DESCR("Map two fingers to middle button"), 660 pms_sysctl_synaptics_verify, 0, 661 &synaptics_two_fingers_emul, 662 0, CTL_HW, root_num, CTL_CREATE, 663 CTL_EOL)) != 0) 664 goto err; 665 666 synaptics_two_fingers_emul_nodenum = node->sysctl_num; 667 668 if ((rc = sysctl_createv(clog, 0, NULL, &node, 669 CTLFLAG_PERMANENT | CTLFLAG_READWRITE, 670 CTLTYPE_INT, "scale_x", 671 SYSCTL_DESCR("Horizontal movement scale factor"), 672 pms_sysctl_synaptics_verify, 0, 673 &synaptics_scale_x, 674 0, CTL_HW, root_num, CTL_CREATE, 675 CTL_EOL)) != 0) 676 goto err; 677 678 synaptics_scale_x_nodenum = node->sysctl_num; 679 680 if ((rc = sysctl_createv(clog, 0, NULL, &node, 681 CTLFLAG_PERMANENT | CTLFLAG_READWRITE, 682 CTLTYPE_INT, "scale_y", 683 SYSCTL_DESCR("Vertical movement scale factor"), 684 pms_sysctl_synaptics_verify, 0, 685 &synaptics_scale_y, 686 0, CTL_HW, root_num, CTL_CREATE, 687 CTL_EOL)) != 0) 688 goto err; 689 690 synaptics_scale_y_nodenum = node->sysctl_num; 691 692 if ((rc = sysctl_createv(clog, 0, NULL, &node, 693 CTLFLAG_PERMANENT | CTLFLAG_READWRITE, 694 CTLTYPE_INT, "scale_z", 695 SYSCTL_DESCR("Sroll wheel emulation scale factor"), 696 pms_sysctl_synaptics_verify, 0, 697 &synaptics_scale_z, 698 0, CTL_HW, root_num, CTL_CREATE, 699 CTL_EOL)) != 0) 700 goto err; 701 702 synaptics_scale_z_nodenum = node->sysctl_num; 703 704 if ((rc = sysctl_createv(clog, 0, NULL, &node, 705 CTLFLAG_PERMANENT | CTLFLAG_READWRITE, 706 CTLTYPE_INT, "max_speed_x", 707 SYSCTL_DESCR("Horizontal movement maximum speed"), 708 pms_sysctl_synaptics_verify, 0, 709 &synaptics_max_speed_x, 710 0, CTL_HW, root_num, CTL_CREATE, 711 CTL_EOL)) != 0) 712 goto err; 713 714 synaptics_max_speed_x_nodenum = node->sysctl_num; 715 716 if ((rc = sysctl_createv(clog, 0, NULL, &node, 717 CTLFLAG_PERMANENT | CTLFLAG_READWRITE, 718 CTLTYPE_INT, "max_speed_y", 719 SYSCTL_DESCR("Vertical movement maximum speed"), 720 pms_sysctl_synaptics_verify, 0, 721 &synaptics_max_speed_y, 722 0, CTL_HW, root_num, CTL_CREATE, 723 CTL_EOL)) != 0) 724 goto err; 725 726 synaptics_max_speed_y_nodenum = node->sysctl_num; 727 728 if ((rc = sysctl_createv(clog, 0, NULL, &node, 729 CTLFLAG_PERMANENT | CTLFLAG_READWRITE, 730 CTLTYPE_INT, "max_speed_z", 731 SYSCTL_DESCR("Scroll wheel emulation maximum speed"), 732 pms_sysctl_synaptics_verify, 0, 733 &synaptics_max_speed_z, 734 0, CTL_HW, root_num, CTL_CREATE, 735 CTL_EOL)) != 0) 736 goto err; 737 738 synaptics_max_speed_z_nodenum = node->sysctl_num; 739 740 if ((rc = sysctl_createv(clog, 0, NULL, &node, 741 CTLFLAG_PERMANENT | CTLFLAG_READWRITE, 742 CTLTYPE_INT, "movement_threshold", 743 SYSCTL_DESCR("Minimum reported movement threshold"), 744 pms_sysctl_synaptics_verify, 0, 745 &synaptics_movement_threshold, 746 0, CTL_HW, root_num, CTL_CREATE, 747 CTL_EOL)) != 0) 748 goto err; 749 750 synaptics_movement_threshold_nodenum = node->sysctl_num; 751 752 if ((rc = sysctl_createv(clog, 0, NULL, &node, 753 CTLFLAG_PERMANENT | CTLFLAG_READWRITE, 754 CTLTYPE_INT, "movement_enable", 755 SYSCTL_DESCR("Enable movement reporting"), 756 pms_sysctl_synaptics_verify, 0, 757 &synaptics_movement_enable, 758 0, CTL_HW, root_num, CTL_CREATE, 759 CTL_EOL)) != 0) 760 goto err; 761 762 synaptics_movement_enable_nodenum = node->sysctl_num; 763 764 if ((rc = sysctl_createv(clog, 0, NULL, &node, 765 CTLFLAG_PERMANENT | CTLFLAG_READWRITE, 766 CTLTYPE_INT, "button_boundary", 767 SYSCTL_DESCR("Top edge of button area"), 768 pms_sysctl_synaptics_verify, 0, 769 &synaptics_button_boundary, 770 0, CTL_HW, root_num, CTL_CREATE, 771 CTL_EOL)) != 0) 772 goto err; 773 774 synaptics_button_boundary_nodenum = node->sysctl_num; 775 776 if ((rc = sysctl_createv(clog, 0, NULL, &node, 777 CTLFLAG_PERMANENT | CTLFLAG_READWRITE, 778 CTLTYPE_INT, "button2_edge", 779 SYSCTL_DESCR("Left edge of button 2 region"), 780 pms_sysctl_synaptics_verify, 0, 781 &synaptics_button2, 782 0, CTL_HW, root_num, CTL_CREATE, 783 CTL_EOL)) != 0) 784 goto err; 785 786 synaptics_button2_nodenum = node->sysctl_num; 787 788 if ((rc = sysctl_createv(clog, 0, NULL, &node, 789 CTLFLAG_PERMANENT | CTLFLAG_READWRITE, 790 CTLTYPE_INT, "button3_edge", 791 SYSCTL_DESCR("Left edge of button 3 region"), 792 pms_sysctl_synaptics_verify, 0, 793 &synaptics_button3, 794 0, CTL_HW, root_num, CTL_CREATE, 795 CTL_EOL)) != 0) 796 goto err; 797 798 synaptics_button3_nodenum = node->sysctl_num; 799 800 if ((rc = sysctl_createv(clog, 0, NULL, &node, 801 CTLFLAG_PERMANENT | CTLFLAG_READWRITE, 802 CTLTYPE_INT, "finger_scroll-min", 803 SYSCTL_DESCR("Minimum width at which y cursor movements will be converted to scroll wheel events"), 804 pms_sysctl_synaptics_verify, 0, 805 &synaptics_fscroll_min, 806 0, CTL_HW, root_num, CTL_CREATE, 807 CTL_EOL)) != 0) 808 goto err; 809 810 synaptics_finger_scroll_min_nodenum = node->sysctl_num; 811 812 if ((rc = sysctl_createv(clog, 0, NULL, &node, 813 CTLFLAG_PERMANENT | CTLFLAG_READWRITE, 814 CTLTYPE_INT, "finger_scroll-max", 815 SYSCTL_DESCR("Maximum width at which y cursor movements will be converted to scroll wheel events"), 816 pms_sysctl_synaptics_verify, 0, 817 &synaptics_fscroll_max, 818 0, CTL_HW, root_num, CTL_CREATE, 819 CTL_EOL)) != 0) 820 goto err; 821 822 synaptics_finger_scroll_max_nodenum = node->sysctl_num; 823 824 if ((rc = sysctl_createv(clog, 0, NULL, &node, 825 CTLFLAG_PERMANENT | CTLFLAG_READWRITE, 826 CTLTYPE_INT, "finger_scroll-hysteresis", 827 SYSCTL_DESCR("Number of packets to keep reporting y cursor movements as scroll wheel events"), 828 pms_sysctl_synaptics_verify, 0, 829 &synaptics_dz_hold, 830 0, CTL_HW, root_num, CTL_CREATE, 831 CTL_EOL)) != 0) 832 goto err; 833 834 synaptics_dz_hold_nodenum = node->sysctl_num; 835 836 if ((rc = sysctl_createv(clog, 0, NULL, &node, 837 CTLFLAG_PERMANENT | CTLFLAG_READWRITE, 838 CTLTYPE_BOOL, "aux_mid_button_scroll", 839 SYSCTL_DESCR("Interpet Y-Axis movement with the middle button held as scrolling on the passthrough device (e.g. TrackPoint)"), 840 pms_sysctl_synaptics_verify, 0, 841 &synaptics_aux_mid_button_scroll, 842 0, CTL_HW, root_num, CTL_CREATE, 843 CTL_EOL)) != 0) 844 goto err; 845 846 synaptics_aux_mid_button_scroll_nodenum = node->sysctl_num; 847 return; 848 849 err: 850 aprint_error("%s: sysctl_createv failed (rc = %d)\n", __func__, rc); 851 } 852 853 static int 854 pms_sysctl_synaptics_verify(SYSCTLFN_ARGS) 855 { 856 int error, t; 857 struct sysctlnode node; 858 859 node = *rnode; 860 t = *(int *)rnode->sysctl_data; 861 node.sysctl_data = &t; 862 error = sysctl_lookup(SYSCTLFN_CALL(&node)); 863 if (error || newp == NULL) 864 return error; 865 866 /* Sanity check the params. */ 867 if (node.sysctl_num == synaptics_up_down_emul_nodenum) { 868 if (t < 0 || t > 3) 869 return (EINVAL); 870 } else 871 if (node.sysctl_num == synaptics_two_fingers_emul_nodenum) { 872 if (t < 0 || t > 2) 873 return (EINVAL); 874 } else 875 if (node.sysctl_num == synaptics_gesture_length_nodenum || 876 node.sysctl_num == synaptics_edge_motion_delta_nodenum || 877 node.sysctl_num == synaptics_up_down_motion_delta_nodenum || 878 node.sysctl_num == synaptics_max_speed_x_nodenum || 879 node.sysctl_num == synaptics_max_speed_y_nodenum || 880 node.sysctl_num == synaptics_max_speed_z_nodenum) { 881 if (t < 0) 882 return (EINVAL); 883 } else 884 if (node.sysctl_num == synaptics_edge_left_nodenum || 885 node.sysctl_num == synaptics_edge_bottom_nodenum) { 886 if (t < 0 || t > (SYNAPTICS_EDGE_MAX / 2)) 887 return (EINVAL); 888 } else 889 if (node.sysctl_num == synaptics_edge_right_nodenum || 890 node.sysctl_num == synaptics_edge_top_nodenum) { 891 if (t < (SYNAPTICS_EDGE_MAX / 2)) 892 return (EINVAL); 893 } else 894 if (node.sysctl_num == synaptics_scale_x_nodenum || 895 node.sysctl_num == synaptics_scale_y_nodenum || 896 node.sysctl_num == synaptics_scale_z_nodenum) { 897 if (t < 1 || t > (SYNAPTICS_EDGE_MAX / 4)) 898 return (EINVAL); 899 } else 900 if (node.sysctl_num == synaptics_finger_high_nodenum) { 901 if (t < 0 || t > SYNAPTICS_FINGER_PALM || 902 t < synaptics_finger_low) 903 return (EINVAL); 904 } else 905 if (node.sysctl_num == synaptics_finger_low_nodenum) { 906 if (t < 0 || t > SYNAPTICS_FINGER_PALM || 907 t > synaptics_finger_high) 908 return (EINVAL); 909 } else 910 if (node.sysctl_num == synaptics_gesture_move_nodenum || 911 node.sysctl_num == synaptics_movement_threshold_nodenum) { 912 if (t < 0 || t > (SYNAPTICS_EDGE_MAX / 4)) 913 return (EINVAL); 914 } else 915 if (node.sysctl_num == synaptics_button_boundary_nodenum) { 916 if (t < 0 || t < SYNAPTICS_EDGE_BOTTOM || 917 t > SYNAPTICS_EDGE_TOP) 918 return (EINVAL); 919 } else 920 if (node.sysctl_num == synaptics_button2_nodenum || 921 node.sysctl_num == synaptics_button3_nodenum) { 922 if (t < SYNAPTICS_EDGE_LEFT || t > SYNAPTICS_EDGE_RIGHT) 923 return (EINVAL); 924 } else 925 if (node.sysctl_num == synaptics_finger_scroll_min_nodenum || 926 node.sysctl_num == synaptics_finger_scroll_max_nodenum) { 927 /* make sure we avoid the "magic" widths, 4 and below 928 are for fingers, 15 is palm detect. */ 929 if ((t < 5) || (t > 14)) 930 return (EINVAL); 931 } else 932 if (node.sysctl_num == synaptics_dz_hold_nodenum) { 933 if (t < 0) 934 return (EINVAL); 935 } else 936 if (node.sysctl_num == synaptics_movement_enable_nodenum) { 937 if (t < 0 || t > 1) 938 return (EINVAL); 939 } else 940 if (node.sysctl_num == synaptics_aux_mid_button_scroll_nodenum) { 941 if (t < 0 || t > 1) 942 return (EINVAL); 943 } else 944 return (EINVAL); 945 946 *(int *)rnode->sysctl_data = t; 947 948 return (0); 949 } 950 951 /* Masks for the first byte of a packet */ 952 #define PMS_LBUTMASK 0x01 953 #define PMS_RBUTMASK 0x02 954 #define PMS_MBUTMASK 0x04 955 956 static void 957 pms_synaptics_parse(struct pms_softc *psc) 958 { 959 struct synaptics_softc *sc = &psc->u.synaptics; 960 struct synaptics_packet sp; 961 char new_buttons, ew_mode; 962 963 memset(&sp, 0, sizeof(sp)); 964 965 /* Width of finger */ 966 sp.sp_w = ((psc->packet[0] & 0x30) >> 2) + 967 ((psc->packet[0] & 0x04) >> 1) + 968 ((psc->packet[3] & 0x04) >> 2); 969 sp.sp_finger = 0; 970 if ((sc->flags & SYN_FLAG_HAS_EXTENDED_WMODE) && 971 (sp.sp_w == SYNAPTICS_WIDTH_EXTENDED_W)) { 972 ew_mode = psc->packet[5] >> 4; 973 switch (ew_mode) 974 { 975 case SYNAPTICS_EW_WHEEL: 976 /* scroll wheel report, ignore for now */ 977 aprint_debug_dev(psc->sc_dev, "mouse wheel packet\n"); 978 return; 979 980 case SYNAPTICS_EW_SECONDARY_FINGER: 981 /* parse the second finger report */ 982 983 sp.sp_finger = 1; /* just one other finger for now */ 984 sp.sp_x = psc->packet[1] 985 + ((psc->packet[4] & 0x0f) << 8); 986 sp.sp_y = psc->packet[2] 987 + ((psc->packet[4] & 0xf0) << 4); 988 sp.sp_z = (psc->packet[3] & 0x30) 989 + (psc->packet[5] & 0x0f); 990 991 /* keep same buttons down as primary */ 992 sp.sp_left = sc->button_history & PMS_LBUTMASK; 993 sp.sp_middle = sc->button_history & PMS_MBUTMASK; 994 sp.sp_right = sc->button_history & PMS_RBUTMASK; 995 break; 996 997 case SYNAPTICS_EW_FINGER_STATUS: 998 /* reports which finger is primary/secondary 999 * ignore for now. 1000 */ 1001 return; 1002 1003 default: 1004 aprint_error_dev(psc->sc_dev, 1005 "invalid extended w mode %d\n", 1006 ew_mode); 1007 return; 1008 } 1009 } else { 1010 1011 /* Absolute X/Y coordinates of finger */ 1012 sp.sp_x = psc->packet[4] + ((psc->packet[1] & 0x0f) << 8) + 1013 ((psc->packet[3] & 0x10) << 8); 1014 sp.sp_y = psc->packet[5] + ((psc->packet[1] & 0xf0) << 4) + 1015 ((psc->packet[3] & 0x20) << 7); 1016 1017 /* Pressure */ 1018 sp.sp_z = psc->packet[2]; 1019 1020 if ((psc->packet[0] ^ psc->packet[3]) & 0x02) { 1021 /* extended buttons */ 1022 1023 aprint_debug_dev(psc->sc_dev, 1024 "synaptics_parse: %02x %02x %02x %02x %02x %02x\n", 1025 psc->packet[0], psc->packet[1], psc->packet[2], 1026 psc->packet[3], psc->packet[4], psc->packet[5]); 1027 1028 if ((psc->packet[4] & SYN_1BUTMASK) != 0) 1029 sc->ext_left = PMS_LBUTMASK; 1030 else 1031 sc->ext_left = 0; 1032 1033 if ((psc->packet[4] & SYN_3BUTMASK) != 0) 1034 sc->ext_middle = PMS_MBUTMASK; 1035 else 1036 sc->ext_middle = 0; 1037 1038 if ((psc->packet[5] & SYN_2BUTMASK) != 0) 1039 sc->ext_right = PMS_RBUTMASK; 1040 else 1041 sc->ext_right = 0; 1042 1043 if ((psc->packet[5] & SYN_4BUTMASK) != 0) 1044 sc->ext_up = 1; 1045 else 1046 sc->ext_up = 0; 1047 1048 if ((psc->packet[4] & SYN_5BUTMASK) != 0) 1049 sc->ext_down = 1; 1050 else 1051 sc->ext_down = 0; 1052 } else { 1053 /* Left/Right button handling. */ 1054 sp.sp_left = psc->packet[0] & PMS_LBUTMASK; 1055 sp.sp_right = psc->packet[0] & PMS_RBUTMASK; 1056 } 1057 1058 /* Up/Down buttons. */ 1059 if (sc->flags & SYN_FLAG_HAS_BUTTONS_4_5) { 1060 /* Old up/down buttons. */ 1061 sp.sp_up = sp.sp_left ^ 1062 (psc->packet[3] & PMS_LBUTMASK); 1063 sp.sp_down = sp.sp_right ^ 1064 (psc->packet[3] & PMS_RBUTMASK); 1065 } else if (sc->flags & SYN_FLAG_HAS_UP_DOWN_BUTTONS && 1066 ((psc->packet[0] & PMS_RBUTMASK) ^ 1067 (psc->packet[3] & PMS_RBUTMASK))) { 1068 /* New up/down button. */ 1069 sp.sp_up = psc->packet[4] & SYN_1BUTMASK; 1070 sp.sp_down = psc->packet[5] & SYN_2BUTMASK; 1071 } else { 1072 sp.sp_up = 0; 1073 sp.sp_down = 0; 1074 } 1075 1076 new_buttons = 0; 1077 if(sc->flags & SYN_FLAG_HAS_ONE_BUTTON_CLICKPAD) { 1078 /* This is not correctly specified. Read this button press 1079 * from L/U bit. Emulate 3 buttons by checking the 1080 * coordinates of the click and returning the appropriate 1081 * button code. Outside the button region default to a 1082 * left click. 1083 */ 1084 u_char bstate = (psc->packet[0] ^ psc->packet[3]) 1085 & 0x01; 1086 if (sp.sp_y < synaptics_button_boundary) { 1087 if (sp.sp_x > synaptics_button3) { 1088 sp.sp_right = 1089 bstate ? PMS_RBUTMASK : 0; 1090 } else if (sp.sp_x > synaptics_button2) { 1091 sp.sp_middle = 1092 bstate ? PMS_MBUTMASK : 0; 1093 } else { 1094 sp.sp_left = bstate ? PMS_LBUTMASK : 0; 1095 } 1096 } else 1097 sp.sp_left = bstate ? 1 : 0; 1098 new_buttons = sp.sp_left | sp.sp_middle | sp.sp_right; 1099 if (new_buttons != sc->button_history) { 1100 if (sc->button_history == 0) 1101 sc->button_history = new_buttons; 1102 else if (new_buttons == 0) { 1103 sc->button_history = 0; 1104 /* ensure all buttons are cleared just in 1105 * case finger comes off in a different 1106 * region. 1107 */ 1108 sp.sp_left = 0; 1109 sp.sp_middle = 0; 1110 sp.sp_right = 0; 1111 } else { 1112 /* make sure we keep the same button even 1113 * if the finger moves to a different 1114 * region. This precludes chording 1115 * but, oh well. 1116 */ 1117 sp.sp_left = sc->button_history & PMS_LBUTMASK; 1118 sp.sp_middle = sc->button_history 1119 & PMS_MBUTMASK; 1120 sp.sp_right = sc->button_history & PMS_RBUTMASK; 1121 } 1122 } 1123 } else if (sc->flags & SYN_FLAG_HAS_MIDDLE_BUTTON) { 1124 /* Old style Middle Button. */ 1125 sp.sp_middle = (psc->packet[0] & PMS_LBUTMASK) ^ 1126 (psc->packet[3] & PMS_LBUTMASK); 1127 } else if (synaptics_up_down_emul != 1) { 1128 sp.sp_middle = 0; 1129 } 1130 1131 /* Overlay extended button state */ 1132 sp.sp_left |= sc->ext_left; 1133 sp.sp_right |= sc->ext_right; 1134 sp.sp_middle |= sc->ext_middle; 1135 sp.sp_up |= sc->ext_up; 1136 sp.sp_down |= sc->ext_down; 1137 1138 switch (synaptics_up_down_emul) { 1139 case 1: 1140 /* Do middle button emulation using up/down buttons */ 1141 sp.sp_middle = sp.sp_up | sp.sp_down; 1142 sp.sp_up = sp.sp_down = 0; 1143 break; 1144 case 3: 1145 /* Do left/right button emulation using up/down buttons */ 1146 sp.sp_left = sp.sp_left | sp.sp_up; 1147 sp.sp_right = sp.sp_right | sp.sp_down; 1148 sp.sp_up = sp.sp_down = 0; 1149 break; 1150 default: 1151 /* 1152 * Don't do any remapping... 1153 * Z-axis emulation is handled in pms_synaptics_process_packet 1154 */ 1155 break; 1156 } 1157 } 1158 1159 pms_synaptics_process_packet(psc, &sp); 1160 } 1161 1162 /* 1163 * Passthrough is used for e.g. TrackPoints and additional pointing 1164 * devices connected to a Synaptics touchpad. 1165 */ 1166 static void 1167 pms_synaptics_passthrough(struct pms_softc *psc) 1168 { 1169 int dx, dy, dz; 1170 int buttons, changed; 1171 int s; 1172 1173 buttons = ((psc->packet[1] & PMS_LBUTMASK) ? 0x20 : 0) | 1174 ((psc->packet[1] & PMS_MBUTMASK) ? 0x40 : 0) | 1175 ((psc->packet[1] & PMS_RBUTMASK) ? 0x80 : 0); 1176 1177 dx = psc->packet[4]; 1178 if (dx >= 128) 1179 dx -= 256; 1180 if (dx == -128) 1181 dx = -127; 1182 1183 dy = psc->packet[5]; 1184 if (dy >= 128) 1185 dy -= 256; 1186 if (dy == -128) 1187 dy = -127; 1188 1189 dz = 0; 1190 1191 changed = buttons ^ (psc->buttons & 0xe0); 1192 psc->buttons ^= changed; 1193 1194 if (dx || dy || dz || changed) { 1195 /* 1196 * If the middle button is held, interpret Y-axis 1197 * movement as scrolling. 1198 */ 1199 if (synaptics_aux_mid_button_scroll && 1200 dy && (psc->buttons & 0x2)) { 1201 dz = -dy; 1202 dx = dy = 0; 1203 } 1204 buttons = (psc->buttons & 0x1f) | ((psc->buttons >> 5) & 0x7); 1205 s = spltty(); 1206 wsmouse_input(psc->sc_wsmousedev, 1207 buttons, dx, dy, dz, 0, 1208 WSMOUSE_INPUT_DELTA); 1209 splx(s); 1210 } 1211 } 1212 1213 static void 1214 pms_synaptics_input(void *vsc, int data) 1215 { 1216 struct pms_softc *psc = vsc; 1217 struct timeval diff; 1218 1219 if (!psc->sc_enabled) { 1220 /* Interrupts are not expected. Discard the byte. */ 1221 return; 1222 } 1223 1224 getmicrouptime(&psc->current); 1225 1226 if (psc->inputstate > 0) { 1227 timersub(&psc->current, &psc->last, &diff); 1228 if (diff.tv_sec > 0 || diff.tv_usec >= 40000) { 1229 aprint_debug_dev(psc->sc_dev, 1230 "pms_synaptics_input: unusual delay (%ld.%06ld s), " 1231 "scheduling reset\n", 1232 (long)diff.tv_sec, (long)diff.tv_usec); 1233 printf("pms_synaptics_input: unusual delay (%ld.%06ld s), " 1234 "scheduling reset\n", 1235 (long)diff.tv_sec, (long)diff.tv_usec); 1236 psc->inputstate = 0; 1237 psc->sc_enabled = 0; 1238 wakeup(&psc->sc_enabled); 1239 return; 1240 } 1241 } 1242 psc->last = psc->current; 1243 1244 switch (psc->inputstate) { 1245 case -5: 1246 case -4: 1247 case -3: 1248 case -2: 1249 case -1: 1250 case 0: 1251 if ((data & 0xc8) != 0x80) { 1252 aprint_debug_dev(psc->sc_dev, 1253 "pms_synaptics_input: 0x%02x out of sync\n", data); 1254 /* use negative counts to limit resync phase */ 1255 psc->inputstate--; 1256 return; /* not in sync yet, discard input */ 1257 } 1258 psc->inputstate = 0; 1259 /*FALLTHROUGH*/ 1260 1261 case -6: 1262 case 3: 1263 if ((data & 8) == 8) { 1264 aprint_debug_dev(psc->sc_dev, 1265 "pms_synaptics_input: dropped in relative mode, reset\n"); 1266 psc->inputstate = 0; 1267 psc->sc_enabled = 0; 1268 wakeup(&psc->sc_enabled); 1269 return; 1270 } 1271 } 1272 1273 psc->packet[psc->inputstate++] = data & 0xff; 1274 if (psc->inputstate == 6) { 1275 /* 1276 * We have a complete packet. 1277 * Extract the pertinent details. 1278 */ 1279 psc->inputstate = 0; 1280 if ((psc->packet[0] & 0xfc) == 0x84 && 1281 (psc->packet[3] & 0xcc) == 0xc4) { 1282 /* W = SYNAPTICS_WIDTH_PASSTHROUGH, PS/2 passthrough */ 1283 pms_synaptics_passthrough(psc); 1284 } else { 1285 pms_synaptics_parse(psc); 1286 } 1287 } 1288 } 1289 1290 static inline int 1291 synaptics_finger_detect(struct synaptics_softc *sc, struct synaptics_packet *sp, 1292 int *palmp) 1293 { 1294 int fingers; 1295 1296 /* Assume no palm */ 1297 *palmp = 0; 1298 1299 /* 1300 * Apply some hysteresis when checking for a finger. 1301 * When the finger is first applied, we ignore it until the 1302 * pressure exceeds the 'high' threshold. The finger is considered 1303 * removed only when pressure falls beneath the 'low' threshold. 1304 */ 1305 if ((sc->prev_fingers == 0 && sp->sp_z > synaptics_finger_high) || 1306 (sc->prev_fingers != 0 && sp->sp_z > synaptics_finger_low)) 1307 fingers = 1; 1308 else 1309 fingers = 0; 1310 1311 /* 1312 * If the pad can't do palm detection, skip the rest. 1313 */ 1314 if (fingers == 0 || (sc->flags & SYN_FLAG_HAS_PALM_DETECT) == 0) 1315 return (fingers); 1316 1317 /* 1318 * Palm detection 1319 */ 1320 if (sp->sp_z > SYNAPTICS_FINGER_FLAT && 1321 sp->sp_w >= SYNAPTICS_WIDTH_PALM_MIN) 1322 *palmp = 1; 1323 1324 if (sc->prev_fingers == 0 && 1325 (sp->sp_z > SYNAPTICS_FINGER_FLAT || 1326 sp->sp_w >= SYNAPTICS_WIDTH_PALM_MIN)) { 1327 /* 1328 * Contact area or pressure is too great to be a finger. 1329 * Just ignore it for now. 1330 */ 1331 return (0); 1332 } 1333 1334 /* 1335 * Detect 2 and 3 fingers if supported, but only if multiple 1336 * fingers appear within the tap gesture time period. 1337 */ 1338 if (sc->flags & SYN_FLAG_HAS_MULTI_FINGER && 1339 SYN_TIME(sc, sc->gesture_start_packet, 1340 sp->sp_finger) < synaptics_gesture_length) { 1341 switch (sp->sp_w) { 1342 case SYNAPTICS_WIDTH_TWO_FINGERS: 1343 fingers = 2; 1344 break; 1345 1346 case SYNAPTICS_WIDTH_THREE_OR_MORE: 1347 fingers = 3; 1348 break; 1349 1350 default: 1351 /* 1352 * The width value can report spurious single-finger 1353 * events after a multi-finger event. 1354 */ 1355 fingers = sc->prev_fingers <= 1 ? 1 : sc->prev_fingers; 1356 break; 1357 } 1358 } 1359 1360 return (fingers); 1361 } 1362 1363 static inline void 1364 synaptics_gesture_detect(struct synaptics_softc *sc, 1365 struct synaptics_packet *sp, int fingers) 1366 { 1367 int gesture_len, gesture_buttons; 1368 int set_buttons; 1369 1370 gesture_len = SYN_TIME(sc, sc->gesture_start_packet, sp->sp_finger); 1371 gesture_buttons = sc->gesture_buttons; 1372 1373 if (fingers > 0 && (fingers == sc->prev_fingers)) { 1374 /* Finger is still present */ 1375 sc->gesture_move_x = abs(sc->gesture_start_x - sp->sp_x); 1376 sc->gesture_move_y = abs(sc->gesture_start_y - sp->sp_y); 1377 } else 1378 if (fingers && sc->prev_fingers == 0) { 1379 /* 1380 * Finger was just applied. 1381 * If the previous gesture was a single-click, set things 1382 * up to deal with a possible drag or double-click gesture. 1383 * Basically, if the finger is removed again within 1384 * 'synaptics_gesture_length' packets, this is treated 1385 * as a double-click. Otherwise we will emulate holding 1386 * the left button down whilst dragging the mouse. 1387 */ 1388 if (SYN_IS_SINGLE_TAP(sc->gesture_type)) 1389 sc->gesture_type |= SYN_GESTURE_DRAG; 1390 1391 sc->gesture_start_x = abs(sp->sp_x); 1392 sc->gesture_start_y = abs(sp->sp_y); 1393 sc->gesture_move_x = 0; 1394 sc->gesture_move_y = 0; 1395 sc->gesture_start_packet = sc->total_packets[0]; 1396 1397 #ifdef DIAGNOSTIC 1398 aprint_debug("Finger applied: gesture_start_x: %d gesture_start_y: %d\n", 1399 sc->gesture_start_x, sc->gesture_start_y); 1400 #endif 1401 } else 1402 if (fingers == 0 && sc->prev_fingers != 0) { 1403 /* 1404 * Finger was just removed. 1405 * Check if the contact time and finger movement were 1406 * small enough to qualify as a gesture. 1407 * Ignore finger movement if multiple fingers were 1408 * detected (the pad may report coordinates for any 1409 * of the fingers). 1410 */ 1411 1412 #ifdef DIAGNOSTIC 1413 aprint_debug("Finger removed: gesture_len: %d (%d)\n", 1414 gesture_len, synaptics_gesture_length); 1415 aprint_debug("gesture_move_x: %d (%d) sp_x: %d\n", 1416 sc->gesture_move_x, synaptics_gesture_move, abs(sp->sp_x)); 1417 aprint_debug("gesture_move_y: %d (%d) sp_y: %d\n", 1418 sc->gesture_move_y, synaptics_gesture_move, abs(sp->sp_y)); 1419 #endif 1420 1421 if (gesture_len < synaptics_gesture_length && 1422 ((sc->gesture_move_x < synaptics_gesture_move && 1423 sc->gesture_move_y < synaptics_gesture_move))) { 1424 /* 1425 * Looking good so far. 1426 */ 1427 if (SYN_IS_DRAG(sc->gesture_type)) { 1428 /* 1429 * Promote this gesture to double-click. 1430 */ 1431 sc->gesture_type |= SYN_GESTURE_DOUBLE; 1432 sc->gesture_type &= ~SYN_GESTURE_SINGLE; 1433 } else { 1434 /* 1435 * Single tap gesture. Set the tap length timer 1436 * and flag a single-click. 1437 */ 1438 sc->gesture_tap_packet = sc->total_packets[0]; 1439 sc->gesture_type |= SYN_GESTURE_SINGLE; 1440 1441 /* 1442 * The gesture can be modified depending on 1443 * the number of fingers detected. 1444 * 1445 * 1: Normal left button emulation. 1446 * 2: Either middle button or right button 1447 * depending on the value of the two_fingers 1448 * sysctl variable. 1449 * 3: Right button. 1450 */ 1451 switch (sc->prev_fingers) { 1452 case 2: 1453 if (synaptics_two_fingers_emul == 1) 1454 gesture_buttons |= PMS_RBUTMASK; 1455 else 1456 if (synaptics_two_fingers_emul == 2) 1457 gesture_buttons |= PMS_MBUTMASK; 1458 break; 1459 case 3: 1460 gesture_buttons |= PMS_RBUTMASK; 1461 break; 1462 default: 1463 gesture_buttons |= PMS_LBUTMASK; 1464 break; 1465 } 1466 } 1467 } 1468 1469 /* 1470 * Always clear drag state when the finger is removed. 1471 */ 1472 sc->gesture_type &= ~SYN_GESTURE_DRAG; 1473 } 1474 1475 if (sc->gesture_type == 0) { 1476 /* 1477 * There is no gesture in progress. 1478 * Clear emulated button state. 1479 */ 1480 sc->gesture_buttons = 0; 1481 return; 1482 } 1483 1484 /* 1485 * A gesture is in progress. 1486 */ 1487 set_buttons = 0; 1488 1489 if (SYN_IS_SINGLE_TAP(sc->gesture_type)) { 1490 /* 1491 * Single-click. 1492 * Activate the relevant button(s) until the 1493 * gesture tap timer has expired. 1494 */ 1495 if (SYN_TIME(sc, sc->gesture_tap_packet, sp->sp_finger) < 1496 synaptics_gesture_length) 1497 set_buttons = 1; 1498 else 1499 sc->gesture_type &= ~SYN_GESTURE_SINGLE; 1500 } else 1501 if (SYN_IS_DOUBLE_TAP(sc->gesture_type) && sc->prev_fingers == 0) { 1502 /* 1503 * Double-click. 1504 * Activate the relevant button(s) once. 1505 */ 1506 set_buttons = 1; 1507 sc->gesture_type &= ~SYN_GESTURE_DOUBLE; 1508 } 1509 1510 if (set_buttons || SYN_IS_DRAG(sc->gesture_type)) { 1511 /* 1512 * Single-click and drag. 1513 * Maintain button state until the finger is removed. 1514 */ 1515 sp->sp_left |= gesture_buttons & PMS_LBUTMASK; 1516 sp->sp_right |= gesture_buttons & PMS_RBUTMASK; 1517 sp->sp_middle |= gesture_buttons & PMS_MBUTMASK; 1518 } 1519 1520 sc->gesture_buttons = gesture_buttons; 1521 } 1522 1523 static inline int 1524 synaptics_filter_policy(struct synaptics_softc *sc, int finger, int *history, 1525 int value) 1526 { 1527 int a, b, rv, count; 1528 1529 count = sc->total_packets[finger]; 1530 1531 /* 1532 * Once we've accumulated at least SYN_HIST_SIZE values, combine 1533 * each new value with the previous two and return the average. 1534 * 1535 * This is necessary when the touchpad is operating in 80 packets 1536 * per second mode, as it performs little internal filtering on 1537 * reported values. 1538 * 1539 * Using a rolling average helps to filter out jitter caused by 1540 * tiny finger movements. 1541 */ 1542 if (sc->movement_history[finger] >= SYN_HIST_SIZE) { 1543 a = (history[(count + 0) % SYN_HIST_SIZE] + 1544 history[(count + 1) % SYN_HIST_SIZE]) / 2; 1545 1546 b = (value + history[(count + 0) % SYN_HIST_SIZE]) / 2; 1547 1548 rv = b - a; 1549 1550 /* 1551 * Don't report the movement if it's below a certain 1552 * threshold. 1553 */ 1554 if (abs(rv) < synaptics_movement_threshold) 1555 rv = 0; 1556 } else 1557 rv = 0; 1558 1559 /* 1560 * Add the new value to the history buffer. 1561 */ 1562 history[(count + 1) % SYN_HIST_SIZE] = value; 1563 1564 return (rv); 1565 } 1566 1567 /* Edge detection */ 1568 #define SYN_EDGE_TOP 1 1569 #define SYN_EDGE_BOTTOM 2 1570 #define SYN_EDGE_LEFT 4 1571 #define SYN_EDGE_RIGHT 8 1572 1573 static inline int 1574 synaptics_check_edge(int x, int y) 1575 { 1576 int rv = 0; 1577 1578 if (x < synaptics_edge_left) 1579 rv |= SYN_EDGE_LEFT; 1580 else 1581 if (x > synaptics_edge_right) 1582 rv |= SYN_EDGE_RIGHT; 1583 1584 if (y < synaptics_edge_bottom) 1585 rv |= SYN_EDGE_BOTTOM; 1586 else 1587 if (y > synaptics_edge_top) 1588 rv |= SYN_EDGE_TOP; 1589 1590 return (rv); 1591 } 1592 1593 static inline int 1594 synaptics_edge_motion(struct synaptics_softc *sc, int delta, int dir) 1595 { 1596 1597 /* 1598 * When edge motion is enabled, synaptics_edge_motion_delta is 1599 * combined with the current delta, together with the direction 1600 * in which to simulate the motion. The result is added to 1601 * the delta derived from finger movement. This provides a smooth 1602 * transition from finger movement to edge motion. 1603 */ 1604 delta = synaptics_edge_motion_delta + (dir * delta); 1605 if (delta < 0) 1606 return (0); 1607 if (delta > synaptics_edge_motion_delta) 1608 return (synaptics_edge_motion_delta); 1609 return (delta); 1610 } 1611 1612 static inline int 1613 synaptics_scale(int delta, int scale, int *remp) 1614 { 1615 int rv; 1616 1617 /* 1618 * Scale the raw delta in Synaptics coordinates (0-6143) into 1619 * something more reasonable by dividing the raw delta by a 1620 * scale factor. Any remainder from the previous scale result 1621 * is added to the current delta before scaling. 1622 * This prevents loss of resolution for very small/slow 1623 * movements of the finger. 1624 */ 1625 delta += *remp; 1626 rv = delta / scale; 1627 *remp = delta % scale; 1628 1629 return (rv); 1630 } 1631 1632 static inline void 1633 synaptics_movement(struct synaptics_softc *sc, struct synaptics_packet *sp, 1634 int finger, int scroll_emul, int *dxp, int *dyp, int *dzp) 1635 { 1636 int dx, dy, dz, edge; 1637 1638 dx = dy = dz = 0; 1639 1640 /* 1641 * Compute the next values of dx and dy and dz. If scroll_emul 1642 * is non-zero, take the dy and used it as use it as dz so we 1643 * can emulate a scroll wheel. 1644 */ 1645 if (scroll_emul == 0) { 1646 dx = synaptics_filter_policy(sc, finger, sc->history_x[finger], 1647 sp->sp_x); 1648 dy = synaptics_filter_policy(sc, finger, sc->history_y[finger], 1649 sp->sp_y); 1650 } else { 1651 dz = synaptics_filter_policy(sc, finger, sc->history_z[finger], 1652 sp->sp_y); 1653 dx = dy = 0; 1654 } 1655 1656 /* 1657 * If we're dealing with a drag gesture, and the finger moves to 1658 * the edge of the touchpad, apply edge motion emulation if it 1659 * is enabled. 1660 */ 1661 if (synaptics_edge_motion_delta && SYN_IS_DRAG(sc->gesture_type)) { 1662 edge = synaptics_check_edge(sp->sp_x, sp->sp_y); 1663 1664 if (edge & SYN_EDGE_LEFT) 1665 dx -= synaptics_edge_motion(sc, dx, 1); 1666 if (edge & SYN_EDGE_RIGHT) 1667 dx += synaptics_edge_motion(sc, dx, -1); 1668 if (edge & SYN_EDGE_BOTTOM) 1669 dy -= synaptics_edge_motion(sc, dy, 1); 1670 if (edge & SYN_EDGE_TOP) 1671 dy += synaptics_edge_motion(sc, dy, -1); 1672 } 1673 1674 /* 1675 * Apply scaling to the deltas 1676 */ 1677 dx = synaptics_scale(dx, synaptics_scale_x, &sc->rem_x[finger]); 1678 dy = synaptics_scale(dy, synaptics_scale_y, &sc->rem_y[finger]); 1679 dz = synaptics_scale(dz, synaptics_scale_z, &sc->rem_z[finger]); 1680 1681 /* 1682 * Clamp deltas to specified maximums. 1683 */ 1684 if (abs(dx) > synaptics_max_speed_x) 1685 dx = ((dx >= 0)? 1 : -1) * synaptics_max_speed_x; 1686 if (abs(dy) > synaptics_max_speed_y) 1687 dy = ((dy >= 0)? 1 : -1) * synaptics_max_speed_y; 1688 if (abs(dz) > synaptics_max_speed_z) 1689 dz = ((dz >= 0)? 1 : -1) * synaptics_max_speed_z; 1690 1691 *dxp = dx; 1692 *dyp = dy; 1693 *dzp = dz; 1694 1695 sc->movement_history[finger]++; 1696 } 1697 1698 static void 1699 pms_synaptics_process_packet(struct pms_softc *psc, struct synaptics_packet *sp) 1700 { 1701 struct synaptics_softc *sc = &psc->u.synaptics; 1702 int dx, dy, dz; 1703 int fingers, palm, buttons, changed; 1704 int s, z_emul; 1705 1706 /* 1707 * Do Z-axis emulation using up/down buttons if required. 1708 * Note that the pad will send a one second burst of packets 1709 * when an up/down button is pressed and held. At the moment 1710 * we don't deal with auto-repeat, so convert the burst into 1711 * a one-shot. 1712 */ 1713 dz = 0; 1714 if (synaptics_up_down_emul == 2) { 1715 if (sc->up_down == 0) { 1716 if (sp->sp_up && sp->sp_down) { 1717 sp->sp_middle = 1; 1718 } else if (sp->sp_up) { 1719 dz = -synaptics_up_down_motion_delta; 1720 } else if (sp->sp_down) { 1721 dz = synaptics_up_down_motion_delta; 1722 } 1723 } 1724 1725 sc->up_down = sp->sp_up | sp->sp_down; 1726 sp->sp_up = sp->sp_down = 0; 1727 } 1728 1729 /* 1730 * Determine whether or not a finger is on the pad. 1731 * On some pads, this will return the number of fingers 1732 * detected. 1733 */ 1734 fingers = synaptics_finger_detect(sc, sp, &palm); 1735 1736 /* 1737 * Do gesture processing only if we didn't detect a palm and 1738 * it is not the seondary finger. 1739 */ 1740 if ((sp->sp_finger == 0) && (palm == 0)) 1741 synaptics_gesture_detect(sc, sp, fingers); 1742 else 1743 sc->gesture_type = sc->gesture_buttons = 0; 1744 1745 /* 1746 * Determine what buttons to report 1747 */ 1748 buttons = (sp->sp_left ? 0x1 : 0) | 1749 (sp->sp_middle ? 0x2 : 0) | 1750 (sp->sp_right ? 0x4 : 0) | 1751 (sp->sp_up ? 0x8 : 0) | 1752 (sp->sp_down ? 0x10 : 0); 1753 changed = buttons ^ (psc->buttons & 0x1f); 1754 psc->buttons ^= changed; 1755 1756 sc->prev_fingers = fingers; 1757 sc->total_packets[sp->sp_finger]++; 1758 1759 /* 1760 * Do movement processing IFF we have a single finger and no palm or 1761 * a secondary finger and no palm. 1762 */ 1763 if (palm == 0 && synaptics_movement_enable) { 1764 if (fingers == 1) { 1765 z_emul = 0; 1766 1767 if ((sp->sp_w >= synaptics_fscroll_min) && 1768 (sp->sp_w <= synaptics_fscroll_max)) { 1769 z_emul = 1; 1770 sc->dz_hold = synaptics_dz_hold; 1771 } 1772 1773 if (sc->dz_hold > 0) { 1774 z_emul = 1; 1775 } 1776 1777 synaptics_movement(sc, sp, sp->sp_finger, 1778 z_emul, &dx, &dy, &dz); 1779 } else { 1780 /* 1781 * No valid finger. Therefore no movement. 1782 */ 1783 sc->movement_history[sp->sp_finger] = 0; 1784 sc->rem_x[sp->sp_finger] = sc->rem_y[sp->sp_finger] = 0; 1785 dx = dy = 0; 1786 } 1787 } else { 1788 /* 1789 * No valid finger. Therefore no movement. 1790 */ 1791 sc->movement_history[0] = 0; 1792 sc->rem_x[0] = sc->rem_y[0] = sc->rem_z[0] = 0; 1793 dx = dy = dz = 0; 1794 } 1795 1796 if (sc->dz_hold > 0) 1797 sc->dz_hold--; 1798 1799 /* 1800 * Pass the final results up to wsmouse_input() if necessary. 1801 */ 1802 if (dx || dy || dz || changed) { 1803 buttons = (psc->buttons & 0x1f) | ((psc->buttons >> 5) & 0x7); 1804 s = spltty(); 1805 wsmouse_input(psc->sc_wsmousedev, 1806 buttons, 1807 dx, dy, dz, 0, 1808 WSMOUSE_INPUT_DELTA); 1809 splx(s); 1810 } 1811 } 1812