aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorAlan Stern <stern@rowland.harvard.edu>2008-08-12 14:33:59 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2008-08-21 13:26:36 -0400
commit55151d7daba185f94e9dc561a5a2ba36b5f647dd (patch)
treea769ff8a82367c8767d03c733278a078536e0945 /drivers
parent65605ae8e587d714f73e674369bc4cd5a1e53a9b (diff)
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: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/usb/core/driver.c31
1 files changed, 28 insertions, 3 deletions
diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c
index ed1cc8530a93..637b2bea5563 100644
--- a/drivers/usb/core/driver.c
+++ b/drivers/usb/core/driver.c
@@ -230,6 +230,13 @@ static int usb_probe_interface(struct device *dev)
230 */ 230 */
231 intf->pm_usage_cnt = !(driver->supports_autosuspend); 231 intf->pm_usage_cnt = !(driver->supports_autosuspend);
232 232
233 /* Carry out a deferred switch to altsetting 0 */
234 if (intf->needs_altsetting0) {
235 usb_set_interface(udev, intf->altsetting[0].
236 desc.bInterfaceNumber, 0);
237 intf->needs_altsetting0 = 0;
238 }
239
233 error = driver->probe(intf, id); 240 error = driver->probe(intf, id);
234 if (error) { 241 if (error) {
235 mark_quiesced(intf); 242 mark_quiesced(intf);
@@ -266,8 +273,17 @@ static int usb_unbind_interface(struct device *dev)
266 273
267 driver->disconnect(intf); 274 driver->disconnect(intf);
268 275
269 /* reset other interface state */ 276 /* Reset other interface state.
270 usb_set_interface(udev, intf->altsetting[0].desc.bInterfaceNumber, 0); 277 * We cannot do a Set-Interface if the device is suspended or
278 * if it is prepared for a system sleep (since installing a new
279 * altsetting means creating new endpoint device entries).
280 * When either of these happens, defer the Set-Interface.
281 */
282 if (!error && intf->dev.power.status == DPM_ON)
283 usb_set_interface(udev, intf->altsetting[0].
284 desc.bInterfaceNumber, 0);
285 else
286 intf->needs_altsetting0 = 1;
271 usb_set_intfdata(intf, NULL); 287 usb_set_intfdata(intf, NULL);
272 288
273 intf->condition = USB_INTERFACE_UNBOUND; 289 intf->condition = USB_INTERFACE_UNBOUND;
@@ -975,8 +991,17 @@ static int usb_resume_interface(struct usb_device *udev,
975 goto done; 991 goto done;
976 992
977 /* Can't resume it if it doesn't have a driver. */ 993 /* Can't resume it if it doesn't have a driver. */
978 if (intf->condition == USB_INTERFACE_UNBOUND) 994 if (intf->condition == USB_INTERFACE_UNBOUND) {
995
996 /* Carry out a deferred switch to altsetting 0 */
997 if (intf->needs_altsetting0 &&
998 intf->dev.power.status == DPM_ON) {
999 usb_set_interface(udev, intf->altsetting[0].
1000 desc.bInterfaceNumber, 0);
1001 intf->needs_altsetting0 = 0;
1002 }
979 goto done; 1003 goto done;
1004 }
980 1005
981 /* Don't resume if the interface is marked for rebinding */ 1006 /* Don't resume if the interface is marked for rebinding */
982 if (intf->needs_binding) 1007 if (intf->needs_binding)