diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c index 0a0e8cea0afc6d84fc822cd4cac0642cdba6592f..8da1a56659be48e789d47f328d83a591e99e1160 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) udev = interface_to_usbdev(intf); error = usb_autoresume_device(udev); - /* release all urbs for this interface */ - usb_disable_interface(interface_to_usbdev(intf), intf); + /* Terminate all URBs for this interface unless the driver + * supports "soft" unbinding. + */ + if (!driver->soft_unbind) + usb_disable_interface(udev, intf); driver->disconnect(intf); /* reset other interface state */ - usb_set_interface(interface_to_usbdev(intf), - intf->altsetting[0].desc.bInterfaceNumber, - 0); + usb_set_interface(udev, intf->altsetting[0].desc.bInterfaceNumber, 0); usb_set_intfdata(intf, NULL); intf->condition = USB_INTERFACE_UNBOUND; diff --git a/include/linux/usb.h b/include/linux/usb.h index cee7fbb2b605112d6ce2e933f4b3420aaef1f54c..8429d08bd2fd7ac0d2c62b264677d33a9c2788d5 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h @@ -972,6 +972,8 @@ struct usbdrv_wrap { * added to this driver by preventing the sysfs file from being created. * @supports_autosuspend: if set to 0, the USB core will not allow autosuspend * for interfaces bound to this driver. + * @soft_unbind: if set to 1, the USB core will not kill URBs and disable + * endpoints before calling the driver's disconnect method. * * USB interface drivers must provide a name, probe() and disconnect() * methods, and an id_table. Other driver fields are optional. @@ -1012,6 +1014,7 @@ struct usb_driver { struct usbdrv_wrap drvwrap; unsigned int no_dynamic_id:1; unsigned int supports_autosuspend:1; + unsigned int soft_unbind:1; }; #define to_usb_driver(d) container_of(d, struct usb_driver, drvwrap.driver)