1 /* $OpenBSD: uhidev.c,v 1.110 2024/05/23 03:21:09 jsg Exp $ */ 2 /* $NetBSD: uhidev.c,v 1.14 2003/03/11 16:44:00 augustss Exp $ */ 3 4 /* 5 * Copyright (c) 2001 The NetBSD Foundation, Inc. 6 * All rights reserved. 7 * 8 * This code is derived from software contributed to The NetBSD Foundation 9 * by Lennart Augustsson (lennart@augustsson.net) at 10 * Carlstedt Research & Technology. 11 * 12 * Redistribution and use in source and binary forms, with or without 13 * modification, are permitted provided that the following conditions 14 * are met: 15 * 1. Redistributions of source code must retain the above copyright 16 * notice, this list of conditions and the following disclaimer. 17 * 2. Redistributions in binary form must reproduce the above copyright 18 * notice, this list of conditions and the following disclaimer in the 19 * documentation and/or other materials provided with the distribution. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 22 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 23 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 24 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 25 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 31 * POSSIBILITY OF SUCH DAMAGE. 32 */ 33 34 /* 35 * HID spec: https://www.usb.org/sites/default/files/hid1_11.pdf 36 */ 37 38 #include <sys/param.h> 39 #include <sys/systm.h> 40 #include <sys/malloc.h> 41 #include <sys/device.h> 42 43 #include <machine/bus.h> 44 45 #include <dev/usb/usb.h> 46 #include <dev/usb/usbhid.h> 47 48 #include <dev/usb/usbdevs.h> 49 #include <dev/usb/usbdi.h> 50 #include <dev/usb/usbdi_util.h> 51 #include <dev/usb/usbdivar.h> 52 #include <dev/usb/usb_mem.h> 53 #include <dev/usb/usb_quirks.h> 54 55 #include <dev/usb/uhidev.h> 56 57 #ifndef SMALL_KERNEL 58 /* Replacement report descriptors for devices shipped with broken ones */ 59 #include <dev/usb/uhid_rdesc.h> 60 int uhidev_use_rdesc(struct uhidev_softc *, usb_interface_descriptor_t *, 61 int, int, void **, int *); 62 #define UISUBCLASS_XBOX360_CONTROLLER 0x5d 63 #define UIPROTO_XBOX360_GAMEPAD 0x01 64 #define UISUBCLASS_XBOXONE_CONTROLLER 0x47 65 #define UIPROTO_XBOXONE_GAMEPAD 0xd0 66 #endif /* !SMALL_KERNEL */ 67 68 #define DEVNAME(sc) ((sc)->sc_dev.dv_xname) 69 70 #ifdef UHIDEV_DEBUG 71 #define DPRINTF(x) do { if (uhidevdebug) printf x; } while (0) 72 #define DPRINTFN(n,x) do { if (uhidevdebug>(n)) printf x; } while (0) 73 int uhidevdebug = 0; 74 #else 75 #define DPRINTF(x) 76 #define DPRINTFN(n,x) 77 #endif 78 79 struct uhidev_async_info { 80 void (*callback)(void *priv, int id, void *data, int len); 81 void *priv; 82 void *data; 83 int id; 84 }; 85 86 void uhidev_intr(struct usbd_xfer *, void *, usbd_status); 87 88 int uhidev_maxrepid(void *buf, int len); 89 int uhidevprint(void *aux, const char *pnp); 90 91 int uhidev_match(struct device *, void *, void *); 92 void uhidev_attach(struct device *, struct device *, void *); 93 int uhidev_detach(struct device *, int); 94 int uhidev_activate(struct device *, int); 95 96 void uhidev_get_report_async_cb(struct usbd_xfer *, void *, usbd_status); 97 void uhidev_set_report_async_cb(struct usbd_xfer *, void *, usbd_status); 98 99 struct cfdriver uhidev_cd = { 100 NULL, "uhidev", DV_DULL 101 }; 102 103 const struct cfattach uhidev_ca = { 104 sizeof(struct uhidev_softc), uhidev_match, uhidev_attach, 105 uhidev_detach, uhidev_activate, 106 }; 107 108 int 109 uhidev_match(struct device *parent, void *match, void *aux) 110 { 111 struct usb_attach_arg *uaa = aux; 112 usb_interface_descriptor_t *id; 113 114 if (uaa->iface == NULL) 115 return (UMATCH_NONE); 116 id = usbd_get_interface_descriptor(uaa->iface); 117 if (id == NULL) 118 return (UMATCH_NONE); 119 #ifndef SMALL_KERNEL 120 if (id->bInterfaceClass == UICLASS_VENDOR && 121 id->bInterfaceSubClass == UISUBCLASS_XBOX360_CONTROLLER && 122 id->bInterfaceProtocol == UIPROTO_XBOX360_GAMEPAD) 123 return (UMATCH_IFACECLASS_IFACESUBCLASS_IFACEPROTO); 124 if (id->bInterfaceClass == UICLASS_VENDOR && 125 id->bInterfaceSubClass == UISUBCLASS_XBOXONE_CONTROLLER && 126 id->bInterfaceProtocol == UIPROTO_XBOXONE_GAMEPAD) { 127 return (UMATCH_IFACECLASS_IFACESUBCLASS_IFACEPROTO); 128 } 129 #endif /* !SMALL_KERNEL */ 130 if (id->bInterfaceClass != UICLASS_HID) 131 return (UMATCH_NONE); 132 if (usbd_get_quirks(uaa->device)->uq_flags & UQ_BAD_HID) 133 return (UMATCH_NONE); 134 135 return (UMATCH_IFACECLASS_GENERIC); 136 } 137 138 int 139 uhidev_attach_repid(struct uhidev_softc *sc, struct uhidev_attach_arg *uha, 140 int repid) 141 { 142 struct device *dev; 143 144 /* Could already be assigned by uhidev_set_report_dev(). */ 145 if (sc->sc_subdevs[repid] != NULL) 146 return 0; 147 148 uha->reportid = repid; 149 dev = config_found_sm(&sc->sc_dev, uha, uhidevprint, NULL); 150 sc->sc_subdevs[repid] = (struct uhidev *)dev; 151 return 1; 152 } 153 154 void 155 uhidev_attach(struct device *parent, struct device *self, void *aux) 156 { 157 struct uhidev_softc *sc = (struct uhidev_softc *)self; 158 struct usb_attach_arg *uaa = aux; 159 usb_interface_descriptor_t *id; 160 usb_endpoint_descriptor_t *ed; 161 struct uhidev_attach_arg uha; 162 int nrepid, repid, repsz; 163 int i; 164 void *desc = NULL; 165 int size = 0; 166 struct device *dev; 167 168 sc->sc_udev = uaa->device; 169 sc->sc_iface = uaa->iface; 170 sc->sc_ifaceno = uaa->ifaceno; 171 id = usbd_get_interface_descriptor(sc->sc_iface); 172 173 sc->sc_iep_addr = sc->sc_oep_addr = -1; 174 for (i = 0; i < id->bNumEndpoints; i++) { 175 ed = usbd_interface2endpoint_descriptor(sc->sc_iface, i); 176 if (ed == NULL) { 177 printf("%s: could not read endpoint descriptor\n", 178 DEVNAME(sc)); 179 return; 180 } 181 182 DPRINTFN(10,("uhidev_attach: bLength=%d bDescriptorType=%d " 183 "bEndpointAddress=%d-%s bmAttributes=%d wMaxPacketSize=%d" 184 " bInterval=%d\n", 185 ed->bLength, ed->bDescriptorType, 186 ed->bEndpointAddress & UE_ADDR, 187 UE_GET_DIR(ed->bEndpointAddress)==UE_DIR_IN? "in" : "out", 188 UE_GET_XFERTYPE(ed->bmAttributes), 189 UGETW(ed->wMaxPacketSize), ed->bInterval)); 190 191 if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && 192 UE_GET_XFERTYPE(ed->bmAttributes) == UE_INTERRUPT) { 193 sc->sc_iep_addr = ed->bEndpointAddress; 194 } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT && 195 UE_GET_XFERTYPE(ed->bmAttributes) == UE_INTERRUPT) { 196 sc->sc_oep_addr = ed->bEndpointAddress; 197 } else { 198 printf("%s: unexpected endpoint\n", DEVNAME(sc)); 199 return; 200 } 201 } 202 203 /* 204 * Check that we found an input interrupt endpoint. 205 * The output interrupt endpoint is optional 206 */ 207 if (sc->sc_iep_addr == -1) { 208 printf("%s: no input interrupt endpoint\n", DEVNAME(sc)); 209 return; 210 } 211 212 #ifndef SMALL_KERNEL 213 if (uhidev_use_rdesc(sc, id, uaa->vendor, uaa->product, &desc, &size)) 214 return; 215 #endif /* !SMALL_KERNEL */ 216 217 if (desc == NULL) { 218 struct usb_hid_descriptor *hid; 219 220 hid = usbd_get_hid_descriptor(sc->sc_udev, id); 221 if (hid == NULL) { 222 printf("%s: no HID descriptor\n", DEVNAME(sc)); 223 return; 224 } 225 size = UGETW(hid->descrs[0].wDescriptorLength); 226 desc = malloc(size, M_USBDEV, M_NOWAIT); 227 if (desc == NULL) { 228 printf("%s: no memory\n", DEVNAME(sc)); 229 return; 230 } 231 if (usbd_get_report_descriptor(sc->sc_udev, sc->sc_ifaceno, 232 desc, size)) { 233 printf("%s: no report descriptor\n", DEVNAME(sc)); 234 free(desc, M_USBDEV, size); 235 return; 236 } 237 } 238 239 sc->sc_repdesc = desc; 240 sc->sc_repdesc_size = size; 241 242 nrepid = uhidev_maxrepid(desc, size); 243 if (nrepid < 0) 244 return; 245 printf("%s: iclass %d/%d", DEVNAME(sc), id->bInterfaceClass, 246 id->bInterfaceSubClass); 247 if (nrepid > 0) 248 printf(", %d report id%s", nrepid, nrepid > 1 ? "s" : ""); 249 printf("\n"); 250 nrepid++; 251 sc->sc_subdevs = mallocarray(nrepid, sizeof(struct uhidev *), 252 M_USBDEV, M_NOWAIT | M_ZERO); 253 if (sc->sc_subdevs == NULL) { 254 printf("%s: no memory\n", DEVNAME(sc)); 255 return; 256 } 257 sc->sc_nrepid = nrepid; 258 sc->sc_isize = 0; 259 260 for (repid = 0; repid < nrepid; repid++) { 261 repsz = hid_report_size(desc, size, hid_input, repid); 262 DPRINTF(("uhidev_match: repid=%d, repsz=%d\n", repid, repsz)); 263 if (repsz > sc->sc_isize) 264 sc->sc_isize = repsz; 265 } 266 sc->sc_isize += (nrepid != 1); /* one byte for the report ID */ 267 DPRINTF(("uhidev_attach: isize=%d\n", sc->sc_isize)); 268 269 uha.uaa = uaa; 270 uha.parent = sc; 271 uha.reportid = 0; 272 uha.nreports = nrepid; 273 uha.claimed = malloc(nrepid, M_TEMP, M_WAITOK|M_ZERO); 274 275 /* Look for a driver claiming multiple report IDs first. */ 276 dev = config_found_sm(self, &uha, NULL, NULL); 277 if (dev != NULL) { 278 int nclaimed = 0; 279 280 for (repid = 0; repid < nrepid; repid++) { 281 if (!uha.claimed[repid]) 282 continue; 283 284 nclaimed++; 285 /* 286 * Could already be assigned by uhidev_set_report_dev(). 287 */ 288 if (sc->sc_subdevs[repid] == NULL) 289 sc->sc_subdevs[repid] = (struct uhidev *)dev; 290 } 291 KASSERTMSG(nclaimed > 0, "%s did not claim any report ids", 292 dev->dv_xname); 293 } 294 295 free(uha.claimed, M_TEMP, nrepid); 296 uha.claimed = NULL; 297 298 /* Special case for Wacom tablets */ 299 if (uha.uaa->vendor == USB_VENDOR_WACOM) { 300 int ndigitizers = 0; 301 /* 302 * Get all the needed collections (only 3 seem to be of 303 * interest currently). 304 */ 305 repid = hid_get_id_of_collection(desc, size, 306 HID_USAGE2(HUP_WACOM | HUP_DIGITIZERS, HUD_STYLUS), 307 HCOLL_PHYSICAL); 308 if (repid >= 0 && repid < nrepid) 309 ndigitizers += uhidev_attach_repid(sc, &uha, repid); 310 repid = hid_get_id_of_collection(desc, size, 311 HID_USAGE2(HUP_WACOM | HUP_DIGITIZERS, HUD_TABLET_FKEYS), 312 HCOLL_PHYSICAL); 313 if (repid >= 0 && repid < nrepid) 314 ndigitizers += uhidev_attach_repid(sc, &uha, repid); 315 #ifdef notyet /* not handled in hidms_wacom_setup() yet */ 316 repid = hid_get_id_of_collection(desc, size, 317 HID_USAGE2(HUP_WACOM | HUP_DIGITIZERS, HUD_WACOM_BATTERY), 318 HCOLL_PHYSICAL); 319 if (repid >= 0 && repid < nrepid) 320 ndigitizers += uhidev_attach_repid(sc, &uha, repid); 321 #endif 322 323 if (ndigitizers != 0) 324 return; 325 } 326 327 for (repid = 0; repid < nrepid; repid++) { 328 DPRINTF(("%s: try repid=%d\n", __func__, repid)); 329 if (hid_report_size(desc, size, hid_input, repid) == 0 && 330 hid_report_size(desc, size, hid_output, repid) == 0 && 331 hid_report_size(desc, size, hid_feature, repid) == 0) 332 continue; 333 334 uhidev_attach_repid(sc, &uha, repid); 335 } 336 } 337 338 #ifndef SMALL_KERNEL 339 int 340 uhidev_use_rdesc(struct uhidev_softc *sc, usb_interface_descriptor_t *id, 341 int vendor, int product, void **descp, int *sizep) 342 { 343 static uByte reportbuf[] = {2, 2}; 344 const void *descptr = NULL; 345 void *desc; 346 int size; 347 348 if (vendor == USB_VENDOR_WACOM) { 349 /* The report descriptor for the Wacom Graphire is broken. */ 350 switch (product) { 351 case USB_PRODUCT_WACOM_GRAPHIRE: 352 size = sizeof(uhid_graphire_report_descr); 353 descptr = uhid_graphire_report_descr; 354 break; 355 case USB_PRODUCT_WACOM_GRAPHIRE3_4X5: 356 case USB_PRODUCT_WACOM_GRAPHIRE4_4X5: 357 uhidev_set_report(sc, UHID_FEATURE_REPORT, 358 2, &reportbuf, sizeof(reportbuf)); 359 size = sizeof(uhid_graphire3_4x5_report_descr); 360 descptr = uhid_graphire3_4x5_report_descr; 361 break; 362 default: 363 break; 364 } 365 } else if ((id->bInterfaceClass == UICLASS_VENDOR && 366 id->bInterfaceSubClass == UISUBCLASS_XBOX360_CONTROLLER && 367 id->bInterfaceProtocol == UIPROTO_XBOX360_GAMEPAD)) { 368 /* The Xbox 360 gamepad has no report descriptor. */ 369 size = sizeof(uhid_xb360gp_report_descr); 370 descptr = uhid_xb360gp_report_descr; 371 } else if ((id->bInterfaceClass == UICLASS_VENDOR && 372 id->bInterfaceSubClass == UISUBCLASS_XBOXONE_CONTROLLER && 373 id->bInterfaceProtocol == UIPROTO_XBOXONE_GAMEPAD)) { 374 sc->sc_flags |= UHIDEV_F_XB1; 375 /* The Xbox One gamepad has no report descriptor. */ 376 size = sizeof(uhid_xbonegp_report_descr); 377 descptr = uhid_xbonegp_report_descr; 378 } 379 380 if (descptr) { 381 desc = malloc(size, M_USBDEV, M_NOWAIT); 382 if (desc == NULL) 383 return (ENOMEM); 384 385 memcpy(desc, descptr, size); 386 387 *descp = desc; 388 *sizep = size; 389 } 390 391 return (0); 392 } 393 #endif /* !SMALL_KERNEL */ 394 395 int 396 uhidev_maxrepid(void *buf, int len) 397 { 398 struct hid_data *d; 399 struct hid_item h; 400 int maxid; 401 402 maxid = -1; 403 h.report_ID = 0; 404 for (d = hid_start_parse(buf, len, hid_all); hid_get_item(d, &h);) 405 if (h.report_ID > maxid) 406 maxid = h.report_ID; 407 hid_end_parse(d); 408 return (maxid); 409 } 410 411 int 412 uhidevprint(void *aux, const char *pnp) 413 { 414 struct uhidev_attach_arg *uha = aux; 415 416 if (pnp) 417 printf("uhid at %s", pnp); 418 if (uha->reportid != 0) 419 printf(" reportid %d", uha->reportid); 420 return (UNCONF); 421 } 422 423 int 424 uhidev_activate(struct device *self, int act) 425 { 426 struct uhidev_softc *sc = (struct uhidev_softc *)self; 427 int i, j, already, rv = 0, r; 428 429 switch (act) { 430 case DVACT_DEACTIVATE: 431 for (i = 0; i < sc->sc_nrepid; i++) { 432 if (sc->sc_subdevs[i] == NULL) 433 continue; 434 435 /* 436 * Only notify devices attached to multiple report ids 437 * once. 438 */ 439 for (already = 0, j = 0; j < i; j++) { 440 if (sc->sc_subdevs[i] == sc->sc_subdevs[j]) { 441 already = 1; 442 break; 443 } 444 } 445 446 if (!already) { 447 r = config_deactivate( 448 &sc->sc_subdevs[i]->sc_dev); 449 if (r && r != EOPNOTSUPP) 450 rv = r; 451 } 452 } 453 usbd_deactivate(sc->sc_udev); 454 break; 455 } 456 return (rv); 457 } 458 459 int 460 uhidev_detach(struct device *self, int flags) 461 { 462 struct uhidev_softc *sc = (struct uhidev_softc *)self; 463 int i, j, rv = 0; 464 465 DPRINTF(("uhidev_detach: sc=%p flags=%d\n", sc, flags)); 466 467 if (sc->sc_opipe != NULL) { 468 usbd_close_pipe(sc->sc_opipe); 469 sc->sc_opipe = NULL; 470 } 471 472 if (sc->sc_ipipe != NULL) { 473 usbd_close_pipe(sc->sc_ipipe); 474 sc->sc_ipipe = NULL; 475 } 476 477 if (sc->sc_repdesc != NULL) 478 free(sc->sc_repdesc, M_USBDEV, sc->sc_repdesc_size); 479 480 for (i = 0; i < sc->sc_nrepid; i++) { 481 if (sc->sc_subdevs[i] == NULL) 482 continue; 483 484 rv |= config_detach(&sc->sc_subdevs[i]->sc_dev, flags); 485 486 /* 487 * Nullify without detaching any other instances of this device 488 * found on other report ids. 489 */ 490 for (j = i + 1; j < sc->sc_nrepid; j++) { 491 if (sc->sc_subdevs[i] == sc->sc_subdevs[j]) 492 sc->sc_subdevs[j] = NULL; 493 } 494 495 sc->sc_subdevs[i] = NULL; 496 } 497 free(sc->sc_subdevs, M_USBDEV, sc->sc_nrepid * sizeof(struct uhidev *)); 498 499 return (rv); 500 } 501 502 void 503 uhidev_intr(struct usbd_xfer *xfer, void *addr, usbd_status status) 504 { 505 struct uhidev_softc *sc = addr; 506 struct uhidev *scd; 507 u_char *p; 508 u_int rep; 509 u_int32_t cc; 510 511 if (usbd_is_dying(sc->sc_udev)) 512 return; 513 514 usbd_get_xfer_status(xfer, NULL, NULL, &cc, NULL); 515 516 #ifdef UHIDEV_DEBUG 517 if (uhidevdebug > 5) { 518 u_int32_t i; 519 520 DPRINTF(("uhidev_intr: status=%d cc=%d\n", status, cc)); 521 DPRINTF(("uhidev_intr: data =")); 522 for (i = 0; i < cc; i++) 523 DPRINTF((" %02x", sc->sc_ibuf[i])); 524 DPRINTF(("\n")); 525 } 526 #endif 527 528 if (status == USBD_CANCELLED || status == USBD_IOERROR) 529 return; 530 531 if (status != USBD_NORMAL_COMPLETION) { 532 DPRINTF(("%s: interrupt status=%d\n", DEVNAME(sc), status)); 533 usbd_clear_endpoint_stall_async(sc->sc_ipipe); 534 return; 535 } 536 537 p = sc->sc_ibuf; 538 if (sc->sc_nrepid != 1) 539 rep = *p++, cc--; 540 else 541 rep = 0; 542 if (rep >= sc->sc_nrepid) { 543 printf("uhidev_intr: bad repid %d\n", rep); 544 return; 545 } 546 scd = sc->sc_subdevs[rep]; 547 DPRINTFN(5,("uhidev_intr: rep=%d, scd=%p state=0x%x\n", 548 rep, scd, scd ? scd->sc_state : 0)); 549 if (scd == NULL || !(scd->sc_state & UHIDEV_OPEN)) 550 return; 551 552 scd->sc_intr(scd, p, cc); 553 } 554 555 void 556 uhidev_get_report_desc(struct uhidev_softc *sc, void **desc, int *size) 557 { 558 *desc = sc->sc_repdesc; 559 *size = sc->sc_repdesc_size; 560 } 561 562 int 563 uhidev_open(struct uhidev *scd) 564 { 565 struct uhidev_softc *sc = scd->sc_parent; 566 usbd_status err; 567 int error; 568 569 DPRINTF(("uhidev_open: open pipe, state=%d refcnt=%d\n", 570 scd->sc_state, sc->sc_refcnt)); 571 572 if (scd->sc_state & UHIDEV_OPEN) 573 return (EBUSY); 574 scd->sc_state |= UHIDEV_OPEN; 575 if (sc->sc_refcnt++) 576 return (0); 577 578 if (sc->sc_isize == 0) 579 return (0); 580 581 sc->sc_ibuf = malloc(sc->sc_isize, M_USBDEV, M_WAITOK); 582 583 /* Set up input interrupt pipe. */ 584 DPRINTF(("uhidev_open: isize=%d, ep=0x%02x\n", sc->sc_isize, 585 sc->sc_iep_addr)); 586 587 err = usbd_open_pipe_intr(sc->sc_iface, sc->sc_iep_addr, 588 USBD_SHORT_XFER_OK, &sc->sc_ipipe, sc, sc->sc_ibuf, 589 sc->sc_isize, uhidev_intr, USBD_DEFAULT_INTERVAL); 590 if (err != USBD_NORMAL_COMPLETION) { 591 DPRINTF(("uhidopen: usbd_open_pipe_intr failed, " 592 "error=%d\n", err)); 593 error = EIO; 594 goto out1; 595 } 596 597 DPRINTF(("uhidev_open: sc->sc_ipipe=%p\n", sc->sc_ipipe)); 598 599 sc->sc_ixfer = usbd_alloc_xfer(sc->sc_udev); 600 if (sc->sc_ixfer == NULL) { 601 DPRINTF(("uhidev_open: couldn't allocate an xfer\n")); 602 error = ENOMEM; 603 goto out1; // xxxx 604 } 605 606 /* 607 * Set up output interrupt pipe if an output interrupt endpoint 608 * exists. 609 */ 610 if (sc->sc_oep_addr != -1) { 611 DPRINTF(("uhidev_open: oep=0x%02x\n", sc->sc_oep_addr)); 612 613 err = usbd_open_pipe(sc->sc_iface, sc->sc_oep_addr, 614 0, &sc->sc_opipe); 615 if (err != USBD_NORMAL_COMPLETION) { 616 DPRINTF(("uhidev_open: usbd_open_pipe failed, " 617 "error=%d\n", err)); 618 error = EIO; 619 goto out2; 620 } 621 622 DPRINTF(("uhidev_open: sc->sc_opipe=%p\n", sc->sc_opipe)); 623 624 sc->sc_oxfer = usbd_alloc_xfer(sc->sc_udev); 625 if (sc->sc_oxfer == NULL) { 626 DPRINTF(("uhidev_open: couldn't allocate an xfer\n")); 627 error = ENOMEM; 628 goto out3; 629 } 630 631 sc->sc_owxfer = usbd_alloc_xfer(sc->sc_udev); 632 if (sc->sc_owxfer == NULL) { 633 DPRINTF(("uhidev_open: couldn't allocate owxfer\n")); 634 error = ENOMEM; 635 goto out3; 636 } 637 638 #ifndef SMALL_KERNEL 639 /* XBox One controller initialization */ 640 if (sc->sc_flags & UHIDEV_F_XB1) { 641 uint8_t init_data[] = { 0x05, 0x20, 0x00, 0x01, 0x00 }; 642 size_t init_data_len = sizeof(init_data); 643 usbd_setup_xfer(sc->sc_oxfer, sc->sc_opipe, 0, 644 init_data, init_data_len, 645 USBD_SYNCHRONOUS | USBD_CATCH, USBD_NO_TIMEOUT, 646 NULL); 647 err = usbd_transfer(sc->sc_oxfer); 648 if (err != USBD_NORMAL_COMPLETION) { 649 DPRINTF(("uhidev_open: xb1 init failed, " 650 "error=%d\n", err)); 651 error = EIO; 652 goto out3; 653 } 654 } 655 #endif /* !SMALL_KERNEL */ 656 } 657 658 return (0); 659 660 out3: 661 /* Abort output pipe */ 662 usbd_close_pipe(sc->sc_opipe); 663 out2: 664 /* Abort input pipe */ 665 usbd_close_pipe(sc->sc_ipipe); 666 out1: 667 DPRINTF(("uhidev_open: failed in someway")); 668 free(sc->sc_ibuf, M_USBDEV, sc->sc_isize); 669 sc->sc_ibuf = NULL; 670 scd->sc_state &= ~UHIDEV_OPEN; 671 sc->sc_refcnt = 0; 672 sc->sc_ipipe = NULL; 673 sc->sc_opipe = NULL; 674 if (sc->sc_oxfer != NULL) { 675 usbd_free_xfer(sc->sc_oxfer); 676 sc->sc_oxfer = NULL; 677 } 678 if (sc->sc_owxfer != NULL) { 679 usbd_free_xfer(sc->sc_owxfer); 680 sc->sc_owxfer = NULL; 681 } 682 if (sc->sc_ixfer != NULL) { 683 usbd_free_xfer(sc->sc_ixfer); 684 sc->sc_ixfer = NULL; 685 } 686 return (error); 687 } 688 689 void 690 uhidev_close(struct uhidev *scd) 691 { 692 struct uhidev_softc *sc = scd->sc_parent; 693 694 if (!(scd->sc_state & UHIDEV_OPEN)) 695 return; 696 scd->sc_state &= ~UHIDEV_OPEN; 697 if (--sc->sc_refcnt) 698 return; 699 DPRINTF(("uhidev_close: close pipe\n")); 700 701 /* Disable interrupts. */ 702 if (sc->sc_opipe != NULL) { 703 usbd_close_pipe(sc->sc_opipe); 704 sc->sc_opipe = NULL; 705 } 706 707 if (sc->sc_ipipe != NULL) { 708 usbd_close_pipe(sc->sc_ipipe); 709 sc->sc_ipipe = NULL; 710 } 711 712 if (sc->sc_oxfer != NULL) { 713 usbd_free_xfer(sc->sc_oxfer); 714 sc->sc_oxfer = NULL; 715 } 716 717 if (sc->sc_owxfer != NULL) { 718 usbd_free_xfer(sc->sc_owxfer); 719 sc->sc_owxfer = NULL; 720 } 721 722 if (sc->sc_ixfer != NULL) { 723 usbd_free_xfer(sc->sc_ixfer); 724 sc->sc_ixfer = NULL; 725 } 726 727 if (sc->sc_ibuf != NULL) { 728 free(sc->sc_ibuf, M_USBDEV, sc->sc_isize); 729 sc->sc_ibuf = NULL; 730 } 731 } 732 733 int 734 uhidev_report_type_conv(int hid_type_id) 735 { 736 switch (hid_type_id) { 737 case hid_input: 738 return UHID_INPUT_REPORT; 739 case hid_output: 740 return UHID_OUTPUT_REPORT; 741 case hid_feature: 742 return UHID_FEATURE_REPORT; 743 default: 744 return -1; 745 } 746 } 747 748 int 749 uhidev_set_report(struct uhidev_softc *sc, int type, int id, void *data, 750 int len) 751 { 752 usb_device_request_t req; 753 char *buf = data; 754 int actlen = len; 755 756 /* Prepend the reportID. */ 757 if (id > 0) { 758 len++; 759 buf = malloc(len, M_TEMP, M_WAITOK); 760 buf[0] = id; 761 memcpy(buf + 1, data, len - 1); 762 } 763 764 if (sc->sc_opipe != NULL) { 765 usbd_setup_xfer(sc->sc_owxfer, sc->sc_opipe, 0, buf, len, 766 USBD_SYNCHRONOUS | USBD_CATCH, 0, NULL); 767 if (usbd_transfer(sc->sc_owxfer)) { 768 usbd_clear_endpoint_stall(sc->sc_opipe); 769 actlen = -1; 770 } 771 } else { 772 req.bmRequestType = UT_WRITE_CLASS_INTERFACE; 773 req.bRequest = UR_SET_REPORT; 774 USETW2(req.wValue, type, id); 775 USETW(req.wIndex, sc->sc_ifaceno); 776 USETW(req.wLength, len); 777 778 if (usbd_do_request(sc->sc_udev, &req, buf)) 779 actlen = -1; 780 } 781 782 if (id > 0) 783 free(buf, M_TEMP, len); 784 785 return (actlen); 786 } 787 788 void 789 uhidev_set_report_async_cb(struct usbd_xfer *xfer, void *priv, usbd_status err) 790 { 791 struct uhidev_softc *sc = priv; 792 793 if (err == USBD_STALLED) 794 usbd_clear_endpoint_stall_async(sc->sc_opipe); 795 usbd_free_xfer(xfer); 796 } 797 798 int 799 uhidev_set_report_async(struct uhidev_softc *sc, int type, int id, void *data, 800 int len) 801 { 802 struct usbd_xfer *xfer; 803 usb_device_request_t req; 804 int actlen = len; 805 char *buf; 806 807 xfer = usbd_alloc_xfer(sc->sc_udev); 808 if (xfer == NULL) 809 return (-1); 810 811 if (id > 0) 812 len++; 813 814 buf = usbd_alloc_buffer(xfer, len); 815 if (buf == NULL) { 816 usbd_free_xfer(xfer); 817 return (-1); 818 } 819 820 /* Prepend the reportID. */ 821 if (id > 0) { 822 buf[0] = id; 823 memcpy(buf + 1, data, len - 1); 824 } else { 825 memcpy(buf, data, len); 826 } 827 828 if (sc->sc_opipe != NULL) { 829 usbd_setup_xfer(xfer, sc->sc_opipe, sc, buf, len, 830 USBD_NO_COPY, USBD_DEFAULT_TIMEOUT, 831 uhidev_set_report_async_cb); 832 if (usbd_transfer(xfer)) { 833 usbd_clear_endpoint_stall_async(sc->sc_opipe); 834 actlen = -1; 835 } 836 } else { 837 req.bmRequestType = UT_WRITE_CLASS_INTERFACE; 838 req.bRequest = UR_SET_REPORT; 839 USETW2(req.wValue, type, id); 840 USETW(req.wIndex, sc->sc_ifaceno); 841 USETW(req.wLength, len); 842 if (usbd_request_async(xfer, &req, NULL, NULL)) 843 actlen = -1; 844 } 845 846 return (actlen); 847 } 848 849 int 850 uhidev_get_report(struct uhidev_softc *sc, int type, int id, void *data, 851 int len) 852 { 853 usb_device_request_t req; 854 char *buf = data; 855 usbd_status err; 856 int actlen; 857 858 if (id > 0) { 859 len++; 860 buf = malloc(len, M_TEMP, M_WAITOK|M_ZERO); 861 } 862 863 req.bmRequestType = UT_READ_CLASS_INTERFACE; 864 req.bRequest = UR_GET_REPORT; 865 USETW2(req.wValue, type, id); 866 USETW(req.wIndex, sc->sc_ifaceno); 867 USETW(req.wLength, len); 868 869 err = usbd_do_request_flags(sc->sc_udev, &req, buf, 0, &actlen, 870 USBD_DEFAULT_TIMEOUT); 871 if (err != USBD_NORMAL_COMPLETION && err != USBD_SHORT_XFER) 872 actlen = -1; 873 874 /* Skip the reportID. */ 875 if (id > 0) { 876 memcpy(data, buf + 1, len - 1); 877 free(buf, M_TEMP, len); 878 } 879 880 return (actlen); 881 } 882 883 void 884 uhidev_get_report_async_cb(struct usbd_xfer *xfer, void *priv, usbd_status err) 885 { 886 struct uhidev_async_info *info = priv; 887 char *buf; 888 int len = -1; 889 890 if (!usbd_is_dying(xfer->pipe->device)) { 891 if (err == USBD_NORMAL_COMPLETION || err == USBD_SHORT_XFER) { 892 len = xfer->actlen; 893 buf = KERNADDR(&xfer->dmabuf, 0); 894 if (info->id > 0) { 895 len--; 896 memcpy(info->data, buf + 1, len); 897 } else { 898 memcpy(info->data, buf, len); 899 } 900 } 901 info->callback(info->priv, info->id, info->data, len); 902 } 903 free(info, M_TEMP, sizeof(*info)); 904 usbd_free_xfer(xfer); 905 } 906 907 int 908 uhidev_get_report_async(struct uhidev_softc *sc, int type, int id, void *data, 909 int len, void *priv, void (*callback)(void *, int, void *, int)) 910 { 911 struct usbd_xfer *xfer; 912 usb_device_request_t req; 913 struct uhidev_async_info *info; 914 int actlen = len; 915 char *buf; 916 917 xfer = usbd_alloc_xfer(sc->sc_udev); 918 if (xfer == NULL) 919 return (-1); 920 921 if (id > 0) 922 len++; 923 924 buf = usbd_alloc_buffer(xfer, len); 925 if (buf == NULL) { 926 usbd_free_xfer(xfer); 927 return (-1); 928 } 929 930 info = malloc(sizeof(*info), M_TEMP, M_NOWAIT); 931 if (info == NULL) { 932 usbd_free_xfer(xfer); 933 return (-1); 934 } 935 936 info->callback = callback; 937 info->priv = priv; 938 info->data = data; 939 info->id = id; 940 941 req.bmRequestType = UT_READ_CLASS_INTERFACE; 942 req.bRequest = UR_GET_REPORT; 943 USETW2(req.wValue, type, id); 944 USETW(req.wIndex, sc->sc_ifaceno); 945 USETW(req.wLength, len); 946 947 if (usbd_request_async(xfer, &req, info, uhidev_get_report_async_cb)) { 948 free(info, M_TEMP, sizeof(*info)); 949 actlen = -1; 950 } 951 952 return (actlen); 953 } 954 955 usbd_status 956 uhidev_write(struct uhidev_softc *sc, void *data, int len) 957 { 958 usbd_status error; 959 960 DPRINTF(("uhidev_write: data=%p, len=%d\n", data, len)); 961 962 if (sc->sc_opipe == NULL) 963 return USBD_INVAL; 964 965 #ifdef UHIDEV_DEBUG 966 if (uhidevdebug > 50) { 967 968 u_int32_t i; 969 u_int8_t *d = data; 970 971 DPRINTF(("uhidev_write: data =")); 972 for (i = 0; i < len; i++) 973 DPRINTF((" %02x", d[i])); 974 DPRINTF(("\n")); 975 } 976 #endif 977 usbd_setup_xfer(sc->sc_owxfer, sc->sc_opipe, 0, data, len, 978 USBD_SYNCHRONOUS | USBD_CATCH, 0, NULL); 979 error = usbd_transfer(sc->sc_owxfer); 980 if (error) 981 usbd_clear_endpoint_stall(sc->sc_opipe); 982 983 return (error); 984 } 985 986 int 987 uhidev_ioctl(struct uhidev *sc, u_long cmd, caddr_t addr, int flag, 988 struct proc *p) 989 { 990 struct usb_ctl_report_desc *rd; 991 struct usb_ctl_report *re; 992 int size; 993 void *desc; 994 995 switch (cmd) { 996 case USB_GET_REPORT_DESC: 997 uhidev_get_report_desc(sc->sc_parent, &desc, &size); 998 rd = (struct usb_ctl_report_desc *)addr; 999 size = min(size, sizeof rd->ucrd_data); 1000 rd->ucrd_size = size; 1001 memcpy(rd->ucrd_data, desc, size); 1002 break; 1003 case USB_GET_REPORT: 1004 re = (struct usb_ctl_report *)addr; 1005 switch (re->ucr_report) { 1006 case UHID_INPUT_REPORT: 1007 size = sc->sc_isize; 1008 break; 1009 case UHID_OUTPUT_REPORT: 1010 size = sc->sc_osize; 1011 break; 1012 case UHID_FEATURE_REPORT: 1013 size = sc->sc_fsize; 1014 break; 1015 default: 1016 return EINVAL; 1017 } 1018 if (uhidev_get_report(sc->sc_parent, re->ucr_report, 1019 sc->sc_report_id, re->ucr_data, size) != size) 1020 return EIO; 1021 break; 1022 case USB_SET_REPORT: 1023 re = (struct usb_ctl_report *)addr; 1024 switch (re->ucr_report) { 1025 case UHID_INPUT_REPORT: 1026 size = sc->sc_isize; 1027 break; 1028 case UHID_OUTPUT_REPORT: 1029 size = sc->sc_osize; 1030 break; 1031 case UHID_FEATURE_REPORT: 1032 size = sc->sc_fsize; 1033 break; 1034 default: 1035 return EINVAL; 1036 } 1037 if (uhidev_set_report(sc->sc_parent, re->ucr_report, 1038 sc->sc_report_id, re->ucr_data, size) != size) 1039 return EIO; 1040 break; 1041 case USB_GET_REPORT_ID: 1042 *(int *)addr = sc->sc_report_id; 1043 break; 1044 default: 1045 return -1; 1046 } 1047 return 0; 1048 } 1049 1050 int 1051 uhidev_set_report_dev(struct uhidev_softc *sc, struct uhidev *dev, int repid) 1052 { 1053 if ((dev->sc_state & UHIDEV_OPEN) == 0) 1054 return ENODEV; 1055 if (repid >= sc->sc_nrepid) 1056 return EINVAL; 1057 1058 sc->sc_subdevs[repid] = dev; 1059 return 0; 1060 } 1061