summaryrefslogtreecommitdiffstats
path: root/drivers/usb/core/driver.c
diff options
context:
space:
mode:
authorAlan Stern2006-07-02 04:13:04 +0200
committerGreg Kroah-Hartman2006-09-27 20:58:50 +0200
commit114b368c07964caa3f4e1fa575b16e87fa11936c (patch)
tree74500e47040be3bf4923eebd60404fc7b62004a9 /drivers/usb/core/driver.c
parentusbcore: set device and power states properly (diff)
downloadkernel-qcow2-linux-114b368c07964caa3f4e1fa575b16e87fa11936c.tar.gz
kernel-qcow2-linux-114b368c07964caa3f4e1fa575b16e87fa11936c.tar.xz
kernel-qcow2-linux-114b368c07964caa3f4e1fa575b16e87fa11936c.zip
usbcore: fix up device and power state tests
This patch (as734) rationalizes the various tests of device state and power states. There are duplications and mistaken tests in several places. Perhaps the most interesting challenge is where the hub driver tests to see that all the child devices are suspended before allowing itself to be suspended. When CONFIG_USB_SUSPEND is set the test is straightforward, since we expect that the children _will_ be suspended. But when CONFIG_USB_SUSPEND isn't set, it's not so clear what should be done. The code compromises by checking the child's power.power_state.event field. Signed-off-by: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb/core/driver.c')
-rw-r--r--drivers/usb/core/driver.c40
1 files changed, 19 insertions, 21 deletions
diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c
index 92ecc4eb1e88..affbfb53eb5e 100644
--- a/drivers/usb/core/driver.c
+++ b/drivers/usb/core/driver.c
@@ -757,11 +757,13 @@ static int suspend_device(struct usb_device *udev, pm_message_t msg)
struct usb_device_driver *udriver;
int status = 0;
+ if (udev->state == USB_STATE_NOTATTACHED ||
+ udev->state == USB_STATE_SUSPENDED)
+ goto done;
+
if (udev->dev.driver == NULL)
goto done;
udriver = to_usb_device_driver(udev->dev.driver);
- if (udev->dev.power.power_state.event == msg.event)
- goto done;
status = udriver->suspend(udev, msg);
done:
@@ -776,14 +778,13 @@ static int resume_device(struct usb_device *udev)
struct usb_device_driver *udriver;
int status = 0;
- if (udev->dev.power.power_state.event == PM_EVENT_ON)
+ if (udev->state == USB_STATE_NOTATTACHED ||
+ udev->state != USB_STATE_SUSPENDED)
goto done;
if (udev->dev.driver == NULL)
goto done;
udriver = to_usb_device_driver(udev->dev.driver);
- if (udev->state == USB_STATE_NOTATTACHED)
- goto done;
status = udriver->resume(udev);
done:
@@ -798,14 +799,14 @@ static int suspend_interface(struct usb_interface *intf, pm_message_t msg)
struct usb_driver *driver;
int status = 0;
- if (intf->dev.driver == NULL)
+ /* with no hardware, USB interfaces only use FREEZE and ON states */
+ if (interface_to_usbdev(intf)->state == USB_STATE_NOTATTACHED ||
+ !is_active(intf))
goto done;
- driver = to_usb_driver(intf->dev.driver);
-
- /* with no hardware, USB interfaces only use FREEZE and ON states */
- if (!is_active(intf))
+ if (intf->dev.driver == NULL)
goto done;
+ driver = to_usb_driver(intf->dev.driver);
if (driver->suspend && driver->resume) {
status = driver->suspend(intf, msg);
@@ -831,25 +832,16 @@ done:
static int resume_interface(struct usb_interface *intf)
{
struct usb_driver *driver;
- struct usb_device *udev;
int status = 0;
- if (intf->dev.power.power_state.event == PM_EVENT_ON)
+ if (interface_to_usbdev(intf)->state == USB_STATE_NOTATTACHED ||
+ is_active(intf))
goto done;
if (intf->dev.driver == NULL)
goto done;
-
driver = to_usb_driver(intf->dev.driver);
- udev = interface_to_usbdev(intf);
- if (udev->state == USB_STATE_NOTATTACHED)
- goto done;
-
- /* 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)
- */
if (driver->resume) {
status = driver->resume(intf);
if (status)
@@ -904,6 +896,12 @@ int usb_resume_both(struct usb_device *udev)
int i;
struct usb_interface *intf;
+ /* Can't resume if the parent is suspended */
+ if (udev->parent && udev->parent->state == USB_STATE_SUSPENDED) {
+ dev_warn(&udev->dev, "can't resume; parent is suspended\n");
+ return -EHOSTUNREACH;
+ }
+
status = resume_device(udev);
if (status == 0 && udev->actconfig) {
for (i = 0; i < udev->actconfig->desc.bNumInterfaces; i++) {