mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-16 00:34:20 +08:00
usbcore: set device and power states properly
This patch (as733) fixes up the places where device states and power states are set in usbcore. Right now things are duplicated or missing; this should straighten things out. The idea is that udev->state is USB_STATE_SUSPENDED exactly when the device's upstream port has been suspended, whereas udev->dev.power.power_state.event reflects the result of the last call to the suspend/resume routines (which might not actually change the device state, especially if CONFIG_USB_SUSPEND isn't set). Signed-off-by: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
This commit is contained in:
parent
4d064c0802
commit
2bf4086d7a
@ -755,48 +755,57 @@ EXPORT_SYMBOL_GPL_FUTURE(usb_deregister);
|
|||||||
static int suspend_device(struct usb_device *udev, pm_message_t msg)
|
static int suspend_device(struct usb_device *udev, pm_message_t msg)
|
||||||
{
|
{
|
||||||
struct usb_device_driver *udriver;
|
struct usb_device_driver *udriver;
|
||||||
|
int status = 0;
|
||||||
|
|
||||||
if (udev->dev.driver == NULL)
|
if (udev->dev.driver == NULL)
|
||||||
return 0;
|
goto done;
|
||||||
udriver = to_usb_device_driver(udev->dev.driver);
|
udriver = to_usb_device_driver(udev->dev.driver);
|
||||||
if (udev->dev.power.power_state.event == msg.event)
|
if (udev->dev.power.power_state.event == msg.event)
|
||||||
return 0;
|
goto done;
|
||||||
return udriver->suspend(udev, msg);
|
status = udriver->suspend(udev, msg);
|
||||||
|
|
||||||
|
done:
|
||||||
|
if (status == 0)
|
||||||
|
udev->dev.power.power_state.event = msg.event;
|
||||||
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Caller has locked udev */
|
/* Caller has locked udev */
|
||||||
static int resume_device(struct usb_device *udev)
|
static int resume_device(struct usb_device *udev)
|
||||||
{
|
{
|
||||||
struct usb_device_driver *udriver;
|
struct usb_device_driver *udriver;
|
||||||
|
int status = 0;
|
||||||
|
|
||||||
if (udev->dev.power.power_state.event == PM_EVENT_ON)
|
if (udev->dev.power.power_state.event == PM_EVENT_ON)
|
||||||
return 0;
|
goto done;
|
||||||
|
|
||||||
/* mark things as "on" immediately, no matter what errors crop up */
|
|
||||||
udev->dev.power.power_state.event = PM_EVENT_ON;
|
|
||||||
|
|
||||||
if (udev->dev.driver == NULL)
|
if (udev->dev.driver == NULL)
|
||||||
return 0;
|
goto done;
|
||||||
udriver = to_usb_device_driver(udev->dev.driver);
|
udriver = to_usb_device_driver(udev->dev.driver);
|
||||||
if (udev->state == USB_STATE_NOTATTACHED)
|
if (udev->state == USB_STATE_NOTATTACHED)
|
||||||
return 0;
|
goto done;
|
||||||
return udriver->resume(udev);
|
status = udriver->resume(udev);
|
||||||
|
|
||||||
|
done:
|
||||||
|
if (status == 0)
|
||||||
|
udev->dev.power.power_state.event = PM_EVENT_ON;
|
||||||
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Caller has locked intf's usb_device */
|
/* Caller has locked intf's usb_device */
|
||||||
static int suspend_interface(struct usb_interface *intf, pm_message_t msg)
|
static int suspend_interface(struct usb_interface *intf, pm_message_t msg)
|
||||||
{
|
{
|
||||||
struct usb_driver *driver;
|
struct usb_driver *driver;
|
||||||
int status;
|
int status = 0;
|
||||||
|
|
||||||
if (intf->dev.driver == NULL)
|
if (intf->dev.driver == NULL)
|
||||||
return 0;
|
goto done;
|
||||||
|
|
||||||
driver = to_usb_driver(intf->dev.driver);
|
driver = to_usb_driver(intf->dev.driver);
|
||||||
|
|
||||||
/* with no hardware, USB interfaces only use FREEZE and ON states */
|
/* with no hardware, USB interfaces only use FREEZE and ON states */
|
||||||
if (!is_active(intf))
|
if (!is_active(intf))
|
||||||
return 0;
|
goto done;
|
||||||
|
|
||||||
if (driver->suspend && driver->resume) {
|
if (driver->suspend && driver->resume) {
|
||||||
status = driver->suspend(intf, msg);
|
status = driver->suspend(intf, msg);
|
||||||
@ -810,8 +819,11 @@ static int suspend_interface(struct usb_interface *intf, pm_message_t msg)
|
|||||||
dev_warn(&intf->dev, "no suspend for driver %s?\n",
|
dev_warn(&intf->dev, "no suspend for driver %s?\n",
|
||||||
driver->name);
|
driver->name);
|
||||||
mark_quiesced(intf);
|
mark_quiesced(intf);
|
||||||
status = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
done:
|
||||||
|
if (status == 0)
|
||||||
|
intf->dev.power.power_state.event = msg.event;
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -820,24 +832,19 @@ static int resume_interface(struct usb_interface *intf)
|
|||||||
{
|
{
|
||||||
struct usb_driver *driver;
|
struct usb_driver *driver;
|
||||||
struct usb_device *udev;
|
struct usb_device *udev;
|
||||||
int status;
|
int status = 0;
|
||||||
|
|
||||||
if (intf->dev.power.power_state.event == PM_EVENT_ON)
|
if (intf->dev.power.power_state.event == PM_EVENT_ON)
|
||||||
return 0;
|
goto done;
|
||||||
|
|
||||||
/* mark things as "on" immediately, no matter what errors crop up */
|
if (intf->dev.driver == NULL)
|
||||||
intf->dev.power.power_state.event = PM_EVENT_ON;
|
goto done;
|
||||||
|
|
||||||
if (intf->dev.driver == NULL) {
|
|
||||||
intf->dev.power.power_state.event = PM_EVENT_FREEZE;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
driver = to_usb_driver(intf->dev.driver);
|
driver = to_usb_driver(intf->dev.driver);
|
||||||
|
|
||||||
udev = interface_to_usbdev(intf);
|
udev = interface_to_usbdev(intf);
|
||||||
if (udev->state == USB_STATE_NOTATTACHED)
|
if (udev->state == USB_STATE_NOTATTACHED)
|
||||||
return 0;
|
goto done;
|
||||||
|
|
||||||
/* if driver was suspended, it has a resume method;
|
/* if driver was suspended, it has a resume method;
|
||||||
* however, sysfs can wrongly mark things as suspended
|
* however, sysfs can wrongly mark things as suspended
|
||||||
@ -845,15 +852,21 @@ static int resume_interface(struct usb_interface *intf)
|
|||||||
*/
|
*/
|
||||||
if (driver->resume) {
|
if (driver->resume) {
|
||||||
status = driver->resume(intf);
|
status = driver->resume(intf);
|
||||||
if (status) {
|
if (status)
|
||||||
dev_err(&intf->dev, "%s error %d\n",
|
dev_err(&intf->dev, "%s error %d\n",
|
||||||
"resume", status);
|
"resume", status);
|
||||||
mark_quiesced(intf);
|
else
|
||||||
}
|
mark_active(intf);
|
||||||
} else
|
} else {
|
||||||
dev_warn(&intf->dev, "no resume for driver %s?\n",
|
dev_warn(&intf->dev, "no resume for driver %s?\n",
|
||||||
driver->name);
|
driver->name);
|
||||||
return 0;
|
mark_active(intf);
|
||||||
|
}
|
||||||
|
|
||||||
|
done:
|
||||||
|
if (status == 0)
|
||||||
|
intf->dev.power.power_state.event = PM_EVENT_ON;
|
||||||
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Caller has locked udev */
|
/* Caller has locked udev */
|
||||||
|
@ -1582,9 +1582,10 @@ static int __usb_port_suspend (struct usb_device *udev, int port1)
|
|||||||
if (udev->parent)
|
if (udev->parent)
|
||||||
status = hub_port_suspend(hdev_to_hub(udev->parent), port1,
|
status = hub_port_suspend(hdev_to_hub(udev->parent), port1,
|
||||||
udev);
|
udev);
|
||||||
|
else {
|
||||||
if (status == 0)
|
dev_dbg(&udev->dev, "usb suspend\n");
|
||||||
udev->dev.power.power_state = PMSG_SUSPEND;
|
usb_set_device_state(udev, USB_STATE_SUSPENDED);
|
||||||
|
}
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1617,8 +1618,6 @@ int usb_port_suspend(struct usb_device *udev)
|
|||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
return __usb_port_suspend(udev, udev->portnum);
|
return __usb_port_suspend(udev, udev->portnum);
|
||||||
#else
|
#else
|
||||||
/* NOTE: udev->state unchanged, it's not lying ... */
|
|
||||||
udev->dev.power.power_state = PMSG_SUSPEND;
|
|
||||||
return 0;
|
return 0;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
@ -1647,7 +1646,6 @@ static int finish_port_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,
|
||||||
|
Loading…
Reference in New Issue
Block a user