usbcore: split suspend/resume for device and interfaces

This patch (as716b) splits up the core suspend and resume routines into
two parts each: one for handling devices and one for handling
interfaces.  The behavior of the parts should be the same as in the old
unified code.


Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c
index a62de0a..b0db158 100644
--- a/drivers/usb/core/driver.c
+++ b/drivers/usb/core/driver.c
@@ -751,81 +751,89 @@
 
 #ifdef CONFIG_PM
 
-static int usb_suspend(struct device *dev, pm_message_t message)
+/* Caller has locked udev */
+static int suspend_device(struct usb_device *udev, pm_message_t msg)
 {
-	struct usb_device		*udev;
 	struct usb_device_driver	*udriver;
-	struct usb_interface		*intf;
-	struct usb_driver		*driver;
-	int				status;
 
-	if (is_usb_device(dev)) {
-		if (dev->driver == NULL)
-			return 0;
-		udev = to_usb_device(dev);
-		udriver = to_usb_device_driver(dev->driver);
-		if (dev->power.power_state.event == message.event)
-			return 0;
-		return udriver->suspend(udev, message);
-	}
+	if (udev->dev.driver == NULL)
+		return 0;
+	udriver = to_usb_device_driver(udev->dev.driver);
+	if (udev->dev.power.power_state.event == msg.event)
+		return 0;
+	return udriver->suspend(udev, msg);
+}
 
-	if (dev->driver == NULL)
+/* Caller has locked udev */
+static int resume_device(struct usb_device *udev)
+{
+	struct usb_device_driver	*udriver;
+
+	if (udev->dev.power.power_state.event == PM_EVENT_ON)
 		return 0;
 
-	intf = to_usb_interface(dev);
-	driver = to_usb_driver(dev->driver);
+	/* mark things as "on" immediately, no matter what errors crop up */
+	udev->dev.power.power_state.event = PM_EVENT_ON;
+
+	if (udev->dev.driver == NULL)
+		return 0;
+	udriver = to_usb_device_driver(udev->dev.driver);
+	if (udev->state == USB_STATE_NOTATTACHED)
+		return 0;
+	return udriver->resume(udev);
+}
+
+/* Caller has locked intf */
+static int suspend_interface(struct usb_interface *intf, pm_message_t msg)
+{
+	struct usb_driver	*driver;
+	int			status;
+
+	if (intf->dev.driver == NULL)
+		return 0;
+
+	driver = to_usb_driver(intf->dev.driver);
 
 	/* with no hardware, USB interfaces only use FREEZE and ON states */
 	if (!is_active(intf))
 		return 0;
 
 	if (driver->suspend && driver->resume) {
-		status = driver->suspend(intf, message);
+		status = driver->suspend(intf, msg);
 		if (status)
-			dev_err(dev, "%s error %d\n", "suspend", status);
+			dev_err(&intf->dev, "%s error %d\n",
+					"suspend", status);
 		else
 			mark_quiesced(intf);
 	} else {
 		// FIXME else if there's no suspend method, disconnect...
-		dev_warn(dev, "no suspend for driver %s?\n", driver->name);
+		dev_warn(&intf->dev, "no suspend for driver %s?\n",
+				driver->name);
 		mark_quiesced(intf);
 		status = 0;
 	}
 	return status;
 }
 
-static int usb_resume(struct device *dev)
+/* Caller has locked intf */
+static int resume_interface(struct usb_interface *intf)
 {
-	struct usb_device		*udev;
-	struct usb_device_driver	*udriver;
-	struct usb_interface		*intf;
-	struct usb_driver		*driver;
-	int				status;
+	struct usb_driver	*driver;
+	struct usb_device	*udev;
+	int			status;
 
-	if (dev->power.power_state.event == PM_EVENT_ON)
+	if (intf->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;
+	intf->dev.power.power_state.event = PM_EVENT_ON;
 
-	/* devices resume through their hubs */
-	if (is_usb_device(dev)) {
-		if (dev->driver == NULL)
-			return 0;
-		udev = to_usb_device(dev);
-		udriver = to_usb_device_driver(dev->driver);
-		if (udev->state == USB_STATE_NOTATTACHED)
-			return 0;
-		return udriver->resume(udev);
-	}
-
-	if (dev->driver == NULL) {
-		dev->power.power_state.event = PM_EVENT_FREEZE;
+	if (intf->dev.driver == NULL) {
+		intf->dev.power.power_state.event = PM_EVENT_FREEZE;
 		return 0;
 	}
 
-	intf = to_usb_interface(dev);
-	driver = to_usb_driver(dev->driver);
+	driver = to_usb_driver(intf->dev.driver);
 
 	udev = interface_to_usbdev(intf);
 	if (udev->state == USB_STATE_NOTATTACHED)
@@ -838,14 +846,38 @@
 	if (driver->resume) {
 		status = driver->resume(intf);
 		if (status) {
-			dev_err(dev, "%s error %d\n", "resume", status);
+			dev_err(&intf->dev, "%s error %d\n",
+					"resume", status);
 			mark_quiesced(intf);
 		}
 	} else
-		dev_warn(dev, "no resume for driver %s?\n", driver->name);
+		dev_warn(&intf->dev, "no resume for driver %s?\n",
+				driver->name);
 	return 0;
 }
 
+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);
+	else
+		status = suspend_interface(to_usb_interface(dev), message);
+	return status;
+}
+
+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));
+	return status;
+}
+
 #endif /* CONFIG_PM */
 
 struct bus_type usb_bus_type = {