usb: gadget: composite: Add usb_remove_config
[deliverable/linux.git] / drivers / usb / gadget / composite.c
index baaebf2830fce882022801f7a492a01c4b9f4c79..e51b2314f5c9d433039ef03aed4b1c2fdf3263e2 100644 (file)
@@ -737,6 +737,19 @@ int usb_add_config(struct usb_composite_dev *cdev,
 
        status = bind(config);
        if (status < 0) {
+               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);
                config->cdev = NULL;
        } else {
@@ -774,6 +787,53 @@ done:
        return status;
 }
 
+static void 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" */
+       }
+}
+
+/**
+ * usb_remove_config() - remove a configuration from a device.
+ * @cdev: wraps the USB gadget
+ * @config: the configuration
+ *
+ * Drivers must call usb_gadget_disconnect before calling this function
+ * to disconnect the device from the host and make sure the host will not
+ * try to enumerate the device while we are changing the config list.
+ */
+void 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);
+
+       remove_config(cdev, config);
+}
+
 /*-------------------------------------------------------------------------*/
 
 /* We support strings in multiple languages ... string descriptor zero
@@ -785,7 +845,7 @@ done:
 static void collect_langs(struct usb_gadget_strings **sp, __le16 *buf)
 {
        const struct usb_gadget_strings *s;
-       u16                             language;
+       __le16                          language;
        __le16                          *tmp;
 
        while (*sp) {
@@ -1328,28 +1388,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);
This page took 0.02525 seconds and 5 git commands to generate.