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