synaptics.c revision 1.25.2.1 1 /* $NetBSD: synaptics.c,v 1.25.2.1 2011/06/06 09:08:30 jruoho 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.25.2.1 2011/06/06 09:08:30 jruoho 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 u_char sp_w; /* W (contact patch width) */
83 char sp_left; /* Left mouse button status */
84 char sp_right; /* Right mouse button status */
85 char sp_middle; /* Middle button status (possibly emulated) */
86 char sp_up; /* Up button status */
87 char sp_down; /* Down button status */
88 };
89
90 static int pms_synaptics_send_command(pckbport_tag_t, pckbport_slot_t, u_char);
91 static void pms_synaptics_input(void *, int);
92 static void pms_synaptics_process_packet(struct pms_softc *,
93 struct synaptics_packet *);
94 static void pms_sysctl_synaptics(struct sysctllog **);
95 static int pms_sysctl_synaptics_verify(SYSCTLFN_ARGS);
96
97 /* Controled by sysctl. */
98 static int synaptics_up_down_emul = 2;
99 static int synaptics_up_down_motion_delta = 1;
100 static int synaptics_gesture_move = 200;
101 static int synaptics_gesture_length = 20;
102 static int synaptics_edge_left = SYNAPTICS_EDGE_LEFT;
103 static int synaptics_edge_right = SYNAPTICS_EDGE_RIGHT;
104 static int synaptics_edge_top = SYNAPTICS_EDGE_TOP;
105 static int synaptics_edge_bottom = SYNAPTICS_EDGE_BOTTOM;
106 static int synaptics_edge_motion_delta = 32;
107 static u_int synaptics_finger_high = SYNAPTICS_FINGER_LIGHT + 5;
108 static u_int synaptics_finger_low = SYNAPTICS_FINGER_LIGHT - 10;
109 static int synaptics_two_fingers_emul = 0;
110 static int synaptics_scale_x = 16;
111 static int synaptics_scale_y = 16;
112 static int synaptics_max_speed_x = 32;
113 static int synaptics_max_speed_y = 32;
114 static int synaptics_movement_threshold = 4;
115
116 /* Sysctl nodes. */
117 static int synaptics_up_down_emul_nodenum;
118 static int synaptics_up_down_motion_delta_nodenum;
119 static int synaptics_gesture_move_nodenum;
120 static int synaptics_gesture_length_nodenum;
121 static int synaptics_edge_left_nodenum;
122 static int synaptics_edge_right_nodenum;
123 static int synaptics_edge_top_nodenum;
124 static int synaptics_edge_bottom_nodenum;
125 static int synaptics_edge_motion_delta_nodenum;
126 static int synaptics_finger_high_nodenum;
127 static int synaptics_finger_low_nodenum;
128 static int synaptics_two_fingers_emul_nodenum;
129 static int synaptics_scale_x_nodenum;
130 static int synaptics_scale_y_nodenum;
131 static int synaptics_max_speed_x_nodenum;
132 static int synaptics_max_speed_y_nodenum;
133 static int synaptics_movement_threshold_nodenum;
134
135 int
136 pms_synaptics_probe_init(void *vsc)
137 {
138 struct pms_softc *psc = vsc;
139 struct synaptics_softc *sc = &psc->u.synaptics;
140 u_char cmd[2], resp[3];
141 int res, ver_minor, ver_major;
142 struct sysctllog *clog = NULL;
143
144 res = pms_synaptics_send_command(psc->sc_kbctag, psc->sc_kbcslot,
145 SYNAPTICS_IDENTIFY_TOUCHPAD);
146 cmd[0] = PMS_SEND_DEV_STATUS;
147 res |= pckbport_poll_cmd(psc->sc_kbctag, psc->sc_kbcslot, cmd, 1, 3,
148 resp, 0);
149 if (res) {
150 aprint_debug_dev(psc->sc_dev,
151 "synaptics_probe: Identify Touchpad error.\n");
152 /*
153 * Reset device in case the probe confused it.
154 */
155 doreset:
156 cmd[0] = PMS_RESET;
157 (void) pckbport_poll_cmd(psc->sc_kbctag, psc->sc_kbcslot, cmd,
158 1, 2, resp, 1);
159 return (res);
160 }
161
162 if (resp[1] != SYNAPTICS_MAGIC_BYTE) {
163 aprint_debug_dev(psc->sc_dev,
164 "synaptics_probe: Not synaptics.\n");
165 res = 1;
166 goto doreset;
167 }
168
169 sc->flags = 0;
170
171 /* Check for minimum version and print a nice message. */
172 ver_major = resp[2] & 0x0f;
173 ver_minor = resp[0];
174 aprint_normal_dev(psc->sc_dev, "Synaptics touchpad version %d.%d\n",
175 ver_major, ver_minor);
176 if (ver_major * 10 + ver_minor < SYNAPTICS_MIN_VERSION) {
177 /* No capability query support. */
178 sc->caps = 0;
179 goto done;
180 }
181
182 /* Query the hardware capabilities. */
183 res = pms_synaptics_send_command(psc->sc_kbctag, psc->sc_kbcslot,
184 SYNAPTICS_READ_CAPABILITIES);
185 cmd[0] = PMS_SEND_DEV_STATUS;
186 res |= pckbport_poll_cmd(psc->sc_kbctag, psc->sc_kbcslot, cmd, 1, 3,
187 resp, 0);
188 if (res) {
189 /* Hmm, failed to get capabilites. */
190 aprint_error_dev(psc->sc_dev,
191 "synaptics_probe: Failed to query capabilities.\n");
192 goto doreset;
193 }
194
195 sc->caps = (resp[0] << 8) | resp[2];
196
197 if (sc->caps & SYNAPTICS_CAP_MBUTTON)
198 sc->flags |= SYN_FLAG_HAS_MIDDLE_BUTTON;
199
200 if (sc->caps & SYNAPTICS_CAP_4BUTTON)
201 sc->flags |= SYN_FLAG_HAS_BUTTONS_4_5;
202
203 if (sc->caps & SYNAPTICS_CAP_EXTENDED) {
204 aprint_debug_dev(psc->sc_dev,
205 "synaptics_probe: Capabilities 0x%04x.\n", sc->caps);
206 if (sc->caps & SYNAPTICS_CAP_PASSTHROUGH)
207 sc->flags |= SYN_FLAG_HAS_PASSTHROUGH;
208
209 if (sc->caps & SYNAPTICS_CAP_PALMDETECT)
210 sc->flags |= SYN_FLAG_HAS_PALM_DETECT;
211
212 if (sc->caps & SYNAPTICS_CAP_MULTIDETECT)
213 sc->flags |= SYN_FLAG_HAS_MULTI_FINGER;
214
215 /* Ask about extra buttons to detect up/down. */
216 if (sc->caps & SYNAPTICS_CAP_EXTNUM) {
217 res = pms_synaptics_send_command(psc->sc_kbctag,
218 psc->sc_kbcslot, SYNAPTICS_EXTENDED_QUERY);
219 cmd[0] = PMS_SEND_DEV_STATUS;
220 res |= pckbport_poll_cmd(psc->sc_kbctag,
221 psc->sc_kbcslot, cmd, 1, 3, resp, 0);
222 if (res == 0)
223 aprint_debug_dev(psc->sc_dev,
224 "synaptics_probe: Extended "
225 "Capabilities 0x%02x.\n", resp[1]);
226 if (!res && (resp[1] >> 4) >= 2) {
227 /* Yes. */
228 sc->flags |= SYN_FLAG_HAS_UP_DOWN_BUTTONS;
229 }
230 }
231 }
232
233 if (sc->flags) {
234 const char comma[] = ", ";
235 const char *sep = "";
236 aprint_normal_dev(psc->sc_dev, "");
237 if (sc->flags & SYN_FLAG_HAS_PASSTHROUGH) {
238 aprint_normal("%sPassthrough", sep);
239 sep = comma;
240 }
241 if (sc->flags & SYN_FLAG_HAS_MIDDLE_BUTTON) {
242 aprint_normal("%sMiddle button", sep);
243 sep = comma;
244 }
245 if (sc->flags & SYN_FLAG_HAS_BUTTONS_4_5) {
246 aprint_normal("%sButtons 4/5", sep);
247 sep = comma;
248 }
249 if (sc->flags & SYN_FLAG_HAS_UP_DOWN_BUTTONS) {
250 aprint_normal("%sUp/down buttons", sep);
251 sep = comma;
252 }
253 if (sc->flags & SYN_FLAG_HAS_PALM_DETECT) {
254 aprint_normal("%sPalm detect", sep);
255 sep = comma;
256 }
257 if (sc->flags & SYN_FLAG_HAS_MULTI_FINGER)
258 aprint_normal("%sMulti-finger", sep);
259
260 aprint_normal("\n");
261 }
262
263 done:
264 pms_sysctl_synaptics(&clog);
265 pckbport_set_inputhandler(psc->sc_kbctag, psc->sc_kbcslot,
266 pms_synaptics_input, psc, device_xname(psc->sc_dev));
267
268 return (0);
269 }
270
271 void
272 pms_synaptics_enable(void *vsc)
273 {
274 struct pms_softc *psc = vsc;
275 struct synaptics_softc *sc = &psc->u.synaptics;
276 u_char cmd[2], resp[2];
277 int res;
278
279 if (sc->flags & SYN_FLAG_HAS_PASSTHROUGH) {
280 /*
281 * Extended capability probes can confuse the passthrough device;
282 * reset the touchpad now to cure that.
283 */
284 cmd[0] = PMS_RESET;
285 res = pckbport_poll_cmd(psc->sc_kbctag, psc->sc_kbcslot, cmd,
286 1, 2, resp, 1);
287 }
288
289 /*
290 * Enable Absolute mode with W (width) reporting, and set
291 * the packet rate to maximum (80 packets per second).
292 */
293 res = pms_synaptics_send_command(psc->sc_kbctag, psc->sc_kbcslot,
294 SYNAPTICS_MODE_ABSOLUTE | SYNAPTICS_MODE_W | SYNAPTICS_MODE_RATE);
295 cmd[0] = PMS_SET_SAMPLE;
296 cmd[1] = SYNAPTICS_CMD_SET_MODE2;
297 res |= pckbport_enqueue_cmd(psc->sc_kbctag, psc->sc_kbcslot, cmd, 2, 0,
298 1, NULL);
299 sc->up_down = 0;
300 sc->prev_fingers = 0;
301 sc->gesture_start_x = sc->gesture_start_y = 0;
302 sc->gesture_start_packet = 0;
303 sc->gesture_tap_packet = 0;
304 sc->gesture_type = 0;
305 sc->gesture_buttons = 0;
306 sc->rem_x = sc->rem_y = 0;
307 sc->movement_history = 0;
308 if (res) {
309 aprint_error_dev(psc->sc_dev,
310 "synaptics_enable: Error enabling device.\n");
311 }
312 }
313
314 void
315 pms_synaptics_resume(void *vsc)
316 {
317 struct pms_softc *psc = vsc;
318 unsigned char cmd[1],resp[2] = { 0,0 };
319 int res;
320
321 cmd[0] = PMS_RESET;
322 res = pckbport_poll_cmd(psc->sc_kbctag, psc->sc_kbcslot, cmd, 1, 2,
323 resp, 1);
324 aprint_debug_dev(psc->sc_dev,
325 "pms_synaptics_resume: reset on resume %d 0x%02x 0x%02x\n",
326 res, resp[0], resp[1]);
327 }
328
329 static void
330 pms_sysctl_synaptics(struct sysctllog **clog)
331 {
332 int rc, root_num;
333 const struct sysctlnode *node;
334
335 if ((rc = sysctl_createv(clog, 0, NULL, NULL,
336 CTLFLAG_PERMANENT, CTLTYPE_NODE, "hw", NULL,
337 NULL, 0, NULL, 0, CTL_HW, CTL_EOL)) != 0)
338 goto err;
339
340 if ((rc = sysctl_createv(clog, 0, NULL, &node,
341 CTLFLAG_PERMANENT, CTLTYPE_NODE, "synaptics",
342 SYSCTL_DESCR("Synaptics touchpad controls"),
343 NULL, 0, NULL, 0, CTL_HW, CTL_CREATE, CTL_EOL)) != 0)
344 goto err;
345
346 root_num = node->sysctl_num;
347
348 if ((rc = sysctl_createv(clog, 0, NULL, &node,
349 CTLFLAG_PERMANENT | CTLFLAG_READWRITE,
350 CTLTYPE_INT, "up_down_emulation",
351 SYSCTL_DESCR("Middle button/Z-axis emulation with up/down buttons"),
352 pms_sysctl_synaptics_verify, 0,
353 &synaptics_up_down_emul,
354 0, CTL_HW, root_num, CTL_CREATE,
355 CTL_EOL)) != 0)
356 goto err;
357
358 synaptics_up_down_emul_nodenum = node->sysctl_num;
359
360 if ((rc = sysctl_createv(clog, 0, NULL, &node,
361 CTLFLAG_PERMANENT | CTLFLAG_READWRITE,
362 CTLTYPE_INT, "up_down_motion_delta",
363 SYSCTL_DESCR("Up/down button Z-axis emulation rate"),
364 pms_sysctl_synaptics_verify, 0,
365 &synaptics_up_down_motion_delta,
366 0, CTL_HW, root_num, CTL_CREATE,
367 CTL_EOL)) != 0)
368 goto err;
369
370 synaptics_up_down_motion_delta_nodenum = node->sysctl_num;
371
372 if ((rc = sysctl_createv(clog, 0, NULL, &node,
373 CTLFLAG_PERMANENT | CTLFLAG_READWRITE,
374 CTLTYPE_INT, "gesture_move",
375 SYSCTL_DESCR("Movement greater than this between taps cancels gesture"),
376 pms_sysctl_synaptics_verify, 0,
377 &synaptics_gesture_move,
378 0, CTL_HW, root_num, CTL_CREATE,
379 CTL_EOL)) != 0)
380 goto err;
381
382 synaptics_gesture_move_nodenum = node->sysctl_num;
383
384 if ((rc = sysctl_createv(clog, 0, NULL, &node,
385 CTLFLAG_PERMANENT | CTLFLAG_READWRITE,
386 CTLTYPE_INT, "gesture_length",
387 SYSCTL_DESCR("Time period in which tap is recognised as a gesture"),
388 pms_sysctl_synaptics_verify, 0,
389 &synaptics_gesture_length,
390 0, CTL_HW, root_num, CTL_CREATE,
391 CTL_EOL)) != 0)
392 goto err;
393
394 synaptics_gesture_length_nodenum = node->sysctl_num;
395
396 if ((rc = sysctl_createv(clog, 0, NULL, &node,
397 CTLFLAG_PERMANENT | CTLFLAG_READWRITE,
398 CTLTYPE_INT, "edge_left",
399 SYSCTL_DESCR("Define left edge of touchpad"),
400 pms_sysctl_synaptics_verify, 0,
401 &synaptics_edge_left,
402 0, CTL_HW, root_num, CTL_CREATE,
403 CTL_EOL)) != 0)
404 goto err;
405
406 synaptics_edge_left_nodenum = node->sysctl_num;
407
408 if ((rc = sysctl_createv(clog, 0, NULL, &node,
409 CTLFLAG_PERMANENT | CTLFLAG_READWRITE,
410 CTLTYPE_INT, "edge_right",
411 SYSCTL_DESCR("Define right edge of touchpad"),
412 pms_sysctl_synaptics_verify, 0,
413 &synaptics_edge_right,
414 0, CTL_HW, root_num, CTL_CREATE,
415 CTL_EOL)) != 0)
416 goto err;
417
418 synaptics_edge_right_nodenum = node->sysctl_num;
419
420 if ((rc = sysctl_createv(clog, 0, NULL, &node,
421 CTLFLAG_PERMANENT | CTLFLAG_READWRITE,
422 CTLTYPE_INT, "edge_top",
423 SYSCTL_DESCR("Define top edge of touchpad"),
424 pms_sysctl_synaptics_verify, 0,
425 &synaptics_edge_top,
426 0, CTL_HW, root_num, CTL_CREATE,
427 CTL_EOL)) != 0)
428 goto err;
429
430 synaptics_edge_top_nodenum = node->sysctl_num;
431
432 if ((rc = sysctl_createv(clog, 0, NULL, &node,
433 CTLFLAG_PERMANENT | CTLFLAG_READWRITE,
434 CTLTYPE_INT, "edge_bottom",
435 SYSCTL_DESCR("Define bottom edge of touchpad"),
436 pms_sysctl_synaptics_verify, 0,
437 &synaptics_edge_bottom,
438 0, CTL_HW, root_num, CTL_CREATE,
439 CTL_EOL)) != 0)
440 goto err;
441
442 synaptics_edge_bottom_nodenum = node->sysctl_num;
443
444 if ((rc = sysctl_createv(clog, 0, NULL, &node,
445 CTLFLAG_PERMANENT | CTLFLAG_READWRITE,
446 CTLTYPE_INT, "edge_motion_delta",
447 SYSCTL_DESCR("Define edge motion rate"),
448 pms_sysctl_synaptics_verify, 0,
449 &synaptics_edge_motion_delta,
450 0, CTL_HW, root_num, CTL_CREATE,
451 CTL_EOL)) != 0)
452 goto err;
453
454 synaptics_edge_motion_delta_nodenum = node->sysctl_num;
455
456 if ((rc = sysctl_createv(clog, 0, NULL, &node,
457 CTLFLAG_PERMANENT | CTLFLAG_READWRITE,
458 CTLTYPE_INT, "finger_high",
459 SYSCTL_DESCR("Define finger applied pressure threshold"),
460 pms_sysctl_synaptics_verify, 0,
461 &synaptics_finger_high,
462 0, CTL_HW, root_num, CTL_CREATE,
463 CTL_EOL)) != 0)
464 goto err;
465
466 synaptics_finger_high_nodenum = node->sysctl_num;
467
468 if ((rc = sysctl_createv(clog, 0, NULL, &node,
469 CTLFLAG_PERMANENT | CTLFLAG_READWRITE,
470 CTLTYPE_INT, "finger_low",
471 SYSCTL_DESCR("Define finger removed pressure threshold"),
472 pms_sysctl_synaptics_verify, 0,
473 &synaptics_finger_low,
474 0, CTL_HW, root_num, CTL_CREATE,
475 CTL_EOL)) != 0)
476 goto err;
477
478 synaptics_finger_low_nodenum = node->sysctl_num;
479
480 if ((rc = sysctl_createv(clog, 0, NULL, &node,
481 CTLFLAG_PERMANENT | CTLFLAG_READWRITE,
482 CTLTYPE_INT, "two_fingers_emulation",
483 SYSCTL_DESCR("Map two fingers to middle button"),
484 pms_sysctl_synaptics_verify, 0,
485 &synaptics_two_fingers_emul,
486 0, CTL_HW, root_num, CTL_CREATE,
487 CTL_EOL)) != 0)
488 goto err;
489
490 synaptics_two_fingers_emul_nodenum = node->sysctl_num;
491
492 if ((rc = sysctl_createv(clog, 0, NULL, &node,
493 CTLFLAG_PERMANENT | CTLFLAG_READWRITE,
494 CTLTYPE_INT, "scale_x",
495 SYSCTL_DESCR("Horizontal movement scale factor"),
496 pms_sysctl_synaptics_verify, 0,
497 &synaptics_scale_x,
498 0, CTL_HW, root_num, CTL_CREATE,
499 CTL_EOL)) != 0)
500 goto err;
501
502 synaptics_scale_x_nodenum = node->sysctl_num;
503
504 if ((rc = sysctl_createv(clog, 0, NULL, &node,
505 CTLFLAG_PERMANENT | CTLFLAG_READWRITE,
506 CTLTYPE_INT, "scale_y",
507 SYSCTL_DESCR("Vertical movement scale factor"),
508 pms_sysctl_synaptics_verify, 0,
509 &synaptics_scale_y,
510 0, CTL_HW, root_num, CTL_CREATE,
511 CTL_EOL)) != 0)
512 goto err;
513
514 synaptics_scale_y_nodenum = node->sysctl_num;
515
516 if ((rc = sysctl_createv(clog, 0, NULL, &node,
517 CTLFLAG_PERMANENT | CTLFLAG_READWRITE,
518 CTLTYPE_INT, "max_speed_x",
519 SYSCTL_DESCR("Horizontal movement maximum speed"),
520 pms_sysctl_synaptics_verify, 0,
521 &synaptics_max_speed_x,
522 0, CTL_HW, root_num, CTL_CREATE,
523 CTL_EOL)) != 0)
524 goto err;
525
526 synaptics_max_speed_x_nodenum = node->sysctl_num;
527
528 if ((rc = sysctl_createv(clog, 0, NULL, &node,
529 CTLFLAG_PERMANENT | CTLFLAG_READWRITE,
530 CTLTYPE_INT, "max_speed_y",
531 SYSCTL_DESCR("Vertical movement maximum speed"),
532 pms_sysctl_synaptics_verify, 0,
533 &synaptics_max_speed_y,
534 0, CTL_HW, root_num, CTL_CREATE,
535 CTL_EOL)) != 0)
536 goto err;
537
538 synaptics_max_speed_y_nodenum = node->sysctl_num;
539
540 if ((rc = sysctl_createv(clog, 0, NULL, &node,
541 CTLFLAG_PERMANENT | CTLFLAG_READWRITE,
542 CTLTYPE_INT, "movement_threshold",
543 SYSCTL_DESCR("Minimum reported movement threshold"),
544 pms_sysctl_synaptics_verify, 0,
545 &synaptics_movement_threshold,
546 0, CTL_HW, root_num, CTL_CREATE,
547 CTL_EOL)) != 0)
548 goto err;
549
550 synaptics_movement_threshold_nodenum = node->sysctl_num;
551 return;
552
553 err:
554 aprint_error("%s: sysctl_createv failed (rc = %d)\n", __func__, rc);
555 }
556
557 static int
558 pms_sysctl_synaptics_verify(SYSCTLFN_ARGS)
559 {
560 int error, t;
561 struct sysctlnode node;
562
563 node = *rnode;
564 t = *(int *)rnode->sysctl_data;
565 node.sysctl_data = &t;
566 error = sysctl_lookup(SYSCTLFN_CALL(&node));
567 if (error || newp == NULL)
568 return error;
569
570 /* Sanity check the params. */
571 if (node.sysctl_num == synaptics_up_down_emul_nodenum ||
572 node.sysctl_num == synaptics_two_fingers_emul_nodenum) {
573 if (t < 0 || t > 2)
574 return (EINVAL);
575 } else
576 if (node.sysctl_num == synaptics_gesture_length_nodenum ||
577 node.sysctl_num == synaptics_edge_motion_delta_nodenum ||
578 node.sysctl_num == synaptics_up_down_motion_delta_nodenum) {
579 if (t < 0)
580 return (EINVAL);
581 } else
582 if (node.sysctl_num == synaptics_edge_left_nodenum ||
583 node.sysctl_num == synaptics_edge_bottom_nodenum) {
584 if (t < 0 || t > (SYNAPTICS_EDGE_MAX / 2))
585 return (EINVAL);
586 } else
587 if (node.sysctl_num == synaptics_edge_right_nodenum ||
588 node.sysctl_num == synaptics_edge_top_nodenum) {
589 if (t < (SYNAPTICS_EDGE_MAX / 2))
590 return (EINVAL);
591 } else
592 if (node.sysctl_num == synaptics_scale_x_nodenum ||
593 node.sysctl_num == synaptics_scale_y_nodenum) {
594 if (t < 1 || t > (SYNAPTICS_EDGE_MAX / 4))
595 return (EINVAL);
596 } else
597 if (node.sysctl_num == synaptics_finger_high_nodenum) {
598 if (t < 0 || t > SYNAPTICS_FINGER_PALM ||
599 t < synaptics_finger_low)
600 return (EINVAL);
601 } else
602 if (node.sysctl_num == synaptics_finger_low_nodenum) {
603 if (t < 0 || t > SYNAPTICS_FINGER_PALM ||
604 t > synaptics_finger_high)
605 return (EINVAL);
606 } else
607 if (node.sysctl_num == synaptics_gesture_move_nodenum ||
608 node.sysctl_num == synaptics_movement_threshold_nodenum) {
609 if (t < 0 || t > (SYNAPTICS_EDGE_MAX / 4))
610 return (EINVAL);
611 } else
612 return (EINVAL);
613
614 *(int *)rnode->sysctl_data = t;
615
616 return (0);
617 }
618
619 static int
620 pms_synaptics_send_command(pckbport_tag_t tag, pckbport_slot_t slot,
621 u_char syn_cmd)
622 {
623 u_char cmd[2];
624 int res;
625
626 cmd[0] = PMS_SET_SCALE11;
627 res = pckbport_poll_cmd(tag, slot, cmd, 1, 0, NULL, 0);
628
629 /*
630 * Need to send 4 Set Resolution commands, with the argument
631 * encoded in the bottom most 2 bits.
632 */
633 cmd[0] = PMS_SET_RES;
634 cmd[1] = syn_cmd >> 6;
635 res |= pckbport_poll_cmd(tag, slot, cmd, 2, 0, NULL, 0);
636
637 cmd[0] = PMS_SET_RES;
638 cmd[1] = (syn_cmd & 0x30) >> 4;
639 res |= pckbport_poll_cmd(tag, slot, cmd, 2, 0, NULL, 0);
640
641 cmd[0] = PMS_SET_RES;
642 cmd[1] = (syn_cmd & 0x0c) >> 2;
643 res |= pckbport_poll_cmd(tag, slot, cmd, 2, 0, NULL, 0);
644
645 cmd[0] = PMS_SET_RES;
646 cmd[1] = (syn_cmd & 0x03);
647 res |= pckbport_poll_cmd(tag, slot, cmd, 2, 0, NULL, 0);
648
649 return (res);
650 }
651
652 /* Masks for the first byte of a packet */
653 #define PMS_LBUTMASK 0x01
654 #define PMS_RBUTMASK 0x02
655 #define PMS_MBUTMASK 0x04
656
657 static void
658 pms_synaptics_parse(struct pms_softc *psc)
659 {
660 struct synaptics_softc *sc = &psc->u.synaptics;
661 struct synaptics_packet sp;
662
663 /* Absolute X/Y coordinates of finger */
664 sp.sp_x = psc->packet[4] + ((psc->packet[1] & 0x0f) << 8) +
665 ((psc->packet[3] & 0x10) << 8);
666 sp.sp_y = psc->packet[5] + ((psc->packet[1] & 0xf0) << 4) +
667 ((psc->packet[3] & 0x20) << 7);
668
669 /* Pressure */
670 sp.sp_z = psc->packet[2];
671
672 /* Width of finger */
673 sp.sp_w = ((psc->packet[0] & 0x30) >> 2) +
674 ((psc->packet[0] & 0x04) >> 1) +
675 ((psc->packet[3] & 0x04) >> 2);
676
677 /* Left/Right button handling. */
678 sp.sp_left = psc->packet[0] & PMS_LBUTMASK;
679 sp.sp_right = psc->packet[0] & PMS_RBUTMASK;
680
681 /* Up/Down buttons. */
682 if (sc->flags & SYN_FLAG_HAS_BUTTONS_4_5) {
683 /* Old up/down buttons. */
684 sp.sp_up = sp.sp_left ^
685 (psc->packet[3] & PMS_LBUTMASK);
686 sp.sp_down = sp.sp_right ^
687 (psc->packet[3] & PMS_RBUTMASK);
688 } else
689 if (sc->flags & SYN_FLAG_HAS_UP_DOWN_BUTTONS &&
690 ((psc->packet[0] & PMS_RBUTMASK) ^
691 (psc->packet[3] & PMS_RBUTMASK))) {
692 /* New up/down button. */
693 sp.sp_up = psc->packet[4] & SYN_1BUTMASK;
694 sp.sp_down = psc->packet[5] & SYN_2BUTMASK;
695 } else {
696 sp.sp_up = 0;
697 sp.sp_down = 0;
698 }
699
700 /* Middle button. */
701 if (sc->flags & SYN_FLAG_HAS_MIDDLE_BUTTON) {
702 /* Old style Middle Button. */
703 sp.sp_middle = (psc->packet[0] & PMS_LBUTMASK) ^
704 (psc->packet[3] & PMS_LBUTMASK);
705 } else
706 if (synaptics_up_down_emul == 1) {
707 /* Do middle button emulation using up/down buttons */
708 sp.sp_middle = sp.sp_up | sp.sp_down;
709 sp.sp_up = sp.sp_down = 0;
710 } else
711 sp.sp_middle = 0;
712
713 pms_synaptics_process_packet(psc, &sp);
714 }
715
716 static void
717 pms_synaptics_passthrough(struct pms_softc *psc)
718 {
719 int dx, dy, dz;
720 int buttons, changed;
721 int s;
722
723 buttons = ((psc->packet[1] & PMS_LBUTMASK) ? 0x20 : 0) |
724 ((psc->packet[1] & PMS_MBUTMASK) ? 0x40 : 0) |
725 ((psc->packet[1] & PMS_RBUTMASK) ? 0x80 : 0);
726
727 dx = psc->packet[4];
728 if (dx >= 128)
729 dx -= 256;
730 if (dx == -128)
731 dx = -127;
732
733 dy = psc->packet[5];
734 if (dy >= 128)
735 dy -= 256;
736 if (dy == -128)
737 dy = -127;
738
739 dz = 0;
740
741 changed = buttons ^ (psc->buttons & 0xe0);
742 psc->buttons ^= changed;
743
744 if (dx || dy || dz || changed) {
745 buttons = (psc->buttons & 0x1f) | ((psc->buttons >> 5) & 0x7);
746 s = spltty();
747 wsmouse_input(psc->sc_wsmousedev,
748 buttons, dx, dy, dz, 0,
749 WSMOUSE_INPUT_DELTA);
750 splx(s);
751 }
752 }
753
754 static void
755 pms_synaptics_input(void *vsc, int data)
756 {
757 struct pms_softc *psc = vsc;
758 struct timeval diff;
759
760 if (!psc->sc_enabled) {
761 /* Interrupts are not expected. Discard the byte. */
762 return;
763 }
764
765 getmicrouptime(&psc->current);
766
767 if (psc->inputstate > 0) {
768 timersub(&psc->current, &psc->last, &diff);
769 if (diff.tv_sec > 0 || diff.tv_usec >= 40000) {
770 aprint_debug_dev(psc->sc_dev,
771 "pms_input: unusual delay (%ld.%06ld s), "
772 "scheduling reset\n",
773 (long)diff.tv_sec, (long)diff.tv_usec);
774 psc->inputstate = 0;
775 psc->sc_enabled = 0;
776 wakeup(&psc->sc_enabled);
777 return;
778 }
779 }
780 psc->last = psc->current;
781
782 switch (psc->inputstate) {
783 case 0:
784 if ((data & 0xc8) != 0x80) {
785 aprint_debug_dev(psc->sc_dev,
786 "pms_input: 0x%02x out of sync\n", data);
787 return; /* not in sync yet, discard input */
788 }
789 /*FALLTHROUGH*/
790
791 case 3:
792 if ((data & 8) == 8) {
793 aprint_debug_dev(psc->sc_dev,
794 "pms_input: dropped in relative mode, reset\n");
795 psc->inputstate = 0;
796 psc->sc_enabled = 0;
797 wakeup(&psc->sc_enabled);
798 return;
799 }
800 }
801
802 psc->packet[psc->inputstate++] = data & 0xff;
803 if (psc->inputstate == 6) {
804 /*
805 * We have a complete packet.
806 * Extract the pertinent details.
807 */
808 psc->inputstate = 0;
809
810 if ((psc->packet[0] & 0xfc) == 0x84 &&
811 (psc->packet[3] & 0xcc) == 0xc4) {
812 /* PS/2 passthrough */
813 pms_synaptics_passthrough(psc);
814 } else {
815 pms_synaptics_parse(psc);
816 }
817 }
818 }
819
820 static inline int
821 synaptics_finger_detect(struct synaptics_softc *sc, struct synaptics_packet *sp,
822 int *palmp)
823 {
824 int fingers;
825
826 /* Assume no palm */
827 *palmp = 0;
828
829 /*
830 * Apply some hysteresis when checking for a finger.
831 * When the finger is first applied, we ignore it until the
832 * pressure exceeds the 'high' threshold. The finger is considered
833 * removed only when pressure falls beneath the 'low' threshold.
834 */
835 if ((sc->prev_fingers == 0 && sp->sp_z > synaptics_finger_high) ||
836 (sc->prev_fingers != 0 && sp->sp_z > synaptics_finger_low))
837 fingers = 1;
838 else
839 fingers = 0;
840
841 /*
842 * If the pad can't do palm detection, skip the rest.
843 */
844 if (fingers == 0 || (sc->flags & SYN_FLAG_HAS_PALM_DETECT) == 0)
845 return (fingers);
846
847 /*
848 * Palm detection
849 */
850 if (sp->sp_z > SYNAPTICS_FINGER_FLAT &&
851 sp->sp_w >= SYNAPTICS_WIDTH_PALM_MIN)
852 *palmp = 1;
853
854 if (sc->prev_fingers == 0 &&
855 (sp->sp_z > SYNAPTICS_FINGER_FLAT ||
856 sp->sp_w >= SYNAPTICS_WIDTH_PALM_MIN)) {
857 /*
858 * Contact area or pressure is too great to be a finger.
859 * Just ignore it for now.
860 */
861 return (0);
862 }
863
864 /*
865 * Detect 2 and 3 fingers if supported, but only if multiple
866 * fingers appear within the tap gesture time period.
867 */
868 if (sc->flags & SYN_FLAG_HAS_MULTI_FINGER &&
869 SYN_TIME(sc, sc->gesture_start_packet) < synaptics_gesture_length) {
870 switch (sp->sp_w) {
871 case SYNAPTICS_WIDTH_TWO_FINGERS:
872 fingers = 2;
873 break;
874
875 case SYNAPTICS_WIDTH_THREE_OR_MORE:
876 fingers = 3;
877 break;
878
879 case SYNAPTICS_WIDTH_PEN:
880 fingers = 1;
881 break;
882
883 default:
884 /*
885 * The width value can report spurious single-finger
886 * events after a multi-finger event.
887 */
888 if (sc->prev_fingers > 1)
889 fingers = sc->prev_fingers;
890 else
891 fingers = 1;
892 break;
893 }
894 }
895
896 return (fingers);
897 }
898
899 static inline void
900 synaptics_gesture_detect(struct synaptics_softc *sc,
901 struct synaptics_packet *sp, int fingers)
902 {
903 int gesture_len, gesture_move_x, gesture_move_y, gesture_buttons;
904 int set_buttons;
905
906 gesture_len = SYN_TIME(sc, sc->gesture_start_packet);
907 gesture_buttons = sc->gesture_buttons;
908
909 if (fingers && sc->prev_fingers == 0) {
910 /*
911 * Finger was just applied.
912 * If the previous gesture was a single-click, set things
913 * up to deal with a possible drag or double-click gesture.
914 * Basically, if the finger is removed again within
915 * 'synaptics_gesture_length' packets, this is treated
916 * as a double-click. Otherwise we will emulate holding
917 * the left button down whilst dragging the mouse.
918 */
919 if (SYN_IS_SINGLE_TAP(sc->gesture_type))
920 sc->gesture_type |= SYN_GESTURE_DRAG;
921
922 sc->gesture_start_x = sp->sp_x;
923 sc->gesture_start_y = sp->sp_y;
924 sc->gesture_start_packet = sc->total_packets;
925 } else
926 if (fingers == 0 && sc->prev_fingers != 0) {
927 /*
928 * Finger was just removed.
929 * Check if the contact time and finger movement were
930 * small enough to qualify as a gesture.
931 * Ignore finger movement if multiple fingers were
932 * detected (the pad may report coordinates for any
933 * of the fingers).
934 */
935 gesture_move_x = abs(sc->gesture_start_x - sp->sp_x);
936 gesture_move_y = abs(sc->gesture_start_y - sp->sp_y);
937
938 if (gesture_len < synaptics_gesture_length &&
939 (sc->prev_fingers > 1 ||
940 (gesture_move_x < synaptics_gesture_move &&
941 gesture_move_y < synaptics_gesture_move))) {
942 /*
943 * Looking good so far.
944 */
945 if (SYN_IS_DRAG(sc->gesture_type)) {
946 /*
947 * Promote this gesture to double-click.
948 */
949 sc->gesture_type |= SYN_GESTURE_DOUBLE;
950 sc->gesture_type &= ~SYN_GESTURE_SINGLE;
951 } else {
952 /*
953 * Single tap gesture. Set the tap length timer
954 * and flag a single-click.
955 */
956 sc->gesture_tap_packet = sc->total_packets;
957 sc->gesture_type |= SYN_GESTURE_SINGLE;
958
959 /*
960 * The gesture can be modified depending on
961 * the number of fingers detected.
962 *
963 * 1: Normal left button emulation.
964 * 2: Either middle button or right button
965 * depending on the value of the two_fingers
966 * sysctl variable.
967 * 3: Right button.
968 */
969 switch (sc->prev_fingers) {
970 case 2:
971 if (synaptics_two_fingers_emul == 1)
972 gesture_buttons |= PMS_RBUTMASK;
973 else
974 if (synaptics_two_fingers_emul == 2)
975 gesture_buttons |= PMS_MBUTMASK;
976 break;
977 case 3:
978 gesture_buttons |= PMS_RBUTMASK;
979 break;
980 default:
981 gesture_buttons |= PMS_LBUTMASK;
982 break;
983 }
984 }
985 }
986
987 /*
988 * Always clear drag state when the finger is removed.
989 */
990 sc->gesture_type &= ~SYN_GESTURE_DRAG;
991 }
992
993 if (sc->gesture_type == 0) {
994 /*
995 * There is no gesture in progress.
996 * Clear emulated button state.
997 */
998 sc->gesture_buttons = 0;
999 return;
1000 }
1001
1002 /*
1003 * A gesture is in progress.
1004 */
1005 set_buttons = 0;
1006
1007 if (SYN_IS_SINGLE_TAP(sc->gesture_type)) {
1008 /*
1009 * Single-click.
1010 * Activate the relevant button(s) until the
1011 * gesture tap timer has expired.
1012 */
1013 if (SYN_TIME(sc, sc->gesture_tap_packet) <
1014 synaptics_gesture_length)
1015 set_buttons = 1;
1016 else
1017 sc->gesture_type &= ~SYN_GESTURE_SINGLE;
1018 } else
1019 if (SYN_IS_DOUBLE_TAP(sc->gesture_type) && sc->prev_fingers == 0) {
1020 /*
1021 * Double-click.
1022 * Activate the relevant button(s) once.
1023 */
1024 set_buttons = 1;
1025 sc->gesture_type &= ~SYN_GESTURE_DOUBLE;
1026 }
1027
1028 if (set_buttons || SYN_IS_DRAG(sc->gesture_type)) {
1029 /*
1030 * Single-click and drag.
1031 * Maintain button state until the finger is removed.
1032 */
1033 sp->sp_left |= gesture_buttons & PMS_LBUTMASK;
1034 sp->sp_right |= gesture_buttons & PMS_RBUTMASK;
1035 sp->sp_middle |= gesture_buttons & PMS_MBUTMASK;
1036 }
1037
1038 sc->gesture_buttons = gesture_buttons;
1039 }
1040
1041 static inline int
1042 synaptics_filter_policy(struct synaptics_softc *sc, int *history, int value)
1043 {
1044 int a, b, rv, count;
1045
1046 count = sc->total_packets;
1047
1048 /*
1049 * Once we've accumulated at least SYN_HIST_SIZE values, combine
1050 * each new value with the previous two and return the average.
1051 *
1052 * This is necessary when the touchpad is operating in 80 packets
1053 * per second mode, as it performs little internal filtering on
1054 * reported values.
1055 *
1056 * Using a rolling average helps to filter out jitter caused by
1057 * tiny finger movements.
1058 */
1059 if (sc->movement_history >= SYN_HIST_SIZE) {
1060 a = (history[(count + 0) % SYN_HIST_SIZE] +
1061 history[(count + 1) % SYN_HIST_SIZE]) / 2;
1062
1063 b = (value + history[(count + 0) % SYN_HIST_SIZE]) / 2;
1064
1065 rv = b - a;
1066
1067 /*
1068 * Don't report the movement if it's below a certain
1069 * threshold.
1070 */
1071 if (abs(rv) < synaptics_movement_threshold)
1072 rv = 0;
1073 } else
1074 rv = 0;
1075
1076 /*
1077 * Add the new value to the history buffer.
1078 */
1079 history[(count + 1) % SYN_HIST_SIZE] = value;
1080
1081 return (rv);
1082 }
1083
1084 /* Edge detection */
1085 #define SYN_EDGE_TOP 1
1086 #define SYN_EDGE_BOTTOM 2
1087 #define SYN_EDGE_LEFT 4
1088 #define SYN_EDGE_RIGHT 8
1089
1090 static inline int
1091 synaptics_check_edge(int x, int y)
1092 {
1093 int rv = 0;
1094
1095 if (x < synaptics_edge_left)
1096 rv |= SYN_EDGE_LEFT;
1097 else
1098 if (x > synaptics_edge_right)
1099 rv |= SYN_EDGE_RIGHT;
1100
1101 if (y < synaptics_edge_bottom)
1102 rv |= SYN_EDGE_BOTTOM;
1103 else
1104 if (y > synaptics_edge_top)
1105 rv |= SYN_EDGE_TOP;
1106
1107 return (rv);
1108 }
1109
1110 static inline int
1111 synaptics_edge_motion(struct synaptics_softc *sc, int delta, int dir)
1112 {
1113
1114 /*
1115 * When edge motion is enabled, synaptics_edge_motion_delta is
1116 * combined with the current delta, together with the direction
1117 * in which to simulate the motion. The result is added to
1118 * the delta derived from finger movement. This provides a smooth
1119 * transition from finger movement to edge motion.
1120 */
1121 delta = synaptics_edge_motion_delta + (dir * delta);
1122 if (delta < 0)
1123 return (0);
1124 if (delta > synaptics_edge_motion_delta)
1125 return (synaptics_edge_motion_delta);
1126 return (delta);
1127 }
1128
1129 static inline int
1130 synaptics_scale(int delta, int scale, int *remp)
1131 {
1132 int rv;
1133
1134 /*
1135 * Scale the raw delta in Synaptics coordinates (0-6143) into
1136 * something more reasonable by dividing the raw delta by a
1137 * scale factor. Any remainder from the previous scale result
1138 * is added to the current delta before scaling.
1139 * This prevents loss of resolution for very small/slow
1140 * movements of the finger.
1141 */
1142 delta += *remp;
1143 rv = delta / scale;
1144 *remp = delta % scale;
1145
1146 return (rv);
1147 }
1148
1149 static inline void
1150 synaptics_movement(struct synaptics_softc *sc, struct synaptics_packet *sp,
1151 int *dxp, int *dyp)
1152 {
1153 int dx, dy, edge;
1154
1155 /*
1156 * Compute the next values of dx and dy
1157 */
1158 dx = synaptics_filter_policy(sc, sc->history_x, sp->sp_x);
1159 dy = synaptics_filter_policy(sc, sc->history_y, sp->sp_y);
1160
1161 /*
1162 * If we're dealing with a drag gesture, and the finger moves to
1163 * the edge of the touchpad, apply edge motion emulation if it
1164 * is enabled.
1165 */
1166 if (synaptics_edge_motion_delta && SYN_IS_DRAG(sc->gesture_type)) {
1167 edge = synaptics_check_edge(sp->sp_x, sp->sp_y);
1168
1169 if (edge & SYN_EDGE_LEFT)
1170 dx -= synaptics_edge_motion(sc, dx, 1);
1171 if (edge & SYN_EDGE_RIGHT)
1172 dx += synaptics_edge_motion(sc, dx, -1);
1173 if (edge & SYN_EDGE_BOTTOM)
1174 dy -= synaptics_edge_motion(sc, dy, 1);
1175 if (edge & SYN_EDGE_TOP)
1176 dy += synaptics_edge_motion(sc, dy, -1);
1177 }
1178
1179 /*
1180 * Apply scaling to both deltas
1181 */
1182 dx = synaptics_scale(dx, synaptics_scale_x, &sc->rem_x);
1183 dy = synaptics_scale(dy, synaptics_scale_y, &sc->rem_y);
1184
1185 /*
1186 * Clamp deltas to specified maximums.
1187 */
1188 if (dx > synaptics_max_speed_x)
1189 dx = synaptics_max_speed_x;
1190 if (dy > synaptics_max_speed_y)
1191 dy = synaptics_max_speed_y;
1192
1193 *dxp = dx;
1194 *dyp = dy;
1195
1196 sc->movement_history++;
1197 }
1198
1199 static void
1200 pms_synaptics_process_packet(struct pms_softc *psc, struct synaptics_packet *sp)
1201 {
1202 struct synaptics_softc *sc = &psc->u.synaptics;
1203 int dx, dy, dz;
1204 int fingers, palm, buttons, changed;
1205 int s;
1206
1207 /*
1208 * Do Z-axis emulation using up/down buttons if required.
1209 * Note that the pad will send a one second burst of packets
1210 * when an up/down button is pressed and held. At the moment
1211 * we don't deal with auto-repeat, so convert the burst into
1212 * a one-shot.
1213 */
1214 dz = 0;
1215 if (synaptics_up_down_emul == 2) {
1216 if (sc->up_down == 0) {
1217 if (sp->sp_up && sp->sp_down) {
1218 /*
1219 * Most up/down buttons will be actuated using
1220 * a rocker switch, so we should never see
1221 * them both simultaneously. But just in case,
1222 * treat this situation as a middle button
1223 * event.
1224 */
1225 sp->sp_middle = 1;
1226 } else
1227 if (sp->sp_up)
1228 dz = -synaptics_up_down_motion_delta;
1229 else
1230 if (sp->sp_down)
1231 dz = synaptics_up_down_motion_delta;
1232 }
1233
1234 sc->up_down = sp->sp_up | sp->sp_down;
1235 sp->sp_up = sp->sp_down = 0;
1236 }
1237
1238 /*
1239 * Determine whether or not a finger is on the pad.
1240 * On some pads, this will return the number of fingers
1241 * detected.
1242 */
1243 fingers = synaptics_finger_detect(sc, sp, &palm);
1244
1245 /*
1246 * Do gesture processing only if we didn't detect a palm.
1247 */
1248 if (palm == 0)
1249 synaptics_gesture_detect(sc, sp, fingers);
1250 else
1251 sc->gesture_type = sc->gesture_buttons = 0;
1252
1253 /*
1254 * Determine what buttons to report
1255 */
1256 buttons = (sp->sp_left ? 0x1 : 0) |
1257 (sp->sp_middle ? 0x2 : 0) |
1258 (sp->sp_right ? 0x4 : 0) |
1259 (sp->sp_up ? 0x8 : 0) |
1260 (sp->sp_down ? 0x10 : 0);
1261 changed = buttons ^ (psc->buttons & 0x1f);
1262 psc->buttons ^= changed;
1263
1264 sc->prev_fingers = fingers;
1265 sc->total_packets++;
1266
1267 /*
1268 * Do movement processing IFF we have a single finger and no palm.
1269 */
1270 if (fingers == 1 && palm == 0)
1271 synaptics_movement(sc, sp, &dx, &dy);
1272 else {
1273 /*
1274 * No valid finger. Therefore no movement.
1275 */
1276 sc->movement_history = 0;
1277 sc->rem_x = sc->rem_y = 0;
1278 dx = dy = 0;
1279 }
1280
1281 /*
1282 * Pass the final results up to wsmouse_input() if necessary.
1283 */
1284 if (dx || dy || dz || changed) {
1285 buttons = (psc->buttons & 0x1f) | ((psc->buttons >> 5) & 0x7);
1286 s = spltty();
1287 wsmouse_input(psc->sc_wsmousedev,
1288 buttons,
1289 dx, dy, dz, 0,
1290 WSMOUSE_INPUT_DELTA);
1291 splx(s);
1292 }
1293 }
1294