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