[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(-)
This commit is contained in:
David Brownell
2005-09-13 19:56:33 -07:00
committed by Greg Kroah-Hartman
parent 7586269c0b
commit db69087437
8 changed files with 85 additions and 48 deletions

View File

@ -107,10 +107,19 @@ static int usb_probe_interface(struct device *dev)
id = usb_match_id (intf, driver->id_table);
if (id) {
dev_dbg (dev, "%s - got id\n", __FUNCTION__);
/* Interface "power state" doesn't correspond to any hardware
* state whatsoever. We use it to record when it's bound to
* a driver that may start I/0: it's not frozen/quiesced.
*/
mark_active(intf);
intf->condition = USB_INTERFACE_BINDING;
error = driver->probe (intf, id);
intf->condition = error ? USB_INTERFACE_UNBOUND :
USB_INTERFACE_BOUND;
if (error) {
mark_quiesced(intf);
intf->condition = USB_INTERFACE_UNBOUND;
} else
intf->condition = USB_INTERFACE_BOUND;
}
return error;
@ -136,6 +145,7 @@ static int usb_unbind_interface(struct device *dev)
0);
usb_set_intfdata(intf, NULL);
intf->condition = USB_INTERFACE_UNBOUND;
mark_quiesced(intf);
return 0;
}
@ -299,6 +309,7 @@ int usb_driver_claim_interface(struct usb_driver *driver,
dev->driver = &driver->driver;
usb_set_intfdata(iface, priv);
iface->condition = USB_INTERFACE_BOUND;
mark_active(iface);
/* if interface was already added, bind now; else let
* the future device_add() bind it, bypassing probe()
@ -345,6 +356,7 @@ void usb_driver_release_interface(struct usb_driver *driver,
dev->driver = NULL;
usb_set_intfdata(iface, NULL);
iface->condition = USB_INTERFACE_UNBOUND;
mark_quiesced(iface);
}
/**
@ -1404,8 +1416,9 @@ void usb_buffer_unmap_sg (struct usb_device *dev, unsigned pipe,
static int usb_generic_suspend(struct device *dev, pm_message_t message)
{
struct usb_interface *intf;
struct usb_driver *driver;
struct usb_interface *intf;
struct usb_driver *driver;
int status;
if (dev->driver == &usb_generic_driver)
return usb_suspend_device (to_usb_device(dev), message);
@ -1417,21 +1430,34 @@ static int usb_generic_suspend(struct device *dev, pm_message_t message)
intf = to_usb_interface(dev);
driver = to_usb_driver(dev->driver);
/* there's only one USB suspend state */
if (intf->dev.power.power_state.event)
/* with no hardware, USB interfaces only use FREEZE and ON states */
if (!is_active(intf))
return 0;
if (driver->suspend)
return driver->suspend(intf, message);
return 0;
if (driver->suspend && driver->resume) {
status = driver->suspend(intf, message);
if (status)
dev_err(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 %s?\n", "suspend");
status = 0;
}
return status;
}
static int usb_generic_resume(struct device *dev)
{
struct usb_interface *intf;
struct usb_driver *driver;
struct usb_interface *intf;
struct usb_driver *driver;
int status;
/* devices resume through their hub */
if (dev->power.power_state.event == PM_EVENT_ON)
return 0;
/* devices resume through their hubs */
if (dev->driver == &usb_generic_driver)
return usb_resume_device (to_usb_device(dev));
@ -1442,8 +1468,19 @@ static int usb_generic_resume(struct device *dev)
intf = to_usb_interface(dev);
driver = to_usb_driver(dev->driver);
if (driver->resume)
return driver->resume(intf);
/* 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) {
dev_err(dev, "%s error %d\n", "resume", status);
mark_quiesced(intf);
}
} else
dev_warn(dev, "no %s?\n", "resume");
return 0;
}