1 /* $NetBSD: uhid.c,v 1.34 2000/02/29 21:37:01 augustss Exp $ */ 2 /* $FreeBSD: src/sys/dev/usb/uhid.c,v 1.22 1999/11/17 22:33:43 n_hibma Exp $ */ 3 4 /* 5 * Copyright (c) 1998 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 (augustss@carlstedt.se) 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 * 3. All advertising materials mentioning features or use of this software 21 * must display the following acknowledgement: 22 * This product includes software developed by the NetBSD 23 * Foundation, Inc. and its contributors. 24 * 4. Neither the name of The NetBSD Foundation nor the names of its 25 * contributors may be used to endorse or promote products derived 26 * from this software without specific prior written permission. 27 * 28 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 29 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 30 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 31 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 32 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 33 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 34 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 35 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 36 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 37 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 38 * POSSIBILITY OF SUCH DAMAGE. 39 */ 40 41 /* 42 * HID spec: http://www.usb.org/developers/data/usbhid10.pdf 43 */ 44 45 #include <sys/param.h> 46 #include <sys/systm.h> 47 #include <sys/kernel.h> 48 #include <sys/malloc.h> 49 #if defined(__NetBSD__) || defined(__OpenBSD__) 50 #include <sys/device.h> 51 #include <sys/ioctl.h> 52 #elif defined(__FreeBSD__) 53 #include <sys/ioccom.h> 54 #include <sys/filio.h> 55 #include <sys/module.h> 56 #include <sys/bus.h> 57 #include <sys/ioccom.h> 58 #endif 59 #include <sys/conf.h> 60 #include <sys/tty.h> 61 #include <sys/file.h> 62 #include <sys/select.h> 63 #include <sys/proc.h> 64 #include <sys/vnode.h> 65 #include <sys/poll.h> 66 67 #include <dev/usb/usb.h> 68 #include <dev/usb/usbhid.h> 69 70 #include <dev/usb/usbdi.h> 71 #include <dev/usb/usbdi_util.h> 72 #include <dev/usb/hid.h> 73 #include <dev/usb/usb_quirks.h> 74 75 #ifdef UHID_DEBUG 76 #define DPRINTF(x) if (uhiddebug) logprintf x 77 #define DPRINTFN(n,x) if (uhiddebug>(n)) logprintf x 78 int uhiddebug = 0; 79 #else 80 #define DPRINTF(x) 81 #define DPRINTFN(n,x) 82 #endif 83 84 struct uhid_softc { 85 USBBASEDEVICE sc_dev; /* base device */ 86 usbd_device_handle sc_udev; 87 usbd_interface_handle sc_iface; /* interface */ 88 usbd_pipe_handle sc_intrpipe; /* interrupt pipe */ 89 int sc_ep_addr; 90 91 int sc_isize; 92 int sc_osize; 93 int sc_fsize; 94 u_int8_t sc_iid; 95 u_int8_t sc_oid; 96 u_int8_t sc_fid; 97 98 u_char *sc_ibuf; 99 u_char *sc_obuf; 100 101 void *sc_repdesc; 102 int sc_repdesc_size; 103 104 struct clist sc_q; 105 struct selinfo sc_rsel; 106 u_char sc_state; /* driver state */ 107 #define UHID_OPEN 0x01 /* device is open */ 108 #define UHID_ASLP 0x02 /* waiting for device data */ 109 #define UHID_NEEDCLEAR 0x04 /* needs clearing endpoint stall */ 110 #define UHID_IMMED 0x08 /* return read data immediately */ 111 112 int sc_refcnt; 113 u_char sc_dying; 114 }; 115 116 #define UHIDUNIT(dev) (minor(dev)) 117 #define UHID_CHUNK 128 /* chunk size for read */ 118 #define UHID_BSIZE 1020 /* buffer size */ 119 120 #if defined(__NetBSD__) || defined(__OpenBSD__) 121 cdev_decl(uhid); 122 #elif defined(__FreeBSD__) 123 d_open_t uhidopen; 124 d_close_t uhidclose; 125 d_read_t uhidread; 126 d_write_t uhidwrite; 127 d_ioctl_t uhidioctl; 128 d_poll_t uhidpoll; 129 130 #define UHID_CDEV_MAJOR 122 131 132 static struct cdevsw uhid_cdevsw = { 133 /* open */ uhidopen, 134 /* close */ uhidclose, 135 /* read */ uhidread, 136 /* write */ uhidwrite, 137 /* ioctl */ uhidioctl, 138 /* poll */ uhidpoll, 139 /* mmap */ nommap, 140 /* strategy */ nostrategy, 141 /* name */ "uhid", 142 /* maj */ UHID_CDEV_MAJOR, 143 /* dump */ nodump, 144 /* psize */ nopsize, 145 /* flags */ 0, 146 /* bmaj */ -1 147 }; 148 #endif 149 150 static void uhid_intr __P((usbd_xfer_handle, usbd_private_handle, 151 usbd_status)); 152 153 static int uhid_do_read __P((struct uhid_softc *, struct uio *uio, int)); 154 static int uhid_do_write __P((struct uhid_softc *, struct uio *uio, int)); 155 static int uhid_do_ioctl __P((struct uhid_softc *, u_long, caddr_t, int, 156 struct proc *)); 157 158 USB_DECLARE_DRIVER(uhid); 159 160 USB_MATCH(uhid) 161 { 162 USB_MATCH_START(uhid, uaa); 163 usb_interface_descriptor_t *id; 164 165 if (uaa->iface == NULL) 166 return (UMATCH_NONE); 167 id = usbd_get_interface_descriptor(uaa->iface); 168 if (id == NULL || id->bInterfaceClass != UICLASS_HID) 169 return (UMATCH_NONE); 170 return (UMATCH_IFACECLASS_GENERIC); 171 } 172 173 USB_ATTACH(uhid) 174 { 175 USB_ATTACH_START(uhid, sc, uaa); 176 usbd_interface_handle iface = uaa->iface; 177 usb_interface_descriptor_t *id; 178 usb_endpoint_descriptor_t *ed; 179 int size; 180 void *desc; 181 usbd_status err; 182 char devinfo[1024]; 183 184 sc->sc_udev = uaa->device; 185 sc->sc_iface = iface; 186 id = usbd_get_interface_descriptor(iface); 187 usbd_devinfo(uaa->device, 0, devinfo); 188 USB_ATTACH_SETUP; 189 printf("%s: %s, iclass %d/%d\n", USBDEVNAME(sc->sc_dev), 190 devinfo, id->bInterfaceClass, id->bInterfaceSubClass); 191 192 ed = usbd_interface2endpoint_descriptor(iface, 0); 193 if (ed == NULL) { 194 printf("%s: could not read endpoint descriptor\n", 195 USBDEVNAME(sc->sc_dev)); 196 sc->sc_dying = 1; 197 USB_ATTACH_ERROR_RETURN; 198 } 199 200 DPRINTFN(10,("uhid_attach: bLength=%d bDescriptorType=%d " 201 "bEndpointAddress=%d-%s bmAttributes=%d wMaxPacketSize=%d" 202 " bInterval=%d\n", 203 ed->bLength, ed->bDescriptorType, 204 ed->bEndpointAddress & UE_ADDR, 205 UE_GET_DIR(ed->bEndpointAddress)==UE_DIR_IN? "in" : "out", 206 ed->bmAttributes & UE_XFERTYPE, 207 UGETW(ed->wMaxPacketSize), ed->bInterval)); 208 209 if (UE_GET_DIR(ed->bEndpointAddress) != UE_DIR_IN || 210 (ed->bmAttributes & UE_XFERTYPE) != UE_INTERRUPT) { 211 printf("%s: unexpected endpoint\n", USBDEVNAME(sc->sc_dev)); 212 sc->sc_dying = 1; 213 USB_ATTACH_ERROR_RETURN; 214 } 215 216 sc->sc_ep_addr = ed->bEndpointAddress; 217 218 desc = 0; 219 err = usbd_alloc_report_desc(uaa->iface, &desc, &size, M_USBDEV); 220 if (err) { 221 printf("%s: no report descriptor\n", USBDEVNAME(sc->sc_dev)); 222 sc->sc_dying = 1; 223 USB_ATTACH_ERROR_RETURN; 224 } 225 226 (void)usbd_set_idle(iface, 0, 0); 227 228 sc->sc_isize = hid_report_size(desc, size, hid_input, &sc->sc_iid); 229 sc->sc_osize = hid_report_size(desc, size, hid_output, &sc->sc_oid); 230 sc->sc_fsize = hid_report_size(desc, size, hid_feature, &sc->sc_fid); 231 232 sc->sc_repdesc = desc; 233 sc->sc_repdesc_size = size; 234 235 #ifdef __FreeBSD__ 236 { 237 static int global_init_done = 0; 238 239 if (!global_init_done) { 240 cdevsw_add(&uhid_cdevsw); 241 global_init_done = 1; 242 } 243 } 244 #endif 245 246 usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, sc->sc_udev, 247 USBDEV(sc->sc_dev)); 248 249 USB_ATTACH_SUCCESS_RETURN; 250 } 251 252 #if defined(__NetBSD__) || defined(__OpenBSD__) 253 int 254 uhid_activate(self, act) 255 device_ptr_t self; 256 enum devact act; 257 { 258 struct uhid_softc *sc = (struct uhid_softc *)self; 259 260 switch (act) { 261 case DVACT_ACTIVATE: 262 return (EOPNOTSUPP); 263 break; 264 265 case DVACT_DEACTIVATE: 266 sc->sc_dying = 1; 267 break; 268 } 269 return (0); 270 } 271 #endif 272 273 USB_DETACH(uhid) 274 { 275 USB_DETACH_START(uhid, sc); 276 int s; 277 #if defined(__NetBSD__) || defined(__OpenBSD__) 278 int maj, mn; 279 280 DPRINTF(("uhid_detach: sc=%p flags=%d\n", sc, flags)); 281 #else 282 DPRINTF(("uhid_detach: sc=%p\n", sc)); 283 #endif 284 285 sc->sc_dying = 1; 286 if (sc->sc_intrpipe != NULL) 287 usbd_abort_pipe(sc->sc_intrpipe); 288 289 if (sc->sc_state & UHID_OPEN) { 290 s = splusb(); 291 if (--sc->sc_refcnt >= 0) { 292 /* Wake everyone */ 293 wakeup(&sc->sc_q); 294 /* Wait for processes to go away. */ 295 usb_detach_wait(USBDEV(sc->sc_dev)); 296 } 297 splx(s); 298 } 299 300 #if defined(__NetBSD__) || defined(__OpenBSD__) 301 /* locate the major number */ 302 for (maj = 0; maj < nchrdev; maj++) 303 if (cdevsw[maj].d_open == uhidopen) 304 break; 305 306 /* Nuke the vnodes for any open instances (calls close). */ 307 mn = self->dv_unit; 308 vdevgone(maj, mn, mn, VCHR); 309 #elif defined(__FreeBSD__) 310 /* XXX not implemented yet */ 311 #endif 312 313 free(sc->sc_repdesc, M_USBDEV); 314 315 usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, sc->sc_udev, 316 USBDEV(sc->sc_dev)); 317 318 return (0); 319 } 320 321 void 322 uhid_intr(xfer, addr, status) 323 usbd_xfer_handle xfer; 324 usbd_private_handle addr; 325 usbd_status status; 326 { 327 struct uhid_softc *sc = addr; 328 329 #ifdef UHID_DEBUG 330 if (uhiddebug > 5) { 331 u_int32_t cc, i; 332 333 usbd_get_xfer_status(xfer, NULL, NULL, &cc, NULL); 334 DPRINTF(("uhid_intr: status=%d cc=%d\n", status, cc)); 335 DPRINTF(("uhid_intr: data =")); 336 for (i = 0; i < cc; i++) 337 DPRINTF((" %02x", sc->sc_ibuf[i])); 338 DPRINTF(("\n")); 339 } 340 #endif 341 342 if (status == USBD_CANCELLED) 343 return; 344 345 if (status != USBD_NORMAL_COMPLETION) { 346 DPRINTF(("uhid_intr: status=%d\n", status)); 347 sc->sc_state |= UHID_NEEDCLEAR; 348 return; 349 } 350 351 (void) b_to_q(sc->sc_ibuf, sc->sc_isize, &sc->sc_q); 352 353 if (sc->sc_state & UHID_ASLP) { 354 sc->sc_state &= ~UHID_ASLP; 355 DPRINTFN(5, ("uhid_intr: waking %p\n", sc)); 356 wakeup(&sc->sc_q); 357 } 358 selwakeup(&sc->sc_rsel); 359 } 360 361 int 362 uhidopen(dev, flag, mode, p) 363 dev_t dev; 364 int flag; 365 int mode; 366 struct proc *p; 367 { 368 struct uhid_softc *sc; 369 usbd_status err; 370 371 USB_GET_SC_OPEN(uhid, UHIDUNIT(dev), sc); 372 373 DPRINTF(("uhidopen: sc=%p\n", sc)); 374 375 if (sc->sc_dying) 376 return (ENXIO); 377 378 if (sc->sc_state & UHID_OPEN) 379 return (EBUSY); 380 sc->sc_state |= UHID_OPEN; 381 382 if (clalloc(&sc->sc_q, UHID_BSIZE, 0) == -1) { 383 sc->sc_state &= ~UHID_OPEN; 384 return (ENOMEM); 385 } 386 387 sc->sc_ibuf = malloc(sc->sc_isize, M_USBDEV, M_WAITOK); 388 sc->sc_obuf = malloc(sc->sc_osize, M_USBDEV, M_WAITOK); 389 390 /* Set up interrupt pipe. */ 391 err = usbd_open_pipe_intr(sc->sc_iface, sc->sc_ep_addr, 392 USBD_SHORT_XFER_OK, &sc->sc_intrpipe, sc, sc->sc_ibuf, 393 sc->sc_isize, uhid_intr, USBD_DEFAULT_INTERVAL); 394 if (err) { 395 DPRINTF(("uhidopen: usbd_open_pipe_intr failed, " 396 "error=%d\n",err)); 397 free(sc->sc_ibuf, M_USBDEV); 398 free(sc->sc_obuf, M_USBDEV); 399 sc->sc_state &= ~UHID_OPEN; 400 return (EIO); 401 } 402 403 sc->sc_state &= ~UHID_IMMED; 404 405 return (0); 406 } 407 408 int 409 uhidclose(dev, flag, mode, p) 410 dev_t dev; 411 int flag; 412 int mode; 413 struct proc *p; 414 { 415 struct uhid_softc *sc; 416 417 USB_GET_SC(uhid, UHIDUNIT(dev), sc); 418 419 DPRINTF(("uhidclose: sc=%p\n", sc)); 420 421 /* Disable interrupts. */ 422 usbd_abort_pipe(sc->sc_intrpipe); 423 usbd_close_pipe(sc->sc_intrpipe); 424 sc->sc_intrpipe = 0; 425 426 clfree(&sc->sc_q); 427 428 free(sc->sc_ibuf, M_USBDEV); 429 free(sc->sc_obuf, M_USBDEV); 430 431 sc->sc_state &= ~UHID_OPEN; 432 433 return (0); 434 } 435 436 int 437 uhid_do_read(sc, uio, flag) 438 struct uhid_softc *sc; 439 struct uio *uio; 440 int flag; 441 { 442 int s; 443 int error = 0; 444 size_t length; 445 u_char buffer[UHID_CHUNK]; 446 usbd_status err; 447 448 DPRINTFN(1, ("uhidread\n")); 449 if (sc->sc_state & UHID_IMMED) { 450 DPRINTFN(1, ("uhidread immed\n")); 451 452 err = usbd_get_report(sc->sc_iface, UHID_INPUT_REPORT, 453 sc->sc_iid, buffer, sc->sc_isize); 454 if (err) 455 return (EIO); 456 return (uiomove(buffer, sc->sc_isize, uio)); 457 } 458 459 s = splusb(); 460 while (sc->sc_q.c_cc == 0) { 461 if (flag & IO_NDELAY) { 462 splx(s); 463 return (EWOULDBLOCK); 464 } 465 sc->sc_state |= UHID_ASLP; 466 DPRINTFN(5, ("uhidread: sleep on %p\n", sc)); 467 error = tsleep(&sc->sc_q, PZERO | PCATCH, "uhidrea", 0); 468 DPRINTFN(5, ("uhidread: woke, error=%d\n", error)); 469 if (sc->sc_dying) 470 error = EIO; 471 if (error) { 472 sc->sc_state &= ~UHID_ASLP; 473 break; 474 } 475 if (sc->sc_state & UHID_NEEDCLEAR) { 476 DPRINTFN(-1,("uhidread: clearing stall\n")); 477 sc->sc_state &= ~UHID_NEEDCLEAR; 478 usbd_clear_endpoint_stall(sc->sc_intrpipe); 479 } 480 } 481 splx(s); 482 483 /* Transfer as many chunks as possible. */ 484 while (sc->sc_q.c_cc > 0 && uio->uio_resid > 0 && !error) { 485 length = min(sc->sc_q.c_cc, uio->uio_resid); 486 if (length > sizeof(buffer)) 487 length = sizeof(buffer); 488 489 /* Remove a small chunk from the input queue. */ 490 (void) q_to_b(&sc->sc_q, buffer, length); 491 DPRINTFN(5, ("uhidread: got %lu chars\n", (u_long)length)); 492 493 /* Copy the data to the user process. */ 494 if ((error = uiomove(buffer, length, uio)) != 0) 495 break; 496 } 497 498 return (error); 499 } 500 501 int 502 uhidread(dev, uio, flag) 503 dev_t dev; 504 struct uio *uio; 505 int flag; 506 { 507 struct uhid_softc *sc; 508 int error; 509 510 USB_GET_SC(uhid, UHIDUNIT(dev), sc); 511 512 sc->sc_refcnt++; 513 error = uhid_do_read(sc, uio, flag); 514 if (--sc->sc_refcnt < 0) 515 usb_detach_wakeup(USBDEV(sc->sc_dev)); 516 return (error); 517 } 518 519 int 520 uhid_do_write(sc, uio, flag) 521 struct uhid_softc *sc; 522 struct uio *uio; 523 int flag; 524 { 525 int error; 526 int size; 527 usbd_status err; 528 529 DPRINTFN(1, ("uhidwrite\n")); 530 531 if (sc->sc_dying) 532 return (EIO); 533 534 size = sc->sc_osize; 535 error = 0; 536 if (uio->uio_resid != size) 537 return (EINVAL); 538 error = uiomove(sc->sc_obuf, size, uio); 539 if (!error) { 540 if (sc->sc_oid) 541 err = usbd_set_report(sc->sc_iface, UHID_OUTPUT_REPORT, 542 sc->sc_obuf[0], sc->sc_obuf+1, size-1); 543 else 544 err = usbd_set_report(sc->sc_iface, UHID_OUTPUT_REPORT, 545 0, sc->sc_obuf, size); 546 if (err) 547 error = EIO; 548 } 549 550 return (error); 551 } 552 553 int 554 uhidwrite(dev, uio, flag) 555 dev_t dev; 556 struct uio *uio; 557 int flag; 558 { 559 struct uhid_softc *sc; 560 int error; 561 562 USB_GET_SC(uhid, UHIDUNIT(dev), sc); 563 564 sc->sc_refcnt++; 565 error = uhid_do_write(sc, uio, flag); 566 if (--sc->sc_refcnt < 0) 567 usb_detach_wakeup(USBDEV(sc->sc_dev)); 568 return (error); 569 } 570 571 int 572 uhid_do_ioctl(sc, cmd, addr, flag, p) 573 struct uhid_softc *sc; 574 u_long cmd; 575 caddr_t addr; 576 int flag; 577 struct proc *p; 578 { 579 struct usb_ctl_report_desc *rd; 580 struct usb_ctl_report *re; 581 int size, id; 582 usbd_status err; 583 584 DPRINTFN(2, ("uhidioctl: cmd=%lx\n", cmd)); 585 586 if (sc->sc_dying) 587 return (EIO); 588 589 switch (cmd) { 590 case FIONBIO: 591 /* All handled in the upper FS layer. */ 592 break; 593 594 case USB_GET_REPORT_DESC: 595 rd = (struct usb_ctl_report_desc *)addr; 596 size = min(sc->sc_repdesc_size, sizeof rd->data); 597 rd->size = size; 598 memcpy(rd->data, sc->sc_repdesc, size); 599 break; 600 601 case USB_SET_IMMED: 602 if (*(int *)addr) { 603 /* XXX should read into ibuf, but does it matter? */ 604 err = usbd_get_report(sc->sc_iface, UHID_INPUT_REPORT, 605 sc->sc_iid, sc->sc_ibuf, sc->sc_isize); 606 if (err) 607 return (EOPNOTSUPP); 608 609 sc->sc_state |= UHID_IMMED; 610 } else 611 sc->sc_state &= ~UHID_IMMED; 612 break; 613 614 case USB_GET_REPORT: 615 re = (struct usb_ctl_report *)addr; 616 switch (re->report) { 617 case UHID_INPUT_REPORT: 618 size = sc->sc_isize; 619 id = sc->sc_iid; 620 break; 621 case UHID_OUTPUT_REPORT: 622 size = sc->sc_osize; 623 id = sc->sc_oid; 624 break; 625 case UHID_FEATURE_REPORT: 626 size = sc->sc_fsize; 627 id = sc->sc_fid; 628 break; 629 default: 630 return (EINVAL); 631 } 632 err = usbd_get_report(sc->sc_iface, re->report, id, re->data, 633 size); 634 if (err) 635 return (EIO); 636 break; 637 638 default: 639 return (EINVAL); 640 } 641 return (0); 642 } 643 644 int 645 uhidioctl(dev, cmd, addr, flag, p) 646 dev_t dev; 647 u_long cmd; 648 caddr_t addr; 649 int flag; 650 struct proc *p; 651 { 652 struct uhid_softc *sc; 653 int error; 654 655 USB_GET_SC(uhid, UHIDUNIT(dev), sc); 656 657 sc->sc_refcnt++; 658 error = uhid_do_ioctl(sc, cmd, addr, flag, p); 659 if (--sc->sc_refcnt < 0) 660 usb_detach_wakeup(USBDEV(sc->sc_dev)); 661 return (error); 662 } 663 664 int 665 uhidpoll(dev, events, p) 666 dev_t dev; 667 int events; 668 struct proc *p; 669 { 670 struct uhid_softc *sc; 671 int revents = 0; 672 int s; 673 674 USB_GET_SC(uhid, UHIDUNIT(dev), sc); 675 676 if (sc->sc_dying) 677 return (EIO); 678 679 s = splusb(); 680 if (events & (POLLOUT | POLLWRNORM)) 681 revents |= events & (POLLOUT | POLLWRNORM); 682 if (events & (POLLIN | POLLRDNORM)) { 683 if (sc->sc_q.c_cc > 0) 684 revents |= events & (POLLIN | POLLRDNORM); 685 else 686 selrecord(p, &sc->sc_rsel); 687 } 688 689 splx(s); 690 return (revents); 691 } 692 693 #if defined(__FreeBSD__) 694 DRIVER_MODULE(uhid, uhub, uhid_driver, uhid_devclass, usbd_driver_load, 0); 695 #endif 696