usb: gadget: composite: Add usb_remove_config
authorBenoit Goby <benoit@android.com>
Thu, 26 May 2011 06:59:43 +0000 (23:59 -0700)
committerBenoit Goby <benoit@android.com>
Fri, 17 Jun 2011 23:02:36 +0000 (16:02 -0700)
This allows composite drivers to dynamically change their configuration.
For example, a driver might remove a configuration and register a new
one with a different set of functions.
User should prevent the host from enumerating the device while changing
the configuration:

usb_gadget_disconnect(cdev->gadget);
usb_remove_config(cdev, old_config);
usb_add_config(cdev, new_config, new_conf_bind);
usb_gadget_connect(cdev->gadget);

Change-Id: Icbfb4ce41685fde9bf63d5d58fca1ad242aa69f9
Signed-off-by: Benoit Goby <benoit@android.com>
drivers/usb/gadget/composite.c
include/linux/usb/composite.h

index c9ae8bba6962d1bd5eb6f0edd7733c8aaca27145..6c8fbb18a1e85f7ca4eb17ca10115bbf0ae64874 100644 (file)
@@ -667,6 +667,45 @@ done:
        return status;
 }
 
+static int remove_config(struct usb_composite_dev *cdev,
+                             struct usb_configuration *config)
+{
+       while (!list_empty(&config->functions)) {
+               struct usb_function             *f;
+
+               f = list_first_entry(&config->functions,
+                               struct usb_function, list);
+               list_del(&f->list);
+               if (f->unbind) {
+                       DBG(cdev, "unbind function '%s'/%p\n", f->name, f);
+                       f->unbind(config, f);
+                       /* may free memory for "f" */
+               }
+       }
+       list_del(&config->list);
+       if (config->unbind) {
+               DBG(cdev, "unbind config '%s'/%p\n", config->label, config);
+               config->unbind(config);
+                       /* may free memory for "c" */
+       }
+       return 0;
+}
+
+int usb_remove_config(struct usb_composite_dev *cdev,
+                     struct usb_configuration *config)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&cdev->lock, flags);
+
+       if (cdev->config == config)
+               reset_config(cdev);
+
+       spin_unlock_irqrestore(&cdev->lock, flags);
+
+       return remove_config(cdev, config);
+}
+
 /*-------------------------------------------------------------------------*/
 
 /* We support strings in multiple languages ... string descriptor zero
@@ -1192,28 +1231,9 @@ composite_unbind(struct usb_gadget *gadget)
 
        while (!list_empty(&cdev->configs)) {
                struct usb_configuration        *c;
-
                c = list_first_entry(&cdev->configs,
                                struct usb_configuration, list);
-               while (!list_empty(&c->functions)) {
-                       struct usb_function             *f;
-
-                       f = list_first_entry(&c->functions,
-                                       struct usb_function, list);
-                       list_del(&f->list);
-                       if (f->unbind) {
-                               DBG(cdev, "unbind function '%s'/%p\n",
-                                               f->name, f);
-                               f->unbind(c, f);
-                               /* may free memory for "f" */
-                       }
-               }
-               list_del(&c->list);
-               if (c->unbind) {
-                       DBG(cdev, "unbind config '%s'/%p\n", c->label, c);
-                       c->unbind(c);
-                       /* may free memory for "c" */
-               }
+               remove_config(cdev, c);
        }
        if (composite->unbind)
                composite->unbind(cdev);
index 106c69c7d1a6c061d01b6946d20e40c9fabb616e..d00ab9503adb60e9dee4a6333353715bb6e0f2f5 100644 (file)
@@ -249,6 +249,9 @@ int usb_add_config(struct usb_composite_dev *,
                struct usb_configuration *,
                int (*)(struct usb_configuration *));
 
+int usb_remove_config(struct usb_composite_dev *,
+               struct usb_configuration *);
+
 /**
  * struct usb_composite_driver - groups configurations into a gadget
  * @name: For diagnostics, identifies the driver.