[PATCH] usb_interface power state

This updates the handling of power state for USB interfaces.

  - Formalizes an existing invariant:  interface "power state" is a boolean:
    ON when I/O is allowed, and FREEZE otherwise.  It does so by defining
    some inlined helpers, then using them.

  - Adds a useful invariant:  the only interfaces marked active are those
    bound to non-suspended drivers.  Later patches build on this invariant.

  - Simplifies the interface driver API (and removes some error paths) by
    removing the requirement that they record power state changes during
    suspend and resume callbacks.  Now usbcore does that.

A few drivers were simplified to address that last change.

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

 drivers/usb/core/hub.c       |   33 +++++++++------------
 drivers/usb/core/message.c   |    1
 drivers/usb/core/usb.c       |   65 +++++++++++++++++++++++++++++++++----------
 drivers/usb/core/usb.h       |   18 +++++++++++
 drivers/usb/input/hid-core.c |    2 -
 drivers/usb/misc/usbtest.c   |   10 ------
 drivers/usb/net/pegasus.c    |    2 -
 drivers/usb/net/usbnet.c     |    2 -
 8 files changed, 85 insertions(+), 48 deletions(-)
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index c3e2024..61341d2 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -1624,7 +1624,7 @@
 			struct usb_driver	*driver;
 
 			intf = udev->actconfig->interface[i];
-			if (state.event <= intf->dev.power.power_state.event)
+			if (!is_active(intf))
 				continue;
 			if (!intf->dev.driver)
 				continue;
@@ -1632,11 +1632,12 @@
 
 			if (driver->suspend) {
 				status = driver->suspend(intf, state);
-				if (intf->dev.power.power_state.event != state.event
-						|| status)
+				if (status == 0)
+					mark_quiesced(intf);
+				else
 					dev_err(&intf->dev,
-						"suspend %d fail, code %d\n",
-						state.event, status);
+						"suspend error %d\n",
+						status);
 			}
 
 			/* only drivers with suspend() can ever resume();
@@ -1787,7 +1788,7 @@
 			struct usb_driver	*driver;
 
 			intf = udev->actconfig->interface[i];
-			if (intf->dev.power.power_state.event == PM_EVENT_ON)
+			if (is_active(intf))
 				continue;
 			if (!intf->dev.driver) {
 				/* FIXME maybe force to alt 0 */
@@ -1800,12 +1801,14 @@
 				continue;
 
 			/* can we do better than just logging errors? */
+			mark_active(intf);
 			status = driver->resume(intf);
-			if (intf->dev.power.power_state.event != PM_EVENT_ON
-					|| status)
+			if (status < 0) {
+				mark_quiesced(intf);
 				dev_dbg(&intf->dev,
-					"resume fail, state %d code %d\n",
-					intf->dev.power.power_state.event, status);
+					"resume error %d\n",
+					status);
+			}
 		}
 		status = 0;
 
@@ -1952,7 +1955,7 @@
 	return status;
 }
 
-static int hub_suspend(struct usb_interface *intf, pm_message_t state)
+static int hub_suspend(struct usb_interface *intf, pm_message_t msg)
 {
 	struct usb_hub		*hub = usb_get_intfdata (intf);
 	struct usb_device	*hdev = hub->hdev;
@@ -1970,14 +1973,13 @@
 		if (!udev)
 			continue;
 		down(&udev->serialize);
-		status = __usb_suspend_device(udev, port1, state);
+		status = __usb_suspend_device(udev, port1, msg);
 		up(&udev->serialize);
 		if (status < 0)
 			dev_dbg(&intf->dev, "suspend port %d --> %d\n",
 				port1, status);
 	}
 
-	intf->dev.power.power_state = state;
 	return 0;
 }
 
@@ -1988,9 +1990,6 @@
 	unsigned		port1;
 	int			status;
 
-	if (intf->dev.power.power_state.event == PM_EVENT_ON)
-		return 0;
-
 	for (port1 = 1; port1 <= hdev->maxchild; port1++) {
 		struct usb_device	*udev;
 		u16			portstat, portchange;
@@ -2024,8 +2023,6 @@
 		}
 		up(&udev->serialize);
 	}
-	intf->dev.power.power_state = PMSG_ON;
-
 	hub->resume_root_hub = 0;
 	hub_activate(hub);
 	return 0;