summaryrefslogtreecommitdiff
path: root/sys/dev/usb/uhidev.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/usb/uhidev.c')
-rw-r--r--sys/dev/usb/uhidev.c44
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__);
+}