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