[PATCH] root hub changes (lesser half)

This patch collects various small updates related to root hubs, to shrink
later patches which build on them.

  - For root hub suspend/resume support:
     * Make the existing usb_hcd_resume_root_hub() routine respect pmcore
       locking, exporting and using the dpm_runtime_resume() method.
     * Add a new usb_hcd_suspend_root_hub() to pair with that routine.
       (Essential to make OHCI autosuspend behave again...)
     * HC_SUSPENDED by itself only refers to the root hub's downstream ports.
       So let HCDs see root hub URBs unless the parent device is suspended.

  - Remove an assertion we no longer need (and now, also don't want).

  - Generic suspend/resume updates to work better with swsusp.
     * Ignore the FREEZE vs SUSPEND distinction for hardware; trying to
       use it breaks the swsusp snapshots it's supposed to help (sigh).
     * On resume, mark devices as resumed right away, but then
       do nothing else if the device is marked NOTATTACHED.

These changes shouldn't be very noticable by themselves.

Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

 drivers/base/power/runtime.c |    1
 drivers/usb/core/hcd.c       |   64 ++++++++++++++++++++++++++++++++++++++-----
 drivers/usb/core/hcd.h       |    1
 drivers/usb/core/hub.c       |   45 ++++++++++++++++++++++++------
 drivers/usb/core/usb.c       |   20 +++++++++----
 drivers/usb/core/usb.h       |    1
 6 files changed, 111 insertions(+), 21 deletions(-)
diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c
index e89dbd4..2493e7d 100644
--- a/drivers/usb/core/usb.c
+++ b/drivers/usb/core/usb.c
@@ -1427,6 +1427,7 @@
 
 	/* USB devices enter SUSPEND state through their hubs, but can be
 	 * marked for FREEZE as soon as their children are already idled.
+	 * But those semantics are useless, so we equate the two (sigh).
 	 */
 	if (dev->driver == &usb_generic_driver) {
 		if (dev->power.power_state.event == message.event)
@@ -1435,10 +1436,6 @@
 		status = device_for_each_child(dev, NULL, verify_suspended);
 		if (status)
 			return status;
-		if (message.event == PM_EVENT_FREEZE) {
-			dev->power.power_state = message;
-			return 0;
-		}
  		return usb_suspend_device (to_usb_device(dev));
 	}
 
@@ -1471,14 +1468,22 @@
 {
 	struct usb_interface	*intf;
 	struct usb_driver	*driver;
+	struct usb_device	*udev;
 	int			status;
 
 	if (dev->power.power_state.event == PM_EVENT_ON)
 		return 0;
 
+	/* mark things as "on" immediately, no matter what errors crop up */
+	dev->power.power_state.event = PM_EVENT_ON;
+
 	/* devices resume through their hubs */
-	if (dev->driver == &usb_generic_driver)
+	if (dev->driver == &usb_generic_driver) {
+		udev = to_usb_device(dev);
+		if (udev->state == USB_STATE_NOTATTACHED)
+			return 0;
 		return usb_resume_device (to_usb_device(dev));
+	}
 
 	if ((dev->driver == NULL) ||
 	    (dev->driver_data == &usb_generic_driver_data))
@@ -1487,11 +1492,14 @@
 	intf = to_usb_interface(dev);
 	driver = to_usb_driver(dev->driver);
 
+	udev = interface_to_usbdev(intf);
+	if (udev->state == USB_STATE_NOTATTACHED)
+		return 0;
+
 	/* if driver was suspended, it has a resume method;
 	 * however, sysfs can wrongly mark things as suspended
 	 * (on the "no suspend method" FIXME path above)
 	 */
-	mark_active(intf);
 	if (driver->resume) {
 		status = driver->resume(intf);
 		if (status) {