aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlan Stern <stern@rowland.harvard.edu>2007-05-30 15:38:58 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2007-07-12 19:34:30 -0400
commit54515fe528d8c6f9bfaf7d0b9fffb908deecad78 (patch)
tree02f9205eed99bbf836dc9827f11db8584e93d443
parentf07600cf9eb3ee92777b2001e564faa413144a99 (diff)
USB: unify reset_resume and normal resume
This patch (as919) unifies the code paths used for normal resume and for reset-resume. Earlier I had failed to note a section in the USB spec which requires the host to resume a suspended port before resetting it if the attached device is enabled for remote wakeup. Since the port has to be resumed anyway, we might as well reuse the existing code. The main changes are: usb_reset_suspended_device() is eliminated. usb_root_hub_lost_power() is moved down next to the hub_reset_resume() routine, to which it is logically related. finish_port_resume() does a port reset() if the device's reset_resume flag is set. usb_port_resume() doesn't check whether the port is initially enabled if this is a USB-Persist sort of resume. Code to perform the port reset is added to the resume pathway for the non-CONFIG_USB_SUSPEND case. 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.c2
-rw-r--r--drivers/usb/core/hub.c184
-rw-r--r--drivers/usb/core/usb.h1
3 files changed, 93 insertions, 94 deletions
diff --git a/drivers/usb/core/generic.c b/drivers/usb/core/generic.c
index 4cbe7b339513..b2fc2b115256 100644
--- a/drivers/usb/core/generic.c
+++ b/drivers/usb/core/generic.c
@@ -219,8 +219,6 @@ static int generic_resume(struct usb_device *udev)
219 */ 219 */
220 if (!udev->parent) 220 if (!udev->parent)
221 rc = hcd_bus_resume(udev); 221 rc = hcd_bus_resume(udev);
222 else if (udev->reset_resume)
223 rc = usb_reset_suspended_device(udev);
224 else 222 else
225 rc = usb_port_resume(udev); 223 rc = usb_port_resume(udev);
226 return rc; 224 return rc;
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index 0b8ed414d5cf..c4cdb69a6e9e 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -31,6 +31,12 @@
31#include "hcd.h" 31#include "hcd.h"
32#include "hub.h" 32#include "hub.h"
33 33
34#ifdef CONFIG_USB_PERSIST
35#define USB_PERSIST 1
36#else
37#define USB_PERSIST 0
38#endif
39
34struct usb_hub { 40struct usb_hub {
35 struct device *intfdev; /* the "interface" device */ 41 struct device *intfdev; /* the "interface" device */
36 struct usb_device *hdev; 42 struct usb_device *hdev;
@@ -1080,72 +1086,6 @@ void usb_set_device_state(struct usb_device *udev,
1080 spin_unlock_irqrestore(&device_state_lock, flags); 1086 spin_unlock_irqrestore(&device_state_lock, flags);
1081} 1087}
1082 1088
1083
1084#ifdef CONFIG_PM
1085
1086/**
1087 * usb_reset_suspended_device - reset a suspended device instead of resuming it
1088 * @udev: device to be reset instead of resumed
1089 *
1090 * If a host controller doesn't maintain VBUS suspend current during a
1091 * system sleep or is reset when the system wakes up, all the USB
1092 * power sessions below it will be broken. This is especially troublesome
1093 * for mass-storage devices containing mounted filesystems, since the
1094 * device will appear to have disconnected and all the memory mappings
1095 * to it will be lost.
1096 *
1097 * As an alternative, this routine attempts to recover power sessions for
1098 * devices that are still present by resetting them instead of resuming
1099 * them. If all goes well, the devices will appear to persist across the
1100 * the interruption of the power sessions.
1101 *
1102 * This facility is inherently dangerous. Although usb_reset_device()
1103 * makes every effort to insure that the same device is present after the
1104 * reset as before, it cannot provide a 100% guarantee. Furthermore it's
1105 * quite possible for a device to remain unaltered but its media to be
1106 * changed. If the user replaces a flash memory card while the system is
1107 * asleep, he will have only himself to blame when the filesystem on the
1108 * new card is corrupted and the system crashes.
1109 */
1110int usb_reset_suspended_device(struct usb_device *udev)
1111{
1112 int rc = 0;
1113
1114 dev_dbg(&udev->dev, "usb %sresume\n", "reset-");
1115
1116 /* After we're done the device won't be suspended any more.
1117 * In addition, the reset won't work if udev->state is SUSPENDED.
1118 */
1119 usb_set_device_state(udev, udev->actconfig
1120 ? USB_STATE_CONFIGURED
1121 : USB_STATE_ADDRESS);
1122
1123 /* Root hubs don't need to be (and can't be) reset */
1124 if (udev->parent)
1125 rc = usb_reset_device(udev);
1126 return rc;
1127}
1128
1129/**
1130 * usb_root_hub_lost_power - called by HCD if the root hub lost Vbus power
1131 * @rhdev: struct usb_device for the root hub
1132 *
1133 * The USB host controller driver calls this function when its root hub
1134 * is resumed and Vbus power has been interrupted or the controller
1135 * has been reset. The routine marks @rhdev as having lost power. When
1136 * the hub driver is resumed it will take notice; if CONFIG_USB_PERSIST
1137 * is enabled then it will carry out power-session recovery, otherwise
1138 * it will disconnect all the child devices.
1139 */
1140void usb_root_hub_lost_power(struct usb_device *rhdev)
1141{
1142 dev_warn(&rhdev->dev, "root hub lost power or was reset\n");
1143 rhdev->reset_resume = 1;
1144}
1145EXPORT_SYMBOL_GPL(usb_root_hub_lost_power);
1146
1147#endif /* CONFIG_PM */
1148
1149static void choose_address(struct usb_device *udev) 1089static void choose_address(struct usb_device *udev)
1150{ 1090{
1151 int devnum; 1091 int devnum;
@@ -1672,18 +1612,22 @@ int usb_port_suspend(struct usb_device *udev)
1672/* 1612/*
1673 * If the USB "suspend" state is in use (rather than "global suspend"), 1613 * If the USB "suspend" state is in use (rather than "global suspend"),
1674 * many devices will be individually taken out of suspend state using 1614 * many devices will be individually taken out of suspend state using
1675 * special" resume" signaling. These routines kick in shortly after 1615 * special "resume" signaling. This routine kicks in shortly after
1676 * hardware resume signaling is finished, either because of selective 1616 * hardware resume signaling is finished, either because of selective
1677 * resume (by host) or remote wakeup (by device) ... now see what changed 1617 * resume (by host) or remote wakeup (by device) ... now see what changed
1678 * in the tree that's rooted at this device. 1618 * in the tree that's rooted at this device.
1619 *
1620 * If @udev->reset_resume is set then the device is reset before the
1621 * status check is done.
1679 */ 1622 */
1680static int finish_port_resume(struct usb_device *udev) 1623static int finish_port_resume(struct usb_device *udev)
1681{ 1624{
1682 int status; 1625 int status = 0;
1683 u16 devstatus; 1626 u16 devstatus;
1684 1627
1685 /* caller owns the udev device lock */ 1628 /* caller owns the udev device lock */
1686 dev_dbg(&udev->dev, "finish resume\n"); 1629 dev_dbg(&udev->dev, "finish %sresume\n",
1630 udev->reset_resume ? "reset-" : "");
1687 1631
1688 /* usb ch9 identifies four variants of SUSPENDED, based on what 1632 /* usb ch9 identifies four variants of SUSPENDED, based on what
1689 * state the device resumes to. Linux currently won't see the 1633 * state the device resumes to. Linux currently won't see the
@@ -1694,13 +1638,23 @@ static int finish_port_resume(struct usb_device *udev)
1694 ? USB_STATE_CONFIGURED 1638 ? USB_STATE_CONFIGURED
1695 : USB_STATE_ADDRESS); 1639 : USB_STATE_ADDRESS);
1696 1640
1641 /* 10.5.4.5 says not to reset a suspended port if the attached
1642 * device is enabled for remote wakeup. Hence the reset
1643 * operation is carried out here, after the port has been
1644 * resumed.
1645 */
1646 if (udev->reset_resume)
1647 status = usb_reset_device(udev);
1648
1697 /* 10.5.4.5 says be sure devices in the tree are still there. 1649 /* 10.5.4.5 says be sure devices in the tree are still there.
1698 * For now let's assume the device didn't go crazy on resume, 1650 * For now let's assume the device didn't go crazy on resume,
1699 * and device drivers will know about any resume quirks. 1651 * and device drivers will know about any resume quirks.
1700 */ 1652 */
1701 status = usb_get_status(udev, USB_RECIP_DEVICE, 0, &devstatus); 1653 if (status == 0) {
1702 if (status >= 0) 1654 status = usb_get_status(udev, USB_RECIP_DEVICE, 0, &devstatus);
1703 status = (status == 2 ? 0 : -ENODEV); 1655 if (status >= 0)
1656 status = (status == 2 ? 0 : -ENODEV);
1657 }
1704 1658
1705 if (status) { 1659 if (status) {
1706 dev_dbg(&udev->dev, "gone after usb resume? status %d\n", 1660 dev_dbg(&udev->dev, "gone after usb resume? status %d\n",
@@ -1735,6 +1689,28 @@ static int finish_port_resume(struct usb_device *udev)
1735 * the host and the device is the same as it was when the device 1689 * the host and the device is the same as it was when the device
1736 * suspended. 1690 * suspended.
1737 * 1691 *
1692 * If CONFIG_USB_PERSIST and @udev->reset_resume are both set then this
1693 * routine won't check that the port is still enabled. Furthermore,
1694 * if @udev->reset_resume is set then finish_port_resume() above will
1695 * reset @udev. The end result is that a broken power session can be
1696 * recovered and @udev will appear to persist across a loss of VBUS power.
1697 *
1698 * For example, if a host controller doesn't maintain VBUS suspend current
1699 * during a system sleep or is reset when the system wakes up, all the USB
1700 * power sessions below it will be broken. This is especially troublesome
1701 * for mass-storage devices containing mounted filesystems, since the
1702 * device will appear to have disconnected and all the memory mappings
1703 * to it will be lost. Using the USB_PERSIST facility, the device can be
1704 * made to appear as if it had not disconnected.
1705 *
1706 * This facility is inherently dangerous. Although usb_reset_device()
1707 * makes every effort to insure that the same device is present after the
1708 * reset as before, it cannot provide a 100% guarantee. Furthermore it's
1709 * quite possible for a device to remain unaltered but its media to be
1710 * changed. If the user replaces a flash memory card while the system is
1711 * asleep, he will have only himself to blame when the filesystem on the
1712 * new card is corrupted and the system crashes.
1713 *
1738 * Returns 0 on success, else negative errno. 1714 * Returns 0 on success, else negative errno.
1739 */ 1715 */
1740int usb_port_resume(struct usb_device *udev) 1716int usb_port_resume(struct usb_device *udev)
@@ -1743,6 +1719,7 @@ int usb_port_resume(struct usb_device *udev)
1743 int port1 = udev->portnum; 1719 int port1 = udev->portnum;
1744 int status; 1720 int status;
1745 u16 portchange, portstatus; 1721 u16 portchange, portstatus;
1722 unsigned mask_flags, want_flags;
1746 1723
1747 /* Skip the initial Clear-Suspend step for a remote wakeup */ 1724 /* Skip the initial Clear-Suspend step for a remote wakeup */
1748 status = hub_port_status(hub, port1, &portstatus, &portchange); 1725 status = hub_port_status(hub, port1, &portstatus, &portchange);
@@ -1765,20 +1742,23 @@ int usb_port_resume(struct usb_device *udev)
1765 udev->auto_pm ? "auto-" : ""); 1742 udev->auto_pm ? "auto-" : "");
1766 msleep(25); 1743 msleep(25);
1767 1744
1768#define LIVE_FLAGS ( USB_PORT_STAT_POWER \
1769 | USB_PORT_STAT_ENABLE \
1770 | USB_PORT_STAT_CONNECTION)
1771
1772 /* Virtual root hubs can trigger on GET_PORT_STATUS to 1745 /* Virtual root hubs can trigger on GET_PORT_STATUS to
1773 * stop resume signaling. Then finish the resume 1746 * stop resume signaling. Then finish the resume
1774 * sequence. 1747 * sequence.
1775 */ 1748 */
1776 status = hub_port_status(hub, port1, &portstatus, &portchange); 1749 status = hub_port_status(hub, port1, &portstatus, &portchange);
1777SuspendCleared: 1750
1778 if (status < 0 1751 SuspendCleared:
1779 || (portstatus & LIVE_FLAGS) != LIVE_FLAGS 1752 if (USB_PERSIST && udev->reset_resume)
1780 || (portstatus & USB_PORT_STAT_SUSPEND) != 0 1753 want_flags = USB_PORT_STAT_POWER
1781 ) { 1754 | USB_PORT_STAT_CONNECTION;
1755 else
1756 want_flags = USB_PORT_STAT_POWER
1757 | USB_PORT_STAT_CONNECTION
1758 | USB_PORT_STAT_ENABLE;
1759 mask_flags = want_flags | USB_PORT_STAT_SUSPEND;
1760
1761 if (status < 0 || (portstatus & mask_flags) != want_flags) {
1782 dev_dbg(hub->intfdev, 1762 dev_dbg(hub->intfdev,
1783 "port %d status %04x.%04x after resume, %d\n", 1763 "port %d status %04x.%04x after resume, %d\n",
1784 port1, portchange, portstatus, status); 1764 port1, portchange, portstatus, status);
@@ -1790,18 +1770,19 @@ SuspendCleared:
1790 USB_PORT_FEAT_C_SUSPEND); 1770 USB_PORT_FEAT_C_SUSPEND);
1791 /* TRSMRCY = 10 msec */ 1771 /* TRSMRCY = 10 msec */
1792 msleep(10); 1772 msleep(10);
1793 status = finish_port_resume(udev);
1794 } 1773 }
1795 } 1774 }
1796 if (status < 0) {
1797 dev_dbg(&udev->dev, "can't resume, status %d\n", status);
1798 hub_port_logical_disconnect(hub, port1);
1799 }
1800 1775
1801 clear_bit(port1, hub->busy_bits); 1776 clear_bit(port1, hub->busy_bits);
1802 if (!hub->hdev->parent && !hub->busy_bits[0]) 1777 if (!hub->hdev->parent && !hub->busy_bits[0])
1803 usb_enable_root_hub_irq(hub->hdev->bus); 1778 usb_enable_root_hub_irq(hub->hdev->bus);
1804 1779
1780 if (status == 0)
1781 status = finish_port_resume(udev);
1782 if (status < 0) {
1783 dev_dbg(&udev->dev, "can't resume, status %d\n", status);
1784 hub_port_logical_disconnect(hub, port1);
1785 }
1805 return status; 1786 return status;
1806} 1787}
1807 1788
@@ -1830,7 +1811,14 @@ int usb_port_suspend(struct usb_device *udev)
1830 1811
1831int usb_port_resume(struct usb_device *udev) 1812int usb_port_resume(struct usb_device *udev)
1832{ 1813{
1833 return 0; 1814 int status = 0;
1815
1816 /* However we may need to do a reset-resume */
1817 if (udev->reset_resume) {
1818 dev_dbg(&udev->dev, "reset-resume\n");
1819 status = usb_reset_device(udev);
1820 }
1821 return status;
1834} 1822}
1835 1823
1836static inline int remote_wakeup(struct usb_device *udev) 1824static inline int remote_wakeup(struct usb_device *udev)
@@ -1886,8 +1874,6 @@ static int hub_resume(struct usb_interface *intf)
1886 1874
1887#ifdef CONFIG_USB_PERSIST 1875#ifdef CONFIG_USB_PERSIST
1888 1876
1889#define USB_PERSIST 1
1890
1891/* For "persistent-device" resets we must mark the child devices for reset 1877/* For "persistent-device" resets we must mark the child devices for reset
1892 * and turn off a possible connect-change status (so khubd won't disconnect 1878 * and turn off a possible connect-change status (so khubd won't disconnect
1893 * them later). 1879 * them later).
@@ -1910,8 +1896,6 @@ static void mark_children_for_reset_resume(struct usb_hub *hub)
1910 1896
1911#else 1897#else
1912 1898
1913#define USB_PERSIST 0
1914
1915static inline void mark_children_for_reset_resume(struct usb_hub *hub) 1899static inline void mark_children_for_reset_resume(struct usb_hub *hub)
1916{ } 1900{ }
1917 1901
@@ -1936,6 +1920,24 @@ static int hub_reset_resume(struct usb_interface *intf)
1936 return 0; 1920 return 0;
1937} 1921}
1938 1922
1923/**
1924 * usb_root_hub_lost_power - called by HCD if the root hub lost Vbus power
1925 * @rhdev: struct usb_device for the root hub
1926 *
1927 * The USB host controller driver calls this function when its root hub
1928 * is resumed and Vbus power has been interrupted or the controller
1929 * has been reset. The routine marks @rhdev as having lost power. When
1930 * the hub driver is resumed it will take notice; if CONFIG_USB_PERSIST
1931 * is enabled then it will carry out power-session recovery, otherwise
1932 * it will disconnect all the child devices.
1933 */
1934void usb_root_hub_lost_power(struct usb_device *rhdev)
1935{
1936 dev_warn(&rhdev->dev, "root hub lost power or was reset\n");
1937 rhdev->reset_resume = 1;
1938}
1939EXPORT_SYMBOL_GPL(usb_root_hub_lost_power);
1940
1939#else /* CONFIG_PM */ 1941#else /* CONFIG_PM */
1940 1942
1941static inline int remote_wakeup(struct usb_device *udev) 1943static inline int remote_wakeup(struct usb_device *udev)
diff --git a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h
index a547499c45f4..ad5fa0338f49 100644
--- a/drivers/usb/core/usb.h
+++ b/drivers/usb/core/usb.h
@@ -36,7 +36,6 @@ extern void usb_host_cleanup(void);
36extern void usb_autosuspend_work(struct work_struct *work); 36extern void usb_autosuspend_work(struct work_struct *work);
37extern int usb_port_suspend(struct usb_device *dev); 37extern int usb_port_suspend(struct usb_device *dev);
38extern int usb_port_resume(struct usb_device *dev); 38extern int usb_port_resume(struct usb_device *dev);
39extern int usb_reset_suspended_device(struct usb_device *udev);
40extern int usb_external_suspend_device(struct usb_device *udev, 39extern int usb_external_suspend_device(struct usb_device *udev,
41 pm_message_t msg); 40 pm_message_t msg);
42extern int usb_external_resume_device(struct usb_device *udev); 41extern int usb_external_resume_device(struct usb_device *udev);