summaryrefslogtreecommitdiffstats
path: root/sys/dev/usb/usb_subr.c
diff options
context:
space:
mode:
authorfgsch <fgsch@openbsd.org>2008-05-19 14:05:43 +0000
committerfgsch <fgsch@openbsd.org>2008-05-19 14:05:43 +0000
commit7e0880b9217a40e54cde8f986c72964383efc6b3 (patch)
tree2b903082b2965a194a974ef75adfa0b6d47d05f3 /sys/dev/usb/usb_subr.c
parentInclude mpe in the Makefile. I forgot to include it when I initially (diff)
downloadwireguard-openbsd-7e0880b9217a40e54cde8f986c72964383efc6b3.tar.xz
wireguard-openbsd-7e0880b9217a40e54cde8f986c72964383efc6b3.zip
try a few times before giving up while getting the device descriptor. if
it fails, reset the port and try again. this seems to fix some devices that would punt with "device problem, disabling port" otherwise. from augustss@netbsd with some change as per discussion with theo. set the address before getting the descriptor. from peterbu at bemac dot com via netbsd kern/24716. tested by many.
Diffstat (limited to 'sys/dev/usb/usb_subr.c')
-rw-r--r--sys/dev/usb/usb_subr.c49
1 files changed, 30 insertions, 19 deletions
diff --git a/sys/dev/usb/usb_subr.c b/sys/dev/usb/usb_subr.c
index cda20113d4a..928907f945f 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.64 2007/11/04 05:52:36 deraadt Exp $ */
+/* $OpenBSD: usb_subr.c,v 1.65 2008/05/19 14:05:43 fgsch 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 $ */
@@ -979,6 +979,7 @@ usbd_new_device(struct device *parent, usbd_bus_handle bus, int depth,
usbd_device_handle dev, adev;
struct usbd_device *hub;
usb_device_descriptor_t *dd;
+ usb_port_status_t ps;
usbd_status err;
int addr;
int i;
@@ -1049,15 +1050,40 @@ usbd_new_device(struct device *parent, usbd_bus_handle bus, int depth,
return (err);
}
+ /* Set the address. Do this early; some devices need that. */
+ /* Try a few times in case the device is slow (i.e. outside specs.) */
+ DPRINTFN(5,("usbd_new_device: setting device address=%d\n", addr));
+ for (i = 0; i < 15; i++) {
+ err = usbd_set_address(dev, addr);
+ if (!err)
+ break;
+ if ((i % 4) == 0)
+ usbd_reset_port(up->parent, port, &ps);
+ else
+ usbd_delay_ms(dev, 200);
+ }
+ if (err) {
+ DPRINTFN(-1,("usbd_new_device: set address %d failed\n", addr));
+ err = USBD_SET_ADDR_FAILED;
+ usbd_remove_device(dev, up);
+ return (err);
+ }
+ /* Allow device time to set new address */
+ usbd_delay_ms(dev, USB_SET_ADDRESS_SETTLE);
+ dev->address = addr; /* New device address now */
+ bus->devices[addr] = dev;
+
dd = &dev->ddesc;
/* Try a few times in case the device is slow (i.e. outside specs.) */
- for (i = 0; i < 5; i++) {
+ for (i = 0; i < 15; i++) {
/* Get the first 8 bytes of the device descriptor. */
err = usbd_get_desc(dev, UDESC_DEVICE, 0, USB_MAX_IPACKET, dd);
if (!err)
break;
- /* progressively increase the delay */
- usbd_delay_ms(dev, 200 * (i + 1));
+ if ((i % 4) == 0)
+ usbd_reset_port(up->parent, port, &ps);
+ else
+ usbd_delay_ms(dev, 200);
}
if (err) {
DPRINTFN(-1, ("usbd_new_device: addr=%d, getting first desc "
@@ -1107,21 +1133,6 @@ usbd_new_device(struct device *parent, usbd_bus_handle bus, int depth,
return (err);
}
- /* Set the address */
- DPRINTFN(5,("usbd_new_device: setting device address=%d\n", addr));
- err = usbd_set_address(dev, addr);
- if (err) {
- DPRINTFN(-1,("usbd_new_device: set address %d failed\n", addr));
- err = USBD_SET_ADDR_FAILED;
- usbd_remove_device(dev, up);
- return (err);
- }
- /* Allow device time to set new address */
- usbd_delay_ms(dev, USB_SET_ADDRESS_SETTLE);
-
- dev->address = addr; /* New device address now */
- bus->devices[addr] = dev;
-
/* Assume 100mA bus powered for now. Changed when configured. */
dev->power = USB_MIN_POWER;
dev->self_powered = 0;