aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlan Stern <stern@rowland.harvard.edu>2007-05-30 15:34:36 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2007-07-12 19:34:29 -0400
commit686314cfbdac21c9019c0e04487b5d940db62406 (patch)
tree245810b09a9b19dc74e668a244e1d5ad88ff6bee
parent4956eccdd6101c5abb71966079e8183d12796d6c (diff)
USB: separate root and non-root suspend/resume
This patch (as916) completes the separation of code paths for suspend and resume of root hubs as opposed to non-root devices. Root hubs will be power-managed through their bus_suspend and bus_resume methods, whereas normal devices will use usb_port_suspend() and usb_port_resume(). Changes to the hcd_bus_{suspend,resume} routines mostly represent motion of code that was already present elsewhere. They include: Adding debugging log messages, Setting the device state appropriately, and Adding a resume recovery time delay. Changes to the port-suspend and port-resume routines in hub.c include: Removal of checks for root devices (since they will never be triggered), and Removal of checks for NULL or invalid device pointers (these were left over from earlier kernel versions and aren't needed at all). Signed-off-by: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
-rw-r--r--drivers/usb/core/generic.c45
-rw-r--r--drivers/usb/core/hcd.c52
-rw-r--r--drivers/usb/core/hcd.h14
-rw-r--r--drivers/usb/core/hub.c42
4 files changed, 59 insertions, 94 deletions
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)
196{ 196{
197 int rc; 197 int rc;
198 198
199 rc = usb_port_suspend(udev); 199 /* Normal USB devices suspend through their upstream port.
200 200 * Root hubs don't have upstream ports to suspend,
201 /* Root hubs don't have upstream ports to suspend, 201 * so we have to shut down their downstream HC-to-USB
202 * so the line above won't do much for them. We have to 202 * interfaces manually by doing a bus (or "global") suspend.
203 * shut down their downstream HC-to-USB interfaces manually,
204 * by doing a bus (or "global") suspend.
205 */ 203 */
206 if (rc == 0 && !udev->parent) { 204 if (!udev->parent)
207 rc = hcd_bus_suspend(udev->bus); 205 rc = hcd_bus_suspend(udev);
208 if (rc) { 206 else
209 dev_dbg(&udev->dev, "'global' suspend %d\n", rc); 207 rc = usb_port_suspend(udev);
210 usb_port_resume(udev);
211 }
212 }
213 return rc; 208 return rc;
214} 209}
215 210
@@ -217,25 +212,17 @@ static int generic_resume(struct usb_device *udev)
217{ 212{
218 int rc; 213 int rc;
219 214
220 if (udev->reset_resume) 215 /* Normal USB devices resume/reset through their upstream port.
216 * Root hubs don't have upstream ports to resume or reset,
217 * so we have to start up their downstream HC-to-USB
218 * interfaces manually by doing a bus (or "global") resume.
219 */
220 if (!udev->parent)
221 rc = hcd_bus_resume(udev);
222 else if (udev->reset_resume)
221 rc = usb_reset_suspended_device(udev); 223 rc = usb_reset_suspended_device(udev);
222 else 224 else
223 rc = usb_port_resume(udev); 225 rc = usb_port_resume(udev);
224
225 /* Root hubs don't have upstream ports to resume or reset,
226 * so the line above won't do much for them. We have to
227 * start up their downstream HC-to-USB interfaces manually,
228 * by doing a bus (or "global") resume.
229 */
230 if (rc == 0 && !udev->parent) {
231 rc = hcd_bus_resume(udev->bus);
232 if (rc)
233 dev_dbg(&udev->dev, "'global' resume %d\n", rc);
234 else {
235 /* TRSMRCY = 10 msec */
236 msleep(10);
237 }
238 }
239 return rc; 226 return rc;
240} 227}
241 228
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:
1257 1257
1258#ifdef CONFIG_PM 1258#ifdef CONFIG_PM
1259 1259
1260int hcd_bus_suspend (struct usb_bus *bus) 1260int hcd_bus_suspend(struct usb_device *rhdev)
1261{ 1261{
1262 struct usb_hcd *hcd; 1262 struct usb_hcd *hcd = container_of(rhdev->bus, struct usb_hcd, self);
1263 int status; 1263 int status;
1264 int old_state = hcd->state;
1264 1265
1265 hcd = container_of (bus, struct usb_hcd, self); 1266 dev_dbg(&rhdev->dev, "bus %s%s\n",
1266 if (!hcd->driver->bus_suspend) 1267 rhdev->auto_pm ? "auto-" : "", "suspend");
1267 return -ENOENT; 1268 if (!hcd->driver->bus_suspend) {
1268 hcd->state = HC_STATE_QUIESCING; 1269 status = -ENOENT;
1269 status = hcd->driver->bus_suspend (hcd); 1270 } else {
1270 if (status == 0) 1271 hcd->state = HC_STATE_QUIESCING;
1272 status = hcd->driver->bus_suspend(hcd);
1273 }
1274 if (status == 0) {
1275 usb_set_device_state(rhdev, USB_STATE_SUSPENDED);
1271 hcd->state = HC_STATE_SUSPENDED; 1276 hcd->state = HC_STATE_SUSPENDED;
1272 else 1277 } else {
1273 dev_dbg(&bus->root_hub->dev, "%s fail, err %d\n", 1278 hcd->state = old_state;
1279 dev_dbg(&rhdev->dev, "bus %s fail, err %d\n",
1274 "suspend", status); 1280 "suspend", status);
1281 }
1275 return status; 1282 return status;
1276} 1283}
1277 1284
1278int hcd_bus_resume (struct usb_bus *bus) 1285int hcd_bus_resume(struct usb_device *rhdev)
1279{ 1286{
1280 struct usb_hcd *hcd; 1287 struct usb_hcd *hcd = container_of(rhdev->bus, struct usb_hcd, self);
1281 int status; 1288 int status;
1282 1289
1283 hcd = container_of (bus, struct usb_hcd, self); 1290 dev_dbg(&rhdev->dev, "usb %s%s\n",
1291 rhdev->auto_pm ? "auto-" : "", "resume");
1284 if (!hcd->driver->bus_resume) 1292 if (!hcd->driver->bus_resume)
1285 return -ENOENT; 1293 return -ENOENT;
1286 if (hcd->state == HC_STATE_RUNNING) 1294 if (hcd->state == HC_STATE_RUNNING)
1287 return 0; 1295 return 0;
1296
1288 hcd->state = HC_STATE_RESUMING; 1297 hcd->state = HC_STATE_RESUMING;
1289 status = hcd->driver->bus_resume (hcd); 1298 status = hcd->driver->bus_resume(hcd);
1290 if (status == 0) 1299 if (status == 0) {
1300 /* TRSMRCY = 10 msec */
1301 msleep(10);
1302 usb_set_device_state(rhdev, rhdev->actconfig
1303 ? USB_STATE_CONFIGURED
1304 : USB_STATE_ADDRESS);
1291 hcd->state = HC_STATE_RUNNING; 1305 hcd->state = HC_STATE_RUNNING;
1292 else { 1306 } else {
1293 dev_dbg(&bus->root_hub->dev, "%s fail, err %d\n", 1307 dev_dbg(&rhdev->dev, "bus %s fail, err %d\n",
1294 "resume", status); 1308 "resume", status);
1295 usb_hc_died(hcd); 1309 usb_hc_died(hcd);
1296 } 1310 }
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,
364#ifdef CONFIG_PM 364#ifdef CONFIG_PM
365extern void usb_hcd_resume_root_hub (struct usb_hcd *hcd); 365extern void usb_hcd_resume_root_hub (struct usb_hcd *hcd);
366extern void usb_root_hub_lost_power (struct usb_device *rhdev); 366extern void usb_root_hub_lost_power (struct usb_device *rhdev);
367extern int hcd_bus_suspend (struct usb_bus *bus); 367extern int hcd_bus_suspend(struct usb_device *rhdev);
368extern int hcd_bus_resume (struct usb_bus *bus); 368extern int hcd_bus_resume(struct usb_device *rhdev);
369#else 369#else
370static inline void usb_hcd_resume_root_hub(struct usb_hcd *hcd) 370static inline void usb_hcd_resume_root_hub(struct usb_hcd *hcd)
371{ 371{
372 return; 372 return;
373} 373}
374
375static inline int hcd_bus_suspend(struct usb_bus *bus)
376{
377 return 0;
378}
379
380static inline int hcd_bus_resume (struct usb_bus *bus)
381{
382 return 0;
383}
384#endif /* CONFIG_PM */ 374#endif /* CONFIG_PM */
385 375
386/* 376/*
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)
1722{ 1722{
1723 int status = 0; 1723 int status = 0;
1724 1724
1725 /* we change the device's upstream USB link, 1725 status = hub_port_suspend(hdev_to_hub(udev->parent),
1726 * but root hubs have no upstream USB link. 1726 udev->portnum, udev);
1727 */
1728 if (udev->parent)
1729 status = hub_port_suspend(hdev_to_hub(udev->parent),
1730 udev->portnum, udev);
1731 else {
1732 dev_dbg(&udev->dev, "usb %ssuspend\n",
1733 udev->auto_pm ? "auto-" : "");
1734 usb_set_device_state(udev, USB_STATE_SUSPENDED);
1735 }
1736 return status; 1727 return status;
1737} 1728}
1738 1729
@@ -1775,8 +1766,7 @@ static int finish_port_resume(struct usb_device *udev)
1775 status); 1766 status);
1776 else if (udev->actconfig) { 1767 else if (udev->actconfig) {
1777 le16_to_cpus(&devstatus); 1768 le16_to_cpus(&devstatus);
1778 if ((devstatus & (1 << USB_DEVICE_REMOTE_WAKEUP)) 1769 if (devstatus & (1 << USB_DEVICE_REMOTE_WAKEUP)) {
1779 && udev->parent) {
1780 status = usb_control_msg(udev, 1770 status = usb_control_msg(udev,
1781 usb_sndctrlpipe(udev, 0), 1771 usb_sndctrlpipe(udev, 0),
1782 USB_REQ_CLEAR_FEATURE, 1772 USB_REQ_CLEAR_FEATURE,
@@ -1789,10 +1779,6 @@ static int finish_port_resume(struct usb_device *udev)
1789 "wakeup, status %d\n", status); 1779 "wakeup, status %d\n", status);
1790 } 1780 }
1791 status = 0; 1781 status = 0;
1792
1793 } else if (udev->devnum <= 0) {
1794 dev_dbg(&udev->dev, "bogus resume!\n");
1795 status = -EINVAL;
1796 } 1782 }
1797 return status; 1783 return status;
1798} 1784}
@@ -1821,9 +1807,8 @@ hub_port_resume(struct usb_hub *hub, int port1, struct usb_device *udev)
1821 port1, status); 1807 port1, status);
1822 } else { 1808 } else {
1823 /* drive resume for at least 20 msec */ 1809 /* drive resume for at least 20 msec */
1824 if (udev) 1810 dev_dbg(&udev->dev, "usb %sresume\n",
1825 dev_dbg(&udev->dev, "usb %sresume\n", 1811 udev->auto_pm ? "auto-" : "");
1826 udev->auto_pm ? "auto-" : "");
1827 msleep(25); 1812 msleep(25);
1828 1813
1829#define LIVE_FLAGS ( USB_PORT_STAT_POWER \ 1814#define LIVE_FLAGS ( USB_PORT_STAT_POWER \
@@ -1851,8 +1836,7 @@ SuspendCleared:
1851 USB_PORT_FEAT_C_SUSPEND); 1836 USB_PORT_FEAT_C_SUSPEND);
1852 /* TRSMRCY = 10 msec */ 1837 /* TRSMRCY = 10 msec */
1853 msleep(10); 1838 msleep(10);
1854 if (udev) 1839 status = finish_port_resume(udev);
1855 status = finish_port_resume(udev);
1856 } 1840 }
1857 } 1841 }
1858 if (status < 0) 1842 if (status < 0)
@@ -1882,18 +1866,8 @@ int usb_port_resume(struct usb_device *udev)
1882{ 1866{
1883 int status; 1867 int status;
1884 1868
1885 /* we change the device's upstream USB link, 1869 status = hub_port_resume(hdev_to_hub(udev->parent),
1886 * but root hubs have no upstream USB link. 1870 udev->portnum, udev);
1887 */
1888 if (udev->parent) {
1889 // NOTE this fails if parent is also suspended...
1890 status = hub_port_resume(hdev_to_hub(udev->parent),
1891 udev->portnum, udev);
1892 } else {
1893 dev_dbg(&udev->dev, "usb %sresume\n",
1894 udev->auto_pm ? "auto-" : "");
1895 status = finish_port_resume(udev);
1896 }
1897 if (status < 0) 1871 if (status < 0)
1898 dev_dbg(&udev->dev, "can't resume, status %d\n", status); 1872 dev_dbg(&udev->dev, "can't resume, status %d\n", status);
1899 return status; 1873 return status;