Greg:

This patch (as717) gets rid of the recursion we've always had in the 
suspend and resume routines.  Now suspending a hub won't automatically 
suspend all the child devices first, and resuming a hub won't 
automatically resume all the child devices afterward.

This is how other parts of the kernel operate, and the recursion isn't 
needed.  After all the Power Management core does its own recursion 
through the device tree when going into or out of a system sleep mode.

One smidgeon of recursion remains: When a remote wakeup request comes in, 
the code still does resume all the interfaces along with the device.  If 
we didn't, remote wakeup would be almost useless.

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
@@ -1036,6 +1036,23 @@ static int resume_interface(struct usb_i
        return 0;
 }
 
+/* Caller has locked udev */
+void usb_resume_both(struct usb_device *udev)
+{
+       int     i;
+
+       if (resume_device(udev) == 0 && udev->actconfig) {
+               for (i = 0; i < udev->actconfig->desc.bNumInterfaces; i++) {
+                       struct usb_interface *intf =
+                                       udev->actconfig->interface[i];
+
+                       down(&intf->dev.sem);
+                       resume_interface(intf);
+                       up(&intf->dev.sem);
+               }
+       }
+}
+
 static int usb_core_suspend(struct device *dev, pm_message_t msg)
 {
        int     status;
Index: usb-2.6/drivers/usb/core/hub.c
===================================================================
--- usb-2.6.orig/drivers/usb/core/hub.c
+++ usb-2.6/drivers/usb/core/hub.c
@@ -1658,9 +1658,6 @@ static int finish_port_resume(struct usb
                        "gone after usb resume? status %d\n",
                        status);
        else if (udev->actconfig) {
-               unsigned        i;
-               int             (*resume)(struct device *);
-
                le16_to_cpus(&devstatus);
                if ((devstatus & (1 << USB_DEVICE_REMOTE_WAKEUP))
                                && udev->parent) {
@@ -1671,24 +1668,9 @@ static int finish_port_resume(struct usb
                                        USB_DEVICE_REMOTE_WAKEUP, 0,
                                        NULL, 0,
                                        USB_CTRL_SET_TIMEOUT);
-                       if (status) {
+                       if (status)
                                dev_dbg(&udev->dev, "disable remote "
                                        "wakeup, status %d\n", status);
-                               status = 0;
-                       }
-               }
-
-               /* resume interface drivers; if this is a hub, it
-                * may have a child resume event to deal with soon
-                */
-               resume = udev->dev.bus->resume;
-               for (i = 0; i < udev->actconfig->desc.bNumInterfaces; i++) {
-                       struct device *dev =
-                                       &udev->actconfig->interface[i]->dev;
-
-                       down(&dev->sem);
-                       (void) resume(dev);
-                       up(&dev->sem);
                }
                status = 0;
 
@@ -1743,6 +1725,9 @@ hub_port_resume(struct usb_hub *hub, int
                                "port %d status %04x.%04x after resume, %d\n",
                                port1, portchange, devstatus, status);
                } else {
+                       if (portchange & USB_PORT_STAT_C_SUSPEND)
+                               clear_port_feature(hub->hdev, port1,
+                                               USB_PORT_FEAT_C_SUSPEND);
                        /* TRSMRCY = 10 msec */
                        msleep(10);
                        if (udev)
@@ -1821,6 +1806,9 @@ static int remote_wakeup(struct usb_devi
                msleep(10);
                status = finish_port_resume(udev);
        }
+
+       if (status == 0)
+               usb_resume_both(udev);
        usb_unlock_device(udev);
 #endif
        return status;
@@ -1892,51 +1880,8 @@ static int hub_resume(struct usb_interfa
                }
        }
 
+       /* tell khubd to look for changes on this hub */
        hub_activate(hub);
-
-       /* REVISIT:  this recursion probably shouldn't exist.  Remove
-        * this code sometime, after retesting with different root and
-        * external hubs.
-        */
-#ifdef CONFIG_USB_SUSPEND
-       {
-       unsigned                port1;
-
-       for (port1 = 1; port1 <= hdev->maxchild; port1++) {
-               struct usb_device       *udev;
-               u16                     portstat, portchange;
-
-               udev = hdev->children [port1-1];
-               status = hub_port_status(hub, port1, &portstat, &portchange);
-               if (status == 0) {
-                       if (portchange & USB_PORT_STAT_C_SUSPEND) {
-                               clear_port_feature(hdev, port1,
-                                       USB_PORT_FEAT_C_SUSPEND);
-                               portchange &= ~USB_PORT_STAT_C_SUSPEND;
-                       }
-
-                       /* let khubd handle disconnects etc */
-                       if (portchange)
-                               continue;
-               }
-
-               if (!udev || status < 0)
-                       continue;
-               usb_lock_device(udev);
-               if (portstat & USB_PORT_STAT_SUSPEND)
-                       status = hub_port_resume(hub, port1, udev);
-               else {
-                       status = finish_port_resume(udev);
-                       if (status < 0) {
-                               dev_dbg(&intf->dev, "resume port %d --> %d\n",
-                                       port1, status);
-                               hub_port_logical_disconnect(hub, port1);
-                       }
-               }
-               usb_unlock_device(udev);
-       }
-       }
-#endif
        return 0;
 }
 
@@ -2593,17 +2538,6 @@ static void hub_events(void)
                usb_get_intf(intf);
                spin_unlock_irq(&hub_event_lock);
 
-               /* Is this is a root hub wanting to reactivate the downstream
-                * ports?  If so, be sure the interface resumes even if its
-                * stub "device" node was never suspended.
-                */
-               if (i) {
-                       dpm_runtime_resume(&hdev->dev);
-                       dpm_runtime_resume(&intf->dev);
-                       usb_put_intf(intf);
-                       continue;
-               }
-
                /* Lock the device, then check to see if we were
                 * disconnected while waiting for the lock to succeed. */
                if (locktree(hdev) < 0) {
@@ -2620,6 +2554,13 @@ static void hub_events(void)
                        goto loop;
                }
 
+               /* Is this is a root hub wanting to reactivate the downstream
+                * ports?  If so, be sure the interface resumes even if its
+                * stub "device" node was never suspended.
+                */
+               if (i)
+                       usb_resume_both(hdev);
+
                /* If this is an inactive or suspended hub, do nothing */
                if (hub->quiescing)
                        goto loop;
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
@@ -27,6 +27,7 @@ extern void usb_major_cleanup(void);
 extern int usb_host_init(void);
 extern void usb_host_cleanup(void);
 
+extern void 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);
 




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

Reply via email to