aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Brownell <david-b@pacbell.net>2005-09-23 01:37:29 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2005-10-28 19:47:40 -0400
commitf3f3253d644d36a2ea5464005a9c2cf28804d200 (patch)
tree913d5d38de9acea02b95c43ea23dc6a28f791236
parent979d5199fee9e80290ddeb532e5993bd15506712 (diff)
[PATCH] root hub updates (greater half)
This patch associates hub suspend and resume logic (including for root hubs) with CONFIG_PM -- instead of CONFIG_USB_SUSPEND as before -- thereby unifying two troublesome versions of suspend logic into just one. It'll be easier to keep things right from now on. - Now usbcore _always_ calls hcd->hub_suspend as needed, instead of only when USB_SUSPEND is enabled: * Those root hub methods are now called from hub suspend/resume; no more skipping between layers during device suspend/resume; * It now handles cases allowed by sysfs or autosuspended root hubs, by forcing the hub interface to resume too. - All devices, including virtual root hubs, now get the same treatment on their resume paths ... including re-activating all their interfaces. Plus it gets rid of those stub copies of usb_{suspend,resume}_device(), and updates the Kconfig to match the new definition of USB_SUSPEND: it provides (a) selective suspend, downstream from hubs; and (b) remote wakeup, upstream from any device configuration which supports it. This calls for minor followup patches for most HCDs (and their PCI glue). Signed-off-by: David Brownell <dbrownell@users.sourceforge.net> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> drivers/usb/core/Kconfig | 11 ++- drivers/usb/core/hub.c | 163 +++++++++++++++++++++++++---------------------- 2 files changed, 97 insertions(+), 77 deletions(-)
-rw-r--r--drivers/usb/core/Kconfig11
-rw-r--r--drivers/usb/core/hub.c163
2 files changed, 97 insertions, 77 deletions
diff --git a/drivers/usb/core/Kconfig b/drivers/usb/core/Kconfig
index 1a9ff6184943..ff03184da403 100644
--- a/drivers/usb/core/Kconfig
+++ b/drivers/usb/core/Kconfig
@@ -61,14 +61,17 @@ config USB_DYNAMIC_MINORS
61 If you are unsure about this, say N here. 61 If you are unsure about this, say N here.
62 62
63config USB_SUSPEND 63config USB_SUSPEND
64 bool "USB suspend/resume (EXPERIMENTAL)" 64 bool "USB selective suspend/resume and wakeup (EXPERIMENTAL)"
65 depends on USB && PM && EXPERIMENTAL 65 depends on USB && PM && EXPERIMENTAL
66 help 66 help
67 If you say Y here, you can use driver calls or the sysfs 67 If you say Y here, you can use driver calls or the sysfs
68 "power/state" file to suspend or resume individual USB 68 "power/state" file to suspend or resume individual USB
69 peripherals. There are many related features, such as 69 peripherals.
70 remote wakeup and driver-specific suspend processing, that 70
71 may not yet work as expected. 71 Also, USB "remote wakeup" signaling is supported, whereby some
72 USB devices (like keyboards and network adapters) can wake up
73 their parent hub. That wakeup cascades up the USB tree, and
74 could wake the system from states like suspend-to-RAM.
72 75
73 If you are unsure about this, say N here. 76 If you are unsure about this, say N here.
74 77
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index 3c8d8d1f993c..6a601a4547e7 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -1612,7 +1612,7 @@ static int hub_port_suspend(struct usb_hub *hub, int port1,
1612 */ 1612 */
1613static int __usb_suspend_device (struct usb_device *udev, int port1) 1613static int __usb_suspend_device (struct usb_device *udev, int port1)
1614{ 1614{
1615 int status; 1615 int status = 0;
1616 1616
1617 /* caller owns the udev device lock */ 1617 /* caller owns the udev device lock */
1618 if (port1 < 0) 1618 if (port1 < 0)
@@ -1638,21 +1638,10 @@ static int __usb_suspend_device (struct usb_device *udev, int port1)
1638 } 1638 }
1639 } 1639 }
1640 1640
1641 /* "global suspend" of the HC-to-USB interface (root hub), or 1641 /* we only change a device's upstream USB link.
1642 * "selective suspend" of just one hub-device link. 1642 * root hubs have no upstream USB link.
1643 */ 1643 */
1644 if (!udev->parent) { 1644 if (udev->parent)
1645 struct usb_bus *bus = udev->bus;
1646 if (bus && bus->op->hub_suspend) {
1647 status = bus->op->hub_suspend (bus);
1648 if (status == 0) {
1649 dev_dbg(&udev->dev, "usb suspend\n");
1650 usb_set_device_state(udev,
1651 USB_STATE_SUSPENDED);
1652 }
1653 } else
1654 status = -EOPNOTSUPP;
1655 } else
1656 status = hub_port_suspend(hdev_to_hub(udev->parent), port1, 1645 status = hub_port_suspend(hdev_to_hub(udev->parent), port1,
1657 udev); 1646 udev);
1658 1647
@@ -1661,6 +1650,8 @@ static int __usb_suspend_device (struct usb_device *udev, int port1)
1661 return status; 1650 return status;
1662} 1651}
1663 1652
1653#endif
1654
1664/** 1655/**
1665 * usb_suspend_device - suspend a usb device 1656 * usb_suspend_device - suspend a usb device
1666 * @udev: device that's no longer in active use 1657 * @udev: device that's no longer in active use
@@ -1683,6 +1674,7 @@ static int __usb_suspend_device (struct usb_device *udev, int port1)
1683 */ 1674 */
1684int usb_suspend_device(struct usb_device *udev) 1675int usb_suspend_device(struct usb_device *udev)
1685{ 1676{
1677#ifdef CONFIG_USB_SUSPEND
1686 int port1, status; 1678 int port1, status;
1687 1679
1688 port1 = locktree(udev); 1680 port1 = locktree(udev);
@@ -1692,8 +1684,14 @@ int usb_suspend_device(struct usb_device *udev)
1692 status = __usb_suspend_device(udev, port1); 1684 status = __usb_suspend_device(udev, port1);
1693 usb_unlock_device(udev); 1685 usb_unlock_device(udev);
1694 return status; 1686 return status;
1687#else
1688 /* NOTE: udev->state unchanged, it's not lying ... */
1689 udev->dev.power.power_state = PMSG_SUSPEND;
1690 return 0;
1691#endif
1695} 1692}
1696 1693
1694
1697/* 1695/*
1698 * If the USB "suspend" state is in use (rather than "global suspend"), 1696 * If the USB "suspend" state is in use (rather than "global suspend"),
1699 * many devices will be individually taken out of suspend state using 1697 * many devices will be individually taken out of suspend state using
@@ -1702,13 +1700,13 @@ int usb_suspend_device(struct usb_device *udev)
1702 * resume (by host) or remote wakeup (by device) ... now see what changed 1700 * resume (by host) or remote wakeup (by device) ... now see what changed
1703 * in the tree that's rooted at this device. 1701 * in the tree that's rooted at this device.
1704 */ 1702 */
1705static int finish_port_resume(struct usb_device *udev) 1703static int finish_device_resume(struct usb_device *udev)
1706{ 1704{
1707 int status; 1705 int status;
1708 u16 devstatus; 1706 u16 devstatus;
1709 1707
1710 /* caller owns the udev device lock */ 1708 /* caller owns the udev device lock */
1711 dev_dbg(&udev->dev, "usb resume\n"); 1709 dev_dbg(&udev->dev, "finish resume\n");
1712 1710
1713 /* usb ch9 identifies four variants of SUSPENDED, based on what 1711 /* usb ch9 identifies four variants of SUSPENDED, based on what
1714 * state the device resumes to. Linux currently won't see the 1712 * state the device resumes to. Linux currently won't see the
@@ -1718,7 +1716,6 @@ static int finish_port_resume(struct usb_device *udev)
1718 usb_set_device_state(udev, udev->actconfig 1716 usb_set_device_state(udev, udev->actconfig
1719 ? USB_STATE_CONFIGURED 1717 ? USB_STATE_CONFIGURED
1720 : USB_STATE_ADDRESS); 1718 : USB_STATE_ADDRESS);
1721 udev->dev.power.power_state = PMSG_ON;
1722 1719
1723 /* 10.5.4.5 says be sure devices in the tree are still there. 1720 /* 10.5.4.5 says be sure devices in the tree are still there.
1724 * For now let's assume the device didn't go crazy on resume, 1721 * For now let's assume the device didn't go crazy on resume,
@@ -1734,7 +1731,8 @@ static int finish_port_resume(struct usb_device *udev)
1734 int (*resume)(struct device *); 1731 int (*resume)(struct device *);
1735 1732
1736 le16_to_cpus(&devstatus); 1733 le16_to_cpus(&devstatus);
1737 if (devstatus & (1 << USB_DEVICE_REMOTE_WAKEUP)) { 1734 if (devstatus & (1 << USB_DEVICE_REMOTE_WAKEUP)
1735 && udev->parent) {
1738 status = usb_control_msg(udev, 1736 status = usb_control_msg(udev,
1739 usb_sndctrlpipe(udev, 0), 1737 usb_sndctrlpipe(udev, 0),
1740 USB_REQ_CLEAR_FEATURE, 1738 USB_REQ_CLEAR_FEATURE,
@@ -1764,6 +1762,8 @@ static int finish_port_resume(struct usb_device *udev)
1764 return status; 1762 return status;
1765} 1763}
1766 1764
1765#ifdef CONFIG_USB_SUSPEND
1766
1767static int 1767static int
1768hub_port_resume(struct usb_hub *hub, int port1, struct usb_device *udev) 1768hub_port_resume(struct usb_hub *hub, int port1, struct usb_device *udev)
1769{ 1769{
@@ -1809,7 +1809,7 @@ hub_port_resume(struct usb_hub *hub, int port1, struct usb_device *udev)
1809 /* TRSMRCY = 10 msec */ 1809 /* TRSMRCY = 10 msec */
1810 msleep(10); 1810 msleep(10);
1811 if (udev) 1811 if (udev)
1812 status = finish_port_resume(udev); 1812 status = finish_device_resume(udev);
1813 } 1813 }
1814 } 1814 }
1815 if (status < 0) 1815 if (status < 0)
@@ -1818,7 +1818,7 @@ hub_port_resume(struct usb_hub *hub, int port1, struct usb_device *udev)
1818 return status; 1818 return status;
1819} 1819}
1820 1820
1821static int hub_resume (struct usb_interface *intf); 1821#endif
1822 1822
1823/** 1823/**
1824 * usb_resume_device - re-activate a suspended usb device 1824 * usb_resume_device - re-activate a suspended usb device
@@ -1841,35 +1841,22 @@ int usb_resume_device(struct usb_device *udev)
1841 if (port1 < 0) 1841 if (port1 < 0)
1842 return port1; 1842 return port1;
1843 1843
1844 /* "global resume" of the HC-to-USB interface (root hub), or 1844#ifdef CONFIG_USB_SUSPEND
1845 * selective resume of one hub-to-device port 1845 /* selective resume of one downstream hub-to-device port */
1846 */ 1846 if (udev->parent) {
1847 if (!udev->parent) { 1847 if (udev->state == USB_STATE_SUSPENDED) {
1848 struct usb_bus *bus = udev->bus; 1848 // NOTE swsusp may bork us, device state being wrong...
1849 if (bus && bus->op->hub_resume) { 1849 // NOTE this fails if parent is also suspended...
1850 status = bus->op->hub_resume (bus); 1850 status = hub_port_resume(hdev_to_hub(udev->parent),
1851 port1, udev);
1851 } else 1852 } else
1852 status = -EOPNOTSUPP; 1853 status = 0;
1853 if (status == 0) { 1854 } else
1854 dev_dbg(&udev->dev, "usb resume\n"); 1855#endif
1855 /* TRSMRCY = 10 msec */ 1856 status = finish_device_resume(udev);
1856 msleep(10); 1857 if (status < 0)
1857 usb_set_device_state (udev, USB_STATE_CONFIGURED);
1858 udev->dev.power.power_state = PMSG_ON;
1859 status = hub_resume (udev
1860 ->actconfig->interface[0]);
1861 }
1862 } else if (udev->state == USB_STATE_SUSPENDED) {
1863 // NOTE this fails if parent is also suspended...
1864 status = hub_port_resume(hdev_to_hub(udev->parent),
1865 port1, udev);
1866 } else {
1867 status = 0;
1868 }
1869 if (status < 0) {
1870 dev_dbg(&udev->dev, "can't resume, status %d\n", 1858 dev_dbg(&udev->dev, "can't resume, status %d\n",
1871 status); 1859 status);
1872 }
1873 1860
1874 usb_unlock_device(udev); 1861 usb_unlock_device(udev);
1875 1862
@@ -1886,6 +1873,8 @@ static int remote_wakeup(struct usb_device *udev)
1886{ 1873{
1887 int status = 0; 1874 int status = 0;
1888 1875
1876#ifdef CONFIG_USB_SUSPEND
1877
1889 /* don't repeat RESUME sequence if this device 1878 /* don't repeat RESUME sequence if this device
1890 * was already woken up by some other task 1879 * was already woken up by some other task
1891 */ 1880 */
@@ -1894,9 +1883,10 @@ static int remote_wakeup(struct usb_device *udev)
1894 dev_dbg(&udev->dev, "RESUME (wakeup)\n"); 1883 dev_dbg(&udev->dev, "RESUME (wakeup)\n");
1895 /* TRSMRCY = 10 msec */ 1884 /* TRSMRCY = 10 msec */
1896 msleep(10); 1885 msleep(10);
1897 status = finish_port_resume(udev); 1886 status = finish_device_resume(udev);
1898 } 1887 }
1899 up(&udev->serialize); 1888 up(&udev->serialize);
1889#endif
1900 return status; 1890 return status;
1901} 1891}
1902 1892
@@ -1911,12 +1901,32 @@ static int hub_suspend(struct usb_interface *intf, pm_message_t msg)
1911 struct usb_device *udev; 1901 struct usb_device *udev;
1912 1902
1913 udev = hdev->children [port1-1]; 1903 udev = hdev->children [port1-1];
1914 if (udev && udev->state != USB_STATE_SUSPENDED) { 1904 if (udev && (udev->dev.power.power_state.event
1905 == PM_EVENT_ON
1906#ifdef CONFIG_USB_SUSPEND
1907 || udev->state != USB_STATE_SUSPENDED
1908#endif
1909 )) {
1915 dev_dbg(&intf->dev, "port %d nyet suspended\n", port1); 1910 dev_dbg(&intf->dev, "port %d nyet suspended\n", port1);
1916 return -EBUSY; 1911 return -EBUSY;
1917 } 1912 }
1918 } 1913 }
1919 1914
1915 /* "global suspend" of the downstream HC-to-USB interface */
1916 if (!hdev->parent) {
1917 struct usb_bus *bus = hdev->bus;
1918 if (bus && bus->op->hub_suspend) {
1919 int status = bus->op->hub_suspend (bus);
1920
1921 if (status != 0) {
1922 dev_dbg(&hdev->dev, "'global' suspend %d\n",
1923 status);
1924 return status;
1925 }
1926 } else
1927 return -EOPNOTSUPP;
1928 }
1929
1920 /* stop khubd and related activity */ 1930 /* stop khubd and related activity */
1921 hub_quiesce(hub); 1931 hub_quiesce(hub);
1922 return 0; 1932 return 0;
@@ -1926,9 +1936,36 @@ static int hub_resume(struct usb_interface *intf)
1926{ 1936{
1927 struct usb_device *hdev = interface_to_usbdev(intf); 1937 struct usb_device *hdev = interface_to_usbdev(intf);
1928 struct usb_hub *hub = usb_get_intfdata (intf); 1938 struct usb_hub *hub = usb_get_intfdata (intf);
1929 unsigned port1;
1930 int status; 1939 int status;
1931 1940
1941 /* "global resume" of the downstream HC-to-USB interface */
1942 if (!hdev->parent) {
1943 struct usb_bus *bus = hdev->bus;
1944 if (bus && bus->op->hub_resume) {
1945 status = bus->op->hub_resume (bus);
1946 if (status) {
1947 dev_dbg(&intf->dev, "'global' resume %d\n",
1948 status);
1949 return status;
1950 }
1951 } else
1952 return -EOPNOTSUPP;
1953 if (status == 0) {
1954 /* TRSMRCY = 10 msec */
1955 msleep(10);
1956 }
1957 }
1958
1959 hub_activate(hub);
1960
1961 /* REVISIT: this recursion probably shouldn't exist. Remove
1962 * this code sometime, after retesting with different root and
1963 * external hubs.
1964 */
1965#ifdef CONFIG_USB_SUSPEND
1966 {
1967 unsigned port1;
1968
1932 for (port1 = 1; port1 <= hdev->maxchild; port1++) { 1969 for (port1 = 1; port1 <= hdev->maxchild; port1++) {
1933 struct usb_device *udev; 1970 struct usb_device *udev;
1934 u16 portstat, portchange; 1971 u16 portstat, portchange;
@@ -1953,7 +1990,7 @@ static int hub_resume(struct usb_interface *intf)
1953 if (portstat & USB_PORT_STAT_SUSPEND) 1990 if (portstat & USB_PORT_STAT_SUSPEND)
1954 status = hub_port_resume(hub, port1, udev); 1991 status = hub_port_resume(hub, port1, udev);
1955 else { 1992 else {
1956 status = finish_port_resume(udev); 1993 status = finish_device_resume(udev);
1957 if (status < 0) { 1994 if (status < 0) {
1958 dev_dbg(&intf->dev, "resume port %d --> %d\n", 1995 dev_dbg(&intf->dev, "resume port %d --> %d\n",
1959 port1, status); 1996 port1, status);
@@ -1962,8 +1999,8 @@ static int hub_resume(struct usb_interface *intf)
1962 } 1999 }
1963 up(&udev->serialize); 2000 up(&udev->serialize);
1964 } 2001 }
1965 hub->resume_root_hub = 0; 2002 }
1966 hub_activate(hub); 2003#endif
1967 return 0; 2004 return 0;
1968} 2005}
1969 2006
@@ -1987,26 +2024,6 @@ void usb_resume_root_hub(struct usb_device *hdev)
1987 kick_khubd(hub); 2024 kick_khubd(hub);
1988} 2025}
1989 2026
1990#else /* !CONFIG_USB_SUSPEND */
1991
1992int usb_suspend_device(struct usb_device *udev)
1993{
1994 /* state does NOT lie by saying it's USB_STATE_SUSPENDED! */
1995 return 0;
1996}
1997
1998int usb_resume_device(struct usb_device *udev)
1999{
2000 udev->dev.power.power_state.event = PM_EVENT_ON;
2001 return 0;
2002}
2003
2004#define hub_suspend NULL
2005#define hub_resume NULL
2006#define remote_wakeup(x) 0
2007
2008#endif /* CONFIG_USB_SUSPEND */
2009
2010EXPORT_SYMBOL(usb_suspend_device); 2027EXPORT_SYMBOL(usb_suspend_device);
2011EXPORT_SYMBOL(usb_resume_device); 2028EXPORT_SYMBOL(usb_resume_device);
2012 2029