wsp.c revision 261509
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: stable/10/sys/dev/usb/input/wsp.c 261509 2014-02-05 08:40:02Z hselasky $");
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 */
67static	SYSCTL_NODE(_hw_usb, OID_AUTO, wsp, CTLFLAG_RW, 0, "USB wsp");
68
69#ifdef USB_DEBUG
70enum 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};
76static int wsp_debug = WSP_LLEVEL_ERROR;/* the default is to only log errors */
77
78SYSCTL_INT(_hw_usb_wsp, OID_AUTO, debug, CTLFLAG_RW,
79    &wsp_debug, WSP_LLEVEL_ERROR, "WSP debug level");
80#endif					/* USB_DEBUG */
81
82static 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
100static void
101wsp_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
111SYSCTL_INT(_hw_usb_wsp, OID_AUTO, scale_factor, CTLFLAG_RW,
112    &wsp_tuning.scale_factor, 0, "movement scale factor");
113SYSCTL_INT(_hw_usb_wsp, OID_AUTO, z_factor, CTLFLAG_RW,
114    &wsp_tuning.z_factor, 0, "Z-axis scale factor");
115SYSCTL_INT(_hw_usb_wsp, OID_AUTO, pressure_touch_threshold, CTLFLAG_RW,
116    &wsp_tuning.pressure_touch_threshold, 0, "touch pressure threshold");
117SYSCTL_INT(_hw_usb_wsp, OID_AUTO, pressure_untouch_threshold, CTLFLAG_RW,
118    &wsp_tuning.pressure_untouch_threshold, 0, "untouch pressure threshold");
119SYSCTL_INT(_hw_usb_wsp, OID_AUTO, pressure_tap_threshold, CTLFLAG_RW,
120    &wsp_tuning.pressure_tap_threshold, 0, "tap pressure threshold");
121SYSCTL_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 */
146struct 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 */
154enum 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 */
173struct 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 */
188struct 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 */
217struct wsp_param {
218	int	snratio;		/* signal-to-noise ratio */
219	int	min;			/* device minimum reading */
220	int	max;			/* device maximum reading */
221};
222
223enum {
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 */
240struct 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
254static 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
523static 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
589enum {
590	WSP_INTR_DT,
591	WSP_N_TRANSFER,
592};
593
594struct 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
643typedef enum interface_mode {
644	RAW_SENSOR_MODE = 0x01,
645	HID_MODE = 0x08
646} interface_mode;
647
648/*
649 * function prototypes
650 */
651static usb_fifo_cmd_t wsp_start_read;
652static usb_fifo_cmd_t wsp_stop_read;
653static usb_fifo_open_t wsp_open;
654static usb_fifo_close_t wsp_close;
655static usb_fifo_ioctl_t wsp_ioctl;
656
657static 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 */
667static int wsp_enable(struct wsp_softc *sc);
668static void wsp_disable(struct wsp_softc *sc);
669
670/* updating fifo */
671static void wsp_reset_buf(struct wsp_softc *sc);
672static void wsp_add_to_queue(struct wsp_softc *, int, int, int, uint32_t);
673
674/* Device methods. */
675static device_probe_t wsp_probe;
676static device_attach_t wsp_attach;
677static device_detach_t wsp_detach;
678static usb_callback_t wsp_intr_callback;
679
680static 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
694static usb_error_t
695wsp_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
724static int
725wsp_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
748static void
749wsp_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
758static int
759wsp_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
776static int
777wsp_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
854detach:
855	wsp_detach(dev);
856	return (ENOMEM);
857}
858
859static int
860wsp_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
880static void
881wsp_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:
1178tr_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
1200static void
1201wsp_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
1239static void
1240wsp_reset_buf(struct wsp_softc *sc)
1241{
1242	/* reset read queue */
1243	usb_fifo_reset(sc->sc_fifo.fp[USB_FIFO_RX]);
1244}
1245
1246static void
1247wsp_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
1269static void
1270wsp_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
1278static int
1279wsp_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
1303static void
1304wsp_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
1314int
1315wsp_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
1401done:
1402	mtx_unlock(&sc->sc_mutex);
1403	return (error);
1404}
1405
1406static 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
1414static driver_t wsp_driver = {
1415	.name = WSP_DRIVER_NAME,
1416	.methods = wsp_methods,
1417	.size = sizeof(struct wsp_softc)
1418};
1419
1420static devclass_t wsp_devclass;
1421
1422DRIVER_MODULE(wsp, uhub, wsp_driver, wsp_devclass, NULL, 0);
1423MODULE_DEPEND(wsp, usb, 1, 1, 1);
1424MODULE_VERSION(wsp, 1);
1425