aboutsummaryrefslogtreecommitdiff
path: root/drivers/usb/core/driver.c
diff options
context:
space:
mode:
authorAlan Stern <stern@rowland.harvard.edu>2006-07-01 22:11:02 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2006-09-27 11:58:50 -0700
commita8e7c5653562f88c0f5f53eac0a890c012655789 (patch)
treeba227138d408fdc73ccfc62ad8f75d912ece4baf /drivers/usb/core/driver.c
parent1cc8a25d5b680ff656927ffa9b66fae6b415b1d3 (diff)
usbcore: resume device resume recursion
This patch (as717b) removes the existing recursion in hub resume code: Resuming a hub will no longer automatically resume the devices attached to the hub. At the same time, it adds one level of recursion: Suspending a USB device will automatically suspend all the device's interfaces. Failure at an intermediate stage will cause all the already-suspended interfaces to be resumed. Attempts to suspend or resume an interface by itself will do nothing, although they won't return an error. Thus the regular system-suspend and system-resume procedures should continue to work as before; only runtime PM will be affected. The patch also removes the code that tests state of the interfaces before suspending a device. It's no longer needed, since everything gets suspended together. Signed-off-by: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb/core/driver.c')
-rw-r--r--drivers/usb/core/driver.c63
1 files changed, 55 insertions, 8 deletions
diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c
index b0db1583c52..eefc98584ea 100644
--- a/drivers/usb/core/driver.c
+++ b/drivers/usb/core/driver.c
@@ -783,7 +783,7 @@ static int resume_device(struct usb_device *udev)
return udriver->resume(udev);
}
-/* Caller has locked intf */
+/* Caller has locked intf's usb_device */
static int suspend_interface(struct usb_interface *intf, pm_message_t msg)
{
struct usb_driver *driver;
@@ -815,7 +815,7 @@ static int suspend_interface(struct usb_interface *intf, pm_message_t msg)
return status;
}
-/* Caller has locked intf */
+/* Caller has locked intf's usb_device */
static int resume_interface(struct usb_interface *intf)
{
struct usb_driver *driver;
@@ -856,14 +856,59 @@ static int resume_interface(struct usb_interface *intf)
return 0;
}
+/* Caller has locked udev */
+int usb_suspend_both(struct usb_device *udev, pm_message_t msg)
+{
+ int status = 0;
+ int i = 0;
+ struct usb_interface *intf;
+
+ if (udev->actconfig) {
+ for (; i < udev->actconfig->desc.bNumInterfaces; i++) {
+ intf = udev->actconfig->interface[i];
+ status = suspend_interface(intf, msg);
+ if (status != 0)
+ break;
+ }
+ }
+ if (status == 0)
+ status = suspend_device(udev, msg);
+
+ /* If the suspend failed, resume interfaces that did get suspended */
+ if (status != 0) {
+ while (--i >= 0) {
+ intf = udev->actconfig->interface[i];
+ resume_interface(intf);
+ }
+ }
+ return status;
+}
+
+/* Caller has locked udev */
+int usb_resume_both(struct usb_device *udev)
+{
+ int status;
+ int i;
+ struct usb_interface *intf;
+
+ status = resume_device(udev);
+ if (status == 0 && udev->actconfig) {
+ for (i = 0; i < udev->actconfig->desc.bNumInterfaces; i++) {
+ intf = udev->actconfig->interface[i];
+ resume_interface(intf);
+ }
+ }
+ return status;
+}
+
static int usb_suspend(struct device *dev, pm_message_t message)
{
int status;
if (is_usb_device(dev))
- status = suspend_device(to_usb_device(dev), message);
+ status = usb_suspend_both(to_usb_device(dev), message);
else
- status = suspend_interface(to_usb_interface(dev), message);
+ status = 0;
return status;
}
@@ -871,10 +916,12 @@ static int usb_resume(struct device *dev)
{
int status;
- if (is_usb_device(dev))
- status = resume_device(to_usb_device(dev));
- else
- status = resume_interface(to_usb_interface(dev));
+ if (is_usb_device(dev)) {
+ status = usb_resume_both(to_usb_device(dev));
+
+ /* Rebind drivers that had no suspend method? */
+ } else
+ status = 0;
return status;
}