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