Greg:

This patch (as719) ties together the states of devices and their
interfaces: No longer is it possible to suspend one without also
suspending the other.  The states that are ruled out (some interfaces
suspended, entire device still awake) don't seem to be very useful, at
least not for now.

This may appear to be a step backward (compare with the earlier patch that
removed the recursion in the suspend/resume routines).  But it makes
sense, since devices and their interfaces are so tightly integrated.  
This is especially true for interface drivers that rely on remote wakeup
for notifications about interesting events while they are suspended --
remote wakeup won't operate unless the device itself is suspended.

Alan Stern



Signed-off-by: Alan Stern <[EMAIL PROTECTED]>

---

Index: usb-2.6/drivers/usb/core/driver.c
===================================================================
--- usb-2.6.orig/drivers/usb/core/driver.c
+++ usb-2.6/drivers/usb/core/driver.c
@@ -974,7 +974,7 @@ done:
        return status;
 }
 
-/* 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;
@@ -1007,7 +1007,7 @@ done:
        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;
@@ -1040,20 +1040,48 @@ done:
 }
 
 /* Caller has locked udev */
-void usb_resume_both(struct usb_device *udev)
+int usb_suspend_both(struct usb_device *udev, pm_message_t msg)
 {
-       int     i;
+       int                     status = 0;
+       int                     i = 0;
+       struct usb_interface    *intf;
 
-       if (resume_device(udev) == 0 && udev->actconfig) {
-               for (i = 0; i < udev->actconfig->desc.bNumInterfaces; i++) {
-                       struct usb_interface *intf =
-                                       udev->actconfig->interface[i];
+       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;
+}
 
-                       down(&intf->dev.sem);
+/* 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);
-                       up(&intf->dev.sem);
                }
        }
+       return status;
 }
 
 static int usb_core_suspend(struct device *dev, pm_message_t msg)
@@ -1061,9 +1089,9 @@ static int usb_core_suspend(struct devic
        int     status;
 
        if (is_usb_device(dev))
-               status = suspend_device(to_usb_device(dev), msg);
+               status = usb_suspend_both(to_usb_device(dev), msg);
        else
-               status = suspend_interface(to_usb_interface(dev), msg);
+               status = 0;
        return status;
 }
 
@@ -1071,13 +1099,12 @@ static int usb_core_resume(struct device
 {
        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;
 }
 
Index: usb-2.6/drivers/usb/core/usb.h
===================================================================
--- usb-2.6.orig/drivers/usb/core/usb.h
+++ usb-2.6/drivers/usb/core/usb.h
@@ -29,15 +29,17 @@ extern void usb_host_cleanup(void);
 
 #ifdef CONFIG_PM
 
-extern void usb_resume_both(struct usb_device *udev);
+extern int usb_suspend_both(struct usb_device *udev, pm_message_t msg);
+extern int usb_resume_both(struct usb_device *udev);
 extern int usb_port_suspend(struct usb_device *dev);
 extern int usb_port_resume(struct usb_device *dev);
 
 #else
 
-#define usb_resume_both(udev)  do {} while (0)
-#define usb_port_suspend(dev)  do {} while (0)
-#define usb_port_resume(dev)   do {} while (0)
+#define usb_suspend_both(udev, msg)    do {} while (0)
+#define usb_resume_both(udev)          do {} while (0)
+#define usb_port_suspend(dev)          do {} while (0)
+#define usb_port_resume(dev)           do {} while (0)
 
 #endif
 




_______________________________________________
[email protected]
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel

Reply via email to