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