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 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 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 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 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 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 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 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 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 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 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 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 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