Commit 7b8e4cb8 authored by Greg Kroah-Hartman's avatar Greg Kroah-Hartman

[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.
parent a1c9274c
...@@ -80,6 +80,23 @@ static struct device_driver usb_generic_driver = { ...@@ -80,6 +80,23 @@ static struct device_driver usb_generic_driver = {
static int usb_generic_driver_data; 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 */ /* needs to be called with BKL held */
int usb_device_probe(struct device *dev) int usb_device_probe(struct device *dev)
{ {
...@@ -116,6 +133,9 @@ int usb_device_remove(struct device *dev) ...@@ -116,6 +133,9 @@ int usb_device_remove(struct device *dev)
down(&driver->serialize); down(&driver->serialize);
/* release all urbs for this device */
nuke_urbs(interface_to_usbdev(intf));
if (intf->driver && intf->driver->disconnect) if (intf->driver && intf->driver->disconnect)
intf->driver->disconnect(intf); intf->driver->disconnect(intf);
...@@ -896,6 +916,9 @@ void usb_disconnect(struct usb_device **pdev) ...@@ -896,6 +916,9 @@ void usb_disconnect(struct usb_device **pdev)
usb_disconnect(child); usb_disconnect(child);
} }
/* deallocate hcd/hardware state ... and nuke all pending urbs */
nuke_urbs(dev);
/* disconnect() drivers from interfaces (a key side effect) */ /* disconnect() drivers from interfaces (a key side effect) */
dev_dbg (&dev->dev, "unregistering interfaces\n"); dev_dbg (&dev->dev, "unregistering interfaces\n");
if (dev->actconfig) { if (dev->actconfig) {
...@@ -908,16 +931,6 @@ void usb_disconnect(struct usb_device **pdev) ...@@ -908,16 +931,6 @@ void usb_disconnect(struct usb_device **pdev)
} }
} }
/* 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);
}
}
dev_dbg (&dev->dev, "unregistering device\n"); dev_dbg (&dev->dev, "unregistering device\n");
/* Free the device number and remove the /proc/bus/usb entry */ /* Free the device number and remove the /proc/bus/usb entry */
if (dev->devnum > 0) { if (dev->devnum > 0) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment