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