diff options
author | Benoit Goby <benoit@android.com> | 2011-05-25 23:59:43 -0700 |
---|---|---|
committer | Dan Willemsen <dwillemsen@nvidia.com> | 2011-11-30 21:38:41 -0800 |
commit | d74a4a005ef4fd02a5fef4e7565fc7c09fad1136 (patch) | |
tree | 3c3f6b3a724a0e380a9e62d317aca32cac1d5937 /drivers/usb/gadget | |
parent | b474bbbd4844d36dbc41775a559cde3375f0eefe (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.c | 60 |
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); |