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