Commit 55151d7d authored by Alan Stern's avatar Alan Stern Committed by Greg Kroah-Hartman

USB: Defer Set-Interface for suspended devices

This patch (as1128) fixes one of the problems related to the new PM
infrastructure.  We are not allowed to register new child devices
during the middle of a system sleep transition, but unbinding a USB
driver causes the core to automatically install altsetting 0 and
thereby create new endpoint pseudo-devices.

The patch fixes this problem (and the related problem that installing
altsetting 0 will fail if the device is suspended) by deferring the
Set-Interface call until some later time when it is legal and can
succeed.  Possible later times are: when a new driver is being probed
for the interface, and when the interface is being resumed.
Signed-off-by: default avatarAlan Stern <stern@rowland.harvard.edu>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent 65605ae8
......@@ -230,6 +230,13 @@ static int usb_probe_interface(struct device *dev)
*/
intf->pm_usage_cnt = !(driver->supports_autosuspend);
/* Carry out a deferred switch to altsetting 0 */
if (intf->needs_altsetting0) {
usb_set_interface(udev, intf->altsetting[0].
desc.bInterfaceNumber, 0);
intf->needs_altsetting0 = 0;
}
error = driver->probe(intf, id);
if (error) {
mark_quiesced(intf);
......@@ -266,8 +273,17 @@ static int usb_unbind_interface(struct device *dev)
driver->disconnect(intf);
/* reset other interface state */
usb_set_interface(udev, intf->altsetting[0].desc.bInterfaceNumber, 0);
/* Reset other interface state.
* We cannot do a Set-Interface if the device is suspended or
* if it is prepared for a system sleep (since installing a new
* altsetting means creating new endpoint device entries).
* When either of these happens, defer the Set-Interface.
*/
if (!error && intf->dev.power.status == DPM_ON)
usb_set_interface(udev, intf->altsetting[0].
desc.bInterfaceNumber, 0);
else
intf->needs_altsetting0 = 1;
usb_set_intfdata(intf, NULL);
intf->condition = USB_INTERFACE_UNBOUND;
......@@ -975,8 +991,17 @@ static int usb_resume_interface(struct usb_device *udev,
goto done;
/* Can't resume it if it doesn't have a driver. */
if (intf->condition == USB_INTERFACE_UNBOUND)
if (intf->condition == USB_INTERFACE_UNBOUND) {
/* Carry out a deferred switch to altsetting 0 */
if (intf->needs_altsetting0 &&
intf->dev.power.status == DPM_ON) {
usb_set_interface(udev, intf->altsetting[0].
desc.bInterfaceNumber, 0);
intf->needs_altsetting0 = 0;
}
goto done;
}
/* Don't resume if the interface is marked for rebinding */
if (intf->needs_binding)
......
......@@ -110,6 +110,8 @@ enum usb_interface_condition {
* @sysfs_files_created: sysfs attributes exist
* @needs_remote_wakeup: flag set when the driver requires remote-wakeup
* capability during autosuspend.
* @needs_altsetting0: flag set when a set-interface request for altsetting 0
* has been deferred.
* @needs_binding: flag set when the driver should be re-probed or unbound
* following a reset or suspend operation it doesn't support.
* @dev: driver model's view of this device
......@@ -162,6 +164,7 @@ struct usb_interface {
unsigned is_active:1; /* the interface is not suspended */
unsigned sysfs_files_created:1; /* the sysfs attributes exist */
unsigned needs_remote_wakeup:1; /* driver requires remote wakeup */
unsigned needs_altsetting0:1; /* switch to altsetting 0 is pending */
unsigned needs_binding:1; /* needs delayed unbind/rebind */
struct device dev; /* interface specific device info */
......
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