Commit 1493138a authored by Oliver Neukum's avatar Oliver Neukum Committed by Greg Kroah-Hartman

USB: code cleanup in suspend/resume path (3rd try)

Do the cleanup to avoid behaviorial parameters Linus
requested.
Signed-off-by: default avatarOliver Neukum <oneukum@suse.de>
Acked-by: default avatarAlan Stern <stern@rowland.harvard.edu>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent dcd6c922
...@@ -958,13 +958,8 @@ void usb_rebind_intf(struct usb_interface *intf) ...@@ -958,13 +958,8 @@ void usb_rebind_intf(struct usb_interface *intf)
int rc; int rc;
/* Delayed unbind of an existing driver */ /* Delayed unbind of an existing driver */
if (intf->dev.driver) { if (intf->dev.driver)
struct usb_driver *driver = usb_forced_unbind_intf(intf);
to_usb_driver(intf->dev.driver);
dev_dbg(&intf->dev, "forced unbind\n");
usb_driver_release_interface(driver, intf);
}
/* Try to rebind the interface */ /* Try to rebind the interface */
if (!intf->dev.power.is_prepared) { if (!intf->dev.power.is_prepared) {
...@@ -977,15 +972,13 @@ void usb_rebind_intf(struct usb_interface *intf) ...@@ -977,15 +972,13 @@ void usb_rebind_intf(struct usb_interface *intf)
#ifdef CONFIG_PM #ifdef CONFIG_PM
#define DO_UNBIND 0 /* Unbind drivers for @udev's interfaces that don't support suspend/resume
#define DO_REBIND 1 * There is no check for reset_resume here because it can be determined
* only during resume whether reset_resume is needed.
/* Unbind drivers for @udev's interfaces that don't support suspend/resume,
* or rebind interfaces that have been unbound, according to @action.
* *
* The caller must hold @udev's device lock. * The caller must hold @udev's device lock.
*/ */
static void do_unbind_rebind(struct usb_device *udev, int action) static void unbind_no_pm_drivers_interfaces(struct usb_device *udev)
{ {
struct usb_host_config *config; struct usb_host_config *config;
int i; int i;
...@@ -996,23 +989,53 @@ static void do_unbind_rebind(struct usb_device *udev, int action) ...@@ -996,23 +989,53 @@ static void do_unbind_rebind(struct usb_device *udev, int action)
if (config) { if (config) {
for (i = 0; i < config->desc.bNumInterfaces; ++i) { for (i = 0; i < config->desc.bNumInterfaces; ++i) {
intf = config->interface[i]; intf = config->interface[i];
switch (action) {
case DO_UNBIND: if (intf->dev.driver) {
if (intf->dev.driver) { drv = to_usb_driver(intf->dev.driver);
drv = to_usb_driver(intf->dev.driver); if (!drv->suspend || !drv->resume)
if (!drv->suspend || !drv->resume) usb_forced_unbind_intf(intf);
usb_forced_unbind_intf(intf);
}
break;
case DO_REBIND:
if (intf->needs_binding)
usb_rebind_intf(intf);
break;
} }
} }
} }
} }
/* Unbind drivers for @udev's interfaces that failed to support reset-resume.
* These interfaces have the needs_binding flag set by usb_resume_interface().
*
* The caller must hold @udev's device lock.
*/
static void unbind_no_reset_resume_drivers_interfaces(struct usb_device *udev)
{
struct usb_host_config *config;
int i;
struct usb_interface *intf;
config = udev->actconfig;
if (config) {
for (i = 0; i < config->desc.bNumInterfaces; ++i) {
intf = config->interface[i];
if (intf->dev.driver && intf->needs_binding)
usb_forced_unbind_intf(intf);
}
}
}
static void do_rebind_interfaces(struct usb_device *udev)
{
struct usb_host_config *config;
int i;
struct usb_interface *intf;
config = udev->actconfig;
if (config) {
for (i = 0; i < config->desc.bNumInterfaces; ++i) {
intf = config->interface[i];
if (intf->needs_binding)
usb_rebind_intf(intf);
}
}
}
static int usb_suspend_device(struct usb_device *udev, pm_message_t msg) static int usb_suspend_device(struct usb_device *udev, pm_message_t msg)
{ {
struct usb_device_driver *udriver; struct usb_device_driver *udriver;
...@@ -1302,7 +1325,12 @@ int usb_suspend(struct device *dev, pm_message_t msg) ...@@ -1302,7 +1325,12 @@ int usb_suspend(struct device *dev, pm_message_t msg)
{ {
struct usb_device *udev = to_usb_device(dev); struct usb_device *udev = to_usb_device(dev);
do_unbind_rebind(udev, DO_UNBIND); unbind_no_pm_drivers_interfaces(udev);
/* From now on we are sure all drivers support suspend/resume
* but not necessarily reset_resume()
* so we may still need to unbind and rebind upon resume
*/
choose_wakeup(udev, msg); choose_wakeup(udev, msg);
return usb_suspend_both(udev, msg); return usb_suspend_both(udev, msg);
} }
...@@ -1313,15 +1341,20 @@ int usb_resume(struct device *dev, pm_message_t msg) ...@@ -1313,15 +1341,20 @@ int usb_resume(struct device *dev, pm_message_t msg)
struct usb_device *udev = to_usb_device(dev); struct usb_device *udev = to_usb_device(dev);
int status; int status;
/* For PM complete calls, all we do is rebind interfaces */ /* For PM complete calls, all we do is rebind interfaces
* whose needs_binding flag is set
*/
if (msg.event == PM_EVENT_ON) { if (msg.event == PM_EVENT_ON) {
if (udev->state != USB_STATE_NOTATTACHED) if (udev->state != USB_STATE_NOTATTACHED)
do_unbind_rebind(udev, DO_REBIND); do_rebind_interfaces(udev);
status = 0; status = 0;
/* For all other calls, take the device back to full power and /* For all other calls, take the device back to full power and
* tell the PM core in case it was autosuspended previously. * tell the PM core in case it was autosuspended previously.
* Unbind the interfaces that will need rebinding later. * Unbind the interfaces that will need rebinding later,
* because they fail to support reset_resume.
* (This can't be done in usb_resume_interface()
* above because it doesn't own the right set of locks.)
*/ */
} else { } else {
status = usb_resume_both(udev, msg); status = usb_resume_both(udev, msg);
...@@ -1329,7 +1362,7 @@ int usb_resume(struct device *dev, pm_message_t msg) ...@@ -1329,7 +1362,7 @@ int usb_resume(struct device *dev, pm_message_t msg)
pm_runtime_disable(dev); pm_runtime_disable(dev);
pm_runtime_set_active(dev); pm_runtime_set_active(dev);
pm_runtime_enable(dev); pm_runtime_enable(dev);
do_unbind_rebind(udev, DO_REBIND); unbind_no_reset_resume_drivers_interfaces(udev);
} }
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment