aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlan Stern <stern@rowland.harvard.edu>2008-05-08 11:54:37 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2008-07-21 18:15:54 -0400
commit9da82bd4649334817ef0e752a69eb99051645dad (patch)
tree490d3696b4a266e9b41a3624cdce4222057b7549
parent473bca94ba432b3c194e6fa315d81d8ac7670a4f (diff)
USB: implement "soft" unbinding
This patch (as1091) changes the way usbcore handles interface unbinding. If the interface's driver supports "soft" unbinding (a new flag in the driver structure) then in-flight URBs are not cancelled and endpoints are not disabled. Instead the driver is allowed to continue communicating with the device (although of course it should stop before its disconnect routine returns). The purpose of this change is to allow drivers to do a clean shutdown when they get unbound from a device that is still plugged in. Killing all the URBs and disabling the endpoints before calling the driver's disconnect method doesn't give the driver any control over what happens, and it can leave devices in indeterminate states. For example, when usb-storage unbinds it doesn't want to stop while in the middle of transmitting a SCSI command. The soft_unbind flag is added because in the past, a number of drivers have experienced problems related to ongoing I/O after their disconnect routine returned. Hence "soft" unbinding is made available only to drivers that claim to support it. The patch also replaces "interface_to_usbdev(intf)" with "udev" in a couple of places, a minor simplification. Signed-off-by: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
-rw-r--r--drivers/usb/core/driver.c11
-rw-r--r--include/linux/usb.h3
2 files changed, 9 insertions, 5 deletions
diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c
index 0a0e8cea0afc..8da1a56659be 100644
--- a/drivers/usb/core/driver.c
+++ b/drivers/usb/core/driver.c
@@ -257,15 +257,16 @@ static int usb_unbind_interface(struct device *dev)
257 udev = interface_to_usbdev(intf); 257 udev = interface_to_usbdev(intf);
258 error = usb_autoresume_device(udev); 258 error = usb_autoresume_device(udev);
259 259
260 /* release all urbs for this interface */ 260 /* Terminate all URBs for this interface unless the driver
261 usb_disable_interface(interface_to_usbdev(intf), intf); 261 * supports "soft" unbinding.
262 */
263 if (!driver->soft_unbind)
264 usb_disable_interface(udev, intf);
262 265
263 driver->disconnect(intf); 266 driver->disconnect(intf);
264 267
265 /* reset other interface state */ 268 /* reset other interface state */
266 usb_set_interface(interface_to_usbdev(intf), 269 usb_set_interface(udev, intf->altsetting[0].desc.bInterfaceNumber, 0);
267 intf->altsetting[0].desc.bInterfaceNumber,
268 0);
269 usb_set_intfdata(intf, NULL); 270 usb_set_intfdata(intf, NULL);
270 271
271 intf->condition = USB_INTERFACE_UNBOUND; 272 intf->condition = USB_INTERFACE_UNBOUND;
diff --git a/include/linux/usb.h b/include/linux/usb.h
index cee7fbb2b605..8429d08bd2fd 100644
--- a/include/linux/usb.h
+++ b/include/linux/usb.h
@@ -972,6 +972,8 @@ struct usbdrv_wrap {
972 * added to this driver by preventing the sysfs file from being created. 972 * added to this driver by preventing the sysfs file from being created.
973 * @supports_autosuspend: if set to 0, the USB core will not allow autosuspend 973 * @supports_autosuspend: if set to 0, the USB core will not allow autosuspend
974 * for interfaces bound to this driver. 974 * for interfaces bound to this driver.
975 * @soft_unbind: if set to 1, the USB core will not kill URBs and disable
976 * endpoints before calling the driver's disconnect method.
975 * 977 *
976 * USB interface drivers must provide a name, probe() and disconnect() 978 * USB interface drivers must provide a name, probe() and disconnect()
977 * methods, and an id_table. Other driver fields are optional. 979 * methods, and an id_table. Other driver fields are optional.
@@ -1012,6 +1014,7 @@ struct usb_driver {
1012 struct usbdrv_wrap drvwrap; 1014 struct usbdrv_wrap drvwrap;
1013 unsigned int no_dynamic_id:1; 1015 unsigned int no_dynamic_id:1;
1014 unsigned int supports_autosuspend:1; 1016 unsigned int supports_autosuspend:1;
1017 unsigned int soft_unbind:1;
1015}; 1018};
1016#define to_usb_driver(d) container_of(d, struct usb_driver, drvwrap.driver) 1019#define to_usb_driver(d) container_of(d, struct usb_driver, drvwrap.driver)
1017 1020