[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 <[EMAIL PROTECTED]>
Signed-off-by: Greg Kroah-Hartman <[EMAIL PROTECTED]>
---
commit 4bf0ba861442d289eebfad8ea9ce365ab04fd582
tree 0301e45a155712ec03e0226a1e85e74198778f7e
parent 7d069b7d80933004282c48edbe62526e4cb0aecc
author Alan Stern <[EMAIL PROTECTED]> Mon, 21 Nov 2005 11:58:07 -0500
committer Greg Kroah-Hartman <[EMAIL PROTECTED]> Wed, 04 Jan 2006 13:48:34 -0800
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 02601f4..895ac82 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -1648,15 +1648,22 @@ static int __usb_suspend_device (struct
int usb_suspend_device(struct usb_device *udev)
{
#ifdef CONFIG_USB_SUSPEND
- int port1, status;
+ int port1;
- port1 = locktree(udev);
- if (port1 < 0)
- return port1;
+ if (udev->state == USB_STATE_NOTATTACHED)
+ return -ENODEV;
+ if (!udev->parent)
+ port1 = 0;
+ else {
+ for (port1 = udev->parent->maxchild; port1 > 0; --port1) {
+ if (udev->parent->children[port1-1] == udev)
+ break;
+ }
+ if (port1 == 0)
+ return -ENODEV;
+ }
- status = __usb_suspend_device(udev, port1);
- usb_unlock_device(udev);
- return status;
+ return __usb_suspend_device(udev, port1);
#else
/* NOTE: udev->state unchanged, it's not lying ... */
udev->dev.power.power_state = PMSG_SUSPEND;
@@ -1688,6 +1695,7 @@ static int finish_device_resume(struct u
usb_set_device_state(udev, udev->actconfig
? USB_STATE_CONFIGURED
: USB_STATE_ADDRESS);
+ udev->dev.power.power_state = PMSG_ON;
/* 10.5.4.5 says be sure devices in the tree are still there.
* For now let's assume the device didn't go crazy on resume,
@@ -1723,8 +1731,14 @@ static int finish_device_resume(struct u
* may have a child resume event to deal with soon
*/
resume = udev->dev.bus->resume;
- for (i = 0; i < udev->actconfig->desc.bNumInterfaces; i++)
- (void) resume(&udev->actconfig->interface[i]->dev);
+ for (i = 0; i < udev->actconfig->desc.bNumInterfaces; i++) {
+ struct device *dev =
+ &udev->actconfig->interface[i]->dev;
+
+ down(&dev->sem);
+ (void) resume(dev);
+ up(&dev->sem);
+ }
status = 0;
} else if (udev->devnum <= 0) {
@@ -1809,9 +1823,18 @@ int usb_resume_device(struct usb_device
{
int port1, status;
- port1 = locktree(udev);
- if (port1 < 0)
- return port1;
+ if (udev->state == USB_STATE_NOTATTACHED)
+ return -ENODEV;
+ if (!udev->parent)
+ port1 = 0;
+ else {
+ for (port1 = udev->parent->maxchild; port1 > 0; --port1) {
+ if (udev->parent->children[port1-1] == udev)
+ break;
+ }
+ if (port1 == 0)
+ return -ENODEV;
+ }
#ifdef CONFIG_USB_SUSPEND
/* selective resume of one downstream hub-to-device port */
@@ -1830,11 +1853,12 @@ int usb_resume_device(struct usb_device
dev_dbg(&udev->dev, "can't resume, status %d\n",
status);
- usb_unlock_device(udev);
-
/* rebind drivers that had no suspend() */
- if (status == 0)
+ if (status == 0) {
+ usb_unlock_device(udev);
bus_rescan_devices(&usb_bus_type);
+ usb_lock_device(udev);
+ }
return status;
}
-------------------------------------------------------
This SF.net email is sponsored by: Splunk Inc. Do you grep through log files
for problems? Stop! Download the new AJAX search engine that makes
searching your log files as easy as surfing the web. DOWNLOAD SPLUNK!
http://ads.osdn.com/?ad_idv37&alloc_id865&op=click
_______________________________________________
[email protected]
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel