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