1 /* $NetBSD: synaptics.c,v 1.84 2024/07/19 04:48:13 mlelstv 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.84 2024/07/19 04:48:13 mlelstv 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 signed short sp_sx; /* Unscaled absolute X/Y coordinates */ 83 signed short sp_sy; /* for secondary finger */ 84 u_char sp_sz; /* Z (pressure) */ 85 u_char sp_w; /* W (contact patch width) */ 86 u_char sp_primary; /* seen primary finger packet */ 87 u_char sp_secondary; /* seen secondary finger packet */ 88 u_char sp_finger_status; /* seen extended finger packet */ 89 u_char sp_finger_count; /* number of fingers seen */ 90 char sp_left; /* Left mouse button status */ 91 char sp_right; /* Right mouse button status */ 92 char sp_middle; /* Middle button status (possibly emulated) */ 93 char sp_up; /* Up button status */ 94 char sp_down; /* Down button status */ 95 }; 96 97 static void pms_synaptics_input(void *, int); 98 static void pms_synaptics_process_packet(struct pms_softc *, 99 struct synaptics_packet *); 100 static void pms_sysctl_synaptics(struct sysctllog **); 101 static int pms_sysctl_synaptics_verify(SYSCTLFN_ARGS); 102 103 /* Controlled by sysctl. */ 104 static int synaptics_up_down_emul = 3; 105 static int synaptics_up_down_motion_delta = 1; 106 static int synaptics_gesture_move = 200; 107 static int synaptics_gesture_length = 20; 108 static int synaptics_edge_left = SYNAPTICS_EDGE_LEFT; 109 static int synaptics_edge_right = SYNAPTICS_EDGE_RIGHT; 110 static int synaptics_edge_top = SYNAPTICS_EDGE_TOP; 111 static int synaptics_edge_bottom = SYNAPTICS_EDGE_BOTTOM; 112 static int synaptics_edge_motion_delta = 32; 113 static u_int synaptics_finger_high = SYNAPTICS_FINGER_LIGHT + 5; 114 static u_int synaptics_finger_low = SYNAPTICS_FINGER_LIGHT - 10; 115 static int synaptics_hscroll_pct = 0; 116 static int synaptics_vscroll_pct = 0; 117 static int synaptics_button_pct = 0; 118 static int synaptics_button_boundary = SYNAPTICS_EDGE_BOTTOM; 119 static int synaptics_button2; 120 static int synaptics_button3; 121 static int synaptics_two_fingers_emul = 0; 122 static int synaptics_scale_x = 8; 123 static int synaptics_scale_y = 8; 124 static int synaptics_scale_z = 32; 125 static int synaptics_max_speed_x = 32; 126 static int synaptics_max_speed_y = 32; 127 static int synaptics_max_speed_z = 2; 128 static int synaptics_movement_threshold = 4; 129 static int synaptics_movement_enable = 1; 130 static int synaptics_button_region_movement = 1; 131 static bool synaptics_aux_mid_button_scroll = TRUE; 132 static int synaptics_debug = 0; 133 134 #define DPRINTF(LEVEL, SC, FMT, ARGS...) do \ 135 { \ 136 if (synaptics_debug >= LEVEL) { \ 137 struct pms_softc *_dprintf_psc = \ 138 container_of((SC), struct pms_softc, u.synaptics); \ 139 device_printf(_dprintf_psc->sc_dev, FMT, ##ARGS); \ 140 } \ 141 } while (0) 142 143 /* Sysctl nodes. */ 144 static int synaptics_button_boundary_nodenum; 145 static int synaptics_button2_nodenum; 146 static int synaptics_button3_nodenum; 147 static int synaptics_up_down_emul_nodenum; 148 static int synaptics_up_down_motion_delta_nodenum; 149 static int synaptics_gesture_move_nodenum; 150 static int synaptics_gesture_length_nodenum; 151 static int synaptics_edge_left_nodenum; 152 static int synaptics_edge_right_nodenum; 153 static int synaptics_edge_top_nodenum; 154 static int synaptics_edge_bottom_nodenum; 155 static int synaptics_edge_motion_delta_nodenum; 156 static int synaptics_finger_high_nodenum; 157 static int synaptics_finger_low_nodenum; 158 static int synaptics_two_fingers_emul_nodenum; 159 static int synaptics_scale_x_nodenum; 160 static int synaptics_scale_y_nodenum; 161 static int synaptics_scale_z_nodenum; 162 static int synaptics_max_speed_x_nodenum; 163 static int synaptics_max_speed_y_nodenum; 164 static int synaptics_max_speed_z_nodenum; 165 static int synaptics_movement_threshold_nodenum; 166 static int synaptics_movement_enable_nodenum; 167 static int synaptics_button_region_movement_nodenum; 168 static int synaptics_aux_mid_button_scroll_nodenum; 169 static int synaptics_hscroll_pct_nodenum; 170 static int synaptics_vscroll_pct_nodenum; 171 static int synaptics_button_pct_nodenum; 172 173 /* 174 * copy of edges so we can recalculate edge limit if there is 175 * vertical scroll region 176 */ 177 static int synaptics_true_edge_right; 178 static int synaptics_true_edge_bottom; 179 180 /* 181 * invalid old values, recalculate everything 182 */ 183 static int synaptics_old_vscroll_pct = -1; 184 static int synaptics_old_hscroll_pct = -1; 185 static int synaptics_old_button_pct = -1; 186 static int synaptics_old_button_boundary = -1; 187 static int synaptics_old_edge_right = -1; 188 static int synaptics_old_edge_bottom = -1; 189 190 /* 191 * This holds the processed packet data, it is global because multiple 192 * packets from the trackpad may be processed when handling multiple 193 * fingers on the trackpad to gather all the data. 194 */ 195 static struct synaptics_packet packet; 196 197 static int 198 synaptics_poll_cmd(struct pms_softc *psc, ...) 199 { 200 u_char cmd[4]; 201 size_t i; 202 va_list ap; 203 204 va_start(ap, psc); 205 206 for (i = 0; i < __arraycount(cmd); i++) 207 if ((cmd[i] = (u_char)va_arg(ap, int)) == 0) 208 break; 209 va_end(ap); 210 211 int res = pckbport_poll_cmd(psc->sc_kbctag, psc->sc_kbcslot, cmd, i, 0, 212 NULL, 0); 213 if (res) 214 device_printf(psc->sc_dev, "command error %#x\n", cmd[0]); 215 return res; 216 } 217 218 static int 219 synaptics_poll_reset(struct pms_softc *psc) 220 { 221 u_char resp[2]; 222 int res; 223 224 u_char cmd[1] = { PMS_RESET }; 225 res = pckbport_poll_cmd(psc->sc_kbctag, psc->sc_kbcslot, cmd, 1, 2, 226 resp, 1); 227 DPRINTF(10, &psc->u.synaptics, "reset %d 0x%02x 0x%02x\n", 228 res, resp[0], resp[1]); 229 return res; 230 } 231 232 static int 233 synaptics_special_read(struct pms_softc *psc, u_char slice, u_char resp[3]) 234 { 235 u_char cmd[1] = { PMS_SEND_DEV_STATUS }; 236 int res = pms_sliced_command(psc->sc_kbctag, psc->sc_kbcslot, slice); 237 238 return res | pckbport_poll_cmd(psc->sc_kbctag, psc->sc_kbcslot, 239 cmd, 1, 3, resp, 0); 240 } 241 242 static int 243 synaptics_special_write(struct pms_softc *psc, u_char command, u_char arg) 244 { 245 int res = pms_sliced_command(psc->sc_kbctag, psc->sc_kbcslot, arg); 246 if (res) 247 return res; 248 249 u_char cmd[2]; 250 cmd[0] = PMS_SET_SAMPLE; 251 cmd[1] = command; 252 res = pckbport_poll_cmd(psc->sc_kbctag, psc->sc_kbcslot, 253 cmd, 2, 0, NULL, 0); 254 return res; 255 } 256 257 static int 258 synaptics_value(int pct, int low, int high) 259 { 260 return low + pct * (high - low) / 100UL; 261 } 262 263 static int 264 synaptics_percentage(int val, int low, int high) 265 { 266 return ((val - low) * 100UL + high - low - 1) / (high - low); 267 } 268 269 static void 270 pms_synaptics_set_boundaries(void) 271 { 272 if (synaptics_vscroll_pct != synaptics_old_vscroll_pct ) { 273 synaptics_edge_right = synaptics_value( 274 100 - synaptics_vscroll_pct, 275 synaptics_edge_left, 276 synaptics_true_edge_right); 277 synaptics_old_vscroll_pct = synaptics_vscroll_pct; 278 } 279 280 if (synaptics_edge_right != synaptics_old_edge_right) { 281 if (synaptics_edge_right >= synaptics_true_edge_right) { 282 synaptics_vscroll_pct = 0; 283 synaptics_edge_right = synaptics_true_edge_right; 284 } else { 285 synaptics_vscroll_pct = 100 - synaptics_percentage( 286 synaptics_edge_right, 287 synaptics_edge_left, 288 synaptics_true_edge_right); 289 } 290 synaptics_old_vscroll_pct = synaptics_vscroll_pct; 291 synaptics_old_edge_right = synaptics_edge_right; 292 } 293 294 if (synaptics_hscroll_pct != synaptics_old_hscroll_pct ) { 295 synaptics_edge_bottom = synaptics_value( 296 synaptics_hscroll_pct, 297 synaptics_true_edge_bottom, 298 synaptics_edge_top); 299 synaptics_old_hscroll_pct = synaptics_hscroll_pct; 300 } 301 302 if (synaptics_edge_bottom != synaptics_old_edge_bottom) { 303 if (synaptics_edge_bottom <= synaptics_true_edge_bottom) { 304 synaptics_hscroll_pct = 0; 305 synaptics_edge_bottom = synaptics_true_edge_bottom; 306 } else { 307 synaptics_hscroll_pct = synaptics_percentage( 308 synaptics_edge_bottom, 309 synaptics_true_edge_bottom, 310 synaptics_edge_top); 311 } 312 synaptics_old_hscroll_pct = synaptics_hscroll_pct; 313 synaptics_old_edge_bottom = synaptics_edge_bottom; 314 } 315 316 if (synaptics_button_pct != synaptics_old_button_pct) { 317 synaptics_button_boundary = synaptics_value( 318 synaptics_button_pct, 319 synaptics_edge_bottom, 320 synaptics_edge_top); 321 synaptics_old_button_pct = synaptics_button_pct; 322 } 323 324 if (synaptics_button_boundary != synaptics_old_button_boundary) { 325 if (synaptics_button_boundary <= synaptics_edge_bottom) { 326 synaptics_button_pct = 0; 327 synaptics_button_boundary = synaptics_edge_bottom; 328 } else if (synaptics_button_boundary >= synaptics_edge_top) { 329 synaptics_button_pct = 100; 330 synaptics_button_boundary = synaptics_edge_top; 331 } else { 332 synaptics_button_pct = synaptics_percentage( 333 synaptics_button_boundary, 334 synaptics_edge_bottom, 335 synaptics_edge_top); 336 } 337 synaptics_old_button_pct = synaptics_button_pct; 338 synaptics_old_button_boundary = synaptics_button_boundary; 339 } 340 341 synaptics_button2 = synaptics_edge_left + 342 (synaptics_edge_right - synaptics_edge_left) / 3; 343 synaptics_button3 = synaptics_edge_left + 344 2 * (synaptics_edge_right - synaptics_edge_left) / 3; 345 346 } 347 348 static void 349 pms_synaptics_probe_extended(struct pms_softc *psc) 350 { 351 struct synaptics_softc *sc = &psc->u.synaptics; 352 u_char resp[3]; 353 int res; 354 355 DPRINTF(10, sc, 356 "synaptics_probe: Capabilities 0x%04x.\n", sc->caps); 357 if (sc->caps & SYNAPTICS_CAP_PASSTHROUGH) 358 sc->flags |= SYN_FLAG_HAS_PASSTHROUGH; 359 360 if (sc->caps & SYNAPTICS_CAP_PALMDETECT) 361 sc->flags |= SYN_FLAG_HAS_PALM_DETECT; 362 363 if (sc->caps & SYNAPTICS_CAP_MULTIDETECT) 364 sc->flags |= SYN_FLAG_HAS_MULTI_FINGER; 365 366 if (sc->caps & SYNAPTICS_CAP_MULTIFINGERREPORT) 367 sc->flags |= SYN_FLAG_HAS_MULTI_FINGER_REPORT; 368 369 /* Ask about extra buttons to detect up/down. */ 370 if ((__SHIFTOUT(sc->caps, SYNAPTICS_CAP_EXTNUM) + 0x08) 371 >= SYNAPTICS_EXTENDED_QUERY) 372 { 373 res = synaptics_special_read(psc, SYNAPTICS_EXTENDED_QUERY, resp); 374 if (res == 0) { 375 sc->num_buttons = (resp[1] >> 4); 376 if (sc->num_buttons > 0) 377 sc->button_mask = sc->button_mask << 378 ((sc->num_buttons + 1) >> 1); 379 380 DPRINTF(10, sc, 381 "Extended Buttons: %d.\n", 382 sc->num_buttons); 383 384 DPRINTF(10, sc, "Extended " 385 "Capabilities: 0x%02x 0x%02x 0x%02x.\n", 386 resp[0], resp[1], resp[2]); 387 if (sc->num_buttons >= 2) { 388 /* Yes. */ 389 sc->flags |= SYN_FLAG_HAS_UP_DOWN_BUTTONS; 390 } 391 if (resp[0] & 0x1) { 392 /* Vertical scroll area */ 393 sc->flags |= SYN_FLAG_HAS_VERTICAL_SCROLL; 394 } 395 if (resp[0] & 0x2) { 396 /* Horizontal scroll area */ 397 sc->flags |= SYN_FLAG_HAS_HORIZONTAL_SCROLL; 398 } 399 if (resp[0] & 0x4) { 400 /* Extended W-Mode */ 401 sc->flags |= SYN_FLAG_HAS_EXTENDED_WMODE; 402 } 403 } 404 } 405 406 /* Ask about click pad */ 407 if ((__SHIFTOUT(sc->caps, SYNAPTICS_CAP_EXTNUM) + 0x08) >= 408 SYNAPTICS_CONTINUED_CAPABILITIES) 409 { 410 res = synaptics_special_read(psc, 411 SYNAPTICS_CONTINUED_CAPABILITIES, resp); 412 413 /* 414 * The following describes response for the 415 * SYNAPTICS_CONTINUED_CAPABILITIES query. 416 * 417 * byte mask name meaning 418 * ---- ---- ------- ------------ 419 * 0 0x01 adjustable threshold capacitive button sensitivity 420 * can be adjusted 421 * 0 0x02 report max query 0x0d gives max coord reported 422 * 0 0x04 clearpad sensor is ClearPad product 423 * 0 0x08 advanced gesture not particularly meaningful 424 * 0 0x10 clickpad bit 0 1-button ClickPad 425 * 0 0x60 multifinger mode identifies firmware finger counting 426 * (not reporting!) algorithm. 427 * Not particularly meaningful 428 * 0 0x80 covered pad W clipped to 14, 15 == pad mostly covered 429 * 1 0x01 clickpad bit 1 2-button ClickPad 430 * 1 0x02 deluxe LED controls touchpad support LED commands 431 * ala multimedia control bar 432 * 1 0x04 reduced filtering firmware does less filtering on 433 * position data, driver should watch 434 * for noise. 435 * 1 0x08 image sensor image sensor tracks 5 fingers, but only 436 * reports 2. 437 * 1 0x10 uniform clickpad whole clickpad moves instead of being 438 * hinged at the top. 439 * 1 0x20 report min query 0x0f gives min coord reported 440 */ 441 if (res == 0) { 442 uint val = SYN_CCAP_VALUE(resp); 443 444 DPRINTF(10, sc, "Continued " 445 "Capabilities 0x%02x 0x%02x 0x%02x.\n", 446 resp[0], resp[1], resp[2]); 447 switch (SYN_CCAP_CLICKPAD_TYPE(val)) { 448 case 0: /* not a clickpad */ 449 break; 450 case 1: 451 sc->flags |= SYN_FLAG_HAS_ONE_BUTTON_CLICKPAD; 452 break; 453 case 2: 454 sc->flags |= SYN_FLAG_HAS_TWO_BUTTON_CLICKPAD; 455 break; 456 case 3: /* reserved */ 457 default: 458 /* unreached */ 459 break; 460 } 461 462 if ((val & SYN_CCAP_HAS_ADV_GESTURE_MODE)) 463 sc->flags |= SYN_FLAG_HAS_ADV_GESTURE_MODE; 464 465 if ((val & SYN_CCAP_REPORT_MAX)) 466 sc->flags |= SYN_FLAG_HAS_MAX_REPORT; 467 468 if ((val & SYN_CCAP_REPORT_MIN)) 469 sc->flags |= SYN_FLAG_HAS_MIN_REPORT; 470 } 471 } 472 } 473 474 static const struct { 475 int bit; 476 const char *desc; 477 } syn_flags[] = { 478 { SYN_FLAG_HAS_EXTENDED_WMODE, "Extended W mode", }, 479 { SYN_FLAG_HAS_PASSTHROUGH, "Passthrough", }, 480 { SYN_FLAG_HAS_MIDDLE_BUTTON, "Middle button", }, 481 { SYN_FLAG_HAS_BUTTONS_4_5, "Buttons 4/5", }, 482 { SYN_FLAG_HAS_UP_DOWN_BUTTONS, "Up/down buttons", }, 483 { SYN_FLAG_HAS_PALM_DETECT, "Palm detect", }, 484 { SYN_FLAG_HAS_ONE_BUTTON_CLICKPAD, "One button click pad", }, 485 { SYN_FLAG_HAS_TWO_BUTTON_CLICKPAD, "Two button click pad", }, 486 { SYN_FLAG_HAS_VERTICAL_SCROLL, "Vertical scroll", }, 487 { SYN_FLAG_HAS_HORIZONTAL_SCROLL, "Horizontal scroll", }, 488 { SYN_FLAG_HAS_MULTI_FINGER_REPORT, "Multi-finger Report", }, 489 { SYN_FLAG_HAS_MULTI_FINGER, "Multi-finger", }, 490 { SYN_FLAG_HAS_MAX_REPORT, "Reports max", }, 491 { SYN_FLAG_HAS_MIN_REPORT, "Reports min", }, 492 }; 493 494 int 495 pms_synaptics_probe_init(void *vsc) 496 { 497 struct pms_softc *psc = vsc; 498 struct synaptics_softc *sc = &psc->u.synaptics; 499 u_char cmd[1], resp[3]; 500 int res, ver_minor, ver_major; 501 struct sysctllog *clog = NULL; 502 503 res = pms_sliced_command(psc->sc_kbctag, psc->sc_kbcslot, 504 SYNAPTICS_IDENTIFY_TOUCHPAD); 505 cmd[0] = PMS_SEND_DEV_STATUS; 506 res |= pckbport_poll_cmd(psc->sc_kbctag, psc->sc_kbcslot, cmd, 1, 3, 507 resp, 0); 508 if (res) { 509 aprint_debug_dev(psc->sc_dev, 510 "synaptics_probe: Identify Touchpad error.\n"); 511 /* 512 * Reset device in case the probe confused it. 513 */ 514 doreset: 515 (void)synaptics_poll_reset(psc); 516 return res; 517 } 518 519 if (resp[1] != SYNAPTICS_MAGIC_BYTE) { 520 aprint_debug_dev(psc->sc_dev, 521 "synaptics_probe: Not synaptics.\n"); 522 res = 1; 523 goto doreset; 524 } 525 526 sc->flags = 0; 527 sc->num_buttons = 0; 528 sc->button_mask = 0xff; 529 530 synaptics_true_edge_right = synaptics_edge_right; 531 synaptics_true_edge_bottom = synaptics_edge_bottom; 532 533 /* Check for minimum version and print a nice message. */ 534 ver_major = resp[2] & 0x0f; 535 ver_minor = resp[0]; 536 aprint_normal_dev(psc->sc_dev, "Synaptics touchpad version %d.%d\n", 537 ver_major, ver_minor); 538 if (ver_major * 10 + ver_minor < SYNAPTICS_MIN_VERSION) { 539 /* No capability query support. */ 540 sc->caps = 0; 541 goto done; 542 } 543 544 /* Query the hardware capabilities. */ 545 res = synaptics_special_read(psc, SYNAPTICS_READ_CAPABILITIES, resp); 546 if (res) { 547 /* Hmm, failed to get capabilities. */ 548 aprint_error_dev(psc->sc_dev, 549 "synaptics_probe: Failed to query capabilities.\n"); 550 goto doreset; 551 } 552 553 sc->caps = SYNAPTICS_CAP_VALUE(resp); 554 555 if (sc->caps & SYNAPTICS_CAP_MBUTTON) 556 sc->flags |= SYN_FLAG_HAS_MIDDLE_BUTTON; 557 558 if (sc->caps & SYNAPTICS_CAP_4BUTTON) 559 sc->flags |= SYN_FLAG_HAS_BUTTONS_4_5; 560 561 if (sc->caps & SYNAPTICS_CAP_EXTENDED) { 562 pms_synaptics_probe_extended(psc); 563 } 564 565 if (sc->flags) { 566 const char comma[] = ", "; 567 const char *sep = ""; 568 aprint_normal_dev(psc->sc_dev, ""); 569 for (size_t f = 0; f < __arraycount(syn_flags); f++) { 570 if (sc->flags & syn_flags[f].bit) { 571 aprint_normal("%s%s", sep, syn_flags[f].desc); 572 sep = comma; 573 } 574 } 575 aprint_normal("\n"); 576 } 577 578 if (sc->flags & SYN_FLAG_HAS_MAX_REPORT) { 579 res = synaptics_special_read(psc, SYNAPTICS_READ_MAX_COORDS, 580 resp); 581 if (res) { 582 aprint_error_dev(psc->sc_dev, 583 "synaptics_probe: Failed to query max coords.\n"); 584 } else { 585 synaptics_edge_right = (resp[0] << 5) + 586 ((resp[1] & 0x0f) << 1); 587 synaptics_edge_top = (resp[2] << 5) + 588 ((resp[1] & 0xf0) >> 3); 589 590 synaptics_true_edge_right = synaptics_edge_right; 591 592 /* 593 * If we have vertical scroll then steal 10% 594 * for that region. 595 */ 596 if (sc->flags & SYN_FLAG_HAS_VERTICAL_SCROLL) 597 synaptics_edge_right -= 598 synaptics_edge_right / 10; 599 600 aprint_normal_dev(psc->sc_dev, 601 "Probed max coordinates right: %d, top: %d\n", 602 synaptics_edge_right, synaptics_edge_top); 603 } 604 } 605 606 if (sc->flags & SYN_FLAG_HAS_MIN_REPORT) { 607 res = synaptics_special_read(psc, SYNAPTICS_READ_MIN_COORDS, 608 resp); 609 if (res) { 610 aprint_error_dev(psc->sc_dev, 611 "synaptics_probe: Failed to query min coords.\n"); 612 } else { 613 synaptics_edge_left = (resp[0] << 5) + 614 ((resp[1] & 0x0f) << 1); 615 synaptics_edge_bottom = (resp[2] << 5) + 616 ((resp[1] & 0xf0) >> 3); 617 618 synaptics_true_edge_bottom = synaptics_edge_bottom; 619 620 /* 621 * If we have horizontal scroll then steal 10% 622 * for that region. 623 */ 624 if (sc->flags & SYN_FLAG_HAS_HORIZONTAL_SCROLL) 625 synaptics_hscroll_pct = 10; 626 627 aprint_normal_dev(psc->sc_dev, 628 "Probed min coordinates left: %d, bottom: %d\n", 629 synaptics_edge_left, synaptics_edge_bottom); 630 } 631 } 632 633 done: 634 pms_synaptics_set_boundaries(); 635 636 pms_sysctl_synaptics(&clog); 637 pckbport_set_inputhandler(psc->sc_kbctag, psc->sc_kbcslot, 638 pms_synaptics_input, psc, device_xname(psc->sc_dev)); 639 640 return (0); 641 } 642 643 void 644 pms_synaptics_enable(void *vsc) 645 { 646 struct pms_softc *psc = vsc; 647 struct synaptics_softc *sc = &psc->u.synaptics; 648 u_char enable_modes; 649 int res, i; 650 651 if (sc->flags & SYN_FLAG_HAS_PASSTHROUGH) { 652 /* 653 * Extended capability probes can confuse the passthrough 654 * device; reset the touchpad now to cure that. 655 */ 656 res = synaptics_poll_reset(psc); 657 } 658 659 /* 660 * Enable Absolute mode with W (width) reporting, and set 661 * the packet rate to maximum (80 packets per second). Enable 662 * extended W mode if supported so we can report second finger 663 * position. 664 */ 665 enable_modes = 666 SYNAPTICS_MODE_ABSOLUTE | SYNAPTICS_MODE_W | SYNAPTICS_MODE_RATE; 667 668 if (sc->flags & SYN_FLAG_HAS_EXTENDED_WMODE) 669 enable_modes |= SYNAPTICS_MODE_EXTENDED_W; 670 671 /* 672 * Synaptics documentation says to disable device before 673 * setting mode. 674 */ 675 synaptics_poll_cmd(psc, PMS_DEV_DISABLE, 0); 676 /* a couple of set scales to clear out pending commands */ 677 for (i = 0; i < 2; i++) 678 synaptics_poll_cmd(psc, PMS_SET_SCALE11, 0); 679 680 res = synaptics_special_write(psc, SYNAPTICS_CMD_SET_MODE2, enable_modes); 681 if (res) 682 device_printf(psc->sc_dev, "set mode error\n"); 683 684 /* a couple of set scales to clear out pending commands */ 685 for (i = 0; i < 2; i++) 686 synaptics_poll_cmd(psc, PMS_SET_SCALE11, 0); 687 688 /* Set advanced gesture mode */ 689 if ((sc->flags & SYN_FLAG_HAS_EXTENDED_WMODE) || 690 (sc->flags & SYN_FLAG_HAS_ADV_GESTURE_MODE)) 691 synaptics_special_write(psc, SYNAPTICS_WRITE_DELUXE_3, 0x3); 692 693 /* Disable motion in the button region for clickpads */ 694 if(sc->flags & SYN_FLAG_HAS_ONE_BUTTON_CLICKPAD) 695 synaptics_button_region_movement = 0; 696 697 sc->up_down = 0; 698 sc->prev_fingers = 0; 699 sc->gesture_start_x = sc->gesture_start_y = 0; 700 sc->gesture_start_packet = 0; 701 sc->gesture_tap_packet = 0; 702 sc->gesture_type = 0; 703 sc->gesture_buttons = 0; 704 sc->total_packets = 0; 705 for (i = 0; i < SYN_MAX_FINGERS; i++) { 706 sc->rem_x[i] = sc->rem_y[i] = sc->rem_z[i] = 0; 707 } 708 sc->button_history = 0; 709 710 /* clear the packet decode structure */ 711 memset(&packet, 0, sizeof(packet)); 712 } 713 714 void 715 pms_synaptics_resume(void *vsc) 716 { 717 (void)synaptics_poll_reset(vsc); 718 } 719 720 static void 721 pms_sysctl_synaptics(struct sysctllog **clog) 722 { 723 int rc, root_num; 724 const struct sysctlnode *node; 725 726 if ((rc = sysctl_createv(clog, 0, NULL, &node, 727 CTLFLAG_PERMANENT, CTLTYPE_NODE, "synaptics", 728 SYSCTL_DESCR("Synaptics touchpad controls"), 729 NULL, 0, NULL, 0, CTL_HW, CTL_CREATE, CTL_EOL)) != 0) 730 goto err; 731 732 root_num = node->sysctl_num; 733 734 if ((rc = sysctl_createv(clog, 0, NULL, &node, 735 CTLFLAG_PERMANENT | CTLFLAG_READWRITE, 736 CTLTYPE_INT, "up_down_emulation", 737 SYSCTL_DESCR("Middle button/Z-axis emulation with up/down buttons"), 738 pms_sysctl_synaptics_verify, 0, 739 &synaptics_up_down_emul, 740 0, CTL_HW, root_num, CTL_CREATE, 741 CTL_EOL)) != 0) 742 goto err; 743 744 synaptics_up_down_emul_nodenum = node->sysctl_num; 745 746 if ((rc = sysctl_createv(clog, 0, NULL, &node, 747 CTLFLAG_PERMANENT | CTLFLAG_READWRITE, 748 CTLTYPE_INT, "up_down_motion_delta", 749 SYSCTL_DESCR("Up/down button Z-axis emulation rate"), 750 pms_sysctl_synaptics_verify, 0, 751 &synaptics_up_down_motion_delta, 752 0, CTL_HW, root_num, CTL_CREATE, 753 CTL_EOL)) != 0) 754 goto err; 755 756 synaptics_up_down_motion_delta_nodenum = node->sysctl_num; 757 758 if ((rc = sysctl_createv(clog, 0, NULL, &node, 759 CTLFLAG_PERMANENT | CTLFLAG_READWRITE, 760 CTLTYPE_INT, "gesture_move", 761 SYSCTL_DESCR("Movement greater than this between taps cancels gesture"), 762 pms_sysctl_synaptics_verify, 0, 763 &synaptics_gesture_move, 764 0, CTL_HW, root_num, CTL_CREATE, 765 CTL_EOL)) != 0) 766 goto err; 767 768 synaptics_gesture_move_nodenum = node->sysctl_num; 769 770 if ((rc = sysctl_createv(clog, 0, NULL, &node, 771 CTLFLAG_PERMANENT | CTLFLAG_READWRITE, 772 CTLTYPE_INT, "gesture_length", 773 SYSCTL_DESCR("Time period in which tap is recognised as a gesture"), 774 pms_sysctl_synaptics_verify, 0, 775 &synaptics_gesture_length, 776 0, CTL_HW, root_num, CTL_CREATE, 777 CTL_EOL)) != 0) 778 goto err; 779 780 synaptics_gesture_length_nodenum = node->sysctl_num; 781 782 if ((rc = sysctl_createv(clog, 0, NULL, &node, 783 CTLFLAG_PERMANENT | CTLFLAG_READWRITE, 784 CTLTYPE_INT, "edge_left", 785 SYSCTL_DESCR("Define left edge of touchpad"), 786 pms_sysctl_synaptics_verify, 0, 787 &synaptics_edge_left, 788 0, CTL_HW, root_num, CTL_CREATE, 789 CTL_EOL)) != 0) 790 goto err; 791 792 synaptics_edge_left_nodenum = node->sysctl_num; 793 794 if ((rc = sysctl_createv(clog, 0, NULL, &node, 795 CTLFLAG_PERMANENT | CTLFLAG_READWRITE, 796 CTLTYPE_INT, "edge_right", 797 SYSCTL_DESCR("Define right edge of touchpad"), 798 pms_sysctl_synaptics_verify, 0, 799 &synaptics_edge_right, 800 0, CTL_HW, root_num, CTL_CREATE, 801 CTL_EOL)) != 0) 802 goto err; 803 804 synaptics_edge_right_nodenum = node->sysctl_num; 805 806 if ((rc = sysctl_createv(clog, 0, NULL, &node, 807 CTLFLAG_PERMANENT | CTLFLAG_READWRITE, 808 CTLTYPE_INT, "edge_top", 809 SYSCTL_DESCR("Define top edge of touchpad"), 810 pms_sysctl_synaptics_verify, 0, 811 &synaptics_edge_top, 812 0, CTL_HW, root_num, CTL_CREATE, 813 CTL_EOL)) != 0) 814 goto err; 815 816 synaptics_edge_top_nodenum = node->sysctl_num; 817 818 if ((rc = sysctl_createv(clog, 0, NULL, &node, 819 CTLFLAG_PERMANENT | CTLFLAG_READWRITE, 820 CTLTYPE_INT, "edge_bottom", 821 SYSCTL_DESCR("Define bottom edge of touchpad"), 822 pms_sysctl_synaptics_verify, 0, 823 &synaptics_edge_bottom, 824 0, CTL_HW, root_num, CTL_CREATE, 825 CTL_EOL)) != 0) 826 goto err; 827 828 synaptics_edge_bottom_nodenum = node->sysctl_num; 829 830 if ((rc = sysctl_createv(clog, 0, NULL, &node, 831 CTLFLAG_PERMANENT | CTLFLAG_READWRITE, 832 CTLTYPE_INT, "edge_motion_delta", 833 SYSCTL_DESCR("Define edge motion rate"), 834 pms_sysctl_synaptics_verify, 0, 835 &synaptics_edge_motion_delta, 836 0, CTL_HW, root_num, CTL_CREATE, 837 CTL_EOL)) != 0) 838 goto err; 839 840 synaptics_edge_motion_delta_nodenum = node->sysctl_num; 841 842 if ((rc = sysctl_createv(clog, 0, NULL, &node, 843 CTLFLAG_PERMANENT | CTLFLAG_READWRITE, 844 CTLTYPE_INT, "finger_high", 845 SYSCTL_DESCR("Define finger applied pressure threshold"), 846 pms_sysctl_synaptics_verify, 0, 847 &synaptics_finger_high, 848 0, CTL_HW, root_num, CTL_CREATE, 849 CTL_EOL)) != 0) 850 goto err; 851 852 synaptics_finger_high_nodenum = node->sysctl_num; 853 854 if ((rc = sysctl_createv(clog, 0, NULL, &node, 855 CTLFLAG_PERMANENT | CTLFLAG_READWRITE, 856 CTLTYPE_INT, "finger_low", 857 SYSCTL_DESCR("Define finger removed pressure threshold"), 858 pms_sysctl_synaptics_verify, 0, 859 &synaptics_finger_low, 860 0, CTL_HW, root_num, CTL_CREATE, 861 CTL_EOL)) != 0) 862 goto err; 863 864 synaptics_finger_low_nodenum = node->sysctl_num; 865 866 if ((rc = sysctl_createv(clog, 0, NULL, &node, 867 CTLFLAG_PERMANENT | CTLFLAG_READWRITE, 868 CTLTYPE_INT, "two_fingers_emulation", 869 SYSCTL_DESCR("Map two fingers to middle button"), 870 pms_sysctl_synaptics_verify, 0, 871 &synaptics_two_fingers_emul, 872 0, CTL_HW, root_num, CTL_CREATE, 873 CTL_EOL)) != 0) 874 goto err; 875 876 synaptics_two_fingers_emul_nodenum = node->sysctl_num; 877 878 if ((rc = sysctl_createv(clog, 0, NULL, &node, 879 CTLFLAG_PERMANENT | CTLFLAG_READWRITE, 880 CTLTYPE_INT, "scale_x", 881 SYSCTL_DESCR("Horizontal movement scale factor"), 882 pms_sysctl_synaptics_verify, 0, 883 &synaptics_scale_x, 884 0, CTL_HW, root_num, CTL_CREATE, 885 CTL_EOL)) != 0) 886 goto err; 887 888 synaptics_scale_x_nodenum = node->sysctl_num; 889 890 if ((rc = sysctl_createv(clog, 0, NULL, &node, 891 CTLFLAG_PERMANENT | CTLFLAG_READWRITE, 892 CTLTYPE_INT, "scale_y", 893 SYSCTL_DESCR("Vertical movement scale factor"), 894 pms_sysctl_synaptics_verify, 0, 895 &synaptics_scale_y, 896 0, CTL_HW, root_num, CTL_CREATE, 897 CTL_EOL)) != 0) 898 goto err; 899 900 synaptics_scale_y_nodenum = node->sysctl_num; 901 902 if ((rc = sysctl_createv(clog, 0, NULL, &node, 903 CTLFLAG_PERMANENT | CTLFLAG_READWRITE, 904 CTLTYPE_INT, "scale_z", 905 SYSCTL_DESCR("Sroll wheel emulation scale factor"), 906 pms_sysctl_synaptics_verify, 0, 907 &synaptics_scale_z, 908 0, CTL_HW, root_num, CTL_CREATE, 909 CTL_EOL)) != 0) 910 goto err; 911 912 synaptics_scale_z_nodenum = node->sysctl_num; 913 914 if ((rc = sysctl_createv(clog, 0, NULL, &node, 915 CTLFLAG_PERMANENT | CTLFLAG_READWRITE, 916 CTLTYPE_INT, "max_speed_x", 917 SYSCTL_DESCR("Horizontal movement maximum speed"), 918 pms_sysctl_synaptics_verify, 0, 919 &synaptics_max_speed_x, 920 0, CTL_HW, root_num, CTL_CREATE, 921 CTL_EOL)) != 0) 922 goto err; 923 924 synaptics_max_speed_x_nodenum = node->sysctl_num; 925 926 if ((rc = sysctl_createv(clog, 0, NULL, &node, 927 CTLFLAG_PERMANENT | CTLFLAG_READWRITE, 928 CTLTYPE_INT, "max_speed_y", 929 SYSCTL_DESCR("Vertical movement maximum speed"), 930 pms_sysctl_synaptics_verify, 0, 931 &synaptics_max_speed_y, 932 0, CTL_HW, root_num, CTL_CREATE, 933 CTL_EOL)) != 0) 934 goto err; 935 936 synaptics_max_speed_y_nodenum = node->sysctl_num; 937 938 if ((rc = sysctl_createv(clog, 0, NULL, &node, 939 CTLFLAG_PERMANENT | CTLFLAG_READWRITE, 940 CTLTYPE_INT, "max_speed_z", 941 SYSCTL_DESCR("Scroll wheel emulation maximum speed"), 942 pms_sysctl_synaptics_verify, 0, 943 &synaptics_max_speed_z, 944 0, CTL_HW, root_num, CTL_CREATE, 945 CTL_EOL)) != 0) 946 goto err; 947 948 synaptics_max_speed_z_nodenum = node->sysctl_num; 949 950 if ((rc = sysctl_createv(clog, 0, NULL, &node, 951 CTLFLAG_PERMANENT | CTLFLAG_READWRITE, 952 CTLTYPE_INT, "movement_threshold", 953 SYSCTL_DESCR("Minimum reported movement threshold"), 954 pms_sysctl_synaptics_verify, 0, 955 &synaptics_movement_threshold, 956 0, CTL_HW, root_num, CTL_CREATE, 957 CTL_EOL)) != 0) 958 goto err; 959 960 synaptics_movement_threshold_nodenum = node->sysctl_num; 961 962 if ((rc = sysctl_createv(clog, 0, NULL, &node, 963 CTLFLAG_PERMANENT | CTLFLAG_READWRITE, 964 CTLTYPE_INT, "movement_enable", 965 SYSCTL_DESCR("Enable movement reporting"), 966 pms_sysctl_synaptics_verify, 0, 967 &synaptics_movement_enable, 968 0, CTL_HW, root_num, CTL_CREATE, 969 CTL_EOL)) != 0) 970 goto err; 971 972 synaptics_movement_enable_nodenum = node->sysctl_num; 973 974 if ((rc = sysctl_createv(clog, 0, NULL, &node, 975 CTLFLAG_PERMANENT | CTLFLAG_READWRITE, 976 CTLTYPE_INT, "button_region_movement_enable", 977 SYSCTL_DESCR("Enable movement within clickpad button region"), 978 pms_sysctl_synaptics_verify, 0, 979 &synaptics_button_region_movement, 980 0, CTL_HW, root_num, CTL_CREATE, 981 CTL_EOL)) != 0) 982 goto err; 983 984 synaptics_button_region_movement_nodenum = node->sysctl_num; 985 986 if ((rc = sysctl_createv(clog, 0, NULL, &node, 987 CTLFLAG_PERMANENT | CTLFLAG_READWRITE, 988 CTLTYPE_INT, "button_boundary", 989 SYSCTL_DESCR("Top edge of button area"), 990 pms_sysctl_synaptics_verify, 0, 991 &synaptics_button_boundary, 992 0, CTL_HW, root_num, CTL_CREATE, 993 CTL_EOL)) != 0) 994 goto err; 995 996 synaptics_button_boundary_nodenum = node->sysctl_num; 997 998 if ((rc = sysctl_createv(clog, 0, NULL, &node, 999 CTLFLAG_PERMANENT | CTLFLAG_READWRITE, 1000 CTLTYPE_INT, "button2_edge", 1001 SYSCTL_DESCR("Left edge of button 2 region"), 1002 pms_sysctl_synaptics_verify, 0, 1003 &synaptics_button2, 1004 0, CTL_HW, root_num, CTL_CREATE, 1005 CTL_EOL)) != 0) 1006 goto err; 1007 1008 synaptics_button2_nodenum = node->sysctl_num; 1009 1010 if ((rc = sysctl_createv(clog, 0, NULL, &node, 1011 CTLFLAG_PERMANENT | CTLFLAG_READWRITE, 1012 CTLTYPE_INT, "button3_edge", 1013 SYSCTL_DESCR("Left edge of button 3 region"), 1014 pms_sysctl_synaptics_verify, 0, 1015 &synaptics_button3, 1016 0, CTL_HW, root_num, CTL_CREATE, 1017 CTL_EOL)) != 0) 1018 goto err; 1019 1020 synaptics_button3_nodenum = node->sysctl_num; 1021 1022 if ((rc = sysctl_createv(clog, 0, NULL, &node, 1023 CTLFLAG_PERMANENT | CTLFLAG_READWRITE, 1024 CTLTYPE_BOOL, "aux_mid_button_scroll", 1025 SYSCTL_DESCR("Interpret Y-Axis movement with the middle button held as scrolling on the passthrough device (e.g. TrackPoint)"), 1026 pms_sysctl_synaptics_verify, 0, 1027 &synaptics_aux_mid_button_scroll, 1028 0, CTL_HW, root_num, CTL_CREATE, 1029 CTL_EOL)) != 0) 1030 goto err; 1031 1032 synaptics_aux_mid_button_scroll_nodenum = node->sysctl_num; 1033 1034 if ((rc = sysctl_createv(clog, 0, NULL, &node, 1035 CTLFLAG_PERMANENT | CTLFLAG_READWRITE, 1036 CTLTYPE_INT, "vert_scroll_percent", 1037 SYSCTL_DESCR("Percent of trackpad width to reserve for vertical scroll region"), 1038 pms_sysctl_synaptics_verify, 0, 1039 &synaptics_vscroll_pct, 1040 0, CTL_HW, root_num, CTL_CREATE, 1041 CTL_EOL)) != 0) 1042 goto err; 1043 1044 synaptics_vscroll_pct_nodenum = node->sysctl_num; 1045 1046 if ((rc = sysctl_createv(clog, 0, NULL, &node, 1047 CTLFLAG_PERMANENT | CTLFLAG_READWRITE, 1048 CTLTYPE_INT, "horizontal_scroll_percent", 1049 SYSCTL_DESCR("Percent of trackpad height to reserve for scroll region"), 1050 pms_sysctl_synaptics_verify, 0, 1051 &synaptics_hscroll_pct, 1052 0, CTL_HW, root_num, CTL_CREATE, 1053 CTL_EOL)) != 0) 1054 goto err; 1055 1056 synaptics_hscroll_pct_nodenum = node->sysctl_num; 1057 1058 if ((rc = sysctl_createv(clog, 0, NULL, &node, 1059 CTLFLAG_PERMANENT | CTLFLAG_READWRITE, 1060 CTLTYPE_INT, "button_region_percent", 1061 SYSCTL_DESCR("Percent of trackpad height to reserve for button region"), 1062 pms_sysctl_synaptics_verify, 0, 1063 &synaptics_button_pct, 1064 0, CTL_HW, root_num, CTL_CREATE, 1065 CTL_EOL)) != 0) 1066 goto err; 1067 1068 synaptics_button_pct_nodenum = node->sysctl_num; 1069 1070 if ((rc = sysctl_createv(clog, 0, NULL, &node, 1071 CTLFLAG_PERMANENT | CTLFLAG_READWRITE, 1072 CTLTYPE_INT, "debug", 1073 SYSCTL_DESCR("Enable debug output"), 1074 NULL, 0, 1075 &synaptics_debug, 1076 0, CTL_HW, root_num, CTL_CREATE, 1077 CTL_EOL)) != 0) 1078 goto err; 1079 1080 return; 1081 1082 err: 1083 aprint_error("%s: sysctl_createv failed (rc = %d)\n", __func__, rc); 1084 } 1085 1086 static int 1087 pms_sysctl_synaptics_verify(SYSCTLFN_ARGS) 1088 { 1089 int error, t; 1090 struct sysctlnode node; 1091 1092 node = *rnode; 1093 t = *(int *)rnode->sysctl_data; 1094 node.sysctl_data = &t; 1095 error = sysctl_lookup(SYSCTLFN_CALL(&node)); 1096 if (error || newp == NULL) 1097 return error; 1098 1099 /* Sanity check the params. */ 1100 if (node.sysctl_num == synaptics_up_down_emul_nodenum) { 1101 if (t < 0 || t > 3) 1102 return (EINVAL); 1103 } else 1104 if (node.sysctl_num == synaptics_two_fingers_emul_nodenum) { 1105 if (t < 0 || t > 2) 1106 return (EINVAL); 1107 } else 1108 if (node.sysctl_num == synaptics_gesture_length_nodenum || 1109 node.sysctl_num == synaptics_edge_motion_delta_nodenum || 1110 node.sysctl_num == synaptics_up_down_motion_delta_nodenum || 1111 node.sysctl_num == synaptics_max_speed_x_nodenum || 1112 node.sysctl_num == synaptics_max_speed_y_nodenum || 1113 node.sysctl_num == synaptics_max_speed_z_nodenum) { 1114 if (t < 0) 1115 return (EINVAL); 1116 } else 1117 if (node.sysctl_num == synaptics_edge_left_nodenum || 1118 node.sysctl_num == synaptics_edge_bottom_nodenum) { 1119 if (t < 0 || t > (SYNAPTICS_EDGE_MAX / 2)) 1120 return (EINVAL); 1121 } else 1122 if (node.sysctl_num == synaptics_edge_right_nodenum || 1123 node.sysctl_num == synaptics_edge_top_nodenum) { 1124 if (t < (SYNAPTICS_EDGE_MAX / 2)) 1125 return (EINVAL); 1126 } else 1127 if (node.sysctl_num == synaptics_scale_x_nodenum || 1128 node.sysctl_num == synaptics_scale_y_nodenum || 1129 node.sysctl_num == synaptics_scale_z_nodenum) { 1130 if (t < 1 || t > (SYNAPTICS_EDGE_MAX / 4)) 1131 return (EINVAL); 1132 } else 1133 if (node.sysctl_num == synaptics_finger_high_nodenum) { 1134 if (t < 0 || t > SYNAPTICS_FINGER_PALM || 1135 t < synaptics_finger_low) 1136 return (EINVAL); 1137 } else 1138 if (node.sysctl_num == synaptics_finger_low_nodenum) { 1139 if (t < 0 || t > SYNAPTICS_FINGER_PALM || 1140 t > synaptics_finger_high) 1141 return (EINVAL); 1142 } else 1143 if (node.sysctl_num == synaptics_gesture_move_nodenum || 1144 node.sysctl_num == synaptics_movement_threshold_nodenum) { 1145 if (t < 0 || t > (SYNAPTICS_EDGE_MAX / 4)) 1146 return (EINVAL); 1147 } else 1148 if (node.sysctl_num == synaptics_button_boundary_nodenum) { 1149 if (t < 0 || t < synaptics_edge_bottom || 1150 t > synaptics_edge_top) 1151 return (EINVAL); 1152 } else 1153 if (node.sysctl_num == synaptics_button2_nodenum || 1154 node.sysctl_num == synaptics_button3_nodenum) { 1155 if (t < synaptics_edge_left || t > synaptics_edge_right) 1156 return (EINVAL); 1157 } else 1158 if (node.sysctl_num == synaptics_movement_enable_nodenum) { 1159 if (t < 0 || t > 1) 1160 return (EINVAL); 1161 } else 1162 if (node.sysctl_num == synaptics_button_region_movement_nodenum) { 1163 if (t < 0 || t > 1) 1164 return (EINVAL); 1165 } else 1166 if (node.sysctl_num == synaptics_aux_mid_button_scroll_nodenum) { 1167 if (t < 0 || t > 1) 1168 return (EINVAL); 1169 } else 1170 if (node.sysctl_num == synaptics_vscroll_pct_nodenum) { 1171 if (t < 0 || t > 100) 1172 return (EINVAL); 1173 } else 1174 if (node.sysctl_num == synaptics_hscroll_pct_nodenum) { 1175 if (t < 0 || t > 100) 1176 return (EINVAL); 1177 } else 1178 if (node.sysctl_num == synaptics_button_pct_nodenum) { 1179 if (t < 0 || t > 100) 1180 return (EINVAL); 1181 } else 1182 return (EINVAL); 1183 1184 *(int *)rnode->sysctl_data = t; 1185 1186 pms_synaptics_set_boundaries(); 1187 1188 return (0); 1189 } 1190 1191 /* 1192 * Extract the number of fingers from the current packet and return 1193 * it to the caller. 1194 */ 1195 static unsigned 1196 pms_synaptics_get_fingers(struct pms_softc *psc, u_char w, short z) 1197 { 1198 struct synaptics_softc *sc = &psc->u.synaptics; 1199 unsigned short ew_mode; 1200 unsigned fingers; 1201 1202 fingers = 0; 1203 1204 1205 /* 1206 * If w is zero and z says no fingers then return 1207 * no fingers, w == can also mean 2 fingers... confusing. 1208 */ 1209 if (w == 0 && z == SYNAPTICS_FINGER_NONE) 1210 return 0; 1211 1212 if ((sc->flags & SYN_FLAG_HAS_EXTENDED_WMODE) && 1213 (w == SYNAPTICS_WIDTH_EXTENDED_W)) { 1214 ew_mode = psc->packet[5] >> 4; 1215 switch (ew_mode) 1216 { 1217 case SYNAPTICS_EW_WHEEL: 1218 break; 1219 1220 case SYNAPTICS_EW_SECONDARY_FINGER: 1221 /* to get here we must have 2 fingers at least */ 1222 fingers = 2; 1223 break; 1224 1225 case SYNAPTICS_EW_FINGER_STATUS: 1226 fingers = psc->packet[1] & 0x0f; 1227 break; 1228 1229 default: 1230 device_printf(psc->sc_dev, 1231 "invalid extended w mode %d\n", 1232 ew_mode); 1233 return 0; /* pretend there are no fingers */ 1234 } 1235 } else { 1236 1237 fingers = 1; 1238 1239 /* 1240 * If SYN_FLAG_HAS_MULTI_FINGER is set then check 1241 * sp_w is below SYNAPTICS_WIDTH_FINGER_MIN, if it is 1242 * then this will be the finger count. 1243 * 1244 * There are a couple of "special" values otherwise 1245 * just punt with one finger, if this really is a palm 1246 * then it will be caught later. 1247 */ 1248 if (sc->flags & (SYN_FLAG_HAS_MULTI_FINGER | SYN_FLAG_HAS_MULTI_FINGER_REPORT)) { 1249 if (w == SYNAPTICS_WIDTH_TWO_FINGERS) 1250 fingers = 2; 1251 else if (w == SYNAPTICS_WIDTH_THREE_OR_MORE) 1252 fingers = 3; 1253 } 1254 1255 } 1256 1257 return fingers; 1258 } 1259 1260 /* Masks for the first byte of a packet */ 1261 #define PMS_LBUTMASK 0x01 1262 #define PMS_RBUTMASK 0x02 1263 #define PMS_MBUTMASK 0x04 1264 1265 static void 1266 pms_synaptics_parse(struct pms_softc *psc) 1267 { 1268 struct synaptics_softc *sc = &psc->u.synaptics; 1269 struct synaptics_packet nsp; 1270 char new_buttons, ew_mode; 1271 uint8_t btn_mask, packet4, packet5; 1272 unsigned v, primary_finger, secondary_finger; 1273 int ext_left = -1, ext_right = -1, ext_middle = -1, 1274 ext_up = -1, ext_down = -1; 1275 1276 sc->total_packets++; 1277 1278 memcpy(&nsp, &packet, sizeof(packet)); 1279 1280 /* Width of finger */ 1281 nsp.sp_w = ((psc->packet[0] & 0x30) >> 2) 1282 + ((psc->packet[0] & 0x04) >> 1) 1283 + ((psc->packet[3] & 0x04) >> 2); 1284 1285 v = 0; 1286 primary_finger = 0; 1287 secondary_finger = 0; 1288 if ((sc->flags & SYN_FLAG_HAS_EXTENDED_WMODE) && 1289 (nsp.sp_w == SYNAPTICS_WIDTH_EXTENDED_W)) { 1290 ew_mode = psc->packet[5] >> 4; 1291 switch (ew_mode) 1292 { 1293 case SYNAPTICS_EW_WHEEL: 1294 /* scroll wheel report, ignore for now */ 1295 DPRINTF(10, sc, "mouse wheel packet\n"); 1296 return; 1297 1298 case SYNAPTICS_EW_SECONDARY_FINGER: 1299 /* parse the second finger report */ 1300 1301 nsp.sp_secondary = 1; 1302 1303 nsp.sp_sx = ((psc->packet[1] & 0xfe) << 1) 1304 + ((psc->packet[4] & 0x0f) << 9); 1305 nsp.sp_sy = ((psc->packet[2] & 0xfe) << 1) 1306 + ((psc->packet[4] & 0xf0) << 5); 1307 nsp.sp_sz = (psc->packet[3] & 0x30) 1308 + ((psc->packet[5] & 0x0e) << 1); 1309 1310 /* 1311 * Check if the x and y are non-zero that they 1312 * are within the bounds of the trackpad 1313 * otherwise ignore the packet. 1314 */ 1315 if (((nsp.sp_sx != 0) && 1316 ((nsp.sp_sx < synaptics_edge_left) || 1317 (nsp.sp_sx > synaptics_edge_right))) || 1318 ((nsp.sp_sy != 0) && 1319 ((nsp.sp_sy < synaptics_edge_bottom) || 1320 (nsp.sp_sy > synaptics_edge_top)))) { 1321 sc->gesture_type = 0; 1322 sc->gesture_buttons = 0; 1323 sc->total_packets--; 1324 DPRINTF(20, sc, 1325 "synaptics_parse: dropping out of bounds " 1326 "packet sp_sx %d sp_sy %d\n", 1327 nsp.sp_sx, nsp.sp_sy); 1328 return; 1329 } 1330 1331 /* work out the virtual finger width */ 1332 v = 8 + (psc->packet[1] & 0x01) + 1333 ((psc->packet[2] & 0x01) << 1) + 1334 ((psc->packet[5] & 0x01) << 2); 1335 1336 /* keep same buttons down as primary */ 1337 nsp.sp_left = sc->button_history & PMS_LBUTMASK; 1338 nsp.sp_middle = sc->button_history & PMS_MBUTMASK; 1339 nsp.sp_right = sc->button_history & PMS_RBUTMASK; 1340 break; 1341 1342 case SYNAPTICS_EW_FINGER_STATUS: 1343 /* This works but what is it good for? 1344 * it gives us an index of the primary/secondary 1345 * fingers but no other packets pass this 1346 * index. 1347 * 1348 * XXX Park this, possibly handle a finger 1349 * XXX change if indexes change. 1350 */ 1351 primary_finger = psc->packet[2]; 1352 secondary_finger = psc->packet[4]; 1353 nsp.sp_finger_status = 1; 1354 nsp.sp_finger_count = pms_synaptics_get_fingers(psc, 1355 nsp.sp_w, nsp.sp_z); 1356 goto skip_position; 1357 1358 default: 1359 device_printf(psc->sc_dev, 1360 "invalid extended w mode %d\n", 1361 ew_mode); 1362 return; 1363 } 1364 } else { 1365 nsp.sp_primary = 1; 1366 1367 /* 1368 * If the trackpad has external buttons and one of 1369 * those buttons is pressed then the lower bits of 1370 * x and y are "stolen" for button status. We can tell 1371 * this has happened by doing an xor of the two right 1372 * button status bits residing in byte 0 and 3, if the 1373 * result is non-zero then there is an external button 1374 * report and the position bytes need to be masked. 1375 */ 1376 btn_mask = 0xff; 1377 if ((sc->num_buttons > 0) && 1378 ((psc->packet[0] & PMS_RBUTMASK) ^ 1379 (psc->packet[3] & PMS_RBUTMASK))) { 1380 btn_mask = sc->button_mask; 1381 } 1382 1383 packet4 = psc->packet[4] & btn_mask; 1384 packet5 = psc->packet[5] & btn_mask; 1385 1386 /* 1387 * If SYN_FLAG_HAS_MULTI_FINGER is set then check 1388 * sp_w is below SYNAPTICS_WIDTH_FINGER_MIN, if it is 1389 * then this will be the finger count. 1390 * 1391 * There are a couple of "special" values otherwise 1392 * just punt with one finger, if this really is a palm 1393 * then it will be caught later. 1394 */ 1395 if ((sc->flags & SYN_FLAG_HAS_MULTI_FINGER) && 1396 ((nsp.sp_w == SYNAPTICS_WIDTH_TWO_FINGERS) || 1397 (nsp.sp_w == SYNAPTICS_WIDTH_THREE_OR_MORE))) { 1398 /* 1399 * To make life interesting if there are 1400 * two or more fingers on the touchpad then 1401 * the coordinate reporting changes and an extra 1402 * "virtual" finger width is reported. 1403 */ 1404 nsp.sp_x = (packet4 & 0xfc) + 1405 ((packet4 & 0x02) << 1) + 1406 ((psc->packet[1] & 0x0f) << 8) + 1407 ((psc->packet[3] & 0x10) << 8); 1408 1409 nsp.sp_y = (packet5 & 0xfc) + 1410 ((packet5 & 0x02) << 1) + 1411 ((psc->packet[1] & 0xf0) << 4) + 1412 ((psc->packet[3] & 0x20) << 7); 1413 1414 /* Pressure */ 1415 nsp.sp_z = psc->packet[2] & 0xfe; 1416 1417 /* derive the virtual finger width */ 1418 v = 8 + ((packet4 & 0x02) >> 1) + 1419 (packet5 & 0x02) + 1420 ((psc->packet[2] & 0x01) << 2); 1421 1422 } else { 1423 /* Absolute X/Y coordinates of finger */ 1424 nsp.sp_x = packet4 + 1425 ((psc->packet[1] & 0x0f) << 8) + 1426 ((psc->packet[3] & 0x10) << 8); 1427 1428 nsp.sp_y = packet5 + 1429 ((psc->packet[1] & 0xf0) << 4) + 1430 ((psc->packet[3] & 0x20) << 7); 1431 1432 /* Pressure */ 1433 nsp.sp_z = psc->packet[2]; 1434 } 1435 1436 /* 1437 * Check if the x and y are non-zero that they 1438 * are within the bounds of the trackpad 1439 * otherwise ignore the packet. 1440 */ 1441 if (((nsp.sp_x != 0) && 1442 ((nsp.sp_x < synaptics_edge_left) || 1443 (nsp.sp_x > synaptics_edge_right))) || 1444 ((nsp.sp_y != 0) && 1445 ((nsp.sp_y < synaptics_edge_bottom) || 1446 (nsp.sp_y > synaptics_edge_top)))) { 1447 sc->gesture_type = 0; 1448 sc->gesture_buttons = 0; 1449 sc->total_packets--; 1450 DPRINTF(20, sc, 1451 "synaptics_parse: dropping out of bounds packet " 1452 "sp_x %d sp_y %d\n", 1453 nsp.sp_x, nsp.sp_y); 1454 return; 1455 } 1456 1457 nsp.sp_finger_count = pms_synaptics_get_fingers(psc, 1458 nsp.sp_w, nsp.sp_z); 1459 1460 /* 1461 * We don't have extended W so we only know if there 1462 * are multiple fingers on the touchpad, only the primary 1463 * location is reported so just pretend we have an 1464 * unmoving second finger. 1465 */ 1466 if (((sc->flags & SYN_FLAG_HAS_EXTENDED_WMODE) 1467 != SYN_FLAG_HAS_EXTENDED_WMODE) && 1468 (nsp.sp_finger_count > 1)) { 1469 nsp.sp_secondary = 1; 1470 nsp.sp_sx = 0; 1471 nsp.sp_sy = 0; 1472 nsp.sp_sz = 0; 1473 } 1474 1475 if ((psc->packet[0] ^ psc->packet[3]) & 0x02) { 1476 /* extended buttons */ 1477 1478 DPRINTF(10, sc, 1479 "synaptics_parse: %02x %02x %02x %02x %02x %02x\n", 1480 psc->packet[0], psc->packet[1], psc->packet[2], 1481 psc->packet[3], psc->packet[4], psc->packet[5]); 1482 1483 if ((psc->packet[4] & SYN_1BUTMASK) != 0) 1484 ext_left = PMS_LBUTMASK; 1485 else 1486 ext_left = 0; 1487 1488 if ((psc->packet[4] & SYN_3BUTMASK) != 0) 1489 ext_middle = PMS_MBUTMASK; 1490 else 1491 ext_middle = 0; 1492 1493 if ((psc->packet[5] & SYN_2BUTMASK) != 0) 1494 ext_right = PMS_RBUTMASK; 1495 else 1496 ext_right = 0; 1497 1498 if ((psc->packet[5] & SYN_4BUTMASK) != 0) 1499 ext_up = 1; 1500 else 1501 ext_up = 0; 1502 1503 if ((psc->packet[4] & SYN_5BUTMASK) != 0) 1504 ext_down = 1; 1505 else 1506 ext_down = 0; 1507 } else { 1508 /* Left/Right button handling. */ 1509 nsp.sp_left = psc->packet[0] & PMS_LBUTMASK; 1510 nsp.sp_right = psc->packet[0] & PMS_RBUTMASK; 1511 } 1512 1513 /* Up/Down buttons. */ 1514 if (sc->flags & SYN_FLAG_HAS_BUTTONS_4_5) { 1515 /* Old up/down buttons. */ 1516 nsp.sp_up = nsp.sp_left ^ 1517 (psc->packet[3] & PMS_LBUTMASK); 1518 nsp.sp_down = nsp.sp_right ^ 1519 (psc->packet[3] & PMS_RBUTMASK); 1520 } else if (sc->flags & SYN_FLAG_HAS_UP_DOWN_BUTTONS && 1521 ((psc->packet[0] & PMS_RBUTMASK) ^ 1522 (psc->packet[3] & PMS_RBUTMASK))) { 1523 /* New up/down button. */ 1524 nsp.sp_up = psc->packet[4] & SYN_1BUTMASK; 1525 nsp.sp_down = psc->packet[5] & SYN_2BUTMASK; 1526 } else { 1527 nsp.sp_up = 0; 1528 nsp.sp_down = 0; 1529 } 1530 1531 new_buttons = 0; 1532 if(sc->flags & SYN_FLAG_HAS_ONE_BUTTON_CLICKPAD) { 1533 /* This is not correctly specified. Read this button press 1534 * from L/U bit. Emulate 3 buttons by checking the 1535 * coordinates of the click and returning the appropriate 1536 * button code. Outside the button region default to a 1537 * left click. 1538 */ 1539 u_char bstate = (psc->packet[0] ^ psc->packet[3]) 1540 & 0x01; 1541 if (nsp.sp_y < synaptics_button_boundary) { 1542 if (nsp.sp_x > synaptics_button3) { 1543 nsp.sp_right = 1544 bstate ? PMS_RBUTMASK : 0; 1545 } else if (nsp.sp_x > synaptics_button2) { 1546 nsp.sp_middle = 1547 bstate ? PMS_MBUTMASK : 0; 1548 } else { 1549 nsp.sp_left = bstate ? PMS_LBUTMASK : 0; 1550 } 1551 } else 1552 nsp.sp_left = bstate ? 1 : 0; 1553 new_buttons = nsp.sp_left | nsp.sp_middle | nsp.sp_right; 1554 if (new_buttons != sc->button_history) { 1555 if (sc->button_history == 0) 1556 sc->button_history = new_buttons; 1557 else if (new_buttons == 0) { 1558 sc->button_history = 0; 1559 /* ensure all buttons are cleared just in 1560 * case finger comes off in a different 1561 * region. 1562 */ 1563 nsp.sp_left = 0; 1564 nsp.sp_middle = 0; 1565 nsp.sp_right = 0; 1566 } else { 1567 /* make sure we keep the same button even 1568 * if the finger moves to a different 1569 * region. This precludes chording 1570 * but, oh well. 1571 */ 1572 nsp.sp_left = sc->button_history & PMS_LBUTMASK; 1573 nsp.sp_middle = sc->button_history 1574 & PMS_MBUTMASK; 1575 nsp.sp_right = sc->button_history & PMS_RBUTMASK; 1576 } 1577 } 1578 } else if (sc->flags & SYN_FLAG_HAS_MIDDLE_BUTTON) { 1579 /* Old style Middle Button. */ 1580 nsp.sp_middle = (psc->packet[0] & PMS_LBUTMASK) ^ 1581 (psc->packet[3] & PMS_LBUTMASK); 1582 } else { 1583 nsp.sp_middle = 0; 1584 } 1585 1586 /* 1587 * Overlay extended button state if anything changed, 1588 * preserve the state if a button is being held. 1589 */ 1590 if (ext_left != -1) 1591 nsp.sp_left = sc->ext_left = ext_left; 1592 else if (sc->ext_left != 0) 1593 nsp.sp_left = sc->ext_left; 1594 1595 if (ext_right != -1) 1596 nsp.sp_right = sc->ext_right = ext_right; 1597 else if (sc->ext_right != 0) 1598 nsp.sp_right = sc->ext_right; 1599 1600 if (ext_middle != -1) 1601 nsp.sp_middle = sc->ext_middle = ext_middle; 1602 else if (sc->ext_middle != 0) 1603 nsp.sp_middle = sc->ext_middle; 1604 1605 if (ext_up != -1) 1606 nsp.sp_up = sc->ext_up = ext_up; 1607 else if (sc->ext_up != 0) 1608 nsp.sp_up = sc->ext_up; 1609 1610 if (ext_down != -1) 1611 nsp.sp_down = sc->ext_down = ext_down; 1612 else if (sc->ext_down != 0) 1613 nsp.sp_down = sc->ext_down; 1614 1615 switch (synaptics_up_down_emul) { 1616 case 1: 1617 /* Do middle button emulation using up/down buttons */ 1618 nsp.sp_middle = nsp.sp_up | nsp.sp_down; 1619 nsp.sp_up = nsp.sp_down = 0; 1620 break; 1621 case 3: 1622 /* Do left/right button emulation using up/down buttons */ 1623 nsp.sp_left = nsp.sp_left | nsp.sp_up; 1624 nsp.sp_right = nsp.sp_right | nsp.sp_down; 1625 nsp.sp_up = nsp.sp_down = 0; 1626 break; 1627 default: 1628 /* 1629 * Don't do any remapping... 1630 * Z-axis emulation is handled in pms_synaptics_process_packet 1631 */ 1632 break; 1633 } 1634 } 1635 1636 /* set the finger count only if we haven't seen an extended-w 1637 * finger count status 1638 */ 1639 if (nsp.sp_finger_status == 0) 1640 nsp.sp_finger_count = pms_synaptics_get_fingers(psc, nsp.sp_w, 1641 nsp.sp_z); 1642 1643 skip_position: 1644 DPRINTF(20, sc, 1645 "synaptics_parse: sp_x %d sp_y %d sp_z %d, sp_sx %d, sp_sy %d, " 1646 "sp_sz %d, sp_w %d sp_finger_count %d, sp_primary %d, " 1647 "sp_secondary %d, v %d, primary_finger %d, secondary_finger %d\n", 1648 nsp.sp_x, nsp.sp_y, nsp.sp_z, nsp.sp_sx, 1649 nsp.sp_sy, nsp.sp_sz, nsp.sp_w, nsp.sp_finger_count, 1650 nsp.sp_primary, nsp.sp_secondary, v, primary_finger, 1651 secondary_finger); 1652 1653 pms_synaptics_process_packet(psc, &nsp); 1654 1655 /* Clear fingers */ 1656 if ((nsp.sp_primary && nsp.sp_finger_count <= 1) || nsp.sp_secondary) { 1657 nsp.sp_primary = 0; 1658 nsp.sp_secondary = 0; 1659 nsp.sp_finger_status = 0; 1660 } 1661 1662 memcpy(&packet, &nsp, sizeof(packet)); 1663 } 1664 1665 /* 1666 * Passthrough is used for e.g. TrackPoints and additional pointing 1667 * devices connected to a Synaptics touchpad. 1668 */ 1669 static void 1670 pms_synaptics_passthrough(struct pms_softc *psc) 1671 { 1672 int dx, dy, dz; 1673 int buttons, changed; 1674 int s; 1675 1676 buttons = ((psc->packet[1] & PMS_LBUTMASK) ? 0x20 : 0) | 1677 ((psc->packet[1] & PMS_MBUTMASK) ? 0x40 : 0) | 1678 ((psc->packet[1] & PMS_RBUTMASK) ? 0x80 : 0); 1679 1680 dx = psc->packet[4]; 1681 if (dx >= 128) 1682 dx -= 256; 1683 if (dx == -128) 1684 dx = -127; 1685 1686 dy = psc->packet[5]; 1687 if (dy >= 128) 1688 dy -= 256; 1689 if (dy == -128) 1690 dy = -127; 1691 1692 dz = 0; 1693 1694 changed = buttons ^ (psc->buttons & 0xe0); 1695 psc->buttons ^= changed; 1696 1697 if (dx || dy || dz || changed) { 1698 s = spltty(); 1699 /* 1700 * If the middle button is held, interpret movement as 1701 * scrolling. 1702 */ 1703 if (synaptics_aux_mid_button_scroll && 1704 dy && (psc->buttons & 0x42)) { 1705 wsmouse_precision_scroll(psc->sc_wsmousedev, dx, dy); 1706 } else { 1707 buttons = (psc->buttons & 0x1f) | ((psc->buttons >> 5) & 0x7); 1708 wsmouse_input(psc->sc_wsmousedev, 1709 buttons, dx, dy, dz, 0, 1710 WSMOUSE_INPUT_DELTA); 1711 } 1712 splx(s); 1713 } 1714 } 1715 1716 static void 1717 pms_synaptics_input(void *vsc, int data) 1718 { 1719 struct pms_softc *psc = vsc; 1720 struct timeval diff; 1721 1722 if (!psc->sc_enabled) { 1723 /* Interrupts are not expected. Discard the byte. */ 1724 return; 1725 } 1726 1727 getmicrouptime(&psc->current); 1728 1729 if (psc->inputstate > 0) { 1730 timersub(&psc->current, &psc->last, &diff); 1731 if (diff.tv_sec > 0 || diff.tv_usec >= 40000) { 1732 device_printf(psc->sc_dev, 1733 "pms_synaptics_input: unusual delay (%ld.%06ld s), " 1734 "scheduling reset\n", 1735 (long)diff.tv_sec, (long)diff.tv_usec); 1736 psc->inputstate = 0; 1737 psc->sc_enabled = 0; 1738 wakeup(&psc->sc_enabled); 1739 return; 1740 } 1741 } 1742 psc->last = psc->current; 1743 1744 switch (psc->inputstate) { 1745 case -5: 1746 case -4: 1747 case -3: 1748 case -2: 1749 case -1: 1750 case 0: 1751 if ((data & 0xc8) != 0x80) { 1752 device_printf(psc->sc_dev, 1753 "pms_synaptics_input: 0x%02x out of sync\n", data); 1754 /* use negative counts to limit resync phase */ 1755 psc->inputstate--; 1756 return; /* not in sync yet, discard input */ 1757 } 1758 psc->inputstate = 0; 1759 /*FALLTHROUGH*/ 1760 1761 case -6: 1762 case 3: 1763 if ((data & 8) == 8) { 1764 device_printf(psc->sc_dev, 1765 "pms_synaptics_input: dropped in relative mode, reset\n"); 1766 psc->inputstate = 0; 1767 psc->sc_enabled = 0; 1768 wakeup(&psc->sc_enabled); 1769 return; 1770 } 1771 } 1772 if (psc->inputstate >= sizeof(psc->packet)) 1773 panic("inputstate should never be %d", psc->inputstate); 1774 1775 psc->packet[psc->inputstate++] = data & 0xff; 1776 if (psc->inputstate == 6) { 1777 struct synaptics_softc *sc = &psc->u.synaptics; 1778 DPRINTF(10, sc, "synaptics: packet: 0x%02x%02x%02x%02x%02x%02x\n", 1779 psc->packet[0], psc->packet[1], psc->packet[2], 1780 psc->packet[3], psc->packet[4], psc->packet[5]); 1781 /* 1782 * We have a complete packet. 1783 * Extract the pertinent details. 1784 */ 1785 psc->inputstate = 0; 1786 if ((psc->packet[0] & 0xfc) == 0x84 && 1787 (psc->packet[3] & 0xcc) == 0xc4) { 1788 /* W = SYNAPTICS_WIDTH_PASSTHROUGH, PS/2 passthrough */ 1789 pms_synaptics_passthrough(psc); 1790 } else { 1791 pms_synaptics_parse(psc); 1792 } 1793 } 1794 } 1795 1796 static inline int 1797 synaptics_finger_detect(struct synaptics_softc *sc, struct synaptics_packet *sp, 1798 int *palmp) 1799 { 1800 int fingers; 1801 1802 /* Assume no palm */ 1803 *palmp = 0; 1804 1805 /* 1806 * Apply some hysteresis when checking for a finger. 1807 * When the finger is first applied, we ignore it until the 1808 * pressure exceeds the 'high' threshold. The finger is considered 1809 * removed only when pressure falls beneath the 'low' threshold. 1810 */ 1811 if ((sc->prev_fingers == 0 && sp->sp_z > synaptics_finger_high) || 1812 (sc->prev_fingers != 0 && sp->sp_z > synaptics_finger_low)) 1813 fingers = 1; 1814 else 1815 fingers = 0; 1816 1817 /* 1818 * If the pad can't do palm detection, skip the rest. 1819 */ 1820 if (fingers == 0 || (sc->flags & SYN_FLAG_HAS_PALM_DETECT) == 0) 1821 return (fingers); 1822 1823 /* 1824 * Palm detection 1825 */ 1826 if (sp->sp_z > SYNAPTICS_FINGER_FLAT && 1827 sp->sp_w >= SYNAPTICS_WIDTH_PALM_MIN) 1828 *palmp = 1; 1829 1830 if (sc->prev_fingers == 0 && 1831 (sp->sp_z > SYNAPTICS_FINGER_FLAT || 1832 sp->sp_w >= SYNAPTICS_WIDTH_PALM_MIN)) { 1833 /* 1834 * Contact area or pressure is too great to be a finger. 1835 * Just ignore it for now. 1836 */ 1837 return (0); 1838 } 1839 1840 /* 1841 * Detect 2 and 3 fingers if supported, but only if multiple 1842 * fingers appear within the tap gesture time period. 1843 */ 1844 if ((sc->flags & SYN_FLAG_HAS_MULTI_FINGER) && 1845 ((SYN_TIME(sc, sc->gesture_start_packet) 1846 < synaptics_gesture_length) || 1847 SYN_TIME(sc, sc->gesture_start_packet) 1848 < synaptics_gesture_length)) { 1849 switch (sp->sp_w) { 1850 case SYNAPTICS_WIDTH_TWO_FINGERS: 1851 fingers = 2; 1852 break; 1853 1854 case SYNAPTICS_WIDTH_THREE_OR_MORE: 1855 fingers = 3; 1856 break; 1857 1858 default: 1859 /* 1860 * The width value can report spurious single-finger 1861 * events after a multi-finger event. 1862 */ 1863 fingers = sc->prev_fingers <= 1 ? 1 : sc->prev_fingers; 1864 break; 1865 } 1866 } 1867 1868 return (fingers); 1869 } 1870 1871 static inline void 1872 synaptics_gesture_detect(struct synaptics_softc *sc, 1873 struct synaptics_packet *sp, int fingers) 1874 { 1875 int gesture_len, gesture_buttons; 1876 int set_buttons; 1877 1878 gesture_len = SYN_TIME(sc, sc->gesture_start_packet); 1879 gesture_buttons = sc->gesture_buttons; 1880 1881 if (fingers > 0 && (fingers == sc->prev_fingers)) { 1882 /* Finger is still present */ 1883 sc->gesture_move_x = abs(sc->gesture_start_x - sp->sp_x); 1884 sc->gesture_move_y = abs(sc->gesture_start_y - sp->sp_y); 1885 } else 1886 if (fingers && sc->prev_fingers == 0) { 1887 /* 1888 * Finger was just applied. 1889 * If the previous gesture was a single-click, set things 1890 * up to deal with a possible drag or double-click gesture. 1891 * Basically, if the finger is removed again within 1892 * 'synaptics_gesture_length' packets, this is treated 1893 * as a double-click. Otherwise we will emulate holding 1894 * the left button down whilst dragging the mouse. 1895 */ 1896 if (SYN_IS_SINGLE_TAP(sc->gesture_type)) 1897 sc->gesture_type |= SYN_GESTURE_DRAG; 1898 1899 sc->gesture_start_x = abs(sp->sp_x); 1900 sc->gesture_start_y = abs(sp->sp_y); 1901 sc->gesture_move_x = 0; 1902 sc->gesture_move_y = 0; 1903 sc->gesture_start_packet = sc->total_packets; 1904 1905 DPRINTF(10, sc, "Finger applied:" 1906 " gesture_start_x: %d" 1907 " gesture_start_y: %d\n", 1908 sc->gesture_start_x, sc->gesture_start_y); 1909 } else 1910 if (fingers == 0 && sc->prev_fingers != 0) { 1911 /* 1912 * Finger was just removed. 1913 * Check if the contact time and finger movement were 1914 * small enough to qualify as a gesture. 1915 * Ignore finger movement if multiple fingers were 1916 * detected (the pad may report coordinates for any 1917 * of the fingers). 1918 */ 1919 1920 DPRINTF(10, sc, "Finger removed: gesture_len: %d (%d)\n", 1921 gesture_len, synaptics_gesture_length); 1922 DPRINTF(10, sc, "gesture_move_x: %d (%d) sp_x: %d\n", 1923 sc->gesture_move_x, synaptics_gesture_move, abs(sp->sp_x)); 1924 DPRINTF(10, sc, "gesture_move_y: %d (%d) sp_y: %d\n", 1925 sc->gesture_move_y, synaptics_gesture_move, abs(sp->sp_y)); 1926 1927 if (gesture_len < synaptics_gesture_length && 1928 ((sc->gesture_move_x < synaptics_gesture_move && 1929 sc->gesture_move_y < synaptics_gesture_move))) { 1930 /* 1931 * Looking good so far. 1932 */ 1933 if (SYN_IS_DRAG(sc->gesture_type)) { 1934 /* 1935 * Promote this gesture to double-click. 1936 */ 1937 sc->gesture_type |= SYN_GESTURE_DOUBLE; 1938 sc->gesture_type &= ~SYN_GESTURE_SINGLE; 1939 } else { 1940 /* 1941 * Single tap gesture. Set the tap length timer 1942 * and flag a single-click. 1943 */ 1944 sc->gesture_tap_packet = sc->total_packets; 1945 sc->gesture_type |= SYN_GESTURE_SINGLE; 1946 1947 /* 1948 * The gesture can be modified depending on 1949 * the number of fingers detected. 1950 * 1951 * 1: Normal left button emulation. 1952 * 2: Either middle button or right button 1953 * depending on the value of the two_fingers 1954 * sysctl variable. 1955 * 3: Right button. 1956 */ 1957 switch (sc->prev_fingers) { 1958 case 2: 1959 if (synaptics_two_fingers_emul == 1) 1960 gesture_buttons |= PMS_RBUTMASK; 1961 else 1962 if (synaptics_two_fingers_emul == 2) 1963 gesture_buttons |= PMS_MBUTMASK; 1964 break; 1965 case 3: 1966 gesture_buttons |= PMS_RBUTMASK; 1967 break; 1968 default: 1969 gesture_buttons |= PMS_LBUTMASK; 1970 break; 1971 } 1972 } 1973 } 1974 1975 /* 1976 * Always clear drag state when the finger is removed. 1977 */ 1978 sc->gesture_type &= ~SYN_GESTURE_DRAG; 1979 } 1980 1981 if (sc->gesture_type == 0) { 1982 /* 1983 * There is no gesture in progress. 1984 * Clear emulated button state. 1985 */ 1986 sc->gesture_buttons = 0; 1987 return; 1988 } 1989 1990 /* 1991 * A gesture is in progress. 1992 */ 1993 set_buttons = 0; 1994 1995 if (SYN_IS_SINGLE_TAP(sc->gesture_type)) { 1996 /* 1997 * Single-click. 1998 * Activate the relevant button(s) until the 1999 * gesture tap timer has expired. 2000 */ 2001 if (SYN_TIME(sc, sc->gesture_tap_packet) < 2002 synaptics_gesture_length) 2003 set_buttons = 1; 2004 else 2005 sc->gesture_type &= ~SYN_GESTURE_SINGLE; 2006 DPRINTF(10, sc, "synaptics_gesture: single tap, buttons %d\n", 2007 set_buttons); 2008 DPRINTF(10, sc, "synaptics_gesture: single tap, tap at %d, current %d\n", 2009 sc->gesture_tap_packet, sc->total_packets); 2010 DPRINTF(10, sc, "synaptics_gesture: single tap, tap_time %d, gesture len %d\n", 2011 SYN_TIME(sc, sc->gesture_tap_packet), synaptics_gesture_length); 2012 } else 2013 if (SYN_IS_DOUBLE_TAP(sc->gesture_type) && sc->prev_fingers == 0) { 2014 /* 2015 * Double-click. 2016 * Activate the relevant button(s) once. 2017 */ 2018 set_buttons = 1; 2019 sc->gesture_type &= ~SYN_GESTURE_DOUBLE; 2020 } 2021 2022 if (set_buttons || SYN_IS_DRAG(sc->gesture_type)) { 2023 /* 2024 * Single-click and drag. 2025 * Maintain button state until the finger is removed. 2026 */ 2027 sp->sp_left |= gesture_buttons & PMS_LBUTMASK; 2028 sp->sp_right |= gesture_buttons & PMS_RBUTMASK; 2029 sp->sp_middle |= gesture_buttons & PMS_MBUTMASK; 2030 } 2031 2032 sc->gesture_buttons = gesture_buttons; 2033 } 2034 2035 static inline int 2036 synaptics_filter_policy(struct synaptics_softc *sc, int finger, int *history, 2037 int value, u_int count) 2038 { 2039 int a, b, rv; 2040 2041 /* 2042 * Once we've accumulated at least SYN_HIST_SIZE values, combine 2043 * each new value with the previous two and return the average. 2044 * 2045 * This is necessary when the touchpad is operating in 80 packets 2046 * per second mode, as it performs little internal filtering on 2047 * reported values. 2048 * 2049 * Using a rolling average helps to filter out jitter caused by 2050 * tiny finger movements. 2051 */ 2052 if (count >= SYN_HIST_SIZE) { 2053 a = (history[(count - 2) % SYN_HIST_SIZE] + 2054 history[(count - 1) % SYN_HIST_SIZE]) / 2; 2055 2056 b = (value + history[(count - 1) % SYN_HIST_SIZE]) / 2; 2057 2058 rv = b - a; 2059 2060 /* 2061 * Don't report the movement if it's below a certain 2062 * threshold. 2063 */ 2064 if (abs(rv) < synaptics_movement_threshold) 2065 rv = 0; 2066 } else 2067 rv = 0; 2068 2069 /* 2070 * Add the new value to the history buffer. 2071 */ 2072 history[(count + 0) % SYN_HIST_SIZE] = value; 2073 2074 return (rv); 2075 } 2076 2077 /* Edge detection */ 2078 #define SYN_EDGE_TOP 1 2079 #define SYN_EDGE_BOTTOM 2 2080 #define SYN_EDGE_LEFT 4 2081 #define SYN_EDGE_RIGHT 8 2082 2083 static inline int 2084 synaptics_check_edge(int x, int y) 2085 { 2086 int rv = 0; 2087 2088 if (x < synaptics_edge_left) 2089 rv |= SYN_EDGE_LEFT; 2090 else 2091 if (x > synaptics_edge_right) 2092 rv |= SYN_EDGE_RIGHT; 2093 2094 if (y < synaptics_edge_bottom) 2095 rv |= SYN_EDGE_BOTTOM; 2096 else 2097 if (y > synaptics_edge_top) 2098 rv |= SYN_EDGE_TOP; 2099 2100 return (rv); 2101 } 2102 2103 static inline int 2104 synaptics_edge_motion(struct synaptics_softc *sc, int delta, int dir) 2105 { 2106 2107 /* 2108 * When edge motion is enabled, synaptics_edge_motion_delta is 2109 * combined with the current delta, together with the direction 2110 * in which to simulate the motion. The result is added to 2111 * the delta derived from finger movement. This provides a smooth 2112 * transition from finger movement to edge motion. 2113 */ 2114 delta = synaptics_edge_motion_delta + (dir * delta); 2115 if (delta < 0) 2116 return (0); 2117 if (delta > synaptics_edge_motion_delta) 2118 return (synaptics_edge_motion_delta); 2119 return (delta); 2120 } 2121 2122 static inline int 2123 synaptics_scale(int delta, int scale, int *remp) 2124 { 2125 int rv; 2126 2127 /* 2128 * Scale the raw delta in Synaptics coordinates (0-6143) into 2129 * something more reasonable by dividing the raw delta by a 2130 * scale factor. Any remainder from the previous scale result 2131 * is added to the current delta before scaling. 2132 * This prevents loss of resolution for very small/slow 2133 * movements of the finger. 2134 */ 2135 delta += *remp; 2136 rv = delta / scale; 2137 *remp = delta % scale; 2138 2139 return (rv); 2140 } 2141 2142 static inline void 2143 synaptics_movement(struct synaptics_softc *sc, struct synaptics_packet *sp, 2144 int *dxp, int *dyp, int *dzp, int *sdxp, int *sdyp, int *sdzp) 2145 { 2146 int dx, dy, dz, sdx, sdy, sdz, edge; 2147 2148 dx = dy = dz = sdx = sdy = sdz = 0; 2149 2150 /* 2151 * Compute the next values of dx, dy, dz, sdx, sdy, sdz. 2152 */ 2153 dx = synaptics_filter_policy(sc, 0, 2154 sc->history_x[SYN_PRIMARY_FINGER], sp->sp_x, 2155 sc->packet_count[SYN_PRIMARY_FINGER]); 2156 dy = synaptics_filter_policy(sc, 0, 2157 sc->history_y[SYN_PRIMARY_FINGER], sp->sp_y, 2158 sc->packet_count[SYN_PRIMARY_FINGER]); 2159 sc->packet_count[SYN_PRIMARY_FINGER]++; 2160 2161 if (sp->sp_finger_count > 1) { 2162 sdx = synaptics_filter_policy(sc, 1, 2163 sc->history_x[SYN_SECONDARY_FINGER], sp->sp_sx, 2164 sc->packet_count[SYN_SECONDARY_FINGER]); 2165 sdy = synaptics_filter_policy(sc, 1, 2166 sc->history_y[SYN_SECONDARY_FINGER], sp->sp_sy, 2167 sc->packet_count[SYN_SECONDARY_FINGER]); 2168 sc->packet_count[SYN_SECONDARY_FINGER]++; 2169 DPRINTF(10, sc, "synaptics_movement: dx %d dy %d sdx %d sdy %d\n", 2170 dx, dy, sdx, sdy); 2171 } 2172 2173 /* 2174 * If we're dealing with a drag gesture, and the finger moves to 2175 * the edge of the touchpad, apply edge motion emulation if it 2176 * is enabled. 2177 */ 2178 if (synaptics_edge_motion_delta && SYN_IS_DRAG(sc->gesture_type)) { 2179 edge = synaptics_check_edge(sp->sp_x, sp->sp_y); 2180 2181 if (edge & SYN_EDGE_LEFT) 2182 dx -= synaptics_edge_motion(sc, dx, 1); 2183 if (edge & SYN_EDGE_RIGHT) 2184 dx += synaptics_edge_motion(sc, dx, -1); 2185 if (edge & SYN_EDGE_BOTTOM) 2186 dy -= synaptics_edge_motion(sc, dy, 1); 2187 if (edge & SYN_EDGE_TOP) 2188 dy += synaptics_edge_motion(sc, dy, -1); 2189 2190 if (sp->sp_finger_count > 1) { 2191 edge = synaptics_check_edge(sp->sp_sx, sp->sp_sy); 2192 2193 if (edge & SYN_EDGE_LEFT) 2194 sdx -= synaptics_edge_motion(sc, sdx, 1); 2195 if (edge & SYN_EDGE_RIGHT) 2196 sdx += synaptics_edge_motion(sc, sdx, -1); 2197 if (edge & SYN_EDGE_BOTTOM) 2198 sdy -= synaptics_edge_motion(sc, sdy, 1); 2199 if (edge & SYN_EDGE_TOP) 2200 sdy += synaptics_edge_motion(sc, sdy, -1); 2201 } 2202 } 2203 2204 /* 2205 * Apply scaling to the deltas 2206 */ 2207 dx = synaptics_scale(dx, synaptics_scale_x, 2208 &sc->rem_x[SYN_PRIMARY_FINGER]); 2209 dy = synaptics_scale(dy, synaptics_scale_y, 2210 &sc->rem_y[SYN_PRIMARY_FINGER]); 2211 dz = synaptics_scale(dz, synaptics_scale_z, 2212 &sc->rem_z[SYN_PRIMARY_FINGER]); 2213 2214 if (sp->sp_finger_count > 1) { 2215 sdx = synaptics_scale(sdx, synaptics_scale_x, 2216 &sc->rem_x[SYN_SECONDARY_FINGER]); 2217 sdy = synaptics_scale(sdy, synaptics_scale_y, 2218 &sc->rem_y[SYN_SECONDARY_FINGER]); 2219 sdz = synaptics_scale(sdz, synaptics_scale_z, 2220 &sc->rem_z[SYN_SECONDARY_FINGER]); 2221 2222 DPRINTF(10, sc, 2223 "synaptics_movement 2: dx %d dy %d sdx %d sdy %d\n", 2224 dx, dy, sdx, sdy); 2225 } 2226 2227 /* 2228 * Clamp deltas to specified maximums. 2229 */ 2230 if (abs(dx) > synaptics_max_speed_x) 2231 dx = ((dx >= 0)? 1 : -1) * synaptics_max_speed_x; 2232 if (abs(dy) > synaptics_max_speed_y) 2233 dy = ((dy >= 0)? 1 : -1) * synaptics_max_speed_y; 2234 if (abs(dz) > synaptics_max_speed_z) 2235 dz = ((dz >= 0)? 1 : -1) * synaptics_max_speed_z; 2236 2237 if (sp->sp_finger_count > 1) { 2238 if (abs(sdx) > synaptics_max_speed_x) 2239 sdx = ((sdx >= 0)? 1 : -1) * synaptics_max_speed_x; 2240 if (abs(dy) > synaptics_max_speed_y) 2241 sdy = ((sdy >= 0)? 1 : -1) * synaptics_max_speed_y; 2242 if (abs(sdz) > synaptics_max_speed_z) 2243 sdz = ((sdz >= 0)? 1 : -1) * synaptics_max_speed_z; 2244 } 2245 2246 *dxp = dx; 2247 *dyp = dy; 2248 *dzp = dz; 2249 *sdxp = sdx; 2250 *sdyp = sdy; 2251 *sdzp = sdz; 2252 2253 } 2254 2255 static void 2256 pms_synaptics_process_packet(struct pms_softc *psc, struct synaptics_packet *sp) 2257 { 2258 struct synaptics_softc *sc = &psc->u.synaptics; 2259 int dx, dy, dz, sdx, sdy, sdz; 2260 int fingers, palm, buttons, changed; 2261 int s; 2262 2263 sdx = sdy = sdz = 0; 2264 2265 /* 2266 * Do Z-axis emulation using up/down buttons if required. 2267 * Note that the pad will send a one second burst of packets 2268 * when an up/down button is pressed and held. At the moment 2269 * we don't deal with auto-repeat, so convert the burst into 2270 * a one-shot. 2271 */ 2272 dz = 0; 2273 if (synaptics_up_down_emul == 2) { 2274 if (sc->up_down == 0) { 2275 if (sp->sp_up && sp->sp_down) { 2276 sp->sp_middle = 1; 2277 } else if (sp->sp_up) { 2278 dz = -synaptics_up_down_motion_delta; 2279 } else if (sp->sp_down) { 2280 dz = synaptics_up_down_motion_delta; 2281 } 2282 } 2283 2284 sc->up_down = sp->sp_up | sp->sp_down; 2285 sp->sp_up = sp->sp_down = 0; 2286 } 2287 2288 /* 2289 * Determine whether or not a finger is on the pad. 2290 * On some pads, this will return the number of fingers 2291 * detected. 2292 */ 2293 fingers = synaptics_finger_detect(sc, sp, &palm); 2294 2295 /* 2296 * Do gesture processing only if we didn't detect a palm. 2297 */ 2298 if (palm == 0) 2299 synaptics_gesture_detect(sc, sp, fingers); 2300 else 2301 sc->gesture_type = sc->gesture_buttons = 0; 2302 2303 /* 2304 * Determine what buttons to report 2305 */ 2306 buttons = (sp->sp_left ? 0x1 : 0) | 2307 (sp->sp_middle ? 0x2 : 0) | 2308 (sp->sp_right ? 0x4 : 0) | 2309 (sp->sp_up ? 0x8 : 0) | 2310 (sp->sp_down ? 0x10 : 0); 2311 changed = buttons ^ (psc->buttons & 0x1f); 2312 psc->buttons ^= changed; 2313 2314 sc->prev_fingers = fingers; 2315 2316 /* 2317 * Do movement processing IFF we have a single finger and no palm or 2318 * a secondary finger and no palm. 2319 */ 2320 if (palm == 0 && synaptics_movement_enable) { 2321 if (fingers > 0) { 2322 synaptics_movement(sc, sp, &dx, &dy, &dz, &sdx, &sdy, 2323 &sdz); 2324 2325 /* 2326 * Check if there are two fingers, if there are then 2327 * check if we have a clickpad, if we do then we 2328 * don't scroll iff one of the fingers is in the 2329 * button region. Otherwise interpret as a scroll 2330 */ 2331 if (sp->sp_finger_count >= 2 && sc->gesture_type == 0 ) { 2332 if (!(sc->flags & SYN_FLAG_HAS_ONE_BUTTON_CLICKPAD) || 2333 ((sc->flags & SYN_FLAG_HAS_ONE_BUTTON_CLICKPAD) && 2334 (sp->sp_y > synaptics_button_boundary) && 2335 (sp->sp_sy > synaptics_button_boundary))) { 2336 s = spltty(); 2337 wsmouse_precision_scroll( 2338 psc->sc_wsmousedev, dx, dy); 2339 splx(s); 2340 return; 2341 } 2342 } 2343 2344 /* 2345 * Allow user to turn off movements in the button 2346 * region of a click pad. 2347 */ 2348 if (sc->flags & SYN_FLAG_HAS_ONE_BUTTON_CLICKPAD) { 2349 if ((sp->sp_y < synaptics_button_boundary) && 2350 (!synaptics_button_region_movement)) { 2351 dx = dy = dz = 0; 2352 } 2353 2354 if ((sp->sp_sy < synaptics_button_boundary) && 2355 (!synaptics_button_region_movement)) { 2356 sdx = sdy = sdz = 0; 2357 } 2358 } 2359 2360 /* Now work out which finger to report, just 2361 * go with the one that has moved the most. 2362 */ 2363 if ((abs(dx) + abs(dy) + abs(dz)) < 2364 (abs(sdx) + abs(sdy) + abs(sdz))) { 2365 /* secondary finger wins */ 2366 dx = sdx; 2367 dy = sdy; 2368 dz = sdz; 2369 } 2370 } else { 2371 /* 2372 * No valid finger. Therefore no movement. 2373 */ 2374 sc->rem_x[SYN_PRIMARY_FINGER] = 0; 2375 sc->rem_y[SYN_PRIMARY_FINGER] = 0; 2376 sc->rem_x[SYN_SECONDARY_FINGER] = 0; 2377 sc->rem_y[SYN_SECONDARY_FINGER] = 0; 2378 dx = dy = 0; 2379 2380 sc->packet_count[SYN_PRIMARY_FINGER] = 0; 2381 sc->packet_count[SYN_SECONDARY_FINGER] = 0; 2382 } 2383 } else { 2384 /* 2385 * No valid finger. Therefore no movement. 2386 */ 2387 sc->rem_x[SYN_PRIMARY_FINGER] = 0; 2388 sc->rem_y[SYN_PRIMARY_FINGER] = 0; 2389 sc->rem_z[SYN_PRIMARY_FINGER] = 0; 2390 dx = dy = dz = 0; 2391 } 2392 2393 DPRINTF(10, sc, 2394 "pms_synaptics_process_packet: dx %d dy %d dz %d sdx %d sdy %d sdz %d\n", 2395 dx, dy, dz, sdx, sdy, sdz); 2396 2397 /* 2398 * Pass the final results up to wsmouse_input() if necessary. 2399 */ 2400 if (dx || dy || dz || changed) { 2401 buttons = (psc->buttons & 0x1f) | ((psc->buttons >> 5) & 0x7); 2402 s = spltty(); 2403 wsmouse_input(psc->sc_wsmousedev, 2404 buttons, 2405 dx, dy, dz, 0, 2406 WSMOUSE_INPUT_DELTA); 2407 splx(s); 2408 } 2409 } 2410