diff options
author | Alan Stern <stern@rowland.harvard.edu> | 2006-07-01 22:11:02 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2006-09-27 14:58:50 -0400 |
commit | a8e7c5653562f88c0f5f53eac0a890c012655789 (patch) | |
tree | ba227138d408fdc73ccfc62ad8f75d912ece4baf /drivers/usb/core/hub.c | |
parent | 1cc8a25d5b680ff656927ffa9b66fae6b415b1d3 (diff) |
usbcore: resume device resume recursion
This patch (as717b) removes the existing recursion in hub resume code:
Resuming a hub will no longer automatically resume the devices attached
to the hub.
At the same time, it adds one level of recursion: Suspending a USB
device will automatically suspend all the device's interfaces. Failure
at an intermediate stage will cause all the already-suspended interfaces
to be resumed. Attempts to suspend or resume an interface by itself will
do nothing, although they won't return an error. Thus the regular
system-suspend and system-resume procedures should continue to work as
before; only runtime PM will be affected.
The patch also removes the code that tests state of the interfaces
before suspending a device. It's no longer needed, since everything
gets suspended together.
Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb/core/hub.c')
-rw-r--r-- | drivers/usb/core/hub.c | 96 |
1 files changed, 13 insertions, 83 deletions
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index a372332440b..a39112041e6 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c | |||
@@ -1662,9 +1662,6 @@ static int finish_port_resume(struct usb_device *udev) | |||
1662 | "gone after usb resume? status %d\n", | 1662 | "gone after usb resume? status %d\n", |
1663 | status); | 1663 | status); |
1664 | else if (udev->actconfig) { | 1664 | else if (udev->actconfig) { |
1665 | unsigned i; | ||
1666 | int (*resume)(struct device *); | ||
1667 | |||
1668 | le16_to_cpus(&devstatus); | 1665 | le16_to_cpus(&devstatus); |
1669 | if ((devstatus & (1 << USB_DEVICE_REMOTE_WAKEUP)) | 1666 | if ((devstatus & (1 << USB_DEVICE_REMOTE_WAKEUP)) |
1670 | && udev->parent) { | 1667 | && udev->parent) { |
@@ -1675,24 +1672,9 @@ static int finish_port_resume(struct usb_device *udev) | |||
1675 | USB_DEVICE_REMOTE_WAKEUP, 0, | 1672 | USB_DEVICE_REMOTE_WAKEUP, 0, |
1676 | NULL, 0, | 1673 | NULL, 0, |
1677 | USB_CTRL_SET_TIMEOUT); | 1674 | USB_CTRL_SET_TIMEOUT); |
1678 | if (status) { | 1675 | if (status) |
1679 | dev_dbg(&udev->dev, "disable remote " | 1676 | dev_dbg(&udev->dev, "disable remote " |
1680 | "wakeup, status %d\n", status); | 1677 | "wakeup, status %d\n", status); |
1681 | status = 0; | ||
1682 | } | ||
1683 | } | ||
1684 | |||
1685 | /* resume interface drivers; if this is a hub, it | ||
1686 | * may have a child resume event to deal with soon | ||
1687 | */ | ||
1688 | resume = udev->dev.bus->resume; | ||
1689 | for (i = 0; i < udev->actconfig->desc.bNumInterfaces; i++) { | ||
1690 | struct device *dev = | ||
1691 | &udev->actconfig->interface[i]->dev; | ||
1692 | |||
1693 | down(&dev->sem); | ||
1694 | (void) resume(dev); | ||
1695 | up(&dev->sem); | ||
1696 | } | 1678 | } |
1697 | status = 0; | 1679 | status = 0; |
1698 | 1680 | ||
@@ -1802,15 +1784,7 @@ int usb_port_resume(struct usb_device *udev) | |||
1802 | } else | 1784 | } else |
1803 | status = finish_port_resume(udev); | 1785 | status = finish_port_resume(udev); |
1804 | if (status < 0) | 1786 | if (status < 0) |
1805 | dev_dbg(&udev->dev, "can't resume, status %d\n", | 1787 | dev_dbg(&udev->dev, "can't resume, status %d\n", status); |
1806 | status); | ||
1807 | |||
1808 | /* rebind drivers that had no suspend() */ | ||
1809 | if (status == 0) { | ||
1810 | usb_unlock_device(udev); | ||
1811 | bus_rescan_devices(&usb_bus_type); | ||
1812 | usb_lock_device(udev); | ||
1813 | } | ||
1814 | return status; | 1788 | return status; |
1815 | } | 1789 | } |
1816 | 1790 | ||
@@ -1830,6 +1804,9 @@ static int remote_wakeup(struct usb_device *udev) | |||
1830 | msleep(10); | 1804 | msleep(10); |
1831 | status = finish_port_resume(udev); | 1805 | status = finish_port_resume(udev); |
1832 | } | 1806 | } |
1807 | |||
1808 | if (status == 0) | ||
1809 | usb_resume_both(udev); | ||
1833 | usb_unlock_device(udev); | 1810 | usb_unlock_device(udev); |
1834 | #endif | 1811 | #endif |
1835 | return status; | 1812 | return status; |
@@ -1901,51 +1878,8 @@ static int hub_resume(struct usb_interface *intf) | |||
1901 | } | 1878 | } |
1902 | } | 1879 | } |
1903 | 1880 | ||
1881 | /* tell khubd to look for changes on this hub */ | ||
1904 | hub_activate(hub); | 1882 | hub_activate(hub); |
1905 | |||
1906 | /* REVISIT: this recursion probably shouldn't exist. Remove | ||
1907 | * this code sometime, after retesting with different root and | ||
1908 | * external hubs. | ||
1909 | */ | ||
1910 | #ifdef CONFIG_USB_SUSPEND | ||
1911 | { | ||
1912 | unsigned port1; | ||
1913 | |||
1914 | for (port1 = 1; port1 <= hdev->maxchild; port1++) { | ||
1915 | struct usb_device *udev; | ||
1916 | u16 portstat, portchange; | ||
1917 | |||
1918 | udev = hdev->children [port1-1]; | ||
1919 | status = hub_port_status(hub, port1, &portstat, &portchange); | ||
1920 | if (status == 0) { | ||
1921 | if (portchange & USB_PORT_STAT_C_SUSPEND) { | ||
1922 | clear_port_feature(hdev, port1, | ||
1923 | USB_PORT_FEAT_C_SUSPEND); | ||
1924 | portchange &= ~USB_PORT_STAT_C_SUSPEND; | ||
1925 | } | ||
1926 | |||
1927 | /* let khubd handle disconnects etc */ | ||
1928 | if (portchange) | ||
1929 | continue; | ||
1930 | } | ||
1931 | |||
1932 | if (!udev || status < 0) | ||
1933 | continue; | ||
1934 | usb_lock_device(udev); | ||
1935 | if (portstat & USB_PORT_STAT_SUSPEND) | ||
1936 | status = hub_port_resume(hub, port1, udev); | ||
1937 | else { | ||
1938 | status = finish_port_resume(udev); | ||
1939 | if (status < 0) { | ||
1940 | dev_dbg(&intf->dev, "resume port %d --> %d\n", | ||
1941 | port1, status); | ||
1942 | hub_port_logical_disconnect(hub, port1); | ||
1943 | } | ||
1944 | } | ||
1945 | usb_unlock_device(udev); | ||
1946 | } | ||
1947 | } | ||
1948 | #endif | ||
1949 | return 0; | 1883 | return 0; |
1950 | } | 1884 | } |
1951 | 1885 | ||
@@ -2602,17 +2536,6 @@ static void hub_events(void) | |||
2602 | usb_get_intf(intf); | 2536 | usb_get_intf(intf); |
2603 | spin_unlock_irq(&hub_event_lock); | 2537 | spin_unlock_irq(&hub_event_lock); |
2604 | 2538 | ||
2605 | /* Is this is a root hub wanting to reactivate the downstream | ||
2606 | * ports? If so, be sure the interface resumes even if its | ||
2607 | * stub "device" node was never suspended. | ||
2608 | */ | ||
2609 | if (i) { | ||
2610 | dpm_runtime_resume(&hdev->dev); | ||
2611 | dpm_runtime_resume(&intf->dev); | ||
2612 | usb_put_intf(intf); | ||
2613 | continue; | ||
2614 | } | ||
2615 | |||
2616 | /* Lock the device, then check to see if we were | 2539 | /* Lock the device, then check to see if we were |
2617 | * disconnected while waiting for the lock to succeed. */ | 2540 | * disconnected while waiting for the lock to succeed. */ |
2618 | if (locktree(hdev) < 0) { | 2541 | if (locktree(hdev) < 0) { |
@@ -2629,6 +2552,13 @@ static void hub_events(void) | |||
2629 | goto loop; | 2552 | goto loop; |
2630 | } | 2553 | } |
2631 | 2554 | ||
2555 | /* Is this is a root hub wanting to reactivate the downstream | ||
2556 | * ports? If so, be sure the interface resumes even if its | ||
2557 | * stub "device" node was never suspended. | ||
2558 | */ | ||
2559 | if (i) | ||
2560 | usb_resume_both(hdev); | ||
2561 | |||
2632 | /* If this is an inactive or suspended hub, do nothing */ | 2562 | /* If this is an inactive or suspended hub, do nothing */ |
2633 | if (hub->quiescing) | 2563 | if (hub->quiescing) |
2634 | goto loop; | 2564 | goto loop; |