Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Alan Stern and committed by
Greg Kroah-Hartman
9da82bd4 473bca94

+9 -5
+6 -5
drivers/usb/core/driver.c
··· 257 257 udev = interface_to_usbdev(intf); 258 258 error = usb_autoresume_device(udev); 259 259 260 - /* release all urbs for this interface */ 261 - usb_disable_interface(interface_to_usbdev(intf), intf); 260 + /* Terminate all URBs for this interface unless the driver 261 + * supports "soft" unbinding. 262 + */ 263 + if (!driver->soft_unbind) 264 + usb_disable_interface(udev, intf); 262 265 263 266 driver->disconnect(intf); 264 267 265 268 /* reset other interface state */ 266 - usb_set_interface(interface_to_usbdev(intf), 267 - intf->altsetting[0].desc.bInterfaceNumber, 268 - 0); 269 + usb_set_interface(udev, intf->altsetting[0].desc.bInterfaceNumber, 0); 269 270 usb_set_intfdata(intf, NULL); 270 271 271 272 intf->condition = USB_INTERFACE_UNBOUND;
+3
include/linux/usb.h
··· 972 972 * added to this driver by preventing the sysfs file from being created. 973 973 * @supports_autosuspend: if set to 0, the USB core will not allow autosuspend 974 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 978 * USB interface drivers must provide a name, probe() and disconnect() 977 979 * methods, and an id_table. Other driver fields are optional. ··· 1014 1012 struct usbdrv_wrap drvwrap; 1015 1013 unsigned int no_dynamic_id:1; 1016 1014 unsigned int supports_autosuspend:1; 1015 + unsigned int soft_unbind:1; 1017 1016 }; 1018 1017 #define to_usb_driver(d) container_of(d, struct usb_driver, drvwrap.driver) 1019 1018