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