Skip to content

Commit

Permalink
USB: put claimed interfaces in the "suspended" state
Browse files Browse the repository at this point in the history
This patch (as1370) fixes a bug in the USB runtime power management
code.  When a driver claims an interface, it doesn't expect to need to
call usb_autopm_get_interface() or usb_autopm_put_interface() for
runtime PM to work.  Runtime PM can be controlled by the driver's
primary interface; the additional interfaces it claims shouldn't
interfere.  As things stand, the claimed interfaces will prevent the
device from autosuspending.

To fix this problem, the patch sets interfaces to the suspended state
when they are claimed.

Also, although in theory this shouldn't matter, the patch changes the
suspend code so that interfaces are suspended in reverse order from
detection and resuming.  This is how the PM core works, and we ought
to use the same approach.

Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
Debugged-and-tested-by: Dominik Brodowski <linux@dominikbrodowski.net>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
  • Loading branch information
Alan Stern authored and Greg Kroah-Hartman committed Apr 22, 2010
1 parent 0e5f231 commit 571dc79
Showing 1 changed file with 7 additions and 6 deletions.
13 changes: 7 additions & 6 deletions drivers/usb/core/driver.c
Original file line number Diff line number Diff line change
Expand Up @@ -301,7 +301,7 @@ static int usb_probe_interface(struct device *dev)

intf->condition = USB_INTERFACE_BINDING;

/* Bound interfaces are initially active. They are
/* Probed interfaces are initially active. They are
* runtime-PM-enabled only if the driver has autosuspend support.
* They are sensitive to their children's power states.
*/
Expand Down Expand Up @@ -437,11 +437,11 @@ int usb_driver_claim_interface(struct usb_driver *driver,

iface->condition = USB_INTERFACE_BOUND;

/* Bound interfaces are initially active. They are
/* Claimed interfaces are initially inactive (suspended). They are
* runtime-PM-enabled only if the driver has autosuspend support.
* They are sensitive to their children's power states.
*/
pm_runtime_set_active(dev);
pm_runtime_set_suspended(dev);
pm_suspend_ignore_children(dev, false);
if (driver->supports_autosuspend)
pm_runtime_enable(dev);
Expand Down Expand Up @@ -1170,7 +1170,7 @@ static int usb_resume_interface(struct usb_device *udev,
static int usb_suspend_both(struct usb_device *udev, pm_message_t msg)
{
int status = 0;
int i = 0;
int i = 0, n = 0;
struct usb_interface *intf;

if (udev->state == USB_STATE_NOTATTACHED ||
Expand All @@ -1179,7 +1179,8 @@ static int usb_suspend_both(struct usb_device *udev, pm_message_t msg)

/* Suspend all the interfaces and then udev itself */
if (udev->actconfig) {
for (; i < udev->actconfig->desc.bNumInterfaces; i++) {
n = udev->actconfig->desc.bNumInterfaces;
for (i = n - 1; i >= 0; --i) {
intf = udev->actconfig->interface[i];
status = usb_suspend_interface(udev, intf, msg);
if (status != 0)
Expand All @@ -1192,7 +1193,7 @@ static int usb_suspend_both(struct usb_device *udev, pm_message_t msg)
/* If the suspend failed, resume interfaces that did get suspended */
if (status != 0) {
msg.event ^= (PM_EVENT_SUSPEND | PM_EVENT_RESUME);
while (--i >= 0) {
while (++i < n) {
intf = udev->actconfig->interface[i];
usb_resume_interface(udev, intf, msg, 0);
}
Expand Down

0 comments on commit 571dc79

Please sign in to comment.