diff options
author | Alan Stern <stern@rowland.harvard.edu> | 2005-11-21 11:58:07 -0500 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2006-01-04 16:48:34 -0500 |
commit | 4bf0ba861442d289eebfad8ea9ce365ab04fd582 (patch) | |
tree | 0301e45a155712ec03e0226a1e85e74198778f7e /drivers/usb/core | |
parent | 7d069b7d80933004282c48edbe62526e4cb0aecc (diff) |
[PATCH] USB: Fix locking for USB suspend/resume
The earlier USB locking updates didn't touch the suspend/resume
routines. They need updating as well, since now the caller holds the
device semaphore. This patch (as608) makes the necessary changes. It
also adds a line to store the correct power state when a device is
resumed, something which was unaccountably missing.
Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb/core')
-rw-r--r-- | drivers/usb/core/hub.c | 54 |
1 files changed, 39 insertions, 15 deletions
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 02601f412f9d..895ac829b9cf 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c | |||
@@ -1648,15 +1648,22 @@ static int __usb_suspend_device (struct usb_device *udev, int port1) | |||
1648 | int usb_suspend_device(struct usb_device *udev) | 1648 | int usb_suspend_device(struct usb_device *udev) |
1649 | { | 1649 | { |
1650 | #ifdef CONFIG_USB_SUSPEND | 1650 | #ifdef CONFIG_USB_SUSPEND |
1651 | int port1, status; | 1651 | int port1; |
1652 | 1652 | ||
1653 | port1 = locktree(udev); | 1653 | if (udev->state == USB_STATE_NOTATTACHED) |
1654 | if (port1 < 0) | 1654 | return -ENODEV; |
1655 | return port1; | 1655 | if (!udev->parent) |
1656 | port1 = 0; | ||
1657 | else { | ||
1658 | for (port1 = udev->parent->maxchild; port1 > 0; --port1) { | ||
1659 | if (udev->parent->children[port1-1] == udev) | ||
1660 | break; | ||
1661 | } | ||
1662 | if (port1 == 0) | ||
1663 | return -ENODEV; | ||
1664 | } | ||
1656 | 1665 | ||
1657 | status = __usb_suspend_device(udev, port1); | 1666 | return __usb_suspend_device(udev, port1); |
1658 | usb_unlock_device(udev); | ||
1659 | return status; | ||
1660 | #else | 1667 | #else |
1661 | /* NOTE: udev->state unchanged, it's not lying ... */ | 1668 | /* NOTE: udev->state unchanged, it's not lying ... */ |
1662 | udev->dev.power.power_state = PMSG_SUSPEND; | 1669 | udev->dev.power.power_state = PMSG_SUSPEND; |
@@ -1688,6 +1695,7 @@ static int finish_device_resume(struct usb_device *udev) | |||
1688 | usb_set_device_state(udev, udev->actconfig | 1695 | usb_set_device_state(udev, udev->actconfig |
1689 | ? USB_STATE_CONFIGURED | 1696 | ? USB_STATE_CONFIGURED |
1690 | : USB_STATE_ADDRESS); | 1697 | : USB_STATE_ADDRESS); |
1698 | udev->dev.power.power_state = PMSG_ON; | ||
1691 | 1699 | ||
1692 | /* 10.5.4.5 says be sure devices in the tree are still there. | 1700 | /* 10.5.4.5 says be sure devices in the tree are still there. |
1693 | * For now let's assume the device didn't go crazy on resume, | 1701 | * For now let's assume the device didn't go crazy on resume, |
@@ -1723,8 +1731,14 @@ static int finish_device_resume(struct usb_device *udev) | |||
1723 | * may have a child resume event to deal with soon | 1731 | * may have a child resume event to deal with soon |
1724 | */ | 1732 | */ |
1725 | resume = udev->dev.bus->resume; | 1733 | resume = udev->dev.bus->resume; |
1726 | for (i = 0; i < udev->actconfig->desc.bNumInterfaces; i++) | 1734 | for (i = 0; i < udev->actconfig->desc.bNumInterfaces; i++) { |
1727 | (void) resume(&udev->actconfig->interface[i]->dev); | 1735 | struct device *dev = |
1736 | &udev->actconfig->interface[i]->dev; | ||
1737 | |||
1738 | down(&dev->sem); | ||
1739 | (void) resume(dev); | ||
1740 | up(&dev->sem); | ||
1741 | } | ||
1728 | status = 0; | 1742 | status = 0; |
1729 | 1743 | ||
1730 | } else if (udev->devnum <= 0) { | 1744 | } else if (udev->devnum <= 0) { |
@@ -1809,9 +1823,18 @@ int usb_resume_device(struct usb_device *udev) | |||
1809 | { | 1823 | { |
1810 | int port1, status; | 1824 | int port1, status; |
1811 | 1825 | ||
1812 | port1 = locktree(udev); | 1826 | if (udev->state == USB_STATE_NOTATTACHED) |
1813 | if (port1 < 0) | 1827 | return -ENODEV; |
1814 | return port1; | 1828 | if (!udev->parent) |
1829 | port1 = 0; | ||
1830 | else { | ||
1831 | for (port1 = udev->parent->maxchild; port1 > 0; --port1) { | ||
1832 | if (udev->parent->children[port1-1] == udev) | ||
1833 | break; | ||
1834 | } | ||
1835 | if (port1 == 0) | ||
1836 | return -ENODEV; | ||
1837 | } | ||
1815 | 1838 | ||
1816 | #ifdef CONFIG_USB_SUSPEND | 1839 | #ifdef CONFIG_USB_SUSPEND |
1817 | /* selective resume of one downstream hub-to-device port */ | 1840 | /* selective resume of one downstream hub-to-device port */ |
@@ -1830,11 +1853,12 @@ int usb_resume_device(struct usb_device *udev) | |||
1830 | dev_dbg(&udev->dev, "can't resume, status %d\n", | 1853 | dev_dbg(&udev->dev, "can't resume, status %d\n", |
1831 | status); | 1854 | status); |
1832 | 1855 | ||
1833 | usb_unlock_device(udev); | ||
1834 | |||
1835 | /* rebind drivers that had no suspend() */ | 1856 | /* rebind drivers that had no suspend() */ |
1836 | if (status == 0) | 1857 | if (status == 0) { |
1858 | usb_unlock_device(udev); | ||
1837 | bus_rescan_devices(&usb_bus_type); | 1859 | bus_rescan_devices(&usb_bus_type); |
1860 | usb_lock_device(udev); | ||
1861 | } | ||
1838 | return status; | 1862 | return status; |
1839 | } | 1863 | } |
1840 | 1864 | ||