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