mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2025-01-09 22:50:41 +00:00
[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>
This commit is contained in:
parent
7d069b7d80
commit
4bf0ba8614
@ -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)
|
|||||||
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)
|
|||||||
* 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)
|
|||||||
{
|
{
|
||||||
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)
|
|||||||
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user