summaryrefslogtreecommitdiff
path: root/sys/dev/usb/usb_subr.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/usb/usb_subr.c')
-rw-r--r--sys/dev/usb/usb_subr.c40
1 files changed, 38 insertions, 2 deletions
diff --git a/sys/dev/usb/usb_subr.c b/sys/dev/usb/usb_subr.c
index c251f8cd900..6f485ffa0c7 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.30 2004/11/02 21:28:55 dlg Exp $ */
+/* $OpenBSD: usb_subr.c,v 1.31 2004/11/08 22:01:02 dlg 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 $ */
@@ -87,6 +87,8 @@ Static int usbd_submatch(device_ptr_t, struct cfdata *cf, void *);
Static int usbd_print(void *aux, const char *pnp);
Static int usbd_submatch(device_ptr_t, void *, void *);
#endif
+Static usbd_status usbd_new_device2(device_ptr_t, usbd_bus_handle, int, int,
+ int, struct usbd_port *);
Static void usbd_free_iface_data(usbd_device_handle dev, int ifcno);
Static void usbd_kill_pipe(usbd_pipe_handle);
Static usbd_status usbd_probe_and_attach(device_ptr_t parent,
@@ -132,6 +134,7 @@ Static const char * const usbd_error_strs[] = {
"SHORT_XFER",
"STALLED",
"INTERRUPTED",
+ "NEED_RESET",
"XXX",
};
@@ -918,6 +921,13 @@ usbd_probe_and_attach(device_ptr_t parent, usbd_device_handle dev,
uaa.ifaceno = ifaces[i]->idesc->bInterfaceNumber;
dv = USB_DO_ATTACH(dev, bdev, parent, &uaa, usbd_print,
usbd_submatch);
+ if (dev->address == USB_START_ADDR) {
+#if defined(__FreeBSD__)
+ device_delete_child(parent, bdev);
+#endif
+ return (USBD_NEED_RESET);
+ }
+
if (dv != NULL) {
dev->subdevs[found++] = dv;
dev->subdevs[found] = 0;
@@ -987,7 +997,7 @@ usbd_probe_and_attach(device_ptr_t parent, usbd_device_handle dev,
* and attach a driver.
*/
usbd_status
-usbd_new_device(device_ptr_t parent, usbd_bus_handle bus, int depth,
+usbd_new_device2(device_ptr_t parent, usbd_bus_handle bus, int depth,
int speed, int port, struct usbd_port *up)
{
usbd_device_handle dev;
@@ -1132,6 +1142,11 @@ usbd_new_device(device_ptr_t parent, usbd_bus_handle bus, int depth,
err = usbd_probe_and_attach(parent, dev, port, addr);
if (err) {
+ if (err == USBD_NEED_RESET) {
+ DPRINTF(("usbd_new_device2: device needs reset\n"));
+ /* must set address back to what it was */
+ dev->address = addr;
+ }
usbd_remove_device(dev, up);
return (err);
}
@@ -1140,6 +1155,27 @@ usbd_new_device(device_ptr_t parent, usbd_bus_handle bus, int depth,
}
usbd_status
+usbd_new_device(device_ptr_t parent, usbd_bus_handle bus, int depth,
+ int speed, int ports, struct usbd_port *up)
+{
+ int retry = 0;
+ usbd_status err;
+
+ do {
+ if (retry > 0)
+ DPRINTF(("usbd_new_device: re-enumerating device\n"));
+ err = usbd_new_device2(parent, bus, depth, speed, ports, up);
+ } while ((err == USBD_NEED_RESET) && (retry++ < 5));
+
+ if (retry == 5) {
+ DPRINTF(("usbd_new_device: giving up after 5 tries\n"));
+ return (USBD_NOT_CONFIGURED);
+ }
+
+ return (err);
+}
+
+usbd_status
usbd_reload_device_desc(usbd_device_handle dev)
{
usbd_status err;