diff options
| -rw-r--r-- | drivers/usb/core/driver.c | 31 | ||||
| -rw-r--r-- | include/linux/usb.h | 3 |
2 files changed, 31 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) |
diff --git a/include/linux/usb.h b/include/linux/usb.h index 0924cd9c30f6..94ac74aba6b6 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h | |||
| @@ -110,6 +110,8 @@ enum usb_interface_condition { | |||
| 110 | * @sysfs_files_created: sysfs attributes exist | 110 | * @sysfs_files_created: sysfs attributes exist |
| 111 | * @needs_remote_wakeup: flag set when the driver requires remote-wakeup | 111 | * @needs_remote_wakeup: flag set when the driver requires remote-wakeup |
| 112 | * capability during autosuspend. | 112 | * capability during autosuspend. |
| 113 | * @needs_altsetting0: flag set when a set-interface request for altsetting 0 | ||
| 114 | * has been deferred. | ||
| 113 | * @needs_binding: flag set when the driver should be re-probed or unbound | 115 | * @needs_binding: flag set when the driver should be re-probed or unbound |
| 114 | * following a reset or suspend operation it doesn't support. | 116 | * following a reset or suspend operation it doesn't support. |
| 115 | * @dev: driver model's view of this device | 117 | * @dev: driver model's view of this device |
| @@ -162,6 +164,7 @@ struct usb_interface { | |||
| 162 | unsigned is_active:1; /* the interface is not suspended */ | 164 | unsigned is_active:1; /* the interface is not suspended */ |
| 163 | unsigned sysfs_files_created:1; /* the sysfs attributes exist */ | 165 | unsigned sysfs_files_created:1; /* the sysfs attributes exist */ |
| 164 | unsigned needs_remote_wakeup:1; /* driver requires remote wakeup */ | 166 | unsigned needs_remote_wakeup:1; /* driver requires remote wakeup */ |
| 167 | unsigned needs_altsetting0:1; /* switch to altsetting 0 is pending */ | ||
| 165 | unsigned needs_binding:1; /* needs delayed unbind/rebind */ | 168 | unsigned needs_binding:1; /* needs delayed unbind/rebind */ |
| 166 | 169 | ||
| 167 | struct device dev; /* interface specific device info */ | 170 | struct device dev; /* interface specific device info */ |
