|
@@ -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);
|