1 /* $OpenBSD: ubcmtp.c,v 1.12 2016/03/30 23:34:12 bru 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 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 struct ubcmtp_limit { 129 int limit; 130 int min; 131 int max; 132 }; 133 134 struct ubcmtp_dev { 135 int vendor; /* vendor */ 136 int ansi, iso, jis; /* 3 types of product */ 137 int type; /* 1 (normal) or 2 (integrated btn) */ 138 struct ubcmtp_limit l_pressure; /* finger pressure */ 139 struct ubcmtp_limit l_width; /* finger width */ 140 struct ubcmtp_limit l_x; 141 struct ubcmtp_limit l_y; 142 struct ubcmtp_limit l_orientation; 143 }; 144 145 static struct ubcmtp_dev ubcmtp_devices[] = { 146 /* type 1 devices with separate buttons */ 147 { 148 USB_VENDOR_APPLE, 149 /* MacbookAir */ 150 USB_PRODUCT_APPLE_WELLSPRING_ANSI, 151 USB_PRODUCT_APPLE_WELLSPRING_ISO, 152 USB_PRODUCT_APPLE_WELLSPRING_JIS, 153 UBCMTP_TYPE1, 154 { UBCMTP_SN_PRESSURE, 0, 256 }, 155 { UBCMTP_SN_WIDTH, 0, 2048 }, 156 { UBCMTP_SN_COORD, -4824, 5342 }, 157 { UBCMTP_SN_COORD, -172, 5820 }, 158 { UBCMTP_SN_ORIENT, -UBCMTP_FINGER_ORIENT, UBCMTP_FINGER_ORIENT }, 159 }, 160 { 161 USB_VENDOR_APPLE, 162 /* MacbookProPenryn */ 163 USB_PRODUCT_APPLE_WELLSPRING2_ANSI, 164 USB_PRODUCT_APPLE_WELLSPRING2_ISO, 165 USB_PRODUCT_APPLE_WELLSPRING2_JIS, 166 UBCMTP_TYPE1, 167 { UBCMTP_SN_PRESSURE, 0, 256 }, 168 { UBCMTP_SN_WIDTH, 0, 2048 }, 169 { UBCMTP_SN_COORD, -4824, 4824 }, 170 { UBCMTP_SN_COORD, -172, 4290 }, 171 { UBCMTP_SN_ORIENT, -UBCMTP_FINGER_ORIENT, UBCMTP_FINGER_ORIENT }, 172 }, 173 /* type 2 devices with integrated buttons */ 174 { 175 USB_VENDOR_APPLE, 176 /* Macbook5,1 */ 177 USB_PRODUCT_APPLE_WELLSPRING3_ANSI, 178 USB_PRODUCT_APPLE_WELLSPRING3_ISO, 179 USB_PRODUCT_APPLE_WELLSPRING3_JIS, 180 UBCMTP_TYPE2, 181 { UBCMTP_SN_PRESSURE, 0, 300 }, 182 { UBCMTP_SN_WIDTH, 0, 2048 }, 183 { UBCMTP_SN_COORD, -4460, 5166 }, 184 { UBCMTP_SN_COORD, -75, 6700 }, 185 { UBCMTP_SN_ORIENT, -UBCMTP_FINGER_ORIENT, UBCMTP_FINGER_ORIENT }, 186 }, 187 { 188 USB_VENDOR_APPLE, 189 /* MacbookAir3,1 */ 190 USB_PRODUCT_APPLE_WELLSPRING4A_ANSI, 191 USB_PRODUCT_APPLE_WELLSPRING4A_ISO, 192 USB_PRODUCT_APPLE_WELLSPRING4A_JIS, 193 UBCMTP_TYPE2, 194 { UBCMTP_SN_PRESSURE, 0, 300 }, 195 { UBCMTP_SN_WIDTH, 0, 2048 }, 196 { UBCMTP_SN_COORD, -4616, 5112 }, 197 { UBCMTP_SN_COORD, -142, 5234 }, 198 { UBCMTP_SN_ORIENT, -UBCMTP_FINGER_ORIENT, UBCMTP_FINGER_ORIENT }, 199 }, 200 { 201 USB_VENDOR_APPLE, 202 /* MacbookAir3,2 */ 203 USB_PRODUCT_APPLE_WELLSPRING4_ANSI, 204 USB_PRODUCT_APPLE_WELLSPRING4_ISO, 205 USB_PRODUCT_APPLE_WELLSPRING4_JIS, 206 UBCMTP_TYPE2, 207 { UBCMTP_SN_PRESSURE, 0, 300 }, 208 { UBCMTP_SN_WIDTH, 0, 2048 }, 209 { UBCMTP_SN_COORD, -4620, 5140 }, 210 { UBCMTP_SN_COORD, -150, 6600 }, 211 { UBCMTP_SN_ORIENT, -UBCMTP_FINGER_ORIENT, UBCMTP_FINGER_ORIENT }, 212 }, 213 { 214 USB_VENDOR_APPLE, 215 /* Macbook8 */ 216 USB_PRODUCT_APPLE_WELLSPRING5_ANSI, 217 USB_PRODUCT_APPLE_WELLSPRING5_ISO, 218 USB_PRODUCT_APPLE_WELLSPRING5_JIS, 219 UBCMTP_TYPE2, 220 { UBCMTP_SN_PRESSURE, 0, 300 }, 221 { UBCMTP_SN_WIDTH, 0, 2048 }, 222 { UBCMTP_SN_COORD, -4415, 5050 }, 223 { UBCMTP_SN_COORD, -55, 6680 }, 224 { UBCMTP_SN_ORIENT, -UBCMTP_FINGER_ORIENT, UBCMTP_FINGER_ORIENT }, 225 }, 226 { 227 USB_VENDOR_APPLE, 228 /* Macbook8,2 */ 229 USB_PRODUCT_APPLE_WELLSPRING5A_ANSI, 230 USB_PRODUCT_APPLE_WELLSPRING5A_ISO, 231 USB_PRODUCT_APPLE_WELLSPRING5A_JIS, 232 UBCMTP_TYPE2, 233 { UBCMTP_SN_PRESSURE, 0, 300 }, 234 { UBCMTP_SN_WIDTH, 0, 2048 }, 235 { UBCMTP_SN_COORD, -4750, 5280 }, 236 { UBCMTP_SN_COORD, -150, 6730 }, 237 { UBCMTP_SN_ORIENT, -UBCMTP_FINGER_ORIENT, UBCMTP_FINGER_ORIENT }, 238 }, 239 { 240 USB_VENDOR_APPLE, 241 /* MacbookAir4,2 */ 242 USB_PRODUCT_APPLE_WELLSPRING6_ANSI, 243 USB_PRODUCT_APPLE_WELLSPRING6_ISO, 244 USB_PRODUCT_APPLE_WELLSPRING6_JIS, 245 UBCMTP_TYPE2, 246 { UBCMTP_SN_PRESSURE, 0, 300 }, 247 { UBCMTP_SN_WIDTH, 0, 2048 }, 248 { UBCMTP_SN_COORD, -4620, 5140 }, 249 { UBCMTP_SN_COORD, -150, 6600 }, 250 { UBCMTP_SN_ORIENT, -UBCMTP_FINGER_ORIENT, UBCMTP_FINGER_ORIENT }, 251 }, 252 { 253 USB_VENDOR_APPLE, 254 /* MacbookAir4,1 */ 255 USB_PRODUCT_APPLE_WELLSPRING6A_ANSI, 256 USB_PRODUCT_APPLE_WELLSPRING6A_ISO, 257 USB_PRODUCT_APPLE_WELLSPRING6A_JIS, 258 UBCMTP_TYPE2, 259 { UBCMTP_SN_PRESSURE, 0, 300 }, 260 { UBCMTP_SN_WIDTH, 0, 2048 }, 261 { UBCMTP_SN_COORD, -4620, 5140 }, 262 { UBCMTP_SN_COORD, -150, 6600 }, 263 { UBCMTP_SN_ORIENT, -UBCMTP_FINGER_ORIENT, UBCMTP_FINGER_ORIENT }, 264 }, 265 { 266 USB_VENDOR_APPLE, 267 /* MacbookPro10,1 */ 268 USB_PRODUCT_APPLE_WELLSPRING7_ANSI, 269 USB_PRODUCT_APPLE_WELLSPRING7_ISO, 270 USB_PRODUCT_APPLE_WELLSPRING7_JIS, 271 UBCMTP_TYPE2, 272 { UBCMTP_SN_PRESSURE, 0, 300 }, 273 { UBCMTP_SN_WIDTH, 0, 2048 }, 274 { UBCMTP_SN_COORD, -4750, 5280 }, 275 { UBCMTP_SN_COORD, -150, 6730 }, 276 { UBCMTP_SN_ORIENT, -UBCMTP_FINGER_ORIENT, UBCMTP_FINGER_ORIENT }, 277 }, 278 { 279 USB_VENDOR_APPLE, 280 /* MacbookPro10,2 */ 281 USB_PRODUCT_APPLE_WELLSPRING7A_ANSI, 282 USB_PRODUCT_APPLE_WELLSPRING7A_ISO, 283 USB_PRODUCT_APPLE_WELLSPRING7A_JIS, 284 UBCMTP_TYPE2, 285 { UBCMTP_SN_PRESSURE, 0, 300 }, 286 { UBCMTP_SN_WIDTH, 0, 2048 }, 287 { UBCMTP_SN_COORD, -4750, 5280 }, 288 { UBCMTP_SN_COORD, -150, 6730 }, 289 { UBCMTP_SN_ORIENT, -UBCMTP_FINGER_ORIENT, UBCMTP_FINGER_ORIENT }, 290 }, 291 { 292 USB_VENDOR_APPLE, 293 /* MacbookAir6,1 */ 294 USB_PRODUCT_APPLE_WELLSPRING8_ANSI, 295 USB_PRODUCT_APPLE_WELLSPRING8_ISO, 296 USB_PRODUCT_APPLE_WELLSPRING8_JIS, 297 UBCMTP_TYPE3, 298 { UBCMTP_SN_PRESSURE, 0, 300 }, 299 { UBCMTP_SN_WIDTH, 0, 2048 }, 300 { UBCMTP_SN_COORD, -4620, 5140 }, 301 { UBCMTP_SN_COORD, -150, 6600 }, 302 { UBCMTP_SN_ORIENT, -UBCMTP_FINGER_ORIENT, UBCMTP_FINGER_ORIENT }, 303 }, 304 { 305 USB_VENDOR_APPLE, 306 /* MacbookPro12,1 */ 307 USB_PRODUCT_APPLE_WELLSPRING9_ANSI, 308 USB_PRODUCT_APPLE_WELLSPRING9_ISO, 309 USB_PRODUCT_APPLE_WELLSPRING9_JIS, 310 UBCMTP_TYPE4, 311 { UBCMTP_SN_PRESSURE, 0, 300 }, 312 { UBCMTP_SN_WIDTH, 0, 2048 }, 313 { UBCMTP_SN_COORD, -4828, 5345 }, 314 { UBCMTP_SN_COORD, -203, 6803 }, 315 { UBCMTP_SN_ORIENT, -UBCMTP_FINGER_ORIENT, UBCMTP_FINGER_ORIENT }, 316 }, 317 }; 318 319 /* coordinates for each tracked finger */ 320 struct ubcmtp_pos { 321 int down; 322 int x; 323 int y; 324 int z; 325 int w; 326 int dx; 327 int dy; 328 }; 329 330 struct ubcmtp_softc { 331 struct device sc_dev; /* base device */ 332 333 struct ubcmtp_dev *dev_type; 334 335 struct uhidev sc_hdev; 336 struct usbd_device *sc_udev; 337 struct device *sc_wsmousedev; 338 int wsmode; 339 340 int tp_ifacenum; /* trackpad interface number */ 341 struct usbd_interface *sc_tp_iface; /* trackpad interface */ 342 struct usbd_pipe *sc_tp_pipe; /* trackpad pipe */ 343 int sc_tp_epaddr; /* endpoint addr */ 344 int tp_maxlen; /* max size of tp data */ 345 int tp_offset; /* finger offset into data */ 346 uint8_t *tp_pkt; 347 348 int bt_ifacenum; /* button interface number */ 349 struct usbd_interface *sc_bt_iface; /* button interface */ 350 struct usbd_pipe *sc_bt_pipe; /* button pipe */ 351 int sc_bt_epaddr; /* endpoint addr */ 352 int bt_maxlen; /* max size of button data */ 353 uint8_t *bt_pkt; 354 355 uint32_t sc_status; 356 #define UBCMTP_ENABLED 1 357 358 struct ubcmtp_pos pos[UBCMTP_MAX_FINGERS]; 359 int btn; 360 }; 361 362 int ubcmtp_enable(void *); 363 void ubcmtp_disable(void *); 364 int ubcmtp_ioctl(void *, unsigned long, caddr_t, int, struct proc *); 365 int ubcmtp_raw_mode(struct ubcmtp_softc *, int); 366 int ubcmtp_setup_pipes(struct ubcmtp_softc *); 367 void ubcmtp_bt_intr(struct usbd_xfer *, void *, usbd_status); 368 void ubcmtp_tp_intr(struct usbd_xfer *, void *, usbd_status); 369 370 int ubcmtp_match(struct device *, void *, void *); 371 void ubcmtp_attach(struct device *, struct device *, void *); 372 int ubcmtp_detach(struct device *, int); 373 int ubcmtp_activate(struct device *, int); 374 375 const struct wsmouse_accessops ubcmtp_accessops = { 376 ubcmtp_enable, 377 ubcmtp_ioctl, 378 ubcmtp_disable, 379 }; 380 381 struct cfdriver ubcmtp_cd = { 382 NULL, "ubcmtp", DV_DULL 383 }; 384 385 const struct cfattach ubcmtp_ca = { 386 sizeof(struct ubcmtp_softc), ubcmtp_match, ubcmtp_attach, ubcmtp_detach, 387 ubcmtp_activate, 388 }; 389 390 int 391 ubcmtp_match(struct device *parent, void *match, void *aux) 392 { 393 struct usb_attach_arg *uaa = aux; 394 usb_interface_descriptor_t *id; 395 int i; 396 397 if (uaa->iface == NULL) 398 return (UMATCH_NONE); 399 400 for (i = 0; i < nitems(ubcmtp_devices); i++) { 401 if (uaa->vendor == ubcmtp_devices[i].vendor && ( 402 uaa->product == ubcmtp_devices[i].ansi || 403 uaa->product == ubcmtp_devices[i].iso || 404 uaa->product == ubcmtp_devices[i].jis)) { 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 433 if ((udd = usbd_get_device_descriptor(dev)) == NULL) { 434 printf("ubcmtp: failed getting device descriptor\n"); 435 return; 436 } 437 438 for (i = 0; i < nitems(ubcmtp_devices); i++) { 439 if (uaa->vendor == ubcmtp_devices[i].vendor && ( 440 uaa->product == ubcmtp_devices[i].ansi || 441 uaa->product == ubcmtp_devices[i].iso || 442 uaa->product == ubcmtp_devices[i].jis)) { 443 sc->dev_type = &ubcmtp_devices[i]; 444 DPRINTF("%s: attached to 0x%x/0x%x type %d\n", 445 sc->sc_dev.dv_xname, uaa->vendor, uaa->product, 446 sc->dev_type->type); 447 break; 448 } 449 } 450 451 if (sc->dev_type == NULL) { 452 /* how did we match then? */ 453 printf("%s: failed looking up device in table\n", 454 sc->sc_dev.dv_xname); 455 return; 456 } 457 458 switch (sc->dev_type->type) { 459 case UBCMTP_TYPE1: 460 sc->tp_maxlen = UBCMTP_TYPE1_TPLEN; 461 sc->tp_offset = UBCMTP_TYPE1_TPOFF; 462 sc->tp_ifacenum = UBCMTP_TYPE1_TPIFACE; 463 464 /* button offsets */ 465 sc->bt_maxlen = sizeof(struct ubcmtp_button); 466 sc->bt_ifacenum = UBCMTP_TYPE1_BTIFACE; 467 break; 468 469 case UBCMTP_TYPE2: 470 sc->tp_maxlen = UBCMTP_TYPE2_TPLEN; 471 sc->tp_offset = UBCMTP_TYPE2_TPOFF; 472 sc->tp_ifacenum = UBCMTP_TYPE2_TPIFACE; 473 break; 474 475 case UBCMTP_TYPE3: 476 sc->tp_maxlen = UBCMTP_TYPE3_TPLEN; 477 sc->tp_offset = UBCMTP_TYPE3_TPOFF; 478 sc->tp_ifacenum = UBCMTP_TYPE3_TPIFACE; 479 break; 480 481 case UBCMTP_TYPE4: 482 sc->tp_maxlen = UBCMTP_TYPE4_TPLEN; 483 sc->tp_offset = UBCMTP_TYPE4_TPOFF; 484 sc->tp_ifacenum = UBCMTP_TYPE4_TPIFACE; 485 break; 486 } 487 488 a.accessops = &ubcmtp_accessops; 489 a.accesscookie = sc; 490 491 sc->sc_wsmousedev = config_found(self, &a, wsmousedevprint); 492 } 493 494 int 495 ubcmtp_detach(struct device *self, int flags) 496 { 497 struct ubcmtp_softc *sc = (struct ubcmtp_softc *)self; 498 int ret = 0; 499 500 if (sc->sc_wsmousedev != NULL) 501 ret = config_detach(sc->sc_wsmousedev, flags); 502 503 return (ret); 504 } 505 506 int 507 ubcmtp_activate(struct device *self, int act) 508 { 509 struct ubcmtp_softc *sc = (struct ubcmtp_softc *)self; 510 int rv = 0; 511 512 if (act == DVACT_DEACTIVATE) { 513 if (sc->sc_wsmousedev != NULL) 514 rv = config_deactivate(sc->sc_wsmousedev); 515 usbd_deactivate(sc->sc_udev); 516 } 517 518 return (rv); 519 } 520 521 int 522 ubcmtp_enable(void *v) 523 { 524 struct ubcmtp_softc *sc = v; 525 526 if (sc->sc_status & UBCMTP_ENABLED) 527 return (EBUSY); 528 529 if (usbd_is_dying(sc->sc_udev)) 530 return (EIO); 531 532 if (ubcmtp_raw_mode(sc, 1) != 0) { 533 printf("%s: failed to enter raw mode\n", sc->sc_dev.dv_xname); 534 return (1); 535 } 536 537 if (ubcmtp_setup_pipes(sc) == 0) { 538 sc->sc_status |= UBCMTP_ENABLED; 539 return (0); 540 } else 541 return (1); 542 } 543 544 void 545 ubcmtp_disable(void *v) 546 { 547 struct ubcmtp_softc *sc = v; 548 549 if (usbd_is_dying(sc->sc_udev) || !(sc->sc_status & UBCMTP_ENABLED)) 550 return; 551 552 sc->sc_status &= ~UBCMTP_ENABLED; 553 554 ubcmtp_raw_mode(sc, 0); 555 556 if (sc->sc_tp_pipe != NULL) { 557 usbd_abort_pipe(sc->sc_tp_pipe); 558 usbd_close_pipe(sc->sc_tp_pipe); 559 sc->sc_tp_pipe = NULL; 560 } 561 if (sc->sc_bt_pipe != NULL) { 562 usbd_abort_pipe(sc->sc_bt_pipe); 563 usbd_close_pipe(sc->sc_bt_pipe); 564 sc->sc_bt_pipe = NULL; 565 } 566 567 if (sc->tp_pkt != NULL) { 568 free(sc->tp_pkt, M_USBDEV, 0); 569 sc->tp_pkt = NULL; 570 } 571 if (sc->bt_pkt != NULL) { 572 free(sc->bt_pkt, M_USBDEV, 0); 573 sc->bt_pkt = NULL; 574 } 575 } 576 577 int 578 ubcmtp_ioctl(void *v, unsigned long cmd, caddr_t data, int flag, struct proc *p) 579 { 580 struct ubcmtp_softc *sc = v; 581 struct wsmouse_calibcoords *wsmc = (struct wsmouse_calibcoords *)data; 582 int wsmode; 583 584 DPRINTF("%s: in %s with cmd 0x%lx\n", sc->sc_dev.dv_xname, __func__, 585 cmd); 586 587 switch (cmd) { 588 case WSMOUSEIO_GTYPE: 589 /* so we can specify our own finger/w values to the 590 * xf86-input-synaptics driver like pms(4) */ 591 *(u_int *)data = WSMOUSE_TYPE_ELANTECH; 592 break; 593 594 case WSMOUSEIO_GCALIBCOORDS: 595 wsmc->minx = sc->dev_type->l_x.min; 596 wsmc->maxx = sc->dev_type->l_x.max; 597 wsmc->miny = sc->dev_type->l_y.min; 598 wsmc->maxy = sc->dev_type->l_y.max; 599 wsmc->swapxy = 0; 600 wsmc->resx = 0; 601 wsmc->resy = 0; 602 break; 603 604 case WSMOUSEIO_SETMODE: 605 wsmode = *(u_int *)data; 606 if (wsmode != WSMOUSE_COMPAT && wsmode != WSMOUSE_NATIVE) { 607 printf("%s: invalid mode %d\n", sc->sc_dev.dv_xname, 608 wsmode); 609 return (EINVAL); 610 } 611 612 DPRINTF("%s: changing mode to %s\n", 613 sc->sc_dev.dv_xname, (wsmode == WSMOUSE_COMPAT ? "compat" : 614 "native")); 615 616 sc->wsmode = wsmode; 617 break; 618 619 default: 620 return (-1); 621 } 622 623 return (0); 624 } 625 626 int 627 ubcmtp_raw_mode(struct ubcmtp_softc *sc, int enable) 628 { 629 usb_device_request_t r; 630 usbd_status err; 631 uint8_t buf[8]; 632 633 /* type 3 has no raw mode */ 634 if (sc->dev_type->type == UBCMTP_TYPE3) 635 return (0); 636 637 r.bRequest = UR_GET_REPORT; 638 r.bmRequestType = UT_READ_CLASS_INTERFACE; 639 if (sc->dev_type->type < UBCMTP_TYPE4) { 640 USETW2(r.wValue, UHID_FEATURE_REPORT, 0); 641 USETW(r.wIndex, 0); 642 USETW(r.wLength, UBCMTP_WELLSPRING_MODE_LEN); 643 } else { 644 USETW2(r.wValue, UHID_FEATURE_REPORT, 2); 645 USETW(r.wIndex, 2); 646 USETW(r.wLength, UBCMTP_WELLSPRING9_MODE_LEN); 647 } 648 649 err = usbd_do_request(sc->sc_udev, &r, buf); 650 if (err != USBD_NORMAL_COMPLETION) { 651 printf("%s: %s: failed to get feature report\n", 652 sc->sc_dev.dv_xname, __func__); 653 return (err); 654 } 655 656 /* toggle magic byte and write everything back */ 657 if (sc->dev_type->type < UBCMTP_TYPE4) 658 buf[0] = (enable ? UBCMTP_WELLSPRING_MODE_RAW : 659 UBCMTP_WELLSPRING_MODE_HID); 660 else 661 buf[1] = (enable ? UBCMTP_WELLSPRING9_MODE_RAW : 662 UBCMTP_WELLSPRING9_MODE_HID); 663 664 r.bRequest = UR_SET_REPORT; 665 r.bmRequestType = UT_WRITE_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 toggle raw mode\n", 679 sc->sc_dev.dv_xname, __func__); 680 return (err); 681 } 682 683 return (0); 684 } 685 686 int 687 ubcmtp_setup_pipes(struct ubcmtp_softc *sc) 688 { 689 usbd_status err; 690 usb_endpoint_descriptor_t *ed; 691 692 if (sc->dev_type->type == UBCMTP_TYPE1) { 693 /* setup physical button pipe */ 694 695 if ((err = usbd_device2interface_handle(sc->sc_udev, 696 sc->bt_ifacenum, &sc->sc_bt_iface)) != 0) { 697 printf("%s: failed getting button interface\n", 698 sc->sc_dev.dv_xname); 699 goto fail1; 700 } 701 ed = usbd_interface2endpoint_descriptor(sc->sc_bt_iface, 0); 702 if (ed == NULL) { 703 printf("%s: failed getting button endpoint descriptor\n", 704 sc->sc_dev.dv_xname); 705 goto fail1; 706 } 707 sc->sc_bt_epaddr = ed->bEndpointAddress; 708 sc->bt_pkt = malloc(sc->bt_maxlen, M_USBDEV, M_WAITOK); 709 if (sc->bt_pkt == NULL) 710 goto fail1; 711 712 DPRINTF("%s: button iface at 0x%x, max size %d\n", 713 sc->sc_dev.dv_xname, sc->sc_bt_epaddr, sc->bt_maxlen); 714 715 err = usbd_open_pipe_intr(sc->sc_bt_iface, sc->sc_bt_epaddr, 716 USBD_SHORT_XFER_OK, &sc->sc_bt_pipe, sc, sc->bt_pkt, 717 sc->bt_maxlen, ubcmtp_bt_intr, USBD_DEFAULT_INTERVAL); 718 if (err != USBD_NORMAL_COMPLETION) { 719 printf("%s: failed opening button pipe\n", 720 sc->sc_dev.dv_xname); 721 goto fail1; 722 } 723 } 724 725 /* setup trackpad data pipe */ 726 727 if ((err = usbd_device2interface_handle(sc->sc_udev, sc->tp_ifacenum, 728 &sc->sc_tp_iface)) != 0) { 729 printf("%s: failed getting trackpad data interface\n", 730 sc->sc_dev.dv_xname); 731 goto fail2; 732 } 733 ed = usbd_interface2endpoint_descriptor(sc->sc_tp_iface, 0); 734 if (ed == NULL) { 735 printf("%s: failed getting trackpad data endpoint descriptor\n", 736 sc->sc_dev.dv_xname); 737 goto fail2; 738 } 739 sc->sc_tp_epaddr = ed->bEndpointAddress; 740 sc->tp_pkt = malloc(sc->tp_maxlen, M_USBDEV, M_WAITOK); 741 if (sc->tp_pkt == NULL) 742 goto fail2; 743 744 DPRINTF("%s: trackpad data iface at 0x%x, max size %d\n", 745 sc->sc_dev.dv_xname, sc->sc_tp_epaddr, sc->tp_maxlen); 746 747 err = usbd_open_pipe_intr(sc->sc_tp_iface, sc->sc_tp_epaddr, 748 USBD_SHORT_XFER_OK, &sc->sc_tp_pipe, sc, sc->tp_pkt, sc->tp_maxlen, 749 ubcmtp_tp_intr, USBD_DEFAULT_INTERVAL); 750 if (err != USBD_NORMAL_COMPLETION) { 751 printf("%s: error opening trackpad data pipe\n", 752 sc->sc_dev.dv_xname); 753 goto fail2; 754 } 755 756 return (0); 757 758 fail2: 759 if (sc->sc_tp_pipe != NULL) { 760 usbd_abort_pipe(sc->sc_tp_pipe); 761 usbd_close_pipe(sc->sc_tp_pipe); 762 } 763 if (sc->tp_pkt != NULL) 764 free(sc->tp_pkt, M_USBDEV, 0); 765 fail1: 766 if (sc->sc_bt_pipe != NULL) { 767 usbd_abort_pipe(sc->sc_bt_pipe); 768 usbd_close_pipe(sc->sc_bt_pipe); 769 } 770 if (sc->bt_pkt != NULL) 771 free(sc->bt_pkt, M_USBDEV, 0); 772 773 return (1); 774 } 775 776 void 777 ubcmtp_tp_intr(struct usbd_xfer *xfer, void *priv, usbd_status status) 778 { 779 struct ubcmtp_softc *sc = priv; 780 struct ubcmtp_finger *pkt; 781 u_int32_t pktlen; 782 int i, diff = 0, finger = 0, fingers = 0, s, t; 783 784 if (usbd_is_dying(sc->sc_udev) || !(sc->sc_status & UBCMTP_ENABLED)) 785 return; 786 787 if (status != USBD_NORMAL_COMPLETION) { 788 DPRINTF("%s: %s with status 0x%x\n", sc->sc_dev.dv_xname, 789 __func__, status); 790 791 if (status == USBD_NOT_STARTED || status == USBD_CANCELLED) 792 return; 793 if (status == USBD_STALLED) 794 usbd_clear_endpoint_stall_async(sc->sc_tp_pipe); 795 return; 796 } 797 798 usbd_get_xfer_status(xfer, NULL, NULL, &pktlen, NULL); 799 800 if (sc->tp_pkt == NULL || pktlen < sc->tp_offset) 801 return; 802 803 pkt = (struct ubcmtp_finger *)(sc->tp_pkt + sc->tp_offset); 804 fingers = (pktlen - sc->tp_offset) / sizeof(struct ubcmtp_finger); 805 806 for (i = 0; i < fingers; i++) { 807 if ((int16_t)letoh16(pkt[i].touch_major) == 0) { 808 /* finger lifted */ 809 sc->pos[i].down = 0; 810 diff = 1; 811 continue; 812 } 813 814 if (!sc->pos[finger].down) { 815 sc->pos[finger].down = 1; 816 diff = 1; 817 } 818 819 if ((t = (int16_t)letoh16(pkt[i].abs_x)) != sc->pos[finger].x) { 820 sc->pos[finger].x = t; 821 diff = 1; 822 } 823 824 if ((t = (int16_t)letoh16(pkt[i].abs_y)) != sc->pos[finger].y) { 825 sc->pos[finger].y = t; 826 diff = 1; 827 } 828 829 if ((t = (int16_t)letoh16(pkt[i].rel_x)) != sc->pos[finger].dx) { 830 sc->pos[finger].dx = t; 831 diff = 1; 832 } 833 834 if ((t = (int16_t)letoh16(pkt[i].rel_y)) != sc->pos[finger].dy) { 835 sc->pos[finger].dy = t; 836 diff = 1; 837 } 838 839 finger++; 840 } 841 842 if (sc->dev_type->type == UBCMTP_TYPE2 || 843 sc->dev_type->type == UBCMTP_TYPE3 || 844 sc->dev_type->type == UBCMTP_TYPE4) { 845 if (sc->dev_type->type == UBCMTP_TYPE2) 846 t = !!((int16_t)letoh16(sc->tp_pkt[UBCMTP_TYPE2_BTOFF])); 847 else if (sc->dev_type->type == UBCMTP_TYPE3) 848 t = !!((int16_t)letoh16(sc->tp_pkt[UBCMTP_TYPE3_BTOFF])); 849 else if (sc->dev_type->type == UBCMTP_TYPE4) 850 t = !!((int16_t)letoh16(sc->tp_pkt[UBCMTP_TYPE4_BTOFF])); 851 852 if (sc->btn != t) { 853 sc->btn = t; 854 diff = 1; 855 856 DPRINTF("%s: [button]\n", sc->sc_dev.dv_xname); 857 } 858 } 859 860 if (diff) { 861 s = spltty(); 862 863 DPRINTF("%s: ", sc->sc_dev.dv_xname); 864 865 if (sc->wsmode == WSMOUSE_NATIVE) { 866 DPRINTF("absolute input %d, %d (finger %d, button %d)\n", 867 sc->pos[0].x, sc->pos[0].y, finger, sc->btn); 868 WSMOUSE_TOUCH(sc->sc_wsmousedev, sc->btn, sc->pos[0].x, 869 sc->pos[0].y, (finger ? 50 : 0), finger); 870 } else { 871 DPRINTF("relative input %d, %d (button %d)\n", 872 sc->pos[0].dx, sc->pos[0].dy, sc->btn); 873 WSMOUSE_INPUT(sc->sc_wsmousedev, sc->btn, 874 sc->pos[0].dx, sc->pos[0].dy, 0, 0); 875 } 876 splx(s); 877 } 878 } 879 880 /* hardware button interrupt */ 881 void 882 ubcmtp_bt_intr(struct usbd_xfer *xfer, void *priv, usbd_status status) 883 { 884 struct ubcmtp_softc *sc = priv; 885 struct ubcmtp_button *pkt; 886 u_int32_t len; 887 888 if (usbd_is_dying(sc->sc_udev) || !(sc->sc_status & UBCMTP_ENABLED)) 889 return; 890 891 if (status != USBD_NORMAL_COMPLETION) { 892 if (status == USBD_NOT_STARTED || status == USBD_CANCELLED) 893 return; 894 if (status == USBD_STALLED) 895 usbd_clear_endpoint_stall_async(sc->sc_tp_pipe); 896 return; 897 } 898 899 usbd_get_xfer_status(xfer, NULL, NULL, &len, NULL); 900 901 if (sc->bt_pkt == NULL || len < sizeof(struct ubcmtp_button)) 902 return; 903 904 pkt = (struct ubcmtp_button *)(sc->bt_pkt); 905 906 DPRINTF("%s: button interrupt (%d, %d, %d, %d)", sc->sc_dev.dv_xname, 907 pkt->unused, pkt->button, pkt->rel_x, pkt->rel_y); 908 909 if (pkt->button != sc->btn) { 910 sc->btn = pkt->button; 911 wsmouse_buttons(sc->sc_wsmousedev, sc->btn); 912 wsmouse_input_sync(sc->sc_wsmousedev); 913 } 914 } 915