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