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