diff options
| author | David Brownell <david-b@pacbell.net> | 2005-09-23 01:37:29 -0400 |
|---|---|---|
| committer | Greg Kroah-Hartman <gregkh@suse.de> | 2005-10-28 19:47:40 -0400 |
| commit | f3f3253d644d36a2ea5464005a9c2cf28804d200 (patch) | |
| tree | 913d5d38de9acea02b95c43ea23dc6a28f791236 /drivers/usb/core | |
| parent | 979d5199fee9e80290ddeb532e5993bd15506712 (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')
| -rw-r--r-- | drivers/usb/core/Kconfig | 11 | ||||
| -rw-r--r-- | drivers/usb/core/hub.c | 163 |
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 | ||
| 63 | config USB_SUSPEND | 63 | config 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 | */ |
| 1613 | static int __usb_suspend_device (struct usb_device *udev, int port1) | 1613 | static 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 | */ |
| 1684 | int usb_suspend_device(struct usb_device *udev) | 1675 | int 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 | */ |
| 1705 | static int finish_port_resume(struct usb_device *udev) | 1703 | static 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 | |||
| 1767 | static int | 1767 | static int |
| 1768 | hub_port_resume(struct usb_hub *hub, int port1, struct usb_device *udev) | 1768 | hub_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 | ||
| 1821 | static int hub_resume (struct usb_interface *intf); | 1821 | #endif |
| 1822 | |||
