]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/usb/core/driver.c
USB: Introduce usb_queue_reset() to do resets from atomic contexts
[linux-2.6-omap-h63xx.git] / drivers / usb / core / driver.c
index 23b3c7e79d4be231b23bf7a0ff27a31ed05fb52c..7e26fb3c275935c382cd642f9152e6b0b5cb17ef 100644 (file)
@@ -184,6 +184,20 @@ static int usb_unbind_device(struct device *dev)
        return 0;
 }
 
+/*
+ * Cancel any pending scheduled resets
+ *
+ * [see usb_queue_reset_device()]
+ *
+ * Called after unconfiguring / when releasing interfaces. See
+ * comments in __usb_queue_reset_device() regarding
+ * udev->reset_running.
+ */
+static void usb_cancel_queued_reset(struct usb_interface *iface)
+{
+       if (iface->reset_running == 0)
+               cancel_work_sync(&iface->reset_ws);
+}
 
 /* called from driver core with dev locked */
 static int usb_probe_interface(struct device *dev)
@@ -242,6 +256,7 @@ static int usb_probe_interface(struct device *dev)
                        mark_quiesced(intf);
                        intf->needs_remote_wakeup = 0;
                        intf->condition = USB_INTERFACE_UNBOUND;
+                       usb_cancel_queued_reset(intf);
                } else
                        intf->condition = USB_INTERFACE_BOUND;
 
@@ -272,6 +287,7 @@ static int usb_unbind_interface(struct device *dev)
                usb_disable_interface(udev, intf);
 
        driver->disconnect(intf);
+       usb_cancel_queued_reset(intf);
 
        /* Reset other interface state.
         * We cannot do a Set-Interface if the device is suspended or
@@ -380,8 +396,10 @@ void usb_driver_release_interface(struct usb_driver *driver,
        if (device_is_registered(dev)) {
                iface->condition = USB_INTERFACE_UNBINDING;
                device_release_driver(dev);
+       } else {
+               iface->condition = USB_INTERFACE_UNBOUND;
+               usb_cancel_queued_reset(iface);
        }
-
        dev->driver = NULL;
        usb_set_intfdata(iface, NULL);
 
@@ -942,7 +960,8 @@ static int usb_suspend_interface(struct usb_device *udev,
        if (udev->state == USB_STATE_NOTATTACHED || !is_active(intf))
                goto done;
 
-       if (intf->condition == USB_INTERFACE_UNBOUND)   /* This can't happen */
+       /* This can happen; see usb_driver_release_interface() */
+       if (intf->condition == USB_INTERFACE_UNBOUND)
                goto done;
        driver = to_usb_driver(intf->dev.driver);