From 65fce4d63756c1ad878e93c696e02f96faa43ddf Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Tue, 12 Aug 2008 14:33:59 -0400 Subject: [PATCH] --- yaml --- r: 108977 b: refs/heads/master c: 55151d7daba185f94e9dc561a5a2ba36b5f647dd h: refs/heads/master i: 108975: c29b5cf30201f9c7c25fa7df27db8f46207baf41 v: v3 --- [refs] | 2 +- trunk/drivers/usb/core/driver.c | 31 ++++++++++++++++++++++++++++--- trunk/include/linux/usb.h | 3 +++ 3 files changed, 32 insertions(+), 4 deletions(-) diff --git a/[refs] b/[refs] index f5f4d4e9d455..7536e132239e 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: 65605ae8e587d714f73e674369bc4cd5a1e53a9b +refs/heads/master: 55151d7daba185f94e9dc561a5a2ba36b5f647dd diff --git a/trunk/drivers/usb/core/driver.c b/trunk/drivers/usb/core/driver.c index ed1cc8530a93..637b2bea5563 100644 --- a/trunk/drivers/usb/core/driver.c +++ b/trunk/drivers/usb/core/driver.c @@ -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) diff --git a/trunk/include/linux/usb.h b/trunk/include/linux/usb.h index 0924cd9c30f6..94ac74aba6b6 100644 --- a/trunk/include/linux/usb.h +++ b/trunk/include/linux/usb.h @@ -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 */