synaptics.c revision 1.81.4.1 1 /* $NetBSD: synaptics.c,v 1.81.4.1 2024/06/22 10:02:05 martin 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.4.1 2024/06/22 10:02:05 martin 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 & 0x2)) {
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
1773 psc->packet[psc->inputstate++] = data & 0xff;
1774 if (psc->inputstate == 6) {
1775 struct synaptics_softc *sc = &psc->u.synaptics;
1776 DPRINTF(10, sc, "synaptics: packet: 0x%02x%02x%02x%02x%02x%02x\n",
1777 psc->packet[0], psc->packet[1], psc->packet[2],
1778 psc->packet[3], psc->packet[4], psc->packet[5]);
1779 /*
1780 * We have a complete packet.
1781 * Extract the pertinent details.
1782 */
1783 psc->inputstate = 0;
1784 if ((psc->packet[0] & 0xfc) == 0x84 &&
1785 (psc->packet[3] & 0xcc) == 0xc4) {
1786 /* W = SYNAPTICS_WIDTH_PASSTHROUGH, PS/2 passthrough */
1787 pms_synaptics_passthrough(psc);
1788 } else {
1789 pms_synaptics_parse(psc);
1790 }
1791 }
1792 }
1793
1794 static inline int
1795 synaptics_finger_detect(struct synaptics_softc *sc, struct synaptics_packet *sp,
1796 int *palmp)
1797 {
1798 int fingers;
1799
1800 /* Assume no palm */
1801 *palmp = 0;
1802
1803 /*
1804 * Apply some hysteresis when checking for a finger.
1805 * When the finger is first applied, we ignore it until the
1806 * pressure exceeds the 'high' threshold. The finger is considered
1807 * removed only when pressure falls beneath the 'low' threshold.
1808 */
1809 if ((sc->prev_fingers == 0 && sp->sp_z > synaptics_finger_high) ||
1810 (sc->prev_fingers != 0 && sp->sp_z > synaptics_finger_low))
1811 fingers = 1;
1812 else
1813 fingers = 0;
1814
1815 /*
1816 * If the pad can't do palm detection, skip the rest.
1817 */
1818 if (fingers == 0 || (sc->flags & SYN_FLAG_HAS_PALM_DETECT) == 0)
1819 return (fingers);
1820
1821 /*
1822 * Palm detection
1823 */
1824 if (sp->sp_z > SYNAPTICS_FINGER_FLAT &&
1825 sp->sp_w >= SYNAPTICS_WIDTH_PALM_MIN)
1826 *palmp = 1;
1827
1828 if (sc->prev_fingers == 0 &&
1829 (sp->sp_z > SYNAPTICS_FINGER_FLAT ||
1830 sp->sp_w >= SYNAPTICS_WIDTH_PALM_MIN)) {
1831 /*
1832 * Contact area or pressure is too great to be a finger.
1833 * Just ignore it for now.
1834 */
1835 return (0);
1836 }
1837
1838 /*
1839 * Detect 2 and 3 fingers if supported, but only if multiple
1840 * fingers appear within the tap gesture time period.
1841 */
1842 if ((sc->flags & SYN_FLAG_HAS_MULTI_FINGER) &&
1843 ((SYN_TIME(sc, sc->gesture_start_packet)
1844 < synaptics_gesture_length) ||
1845 SYN_TIME(sc, sc->gesture_start_packet)
1846 < synaptics_gesture_length)) {
1847 switch (sp->sp_w) {
1848 case SYNAPTICS_WIDTH_TWO_FINGERS:
1849 fingers = 2;
1850 break;
1851
1852 case SYNAPTICS_WIDTH_THREE_OR_MORE:
1853 fingers = 3;
1854 break;
1855
1856 default:
1857 /*
1858 * The width value can report spurious single-finger
1859 * events after a multi-finger event.
1860 */
1861 fingers = sc->prev_fingers <= 1 ? 1 : sc->prev_fingers;
1862 break;
1863 }
1864 }
1865
1866 return (fingers);
1867 }
1868
1869 static inline void
1870 synaptics_gesture_detect(struct synaptics_softc *sc,
1871 struct synaptics_packet *sp, int fingers)
1872 {
1873 int gesture_len, gesture_buttons;
1874 int set_buttons;
1875
1876 gesture_len = SYN_TIME(sc, sc->gesture_start_packet);
1877 gesture_buttons = sc->gesture_buttons;
1878
1879 if (fingers > 0 && (fingers == sc->prev_fingers)) {
1880 /* Finger is still present */
1881 sc->gesture_move_x = abs(sc->gesture_start_x - sp->sp_x);
1882 sc->gesture_move_y = abs(sc->gesture_start_y - sp->sp_y);
1883 } else
1884 if (fingers && sc->prev_fingers == 0) {
1885 /*
1886 * Finger was just applied.
1887 * If the previous gesture was a single-click, set things
1888 * up to deal with a possible drag or double-click gesture.
1889 * Basically, if the finger is removed again within
1890 * 'synaptics_gesture_length' packets, this is treated
1891 * as a double-click. Otherwise we will emulate holding
1892 * the left button down whilst dragging the mouse.
1893 */
1894 if (SYN_IS_SINGLE_TAP(sc->gesture_type))
1895 sc->gesture_type |= SYN_GESTURE_DRAG;
1896
1897 sc->gesture_start_x = abs(sp->sp_x);
1898 sc->gesture_start_y = abs(sp->sp_y);
1899 sc->gesture_move_x = 0;
1900 sc->gesture_move_y = 0;
1901 sc->gesture_start_packet = sc->total_packets;
1902
1903 DPRINTF(10, sc, "Finger applied:"
1904 " gesture_start_x: %d"
1905 " gesture_start_y: %d\n",
1906 sc->gesture_start_x, sc->gesture_start_y);
1907 } else
1908 if (fingers == 0 && sc->prev_fingers != 0) {
1909 /*
1910 * Finger was just removed.
1911 * Check if the contact time and finger movement were
1912 * small enough to qualify as a gesture.
1913 * Ignore finger movement if multiple fingers were
1914 * detected (the pad may report coordinates for any
1915 * of the fingers).
1916 */
1917
1918 DPRINTF(10, sc, "Finger removed: gesture_len: %d (%d)\n",
1919 gesture_len, synaptics_gesture_length);
1920 DPRINTF(10, sc, "gesture_move_x: %d (%d) sp_x: %d\n",
1921 sc->gesture_move_x, synaptics_gesture_move, abs(sp->sp_x));
1922 DPRINTF(10, sc, "gesture_move_y: %d (%d) sp_y: %d\n",
1923 sc->gesture_move_y, synaptics_gesture_move, abs(sp->sp_y));
1924
1925 if (gesture_len < synaptics_gesture_length &&
1926 ((sc->gesture_move_x < synaptics_gesture_move &&
1927 sc->gesture_move_y < synaptics_gesture_move))) {
1928 /*
1929 * Looking good so far.
1930 */
1931 if (SYN_IS_DRAG(sc->gesture_type)) {
1932 /*
1933 * Promote this gesture to double-click.
1934 */
1935 sc->gesture_type |= SYN_GESTURE_DOUBLE;
1936 sc->gesture_type &= ~SYN_GESTURE_SINGLE;
1937 } else {
1938 /*
1939 * Single tap gesture. Set the tap length timer
1940 * and flag a single-click.
1941 */
1942 sc->gesture_tap_packet = sc->total_packets;
1943 sc->gesture_type |= SYN_GESTURE_SINGLE;
1944
1945 /*
1946 * The gesture can be modified depending on
1947 * the number of fingers detected.
1948 *
1949 * 1: Normal left button emulation.
1950 * 2: Either middle button or right button
1951 * depending on the value of the two_fingers
1952 * sysctl variable.
1953 * 3: Right button.
1954 */
1955 switch (sc->prev_fingers) {
1956 case 2:
1957 if (synaptics_two_fingers_emul == 1)
1958 gesture_buttons |= PMS_RBUTMASK;
1959 else
1960 if (synaptics_two_fingers_emul == 2)
1961 gesture_buttons |= PMS_MBUTMASK;
1962 break;
1963 case 3:
1964 gesture_buttons |= PMS_RBUTMASK;
1965 break;
1966 default:
1967 gesture_buttons |= PMS_LBUTMASK;
1968 break;
1969 }
1970 }
1971 }
1972
1973 /*
1974 * Always clear drag state when the finger is removed.
1975 */
1976 sc->gesture_type &= ~SYN_GESTURE_DRAG;
1977 }
1978
1979 if (sc->gesture_type == 0) {
1980 /*
1981 * There is no gesture in progress.
1982 * Clear emulated button state.
1983 */
1984 sc->gesture_buttons = 0;
1985 return;
1986 }
1987
1988 /*
1989 * A gesture is in progress.
1990 */
1991 set_buttons = 0;
1992
1993 if (SYN_IS_SINGLE_TAP(sc->gesture_type)) {
1994 /*
1995 * Single-click.
1996 * Activate the relevant button(s) until the
1997 * gesture tap timer has expired.
1998 */
1999 if (SYN_TIME(sc, sc->gesture_tap_packet) <
2000 synaptics_gesture_length)
2001 set_buttons = 1;
2002 else
2003 sc->gesture_type &= ~SYN_GESTURE_SINGLE;
2004 DPRINTF(10, sc, "synaptics_gesture: single tap, buttons %d\n",
2005 set_buttons);
2006 DPRINTF(10, sc, "synaptics_gesture: single tap, tap at %d, current %d\n",
2007 sc->gesture_tap_packet, sc->total_packets);
2008 DPRINTF(10, sc, "synaptics_gesture: single tap, tap_time %d, gesture len %d\n",
2009 SYN_TIME(sc, sc->gesture_tap_packet), synaptics_gesture_length);
2010 } else
2011 if (SYN_IS_DOUBLE_TAP(sc->gesture_type) && sc->prev_fingers == 0) {
2012 /*
2013 * Double-click.
2014 * Activate the relevant button(s) once.
2015 */
2016 set_buttons = 1;
2017 sc->gesture_type &= ~SYN_GESTURE_DOUBLE;
2018 }
2019
2020 if (set_buttons || SYN_IS_DRAG(sc->gesture_type)) {
2021 /*
2022 * Single-click and drag.
2023 * Maintain button state until the finger is removed.
2024 */
2025 sp->sp_left |= gesture_buttons & PMS_LBUTMASK;
2026 sp->sp_right |= gesture_buttons & PMS_RBUTMASK;
2027 sp->sp_middle |= gesture_buttons & PMS_MBUTMASK;
2028 }
2029
2030 sc->gesture_buttons = gesture_buttons;
2031 }
2032
2033 static inline int
2034 synaptics_filter_policy(struct synaptics_softc *sc, int finger, int *history,
2035 int value, u_int count)
2036 {
2037 int a, b, rv;
2038
2039 /*
2040 * Once we've accumulated at least SYN_HIST_SIZE values, combine
2041 * each new value with the previous two and return the average.
2042 *
2043 * This is necessary when the touchpad is operating in 80 packets
2044 * per second mode, as it performs little internal filtering on
2045 * reported values.
2046 *
2047 * Using a rolling average helps to filter out jitter caused by
2048 * tiny finger movements.
2049 */
2050 if (count >= SYN_HIST_SIZE) {
2051 a = (history[(count - 2) % SYN_HIST_SIZE] +
2052 history[(count - 1) % SYN_HIST_SIZE]) / 2;
2053
2054 b = (value + history[(count - 1) % SYN_HIST_SIZE]) / 2;
2055
2056 rv = b - a;
2057
2058 /*
2059 * Don't report the movement if it's below a certain
2060 * threshold.
2061 */
2062 if (abs(rv) < synaptics_movement_threshold)
2063 rv = 0;
2064 } else
2065 rv = 0;
2066
2067 /*
2068 * Add the new value to the history buffer.
2069 */
2070 history[(count + 0) % SYN_HIST_SIZE] = value;
2071
2072 return (rv);
2073 }
2074
2075 /* Edge detection */
2076 #define SYN_EDGE_TOP 1
2077 #define SYN_EDGE_BOTTOM 2
2078 #define SYN_EDGE_LEFT 4
2079 #define SYN_EDGE_RIGHT 8
2080
2081 static inline int
2082 synaptics_check_edge(int x, int y)
2083 {
2084 int rv = 0;
2085
2086 if (x < synaptics_edge_left)
2087 rv |= SYN_EDGE_LEFT;
2088 else
2089 if (x > synaptics_edge_right)
2090 rv |= SYN_EDGE_RIGHT;
2091
2092 if (y < synaptics_edge_bottom)
2093 rv |= SYN_EDGE_BOTTOM;
2094 else
2095 if (y > synaptics_edge_top)
2096 rv |= SYN_EDGE_TOP;
2097
2098 return (rv);
2099 }
2100
2101 static inline int
2102 synaptics_edge_motion(struct synaptics_softc *sc, int delta, int dir)
2103 {
2104
2105 /*
2106 * When edge motion is enabled, synaptics_edge_motion_delta is
2107 * combined with the current delta, together with the direction
2108 * in which to simulate the motion. The result is added to
2109 * the delta derived from finger movement. This provides a smooth
2110 * transition from finger movement to edge motion.
2111 */
2112 delta = synaptics_edge_motion_delta + (dir * delta);
2113 if (delta < 0)
2114 return (0);
2115 if (delta > synaptics_edge_motion_delta)
2116 return (synaptics_edge_motion_delta);
2117 return (delta);
2118 }
2119
2120 static inline int
2121 synaptics_scale(int delta, int scale, int *remp)
2122 {
2123 int rv;
2124
2125 /*
2126 * Scale the raw delta in Synaptics coordinates (0-6143) into
2127 * something more reasonable by dividing the raw delta by a
2128 * scale factor. Any remainder from the previous scale result
2129 * is added to the current delta before scaling.
2130 * This prevents loss of resolution for very small/slow
2131 * movements of the finger.
2132 */
2133 delta += *remp;
2134 rv = delta / scale;
2135 *remp = delta % scale;
2136
2137 return (rv);
2138 }
2139
2140 static inline void
2141 synaptics_movement(struct synaptics_softc *sc, struct synaptics_packet *sp,
2142 int *dxp, int *dyp, int *dzp, int *sdxp, int *sdyp, int *sdzp)
2143 {
2144 int dx, dy, dz, sdx, sdy, sdz, edge;
2145
2146 dx = dy = dz = sdx = sdy = sdz = 0;
2147
2148 /*
2149 * Compute the next values of dx, dy, dz, sdx, sdy, sdz.
2150 */
2151 dx = synaptics_filter_policy(sc, 0,
2152 sc->history_x[SYN_PRIMARY_FINGER], sp->sp_x,
2153 sc->packet_count[SYN_PRIMARY_FINGER]);
2154 dy = synaptics_filter_policy(sc, 0,
2155 sc->history_y[SYN_PRIMARY_FINGER], sp->sp_y,
2156 sc->packet_count[SYN_PRIMARY_FINGER]);
2157 sc->packet_count[SYN_PRIMARY_FINGER]++;
2158
2159 if (sp->sp_finger_count > 1) {
2160 sdx = synaptics_filter_policy(sc, 1,
2161 sc->history_x[SYN_SECONDARY_FINGER], sp->sp_sx,
2162 sc->packet_count[SYN_SECONDARY_FINGER]);
2163 sdy = synaptics_filter_policy(sc, 1,
2164 sc->history_y[SYN_SECONDARY_FINGER], sp->sp_sy,
2165 sc->packet_count[SYN_SECONDARY_FINGER]);
2166 sc->packet_count[SYN_SECONDARY_FINGER]++;
2167 DPRINTF(10, sc, "synaptics_movement: dx %d dy %d sdx %d sdy %d\n",
2168 dx, dy, sdx, sdy);
2169 }
2170
2171 /*
2172 * If we're dealing with a drag gesture, and the finger moves to
2173 * the edge of the touchpad, apply edge motion emulation if it
2174 * is enabled.
2175 */
2176 if (synaptics_edge_motion_delta && SYN_IS_DRAG(sc->gesture_type)) {
2177 edge = synaptics_check_edge(sp->sp_x, sp->sp_y);
2178
2179 if (edge & SYN_EDGE_LEFT)
2180 dx -= synaptics_edge_motion(sc, dx, 1);
2181 if (edge & SYN_EDGE_RIGHT)
2182 dx += synaptics_edge_motion(sc, dx, -1);
2183 if (edge & SYN_EDGE_BOTTOM)
2184 dy -= synaptics_edge_motion(sc, dy, 1);
2185 if (edge & SYN_EDGE_TOP)
2186 dy += synaptics_edge_motion(sc, dy, -1);
2187
2188 if (sp->sp_finger_count > 1) {
2189 edge = synaptics_check_edge(sp->sp_sx, sp->sp_sy);
2190
2191 if (edge & SYN_EDGE_LEFT)
2192 sdx -= synaptics_edge_motion(sc, sdx, 1);
2193 if (edge & SYN_EDGE_RIGHT)
2194 sdx += synaptics_edge_motion(sc, sdx, -1);
2195 if (edge & SYN_EDGE_BOTTOM)
2196 sdy -= synaptics_edge_motion(sc, sdy, 1);
2197 if (edge & SYN_EDGE_TOP)
2198 sdy += synaptics_edge_motion(sc, sdy, -1);
2199 }
2200 }
2201
2202 /*
2203 * Apply scaling to the deltas
2204 */
2205 dx = synaptics_scale(dx, synaptics_scale_x,
2206 &sc->rem_x[SYN_PRIMARY_FINGER]);
2207 dy = synaptics_scale(dy, synaptics_scale_y,
2208 &sc->rem_y[SYN_PRIMARY_FINGER]);
2209 dz = synaptics_scale(dz, synaptics_scale_z,
2210 &sc->rem_z[SYN_PRIMARY_FINGER]);
2211
2212 if (sp->sp_finger_count > 1) {
2213 sdx = synaptics_scale(sdx, synaptics_scale_x,
2214 &sc->rem_x[SYN_SECONDARY_FINGER]);
2215 sdy = synaptics_scale(sdy, synaptics_scale_y,
2216 &sc->rem_y[SYN_SECONDARY_FINGER]);
2217 sdz = synaptics_scale(sdz, synaptics_scale_z,
2218 &sc->rem_z[SYN_SECONDARY_FINGER]);
2219
2220 DPRINTF(10, sc,
2221 "synaptics_movement 2: dx %d dy %d sdx %d sdy %d\n",
2222 dx, dy, sdx, sdy);
2223 }
2224
2225 /*
2226 * Clamp deltas to specified maximums.
2227 */
2228 if (abs(dx) > synaptics_max_speed_x)
2229 dx = ((dx >= 0)? 1 : -1) * synaptics_max_speed_x;
2230 if (abs(dy) > synaptics_max_speed_y)
2231 dy = ((dy >= 0)? 1 : -1) * synaptics_max_speed_y;
2232 if (abs(dz) > synaptics_max_speed_z)
2233 dz = ((dz >= 0)? 1 : -1) * synaptics_max_speed_z;
2234
2235 if (sp->sp_finger_count > 1) {
2236 if (abs(sdx) > synaptics_max_speed_x)
2237 sdx = ((sdx >= 0)? 1 : -1) * synaptics_max_speed_x;
2238 if (abs(dy) > synaptics_max_speed_y)
2239 sdy = ((sdy >= 0)? 1 : -1) * synaptics_max_speed_y;
2240 if (abs(sdz) > synaptics_max_speed_z)
2241 sdz = ((sdz >= 0)? 1 : -1) * synaptics_max_speed_z;
2242 }
2243
2244 *dxp = dx;
2245 *dyp = dy;
2246 *dzp = dz;
2247 *sdxp = sdx;
2248 *sdyp = sdy;
2249 *sdzp = sdz;
2250
2251 }
2252
2253 static void
2254 pms_synaptics_process_packet(struct pms_softc *psc, struct synaptics_packet *sp)
2255 {
2256 struct synaptics_softc *sc = &psc->u.synaptics;
2257 int dx, dy, dz, sdx, sdy, sdz;
2258 int fingers, palm, buttons, changed;
2259 int s;
2260
2261 sdx = sdy = sdz = 0;
2262
2263 /*
2264 * Do Z-axis emulation using up/down buttons if required.
2265 * Note that the pad will send a one second burst of packets
2266 * when an up/down button is pressed and held. At the moment
2267 * we don't deal with auto-repeat, so convert the burst into
2268 * a one-shot.
2269 */
2270 dz = 0;
2271 if (synaptics_up_down_emul == 2) {
2272 if (sc->up_down == 0) {
2273 if (sp->sp_up && sp->sp_down) {
2274 sp->sp_middle = 1;
2275 } else if (sp->sp_up) {
2276 dz = -synaptics_up_down_motion_delta;
2277 } else if (sp->sp_down) {
2278 dz = synaptics_up_down_motion_delta;
2279 }
2280 }
2281
2282 sc->up_down = sp->sp_up | sp->sp_down;
2283 sp->sp_up = sp->sp_down = 0;
2284 }
2285
2286 /*
2287 * Determine whether or not a finger is on the pad.
2288 * On some pads, this will return the number of fingers
2289 * detected.
2290 */
2291 fingers = synaptics_finger_detect(sc, sp, &palm);
2292
2293 /*
2294 * Do gesture processing only if we didn't detect a palm.
2295 */
2296 if (palm == 0)
2297 synaptics_gesture_detect(sc, sp, fingers);
2298 else
2299 sc->gesture_type = sc->gesture_buttons = 0;
2300
2301 /*
2302 * Determine what buttons to report
2303 */
2304 buttons = (sp->sp_left ? 0x1 : 0) |
2305 (sp->sp_middle ? 0x2 : 0) |
2306 (sp->sp_right ? 0x4 : 0) |
2307 (sp->sp_up ? 0x8 : 0) |
2308 (sp->sp_down ? 0x10 : 0);
2309 changed = buttons ^ (psc->buttons & 0x1f);
2310 psc->buttons ^= changed;
2311
2312 sc->prev_fingers = fingers;
2313
2314 /*
2315 * Do movement processing IFF we have a single finger and no palm or
2316 * a secondary finger and no palm.
2317 */
2318 if (palm == 0 && synaptics_movement_enable) {
2319 if (fingers > 0) {
2320 synaptics_movement(sc, sp, &dx, &dy, &dz, &sdx, &sdy,
2321 &sdz);
2322
2323 /*
2324 * Check if there are two fingers, if there are then
2325 * check if we have a clickpad, if we do then we
2326 * don't scroll iff one of the fingers is in the
2327 * button region. Otherwise interpret as a scroll
2328 */
2329 if (sp->sp_finger_count >= 2 && sc->gesture_type == 0 ) {
2330 if (!(sc->flags & SYN_FLAG_HAS_ONE_BUTTON_CLICKPAD) ||
2331 ((sc->flags & SYN_FLAG_HAS_ONE_BUTTON_CLICKPAD) &&
2332 (sp->sp_y > synaptics_button_boundary) &&
2333 (sp->sp_sy > synaptics_button_boundary))) {
2334 s = spltty();
2335 wsmouse_precision_scroll(
2336 psc->sc_wsmousedev, dx, dy);
2337 splx(s);
2338 return;
2339 }
2340 }
2341
2342 /*
2343 * Allow user to turn off movements in the button
2344 * region of a click pad.
2345 */
2346 if (sc->flags & SYN_FLAG_HAS_ONE_BUTTON_CLICKPAD) {
2347 if ((sp->sp_y < synaptics_button_boundary) &&
2348 (!synaptics_button_region_movement)) {
2349 dx = dy = dz = 0;
2350 }
2351
2352 if ((sp->sp_sy < synaptics_button_boundary) &&
2353 (!synaptics_button_region_movement)) {
2354 sdx = sdy = sdz = 0;
2355 }
2356 }
2357
2358 /* Now work out which finger to report, just
2359 * go with the one that has moved the most.
2360 */
2361 if ((abs(dx) + abs(dy) + abs(dz)) <
2362 (abs(sdx) + abs(sdy) + abs(sdz))) {
2363 /* secondary finger wins */
2364 dx = sdx;
2365 dy = sdy;
2366 dz = sdz;
2367 }
2368 } else {
2369 /*
2370 * No valid finger. Therefore no movement.
2371 */
2372 sc->rem_x[SYN_PRIMARY_FINGER] = 0;
2373 sc->rem_y[SYN_PRIMARY_FINGER] = 0;
2374 sc->rem_x[SYN_SECONDARY_FINGER] = 0;
2375 sc->rem_y[SYN_SECONDARY_FINGER] = 0;
2376 dx = dy = 0;
2377
2378 sc->packet_count[SYN_PRIMARY_FINGER] = 0;
2379 sc->packet_count[SYN_SECONDARY_FINGER] = 0;
2380 }
2381 } else {
2382 /*
2383 * No valid finger. Therefore no movement.
2384 */
2385 sc->rem_x[SYN_PRIMARY_FINGER] = 0;
2386 sc->rem_y[SYN_PRIMARY_FINGER] = 0;
2387 sc->rem_z[SYN_PRIMARY_FINGER] = 0;
2388 dx = dy = dz = 0;
2389 }
2390
2391 DPRINTF(10, sc,
2392 "pms_synaptics_process_packet: dx %d dy %d dz %d sdx %d sdy %d sdz %d\n",
2393 dx, dy, dz, sdx, sdy, sdz);
2394
2395 /*
2396 * Pass the final results up to wsmouse_input() if necessary.
2397 */
2398 if (dx || dy || dz || changed) {
2399 buttons = (psc->buttons & 0x1f) | ((psc->buttons >> 5) & 0x7);
2400 s = spltty();
2401 wsmouse_input(psc->sc_wsmousedev,
2402 buttons,
2403 dx, dy, dz, 0,
2404 WSMOUSE_INPUT_DELTA);
2405 splx(s);
2406 }
2407 }
2408