1 /* $OpenBSD: uhidev.c,v 1.76 2018/08/25 18:32:05 jcs 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, size); 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, sc->sc_repdesc_size); 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, sc->sc_isize); 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, sc->sc_isize); 638 sc->sc_ibuf = NULL; 639 } 640 } 641 642 int 643 uhidev_report_type_conv(int hid_type_id) 644 { 645 switch (hid_type_id) { 646 case hid_input: 647 return UHID_INPUT_REPORT; 648 case hid_output: 649 return UHID_OUTPUT_REPORT; 650 case hid_feature: 651 return UHID_FEATURE_REPORT; 652 default: 653 return -1; 654 } 655 } 656 657 int 658 uhidev_set_report(struct uhidev_softc *sc, int type, int id, void *data, 659 int len) 660 { 661 usb_device_request_t req; 662 char *buf = data; 663 int actlen = len; 664 665 /* Prepend the reportID. */ 666 if (id > 0) { 667 len++; 668 buf = malloc(len, M_TEMP, M_WAITOK); 669 buf[0] = id; 670 memcpy(buf + 1, data, len - 1); 671 } 672 673 req.bmRequestType = UT_WRITE_CLASS_INTERFACE; 674 req.bRequest = UR_SET_REPORT; 675 USETW2(req.wValue, type, id); 676 USETW(req.wIndex, sc->sc_ifaceno); 677 USETW(req.wLength, len); 678 679 if (usbd_do_request(sc->sc_udev, &req, buf)) 680 actlen = -1; 681 682 if (id > 0) 683 free(buf, M_TEMP, len); 684 685 return (actlen); 686 } 687 688 int 689 uhidev_set_report_async(struct uhidev_softc *sc, int type, int id, void *data, 690 int len) 691 { 692 struct usbd_xfer *xfer; 693 usb_device_request_t req; 694 int actlen = len; 695 char *buf; 696 697 xfer = usbd_alloc_xfer(sc->sc_udev); 698 if (xfer == NULL) 699 return (-1); 700 701 if (id > 0) 702 len++; 703 704 buf = usbd_alloc_buffer(xfer, len); 705 if (buf == NULL) { 706 usbd_free_xfer(xfer); 707 return (-1); 708 } 709 710 /* Prepend the reportID. */ 711 if (id > 0) { 712 buf[0] = id; 713 memcpy(buf + 1, data, len - 1); 714 } else { 715 memcpy(buf, data, len); 716 } 717 718 req.bmRequestType = UT_WRITE_CLASS_INTERFACE; 719 req.bRequest = UR_SET_REPORT; 720 USETW2(req.wValue, type, id); 721 USETW(req.wIndex, sc->sc_ifaceno); 722 USETW(req.wLength, len); 723 724 if (usbd_request_async(xfer, &req, NULL, NULL)) 725 actlen = -1; 726 727 return (actlen); 728 } 729 730 int 731 uhidev_get_report(struct uhidev_softc *sc, int type, int id, void *data, 732 int len) 733 { 734 usb_device_request_t req; 735 char *buf = data; 736 usbd_status err; 737 int actlen; 738 739 if (id > 0) { 740 len++; 741 buf = malloc(len, M_TEMP, M_WAITOK|M_ZERO); 742 } 743 744 req.bmRequestType = UT_READ_CLASS_INTERFACE; 745 req.bRequest = UR_GET_REPORT; 746 USETW2(req.wValue, type, id); 747 USETW(req.wIndex, sc->sc_ifaceno); 748 USETW(req.wLength, len); 749 750 err = usbd_do_request_flags(sc->sc_udev, &req, buf, 0, &actlen, 751 USBD_DEFAULT_TIMEOUT); 752 if (err != USBD_NORMAL_COMPLETION && err != USBD_SHORT_XFER) 753 actlen = -1; 754 755 /* Skip the reportID. */ 756 if (id > 0) { 757 memcpy(data, buf + 1, len - 1); 758 free(buf, M_TEMP, len); 759 } 760 761 return (actlen); 762 } 763 764 void 765 uhidev_get_report_async_cb(struct usbd_xfer *xfer, void *priv, usbd_status err) 766 { 767 struct uhidev_async_info *info = priv; 768 char *buf; 769 int len = -1; 770 771 if (!usbd_is_dying(xfer->pipe->device)) { 772 if (err == USBD_NORMAL_COMPLETION || err == USBD_SHORT_XFER) { 773 len = xfer->actlen; 774 buf = KERNADDR(&xfer->dmabuf, 0); 775 if (info->id > 0) { 776 len--; 777 memcpy(info->data, buf + 1, len); 778 } else { 779 memcpy(info->data, buf, len); 780 } 781 } 782 info->callback(info->priv, info->id, info->data, len); 783 } 784 free(info, M_TEMP, sizeof(*info)); 785 usbd_free_xfer(xfer); 786 } 787 788 int 789 uhidev_get_report_async(struct uhidev_softc *sc, int type, int id, void *data, 790 int len, void *priv, void (*callback)(void *, int, void *, int)) 791 { 792 struct usbd_xfer *xfer; 793 usb_device_request_t req; 794 struct uhidev_async_info *info; 795 int actlen = len; 796 char *buf; 797 798 xfer = usbd_alloc_xfer(sc->sc_udev); 799 if (xfer == NULL) 800 return (-1); 801 802 if (id > 0) 803 len++; 804 805 buf = usbd_alloc_buffer(xfer, len); 806 if (buf == NULL) { 807 usbd_free_xfer(xfer); 808 return (-1); 809 } 810 811 info = malloc(sizeof(*info), M_TEMP, M_NOWAIT); 812 if (info == NULL) { 813 usbd_free_xfer(xfer); 814 return (-1); 815 } 816 817 info->callback = callback; 818 info->priv = priv; 819 info->data = data; 820 info->id = id; 821 822 req.bmRequestType = UT_READ_CLASS_INTERFACE; 823 req.bRequest = UR_GET_REPORT; 824 USETW2(req.wValue, type, id); 825 USETW(req.wIndex, sc->sc_ifaceno); 826 USETW(req.wLength, len); 827 828 if (usbd_request_async(xfer, &req, info, uhidev_get_report_async_cb)) { 829 free(info, M_TEMP, sizeof(*info)); 830 actlen = -1; 831 } 832 833 return (actlen); 834 } 835 836 usbd_status 837 uhidev_write(struct uhidev_softc *sc, void *data, int len) 838 { 839 usbd_status error; 840 841 DPRINTF(("uhidev_write: data=%p, len=%d\n", data, len)); 842 843 if (sc->sc_opipe == NULL) 844 return USBD_INVAL; 845 846 #ifdef UHIDEV_DEBUG 847 if (uhidevdebug > 50) { 848 849 u_int32_t i; 850 u_int8_t *d = data; 851 852 DPRINTF(("uhidev_write: data =")); 853 for (i = 0; i < len; i++) 854 DPRINTF((" %02x", d[i])); 855 DPRINTF(("\n")); 856 } 857 #endif 858 usbd_setup_xfer(sc->sc_owxfer, sc->sc_opipe, 0, data, len, 859 USBD_SYNCHRONOUS | USBD_CATCH, 0, NULL); 860 error = usbd_transfer(sc->sc_owxfer); 861 if (error) 862 usbd_clear_endpoint_stall(sc->sc_opipe); 863 864 return (error); 865 } 866 867 int 868 uhidev_ioctl(struct uhidev *sc, u_long cmd, caddr_t addr, int flag, 869 struct proc *p) 870 { 871 struct usb_ctl_report_desc *rd; 872 struct usb_ctl_report *re; 873 int size; 874 void *desc; 875 876 switch (cmd) { 877 case USB_GET_REPORT_DESC: 878 uhidev_get_report_desc(sc->sc_parent, &desc, &size); 879 rd = (struct usb_ctl_report_desc *)addr; 880 size = min(size, sizeof rd->ucrd_data); 881 rd->ucrd_size = size; 882 memcpy(rd->ucrd_data, desc, size); 883 break; 884 case USB_GET_REPORT: 885 re = (struct usb_ctl_report *)addr; 886 switch (re->ucr_report) { 887 case UHID_INPUT_REPORT: 888 size = sc->sc_isize; 889 break; 890 case UHID_OUTPUT_REPORT: 891 size = sc->sc_osize; 892 break; 893 case UHID_FEATURE_REPORT: 894 size = sc->sc_fsize; 895 break; 896 default: 897 return EINVAL; 898 } 899 if (uhidev_get_report(sc->sc_parent, re->ucr_report, 900 sc->sc_report_id, re->ucr_data, size) != size) 901 return EIO; 902 break; 903 case USB_SET_REPORT: 904 re = (struct usb_ctl_report *)addr; 905 switch (re->ucr_report) { 906 case UHID_INPUT_REPORT: 907 size = sc->sc_isize; 908 break; 909 case UHID_OUTPUT_REPORT: 910 size = sc->sc_osize; 911 break; 912 case UHID_FEATURE_REPORT: 913 size = sc->sc_fsize; 914 break; 915 default: 916 return EINVAL; 917 } 918 if (uhidev_set_report(sc->sc_parent, re->ucr_report, 919 sc->sc_report_id, re->ucr_data, size) != size) 920 return EIO; 921 break; 922 case USB_GET_REPORT_ID: 923 *(int *)addr = sc->sc_report_id; 924 break; 925 default: 926 return -1; 927 } 928 return 0; 929 } 930