2 * SPDX-License-Identifier: BSD-2-Clause-NetBSD
4 * Copyright (c) 1998 The NetBSD Foundation, Inc.
5 * Copyright (c) 2019 Vladimir Kondratyev <wulf@FreeBSD.org>
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Lennart Augustsson (lennart@augustsson.net) at
9 * Carlstedt Research & Technology.
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
20 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 * POSSIBILITY OF SUCH DAMAGE.
33 #include <sys/cdefs.h>
34 __FBSDID("$FreeBSD$");
37 * HID spec: https://www.usb.org/sites/default/files/documents/hid1_11.pdf
40 #include <sys/stdint.h>
41 #include <sys/stddef.h>
42 #include <sys/param.h>
43 #include <sys/queue.h>
44 #include <sys/types.h>
45 #include <sys/systm.h>
46 #include <sys/kernel.h>
48 #include <sys/module.h>
50 #include <sys/mutex.h>
51 #include <sys/condvar.h>
52 #include <sys/sysctl.h>
54 #include <sys/unistd.h>
55 #include <sys/callout.h>
56 #include <sys/malloc.h>
59 #include <sys/fcntl.h>
61 #include <dev/evdev/input.h>
63 #include <dev/hid/hid.h>
64 #include <dev/hid/hidquirk.h>
66 #include <dev/usb/usb.h>
67 #include <dev/usb/usbdi.h>
68 #include <dev/usb/usbdi_util.h>
69 #include <dev/usb/usbhid.h>
71 #define USB_DEBUG_VAR usbhid_debug
72 #include <dev/usb/usb_debug.h>
74 #include <dev/usb/quirk/usb_quirk.h>
78 static SYSCTL_NODE(_hw_usb, OID_AUTO, usbhid, CTLFLAG_RW, 0, "USB usbhid");
79 static int usbhid_enable = 0;
80 SYSCTL_INT(_hw_usb_usbhid, OID_AUTO, enable, CTLFLAG_RWTUN,
81 &usbhid_enable, 0, "Enable usbhid and prefer it to other USB HID drivers");
83 static int usbhid_debug = 0;
84 SYSCTL_INT(_hw_usb_usbhid, OID_AUTO, debug, CTLFLAG_RWTUN,
85 &usbhid_debug, 0, "Debug level");
95 struct usbhid_xfer_ctx;
96 typedef int usbhid_callback_t(struct usbhid_xfer_ctx *xfer_ctx);
98 union usbhid_device_request {
99 struct { /* INTR xfers */
103 struct usb_device_request ctrl; /* CTRL xfers */
106 /* Syncronous USB transfer context */
107 struct usbhid_xfer_ctx {
108 union usbhid_device_request req;
111 usbhid_callback_t *cb;
117 struct usbhid_softc {
118 hid_intr_t *sc_intr_handler;
122 struct hid_device_info sc_hw;
125 struct usb_config sc_config[USBHID_N_TRANSFER];
126 struct usb_xfer *sc_xfer[USBHID_N_TRANSFER];
127 struct usbhid_xfer_ctx sc_xfer_ctx[USBHID_N_TRANSFER];
129 struct usb_device *sc_udev;
131 uint8_t sc_iface_index;
136 static device_probe_t usbhid_probe;
137 static device_attach_t usbhid_attach;
138 static device_detach_t usbhid_detach;
140 static usb_callback_t usbhid_intr_out_callback;
141 static usb_callback_t usbhid_intr_in_callback;
142 static usb_callback_t usbhid_ctrl_callback;
144 static usbhid_callback_t usbhid_intr_handler_cb;
145 static usbhid_callback_t usbhid_sync_wakeup_cb;
148 usbhid_intr_out_callback(struct usb_xfer *xfer, usb_error_t error)
150 struct usbhid_xfer_ctx *xfer_ctx = usbd_xfer_softc(xfer);
151 struct usb_page_cache *pc;
154 switch (USB_GET_STATE(xfer)) {
155 case USB_ST_TRANSFERRED:
158 len = xfer_ctx->req.intr.maxlen;
160 if (USB_IN_POLLING_MODE_FUNC())
164 pc = usbd_xfer_get_frame(xfer, 0);
165 usbd_copy_in(pc, 0, xfer_ctx->buf, len);
166 usbd_xfer_set_frame_len(xfer, 0, len);
167 usbd_transfer_submit(xfer);
168 xfer_ctx->req.intr.maxlen = 0;
169 if (USB_IN_POLLING_MODE_FUNC())
175 if (error != USB_ERR_CANCELLED) {
176 /* try to clear stall first */
177 usbd_xfer_set_stall(xfer);
180 xfer_ctx->error = EIO;
182 (void)xfer_ctx->cb(xfer_ctx);
188 usbhid_intr_in_callback(struct usb_xfer *xfer, usb_error_t error)
190 struct usbhid_xfer_ctx *xfer_ctx = usbd_xfer_softc(xfer);
191 struct usb_page_cache *pc;
194 switch (USB_GET_STATE(xfer)) {
195 case USB_ST_TRANSFERRED:
196 DPRINTF("transferred!\n");
198 usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL);
199 pc = usbd_xfer_get_frame(xfer, 0);
200 usbd_copy_out(pc, 0, xfer_ctx->buf, actlen);
201 xfer_ctx->req.intr.actlen = actlen;
202 if (xfer_ctx->cb(xfer_ctx) != 0)
207 usbd_xfer_set_frame_len(xfer, 0, xfer_ctx->req.intr.maxlen);
208 usbd_transfer_submit(xfer);
212 if (error != USB_ERR_CANCELLED) {
213 /* try to clear stall first */
214 usbd_xfer_set_stall(xfer);
222 usbhid_ctrl_callback(struct usb_xfer *xfer, usb_error_t error)
224 struct usbhid_xfer_ctx *xfer_ctx = usbd_xfer_softc(xfer);
225 struct usb_device_request *req = &xfer_ctx->req.ctrl;
226 struct usb_page_cache *pc;
227 int len = UGETW(req->wLength);
228 bool is_rd = (req->bmRequestType & UT_READ) != 0;
230 switch (USB_GET_STATE(xfer)) {
232 if (!is_rd && len != 0) {
233 pc = usbd_xfer_get_frame(xfer, 1);
234 usbd_copy_in(pc, 0, xfer_ctx->buf, len);
237 pc = usbd_xfer_get_frame(xfer, 0);
238 usbd_copy_in(pc, 0, req, sizeof(*req));
239 usbd_xfer_set_frame_len(xfer, 0, sizeof(*req));
241 usbd_xfer_set_frame_len(xfer, 1, len);
242 usbd_xfer_set_frames(xfer, len != 0 ? 2 : 1);
243 usbd_transfer_submit(xfer);
246 case USB_ST_TRANSFERRED:
247 if (is_rd && len != 0) {
248 pc = usbd_xfer_get_frame(xfer, 0);
249 usbd_copy_out(pc, sizeof(*req), xfer_ctx->buf, len);
256 DPRINTFN(1, "error=%s\n", usbd_errstr(error));
257 xfer_ctx->error = EIO;
259 (void)xfer_ctx->cb(xfer_ctx);
265 usbhid_intr_handler_cb(struct usbhid_xfer_ctx *xfer_ctx)
267 struct usbhid_softc *sc = xfer_ctx->cb_ctx;
269 sc->sc_intr_handler(sc->sc_intr_ctx, xfer_ctx->buf,
270 xfer_ctx->req.intr.actlen);
276 usbhid_sync_wakeup_cb(struct usbhid_xfer_ctx *xfer_ctx)
279 if (!USB_IN_POLLING_MODE_FUNC())
280 wakeup(xfer_ctx->cb_ctx);
285 static const struct usb_config usbhid_config[USBHID_N_TRANSFER] = {
287 [USBHID_INTR_OUT_DT] = {
288 .type = UE_INTERRUPT,
289 .endpoint = UE_ADDR_ANY,
290 .direction = UE_DIR_OUT,
291 .flags = {.pipe_bof = 1,.proxy_buffer = 1},
292 .callback = &usbhid_intr_out_callback,
294 [USBHID_INTR_IN_DT] = {
295 .type = UE_INTERRUPT,
296 .endpoint = UE_ADDR_ANY,
297 .direction = UE_DIR_IN,
298 .flags = {.pipe_bof = 1,.short_xfer_ok = 1,.proxy_buffer = 1},
299 .callback = &usbhid_intr_in_callback,
303 .endpoint = 0x00, /* Control pipe */
304 .direction = UE_DIR_ANY,
305 .flags = {.proxy_buffer = 1},
306 .callback = &usbhid_ctrl_callback,
307 .timeout = 1000, /* 1 second */
311 static inline usb_frlength_t
312 usbhid_xfer_max_len(struct usb_xfer *xfer)
314 return (xfer == NULL ? 0 : usbd_xfer_max_len(xfer));
318 usbhid_xfer_check_len(struct usbhid_softc* sc, int xfer_idx, hid_size_t len)
320 if (sc->sc_xfer[xfer_idx] == NULL)
322 if (len > usbd_xfer_max_len(sc->sc_xfer[xfer_idx]))
328 usbhid_intr_setup(device_t dev, hid_intr_t intr, void *context,
329 struct hid_rdesc_info *rdesc)
331 struct usbhid_softc* sc = device_get_softc(dev);
336 sc->sc_intr_handler = intr;
337 sc->sc_intr_ctx = context;
338 bcopy(usbhid_config, sc->sc_config, sizeof(usbhid_config));
339 bzero(sc->sc_xfer, sizeof(sc->sc_xfer));
341 /* Set buffer sizes to match HID report sizes */
342 sc->sc_config[USBHID_INTR_OUT_DT].bufsize = rdesc->osize;
343 sc->sc_config[USBHID_INTR_IN_DT].bufsize = rdesc->isize;
344 sc->sc_config[USBHID_CTRL_DT].bufsize =
345 MAX(rdesc->isize, MAX(rdesc->osize, rdesc->fsize));
347 nowrite = hid_test_quirk(&sc->sc_hw, HQ_NOWRITE);
350 * Setup the USB transfers one by one, so they are memory independent
351 * which allows for handling panics triggered by the HID drivers
352 * itself, typically by hkbd via CTRL+ALT+ESC sequences. Or if the HID
353 * keyboard driver was processing a key at the moment of panic.
355 for (n = 0; n != USBHID_N_TRANSFER; n++) {
356 if (nowrite && n == USBHID_INTR_OUT_DT)
358 error = usbd_transfer_setup(sc->sc_udev, &sc->sc_iface_index,
359 sc->sc_xfer + n, sc->sc_config + n, 1,
360 (void *)(sc->sc_xfer_ctx + n), &sc->sc_mtx);
362 DPRINTF("xfer %d setup error=%s\n", n,
366 rdesc->rdsize = usbhid_xfer_max_len(sc->sc_xfer[USBHID_INTR_IN_DT]);
367 rdesc->grsize = usbhid_xfer_max_len(sc->sc_xfer[USBHID_CTRL_DT]);
368 rdesc->srsize = rdesc->grsize;
369 rdesc->wrsize = nowrite ? rdesc->srsize :
370 usbhid_xfer_max_len(sc->sc_xfer[USBHID_INTR_OUT_DT]);
372 sc->sc_intr_buf = malloc(rdesc->rdsize, M_USBDEV, M_ZERO | M_WAITOK);
376 usbhid_intr_unsetup(device_t dev)
378 struct usbhid_softc* sc = device_get_softc(dev);
380 usbd_transfer_unsetup(sc->sc_xfer, USBHID_N_TRANSFER);
381 free(sc->sc_intr_buf, M_USBDEV);
385 usbhid_intr_start(device_t dev)
387 struct usbhid_softc* sc = device_get_softc(dev);
389 if (sc->sc_xfer[USBHID_INTR_IN_DT] == NULL)
392 mtx_lock(&sc->sc_mtx);
393 sc->sc_xfer_ctx[USBHID_INTR_IN_DT] = (struct usbhid_xfer_ctx) {
395 usbd_xfer_max_len(sc->sc_xfer[USBHID_INTR_IN_DT]),
396 .cb = usbhid_intr_handler_cb,
398 .buf = sc->sc_intr_buf,
400 usbd_transfer_start(sc->sc_xfer[USBHID_INTR_IN_DT]);
401 mtx_unlock(&sc->sc_mtx);
407 usbhid_intr_stop(device_t dev)
409 struct usbhid_softc* sc = device_get_softc(dev);
411 usbd_transfer_drain(sc->sc_xfer[USBHID_INTR_IN_DT]);
412 usbd_transfer_drain(sc->sc_xfer[USBHID_INTR_OUT_DT]);
418 usbhid_intr_poll(device_t dev)
420 struct usbhid_softc* sc = device_get_softc(dev);
422 usbd_transfer_poll(sc->sc_xfer + USBHID_INTR_IN_DT, 1);
429 usbhid_sync_xfer(struct usbhid_softc* sc, int xfer_idx,
430 union usbhid_device_request *req, void *buf)
433 struct usbhid_xfer_ctx *xfer_ctx, save;
435 xfer_ctx = sc->sc_xfer_ctx + xfer_idx;
437 if (USB_IN_POLLING_MODE_FUNC()) {
440 mtx_lock(&sc->sc_mtx);
442 while (xfer_ctx->influx)
443 mtx_sleep(&xfer_ctx->waiters, &sc->sc_mtx, 0,
446 xfer_ctx->influx = true;
450 xfer_ctx->req = *req;
451 xfer_ctx->error = ETIMEDOUT;
452 xfer_ctx->cb = &usbhid_sync_wakeup_cb;
453 xfer_ctx->cb_ctx = xfer_ctx;
454 timeout = USB_DEFAULT_TIMEOUT;
455 usbd_transfer_start(sc->sc_xfer[xfer_idx]);
457 if (USB_IN_POLLING_MODE_FUNC())
458 while (timeout > 0 && xfer_ctx->error == ETIMEDOUT) {
459 usbd_transfer_poll(sc->sc_xfer + xfer_idx, 1);
464 msleep_sbt(xfer_ctx, &sc->sc_mtx, 0, "usbhid io",
465 SBT_1MS * timeout, 0, C_HARDCLOCK);
467 /* Perform usbhid_write() asyncronously to improve pipelining */
468 if (USB_IN_POLLING_MODE_FUNC() || xfer_ctx->error != 0 ||
469 sc->sc_config[xfer_idx].type != UE_INTERRUPT ||
470 sc->sc_config[xfer_idx].direction != UE_DIR_OUT)
471 usbd_transfer_stop(sc->sc_xfer[xfer_idx]);
472 error = xfer_ctx->error;
474 *req = xfer_ctx->req;
476 if (USB_IN_POLLING_MODE_FUNC()) {
479 xfer_ctx->influx = false;
480 if (xfer_ctx->waiters != 0)
481 wakeup_one(&xfer_ctx->waiters);
482 mtx_unlock(&sc->sc_mtx);
486 DPRINTF("USB IO error:%d\n", error);
492 usbhid_get_rdesc(device_t dev, void *buf, hid_size_t len)
494 struct usbhid_softc* sc = device_get_softc(dev);
497 error = usbd_req_get_report_descriptor(sc->sc_udev, NULL,
498 buf, len, sc->sc_iface_index);
501 DPRINTF("no report descriptor: %s\n", usbd_errstr(error));
503 return (error == 0 ? 0 : ENXIO);
507 usbhid_get_report(device_t dev, void *buf, hid_size_t maxlen,
508 hid_size_t *actlen, uint8_t type, uint8_t id)
510 struct usbhid_softc* sc = device_get_softc(dev);
511 union usbhid_device_request req;
514 error = usbhid_xfer_check_len(sc, USBHID_CTRL_DT, maxlen);
518 req.ctrl.bmRequestType = UT_READ_CLASS_INTERFACE;
519 req.ctrl.bRequest = UR_GET_REPORT;
520 USETW2(req.ctrl.wValue, type, id);
521 req.ctrl.wIndex[0] = sc->sc_iface_no;
522 req.ctrl.wIndex[1] = 0;
523 USETW(req.ctrl.wLength, maxlen);
525 error = usbhid_sync_xfer(sc, USBHID_CTRL_DT, &req, buf);
526 if (!error && actlen != NULL)
533 usbhid_set_report(device_t dev, const void *buf, hid_size_t len, uint8_t type,
536 struct usbhid_softc* sc = device_get_softc(dev);
537 union usbhid_device_request req;
540 error = usbhid_xfer_check_len(sc, USBHID_CTRL_DT, len);
544 req.ctrl.bmRequestType = UT_WRITE_CLASS_INTERFACE;
545 req.ctrl.bRequest = UR_SET_REPORT;
546 USETW2(req.ctrl.wValue, type, id);
547 req.ctrl.wIndex[0] = sc->sc_iface_no;
548 req.ctrl.wIndex[1] = 0;
549 USETW(req.ctrl.wLength, len);
551 return (usbhid_sync_xfer(sc, USBHID_CTRL_DT, &req,
552 __DECONST(void *, buf)));
556 usbhid_read(device_t dev, void *buf, hid_size_t maxlen, hid_size_t *actlen)
558 struct usbhid_softc* sc = device_get_softc(dev);
559 union usbhid_device_request req;
562 error = usbhid_xfer_check_len(sc, USBHID_INTR_IN_DT, maxlen);
566 req.intr.maxlen = maxlen;
567 error = usbhid_sync_xfer(sc, USBHID_INTR_IN_DT, &req, buf);
568 if (error == 0 && actlen != NULL)
569 *actlen = req.intr.actlen;
575 usbhid_write(device_t dev, const void *buf, hid_size_t len)
577 struct usbhid_softc* sc = device_get_softc(dev);
578 union usbhid_device_request req;
581 error = usbhid_xfer_check_len(sc, USBHID_INTR_OUT_DT, len);
585 req.intr.maxlen = len;
586 return (usbhid_sync_xfer(sc, USBHID_INTR_OUT_DT, &req,
587 __DECONST(void *, buf)));
591 usbhid_set_idle(device_t dev, uint16_t duration, uint8_t id)
593 struct usbhid_softc* sc = device_get_softc(dev);
594 union usbhid_device_request req;
597 error = usbhid_xfer_check_len(sc, USBHID_CTRL_DT, 0);
601 /* Duration is measured in 4 milliseconds per unit. */
602 req.ctrl.bmRequestType = UT_WRITE_CLASS_INTERFACE;
603 req.ctrl.bRequest = UR_SET_IDLE;
604 USETW2(req.ctrl.wValue, (duration + 3) / 4, id);
605 req.ctrl.wIndex[0] = sc->sc_iface_no;
606 req.ctrl.wIndex[1] = 0;
607 USETW(req.ctrl.wLength, 0);
609 return (usbhid_sync_xfer(sc, USBHID_CTRL_DT, &req, NULL));
613 usbhid_set_protocol(device_t dev, uint16_t protocol)
615 struct usbhid_softc* sc = device_get_softc(dev);
616 union usbhid_device_request req;
619 error = usbhid_xfer_check_len(sc, USBHID_CTRL_DT, 0);
623 req.ctrl.bmRequestType = UT_WRITE_CLASS_INTERFACE;
624 req.ctrl.bRequest = UR_SET_PROTOCOL;
625 USETW(req.ctrl.wValue, protocol);
626 req.ctrl.wIndex[0] = sc->sc_iface_no;
627 req.ctrl.wIndex[1] = 0;
628 USETW(req.ctrl.wLength, 0);
630 return (usbhid_sync_xfer(sc, USBHID_CTRL_DT, &req, NULL));
634 usbhid_init_device_info(struct usb_attach_arg *uaa, struct hid_device_info *hw)
638 hw->idVendor = uaa->info.idVendor;
639 hw->idProduct = uaa->info.idProduct;
640 hw->idVersion = uaa->info.bcdDevice;
642 /* Set various quirks based on usb_attach_arg */
643 hid_add_dynamic_quirk(hw, USB_GET_DRIVER_INFO(uaa));
647 usbhid_fill_device_info(struct usb_attach_arg *uaa, struct hid_device_info *hw)
649 struct usb_device *udev = uaa->device;
650 struct usb_interface *iface = uaa->iface;
651 struct usb_hid_descriptor *hid;
652 struct usb_endpoint *ep;
654 snprintf(hw->name, sizeof(hw->name), "%s %s",
655 usb_get_manufacturer(udev), usb_get_product(udev));
656 strlcpy(hw->serial, usb_get_serial(udev), sizeof(hw->serial));
658 if (uaa->info.bInterfaceClass == UICLASS_HID &&
659 iface != NULL && iface->idesc != NULL) {
660 hid = hid_get_descriptor_from_usb(
661 usbd_get_config_descriptor(udev), iface->idesc);
664 UGETW(hid->descrs[0].wDescriptorLength);
667 /* See if there is a interrupt out endpoint. */
668 ep = usbd_get_endpoint(udev, uaa->info.bIfaceIndex,
669 usbhid_config + USBHID_INTR_OUT_DT);
670 if (ep == NULL || ep->methods == NULL)
671 hid_add_dynamic_quirk(hw, HQ_NOWRITE);
674 static const STRUCT_USB_HOST_ID usbhid_devs[] = {
675 /* the Xbox 360 gamepad doesn't use the HID class */
676 {USB_IFACE_CLASS(UICLASS_VENDOR),
677 USB_IFACE_SUBCLASS(UISUBCLASS_XBOX360_CONTROLLER),
678 USB_IFACE_PROTOCOL(UIPROTO_XBOX360_GAMEPAD),
679 USB_DRIVER_INFO(HQ_IS_XBOX360GP)},
680 /* HID keyboard with boot protocol support */
681 {USB_IFACE_CLASS(UICLASS_HID),
682 USB_IFACE_SUBCLASS(UISUBCLASS_BOOT),
683 USB_IFACE_PROTOCOL(UIPROTO_BOOT_KEYBOARD),
684 USB_DRIVER_INFO(HQ_HAS_KBD_BOOTPROTO)},
685 /* HID mouse with boot protocol support */
686 {USB_IFACE_CLASS(UICLASS_HID),
687 USB_IFACE_SUBCLASS(UISUBCLASS_BOOT),
688 USB_IFACE_PROTOCOL(UIPROTO_MOUSE),
689 USB_DRIVER_INFO(HQ_HAS_MS_BOOTPROTO)},
690 /* generic HID class */
691 {USB_IFACE_CLASS(UICLASS_HID), USB_DRIVER_INFO(HQ_NONE)},
695 usbhid_probe(device_t dev)
697 struct usb_attach_arg *uaa = device_get_ivars(dev);
698 struct usbhid_softc *sc = device_get_softc(dev);
703 if (usbhid_enable == 0)
706 if (uaa->usb_mode != USB_MODE_HOST)
709 error = usbd_lookup_id_by_uaa(usbhid_devs, sizeof(usbhid_devs), uaa);
713 if (usb_test_quirk(uaa, UQ_HID_IGNORE))
717 * Setup temporary hid_device_info so that we can figure out some
718 * basic quirks for this device.
720 usbhid_init_device_info(uaa, &sc->sc_hw);
722 if (hid_test_quirk(&sc->sc_hw, HQ_HID_IGNORE))
725 return (BUS_PROBE_GENERIC + 1);
729 usbhid_attach(device_t dev)
731 struct usb_attach_arg *uaa = device_get_ivars(dev);
732 struct usbhid_softc *sc = device_get_softc(dev);
736 DPRINTFN(10, "sc=%p\n", sc);
738 device_set_usb_desc(dev);
740 sc->sc_udev = uaa->device;
741 sc->sc_iface_no = uaa->info.bIfaceNum;
742 sc->sc_iface_index = uaa->info.bIfaceIndex;
744 usbhid_fill_device_info(uaa, &sc->sc_hw);
746 error = usbd_req_set_idle(uaa->device, NULL,
747 uaa->info.bIfaceIndex, 0, 0);
749 DPRINTF("set idle failed, error=%s (ignored)\n",
752 mtx_init(&sc->sc_mtx, "usbhid lock", NULL, MTX_DEF);
754 child = device_add_child(dev, "hidbus", -1);
756 device_printf(dev, "Could not add hidbus device\n");
761 device_set_ivars(child, &sc->sc_hw);
762 error = bus_generic_attach(dev);
764 device_printf(dev, "failed to attach child: %d\n", error);
769 return (0); /* success */
773 usbhid_detach(device_t dev)
775 struct usbhid_softc *sc = device_get_softc(dev);
777 device_delete_children(dev);
778 mtx_destroy(&sc->sc_mtx);
783 static devclass_t usbhid_devclass;
785 static device_method_t usbhid_methods[] = {
786 DEVMETHOD(device_probe, usbhid_probe),
787 DEVMETHOD(device_attach, usbhid_attach),
788 DEVMETHOD(device_detach, usbhid_detach),
790 DEVMETHOD(hid_intr_setup, usbhid_intr_setup),
791 DEVMETHOD(hid_intr_unsetup, usbhid_intr_unsetup),
792 DEVMETHOD(hid_intr_start, usbhid_intr_start),
793 DEVMETHOD(hid_intr_stop, usbhid_intr_stop),
794 DEVMETHOD(hid_intr_poll, usbhid_intr_poll),
797 DEVMETHOD(hid_get_rdesc, usbhid_get_rdesc),
798 DEVMETHOD(hid_read, usbhid_read),
799 DEVMETHOD(hid_write, usbhid_write),
800 DEVMETHOD(hid_get_report, usbhid_get_report),
801 DEVMETHOD(hid_set_report, usbhid_set_report),
802 DEVMETHOD(hid_set_idle, usbhid_set_idle),
803 DEVMETHOD(hid_set_protocol, usbhid_set_protocol),
808 static driver_t usbhid_driver = {
810 .methods = usbhid_methods,
811 .size = sizeof(struct usbhid_softc),
814 DRIVER_MODULE(usbhid, uhub, usbhid_driver, usbhid_devclass, NULL, 0);
815 MODULE_DEPEND(usbhid, usb, 1, 1, 1);
816 MODULE_DEPEND(usbhid, hid, 1, 1, 1);
817 MODULE_DEPEND(usbhid, hidbus, 1, 1, 1);
818 MODULE_VERSION(usbhid, 1);
819 USB_PNP_HOST_INFO(usbhid_devs);