xref: /openbsd-src/sys/dev/usb/ubcmtp.c (revision f6aab3d83b51b91c24247ad2c2573574de475a82)
1 /*	$OpenBSD: ubcmtp.c,v 1.25 2023/07/02 21:44:04 bru Exp $ */
2 
3 /*
4  * Copyright (c) 2013-2014, joshua stein <jcs@openbsd.org>
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 /*
20  * Apple USB multitouch trackpad (Broadcom BCM5974) driver
21  *
22  * Protocol info/magic from bcm5974 Linux driver by Henrik Rydberg, et al.
23  */
24 
25 #include <sys/param.h>
26 #include <sys/device.h>
27 #include <sys/errno.h>
28 #include <sys/malloc.h>
29 
30 #include <sys/ioctl.h>
31 #include <sys/systm.h>
32 #include <sys/tty.h>
33 
34 #include <dev/usb/usb.h>
35 #include <dev/usb/usbdi.h>
36 #include <dev/usb/usbdevs.h>
37 #include <dev/usb/usbhid.h>
38 
39 #include <dev/wscons/wsconsio.h>
40 #include <dev/wscons/wsmousevar.h>
41 
42 /* #define UBCMTP_DEBUG */
43 
44 #ifdef UBCMTP_DEBUG
45 #define DPRINTF(x...)	do { printf(x); } while (0);
46 #else
47 #define DPRINTF(x...)
48 #endif
49 
50 /* magic to switch device from HID (default) mode into raw */
51 #define UBCMTP_WELLSPRING_MODE_RAW	0x01
52 #define UBCMTP_WELLSPRING_MODE_HID	0x08
53 #define UBCMTP_WELLSPRING_MODE_LEN	8
54 #define UBCMTP_WELLSPRING9_MODE_RAW	0x01
55 #define UBCMTP_WELLSPRING9_MODE_HID	0x00
56 #define UBCMTP_WELLSPRING9_MODE_LEN	2
57 
58 struct ubcmtp_button {
59 	uint8_t		unused;
60 	uint8_t		button;
61 	uint8_t		rel_x;
62 	uint8_t		rel_y;
63 };
64 
65 struct ubcmtp_finger {
66 	uint16_t	origin;
67 	uint16_t	abs_x;
68 	uint16_t	abs_y;
69 	uint16_t	rel_x;
70 	uint16_t	rel_y;
71 	uint16_t	tool_major;
72 	uint16_t	tool_minor;
73 	uint16_t	orientation;
74 	uint16_t	touch_major;
75 	uint16_t	touch_minor;
76 	uint16_t	unused[2];
77 	uint16_t	pressure;
78 	uint16_t	multi;
79 } __packed __attribute((aligned(2)));
80 
81 #define UBCMTP_MAX_FINGERS	16
82 #define UBCMTP_ALL_FINGER_SIZE	(UBCMTP_MAX_FINGERS * sizeof(struct ubcmtp_finger))
83 
84 #define UBCMTP_TYPE1		1
85 #define UBCMTP_TYPE1_TPOFF	(13 * sizeof(uint16_t))
86 #define UBCMTP_TYPE1_TPLEN	UBCMTP_TYPE1_TPOFF + UBCMTP_ALL_FINGER_SIZE
87 #define UBCMTP_TYPE1_TPIFACE	1
88 #define UBCMTP_TYPE1_BTIFACE	2
89 
90 #define UBCMTP_TYPE2		2
91 #define UBCMTP_TYPE2_TPOFF	(15 * sizeof(uint16_t))
92 #define UBCMTP_TYPE2_TPLEN	UBCMTP_TYPE2_TPOFF + UBCMTP_ALL_FINGER_SIZE
93 #define UBCMTP_TYPE2_TPIFACE	1
94 #define UBCMTP_TYPE2_BTOFF	15
95 
96 #define UBCMTP_TYPE3		3
97 #define UBCMTP_TYPE3_TPOFF	(19 * sizeof(uint16_t))
98 #define UBCMTP_TYPE3_TPLEN	UBCMTP_TYPE3_TPOFF + UBCMTP_ALL_FINGER_SIZE
99 #define UBCMTP_TYPE3_TPIFACE	2
100 #define UBCMTP_TYPE3_BTOFF	23
101 
102 #define UBCMTP_TYPE4		4
103 #define UBCMTP_TYPE4_TPOFF	(24 * sizeof(uint16_t))
104 #define UBCMTP_TYPE4_TPLEN	UBCMTP_TYPE4_TPOFF + UBCMTP_ALL_FINGER_SIZE
105 #define UBCMTP_TYPE4_TPIFACE	2
106 #define UBCMTP_TYPE4_BTOFF	31
107 #define UBCMTP_TYPE4_FINGERPAD	(1 * sizeof(uint16_t))
108 
109 #define UBCMTP_FINGER_ORIENT	16384
110 #define UBCMTP_SN_PRESSURE	45
111 #define UBCMTP_SN_WIDTH		25
112 #define UBCMTP_SN_COORD		250
113 #define UBCMTP_SN_ORIENT	10
114 
115 /* Identify clickpads in ubcmtp_configure. */
116 #define IS_CLICKPAD(ubcmtp_type) (ubcmtp_type != UBCMTP_TYPE1)
117 
118 /* Use a constant, synaptics-compatible pressure value for now. */
119 #define DEFAULT_PRESSURE	40
120 
121 struct ubcmtp_limit {
122 	int limit;
123 	int min;
124 	int max;
125 };
126 
127 struct ubcmtp_dev {
128 	int vendor;			/* vendor */
129 	int ansi, iso, jis;		/* 3 types of product */
130 	int type;			/* 1 (normal) or 2 (integrated btn) */
131 	struct ubcmtp_limit l_pressure;	/* finger pressure */
132 	struct ubcmtp_limit l_width;	/* finger width */
133 	struct ubcmtp_limit l_x;
134 	struct ubcmtp_limit l_y;
135 	struct ubcmtp_limit l_orientation;
136 };
137 
138 static const struct ubcmtp_dev ubcmtp_devices[] = {
139 	/* type 1 devices with separate buttons */
140 	{
141 		USB_VENDOR_APPLE,
142 		/* MacbookAir */
143 		USB_PRODUCT_APPLE_WELLSPRING_ANSI,
144 		USB_PRODUCT_APPLE_WELLSPRING_ISO,
145 		USB_PRODUCT_APPLE_WELLSPRING_JIS,
146 		UBCMTP_TYPE1,
147 		{ UBCMTP_SN_PRESSURE, 0, 256 },
148 		{ UBCMTP_SN_WIDTH, 0, 2048 },
149 		{ UBCMTP_SN_COORD, -4824, 5342 },
150 		{ UBCMTP_SN_COORD, -172, 5820 },
151 		{ UBCMTP_SN_ORIENT, -UBCMTP_FINGER_ORIENT, UBCMTP_FINGER_ORIENT },
152 	},
153 	{
154 		USB_VENDOR_APPLE,
155 		/* MacbookProPenryn */
156 		USB_PRODUCT_APPLE_WELLSPRING2_ANSI,
157 		USB_PRODUCT_APPLE_WELLSPRING2_ISO,
158 		USB_PRODUCT_APPLE_WELLSPRING2_JIS,
159 		UBCMTP_TYPE1,
160 		{ UBCMTP_SN_PRESSURE, 0, 256 },
161 		{ UBCMTP_SN_WIDTH, 0, 2048 },
162 		{ UBCMTP_SN_COORD, -4824, 4824 },
163 		{ UBCMTP_SN_COORD, -172, 4290 },
164 		{ UBCMTP_SN_ORIENT, -UBCMTP_FINGER_ORIENT, UBCMTP_FINGER_ORIENT },
165 	},
166 	/* type 2 devices with integrated buttons */
167 	{
168 		USB_VENDOR_APPLE,
169 		/* Macbook5,1 */
170 		USB_PRODUCT_APPLE_WELLSPRING3_ANSI,
171 		USB_PRODUCT_APPLE_WELLSPRING3_ISO,
172 		USB_PRODUCT_APPLE_WELLSPRING3_JIS,
173 		UBCMTP_TYPE2,
174 		{ UBCMTP_SN_PRESSURE, 0, 300 },
175 		{ UBCMTP_SN_WIDTH, 0, 2048 },
176 		{ UBCMTP_SN_COORD, -4460, 5166 },
177 		{ UBCMTP_SN_COORD, -75, 6700 },
178 		{ UBCMTP_SN_ORIENT, -UBCMTP_FINGER_ORIENT, UBCMTP_FINGER_ORIENT },
179 	},
180 	{
181 		USB_VENDOR_APPLE,
182 		/* MacbookAir3,1 */
183 		USB_PRODUCT_APPLE_WELLSPRING4A_ANSI,
184 		USB_PRODUCT_APPLE_WELLSPRING4A_ISO,
185 		USB_PRODUCT_APPLE_WELLSPRING4A_JIS,
186 		UBCMTP_TYPE2,
187 		{ UBCMTP_SN_PRESSURE, 0, 300 },
188 		{ UBCMTP_SN_WIDTH, 0, 2048 },
189 		{ UBCMTP_SN_COORD, -4616, 5112 },
190 		{ UBCMTP_SN_COORD, -142, 5234 },
191 		{ UBCMTP_SN_ORIENT, -UBCMTP_FINGER_ORIENT, UBCMTP_FINGER_ORIENT },
192 	},
193 	{
194 		USB_VENDOR_APPLE,
195 		/* MacbookAir3,2 */
196 		USB_PRODUCT_APPLE_WELLSPRING4_ANSI,
197 		USB_PRODUCT_APPLE_WELLSPRING4_ISO,
198 		USB_PRODUCT_APPLE_WELLSPRING4_JIS,
199 		UBCMTP_TYPE2,
200 		{ UBCMTP_SN_PRESSURE, 0, 300 },
201 		{ UBCMTP_SN_WIDTH, 0, 2048 },
202 		{ UBCMTP_SN_COORD, -4620, 5140 },
203 		{ UBCMTP_SN_COORD, -150, 6600 },
204 		{ UBCMTP_SN_ORIENT, -UBCMTP_FINGER_ORIENT, UBCMTP_FINGER_ORIENT },
205 	},
206 	{
207 		USB_VENDOR_APPLE,
208 		/* Macbook8 */
209 		USB_PRODUCT_APPLE_WELLSPRING5_ANSI,
210 		USB_PRODUCT_APPLE_WELLSPRING5_ISO,
211 		USB_PRODUCT_APPLE_WELLSPRING5_JIS,
212 		UBCMTP_TYPE2,
213 		{ UBCMTP_SN_PRESSURE, 0, 300 },
214 		{ UBCMTP_SN_WIDTH, 0, 2048 },
215 		{ UBCMTP_SN_COORD, -4415, 5050 },
216 		{ UBCMTP_SN_COORD, -55, 6680 },
217 		{ UBCMTP_SN_ORIENT, -UBCMTP_FINGER_ORIENT, UBCMTP_FINGER_ORIENT },
218 	},
219 	{
220 		USB_VENDOR_APPLE,
221 		/* Macbook8,2 */
222 		USB_PRODUCT_APPLE_WELLSPRING5A_ANSI,
223 		USB_PRODUCT_APPLE_WELLSPRING5A_ISO,
224 		USB_PRODUCT_APPLE_WELLSPRING5A_JIS,
225 		UBCMTP_TYPE2,
226 		{ UBCMTP_SN_PRESSURE, 0, 300 },
227 		{ UBCMTP_SN_WIDTH, 0, 2048 },
228 		{ UBCMTP_SN_COORD, -4750, 5280 },
229 		{ UBCMTP_SN_COORD, -150, 6730 },
230 		{ UBCMTP_SN_ORIENT, -UBCMTP_FINGER_ORIENT, UBCMTP_FINGER_ORIENT },
231 	},
232 	{
233 		USB_VENDOR_APPLE,
234 		/* MacbookAir4,2 */
235 		USB_PRODUCT_APPLE_WELLSPRING6_ANSI,
236 		USB_PRODUCT_APPLE_WELLSPRING6_ISO,
237 		USB_PRODUCT_APPLE_WELLSPRING6_JIS,
238 		UBCMTP_TYPE2,
239 		{ UBCMTP_SN_PRESSURE, 0, 300 },
240 		{ UBCMTP_SN_WIDTH, 0, 2048 },
241 		{ UBCMTP_SN_COORD, -4620, 5140 },
242 		{ UBCMTP_SN_COORD, -150, 6600 },
243 		{ UBCMTP_SN_ORIENT, -UBCMTP_FINGER_ORIENT, UBCMTP_FINGER_ORIENT },
244 	},
245 	{
246 		USB_VENDOR_APPLE,
247 		/* MacbookAir4,1 */
248 		USB_PRODUCT_APPLE_WELLSPRING6A_ANSI,
249 		USB_PRODUCT_APPLE_WELLSPRING6A_ISO,
250 		USB_PRODUCT_APPLE_WELLSPRING6A_JIS,
251 		UBCMTP_TYPE2,
252 		{ UBCMTP_SN_PRESSURE, 0, 300 },
253 		{ UBCMTP_SN_WIDTH, 0, 2048 },
254 		{ UBCMTP_SN_COORD, -4620, 5140 },
255 		{ UBCMTP_SN_COORD, -150, 6600 },
256 		{ UBCMTP_SN_ORIENT, -UBCMTP_FINGER_ORIENT, UBCMTP_FINGER_ORIENT },
257 	},
258 	{
259 		USB_VENDOR_APPLE,
260 		/* MacbookPro10,1 */
261 		USB_PRODUCT_APPLE_WELLSPRING7_ANSI,
262 		USB_PRODUCT_APPLE_WELLSPRING7_ISO,
263 		USB_PRODUCT_APPLE_WELLSPRING7_JIS,
264 		UBCMTP_TYPE2,
265 		{ UBCMTP_SN_PRESSURE, 0, 300 },
266 		{ UBCMTP_SN_WIDTH, 0, 2048 },
267 		{ UBCMTP_SN_COORD, -4750, 5280 },
268 		{ UBCMTP_SN_COORD, -150, 6730 },
269 		{ UBCMTP_SN_ORIENT, -UBCMTP_FINGER_ORIENT, UBCMTP_FINGER_ORIENT },
270 	},
271 	{
272 		USB_VENDOR_APPLE,
273 		/* MacbookPro10,2 */
274 		USB_PRODUCT_APPLE_WELLSPRING7A_ANSI,
275 		USB_PRODUCT_APPLE_WELLSPRING7A_ISO,
276 		USB_PRODUCT_APPLE_WELLSPRING7A_JIS,
277 		UBCMTP_TYPE2,
278 		{ UBCMTP_SN_PRESSURE, 0, 300 },
279 		{ UBCMTP_SN_WIDTH, 0, 2048 },
280 		{ UBCMTP_SN_COORD, -4750, 5280 },
281 		{ UBCMTP_SN_COORD, -150, 6730 },
282 		{ UBCMTP_SN_ORIENT, -UBCMTP_FINGER_ORIENT, UBCMTP_FINGER_ORIENT },
283 	},
284 	{
285 		USB_VENDOR_APPLE,
286 		/* MacbookAir6,1 */
287 		USB_PRODUCT_APPLE_WELLSPRING8_ANSI,
288 		USB_PRODUCT_APPLE_WELLSPRING8_ISO,
289 		USB_PRODUCT_APPLE_WELLSPRING8_JIS,
290 		UBCMTP_TYPE3,
291 		{ UBCMTP_SN_PRESSURE, 0, 300 },
292 		{ UBCMTP_SN_WIDTH, 0, 2048 },
293 		{ UBCMTP_SN_COORD, -4620, 5140 },
294 		{ UBCMTP_SN_COORD, -150, 6600 },
295 		{ UBCMTP_SN_ORIENT, -UBCMTP_FINGER_ORIENT, UBCMTP_FINGER_ORIENT },
296 	},
297 	{
298 		USB_VENDOR_APPLE,
299 		/* MacbookPro12,1 */
300 		USB_PRODUCT_APPLE_WELLSPRING9_ANSI,
301 		USB_PRODUCT_APPLE_WELLSPRING9_ISO,
302 		USB_PRODUCT_APPLE_WELLSPRING9_JIS,
303 		UBCMTP_TYPE4,
304 		{ UBCMTP_SN_PRESSURE, 0, 300 },
305 		{ UBCMTP_SN_WIDTH, 0, 2048 },
306 		{ UBCMTP_SN_COORD, -4828, 5345 },
307 		{ UBCMTP_SN_COORD, -203, 6803 },
308 		{ UBCMTP_SN_ORIENT, -UBCMTP_FINGER_ORIENT, UBCMTP_FINGER_ORIENT },
309 	},
310 };
311 
312 static struct wsmouse_param ubcmtp_wsmousecfg[] = {
313 	{ WSMOUSECFG_MTBTN_MAXDIST, 0 }, /* 0: Compute a default value. */
314 };
315 
316 struct ubcmtp_softc {
317 	struct device		sc_dev;		/* base device */
318 
319 	const struct ubcmtp_dev	*dev_type;
320 
321 	struct usbd_device	*sc_udev;
322 	struct device		*sc_wsmousedev;
323 
324 	struct usbd_interface	*sc_tp_iface;	/* trackpad interface */
325 	struct usbd_pipe	*sc_tp_pipe;	/* trackpad pipe */
326 	int			sc_tp_epaddr;	/* endpoint addr */
327 	int			tp_maxlen;	/* max size of tp data */
328 	int			tp_offset;	/* finger offset into data */
329 	int			tp_fingerpad;	/* padding between finger data */
330 	uint8_t			*tp_pkt;
331 
332 	struct usbd_interface	*sc_bt_iface;	/* button interface */
333 	struct usbd_pipe	*sc_bt_pipe;	/* button pipe */
334 	int			sc_bt_epaddr;	/* endpoint addr */
335 	int			bt_maxlen;	/* max size of button data */
336 	uint8_t			*bt_pkt;
337 
338 	uint32_t		sc_status;
339 #define UBCMTP_ENABLED		1
340 
341 	struct mtpoint		frame[UBCMTP_MAX_FINGERS];
342 	int			contacts;
343 	int			btn;
344 };
345 
346 int	ubcmtp_enable(void *);
347 void	ubcmtp_disable(void *);
348 int	ubcmtp_ioctl(void *, unsigned long, caddr_t, int, struct proc *);
349 int	ubcmtp_raw_mode(struct ubcmtp_softc *, int);
350 int	ubcmtp_setup_pipes(struct ubcmtp_softc *);
351 void	ubcmtp_bt_intr(struct usbd_xfer *, void *, usbd_status);
352 void	ubcmtp_tp_intr(struct usbd_xfer *, void *, usbd_status);
353 
354 int	ubcmtp_match(struct device *, void *, void *);
355 void	ubcmtp_attach(struct device *, struct device *, void *);
356 int	ubcmtp_detach(struct device *, int);
357 int	ubcmtp_activate(struct device *, int);
358 int	ubcmtp_configure(struct ubcmtp_softc *);
359 
360 const struct wsmouse_accessops ubcmtp_accessops = {
361 	ubcmtp_enable,
362 	ubcmtp_ioctl,
363 	ubcmtp_disable,
364 };
365 
366 struct cfdriver ubcmtp_cd = {
367 	NULL, "ubcmtp", DV_DULL
368 };
369 
370 const struct cfattach ubcmtp_ca = {
371 	sizeof(struct ubcmtp_softc), ubcmtp_match, ubcmtp_attach, ubcmtp_detach,
372 	ubcmtp_activate,
373 };
374 
375 int
376 ubcmtp_match(struct device *parent, void *match, void *aux)
377 {
378 	struct usb_attach_arg *uaa = aux;
379 	usb_interface_descriptor_t *id;
380 	int i;
381 
382 	if (uaa->iface == NULL)
383 		return (UMATCH_NONE);
384 
385 	for (i = 0; i < nitems(ubcmtp_devices); i++) {
386 		if (uaa->vendor == ubcmtp_devices[i].vendor && (
387 		    uaa->product == ubcmtp_devices[i].ansi ||
388 		    uaa->product == ubcmtp_devices[i].iso ||
389 		    uaa->product == ubcmtp_devices[i].jis)) {
390 			if (uaa->nifaces < 2)
391 				return (UMATCH_NONE);
392 			if ((ubcmtp_devices[i].type != UBCMTP_TYPE2) &&
393 			    (uaa->nifaces < 3))
394 				return (UMATCH_NONE);
395 
396 			/*
397 			 * The USB keyboard/mouse device will have one keyboard
398 			 * HID and two mouse HIDs, though only one will have a
399 			 * protocol of mouse -- we only want to take control of
400 			 * that one.
401 			 */
402 			id = usbd_get_interface_descriptor(uaa->iface);
403 			if (id->bInterfaceProtocol == UIPROTO_BOOT_MOUSE)
404 				return (UMATCH_VENDOR_PRODUCT_CONF_IFACE);
405 		}
406 	}
407 
408 	return (UMATCH_NONE);
409 }
410 
411 void
412 ubcmtp_attach(struct device *parent, struct device *self, void *aux)
413 {
414 	struct ubcmtp_softc *sc = (struct ubcmtp_softc *)self;
415 	struct usb_attach_arg *uaa = aux;
416 	struct usbd_device *dev = uaa->device;
417 	struct wsmousedev_attach_args a;
418 	usb_device_descriptor_t *udd;
419 	int i;
420 
421 	sc->sc_udev = uaa->device;
422 	sc->sc_status = 0;
423 	sc->tp_fingerpad = 0;
424 
425 	if ((udd = usbd_get_device_descriptor(dev)) == NULL) {
426 		printf("ubcmtp: failed getting device descriptor\n");
427 		return;
428 	}
429 
430 	for (i = 0; i < nitems(ubcmtp_devices); i++) {
431 		if (uaa->vendor == ubcmtp_devices[i].vendor && (
432 		    uaa->product == ubcmtp_devices[i].ansi ||
433 		    uaa->product == ubcmtp_devices[i].iso ||
434 		    uaa->product == ubcmtp_devices[i].jis)) {
435 			sc->dev_type = &ubcmtp_devices[i];
436 			DPRINTF("%s: attached to 0x%x/0x%x type %d\n",
437 			    sc->sc_dev.dv_xname, uaa->vendor, uaa->product,
438 			    sc->dev_type->type);
439 			break;
440 		}
441 	}
442 
443 	if (sc->dev_type == NULL) {
444 		/* how did we match then? */
445 		printf("%s: failed looking up device in table\n",
446 		    sc->sc_dev.dv_xname);
447 		return;
448 	}
449 
450 	switch (sc->dev_type->type) {
451 	case UBCMTP_TYPE1:
452 		sc->tp_maxlen = UBCMTP_TYPE1_TPLEN;
453 		sc->tp_offset = UBCMTP_TYPE1_TPOFF;
454 		sc->sc_tp_iface = uaa->ifaces[UBCMTP_TYPE1_TPIFACE];
455 		usbd_claim_iface(sc->sc_udev, UBCMTP_TYPE1_TPIFACE);
456 
457 		/* button offsets */
458 		sc->bt_maxlen = sizeof(struct ubcmtp_button);
459 		sc->sc_bt_iface = uaa->ifaces[UBCMTP_TYPE1_BTIFACE];
460 		usbd_claim_iface(sc->sc_udev, UBCMTP_TYPE1_BTIFACE);
461 		break;
462 
463 	case UBCMTP_TYPE2:
464 		sc->tp_maxlen = UBCMTP_TYPE2_TPLEN;
465 		sc->tp_offset = UBCMTP_TYPE2_TPOFF;
466 		sc->sc_tp_iface = uaa->ifaces[UBCMTP_TYPE2_TPIFACE];
467 		usbd_claim_iface(sc->sc_udev, UBCMTP_TYPE2_TPIFACE);
468 		break;
469 
470 	case UBCMTP_TYPE3:
471 		sc->tp_maxlen = UBCMTP_TYPE3_TPLEN;
472 		sc->tp_offset = UBCMTP_TYPE3_TPOFF;
473 		sc->sc_tp_iface = uaa->ifaces[UBCMTP_TYPE3_TPIFACE];
474 		usbd_claim_iface(sc->sc_udev, UBCMTP_TYPE3_TPIFACE);
475 		break;
476 
477 	case UBCMTP_TYPE4:
478 		sc->tp_maxlen = UBCMTP_TYPE4_TPLEN;
479 		sc->tp_offset = UBCMTP_TYPE4_TPOFF;
480 		sc->sc_tp_iface = uaa->ifaces[UBCMTP_TYPE4_TPIFACE];
481 		sc->tp_fingerpad = UBCMTP_TYPE4_FINGERPAD;
482 		usbd_claim_iface(sc->sc_udev, UBCMTP_TYPE4_TPIFACE);
483 		break;
484 	}
485 
486 	a.accessops = &ubcmtp_accessops;
487 	a.accesscookie = sc;
488 
489 	sc->sc_wsmousedev = config_found(self, &a, wsmousedevprint);
490 	if (sc->sc_wsmousedev != NULL && ubcmtp_configure(sc))
491 		ubcmtp_disable(sc);
492 }
493 
494 int
495 ubcmtp_detach(struct device *self, int flags)
496 {
497 	struct ubcmtp_softc *sc = (struct ubcmtp_softc *)self;
498 	int ret = 0;
499 
500 	if (sc->sc_wsmousedev != NULL)
501 		ret = config_detach(sc->sc_wsmousedev, flags);
502 
503 	return (ret);
504 }
505 
506 int
507 ubcmtp_activate(struct device *self, int act)
508 {
509 	struct ubcmtp_softc *sc = (struct ubcmtp_softc *)self;
510 	int rv = 0;
511 
512 	if (act == DVACT_DEACTIVATE) {
513 		if (sc->sc_wsmousedev != NULL)
514 			rv = config_deactivate(sc->sc_wsmousedev);
515 		usbd_deactivate(sc->sc_udev);
516 	}
517 
518 	return (rv);
519 }
520 
521 int
522 ubcmtp_configure(struct ubcmtp_softc *sc)
523 {
524 	struct wsmousehw *hw = wsmouse_get_hw(sc->sc_wsmousedev);
525 
526 	hw->type = WSMOUSE_TYPE_TOUCHPAD;
527 	hw->hw_type = (IS_CLICKPAD(sc->dev_type->type)
528 	    ? WSMOUSEHW_CLICKPAD : WSMOUSEHW_TOUCHPAD);
529 	hw->x_min = sc->dev_type->l_x.min;
530 	hw->x_max = sc->dev_type->l_x.max;
531 	hw->y_min = sc->dev_type->l_y.min;
532 	hw->y_max = sc->dev_type->l_y.max;
533 	hw->mt_slots = UBCMTP_MAX_FINGERS;
534 	hw->flags = WSMOUSEHW_MT_TRACKING;
535 
536 	return wsmouse_configure(sc->sc_wsmousedev,
537 	    ubcmtp_wsmousecfg, nitems(ubcmtp_wsmousecfg));
538 }
539 
540 int
541 ubcmtp_enable(void *v)
542 {
543 	struct ubcmtp_softc *sc = v;
544 
545 	if (sc->sc_status & UBCMTP_ENABLED)
546 		return (EBUSY);
547 
548 	if (usbd_is_dying(sc->sc_udev))
549 		return (EIO);
550 
551 	if (ubcmtp_raw_mode(sc, 1) != 0) {
552 		printf("%s: failed to enter raw mode\n", sc->sc_dev.dv_xname);
553 		return (1);
554 	}
555 
556 	if (ubcmtp_setup_pipes(sc) == 0) {
557 		sc->sc_status |= UBCMTP_ENABLED;
558 		return (0);
559 	} else
560 		return (1);
561 }
562 
563 void
564 ubcmtp_disable(void *v)
565 {
566 	struct ubcmtp_softc *sc = v;
567 
568 	if (usbd_is_dying(sc->sc_udev) || !(sc->sc_status & UBCMTP_ENABLED))
569 		return;
570 
571 	sc->sc_status &= ~UBCMTP_ENABLED;
572 
573 	ubcmtp_raw_mode(sc, 0);
574 
575 	if (sc->sc_tp_pipe != NULL) {
576 		usbd_close_pipe(sc->sc_tp_pipe);
577 		sc->sc_tp_pipe = NULL;
578 	}
579 	if (sc->sc_bt_pipe != NULL) {
580 		usbd_close_pipe(sc->sc_bt_pipe);
581 		sc->sc_bt_pipe = NULL;
582 	}
583 
584 	if (sc->tp_pkt != NULL) {
585 		free(sc->tp_pkt, M_USBDEV, sc->tp_maxlen);
586 		sc->tp_pkt = NULL;
587 	}
588 	if (sc->bt_pkt != NULL) {
589 		free(sc->bt_pkt, M_USBDEV, sc->bt_maxlen);
590 		sc->bt_pkt = NULL;
591 	}
592 }
593 
594 int
595 ubcmtp_ioctl(void *v, unsigned long cmd, caddr_t data, int flag, struct proc *p)
596 {
597 	struct ubcmtp_softc *sc = v;
598 	struct wsmouse_calibcoords *wsmc = (struct wsmouse_calibcoords *)data;
599 	int wsmode;
600 
601 	DPRINTF("%s: in %s with cmd 0x%lx\n", sc->sc_dev.dv_xname, __func__,
602 	    cmd);
603 
604 	switch (cmd) {
605 	case WSMOUSEIO_GTYPE: {
606 		struct wsmousehw *hw = wsmouse_get_hw(sc->sc_wsmousedev);
607 		*(u_int *)data = hw->type;
608 		break;
609 	}
610 
611 	case WSMOUSEIO_GCALIBCOORDS:
612 		wsmc->minx = sc->dev_type->l_x.min;
613 		wsmc->maxx = sc->dev_type->l_x.max;
614 		wsmc->miny = sc->dev_type->l_y.min;
615 		wsmc->maxy = sc->dev_type->l_y.max;
616 		wsmc->swapxy = 0;
617 		wsmc->resx = 0;
618 		wsmc->resy = 0;
619 		break;
620 
621 	case WSMOUSEIO_SETMODE:
622 		wsmode = *(u_int *)data;
623 		if (wsmode != WSMOUSE_COMPAT && wsmode != WSMOUSE_NATIVE) {
624 			printf("%s: invalid mode %d\n", sc->sc_dev.dv_xname,
625 			    wsmode);
626 			return (EINVAL);
627 		}
628 		wsmouse_set_mode(sc->sc_wsmousedev, wsmode);
629 
630 		DPRINTF("%s: changing mode to %s\n",
631 		    sc->sc_dev.dv_xname, (wsmode == WSMOUSE_COMPAT ? "compat" :
632 		    "native"));
633 
634 		break;
635 
636 	default:
637 		return (-1);
638 	}
639 
640 	return (0);
641 }
642 
643 int
644 ubcmtp_raw_mode(struct ubcmtp_softc *sc, int enable)
645 {
646 	usb_device_request_t r;
647 	usbd_status err;
648 	uint8_t buf[8];
649 
650 	/* type 3 has no raw mode */
651 	if (sc->dev_type->type == UBCMTP_TYPE3)
652 		return (0);
653 
654 	r.bRequest = UR_GET_REPORT;
655 	r.bmRequestType = UT_READ_CLASS_INTERFACE;
656 	if (sc->dev_type->type < UBCMTP_TYPE4) {
657 		USETW2(r.wValue, UHID_FEATURE_REPORT, 0);
658 		USETW(r.wIndex, 0);
659 		USETW(r.wLength, UBCMTP_WELLSPRING_MODE_LEN);
660 	} else {
661 		USETW2(r.wValue, UHID_FEATURE_REPORT, 2);
662 		USETW(r.wIndex, 2);
663 		USETW(r.wLength, UBCMTP_WELLSPRING9_MODE_LEN);
664 	}
665 
666 	err = usbd_do_request(sc->sc_udev, &r, buf);
667 	if (err != USBD_NORMAL_COMPLETION) {
668 		printf("%s: %s: failed to get feature report\n",
669 		    sc->sc_dev.dv_xname, __func__);
670 		return (err);
671 	}
672 
673 	/* toggle magic byte and write everything back */
674 	if (sc->dev_type->type < UBCMTP_TYPE4)
675 		buf[0] = (enable ? UBCMTP_WELLSPRING_MODE_RAW :
676 		    UBCMTP_WELLSPRING_MODE_HID);
677 	else
678 		buf[1] = (enable ? UBCMTP_WELLSPRING9_MODE_RAW :
679 		    UBCMTP_WELLSPRING9_MODE_HID);
680 
681 	r.bRequest = UR_SET_REPORT;
682 	r.bmRequestType = UT_WRITE_CLASS_INTERFACE;
683 	if (sc->dev_type->type < UBCMTP_TYPE4) {
684 		USETW2(r.wValue, UHID_FEATURE_REPORT, 0);
685 		USETW(r.wIndex, 0);
686 		USETW(r.wLength, UBCMTP_WELLSPRING_MODE_LEN);
687 	} else {
688 		USETW2(r.wValue, UHID_FEATURE_REPORT, 2);
689 		USETW(r.wIndex, 2);
690 		USETW(r.wLength, UBCMTP_WELLSPRING9_MODE_LEN);
691 	}
692 
693 	err = usbd_do_request(sc->sc_udev, &r, buf);
694 	if (err != USBD_NORMAL_COMPLETION) {
695 		printf("%s: %s: failed to toggle raw mode\n",
696 		    sc->sc_dev.dv_xname, __func__);
697 		return (err);
698 	}
699 
700 	return (0);
701 }
702 
703 int
704 ubcmtp_setup_pipes(struct ubcmtp_softc *sc)
705 {
706 	usbd_status err;
707 	usb_endpoint_descriptor_t *ed;
708 
709 	if (sc->dev_type->type == UBCMTP_TYPE1) {
710 		/* setup physical button pipe */
711 
712 		ed = usbd_interface2endpoint_descriptor(sc->sc_bt_iface, 0);
713 		if (ed == NULL) {
714 			printf("%s: failed getting button endpoint descriptor\n",
715 			    sc->sc_dev.dv_xname);
716 			goto fail1;
717 		}
718 		sc->sc_bt_epaddr = ed->bEndpointAddress;
719 		sc->bt_pkt = malloc(sc->bt_maxlen, M_USBDEV, M_WAITOK);
720 		if (sc->bt_pkt == NULL)
721 			goto fail1;
722 
723 		DPRINTF("%s: button iface at 0x%x, max size %d\n",
724 		    sc->sc_dev.dv_xname, sc->sc_bt_epaddr, sc->bt_maxlen);
725 
726 		err = usbd_open_pipe_intr(sc->sc_bt_iface, sc->sc_bt_epaddr,
727 		    USBD_SHORT_XFER_OK, &sc->sc_bt_pipe, sc, sc->bt_pkt,
728 		    sc->bt_maxlen, ubcmtp_bt_intr, USBD_DEFAULT_INTERVAL);
729 		if (err != USBD_NORMAL_COMPLETION) {
730 			printf("%s: failed opening button pipe\n",
731 			    sc->sc_dev.dv_xname);
732 			goto fail1;
733 		}
734 	}
735 
736 	/* setup trackpad data pipe */
737 
738 	ed = usbd_interface2endpoint_descriptor(sc->sc_tp_iface, 0);
739 	if (ed == NULL) {
740 		printf("%s: failed getting trackpad data endpoint descriptor\n",
741 		    sc->sc_dev.dv_xname);
742 		goto fail2;
743 	}
744 	sc->sc_tp_epaddr = ed->bEndpointAddress;
745 	sc->tp_pkt = malloc(sc->tp_maxlen, M_USBDEV, M_WAITOK);
746 	if (sc->tp_pkt == NULL)
747 		goto fail2;
748 
749 	DPRINTF("%s: trackpad data iface at 0x%x, max size %d\n",
750 	    sc->sc_dev.dv_xname, sc->sc_tp_epaddr, sc->tp_maxlen);
751 
752 	err = usbd_open_pipe_intr(sc->sc_tp_iface, sc->sc_tp_epaddr,
753 	    USBD_SHORT_XFER_OK, &sc->sc_tp_pipe, sc, sc->tp_pkt, sc->tp_maxlen,
754 	    ubcmtp_tp_intr, USBD_DEFAULT_INTERVAL);
755 	if (err != USBD_NORMAL_COMPLETION) {
756 		printf("%s: error opening trackpad data pipe\n",
757 		    sc->sc_dev.dv_xname);
758 		goto fail2;
759 	}
760 
761 	return (0);
762 
763 fail2:
764 	if (sc->sc_tp_pipe != NULL)
765 		usbd_close_pipe(sc->sc_tp_pipe);
766 	if (sc->tp_pkt != NULL)
767 		free(sc->tp_pkt, M_USBDEV, sc->tp_maxlen);
768 fail1:
769 	if (sc->sc_bt_pipe != NULL)
770 		usbd_close_pipe(sc->sc_bt_pipe);
771 	if (sc->bt_pkt != NULL)
772 		free(sc->bt_pkt, M_USBDEV, sc->bt_maxlen);
773 
774 	return (1);
775 }
776 
777 void
778 ubcmtp_tp_intr(struct usbd_xfer *xfer, void *priv, usbd_status status)
779 {
780 	struct ubcmtp_softc *sc = priv;
781 	struct ubcmtp_finger *finger;
782 	u_int32_t pktlen;
783 	int off, s, btn, contacts = 0;
784 
785 	if (usbd_is_dying(sc->sc_udev) || !(sc->sc_status & UBCMTP_ENABLED))
786 		return;
787 
788 	if (status != USBD_NORMAL_COMPLETION) {
789 		DPRINTF("%s: %s with status 0x%x\n", sc->sc_dev.dv_xname,
790 		    __func__, status);
791 
792 		if (status == USBD_NOT_STARTED || status == USBD_CANCELLED)
793 			return;
794 		if (status == USBD_STALLED)
795 			usbd_clear_endpoint_stall_async(sc->sc_tp_pipe);
796 		return;
797 	}
798 
799 	usbd_get_xfer_status(xfer, NULL, NULL, &pktlen, NULL);
800 
801 	if (sc->tp_pkt == NULL || pktlen < sc->tp_offset)
802 		return;
803 
804 	contacts = 0;
805 	for (off = sc->tp_offset; off < pktlen;
806 	    off += (sizeof(struct ubcmtp_finger) + sc->tp_fingerpad)) {
807 		finger = (struct ubcmtp_finger *)(sc->tp_pkt + off);
808 
809 		if ((int16_t)letoh16(finger->touch_major) == 0)
810 			continue; /* finger lifted */
811 
812 		sc->frame[contacts].x = (int16_t)letoh16(finger->abs_x);
813 		sc->frame[contacts].y = (int16_t)letoh16(finger->abs_y);
814 		sc->frame[contacts].pressure = DEFAULT_PRESSURE;
815 		contacts++;
816 	}
817 
818 	btn = sc->btn;
819 	if (sc->dev_type->type == UBCMTP_TYPE2)
820 		sc->btn = !!((int16_t)letoh16(sc->tp_pkt[UBCMTP_TYPE2_BTOFF]));
821 	else if (sc->dev_type->type == UBCMTP_TYPE3)
822 		sc->btn = !!((int16_t)letoh16(sc->tp_pkt[UBCMTP_TYPE3_BTOFF]));
823 	else if (sc->dev_type->type == UBCMTP_TYPE4)
824 		sc->btn = !!((int16_t)letoh16(sc->tp_pkt[UBCMTP_TYPE4_BTOFF]));
825 
826 	if (contacts || sc->contacts || sc->btn != btn) {
827 		sc->contacts = contacts;
828 		s = spltty();
829 		wsmouse_buttons(sc->sc_wsmousedev, sc->btn);
830 		wsmouse_mtframe(sc->sc_wsmousedev, sc->frame, contacts);
831 		wsmouse_input_sync(sc->sc_wsmousedev);
832 		splx(s);
833 	}
834 }
835 
836 /* hardware button interrupt */
837 void
838 ubcmtp_bt_intr(struct usbd_xfer *xfer, void *priv, usbd_status status)
839 {
840 	struct ubcmtp_softc *sc = priv;
841 	struct ubcmtp_button *pkt;
842 	u_int32_t len;
843 
844 	if (usbd_is_dying(sc->sc_udev) || !(sc->sc_status & UBCMTP_ENABLED))
845 		return;
846 
847 	if (status != USBD_NORMAL_COMPLETION) {
848 		DPRINTF("%s: %s with status 0x%x\n", sc->sc_dev.dv_xname,
849 		    __func__, status);
850 		if (status == USBD_NOT_STARTED || status == USBD_CANCELLED)
851 			return;
852 		if (status == USBD_STALLED)
853 			usbd_clear_endpoint_stall_async(sc->sc_tp_pipe);
854 		return;
855 	}
856 
857 	usbd_get_xfer_status(xfer, NULL, NULL, &len, NULL);
858 
859 	if (sc->bt_pkt == NULL || len < sizeof(struct ubcmtp_button))
860 		return;
861 
862 	pkt = (struct ubcmtp_button *)(sc->bt_pkt);
863 
864 	DPRINTF("%s: button interrupt (%d, %d, %d, %d)", sc->sc_dev.dv_xname,
865 	    pkt->unused, pkt->button, pkt->rel_x, pkt->rel_y);
866 
867 	if (pkt->button != sc->btn) {
868 		sc->btn = pkt->button;
869 		wsmouse_buttons(sc->sc_wsmousedev, sc->btn);
870 		wsmouse_input_sync(sc->sc_wsmousedev);
871 	}
872 }
873