synaptics.c revision 1.84 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