diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c index 92ecc4eb1e88ce44b499f2acda20675e90ac73f7..affbfb53eb5e9d7d7a01844df5981ea63181c894 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 @@ static int suspend_interface(struct usb_interface *intf, pm_message_t msg) 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++) { diff --git a/drivers/usb/core/generic.c b/drivers/usb/core/generic.c index b6dacd7551d2e0d843a3d6998bf67a2a4b838ba6..5358e656477ca7296185db938937949715624da9 100644 --- a/drivers/usb/core/generic.c +++ b/drivers/usb/core/generic.c @@ -195,9 +195,6 @@ static int generic_suspend(struct usb_device *udev, pm_message_t msg) static int generic_resume(struct usb_device *udev) { - if (udev->state == USB_STATE_NOTATTACHED) - return 0; - return usb_port_resume(udev); } diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 7af53db4d76ff6e827bb93e60e9aaa593fee9e22..a310c7cede99a13772e19ad283dc69b48b4c5e84 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -1556,26 +1556,6 @@ static int __usb_port_suspend (struct usb_device *udev, int port1) if (port1 < 0) return port1; - if (udev->state == USB_STATE_SUSPENDED - || udev->state == USB_STATE_NOTATTACHED) { - return 0; - } - - /* all interfaces must already be suspended */ - if (udev->actconfig) { - int i; - - for (i = 0; i < udev->actconfig->desc.bNumInterfaces; i++) { - struct usb_interface *intf; - - intf = udev->actconfig->interface[i]; - if (is_active(intf)) { - dev_dbg(&intf->dev, "nyet suspended\n"); - return -EBUSY; - } - } - } - /* we change the device's upstream USB link, * but root hubs have no upstream USB link. */ @@ -1614,8 +1594,6 @@ static int __usb_port_suspend (struct usb_device *udev, int port1) int usb_port_suspend(struct usb_device *udev) { #ifdef CONFIG_USB_SUSPEND - if (udev->state == USB_STATE_NOTATTACHED) - return -ENODEV; return __usb_port_suspend(udev, udev->portnum); #else return 0; @@ -1761,24 +1739,17 @@ hub_port_resume(struct usb_hub *hub, int port1, struct usb_device *udev) */ int usb_port_resume(struct usb_device *udev) { - int status; - - if (udev->state == USB_STATE_NOTATTACHED) - return -ENODEV; + int status = 0; /* we change the device's upstream USB link, * but root hubs have no upstream USB link. */ if (udev->parent) { #ifdef CONFIG_USB_SUSPEND - if (udev->state == USB_STATE_SUSPENDED) { - // NOTE swsusp may bork us, device state being wrong... - // NOTE this fails if parent is also suspended... - status = hub_port_resume(hdev_to_hub(udev->parent), - udev->portnum, udev); - } else + // NOTE this fails if parent is also suspended... + status = hub_port_resume(hdev_to_hub(udev->parent), + udev->portnum, udev); #endif - status = 0; } else status = finish_port_resume(udev); if (status < 0) @@ -1821,12 +1792,14 @@ static int hub_suspend(struct usb_interface *intf, pm_message_t msg) struct usb_device *udev; udev = hdev->children [port1-1]; - if (udev && (udev->dev.power.power_state.event - == PM_EVENT_ON + if (udev && msg.event == PM_EVENT_SUSPEND && #ifdef CONFIG_USB_SUSPEND - || udev->state != USB_STATE_SUSPENDED + udev->state != USB_STATE_SUSPENDED +#else + udev->dev.power.power_state.event + == PM_EVENT_ON #endif - )) { + ) { dev_dbg(&intf->dev, "port %d nyet suspended\n", port1); return -EBUSY; }