summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorMartin Pieuchot <mpi@cvs.openbsd.org>2014-12-21 12:04:02 +0000
committerMartin Pieuchot <mpi@cvs.openbsd.org>2014-12-21 12:04:02 +0000
commit3bf082d2aa24e7b02abda93f0b26abac99b3c330 (patch)
tree4aab1da9b23cb7d2bea89f426095b6df525815a0 /sys
parent5486f29ec93280df92566bd5a76c762575112915 (diff)
Always clear a port reset feature after setting it, or at least try to.
Otherwise we might leave a port in an unwanted state. Found while investigating timeout issues on xhci(4).
Diffstat (limited to 'sys')
-rw-r--r--sys/dev/usb/usb_subr.c35
-rw-r--r--sys/dev/usb/usbdivar.h4
2 files changed, 19 insertions, 20 deletions
diff --git a/sys/dev/usb/usb_subr.c b/sys/dev/usb/usb_subr.c
index 606e795c6ce..b5bcc17cd6f 100644
--- a/sys/dev/usb/usb_subr.c
+++ b/sys/dev/usb/usb_subr.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: usb_subr.c,v 1.115 2014/12/13 21:05:33 doug Exp $ */
+/* $OpenBSD: usb_subr.c,v 1.116 2014/12/21 12:04:01 mpi Exp $ */
/* $NetBSD: usb_subr.c,v 1.103 2003/01/10 11:19:13 augustss Exp $ */
/* $FreeBSD: src/sys/dev/usb/usb_subr.c,v 1.18 1999/11/17 22:33:47 n_hibma Exp $ */
@@ -370,41 +370,40 @@ usbd_port_disown_to_1_1(struct usbd_device *dev, int port)
return (err);
}
-usbd_status
+int
usbd_reset_port(struct usbd_device *dev, int port)
{
usb_port_status_t ps;
- usbd_status err;
int n;
- err = usbd_set_port_feature(dev, port, UHF_PORT_RESET);
+ if (usbd_set_port_feature(dev, port, UHF_PORT_RESET))
+ return (EIO);
DPRINTF(("%s: port %d reset done\n", __func__, port));
- if (err)
- return (err);
n = 10;
do {
/* Wait for device to recover from reset. */
usbd_delay_ms(dev, USB_PORT_RESET_DELAY);
- err = usbd_get_port_status(dev, port, &ps);
- if (err) {
- DPRINTF(("%s: get status failed %d\n", __func__, err));
- return (err);
+ if (usbd_get_port_status(dev, port, &ps)) {
+ DPRINTF(("%s: get status failed\n", __func__));
+ return (EIO);
}
/* If the device disappeared, just give up. */
if (!(UGETW(ps.wPortStatus) & UPS_CURRENT_CONNECT_STATUS))
- return (USBD_NORMAL_COMPLETION);
+ return (0);
} while ((UGETW(ps.wPortChange) & UPS_C_PORT_RESET) == 0 && --n > 0);
+
+ /* Clear port reset even if a timeout occured. */
+ if (usbd_clear_port_feature(dev, port, UHF_C_PORT_RESET)) {
+ DPRINTF(("%s: clear port feature failed\n", __func__));
+ return (EIO);
+ }
+
if (n == 0)
- return (USBD_TIMEOUT);
- err = usbd_clear_port_feature(dev, port, UHF_C_PORT_RESET);
-#ifdef USB_DEBUG
- if (err)
- DPRINTF(("%s: clear port feature failed %d\n", __func__, err));
-#endif
+ return (ETIMEDOUT);
/* Wait for the device to recover from reset. */
usbd_delay_ms(dev, USB_PORT_RESET_RECOVERY);
- return (err);
+ return (0);
}
usb_interface_descriptor_t *
diff --git a/sys/dev/usb/usbdivar.h b/sys/dev/usb/usbdivar.h
index 526a09c5218..3a7bac3c48c 100644
--- a/sys/dev/usb/usbdivar.h
+++ b/sys/dev/usb/usbdivar.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: usbdivar.h,v 1.68 2014/11/11 20:57:27 mpi Exp $ */
+/* $OpenBSD: usbdivar.h,v 1.69 2014/12/21 12:04:01 mpi Exp $ */
/* $NetBSD: usbdivar.h,v 1.70 2002/07/11 21:14:36 augustss Exp $ */
/* $FreeBSD: src/sys/dev/usb/usbdivar.h,v 1.11 1999/11/17 22:33:51 n_hibma Exp $ */
@@ -231,7 +231,7 @@ void usbd_dump_pipe(struct usbd_pipe *);
int usbctlprint(void *, const char *);
void usb_delay_ms(struct usbd_bus *, u_int);
usbd_status usbd_port_disown_to_1_1(struct usbd_device *, int);
-usbd_status usbd_reset_port(struct usbd_device *, int);
+int usbd_reset_port(struct usbd_device *, int);
usbd_status usbd_setup_pipe(struct usbd_device *,
struct usbd_interface *, struct usbd_endpoint *, int,
struct usbd_pipe **);