1 /* $OpenBSD: ubcmtp.c,v 1.17 2017/06/06 21:53:07 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 /* 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 uhidev sc_hdev; 331 struct usbd_device *sc_udev; 332 struct device *sc_wsmousedev; 333 334 int tp_ifacenum; /* trackpad interface number */ 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 uint8_t *tp_pkt; 341 342 int bt_ifacenum; /* button interface number */ 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 /* 402 * The USB keyboard/mouse device will have one keyboard 403 * HID and two mouse HIDs, though only one will have a 404 * protocol of mouse -- we only want to take control of 405 * that one. 406 */ 407 id = usbd_get_interface_descriptor(uaa->iface); 408 if (id->bInterfaceProtocol == UIPROTO_BOOT_MOUSE) 409 return (UMATCH_VENDOR_PRODUCT_CONF_IFACE); 410 } 411 } 412 413 return (UMATCH_NONE); 414 } 415 416 void 417 ubcmtp_attach(struct device *parent, struct device *self, void *aux) 418 { 419 struct ubcmtp_softc *sc = (struct ubcmtp_softc *)self; 420 struct usb_attach_arg *uaa = aux; 421 struct usbd_device *dev = uaa->device; 422 struct wsmousedev_attach_args a; 423 usb_device_descriptor_t *udd; 424 int i; 425 426 sc->sc_udev = uaa->device; 427 sc->sc_status = 0; 428 429 if ((udd = usbd_get_device_descriptor(dev)) == NULL) { 430 printf("ubcmtp: failed getting device descriptor\n"); 431 return; 432 } 433 434 for (i = 0; i < nitems(ubcmtp_devices); i++) { 435 if (uaa->vendor == ubcmtp_devices[i].vendor && ( 436 uaa->product == ubcmtp_devices[i].ansi || 437 uaa->product == ubcmtp_devices[i].iso || 438 uaa->product == ubcmtp_devices[i].jis)) { 439 sc->dev_type = &ubcmtp_devices[i]; 440 DPRINTF("%s: attached to 0x%x/0x%x type %d\n", 441 sc->sc_dev.dv_xname, uaa->vendor, uaa->product, 442 sc->dev_type->type); 443 break; 444 } 445 } 446 447 if (sc->dev_type == NULL) { 448 /* how did we match then? */ 449 printf("%s: failed looking up device in table\n", 450 sc->sc_dev.dv_xname); 451 return; 452 } 453 454 switch (sc->dev_type->type) { 455 case UBCMTP_TYPE1: 456 sc->tp_maxlen = UBCMTP_TYPE1_TPLEN; 457 sc->tp_offset = UBCMTP_TYPE1_TPOFF; 458 sc->tp_ifacenum = UBCMTP_TYPE1_TPIFACE; 459 460 /* button offsets */ 461 sc->bt_maxlen = sizeof(struct ubcmtp_button); 462 sc->bt_ifacenum = UBCMTP_TYPE1_BTIFACE; 463 break; 464 465 case UBCMTP_TYPE2: 466 sc->tp_maxlen = UBCMTP_TYPE2_TPLEN; 467 sc->tp_offset = UBCMTP_TYPE2_TPOFF; 468 sc->tp_ifacenum = UBCMTP_TYPE2_TPIFACE; 469 break; 470 471 case UBCMTP_TYPE3: 472 sc->tp_maxlen = UBCMTP_TYPE3_TPLEN; 473 sc->tp_offset = UBCMTP_TYPE3_TPOFF; 474 sc->tp_ifacenum = UBCMTP_TYPE3_TPIFACE; 475 break; 476 477 case UBCMTP_TYPE4: 478 sc->tp_maxlen = UBCMTP_TYPE4_TPLEN; 479 sc->tp_offset = UBCMTP_TYPE4_TPOFF; 480 sc->tp_ifacenum = UBCMTP_TYPE4_TPIFACE; 481 break; 482 } 483 484 a.accessops = &ubcmtp_accessops; 485 a.accesscookie = sc; 486 487 sc->sc_wsmousedev = config_found(self, &a, wsmousedevprint); 488 if (sc->sc_wsmousedev != NULL && ubcmtp_configure(sc)) 489 ubcmtp_disable(sc); 490 } 491 492 int 493 ubcmtp_detach(struct device *self, int flags) 494 { 495 struct ubcmtp_softc *sc = (struct ubcmtp_softc *)self; 496 int ret = 0; 497 498 if (sc->sc_wsmousedev != NULL) 499 ret = config_detach(sc->sc_wsmousedev, flags); 500 501 return (ret); 502 } 503 504 int 505 ubcmtp_activate(struct device *self, int act) 506 { 507 struct ubcmtp_softc *sc = (struct ubcmtp_softc *)self; 508 int rv = 0; 509 510 if (act == DVACT_DEACTIVATE) { 511 if (sc->sc_wsmousedev != NULL) 512 rv = config_deactivate(sc->sc_wsmousedev); 513 usbd_deactivate(sc->sc_udev); 514 } 515 516 return (rv); 517 } 518 519 int 520 ubcmtp_configure(struct ubcmtp_softc *sc) 521 { 522 struct wsmousehw *hw = wsmouse_get_hw(sc->sc_wsmousedev); 523 524 hw->type = WSMOUSE_TYPE_ELANTECH; /* see ubcmtp_ioctl */ 525 hw->hw_type = (IS_CLICKPAD(sc->dev_type->type) 526 ? WSMOUSEHW_CLICKPAD : WSMOUSEHW_TOUCHPAD); 527 hw->x_min = sc->dev_type->l_x.min; 528 hw->x_max = sc->dev_type->l_x.max; 529 hw->y_min = sc->dev_type->l_y.min; 530 hw->y_max = sc->dev_type->l_y.max; 531 hw->mt_slots = UBCMTP_MAX_FINGERS; 532 hw->flags = WSMOUSEHW_MT_TRACKING; 533 534 return wsmouse_configure(sc->sc_wsmousedev, NULL, 0); 535 } 536 537 int 538 ubcmtp_enable(void *v) 539 { 540 struct ubcmtp_softc *sc = v; 541 542 if (sc->sc_status & UBCMTP_ENABLED) 543 return (EBUSY); 544 545 if (usbd_is_dying(sc->sc_udev)) 546 return (EIO); 547 548 if (ubcmtp_raw_mode(sc, 1) != 0) { 549 printf("%s: failed to enter raw mode\n", sc->sc_dev.dv_xname); 550 return (1); 551 } 552 553 if (ubcmtp_setup_pipes(sc) == 0) { 554 sc->sc_status |= UBCMTP_ENABLED; 555 return (0); 556 } else 557 return (1); 558 } 559 560 void 561 ubcmtp_disable(void *v) 562 { 563 struct ubcmtp_softc *sc = v; 564 565 if (usbd_is_dying(sc->sc_udev) || !(sc->sc_status & UBCMTP_ENABLED)) 566 return; 567 568 sc->sc_status &= ~UBCMTP_ENABLED; 569 570 ubcmtp_raw_mode(sc, 0); 571 572 if (sc->sc_tp_pipe != NULL) { 573 usbd_abort_pipe(sc->sc_tp_pipe); 574 usbd_close_pipe(sc->sc_tp_pipe); 575 sc->sc_tp_pipe = NULL; 576 } 577 if (sc->sc_bt_pipe != NULL) { 578 usbd_abort_pipe(sc->sc_bt_pipe); 579 usbd_close_pipe(sc->sc_bt_pipe); 580 sc->sc_bt_pipe = NULL; 581 } 582 583 if (sc->tp_pkt != NULL) { 584 free(sc->tp_pkt, M_USBDEV, sc->tp_maxlen); 585 sc->tp_pkt = NULL; 586 } 587 if (sc->bt_pkt != NULL) { 588 free(sc->bt_pkt, M_USBDEV, sc->bt_maxlen); 589 sc->bt_pkt = NULL; 590 } 591 } 592 593 int 594 ubcmtp_ioctl(void *v, unsigned long cmd, caddr_t data, int flag, struct proc *p) 595 { 596 struct ubcmtp_softc *sc = v; 597 struct wsmouse_calibcoords *wsmc = (struct wsmouse_calibcoords *)data; 598 int wsmode; 599 600 DPRINTF("%s: in %s with cmd 0x%lx\n", sc->sc_dev.dv_xname, __func__, 601 cmd); 602 603 switch (cmd) { 604 case WSMOUSEIO_GTYPE: 605 /* so we can specify our own finger/w values to the 606 * xf86-input-synaptics driver like pms(4) */ 607 *(u_int *)data = WSMOUSE_TYPE_ELANTECH; 608 break; 609 610 case WSMOUSEIO_GCALIBCOORDS: 611 wsmc->minx = sc->dev_type->l_x.min; 612 wsmc->maxx = sc->dev_type->l_x.max; 613 wsmc->miny = sc->dev_type->l_y.min; 614 wsmc->maxy = sc->dev_type->l_y.max; 615 wsmc->swapxy = 0; 616 wsmc->resx = 0; 617 wsmc->resy = 0; 618 break; 619 620 case WSMOUSEIO_SETMODE: 621 wsmode = *(u_int *)data; 622 if (wsmode != WSMOUSE_COMPAT && wsmode != WSMOUSE_NATIVE) { 623 printf("%s: invalid mode %d\n", sc->sc_dev.dv_xname, 624 wsmode); 625 return (EINVAL); 626 } 627 wsmouse_set_mode(sc->sc_wsmousedev, wsmode); 628 629 DPRINTF("%s: changing mode to %s\n", 630 sc->sc_dev.dv_xname, (wsmode == WSMOUSE_COMPAT ? "compat" : 631 "native")); 632 633 break; 634 635 default: 636 return (-1); 637 } 638 639 return (0); 640 } 641 642 int 643 ubcmtp_raw_mode(struct ubcmtp_softc *sc, int enable) 644 { 645 usb_device_request_t r; 646 usbd_status err; 647 uint8_t buf[8]; 648 649 /* type 3 has no raw mode */ 650 if (sc->dev_type->type == UBCMTP_TYPE3) 651 return (0); 652 653 r.bRequest = UR_GET_REPORT; 654 r.bmRequestType = UT_READ_CLASS_INTERFACE; 655 if (sc->dev_type->type < UBCMTP_TYPE4) { 656 USETW2(r.wValue, UHID_FEATURE_REPORT, 0); 657 USETW(r.wIndex, 0); 658 USETW(r.wLength, UBCMTP_WELLSPRING_MODE_LEN); 659 } else { 660 USETW2(r.wValue, UHID_FEATURE_REPORT, 2); 661 USETW(r.wIndex, 2); 662 USETW(r.wLength, UBCMTP_WELLSPRING9_MODE_LEN); 663 } 664 665 err = usbd_do_request(sc->sc_udev, &r, buf); 666 if (err != USBD_NORMAL_COMPLETION) { 667 printf("%s: %s: failed to get feature report\n", 668 sc->sc_dev.dv_xname, __func__); 669 return (err); 670 } 671 672 /* toggle magic byte and write everything back */ 673 if (sc->dev_type->type < UBCMTP_TYPE4) 674 buf[0] = (enable ? UBCMTP_WELLSPRING_MODE_RAW : 675 UBCMTP_WELLSPRING_MODE_HID); 676 else 677 buf[1] = (enable ? UBCMTP_WELLSPRING9_MODE_RAW : 678 UBCMTP_WELLSPRING9_MODE_HID); 679 680 r.bRequest = UR_SET_REPORT; 681 r.bmRequestType = UT_WRITE_CLASS_INTERFACE; 682 if (sc->dev_type->type < UBCMTP_TYPE4) { 683 USETW2(r.wValue, UHID_FEATURE_REPORT, 0); 684 USETW(r.wIndex, 0); 685 USETW(r.wLength, UBCMTP_WELLSPRING_MODE_LEN); 686 } else { 687 USETW2(r.wValue, UHID_FEATURE_REPORT, 2); 688 USETW(r.wIndex, 2); 689 USETW(r.wLength, UBCMTP_WELLSPRING9_MODE_LEN); 690 } 691 692 err = usbd_do_request(sc->sc_udev, &r, buf); 693 if (err != USBD_NORMAL_COMPLETION) { 694 printf("%s: %s: failed to toggle raw mode\n", 695 sc->sc_dev.dv_xname, __func__); 696 return (err); 697 } 698 699 return (0); 700 } 701 702 int 703 ubcmtp_setup_pipes(struct ubcmtp_softc *sc) 704 { 705 usbd_status err; 706 usb_endpoint_descriptor_t *ed; 707 708 if (sc->dev_type->type == UBCMTP_TYPE1) { 709 /* setup physical button pipe */ 710 711 if ((err = usbd_device2interface_handle(sc->sc_udev, 712 sc->bt_ifacenum, &sc->sc_bt_iface)) != 0) { 713 printf("%s: failed getting button interface\n", 714 sc->sc_dev.dv_xname); 715 goto fail1; 716 } 717 ed = usbd_interface2endpoint_descriptor(sc->sc_bt_iface, 0); 718 if (ed == NULL) { 719 printf("%s: failed getting button endpoint descriptor\n", 720 sc->sc_dev.dv_xname); 721 goto fail1; 722 } 723 sc->sc_bt_epaddr = ed->bEndpointAddress; 724 sc->bt_pkt = malloc(sc->bt_maxlen, M_USBDEV, M_WAITOK); 725 if (sc->bt_pkt == NULL) 726 goto fail1; 727 728 DPRINTF("%s: button iface at 0x%x, max size %d\n", 729 sc->sc_dev.dv_xname, sc->sc_bt_epaddr, sc->bt_maxlen); 730 731 err = usbd_open_pipe_intr(sc->sc_bt_iface, sc->sc_bt_epaddr, 732 USBD_SHORT_XFER_OK, &sc->sc_bt_pipe, sc, sc->bt_pkt, 733 sc->bt_maxlen, ubcmtp_bt_intr, USBD_DEFAULT_INTERVAL); 734 if (err != USBD_NORMAL_COMPLETION) { 735 printf("%s: failed opening button pipe\n", 736 sc->sc_dev.dv_xname); 737 goto fail1; 738 } 739 } 740 741 /* setup trackpad data pipe */ 742 743 if ((err = usbd_device2interface_handle(sc->sc_udev, sc->tp_ifacenum, 744 &sc->sc_tp_iface)) != 0) { 745 printf("%s: failed getting trackpad data interface\n", 746 sc->sc_dev.dv_xname); 747 goto fail2; 748 } 749 ed = usbd_interface2endpoint_descriptor(sc->sc_tp_iface, 0); 750 if (ed == NULL) { 751 printf("%s: failed getting trackpad data endpoint descriptor\n", 752 sc->sc_dev.dv_xname); 753 goto fail2; 754 } 755 sc->sc_tp_epaddr = ed->bEndpointAddress; 756 sc->tp_pkt = malloc(sc->tp_maxlen, M_USBDEV, M_WAITOK); 757 if (sc->tp_pkt == NULL) 758 goto fail2; 759 760 DPRINTF("%s: trackpad data iface at 0x%x, max size %d\n", 761 sc->sc_dev.dv_xname, sc->sc_tp_epaddr, sc->tp_maxlen); 762 763 err = usbd_open_pipe_intr(sc->sc_tp_iface, sc->sc_tp_epaddr, 764 USBD_SHORT_XFER_OK, &sc->sc_tp_pipe, sc, sc->tp_pkt, sc->tp_maxlen, 765 ubcmtp_tp_intr, USBD_DEFAULT_INTERVAL); 766 if (err != USBD_NORMAL_COMPLETION) { 767 printf("%s: error opening trackpad data pipe\n", 768 sc->sc_dev.dv_xname); 769 goto fail2; 770 } 771 772 return (0); 773 774 fail2: 775 if (sc->sc_tp_pipe != NULL) { 776 usbd_abort_pipe(sc->sc_tp_pipe); 777 usbd_close_pipe(sc->sc_tp_pipe); 778 } 779 if (sc->tp_pkt != NULL) 780 free(sc->tp_pkt, M_USBDEV, sc->tp_maxlen); 781 fail1: 782 if (sc->sc_bt_pipe != NULL) { 783 usbd_abort_pipe(sc->sc_bt_pipe); 784 usbd_close_pipe(sc->sc_bt_pipe); 785 } 786 if (sc->bt_pkt != NULL) 787 free(sc->bt_pkt, M_USBDEV, sc->bt_maxlen); 788 789 return (1); 790 } 791 792 void 793 ubcmtp_tp_intr(struct usbd_xfer *xfer, void *priv, usbd_status status) 794 { 795 struct ubcmtp_softc *sc = priv; 796 struct ubcmtp_finger *pkt; 797 u_int32_t pktlen; 798 int i, s, btn, contacts, fingers; 799 800 if (usbd_is_dying(sc->sc_udev) || !(sc->sc_status & UBCMTP_ENABLED)) 801 return; 802 803 if (status != USBD_NORMAL_COMPLETION) { 804 DPRINTF("%s: %s with status 0x%x\n", sc->sc_dev.dv_xname, 805 __func__, status); 806 807 if (status == USBD_NOT_STARTED || status == USBD_CANCELLED) 808 return; 809 if (status == USBD_STALLED) 810 usbd_clear_endpoint_stall_async(sc->sc_tp_pipe); 811 return; 812 } 813 814 usbd_get_xfer_status(xfer, NULL, NULL, &pktlen, NULL); 815 816 if (sc->tp_pkt == NULL || pktlen < sc->tp_offset) 817 return; 818 819 pkt = (struct ubcmtp_finger *)(sc->tp_pkt + sc->tp_offset); 820 fingers = (pktlen - sc->tp_offset) / sizeof(struct ubcmtp_finger); 821 822 contacts = 0; 823 for (i = 0; i < fingers; i++) { 824 if ((int16_t)letoh16(pkt[i].touch_major) == 0) 825 continue; /* finger lifted */ 826 sc->frame[contacts].x = (int16_t)letoh16(pkt[i].abs_x); 827 sc->frame[contacts].y = (int16_t)letoh16(pkt[i].abs_y); 828 sc->frame[contacts].pressure = DEFAULT_PRESSURE; 829 contacts++; 830 } 831 832 btn = sc->btn; 833 if (sc->dev_type->type == UBCMTP_TYPE2) 834 sc->btn = !!((int16_t)letoh16(sc->tp_pkt[UBCMTP_TYPE2_BTOFF])); 835 else if (sc->dev_type->type == UBCMTP_TYPE3) 836 sc->btn = !!((int16_t)letoh16(sc->tp_pkt[UBCMTP_TYPE3_BTOFF])); 837 else if (sc->dev_type->type == UBCMTP_TYPE4) 838 sc->btn = !!((int16_t)letoh16(sc->tp_pkt[UBCMTP_TYPE4_BTOFF])); 839 840 if (contacts || sc->contacts || sc->btn != btn) { 841 sc->contacts = contacts; 842 s = spltty(); 843 wsmouse_buttons(sc->sc_wsmousedev, sc->btn); 844 wsmouse_mtframe(sc->sc_wsmousedev, sc->frame, contacts); 845 wsmouse_input_sync(sc->sc_wsmousedev); 846 splx(s); 847 } 848 } 849 850 /* hardware button interrupt */ 851 void 852 ubcmtp_bt_intr(struct usbd_xfer *xfer, void *priv, usbd_status status) 853 { 854 struct ubcmtp_softc *sc = priv; 855 struct ubcmtp_button *pkt; 856 u_int32_t len; 857 858 if (usbd_is_dying(sc->sc_udev) || !(sc->sc_status & UBCMTP_ENABLED)) 859 return; 860 861 if (status != USBD_NORMAL_COMPLETION) { 862 DPRINTF("%s: %s with status 0x%x\n", sc->sc_dev.dv_xname, 863 __func__, status); 864 if (status == USBD_NOT_STARTED || status == USBD_CANCELLED) 865 return; 866 if (status == USBD_STALLED) 867 usbd_clear_endpoint_stall_async(sc->sc_tp_pipe); 868 return; 869 } 870 871 usbd_get_xfer_status(xfer, NULL, NULL, &len, NULL); 872 873 if (sc->bt_pkt == NULL || len < sizeof(struct ubcmtp_button)) 874 return; 875 876 pkt = (struct ubcmtp_button *)(sc->bt_pkt); 877 878 DPRINTF("%s: button interrupt (%d, %d, %d, %d)", sc->sc_dev.dv_xname, 879 pkt->unused, pkt->button, pkt->rel_x, pkt->rel_y); 880 881 if (pkt->button != sc->btn) { 882 sc->btn = pkt->button; 883 wsmouse_buttons(sc->sc_wsmousedev, sc->btn); 884 wsmouse_input_sync(sc->sc_wsmousedev); 885 } 886 } 887