Commit 1cc8a25d authored by Alan Stern's avatar Alan Stern Committed by Greg Kroah-Hartman

usbcore: split suspend/resume for device and interfaces

This patch (as716b) splits up the core suspend and resume routines into
two parts each: one for handling devices and one for handling
interfaces.  The behavior of the parts should be the same as in the old
unified code.
Signed-off-by: default avatarAlan Stern <stern@rowland.harvard.edu>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent 782da727
...@@ -751,81 +751,89 @@ EXPORT_SYMBOL_GPL_FUTURE(usb_deregister); ...@@ -751,81 +751,89 @@ EXPORT_SYMBOL_GPL_FUTURE(usb_deregister);
#ifdef CONFIG_PM #ifdef CONFIG_PM
static int usb_suspend(struct device *dev, pm_message_t message) /* Caller has locked udev */
static int suspend_device(struct usb_device *udev, pm_message_t msg)
{ {
struct usb_device *udev;
struct usb_device_driver *udriver; struct usb_device_driver *udriver;
struct usb_interface *intf;
struct usb_driver *driver;
int status;
if (is_usb_device(dev)) { if (udev->dev.driver == NULL)
if (dev->driver == NULL)
return 0; return 0;
udev = to_usb_device(dev); udriver = to_usb_device_driver(udev->dev.driver);
udriver = to_usb_device_driver(dev->driver); if (udev->dev.power.power_state.event == msg.event)
if (dev->power.power_state.event == message.event)
return 0; return 0;
return udriver->suspend(udev, message); return udriver->suspend(udev, msg);
} }
/* Caller has locked udev */
static int resume_device(struct usb_device *udev)
{
struct usb_device_driver *udriver;
if (dev->driver == NULL) if (udev->dev.power.power_state.event == PM_EVENT_ON)
return 0; return 0;
intf = to_usb_interface(dev); /* mark things as "on" immediately, no matter what errors crop up */
driver = to_usb_driver(dev->driver); udev->dev.power.power_state.event = PM_EVENT_ON;
if (udev->dev.driver == NULL)
return 0;
udriver = to_usb_device_driver(udev->dev.driver);
if (udev->state == USB_STATE_NOTATTACHED)
return 0;
return udriver->resume(udev);
}
/* Caller has locked intf */
static int suspend_interface(struct usb_interface *intf, pm_message_t msg)
{
struct usb_driver *driver;
int status;
if (intf->dev.driver == NULL)
return 0;
driver = to_usb_driver(intf->dev.driver);
/* with no hardware, USB interfaces only use FREEZE and ON states */ /* with no hardware, USB interfaces only use FREEZE and ON states */
if (!is_active(intf)) if (!is_active(intf))
return 0; return 0;
if (driver->suspend && driver->resume) { if (driver->suspend && driver->resume) {
status = driver->suspend(intf, message); status = driver->suspend(intf, msg);
if (status) if (status)
dev_err(dev, "%s error %d\n", "suspend", status); dev_err(&intf->dev, "%s error %d\n",
"suspend", status);
else else
mark_quiesced(intf); mark_quiesced(intf);
} else { } else {
// FIXME else if there's no suspend method, disconnect... // FIXME else if there's no suspend method, disconnect...
dev_warn(dev, "no suspend for driver %s?\n", driver->name); dev_warn(&intf->dev, "no suspend for driver %s?\n",
driver->name);
mark_quiesced(intf); mark_quiesced(intf);
status = 0; status = 0;
} }
return status; return status;
} }
static int usb_resume(struct device *dev) /* Caller has locked intf */
static int resume_interface(struct usb_interface *intf)
{ {
struct usb_device *udev;
struct usb_device_driver *udriver;
struct usb_interface *intf;
struct usb_driver *driver; struct usb_driver *driver;
struct usb_device *udev;
int status; int status;
if (dev->power.power_state.event == PM_EVENT_ON) if (intf->dev.power.power_state.event == PM_EVENT_ON)
return 0; return 0;
/* mark things as "on" immediately, no matter what errors crop up */ /* mark things as "on" immediately, no matter what errors crop up */
dev->power.power_state.event = PM_EVENT_ON; intf->dev.power.power_state.event = PM_EVENT_ON;
/* devices resume through their hubs */
if (is_usb_device(dev)) {
if (dev->driver == NULL)
return 0;
udev = to_usb_device(dev);
udriver = to_usb_device_driver(dev->driver);
if (udev->state == USB_STATE_NOTATTACHED)
return 0;
return udriver->resume(udev);
}
if (dev->driver == NULL) { if (intf->dev.driver == NULL) {
dev->power.power_state.event = PM_EVENT_FREEZE; intf->dev.power.power_state.event = PM_EVENT_FREEZE;
return 0; return 0;
} }
intf = to_usb_interface(dev); driver = to_usb_driver(intf->dev.driver);
driver = to_usb_driver(dev->driver);
udev = interface_to_usbdev(intf); udev = interface_to_usbdev(intf);
if (udev->state == USB_STATE_NOTATTACHED) if (udev->state == USB_STATE_NOTATTACHED)
...@@ -838,14 +846,38 @@ static int usb_resume(struct device *dev) ...@@ -838,14 +846,38 @@ static int usb_resume(struct device *dev)
if (driver->resume) { if (driver->resume) {
status = driver->resume(intf); status = driver->resume(intf);
if (status) { if (status) {
dev_err(dev, "%s error %d\n", "resume", status); dev_err(&intf->dev, "%s error %d\n",
"resume", status);
mark_quiesced(intf); mark_quiesced(intf);
} }
} else } else
dev_warn(dev, "no resume for driver %s?\n", driver->name); dev_warn(&intf->dev, "no resume for driver %s?\n",
driver->name);
return 0; return 0;
} }
static int usb_suspend(struct device *dev, pm_message_t message)
{
int status;
if (is_usb_device(dev))
status = suspend_device(to_usb_device(dev), message);
else
status = suspend_interface(to_usb_interface(dev), message);
return status;
}
static int usb_resume(struct device *dev)
{
int status;
if (is_usb_device(dev))
status = resume_device(to_usb_device(dev));
else
status = resume_interface(to_usb_interface(dev));
return status;
}
#endif /* CONFIG_PM */ #endif /* CONFIG_PM */
struct bus_type usb_bus_type = { struct bus_type usb_bus_type = {
......
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