aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/core/hub.c
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 /drivers/usb/core/hub.c
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(-)
Diffstat (limited to 'drivers/usb/core/hub.c')
-rw-r--r--drivers/usb/core/hub.c163
1 files changed, 90 insertions, 73 deletions
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index 3c8d8d1f993..6a601a4547e 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