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); } }