[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:
committed by
Greg Kroah-Hartman
parent
7586269c0b
commit
db69087437
@ -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;
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user