Skip to content

Commit

Permalink
usb: gadget: composite: Add usb_remove_config
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Benoit Goby authored and Greg Kroah-Hartman committed May 10, 2012
1 parent 56d95f3 commit 51cce6f
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 20 deletions.
68 changes: 48 additions & 20 deletions drivers/usb/gadget/composite.c
Original file line number Diff line number Diff line change
Expand Up @@ -787,6 +787,53 @@ int usb_add_config(struct usb_composite_dev *cdev,
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
Expand Down Expand Up @@ -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);
Expand Down
3 changes: 3 additions & 0 deletions include/linux/usb/composite.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down

0 comments on commit 51cce6f

Please sign in to comment.