ChangeSet 1.1455.1.19, 2003/07/15 14:32:34-07:00, greg@kroah.com

[PATCH] USB: flush all in-flight urbs _before_ disconnect() is called.

This solves the module unload problem for some usb-serial drivers
(like visor.c and ftdi_sio.c), and makes usb drivers much simpler.


 drivers/usb/core/usb.c |   33 +++++++++++++++++++++++----------
 1 files changed, 23 insertions(+), 10 deletions(-)


diff -Nru a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c
--- a/drivers/usb/core/usb.c	Thu Jul 17 17:05:15 2003
+++ b/drivers/usb/core/usb.c	Thu Jul 17 17:05:15 2003
@@ -80,6 +80,23 @@
 
 static int usb_generic_driver_data;
 
+/* deallocate hcd/hardware state ... and nuke all pending urbs */
+static void nuke_urbs(struct usb_device *dev)
+{
+	void (*disable)(struct usb_device *, int);
+	int i;
+
+	if (!dev || !dev->bus || !dev->bus->op || !dev->bus->op->disable)
+		return;
+	dbg("nuking urbs assigned to %s", dev->dev.bus_id);
+
+	disable = dev->bus->op->disable;
+	for (i = 0; i < 15; i++) {
+		disable(dev, i);
+		disable(dev, USB_DIR_IN | i);
+	}
+}
+
 /* needs to be called with BKL held */
 int usb_device_probe(struct device *dev)
 {
@@ -116,6 +133,9 @@
 
 	down(&driver->serialize);
 
+	/* release all urbs for this device */
+	nuke_urbs(interface_to_usbdev(intf));
+
 	if (intf->driver && intf->driver->disconnect)
 		intf->driver->disconnect(intf);
 
@@ -896,6 +916,9 @@
 			usb_disconnect(child);
 	}
 
+	/* deallocate hcd/hardware state ... and nuke all pending urbs */
+	nuke_urbs(dev);
+
 	/* disconnect() drivers from interfaces (a key side effect) */
 	dev_dbg (&dev->dev, "unregistering interfaces\n");
 	if (dev->actconfig) {
@@ -905,16 +928,6 @@
 			/* remove this interface */
 			interface = &dev->actconfig->interface[i];
 			device_unregister(&interface->dev);
-		}
-	}
-
-	/* deallocate hcd/hardware state */
-	if (ops->disable) {
-		void	(*disable)(struct usb_device *, int) = ops->disable;
-
-		for (i = 0; i < 15; i++) {
-			disable (dev, i);
-			disable (dev, USB_DIR_IN | i);
 		}
 	}
 
