The kernel supports the device authorization because of wireless USB. These is usable for wired USB devices, too. These new interface authorization allows to enable or disable individual interfaces instead a whole device. To avoid side effects the driver probing process for the interface and it's siblings is triggered after each authorization. Signed-off-by: Stefan Koch <skoch@xxxxxxx> --- drivers/usb/core/hub.c | 77 +++++++++++++++++++++++++++++++++++++++++++++++++- drivers/usb/core/usb.h | 2 ++ 2 files changed, 78 insertions(+), 1 deletion(-) diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 3b71516..6837281 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -2528,6 +2528,82 @@ out_unauthorized: return 0; } +/* + * usb_deauthorize_interface - deauthorize an USB interface + * + * @intf: USB interface structure + * + * Returns: 0 at success, <0 at failure + */ +int usb_deauthorize_interface(struct usb_interface *intf) +{ + struct device *dev = &intf->dev; + + if (!dev || !dev->parent) + return -ENODEV; + + device_lock(dev->parent); + + if (intf->authorized) { + intf->unregistering = 1; + intf->authorized = 0; + usb_forced_unbind_intf(intf); + } + + device_unlock(dev->parent); + + return 0; +} + +/* + * usb_authorize_interface - authorize an USB interface + * + * @intf: USB interface structure + * + * Returns: 0 at success, <0 at failure + */ +int usb_authorize_interface(struct usb_interface *intf) +{ + struct device *dev = &intf->dev; + struct usb_device *usb_pdev; + unsigned i, n; + struct usb_host_config *actconfig; + + if (!dev->parent) + return -ENODEV; + + device_lock(dev->parent); + usb_pdev = to_usb_device(dev->parent); + + if (!usb_pdev || !usb_pdev->actconfig) { + device_unlock(dev->parent); + return -ENODEV; + } + + actconfig = usb_pdev->actconfig; + + if (!intf->authorized) { + intf->authorized = 1; /* authorize interface */ + + /* number of device's interfaces */ + n = actconfig->desc.bNumInterfaces; + + /* + * probe all interfaces to ensure correct binding + * of drivers with multiple interfaces + */ + for (i = 0; i < n; i++) { + struct usb_interface *intf = actconfig->interface[i]; + + if (intf) + bus_probe_device(&intf->dev); + } + } + + device_unlock(dev->parent); + + return 0; +} int usb_authorize_device(struct usb_device *usb_dev) { @@ -2577,7 +2653,6 @@ out_authorized: return result; } - /* Returns 1 if @hub is a WUSB root hub, 0 otherwise */ static unsigned hub_is_wusb(struct usb_hub *hub) { diff --git a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h index 7eb1e26..37b0055 100644 --- a/drivers/usb/core/usb.h +++ b/drivers/usb/core/usb.h @@ -27,6 +27,8 @@ extern void usb_release_interface_cache(struct kref *ref); extern void usb_disable_device(struct usb_device *dev, int skip_ep0); extern int usb_deauthorize_device(struct usb_device *); extern int usb_authorize_device(struct usb_device *); +extern int usb_deauthorize_interface(struct usb_interface *); +extern int usb_authorize_interface(struct usb_interface *); extern void usb_detect_quirks(struct usb_device *udev); extern void usb_detect_interface_quirks(struct usb_device *udev); extern int usb_remove_device(struct usb_device *udev); -- 2.1.4 -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html