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