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