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