diff --git a/drivers/usb/core/generic.c b/drivers/usb/core/generic.c index d363b0ea7345..4cbe7b339513 100644 --- a/drivers/usb/core/generic.c +++ b/drivers/usb/core/generic.c @@ -196,20 +196,15 @@ static int generic_suspend(struct usb_device *udev, pm_message_t msg) { int rc; - rc = usb_port_suspend(udev); - - /* Root hubs don't have upstream ports to suspend, - * so the line above won't do much for them. We have to - * shut down their downstream HC-to-USB interfaces manually, - * by doing a bus (or "global") suspend. + /* Normal USB devices suspend through their upstream port. + * Root hubs don't have upstream ports to suspend, + * so we have to shut down their downstream HC-to-USB + * interfaces manually by doing a bus (or "global") suspend. */ - if (rc == 0 && !udev->parent) { - rc = hcd_bus_suspend(udev->bus); - if (rc) { - dev_dbg(&udev->dev, "'global' suspend %d\n", rc); - usb_port_resume(udev); - } - } + if (!udev->parent) + rc = hcd_bus_suspend(udev); + else + rc = usb_port_suspend(udev); return rc; } @@ -217,25 +212,17 @@ static int generic_resume(struct usb_device *udev) { int rc; - if (udev->reset_resume) + /* Normal USB devices resume/reset through their upstream port. + * Root hubs don't have upstream ports to resume or reset, + * so we have to start up their downstream HC-to-USB + * interfaces manually by doing a bus (or "global") resume. + */ + if (!udev->parent) + rc = hcd_bus_resume(udev); + else if (udev->reset_resume) rc = usb_reset_suspended_device(udev); else rc = usb_port_resume(udev); - - /* Root hubs don't have upstream ports to resume or reset, - * so the line above won't do much for them. We have to - * start up their downstream HC-to-USB interfaces manually, - * by doing a bus (or "global") resume. - */ - if (rc == 0 && !udev->parent) { - rc = hcd_bus_resume(udev->bus); - if (rc) - dev_dbg(&udev->dev, "'global' resume %d\n", rc); - else { - /* TRSMRCY = 10 msec */ - msleep(10); - } - } return rc; } diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index 87d6edf11f92..e5058fb26a7e 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -1257,40 +1257,54 @@ rescan: #ifdef CONFIG_PM -int hcd_bus_suspend (struct usb_bus *bus) +int hcd_bus_suspend(struct usb_device *rhdev) { - struct usb_hcd *hcd; - int status; + struct usb_hcd *hcd = container_of(rhdev->bus, struct usb_hcd, self); + int status; + int old_state = hcd->state; - hcd = container_of (bus, struct usb_hcd, self); - if (!hcd->driver->bus_suspend) - return -ENOENT; - hcd->state = HC_STATE_QUIESCING; - status = hcd->driver->bus_suspend (hcd); - if (status == 0) + dev_dbg(&rhdev->dev, "bus %s%s\n", + rhdev->auto_pm ? "auto-" : "", "suspend"); + if (!hcd->driver->bus_suspend) { + status = -ENOENT; + } else { + hcd->state = HC_STATE_QUIESCING; + status = hcd->driver->bus_suspend(hcd); + } + if (status == 0) { + usb_set_device_state(rhdev, USB_STATE_SUSPENDED); hcd->state = HC_STATE_SUSPENDED; - else - dev_dbg(&bus->root_hub->dev, "%s fail, err %d\n", + } else { + hcd->state = old_state; + dev_dbg(&rhdev->dev, "bus %s fail, err %d\n", "suspend", status); + } return status; } -int hcd_bus_resume (struct usb_bus *bus) +int hcd_bus_resume(struct usb_device *rhdev) { - struct usb_hcd *hcd; - int status; + struct usb_hcd *hcd = container_of(rhdev->bus, struct usb_hcd, self); + int status; - hcd = container_of (bus, struct usb_hcd, self); + dev_dbg(&rhdev->dev, "usb %s%s\n", + rhdev->auto_pm ? "auto-" : "", "resume"); if (!hcd->driver->bus_resume) return -ENOENT; if (hcd->state == HC_STATE_RUNNING) return 0; + hcd->state = HC_STATE_RESUMING; - status = hcd->driver->bus_resume (hcd); - if (status == 0) + status = hcd->driver->bus_resume(hcd); + if (status == 0) { + /* TRSMRCY = 10 msec */ + msleep(10); + usb_set_device_state(rhdev, rhdev->actconfig + ? USB_STATE_CONFIGURED + : USB_STATE_ADDRESS); hcd->state = HC_STATE_RUNNING; - else { - dev_dbg(&bus->root_hub->dev, "%s fail, err %d\n", + } else { + dev_dbg(&rhdev->dev, "bus %s fail, err %d\n", "resume", status); usb_hc_died(hcd); } diff --git a/drivers/usb/core/hcd.h b/drivers/usb/core/hcd.h index ef50fa494e47..b5ebb73c2332 100644 --- a/drivers/usb/core/hcd.h +++ b/drivers/usb/core/hcd.h @@ -364,23 +364,13 @@ extern int usb_find_interface_driver (struct usb_device *dev, #ifdef CONFIG_PM extern void usb_hcd_resume_root_hub (struct usb_hcd *hcd); extern void usb_root_hub_lost_power (struct usb_device *rhdev); -extern int hcd_bus_suspend (struct usb_bus *bus); -extern int hcd_bus_resume (struct usb_bus *bus); +extern int hcd_bus_suspend(struct usb_device *rhdev); +extern int hcd_bus_resume(struct usb_device *rhdev); #else static inline void usb_hcd_resume_root_hub(struct usb_hcd *hcd) { return; } - -static inline int hcd_bus_suspend(struct usb_bus *bus) -{ - return 0; -} - -static inline int hcd_bus_resume (struct usb_bus *bus) -{ - return 0; -} #endif /* CONFIG_PM */ /* diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 04d6fde57d88..ac1ef1527dd2 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -1722,17 +1722,8 @@ int usb_port_suspend(struct usb_device *udev) { int status = 0; - /* we change the device's upstream USB link, - * but root hubs have no upstream USB link. - */ - if (udev->parent) - status = hub_port_suspend(hdev_to_hub(udev->parent), - udev->portnum, udev); - else { - dev_dbg(&udev->dev, "usb %ssuspend\n", - udev->auto_pm ? "auto-" : ""); - usb_set_device_state(udev, USB_STATE_SUSPENDED); - } + status = hub_port_suspend(hdev_to_hub(udev->parent), + udev->portnum, udev); return status; } @@ -1775,8 +1766,7 @@ static int finish_port_resume(struct usb_device *udev) status); else if (udev->actconfig) { le16_to_cpus(&devstatus); - if ((devstatus & (1 << USB_DEVICE_REMOTE_WAKEUP)) - && udev->parent) { + if (devstatus & (1 << USB_DEVICE_REMOTE_WAKEUP)) { status = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), USB_REQ_CLEAR_FEATURE, @@ -1789,10 +1779,6 @@ static int finish_port_resume(struct usb_device *udev) "wakeup, status %d\n", status); } status = 0; - - } else if (udev->devnum <= 0) { - dev_dbg(&udev->dev, "bogus resume!\n"); - status = -EINVAL; } return status; } @@ -1821,9 +1807,8 @@ hub_port_resume(struct usb_hub *hub, int port1, struct usb_device *udev) port1, status); } else { /* drive resume for at least 20 msec */ - if (udev) - dev_dbg(&udev->dev, "usb %sresume\n", - udev->auto_pm ? "auto-" : ""); + dev_dbg(&udev->dev, "usb %sresume\n", + udev->auto_pm ? "auto-" : ""); msleep(25); #define LIVE_FLAGS ( USB_PORT_STAT_POWER \ @@ -1851,8 +1836,7 @@ SuspendCleared: USB_PORT_FEAT_C_SUSPEND); /* TRSMRCY = 10 msec */ msleep(10); - if (udev) - status = finish_port_resume(udev); + status = finish_port_resume(udev); } } if (status < 0) @@ -1882,18 +1866,8 @@ int usb_port_resume(struct usb_device *udev) { int status; - /* we change the device's upstream USB link, - * but root hubs have no upstream USB link. - */ - if (udev->parent) { - // NOTE this fails if parent is also suspended... - status = hub_port_resume(hdev_to_hub(udev->parent), - udev->portnum, udev); - } else { - dev_dbg(&udev->dev, "usb %sresume\n", - udev->auto_pm ? "auto-" : ""); - status = finish_port_resume(udev); - } + status = hub_port_resume(hdev_to_hub(udev->parent), + udev->portnum, udev); if (status < 0) dev_dbg(&udev->dev, "can't resume, status %d\n", status); return status;