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