xref: /freebsd/sys/dev/usb/input/wsp.c (revision 65d08437ef519124f39f113262a3cc71dadb8569)
1 /*-
2  * Copyright (c) 2012 Huang Wen Hui
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  */
26 
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
29 
30 #include <sys/param.h>
31 #include <sys/systm.h>
32 #include <sys/kernel.h>
33 #include <sys/malloc.h>
34 #include <sys/module.h>
35 #include <sys/lock.h>
36 #include <sys/mutex.h>
37 #include <sys/bus.h>
38 #include <sys/conf.h>
39 #include <sys/fcntl.h>
40 #include <sys/file.h>
41 #include <sys/selinfo.h>
42 #include <sys/poll.h>
43 #include <sys/sysctl.h>
44 
45 #include <dev/usb/usb.h>
46 #include <dev/usb/usbdi.h>
47 #include <dev/usb/usbdi_util.h>
48 #include <dev/usb/usbhid.h>
49 
50 #include "usbdevs.h"
51 
52 #define	USB_DEBUG_VAR wsp_debug
53 #include <dev/usb/usb_debug.h>
54 
55 #include <sys/mouse.h>
56 
57 #define	WSP_DRIVER_NAME "wsp"
58 
59 #define	WSP_CLAMP(x,low,high) do {		\
60 	if ((x) < (low))			\
61 		(x) = (low);			\
62 	else if ((x) > (high))			\
63 		(x) = (high);			\
64 } while (0)
65 
66 /* Tunables */
67 static	SYSCTL_NODE(_hw_usb, OID_AUTO, wsp, CTLFLAG_RW, 0, "USB wsp");
68 
69 #ifdef USB_DEBUG
70 enum wsp_log_level {
71 	WSP_LLEVEL_DISABLED = 0,
72 	WSP_LLEVEL_ERROR,
73 	WSP_LLEVEL_DEBUG,		/* for troubleshooting */
74 	WSP_LLEVEL_INFO,		/* for diagnostics */
75 };
76 static int wsp_debug = WSP_LLEVEL_ERROR;/* the default is to only log errors */
77 
78 SYSCTL_INT(_hw_usb_wsp, OID_AUTO, debug, CTLFLAG_RW,
79     &wsp_debug, WSP_LLEVEL_ERROR, "WSP debug level");
80 #endif					/* USB_DEBUG */
81 
82 static struct wsp_tuning {
83 	int	scale_factor;
84 	int	z_factor;
85 	int	pressure_touch_threshold;
86 	int	pressure_untouch_threshold;
87 	int	pressure_tap_threshold;
88 	int	scr_hor_threshold;
89 }
90 	wsp_tuning =
91 {
92 	.scale_factor = 12,
93 	.z_factor = 5,
94 	.pressure_touch_threshold = 50,
95 	.pressure_untouch_threshold = 10,
96 	.pressure_tap_threshold = 120,
97 	.scr_hor_threshold = 50,
98 };
99 
100 static void
101 wsp_runing_rangecheck(struct wsp_tuning *ptun)
102 {
103 	WSP_CLAMP(ptun->scale_factor, 1, 63);
104 	WSP_CLAMP(ptun->z_factor, 1, 63);
105 	WSP_CLAMP(ptun->pressure_touch_threshold, 1, 255);
106 	WSP_CLAMP(ptun->pressure_untouch_threshold, 1, 255);
107 	WSP_CLAMP(ptun->pressure_tap_threshold, 1, 255);
108 	WSP_CLAMP(ptun->scr_hor_threshold, 1, 255);
109 }
110 
111 SYSCTL_INT(_hw_usb_wsp, OID_AUTO, scale_factor, CTLFLAG_RW,
112     &wsp_tuning.scale_factor, 0, "movement scale factor");
113 SYSCTL_INT(_hw_usb_wsp, OID_AUTO, z_factor, CTLFLAG_RW,
114     &wsp_tuning.z_factor, 0, "Z-axis scale factor");
115 SYSCTL_INT(_hw_usb_wsp, OID_AUTO, pressure_touch_threshold, CTLFLAG_RW,
116     &wsp_tuning.pressure_touch_threshold, 0, "touch pressure threshold");
117 SYSCTL_INT(_hw_usb_wsp, OID_AUTO, pressure_untouch_threshold, CTLFLAG_RW,
118     &wsp_tuning.pressure_untouch_threshold, 0, "untouch pressure threshold");
119 SYSCTL_INT(_hw_usb_wsp, OID_AUTO, pressure_tap_threshold, CTLFLAG_RW,
120     &wsp_tuning.pressure_tap_threshold, 0, "tap pressure threshold");
121 SYSCTL_INT(_hw_usb_wsp, OID_AUTO, scr_hor_threshold, CTLFLAG_RW,
122     &wsp_tuning.scr_hor_threshold, 0, "horizontal scrolling threshold");
123 
124 #define	WSP_IFACE_INDEX	1
125 
126 /*
127  * Some tables, structures, definitions and initialisation values for
128  * the touchpad protocol has been copied from Linux's
129  * "drivers/input/mouse/bcm5974.c" which has the following copyright
130  * holders under GPLv2. All device specific code in this driver has
131  * been written from scratch. The decoding algorithm is based on
132  * output from usbdump.
133  *
134  * Copyright (C) 2008      Henrik Rydberg (rydberg@euromail.se)
135  * Copyright (C) 2008      Scott Shawcroft (scott.shawcroft@gmail.com)
136  * Copyright (C) 2001-2004 Greg Kroah-Hartman (greg@kroah.com)
137  * Copyright (C) 2005      Johannes Berg (johannes@sipsolutions.net)
138  * Copyright (C) 2005      Stelian Pop (stelian@popies.net)
139  * Copyright (C) 2005      Frank Arnold (frank@scirocco-5v-turbo.de)
140  * Copyright (C) 2005      Peter Osterlund (petero2@telia.com)
141  * Copyright (C) 2005      Michael Hanselmann (linux-kernel@hansmi.ch)
142  * Copyright (C) 2006      Nicolas Boichat (nicolas@boichat.ch)
143  */
144 
145 /* button data structure */
146 struct bt_data {
147 	uint8_t	unknown1;		/* constant */
148 	uint8_t	button;			/* left button */
149 	uint8_t	rel_x;			/* relative x coordinate */
150 	uint8_t	rel_y;			/* relative y coordinate */
151 } __packed;
152 
153 /* trackpad header types */
154 enum tp_type {
155 	TYPE1,			/* plain trackpad */
156 	TYPE2,			/* button integrated in trackpad */
157 	TYPE3			/* additional header fields since June 2013 */
158 };
159 
160 /* trackpad finger data offsets, le16-aligned */
161 #define	FINGER_TYPE1		(13 * 2)
162 #define	FINGER_TYPE2		(15 * 2)
163 #define	FINGER_TYPE3		(19 * 2)
164 
165 /* trackpad button data offsets */
166 #define	BUTTON_TYPE2		15
167 #define	BUTTON_TYPE3		23
168 
169 /* list of device capability bits */
170 #define	HAS_INTEGRATED_BUTTON	1
171 
172 /* trackpad finger header - little endian */
173 struct tp_header {
174 	uint8_t	flag;
175 	uint8_t	sn0;
176 	uint16_t wFixed0;
177 	uint32_t dwSn1;
178 	uint32_t dwFixed1;
179 	uint16_t wLength;
180 	uint8_t	nfinger;
181 	uint8_t	ibt;
182 	int16_t	wUnknown[6];
183 	uint8_t	q1;
184 	uint8_t	q2;
185 } __packed;
186 
187 /* trackpad finger structure - little endian */
188 struct tp_finger {
189 	int16_t	origin;			/* zero when switching track finger */
190 	int16_t	abs_x;			/* absolute x coodinate */
191 	int16_t	abs_y;			/* absolute y coodinate */
192 	int16_t	rel_x;			/* relative x coodinate */
193 	int16_t	rel_y;			/* relative y coodinate */
194 	int16_t	tool_major;		/* tool area, major axis */
195 	int16_t	tool_minor;		/* tool area, minor axis */
196 	int16_t	orientation;		/* 16384 when point, else 15 bit angle */
197 	int16_t	touch_major;		/* touch area, major axis */
198 	int16_t	touch_minor;		/* touch area, minor axis */
199 	int16_t	unused[3];		/* zeros */
200 	int16_t	multi;			/* one finger: varies, more fingers:
201 					 * constant */
202 } __packed;
203 
204 /* trackpad finger data size, empirically at least ten fingers */
205 #define	MAX_FINGERS		16
206 #define	SIZEOF_FINGER		sizeof(struct tp_finger)
207 #define	SIZEOF_ALL_FINGERS	(MAX_FINGERS * SIZEOF_FINGER)
208 #define	MAX_FINGER_ORIENTATION	16384
209 
210 /* logical signal quality */
211 #define	SN_PRESSURE	45		/* pressure signal-to-noise ratio */
212 #define	SN_WIDTH	25		/* width signal-to-noise ratio */
213 #define	SN_COORD	250		/* coordinate signal-to-noise ratio */
214 #define	SN_ORIENT	10		/* orientation signal-to-noise ratio */
215 
216 /* device-specific parameters */
217 struct wsp_param {
218 	int	snratio;		/* signal-to-noise ratio */
219 	int	min;			/* device minimum reading */
220 	int	max;			/* device maximum reading */
221 };
222 
223 enum {
224 	WSP_FLAG_WELLSPRING1,
225 	WSP_FLAG_WELLSPRING2,
226 	WSP_FLAG_WELLSPRING3,
227 	WSP_FLAG_WELLSPRING4,
228 	WSP_FLAG_WELLSPRING4A,
229 	WSP_FLAG_WELLSPRING5,
230 	WSP_FLAG_WELLSPRING6A,
231 	WSP_FLAG_WELLSPRING6,
232 	WSP_FLAG_WELLSPRING5A,
233 	WSP_FLAG_WELLSPRING7,
234 	WSP_FLAG_WELLSPRING7A,
235 	WSP_FLAG_WELLSPRING8,
236 	WSP_FLAG_MAX,
237 };
238 
239 /* device-specific configuration */
240 struct wsp_dev_params {
241 	uint8_t	caps;			/* device capability bitmask */
242 	uint16_t bt_datalen;		/* data length of the button interface */
243 	uint8_t	tp_type;		/* type of trackpad interface */
244 	uint8_t	tp_offset;		/* offset to trackpad finger data */
245 	uint16_t tp_datalen;		/* data length of the trackpad
246 					 * interface */
247 	struct wsp_param p;		/* finger pressure limits */
248 	struct wsp_param w;		/* finger width limits */
249 	struct wsp_param x;		/* horizontal limits */
250 	struct wsp_param y;		/* vertical limits */
251 	struct wsp_param o;		/* orientation limits */
252 };
253 
254 static const struct wsp_dev_params wsp_dev_params[WSP_FLAG_MAX] = {
255 	[WSP_FLAG_WELLSPRING1] = {
256 		.caps = 0,
257 		.bt_datalen = sizeof(struct bt_data),
258 		.tp_type = TYPE1,
259 		.tp_offset = FINGER_TYPE1,
260 		.tp_datalen = FINGER_TYPE1 + SIZEOF_ALL_FINGERS,
261 		.p = {
262 			SN_PRESSURE, 0, 256
263 		},
264 		.w = {
265 			SN_WIDTH, 0, 2048
266 		},
267 		.x = {
268 			SN_COORD, -4824, 5342
269 		},
270 		.y = {
271 			SN_COORD, -172, 5820
272 		},
273 		.o = {
274 			SN_ORIENT, -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION
275 		},
276 	},
277 	[WSP_FLAG_WELLSPRING2] = {
278 		.caps = 0,
279 		.bt_datalen = sizeof(struct bt_data),
280 		.tp_type = TYPE1,
281 		.tp_offset = FINGER_TYPE1,
282 		.tp_datalen = FINGER_TYPE1 + SIZEOF_ALL_FINGERS,
283 		.p = {
284 			SN_PRESSURE, 0, 256
285 		},
286 		.w = {
287 			SN_WIDTH, 0, 2048
288 		},
289 		.x = {
290 			SN_COORD, -4824, 4824
291 		},
292 		.y = {
293 			SN_COORD, -172, 4290
294 		},
295 		.o = {
296 			SN_ORIENT, -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION
297 		},
298 	},
299 	[WSP_FLAG_WELLSPRING3] = {
300 		.caps = HAS_INTEGRATED_BUTTON,
301 		.bt_datalen = sizeof(struct bt_data),
302 		.tp_type = TYPE2,
303 		.tp_offset = FINGER_TYPE2,
304 		.tp_datalen = FINGER_TYPE2 + SIZEOF_ALL_FINGERS,
305 		.p = {
306 			SN_PRESSURE, 0, 300
307 		},
308 		.w = {
309 			SN_WIDTH, 0, 2048
310 		},
311 		.x = {
312 			SN_COORD, -4460, 5166
313 		},
314 		.y = {
315 			SN_COORD, -75, 6700
316 		},
317 		.o = {
318 			SN_ORIENT, -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION
319 		},
320 	},
321 	[WSP_FLAG_WELLSPRING4] = {
322 		.caps = HAS_INTEGRATED_BUTTON,
323 		.bt_datalen = sizeof(struct bt_data),
324 		.tp_type = TYPE2,
325 		.tp_offset = FINGER_TYPE2,
326 		.tp_datalen = FINGER_TYPE2 + SIZEOF_ALL_FINGERS,
327 		.p = {
328 			SN_PRESSURE, 0, 300
329 		},
330 		.w = {
331 			SN_WIDTH, 0, 2048
332 		},
333 		.x = {
334 			SN_COORD, -4620, 5140
335 		},
336 		.y = {
337 			SN_COORD, -150, 6600
338 		},
339 		.o = {
340 			SN_ORIENT, -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION
341 		},
342 	},
343 	[WSP_FLAG_WELLSPRING4A] = {
344 		.caps = HAS_INTEGRATED_BUTTON,
345 		.bt_datalen = sizeof(struct bt_data),
346 		.tp_type = TYPE2,
347 		.tp_offset = FINGER_TYPE2,
348 		.tp_datalen = FINGER_TYPE2 + SIZEOF_ALL_FINGERS,
349 		.p = {
350 			SN_PRESSURE, 0, 300
351 		},
352 		.w = {
353 			SN_WIDTH, 0, 2048
354 		},
355 		.x = {
356 			SN_COORD, -4616, 5112
357 		},
358 		.y = {
359 			SN_COORD, -142, 5234
360 		},
361 		.o = {
362 			SN_ORIENT, -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION
363 		},
364 	},
365 	[WSP_FLAG_WELLSPRING5] = {
366 		.caps = HAS_INTEGRATED_BUTTON,
367 		.bt_datalen = sizeof(struct bt_data),
368 		.tp_type = TYPE2,
369 		.tp_offset = FINGER_TYPE2,
370 		.tp_datalen = FINGER_TYPE2 + SIZEOF_ALL_FINGERS,
371 		.p = {
372 			SN_PRESSURE, 0, 300
373 		},
374 		.w = {
375 			SN_WIDTH, 0, 2048
376 		},
377 		.x = {
378 			SN_COORD, -4415, 5050
379 		},
380 		.y = {
381 			SN_COORD, -55, 6680
382 		},
383 		.o = {
384 			SN_ORIENT, -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION
385 		},
386 	},
387 	[WSP_FLAG_WELLSPRING6] = {
388 		.caps = HAS_INTEGRATED_BUTTON,
389 		.bt_datalen = sizeof(struct bt_data),
390 		.tp_type = TYPE2,
391 		.tp_offset = FINGER_TYPE2,
392 		.tp_datalen = FINGER_TYPE2 + SIZEOF_ALL_FINGERS,
393 		.p = {
394 			SN_PRESSURE, 0, 300
395 		},
396 		.w = {
397 			SN_WIDTH, 0, 2048
398 		},
399 		.x = {
400 			SN_COORD, -4620, 5140
401 		},
402 		.y = {
403 			SN_COORD, -150, 6600
404 		},
405 		.o = {
406 			SN_ORIENT, -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION
407 		},
408 	},
409 	[WSP_FLAG_WELLSPRING5A] = {
410 		.caps = HAS_INTEGRATED_BUTTON,
411 		.bt_datalen = sizeof(struct bt_data),
412 		.tp_type = TYPE2,
413 		.tp_offset = FINGER_TYPE2,
414 		.tp_datalen = FINGER_TYPE2 + SIZEOF_ALL_FINGERS,
415 		.p = {
416 			SN_PRESSURE, 0, 300
417 		},
418 		.w = {
419 			SN_WIDTH, 0, 2048
420 		},
421 		.x = {
422 			SN_COORD, -4750, 5280
423 		},
424 		.y = {
425 			SN_COORD, -150, 6730
426 		},
427 		.o = {
428 			SN_ORIENT, -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION
429 		},
430 	},
431 	[WSP_FLAG_WELLSPRING6A] = {
432 		.caps = HAS_INTEGRATED_BUTTON,
433 		.bt_datalen = sizeof(struct bt_data),
434 		.tp_type = TYPE2,
435 		.tp_offset = FINGER_TYPE2,
436 		.tp_datalen = FINGER_TYPE2 + SIZEOF_ALL_FINGERS,
437 		.p = {
438 			SN_PRESSURE, 0, 300
439 		},
440 		.w = {
441 			SN_WIDTH, 0, 2048
442 		},
443 		.x = {
444 			SN_COORD, -4620, 5140
445 		},
446 		.y = {
447 			SN_COORD, -150, 6600
448 		},
449 		.o = {
450 			SN_ORIENT, -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION
451 		},
452 	},
453 	[WSP_FLAG_WELLSPRING7] = {
454 		.caps = HAS_INTEGRATED_BUTTON,
455 		.bt_datalen = sizeof(struct bt_data),
456 		.tp_type = TYPE2,
457 		.tp_offset = FINGER_TYPE2,
458 		.tp_datalen = FINGER_TYPE2 + SIZEOF_ALL_FINGERS,
459 		.p = {
460 			SN_PRESSURE, 0, 300
461 		},
462 		.w = {
463 			SN_WIDTH, 0, 2048
464 		},
465 		.x = {
466 			SN_COORD, -4750, 5280
467 		},
468 		.y = {
469 			SN_COORD, -150, 6730
470 		},
471 		.o = {
472 			SN_ORIENT, -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION
473 		},
474 	},
475 	[WSP_FLAG_WELLSPRING7A] = {
476 		.caps = HAS_INTEGRATED_BUTTON,
477 		.bt_datalen = sizeof(struct bt_data),
478 		.tp_type = TYPE2,
479 		.tp_offset = FINGER_TYPE2,
480 		.tp_datalen = FINGER_TYPE2 + SIZEOF_ALL_FINGERS,
481 		.p = {
482 			SN_PRESSURE, 0, 300
483 		},
484 		.w = {
485 			SN_WIDTH, 0, 2048
486 		},
487 		.x = {
488 			SN_COORD, -4750, 5280
489 		},
490 		.y = {
491 			SN_COORD, -150, 6730
492 		},
493 		.o = {
494 			SN_ORIENT, -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION
495 		},
496 	},
497 	[WSP_FLAG_WELLSPRING8] = {
498 		.caps = HAS_INTEGRATED_BUTTON,
499 		.bt_datalen = sizeof(struct bt_data),
500 		.tp_type = TYPE3,
501 		.tp_offset = FINGER_TYPE3,
502 		.tp_datalen = FINGER_TYPE3 + SIZEOF_ALL_FINGERS,
503 		.p = {
504 			SN_PRESSURE, 0, 300
505 		},
506 		.w = {
507 			SN_WIDTH, 0, 2048
508 		},
509 		.x = {
510 			SN_COORD, -4620, 5140
511 		},
512 		.y = {
513 			SN_COORD, -150, 6600
514 		},
515 		.o = {
516 			SN_ORIENT, -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION
517 		},
518 	},
519 };
520 
521 #define	WSP_DEV(v,p,i) { USB_VPI(USB_VENDOR_##v, USB_PRODUCT_##v##_##p, i) }
522 
523 static const STRUCT_USB_HOST_ID wsp_devs[] = {
524 	/* MacbookAir1.1 */
525 	WSP_DEV(APPLE, WELLSPRING_ANSI, WSP_FLAG_WELLSPRING1),
526 	WSP_DEV(APPLE, WELLSPRING_ISO, WSP_FLAG_WELLSPRING1),
527 	WSP_DEV(APPLE, WELLSPRING_JIS, WSP_FLAG_WELLSPRING1),
528 
529 	/* MacbookProPenryn, aka wellspring2 */
530 	WSP_DEV(APPLE, WELLSPRING2_ANSI, WSP_FLAG_WELLSPRING2),
531 	WSP_DEV(APPLE, WELLSPRING2_ISO, WSP_FLAG_WELLSPRING2),
532 	WSP_DEV(APPLE, WELLSPRING2_JIS, WSP_FLAG_WELLSPRING2),
533 
534 	/* Macbook5,1 (unibody), aka wellspring3 */
535 	WSP_DEV(APPLE, WELLSPRING3_ANSI, WSP_FLAG_WELLSPRING3),
536 	WSP_DEV(APPLE, WELLSPRING3_ISO, WSP_FLAG_WELLSPRING3),
537 	WSP_DEV(APPLE, WELLSPRING3_JIS, WSP_FLAG_WELLSPRING3),
538 
539 	/* MacbookAir3,2 (unibody), aka wellspring4 */
540 	WSP_DEV(APPLE, WELLSPRING4_ANSI, WSP_FLAG_WELLSPRING4),
541 	WSP_DEV(APPLE, WELLSPRING4_ISO, WSP_FLAG_WELLSPRING4),
542 	WSP_DEV(APPLE, WELLSPRING4_JIS, WSP_FLAG_WELLSPRING4),
543 
544 	/* MacbookAir3,1 (unibody), aka wellspring4 */
545 	WSP_DEV(APPLE, WELLSPRING4A_ANSI, WSP_FLAG_WELLSPRING4A),
546 	WSP_DEV(APPLE, WELLSPRING4A_ISO, WSP_FLAG_WELLSPRING4A),
547 	WSP_DEV(APPLE, WELLSPRING4A_JIS, WSP_FLAG_WELLSPRING4A),
548 
549 	/* Macbook8 (unibody, March 2011) */
550 	WSP_DEV(APPLE, WELLSPRING5_ANSI, WSP_FLAG_WELLSPRING5),
551 	WSP_DEV(APPLE, WELLSPRING5_ISO, WSP_FLAG_WELLSPRING5),
552 	WSP_DEV(APPLE, WELLSPRING5_JIS, WSP_FLAG_WELLSPRING5),
553 
554 	/* MacbookAir4,1 (unibody, July 2011) */
555 	WSP_DEV(APPLE, WELLSPRING6A_ANSI, WSP_FLAG_WELLSPRING6A),
556 	WSP_DEV(APPLE, WELLSPRING6A_ISO, WSP_FLAG_WELLSPRING6A),
557 	WSP_DEV(APPLE, WELLSPRING6A_JIS, WSP_FLAG_WELLSPRING6A),
558 
559 	/* MacbookAir4,2 (unibody, July 2011) */
560 	WSP_DEV(APPLE, WELLSPRING6_ANSI, WSP_FLAG_WELLSPRING6),
561 	WSP_DEV(APPLE, WELLSPRING6_ISO, WSP_FLAG_WELLSPRING6),
562 	WSP_DEV(APPLE, WELLSPRING6_JIS, WSP_FLAG_WELLSPRING6),
563 
564 	/* Macbook8,2 (unibody) */
565 	WSP_DEV(APPLE, WELLSPRING5A_ANSI, WSP_FLAG_WELLSPRING5A),
566 	WSP_DEV(APPLE, WELLSPRING5A_ISO, WSP_FLAG_WELLSPRING5A),
567 	WSP_DEV(APPLE, WELLSPRING5A_JIS, WSP_FLAG_WELLSPRING5A),
568 
569 	/* MacbookPro10,1 (unibody, June 2012) */
570 	/* MacbookPro11,? (unibody, June 2013) */
571 	WSP_DEV(APPLE, WELLSPRING7_ANSI, WSP_FLAG_WELLSPRING7),
572 	WSP_DEV(APPLE, WELLSPRING7_ISO, WSP_FLAG_WELLSPRING7),
573 	WSP_DEV(APPLE, WELLSPRING7_JIS, WSP_FLAG_WELLSPRING7),
574 
575 	/* MacbookPro10,2 (unibody, October 2012) */
576 	WSP_DEV(APPLE, WELLSPRING7A_ANSI, WSP_FLAG_WELLSPRING7A),
577 	WSP_DEV(APPLE, WELLSPRING7A_ISO, WSP_FLAG_WELLSPRING7A),
578 	WSP_DEV(APPLE, WELLSPRING7A_JIS, WSP_FLAG_WELLSPRING7A),
579 
580 	/* MacbookAir6,2 (unibody, June 2013) */
581 	WSP_DEV(APPLE, WELLSPRING8_ANSI, WSP_FLAG_WELLSPRING8),
582 	WSP_DEV(APPLE, WELLSPRING8_ISO, WSP_FLAG_WELLSPRING8),
583 	WSP_DEV(APPLE, WELLSPRING8_JIS, WSP_FLAG_WELLSPRING8),
584 };
585 
586 #define	WSP_FIFO_BUF_SIZE	 8	/* bytes */
587 #define	WSP_FIFO_QUEUE_MAXLEN	50	/* units */
588 
589 enum {
590 	WSP_INTR_DT,
591 	WSP_N_TRANSFER,
592 };
593 
594 struct wsp_softc {
595 	struct usb_device *sc_usb_device;
596 	struct mtx sc_mutex;		/* for synchronization */
597 	struct usb_xfer *sc_xfer[WSP_N_TRANSFER];
598 	struct usb_fifo_sc sc_fifo;
599 
600 	const struct wsp_dev_params *sc_params;	/* device configuration */
601 
602 	mousehw_t sc_hw;
603 	mousemode_t sc_mode;
604 	u_int	sc_pollrate;
605 	mousestatus_t sc_status;
606 	u_int	sc_state;
607 #define	WSP_ENABLED	       0x01
608 
609 	struct bt_data *bt_data;	/* button transferred data */
610 	uint8_t *tp_data;		/* trackpad transferred data */
611 	struct tp_finger *index[MAX_FINGERS];	/* finger index data */
612 	int16_t	pos_x[MAX_FINGERS];	/* position array */
613 	int16_t	pos_y[MAX_FINGERS];	/* position array */
614 	u_int	sc_touch;		/* touch status */
615 #define	WSP_UNTOUCH		0x00
616 #define	WSP_FIRST_TOUCH		0x01
617 #define	WSP_SECOND_TOUCH	0x02
618 #define	WSP_TOUCHING		0x04
619 	int16_t	pre_pos_x;		/* previous position array */
620 	int16_t	pre_pos_y;		/* previous position array */
621 	int	dx_sum;			/* x axis cumulative movement */
622 	int	dy_sum;			/* y axis cumulative movement */
623 	int	dz_sum;			/* z axis cumulative movement */
624 	int	dz_count;
625 #define	WSP_DZ_MAX_COUNT	32
626 	int	dt_sum;			/* T-axis cumulative movement */
627 
628 	uint8_t o_ntouch;		/* old touch finger status */
629 	uint8_t	finger;			/* 0 or 1 *, check which finger moving */
630 	uint16_t intr_count;
631 #define	WSP_TAP_THRESHOLD	3
632 #define	WSP_TAP_MAX_COUNT	20
633 	int	distance;		/* the distance of 2 fingers */
634 #define	MAX_DISTANCE		2500	/* the max allowed distance */
635 	uint8_t	ibtn;			/* button status in tapping */
636 	uint8_t	ntaps;			/* finger status in tapping */
637 	uint8_t	scr_mode;		/* scroll status in movement */
638 #define	WSP_SCR_NONE		0
639 #define	WSP_SCR_VER		1
640 #define	WSP_SCR_HOR		2
641 };
642 
643 typedef enum interface_mode {
644 	RAW_SENSOR_MODE = 0x01,
645 	HID_MODE = 0x08
646 } interface_mode;
647 
648 /*
649  * function prototypes
650  */
651 static usb_fifo_cmd_t wsp_start_read;
652 static usb_fifo_cmd_t wsp_stop_read;
653 static usb_fifo_open_t wsp_open;
654 static usb_fifo_close_t wsp_close;
655 static usb_fifo_ioctl_t wsp_ioctl;
656 
657 static struct usb_fifo_methods wsp_fifo_methods = {
658 	.f_open = &wsp_open,
659 	.f_close = &wsp_close,
660 	.f_ioctl = &wsp_ioctl,
661 	.f_start_read = &wsp_start_read,
662 	.f_stop_read = &wsp_stop_read,
663 	.basename[0] = WSP_DRIVER_NAME,
664 };
665 
666 /* device initialization and shutdown */
667 static int wsp_enable(struct wsp_softc *sc);
668 static void wsp_disable(struct wsp_softc *sc);
669 
670 /* updating fifo */
671 static void wsp_reset_buf(struct wsp_softc *sc);
672 static void wsp_add_to_queue(struct wsp_softc *, int, int, int, uint32_t);
673 
674 /* Device methods. */
675 static device_probe_t wsp_probe;
676 static device_attach_t wsp_attach;
677 static device_detach_t wsp_detach;
678 static usb_callback_t wsp_intr_callback;
679 
680 static struct usb_config wsp_config[WSP_N_TRANSFER] = {
681 	[WSP_INTR_DT] = {
682 		.type = UE_INTERRUPT,
683 		.endpoint = UE_ADDR_ANY,
684 		.direction = UE_DIR_IN,
685 		.flags = {
686 			.pipe_bof = 0,
687 			.short_xfer_ok = 1,
688 		},
689 		.bufsize = 0,		/* use wMaxPacketSize */
690 		.callback = &wsp_intr_callback,
691 	},
692 };
693 
694 static usb_error_t
695 wsp_set_device_mode(struct wsp_softc *sc, interface_mode mode)
696 {
697 	uint8_t	mode_bytes[8];
698 	usb_error_t err;
699 
700 	err = usbd_req_get_report(sc->sc_usb_device, NULL,
701 	    mode_bytes, sizeof(mode_bytes), 0,
702 	    0x03, 0x00);
703 
704 	if (err != USB_ERR_NORMAL_COMPLETION) {
705 		DPRINTF("Failed to read device mode (%d)\n", err);
706 		return (err);
707 	}
708 
709 	/*
710 	 * XXX Need to wait at least 250ms for hardware to get
711 	 * ready. The device mode handling appears to be handled
712 	 * asynchronously and we should not issue these commands too
713 	 * quickly.
714 	 */
715 	pause("WHW", hz / 4);
716 
717 	mode_bytes[0] = mode;
718 
719 	return (usbd_req_set_report(sc->sc_usb_device, NULL,
720 	    mode_bytes, sizeof(mode_bytes), 0,
721 	    0x03, 0x00));
722 }
723 
724 static int
725 wsp_enable(struct wsp_softc *sc)
726 {
727 	const struct wsp_dev_params *params = sc->sc_params;
728 
729 	if (params == NULL || params->tp_datalen == 0) {
730 		DPRINTF("params uninitialized!\n");
731 		return (ENXIO);
732 	}
733 	/* Allocate the dynamic buffers */
734 	sc->tp_data = malloc(params->tp_datalen, M_USB, M_WAITOK | M_ZERO);
735 	if (sc->tp_data == NULL) {
736 		DPRINTF("Cannot allocate memory\n");
737 		return (ENXIO);
738 	}
739 
740 	/* reset status */
741 	memset(&sc->sc_status, 0, sizeof(sc->sc_status));
742 	sc->sc_state |= WSP_ENABLED;
743 
744 	DPRINTFN(WSP_LLEVEL_INFO, "enabled wsp\n");
745 	return (0);
746 }
747 
748 static void
749 wsp_disable(struct wsp_softc *sc)
750 {
751 	free(sc->tp_data, M_USB);
752 	sc->tp_data = NULL;
753 
754 	sc->sc_state &= ~WSP_ENABLED;
755 	DPRINTFN(WSP_LLEVEL_INFO, "disabled wsp\n");
756 }
757 
758 static int
759 wsp_probe(device_t self)
760 {
761 	struct usb_attach_arg *uaa = device_get_ivars(self);
762 
763 	if (uaa->usb_mode != USB_MODE_HOST)
764 		return (ENXIO);
765 
766 	if (uaa->info.bIfaceIndex != WSP_IFACE_INDEX)
767 		return (ENXIO);
768 
769 	if ((uaa->info.bInterfaceClass != UICLASS_HID) ||
770 	    (uaa->info.bInterfaceProtocol != 0))
771 		return (ENXIO);
772 
773 	return (usbd_lookup_id_by_uaa(wsp_devs, sizeof(wsp_devs), uaa));
774 }
775 
776 static int
777 wsp_attach(device_t dev)
778 {
779 	struct wsp_softc *sc = device_get_softc(dev);
780 	struct usb_attach_arg *uaa = device_get_ivars(dev);
781 	usb_error_t err;
782 
783 	DPRINTFN(WSP_LLEVEL_INFO, "sc=%p\n", sc);
784 
785 	sc->sc_usb_device = uaa->device;
786 
787 	/*
788 	 * By default the touchpad behaves like a HID device, sending
789 	 * packets with reportID = 8. Such reports contain only
790 	 * limited information. They encode movement deltas and button
791 	 * events, but do not include data from the pressure
792 	 * sensors. The device input mode can be switched from HID
793 	 * reports to raw sensor data using vendor-specific USB
794 	 * control commands:
795 	 */
796 
797 	/*
798 	 * During re-enumeration of the device we need to force the
799 	 * device back into HID mode before switching it to RAW
800 	 * mode. Else the device does not work like expected.
801 	 */
802 	err = wsp_set_device_mode(sc, HID_MODE);
803 	if (err != USB_ERR_NORMAL_COMPLETION) {
804 		DPRINTF("Failed to set mode to HID MODE (%d)\n", err);
805 		return (ENXIO);
806 	}
807 
808 	err = wsp_set_device_mode(sc, RAW_SENSOR_MODE);
809 	if (err != USB_ERR_NORMAL_COMPLETION) {
810 		DPRINTF("failed to set mode to RAW MODE (%d)\n", err);
811 		return (ENXIO);
812 	}
813 
814 	mtx_init(&sc->sc_mutex, "wspmtx", NULL, MTX_DEF | MTX_RECURSE);
815 
816 	/* get device specific configuration */
817 	sc->sc_params = wsp_dev_params + USB_GET_DRIVER_INFO(uaa);
818 
819 	/* set to 0 to use wMaxPacketSize is not enough */
820 	wsp_config[0].bufsize = sc->sc_params->tp_datalen;
821 
822 	err = usbd_transfer_setup(uaa->device,
823 	    &uaa->info.bIfaceIndex, sc->sc_xfer, wsp_config,
824 	    WSP_N_TRANSFER, sc, &sc->sc_mutex);
825 
826 	if (err) {
827 		DPRINTF("error=%s\n", usbd_errstr(err));
828 		goto detach;
829 	}
830 	if (usb_fifo_attach(sc->sc_usb_device, sc, &sc->sc_mutex,
831 	    &wsp_fifo_methods, &sc->sc_fifo,
832 	    device_get_unit(dev), -1, uaa->info.bIfaceIndex,
833 	    UID_ROOT, GID_OPERATOR, 0644)) {
834 		goto detach;
835 	}
836 	device_set_usb_desc(dev);
837 
838 	sc->sc_hw.buttons = 3;
839 	sc->sc_hw.iftype = MOUSE_IF_USB;
840 	sc->sc_hw.type = MOUSE_PAD;
841 	sc->sc_hw.model = MOUSE_MODEL_GENERIC;
842 	sc->sc_mode.protocol = MOUSE_PROTO_MSC;
843 	sc->sc_mode.rate = -1;
844 	sc->sc_mode.resolution = MOUSE_RES_UNKNOWN;
845 	sc->sc_mode.packetsize = MOUSE_MSC_PACKETSIZE;
846 	sc->sc_mode.syncmask[0] = MOUSE_MSC_SYNCMASK;
847 	sc->sc_mode.syncmask[1] = MOUSE_MSC_SYNC;
848 
849 	sc->sc_touch = WSP_UNTOUCH;
850 	sc->scr_mode = WSP_SCR_NONE;
851 
852 	return (0);
853 
854 detach:
855 	wsp_detach(dev);
856 	return (ENOMEM);
857 }
858 
859 static int
860 wsp_detach(device_t dev)
861 {
862 	struct wsp_softc *sc = device_get_softc(dev);
863 
864 	(void) wsp_set_device_mode(sc, HID_MODE);
865 
866 	mtx_lock(&sc->sc_mutex);
867 	if (sc->sc_state & WSP_ENABLED)
868 		wsp_disable(sc);
869 	mtx_unlock(&sc->sc_mutex);
870 
871 	usb_fifo_detach(&sc->sc_fifo);
872 
873 	usbd_transfer_unsetup(sc->sc_xfer, WSP_N_TRANSFER);
874 
875 	mtx_destroy(&sc->sc_mutex);
876 
877 	return (0);
878 }
879 
880 static void
881 wsp_intr_callback(struct usb_xfer *xfer, usb_error_t error)
882 {
883 	struct wsp_softc *sc = usbd_xfer_softc(xfer);
884 	const struct wsp_dev_params *params = sc->sc_params;
885 	struct usb_page_cache *pc;
886 	struct tp_finger *f;
887 	struct tp_header *h;
888 	struct wsp_tuning tun = wsp_tuning;
889 	int ntouch = 0;			/* the finger number in touch */
890 	int ibt = 0;			/* button status */
891 	int dx = 0;
892 	int dy = 0;
893 	int dz = 0;
894 	int len;
895 	int i;
896 
897 	wsp_runing_rangecheck(&tun);
898 
899 	if (sc->dz_count == 0)
900 		sc->dz_count = WSP_DZ_MAX_COUNT;
901 
902 	usbd_xfer_status(xfer, &len, NULL, NULL, NULL);
903 
904 	switch (USB_GET_STATE(xfer)) {
905 	case USB_ST_TRANSFERRED:
906 		if (len > (int)params->tp_datalen) {
907 			DPRINTFN(WSP_LLEVEL_ERROR,
908 			    "truncating large packet from %u to %u bytes\n",
909 			    len, params->tp_datalen);
910 			len = params->tp_datalen;
911 		} else {
912 			/* make sure we don't process old data */
913 			memset(sc->tp_data + len, 0, params->tp_datalen - len);
914 		}
915 
916 		pc = usbd_xfer_get_frame(xfer, 0);
917 		usbd_copy_out(pc, 0, sc->tp_data, len);
918 
919 		h = (struct tp_header *)(sc->tp_data);
920 
921 		if (params->tp_type == TYPE2) {
922 			ibt = sc->tp_data[BUTTON_TYPE2];
923 			ntouch = sc->tp_data[BUTTON_TYPE2 - 1];
924 		} else if (params->tp_type == TYPE3) {
925 			ibt = sc->tp_data[BUTTON_TYPE3];
926 			ntouch = sc->tp_data[BUTTON_TYPE3 - 1];
927 		}
928 		/* range check */
929 		if (ntouch < 0)
930 			ntouch = 0;
931 		else if (ntouch > MAX_FINGERS)
932 			ntouch = MAX_FINGERS;
933 
934 		f = (struct tp_finger *)(sc->tp_data + params->tp_offset);
935 
936 		for (i = 0; i != ntouch; i++) {
937 			/* swap endianness, if any */
938 			if (le16toh(0x1234) != 0x1234) {
939 				f[i].origin = le16toh((uint16_t)f[i].origin);
940 				f[i].abs_x = le16toh((uint16_t)f[i].abs_x);
941 				f[i].abs_y = le16toh((uint16_t)f[i].abs_y);
942 				f[i].rel_x = le16toh((uint16_t)f[i].rel_x);
943 				f[i].rel_y = le16toh((uint16_t)f[i].rel_y);
944 				f[i].tool_major = le16toh((uint16_t)f[i].tool_major);
945 				f[i].tool_minor = le16toh((uint16_t)f[i].tool_minor);
946 				f[i].orientation = le16toh((uint16_t)f[i].orientation);
947 				f[i].touch_major = le16toh((uint16_t)f[i].touch_major);
948 				f[i].touch_minor = le16toh((uint16_t)f[i].touch_minor);
949 				f[i].multi = le16toh((uint16_t)f[i].multi);
950 			}
951 			DPRINTFN(WSP_LLEVEL_INFO, "[%d]ibt=%d, taps=%d, u=%x, o=%4d, ax=%5d, ay=%5d, "
952 			    "rx=%5d, ry=%5d, tlmaj=%4d, tlmin=%4d, ot=%5d, tchmaj=%4d, tchmin=%4d, m=%4x\n",
953 			    i, ibt, ntouch, h->q2,
954 			    f[i].origin, f[i].abs_x, f[i].abs_y, f[i].rel_x, f[i].rel_y,
955 			    f[i].tool_major, f[i].tool_minor, f[i].orientation,
956 			    f[i].touch_major, f[i].touch_minor, f[i].multi);
957 
958 			sc->pos_x[i] = f[i].abs_x;
959 			sc->pos_y[i] = params->y.min + params->y.max - f[i].abs_y;
960 			sc->index[i] = &f[i];
961 		}
962 
963 		sc->sc_status.flags &= ~MOUSE_POSCHANGED;
964 		sc->sc_status.flags &= ~MOUSE_STDBUTTONSCHANGED;
965 		sc->sc_status.obutton = sc->sc_status.button;
966 		sc->sc_status.button = 0;
967 
968 		if (ibt != 0) {
969 			sc->sc_status.button |= MOUSE_BUTTON1DOWN;
970 			sc->ibtn = 1;
971 		}
972 		if (h->q2 == 4)
973 			sc->intr_count++;
974 
975 		if (sc->ntaps < ntouch) {
976 			switch (ntouch) {
977 			case 1:
978 				if (f[0].touch_major > tun.pressure_tap_threshold)
979 					sc->ntaps = 1;
980 				break;
981 			case 2:
982 				if (f[0].touch_major > tun.pressure_tap_threshold &&
983 				    f[1].touch_major > tun.pressure_tap_threshold)
984 					sc->ntaps = 2;
985 				break;
986 			case 3:
987 				if (f[0].touch_major > tun.pressure_tap_threshold &&
988 				    f[1].touch_major > tun.pressure_tap_threshold &&
989 				    f[2].touch_major > tun.pressure_tap_threshold)
990 					sc->ntaps = 3;
991 				break;
992 			default:
993 				break;
994 			}
995 		}
996 		if (ntouch == 2) {
997 			sc->distance = max(sc->distance, max(
998 			    abs(sc->pos_x[0] - sc->pos_x[1]),
999 			    abs(sc->pos_y[0] - sc->pos_y[1])));
1000 		}
1001 		if (f[0].touch_major < tun.pressure_untouch_threshold &&
1002 		    sc->sc_status.button == 0) {
1003 			sc->sc_touch = WSP_UNTOUCH;
1004 			if (sc->intr_count < WSP_TAP_MAX_COUNT &&
1005 			    sc->intr_count > WSP_TAP_THRESHOLD &&
1006 			    sc->ntaps && sc->ibtn == 0) {
1007 				/*
1008 				 * Add a pair of events (button-down and
1009 				 * button-up).
1010 				 */
1011 				switch (sc->ntaps) {
1012 #if 0
1013 				case 1:
1014 					wsp_add_to_queue(sc, 0, 0, 0, MOUSE_BUTTON1DOWN);
1015 					DPRINTFN(WSP_LLEVEL_INFO, "LEFT CLICK!\n");
1016 					break;
1017 #endif
1018 				case 2:
1019 					if (sc->distance < MAX_DISTANCE)
1020 						wsp_add_to_queue(sc, 0, 0, 0, MOUSE_BUTTON3DOWN);
1021 					DPRINTFN(WSP_LLEVEL_INFO, "RIGHT CLICK!\n");
1022 					break;
1023 				case 3:
1024 					wsp_add_to_queue(sc, 0, 0, 0, MOUSE_BUTTON2DOWN);
1025 					break;
1026 				default:
1027 					/* we don't handle taps of more than three fingers */
1028 					break;
1029 				}
1030 				wsp_add_to_queue(sc, 0, 0, 0, 0);	/* button release */
1031 			}
1032 			if (sc->intr_count >= WSP_TAP_MAX_COUNT &&
1033 			    (sc->dt_sum / tun.scr_hor_threshold) != 0 &&
1034 			    sc->ntaps == 2 && sc->scr_mode == WSP_SCR_HOR) {
1035 
1036 				/*
1037 				 * translate T-axis into button presses
1038 				 * until further
1039 				 */
1040 				if (sc->dt_sum > 0)
1041 					wsp_add_to_queue(sc, 0, 0, 0, 1UL << 3);
1042 				else if (sc->dt_sum < 0)
1043 					wsp_add_to_queue(sc, 0, 0, 0, 1UL << 4);
1044 			}
1045 			sc->dz_count = WSP_DZ_MAX_COUNT;
1046 			sc->dz_sum = 0;
1047 			sc->intr_count = 0;
1048 			sc->ibtn = 0;
1049 			sc->ntaps = 0;
1050 			sc->finger = 0;
1051 			sc->distance = 0;
1052 			sc->dt_sum = 0;
1053 			sc->dx_sum = 0;
1054 			sc->dy_sum = 0;
1055 			sc->scr_mode = WSP_SCR_NONE;
1056 		} else if (f[0].touch_major >= tun.pressure_touch_threshold &&
1057 		    sc->sc_touch == WSP_UNTOUCH) {	/* ignore first touch */
1058 			sc->sc_touch = WSP_FIRST_TOUCH;
1059 		} else if (f[0].touch_major >= tun.pressure_touch_threshold &&
1060 		    sc->sc_touch == WSP_FIRST_TOUCH) {	/* ignore second touch */
1061 			sc->sc_touch = WSP_SECOND_TOUCH;
1062 			DPRINTFN(WSP_LLEVEL_INFO, "Fist pre_x=%5d, pre_y=%5d\n",
1063 			    sc->pre_pos_x, sc->pre_pos_y);
1064 		} else {
1065 			if (sc->sc_touch == WSP_SECOND_TOUCH)
1066 				sc->sc_touch = WSP_TOUCHING;
1067 
1068 			if (ntouch != 0 &&
1069 			    h->q2 == 4 &&
1070 			    f[0].touch_major >= tun.pressure_touch_threshold) {
1071 				dx = sc->pos_x[0] - sc->pre_pos_x;
1072 				dy = sc->pos_y[0] - sc->pre_pos_y;
1073 
1074 				/* Ignore movement from ibt=1 to ibt=0 */
1075 				if (sc->sc_status.obutton != 0 &&
1076 				    sc->sc_status.button == 0) {
1077 					dx = 0;
1078 					dy = 0;
1079 				}
1080 				/* Ignore movement if ntouch changed */
1081 				if (sc->o_ntouch != ntouch) {
1082 					dx = 0;
1083 					dy = 0;
1084 				}
1085 
1086 				if (ntouch == 2 && sc->sc_status.button != 0) {
1087 					dx = sc->pos_x[sc->finger] - sc->pre_pos_x;
1088 					dy = sc->pos_y[sc->finger] - sc->pre_pos_y;
1089 
1090 					/*
1091 					 * Ignore movement of switch finger or
1092 					 * movement from ibt=0 to ibt=1
1093 					 */
1094 					if (f[0].origin == 0 || f[1].origin == 0 ||
1095 					    sc->sc_status.obutton != sc->sc_status.button) {
1096 						dx = 0;
1097 						dy = 0;
1098 						sc->finger = 0;
1099 					}
1100 					if ((abs(f[0].rel_x) + abs(f[0].rel_y)) <
1101 					    (abs(f[1].rel_x) + abs(f[1].rel_y)) &&
1102 					    sc->finger == 0) {
1103 						sc->sc_touch = WSP_SECOND_TOUCH;
1104 						dx = 0;
1105 						dy = 0;
1106 						sc->finger = 1;
1107 					}
1108 					if ((abs(f[0].rel_x) + abs(f[0].rel_y)) >=
1109 					    (abs(f[1].rel_x) + abs(f[1].rel_y)) &&
1110 					    sc->finger == 1) {
1111 						sc->sc_touch = WSP_SECOND_TOUCH;
1112 						dx = 0;
1113 						dy = 0;
1114 						sc->finger = 0;
1115 					}
1116 					DPRINTFN(WSP_LLEVEL_INFO, "dx=%5d, dy=%5d, mov=%5d\n",
1117 					    dx, dy, sc->finger);
1118 				}
1119 				if (sc->dz_count--)
1120 					sc->dz_sum -= (dy / tun.scale_factor);
1121 				if ((sc->dz_sum / tun.z_factor) != 0)
1122 					sc->dz_count = 0;
1123 			}
1124 			dx /= tun.scale_factor;
1125 			dy /= tun.scale_factor;
1126 			sc->dx_sum += dx;
1127 			sc->dy_sum += dy;
1128 
1129 			if (ntouch == 2 && sc->sc_status.button == 0) {
1130 				if (sc->scr_mode == WSP_SCR_NONE &&
1131 				    abs(sc->dx_sum) + abs(sc->dy_sum) > 50)
1132 					sc->scr_mode = abs(sc->dx_sum) >
1133 					    abs(sc->dy_sum) ? WSP_SCR_HOR :
1134 					    WSP_SCR_VER;
1135 				DPRINTFN(WSP_LLEVEL_INFO, "scr_mode=%5d, count=%d, dx_sum=%d, dy_sum=%d\n",
1136 				    sc->scr_mode, sc->intr_count, sc->dx_sum, sc->dy_sum);
1137 				if (sc->scr_mode == WSP_SCR_HOR)
1138 					sc->dt_sum += dx;
1139 				else
1140 					sc->dt_sum = 0;
1141 
1142 				dx = 0;
1143 				dy = 0;
1144 				if (sc->dz_count == 0)
1145 					dz = sc->dz_sum / tun.z_factor;
1146 				if (abs(sc->pos_x[0] - sc->pos_x[1]) > MAX_DISTANCE ||
1147 				    abs(sc->pos_y[0] - sc->pos_y[1]) > MAX_DISTANCE)
1148 					dz = 0;
1149 			}
1150 			if (sc->intr_count < WSP_TAP_MAX_COUNT &&
1151 			    abs(dx) < 3 && abs(dy) < 3 && abs(dz) < 3) {
1152 				dx = dy = dz = 0;
1153 			} else
1154 				sc->intr_count = WSP_TAP_MAX_COUNT;
1155 			if (dx || dy || dz)
1156 				sc->sc_status.flags |= MOUSE_POSCHANGED;
1157 			DPRINTFN(WSP_LLEVEL_INFO, "dx=%5d, dy=%5d, dz=%5d, sc_touch=%x, btn=%x\n",
1158 			    dx, dy, dz, sc->sc_touch, sc->sc_status.button);
1159 			sc->sc_status.dx += dx;
1160 			sc->sc_status.dy += dy;
1161 			sc->sc_status.dz += dz;
1162 
1163 			wsp_add_to_queue(sc, dx, -dy, dz, sc->sc_status.button);
1164 			if (sc->dz_count == 0)
1165 				sc->dz_sum = 0;
1166 
1167 		}
1168 		sc->pre_pos_x = sc->pos_x[0];
1169 		sc->pre_pos_y = sc->pos_y[0];
1170 
1171 		if (ntouch == 2 && sc->sc_status.button != 0) {
1172 			sc->pre_pos_x = sc->pos_x[sc->finger];
1173 			sc->pre_pos_y = sc->pos_y[sc->finger];
1174 		}
1175 		sc->o_ntouch = ntouch;
1176 
1177 	case USB_ST_SETUP:
1178 tr_setup:
1179 		/* check if we can put more data into the FIFO */
1180 		if (usb_fifo_put_bytes_max(
1181 		    sc->sc_fifo.fp[USB_FIFO_RX]) != 0) {
1182 			usbd_xfer_set_frame_len(xfer, 0,
1183 			    sc->sc_params->tp_datalen);
1184 			usbd_transfer_submit(xfer);
1185 		}
1186 		break;
1187 
1188 	default:			/* Error */
1189 		if (error != USB_ERR_CANCELLED) {
1190 			/* try clear stall first */
1191 			usbd_xfer_set_stall(xfer);
1192 			goto tr_setup;
1193 		}
1194 		break;
1195 	}
1196 
1197 	return;
1198 }
1199 
1200 static void
1201 wsp_add_to_queue(struct wsp_softc *sc, int dx, int dy, int dz,
1202     uint32_t buttons_in)
1203 {
1204 	uint32_t buttons_out;
1205 	uint8_t buf[8];
1206 
1207 	dx = imin(dx, 254);
1208 	dx = imax(dx, -256);
1209 	dy = imin(dy, 254);
1210 	dy = imax(dy, -256);
1211 	dz = imin(dz, 126);
1212 	dz = imax(dz, -128);
1213 
1214 	buttons_out = MOUSE_MSC_BUTTONS;
1215 	if (buttons_in & MOUSE_BUTTON1DOWN)
1216 		buttons_out &= ~MOUSE_MSC_BUTTON1UP;
1217 	else if (buttons_in & MOUSE_BUTTON2DOWN)
1218 		buttons_out &= ~MOUSE_MSC_BUTTON2UP;
1219 	else if (buttons_in & MOUSE_BUTTON3DOWN)
1220 		buttons_out &= ~MOUSE_MSC_BUTTON3UP;
1221 
1222 	/* Encode the mouse data in standard format; refer to mouse(4) */
1223 	buf[0] = sc->sc_mode.syncmask[1];
1224 	buf[0] |= buttons_out;
1225 	buf[1] = dx >> 1;
1226 	buf[2] = dy >> 1;
1227 	buf[3] = dx - (dx >> 1);
1228 	buf[4] = dy - (dy >> 1);
1229 	/* Encode extra bytes for level 1 */
1230 	if (sc->sc_mode.level == 1) {
1231 		buf[5] = dz >> 1;	/* dz / 2 */
1232 		buf[6] = dz - (dz >> 1);/* dz - (dz / 2) */
1233 		buf[7] = (((~buttons_in) >> 3) & MOUSE_SYS_EXTBUTTONS);
1234 	}
1235 	usb_fifo_put_data_linear(sc->sc_fifo.fp[USB_FIFO_RX], buf,
1236 	    sc->sc_mode.packetsize, 1);
1237 }
1238 
1239 static void
1240 wsp_reset_buf(struct wsp_softc *sc)
1241 {
1242 	/* reset read queue */
1243 	usb_fifo_reset(sc->sc_fifo.fp[USB_FIFO_RX]);
1244 }
1245 
1246 static void
1247 wsp_start_read(struct usb_fifo *fifo)
1248 {
1249 	struct wsp_softc *sc = usb_fifo_softc(fifo);
1250 	int rate;
1251 
1252 	/* Check if we should override the default polling interval */
1253 	rate = sc->sc_pollrate;
1254 	/* Range check rate */
1255 	if (rate > 1000)
1256 		rate = 1000;
1257 	/* Check for set rate */
1258 	if ((rate > 0) && (sc->sc_xfer[WSP_INTR_DT] != NULL)) {
1259 		/* Stop current transfer, if any */
1260 		usbd_transfer_stop(sc->sc_xfer[WSP_INTR_DT]);
1261 		/* Set new interval */
1262 		usbd_xfer_set_interval(sc->sc_xfer[WSP_INTR_DT], 1000 / rate);
1263 		/* Only set pollrate once */
1264 		sc->sc_pollrate = 0;
1265 	}
1266 	usbd_transfer_start(sc->sc_xfer[WSP_INTR_DT]);
1267 }
1268 
1269 static void
1270 wsp_stop_read(struct usb_fifo *fifo)
1271 {
1272 	struct wsp_softc *sc = usb_fifo_softc(fifo);
1273 
1274 	usbd_transfer_stop(sc->sc_xfer[WSP_INTR_DT]);
1275 }
1276 
1277 
1278 static int
1279 wsp_open(struct usb_fifo *fifo, int fflags)
1280 {
1281 	DPRINTFN(WSP_LLEVEL_INFO, "\n");
1282 
1283 	if (fflags & FREAD) {
1284 		struct wsp_softc *sc = usb_fifo_softc(fifo);
1285 		int rc;
1286 
1287 		if (sc->sc_state & WSP_ENABLED)
1288 			return (EBUSY);
1289 
1290 		if (usb_fifo_alloc_buffer(fifo,
1291 		    WSP_FIFO_BUF_SIZE, WSP_FIFO_QUEUE_MAXLEN)) {
1292 			return (ENOMEM);
1293 		}
1294 		rc = wsp_enable(sc);
1295 		if (rc != 0) {
1296 			usb_fifo_free_buffer(fifo);
1297 			return (rc);
1298 		}
1299 	}
1300 	return (0);
1301 }
1302 
1303 static void
1304 wsp_close(struct usb_fifo *fifo, int fflags)
1305 {
1306 	if (fflags & FREAD) {
1307 		struct wsp_softc *sc = usb_fifo_softc(fifo);
1308 
1309 		wsp_disable(sc);
1310 		usb_fifo_free_buffer(fifo);
1311 	}
1312 }
1313 
1314 int
1315 wsp_ioctl(struct usb_fifo *fifo, u_long cmd, void *addr, int fflags)
1316 {
1317 	struct wsp_softc *sc = usb_fifo_softc(fifo);
1318 	mousemode_t mode;
1319 	int error = 0;
1320 
1321 	mtx_lock(&sc->sc_mutex);
1322 
1323 	switch (cmd) {
1324 	case MOUSE_GETHWINFO:
1325 		*(mousehw_t *)addr = sc->sc_hw;
1326 		break;
1327 	case MOUSE_GETMODE:
1328 		*(mousemode_t *)addr = sc->sc_mode;
1329 		break;
1330 	case MOUSE_SETMODE:
1331 		mode = *(mousemode_t *)addr;
1332 
1333 		if (mode.level == -1)
1334 			/* Don't change the current setting */
1335 			;
1336 		else if ((mode.level < 0) || (mode.level > 1)) {
1337 			error = EINVAL;
1338 			goto done;
1339 		}
1340 		sc->sc_mode.level = mode.level;
1341 		sc->sc_pollrate = mode.rate;
1342 		sc->sc_hw.buttons = 3;
1343 
1344 		if (sc->sc_mode.level == 0) {
1345 			sc->sc_mode.protocol = MOUSE_PROTO_MSC;
1346 			sc->sc_mode.packetsize = MOUSE_MSC_PACKETSIZE;
1347 			sc->sc_mode.syncmask[0] = MOUSE_MSC_SYNCMASK;
1348 			sc->sc_mode.syncmask[1] = MOUSE_MSC_SYNC;
1349 		} else if (sc->sc_mode.level == 1) {
1350 			sc->sc_mode.protocol = MOUSE_PROTO_SYSMOUSE;
1351 			sc->sc_mode.packetsize = MOUSE_SYS_PACKETSIZE;
1352 			sc->sc_mode.syncmask[0] = MOUSE_SYS_SYNCMASK;
1353 			sc->sc_mode.syncmask[1] = MOUSE_SYS_SYNC;
1354 		}
1355 		wsp_reset_buf(sc);
1356 		break;
1357 	case MOUSE_GETLEVEL:
1358 		*(int *)addr = sc->sc_mode.level;
1359 		break;
1360 	case MOUSE_SETLEVEL:
1361 		if (*(int *)addr < 0 || *(int *)addr > 1) {
1362 			error = EINVAL;
1363 			goto done;
1364 		}
1365 		sc->sc_mode.level = *(int *)addr;
1366 		sc->sc_hw.buttons = 3;
1367 
1368 		if (sc->sc_mode.level == 0) {
1369 			sc->sc_mode.protocol = MOUSE_PROTO_MSC;
1370 			sc->sc_mode.packetsize = MOUSE_MSC_PACKETSIZE;
1371 			sc->sc_mode.syncmask[0] = MOUSE_MSC_SYNCMASK;
1372 			sc->sc_mode.syncmask[1] = MOUSE_MSC_SYNC;
1373 		} else if (sc->sc_mode.level == 1) {
1374 			sc->sc_mode.protocol = MOUSE_PROTO_SYSMOUSE;
1375 			sc->sc_mode.packetsize = MOUSE_SYS_PACKETSIZE;
1376 			sc->sc_mode.syncmask[0] = MOUSE_SYS_SYNCMASK;
1377 			sc->sc_mode.syncmask[1] = MOUSE_SYS_SYNC;
1378 		}
1379 		wsp_reset_buf(sc);
1380 		break;
1381 	case MOUSE_GETSTATUS:{
1382 			mousestatus_t *status = (mousestatus_t *)addr;
1383 
1384 			*status = sc->sc_status;
1385 			sc->sc_status.obutton = sc->sc_status.button;
1386 			sc->sc_status.button = 0;
1387 			sc->sc_status.dx = 0;
1388 			sc->sc_status.dy = 0;
1389 			sc->sc_status.dz = 0;
1390 
1391 			if (status->dx || status->dy || status->dz)
1392 				status->flags |= MOUSE_POSCHANGED;
1393 			if (status->button != status->obutton)
1394 				status->flags |= MOUSE_BUTTONSCHANGED;
1395 			break;
1396 		}
1397 	default:
1398 		error = ENOTTY;
1399 	}
1400 
1401 done:
1402 	mtx_unlock(&sc->sc_mutex);
1403 	return (error);
1404 }
1405 
1406 static device_method_t wsp_methods[] = {
1407 	/* Device interface */
1408 	DEVMETHOD(device_probe, wsp_probe),
1409 	DEVMETHOD(device_attach, wsp_attach),
1410 	DEVMETHOD(device_detach, wsp_detach),
1411 	DEVMETHOD_END
1412 };
1413 
1414 static driver_t wsp_driver = {
1415 	.name = WSP_DRIVER_NAME,
1416 	.methods = wsp_methods,
1417 	.size = sizeof(struct wsp_softc)
1418 };
1419 
1420 static devclass_t wsp_devclass;
1421 
1422 DRIVER_MODULE(wsp, uhub, wsp_driver, wsp_devclass, NULL, 0);
1423 MODULE_DEPEND(wsp, usb, 1, 1, 1);
1424 MODULE_VERSION(wsp, 1);
1425