summaryrefslogtreecommitdiff
path: root/drivers/usb/gadget
diff options
context:
space:
mode:
authorBenoit Goby <benoit@android.com>2011-05-25 23:59:43 -0700
committerDan Willemsen <dwillemsen@nvidia.com>2011-11-30 21:38:41 -0800
commitd74a4a005ef4fd02a5fef4e7565fc7c09fad1136 (patch)
tree3c3f6b3a724a0e380a9e62d317aca32cac1d5937 /drivers/usb/gadget
parentb474bbbd4844d36dbc41775a559cde3375f0eefe (diff)
usb: gadget: composite: Add usb_remove_config
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>
Diffstat (limited to 'drivers/usb/gadget')
-rw-r--r--drivers/usb/gadget/composite.c60
1 files changed, 40 insertions, 20 deletions
diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c
index 5c06de61269a..98d0e3082342 100644
--- a/drivers/usb/gadget/composite.c
+++ b/drivers/usb/gadget/composite.c
@@ -904,6 +904,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
@@ -1504,28 +1543,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);