1 /* $OpenBSD: ubcmtp.c,v 1.21 2020/07/31 10:49:33 mglocker 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_close_pipe(sc->sc_tp_pipe); 587 sc->sc_tp_pipe = NULL; 588 } 589 if (sc->sc_bt_pipe != NULL) { 590 usbd_close_pipe(sc->sc_bt_pipe); 591 sc->sc_bt_pipe = NULL; 592 } 593 594 if (sc->tp_pkt != NULL) { 595 free(sc->tp_pkt, M_USBDEV, sc->tp_maxlen); 596 sc->tp_pkt = NULL; 597 } 598 if (sc->bt_pkt != NULL) { 599 free(sc->bt_pkt, M_USBDEV, sc->bt_maxlen); 600 sc->bt_pkt = NULL; 601 } 602 } 603 604 int 605 ubcmtp_ioctl(void *v, unsigned long cmd, caddr_t data, int flag, struct proc *p) 606 { 607 struct ubcmtp_softc *sc = v; 608 struct wsmouse_calibcoords *wsmc = (struct wsmouse_calibcoords *)data; 609 int wsmode; 610 611 DPRINTF("%s: in %s with cmd 0x%lx\n", sc->sc_dev.dv_xname, __func__, 612 cmd); 613 614 switch (cmd) { 615 case WSMOUSEIO_GTYPE: { 616 struct wsmousehw *hw = wsmouse_get_hw(sc->sc_wsmousedev); 617 *(u_int *)data = hw->type; 618 break; 619 } 620 621 case WSMOUSEIO_GCALIBCOORDS: 622 wsmc->minx = sc->dev_type->l_x.min; 623 wsmc->maxx = sc->dev_type->l_x.max; 624 wsmc->miny = sc->dev_type->l_y.min; 625 wsmc->maxy = sc->dev_type->l_y.max; 626 wsmc->swapxy = 0; 627 wsmc->resx = 0; 628 wsmc->resy = 0; 629 break; 630 631 case WSMOUSEIO_SETMODE: 632 wsmode = *(u_int *)data; 633 if (wsmode != WSMOUSE_COMPAT && wsmode != WSMOUSE_NATIVE) { 634 printf("%s: invalid mode %d\n", sc->sc_dev.dv_xname, 635 wsmode); 636 return (EINVAL); 637 } 638 wsmouse_set_mode(sc->sc_wsmousedev, wsmode); 639 640 DPRINTF("%s: changing mode to %s\n", 641 sc->sc_dev.dv_xname, (wsmode == WSMOUSE_COMPAT ? "compat" : 642 "native")); 643 644 break; 645 646 default: 647 return (-1); 648 } 649 650 return (0); 651 } 652 653 int 654 ubcmtp_raw_mode(struct ubcmtp_softc *sc, int enable) 655 { 656 usb_device_request_t r; 657 usbd_status err; 658 uint8_t buf[8]; 659 660 /* type 3 has no raw mode */ 661 if (sc->dev_type->type == UBCMTP_TYPE3) 662 return (0); 663 664 r.bRequest = UR_GET_REPORT; 665 r.bmRequestType = UT_READ_CLASS_INTERFACE; 666 if (sc->dev_type->type < UBCMTP_TYPE4) { 667 USETW2(r.wValue, UHID_FEATURE_REPORT, 0); 668 USETW(r.wIndex, 0); 669 USETW(r.wLength, UBCMTP_WELLSPRING_MODE_LEN); 670 } else { 671 USETW2(r.wValue, UHID_FEATURE_REPORT, 2); 672 USETW(r.wIndex, 2); 673 USETW(r.wLength, UBCMTP_WELLSPRING9_MODE_LEN); 674 } 675 676 err = usbd_do_request(sc->sc_udev, &r, buf); 677 if (err != USBD_NORMAL_COMPLETION) { 678 printf("%s: %s: failed to get feature report\n", 679 sc->sc_dev.dv_xname, __func__); 680 return (err); 681 } 682 683 /* toggle magic byte and write everything back */ 684 if (sc->dev_type->type < UBCMTP_TYPE4) 685 buf[0] = (enable ? UBCMTP_WELLSPRING_MODE_RAW : 686 UBCMTP_WELLSPRING_MODE_HID); 687 else 688 buf[1] = (enable ? UBCMTP_WELLSPRING9_MODE_RAW : 689 UBCMTP_WELLSPRING9_MODE_HID); 690 691 r.bRequest = UR_SET_REPORT; 692 r.bmRequestType = UT_WRITE_CLASS_INTERFACE; 693 if (sc->dev_type->type < UBCMTP_TYPE4) { 694 USETW2(r.wValue, UHID_FEATURE_REPORT, 0); 695 USETW(r.wIndex, 0); 696 USETW(r.wLength, UBCMTP_WELLSPRING_MODE_LEN); 697 } else { 698 USETW2(r.wValue, UHID_FEATURE_REPORT, 2); 699 USETW(r.wIndex, 2); 700 USETW(r.wLength, UBCMTP_WELLSPRING9_MODE_LEN); 701 } 702 703 err = usbd_do_request(sc->sc_udev, &r, buf); 704 if (err != USBD_NORMAL_COMPLETION) { 705 printf("%s: %s: failed to toggle raw mode\n", 706 sc->sc_dev.dv_xname, __func__); 707 return (err); 708 } 709 710 return (0); 711 } 712 713 int 714 ubcmtp_setup_pipes(struct ubcmtp_softc *sc) 715 { 716 usbd_status err; 717 usb_endpoint_descriptor_t *ed; 718 719 if (sc->dev_type->type == UBCMTP_TYPE1) { 720 /* setup physical button pipe */ 721 722 ed = usbd_interface2endpoint_descriptor(sc->sc_bt_iface, 0); 723 if (ed == NULL) { 724 printf("%s: failed getting button endpoint descriptor\n", 725 sc->sc_dev.dv_xname); 726 goto fail1; 727 } 728 sc->sc_bt_epaddr = ed->bEndpointAddress; 729 sc->bt_pkt = malloc(sc->bt_maxlen, M_USBDEV, M_WAITOK); 730 if (sc->bt_pkt == NULL) 731 goto fail1; 732 733 DPRINTF("%s: button iface at 0x%x, max size %d\n", 734 sc->sc_dev.dv_xname, sc->sc_bt_epaddr, sc->bt_maxlen); 735 736 err = usbd_open_pipe_intr(sc->sc_bt_iface, sc->sc_bt_epaddr, 737 USBD_SHORT_XFER_OK, &sc->sc_bt_pipe, sc, sc->bt_pkt, 738 sc->bt_maxlen, ubcmtp_bt_intr, USBD_DEFAULT_INTERVAL); 739 if (err != USBD_NORMAL_COMPLETION) { 740 printf("%s: failed opening button pipe\n", 741 sc->sc_dev.dv_xname); 742 goto fail1; 743 } 744 } 745 746 /* setup trackpad data pipe */ 747 748 ed = usbd_interface2endpoint_descriptor(sc->sc_tp_iface, 0); 749 if (ed == NULL) { 750 printf("%s: failed getting trackpad data endpoint descriptor\n", 751 sc->sc_dev.dv_xname); 752 goto fail2; 753 } 754 sc->sc_tp_epaddr = ed->bEndpointAddress; 755 sc->tp_pkt = malloc(sc->tp_maxlen, M_USBDEV, M_WAITOK); 756 if (sc->tp_pkt == NULL) 757 goto fail2; 758 759 DPRINTF("%s: trackpad data iface at 0x%x, max size %d\n", 760 sc->sc_dev.dv_xname, sc->sc_tp_epaddr, sc->tp_maxlen); 761 762 err = usbd_open_pipe_intr(sc->sc_tp_iface, sc->sc_tp_epaddr, 763 USBD_SHORT_XFER_OK, &sc->sc_tp_pipe, sc, sc->tp_pkt, sc->tp_maxlen, 764 ubcmtp_tp_intr, USBD_DEFAULT_INTERVAL); 765 if (err != USBD_NORMAL_COMPLETION) { 766 printf("%s: error opening trackpad data pipe\n", 767 sc->sc_dev.dv_xname); 768 goto fail2; 769 } 770 771 return (0); 772 773 fail2: 774 if (sc->sc_tp_pipe != NULL) 775 usbd_close_pipe(sc->sc_tp_pipe); 776 if (sc->tp_pkt != NULL) 777 free(sc->tp_pkt, M_USBDEV, sc->tp_maxlen); 778 fail1: 779 if (sc->sc_bt_pipe != NULL) 780 usbd_close_pipe(sc->sc_bt_pipe); 781 if (sc->bt_pkt != NULL) 782 free(sc->bt_pkt, M_USBDEV, sc->bt_maxlen); 783 784 return (1); 785 } 786 787 void 788 ubcmtp_tp_intr(struct usbd_xfer *xfer, void *priv, usbd_status status) 789 { 790 struct ubcmtp_softc *sc = priv; 791 struct ubcmtp_finger *finger; 792 u_int32_t pktlen; 793 int off, s, btn, contacts = 0; 794 795 if (usbd_is_dying(sc->sc_udev) || !(sc->sc_status & UBCMTP_ENABLED)) 796 return; 797 798 if (status != USBD_NORMAL_COMPLETION) { 799 DPRINTF("%s: %s with status 0x%x\n", sc->sc_dev.dv_xname, 800 __func__, status); 801 802 if (status == USBD_NOT_STARTED || status == USBD_CANCELLED) 803 return; 804 if (status == USBD_STALLED) 805 usbd_clear_endpoint_stall_async(sc->sc_tp_pipe); 806 return; 807 } 808 809 usbd_get_xfer_status(xfer, NULL, NULL, &pktlen, NULL); 810 811 if (sc->tp_pkt == NULL || pktlen < sc->tp_offset) 812 return; 813 814 contacts = 0; 815 for (off = sc->tp_offset; off < pktlen; 816 off += (sizeof(struct ubcmtp_finger) + sc->tp_fingerpad)) { 817 finger = (struct ubcmtp_finger *)(sc->tp_pkt + off); 818 819 if ((int16_t)letoh16(finger->touch_major) == 0) 820 continue; /* finger lifted */ 821 822 sc->frame[contacts].x = (int16_t)letoh16(finger->abs_x); 823 sc->frame[contacts].y = (int16_t)letoh16(finger->abs_y); 824 sc->frame[contacts].pressure = DEFAULT_PRESSURE; 825 contacts++; 826 } 827 828 btn = sc->btn; 829 if (sc->dev_type->type == UBCMTP_TYPE2) 830 sc->btn = !!((int16_t)letoh16(sc->tp_pkt[UBCMTP_TYPE2_BTOFF])); 831 else if (sc->dev_type->type == UBCMTP_TYPE3) 832 sc->btn = !!((int16_t)letoh16(sc->tp_pkt[UBCMTP_TYPE3_BTOFF])); 833 else if (sc->dev_type->type == UBCMTP_TYPE4) 834 sc->btn = !!((int16_t)letoh16(sc->tp_pkt[UBCMTP_TYPE4_BTOFF])); 835 836 if (contacts || sc->contacts || sc->btn != btn) { 837 sc->contacts = contacts; 838 s = spltty(); 839 wsmouse_buttons(sc->sc_wsmousedev, sc->btn); 840 wsmouse_mtframe(sc->sc_wsmousedev, sc->frame, contacts); 841 wsmouse_input_sync(sc->sc_wsmousedev); 842 splx(s); 843 } 844 } 845 846 /* hardware button interrupt */ 847 void 848 ubcmtp_bt_intr(struct usbd_xfer *xfer, void *priv, usbd_status status) 849 { 850 struct ubcmtp_softc *sc = priv; 851 struct ubcmtp_button *pkt; 852 u_int32_t len; 853 854 if (usbd_is_dying(sc->sc_udev) || !(sc->sc_status & UBCMTP_ENABLED)) 855 return; 856 857 if (status != USBD_NORMAL_COMPLETION) { 858 DPRINTF("%s: %s with status 0x%x\n", sc->sc_dev.dv_xname, 859 __func__, status); 860 if (status == USBD_NOT_STARTED || status == USBD_CANCELLED) 861 return; 862 if (status == USBD_STALLED) 863 usbd_clear_endpoint_stall_async(sc->sc_tp_pipe); 864 return; 865 } 866 867 usbd_get_xfer_status(xfer, NULL, NULL, &len, NULL); 868 869 if (sc->bt_pkt == NULL || len < sizeof(struct ubcmtp_button)) 870 return; 871 872 pkt = (struct ubcmtp_button *)(sc->bt_pkt); 873 874 DPRINTF("%s: button interrupt (%d, %d, %d, %d)", sc->sc_dev.dv_xname, 875 pkt->unused, pkt->button, pkt->rel_x, pkt->rel_y); 876 877 if (pkt->button != sc->btn) { 878 sc->btn = pkt->button; 879 wsmouse_buttons(sc->sc_wsmousedev, sc->btn); 880 wsmouse_input_sync(sc->sc_wsmousedev); 881 } 882 } 883