summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBenoit Goby <benoit@android.com>2012-05-10 10:07:57 +0200
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2012-05-10 12:21:32 -0700
commit51cce6fc155c4d7eea2ff975ee7c82b89332c6d9 (patch)
tree08272c25d5e7dfb95df2261699f44ad4eb4da60e
parent56d95f3174450d22a3b8d936bea2cb414262ce8f (diff)
usb: gadget: composite: Add usb_remove_config
Add usb_remove_config to unbind a configuration and remove it from the configs list. This allows implementing composite gadget drivers that can disconnect themself from the bus and that will later be re-enumerated with a different configuration. Gadget drivers must call usb_gadget_disconnect before calling this function to disable the pullup, disconnect the device from the host, and prevent the host from enumerating the device while we are changing the gadget configuration. Signed-off-by: Benoit Goby <benoit@android.com> [change return type of [usb_]remove_config] Signed-off-by: Andrzej Pietrasiewicz <andrzej.p@samsung.com> Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com> Acked-by: Michal Nazarewicz <mina86@mina86.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--drivers/usb/gadget/composite.c68
-rw-r--r--include/linux/usb/composite.h3
2 files changed, 51 insertions, 20 deletions
diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c
index a3b19fe37f5..e51b2314f5c 100644
--- a/drivers/usb/gadget/composite.c
+++ b/drivers/usb/gadget/composite.c
@@ -787,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
@@ -1341,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);
diff --git a/include/linux/usb/composite.h b/include/linux/usb/composite.h
index a316fba7351..5d27a1fe5ce 100644
--- a/include/linux/usb/composite.h
+++ b/include/linux/usb/composite.h
@@ -242,6 +242,9 @@ int usb_add_config(struct usb_composite_dev *,
struct usb_configuration *,
int (*)(struct usb_configuration *));
+void 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.