Commit 4bf0ba86 authored by Alan Stern's avatar Alan Stern Committed by Greg Kroah-Hartman

[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: default avatarAlan Stern <stern@rowland.harvard.edu>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent 7d069b7d
...@@ -1648,15 +1648,22 @@ static int __usb_suspend_device (struct usb_device *udev, int port1) ...@@ -1648,15 +1648,22 @@ static int __usb_suspend_device (struct usb_device *udev, int port1)
int usb_suspend_device(struct usb_device *udev) int usb_suspend_device(struct usb_device *udev)
{ {
#ifdef CONFIG_USB_SUSPEND #ifdef CONFIG_USB_SUSPEND
int port1, status; int port1;
port1 = locktree(udev); if (udev->state == USB_STATE_NOTATTACHED)
if (port1 < 0) return -ENODEV;
return port1; 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); return __usb_suspend_device(udev, port1);
usb_unlock_device(udev);
return status;
#else #else
/* NOTE: udev->state unchanged, it's not lying ... */ /* NOTE: udev->state unchanged, it's not lying ... */
udev->dev.power.power_state = PMSG_SUSPEND; udev->dev.power.power_state = PMSG_SUSPEND;
...@@ -1688,6 +1695,7 @@ static int finish_device_resume(struct usb_device *udev) ...@@ -1688,6 +1695,7 @@ static int finish_device_resume(struct usb_device *udev)
usb_set_device_state(udev, udev->actconfig usb_set_device_state(udev, udev->actconfig
? USB_STATE_CONFIGURED ? USB_STATE_CONFIGURED
: USB_STATE_ADDRESS); : USB_STATE_ADDRESS);
udev->dev.power.power_state = PMSG_ON;
/* 10.5.4.5 says be sure devices in the tree are still there. /* 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, * 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,8 +1731,14 @@ static int finish_device_resume(struct usb_device *udev)
* may have a child resume event to deal with soon * may have a child resume event to deal with soon
*/ */
resume = udev->dev.bus->resume; resume = udev->dev.bus->resume;
for (i = 0; i < udev->actconfig->desc.bNumInterfaces; i++) for (i = 0; i < udev->actconfig->desc.bNumInterfaces; i++) {
(void) resume(&udev->actconfig->interface[i]->dev); struct device *dev =
&udev->actconfig->interface[i]->dev;
down(&dev->sem);
(void) resume(dev);
up(&dev->sem);
}
status = 0; status = 0;
} else if (udev->devnum <= 0) { } else if (udev->devnum <= 0) {
...@@ -1809,9 +1823,18 @@ int usb_resume_device(struct usb_device *udev) ...@@ -1809,9 +1823,18 @@ int usb_resume_device(struct usb_device *udev)
{ {
int port1, status; int port1, status;
port1 = locktree(udev); if (udev->state == USB_STATE_NOTATTACHED)
if (port1 < 0) return -ENODEV;
return port1; 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 #ifdef CONFIG_USB_SUSPEND
/* selective resume of one downstream hub-to-device port */ /* selective resume of one downstream hub-to-device port */
...@@ -1830,11 +1853,12 @@ int usb_resume_device(struct usb_device *udev) ...@@ -1830,11 +1853,12 @@ int usb_resume_device(struct usb_device *udev)
dev_dbg(&udev->dev, "can't resume, status %d\n", dev_dbg(&udev->dev, "can't resume, status %d\n",
status); status);
usb_unlock_device(udev);
/* rebind drivers that had no suspend() */ /* rebind drivers that had no suspend() */
if (status == 0) if (status == 0) {
usb_unlock_device(udev);
bus_rescan_devices(&usb_bus_type); bus_rescan_devices(&usb_bus_type);
usb_lock_device(udev);
}
return status; return status;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment