diff options
Diffstat (limited to 'sys/dev/usb/uhidev.c')
-rw-r--r-- | sys/dev/usb/uhidev.c | 44 |
1 files changed, 43 insertions, 1 deletions
diff --git a/sys/dev/usb/uhidev.c b/sys/dev/usb/uhidev.c index 5f2bc07cc96..3549129cbfc 100644 --- a/sys/dev/usb/uhidev.c +++ b/sys/dev/usb/uhidev.c @@ -1,4 +1,4 @@ -/* $OpenBSD: uhidev.c,v 1.83 2020/08/31 12:26:49 patrick Exp $ */ +/* $OpenBSD: uhidev.c,v 1.84 2021/01/25 14:14:42 mglocker Exp $ */ /* $NetBSD: uhidev.c,v 1.14 2003/03/11 16:44:00 augustss Exp $ */ /* @@ -98,6 +98,7 @@ int uhidev_activate(struct device *, int); void uhidev_get_report_async_cb(struct usbd_xfer *, void *, usbd_status); void uhidev_set_report_async_cb(struct usbd_xfer *, void *, usbd_status); +void uhidev_clear_iface_eps(struct uhidev_softc *, struct usbd_interface *); struct cfdriver uhidev_cd = { NULL, "uhidev", DV_DULL @@ -508,6 +509,9 @@ uhidev_open(struct uhidev *scd) DPRINTF(("uhidev_open: isize=%d, ep=0x%02x\n", sc->sc_isize, sc->sc_iep_addr)); + /* Clear device endpoint toggle. */ + uhidev_clear_iface_eps(sc, sc->sc_iface); + err = usbd_open_pipe_intr(sc->sc_iface, sc->sc_iep_addr, USBD_SHORT_XFER_OK, &sc->sc_ipipe, sc, sc->sc_ibuf, sc->sc_isize, uhidev_intr, USBD_DEFAULT_INTERVAL); @@ -517,6 +521,8 @@ uhidev_open(struct uhidev *scd) error = EIO; goto out1; } + /* Clear HC endpoint toggle. */ + usbd_clear_endpoint_toggle(sc->sc_ipipe); DPRINTF(("uhidev_open: sc->sc_ipipe=%p\n", sc->sc_ipipe)); @@ -542,6 +548,8 @@ uhidev_open(struct uhidev *scd) error = EIO; goto out2; } + /* Clear HC endpoint toggle. */ + usbd_clear_endpoint_toggle(sc->sc_opipe); DPRINTF(("uhidev_open: sc->sc_opipe=%p\n", sc->sc_opipe)); @@ -950,3 +958,37 @@ uhidev_ioctl(struct uhidev *sc, u_long cmd, caddr_t addr, int flag, } return 0; } + +void +uhidev_clear_iface_eps(struct uhidev_softc *sc, struct usbd_interface *iface) +{ + usb_interface_descriptor_t *id; + usb_endpoint_descriptor_t *ed; + uint8_t xfertype; + int i; + + /* Only clear interface endpoints when none are in use. */ + if (sc->sc_ipipe || sc->sc_opipe) + return; + DPRINTFN(1,("%s: clear interface eps\n", __func__)); + + id = usbd_get_interface_descriptor(iface); + if (id == NULL) + goto bad; + + for (i = 0; i < id->bNumEndpoints; i++) { + ed = usbd_interface2endpoint_descriptor(iface, i); + if (ed == NULL) + goto bad; + + xfertype = UE_GET_XFERTYPE(ed->bmAttributes); + if (xfertype == UE_BULK || xfertype == UE_INTERRUPT) { + if (usbd_clear_endpoint_feature(sc->sc_udev, + ed->bEndpointAddress, UF_ENDPOINT_HALT)) + goto bad; + } + } + return; +bad: + printf("%s: clear endpoints failed!\n", __func__); +} |