usb: gadget: composite: Add usb_remove_config
[deliverable/linux.git] / drivers / usb / gadget / composite.c
index a95de6a4a13447d3217d7495bcd94079bca04903..e51b2314f5c9d433039ef03aed4b1c2fdf3263e2 100644 (file)
@@ -175,13 +175,12 @@ ep_found:
        _ep->comp_desc = comp_desc;
        if (g->speed == USB_SPEED_SUPER) {
                switch (usb_endpoint_type(_ep->desc)) {
-               case USB_ENDPOINT_XFER_BULK:
-               case USB_ENDPOINT_XFER_INT:
-                       _ep->maxburst = comp_desc->bMaxBurst;
-                       break;
                case USB_ENDPOINT_XFER_ISOC:
                        /* mult: bits 1:0 of bmAttributes */
                        _ep->mult = comp_desc->bmAttributes & 0x3;
+               case USB_ENDPOINT_XFER_BULK:
+               case USB_ENDPOINT_XFER_INT:
+                       _ep->maxburst = comp_desc->bMaxBurst;
                        break;
                default:
                        /* Do nothing for control endpoints */
@@ -738,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 {
@@ -775,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
@@ -786,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) {
@@ -1329,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.028049 seconds and 5 git commands to generate.