]> rtime.felk.cvut.cz Git - sojka/nv-tegra/linux-3.10.git/commitdiff
usb: free up composite gadget string ids on unbind
authorRakesh Bodla <rbodla@nvidia.com>
Thu, 5 Jun 2014 06:31:12 +0000 (12:01 +0530)
committerTodd Poynter <tpoynter@nvidia.com>
Thu, 19 Jun 2014 19:10:34 +0000 (12:10 -0700)
There are only 254 USB composite gadget string_ids available.
When switching gadget mode such as mtp and acm repeatedly,
they will be exhausted.

This bug has been brought up since android composite driver
introduced a way to switch gadget modes while the composite
driver is still holding its bind.

Fix this by reset next_string_id and clean up gstrings when
android gadgets are disabled. Also by removing the condition
comparing gadgets' string id to 0 because gadget string id
has to be re-assigned whenever the string count is reset.

The codes removed the condition check will work as the same
as before they have changed if the gadgets are used by other
composite drivers other than android since all of them call
bind only once and never unbind it hence no side effects considered.

Ported from https://android-review.googlesource.com/#/c/95366/

Bug 200001941

Change-Id: I1e2fbe0f59fe05b89052db62e0b61b074d8f032b
Signed-off-by: Rakesh Bodla <rbodla@nvidia.com>
Reviewed-on: http://git-master/r/425165
Reviewed-by: Mitch Luban <mluban@nvidia.com>
drivers/usb/gadget/android.c
drivers/usb/gadget/f_accessory.c
drivers/usb/gadget/f_mass_storage.c
drivers/usb/gadget/f_mtp.c
drivers/usb/gadget/f_rndis.c

index e33641c281532310df9eb1c1e907b980da62afc8..af027f9506cb2d3ead76d007141ad4ee70e75a91 100644 (file)
@@ -100,6 +100,7 @@ struct android_dev {
        bool sw_connected;
        struct work_struct work;
        char ffs_aliases[256];
+       unsigned short ffs_string_ids;
 };
 
 static struct class *android_class;
@@ -152,6 +153,20 @@ static struct usb_configuration android_config_driver = {
        .bConfigurationValue = 1,
 };
 
+static void android_gstring_cleanup(struct android_dev *dev)
+{
+       struct usb_composite_dev *cdev = dev->cdev;
+       struct usb_gadget_string_container *uc, *tmp;
+
+       list_for_each_entry_safe(uc, tmp, &cdev->gstrings, list) {
+               list_del(&uc->list);
+               kfree(uc);
+       }
+       /* reserve unfreed string ids */
+       cdev->next_string_id = ARRAY_SIZE(strings_dev) +
+               dev->ffs_string_ids - 1;
+}
+
 static void android_work(struct work_struct *data)
 {
        struct android_dev *dev = container_of(data, struct android_dev, work);
@@ -202,6 +217,7 @@ static void android_disable(struct android_dev *dev)
                /* Cancel pending control requests */
                usb_ep_dequeue(cdev->gadget->ep0, cdev->req);
                usb_remove_config(cdev, &android_config_driver);
+               android_gstring_cleanup(dev);
        }
 }
 
@@ -327,6 +343,7 @@ static int functionfs_ready_callback(struct ffs_data *ffs)
 
        config->data = ffs;
        config->opened = true;
+       dev->ffs_string_ids = ffs->strings_count;
 
        if (config->enabled)
                android_enable(dev);
@@ -350,6 +367,7 @@ static void functionfs_closed_callback(struct ffs_data *ffs)
        config->data = NULL;
 
        functionfs_unbind(ffs);
+       dev->ffs_string_ids = 0;
 
        mutex_unlock(&dev->mutex);
 }
index f643146acb224b5284bd2a39ffdded481cdeaf18..ffb6b97223c1606a7bb20de3c1bb39baf779bc17 100644 (file)
@@ -1132,13 +1132,11 @@ static int acc_bind_config(struct usb_configuration *c)
        printk(KERN_INFO "acc_bind_config\n");
 
        /* allocate a string ID for our interface */
-       if (acc_string_defs[INTERFACE_STRING_INDEX].id == 0) {
-               ret = usb_string_id(c->cdev);
-               if (ret < 0)
-                       return ret;
-               acc_string_defs[INTERFACE_STRING_INDEX].id = ret;
-               acc_interface_desc.iInterface = ret;
-       }
+       ret = usb_string_id(c->cdev);
+       if (ret < 0)
+               return ret;
+       acc_string_defs[INTERFACE_STRING_INDEX].id = ret;
+       acc_interface_desc.iInterface = ret;
 
        dev->cdev = c->cdev;
        dev->function.name = "accessory";
index c35a9ecc576bb9a7e25724571e4c4841d0227720..832b64261c058166d96c812945238ac2b3816491 100644 (file)
@@ -2656,15 +2656,6 @@ static struct fsg_common *fsg_common_init(struct fsg_common *common,
        common->ep0req = cdev->req;
        common->cdev = cdev;
 
-       /* Maybe allocate device-global string IDs, and patch descriptors */
-       if (fsg_strings[FSG_STRING_INTERFACE].id == 0) {
-               rc = usb_string_id(cdev);
-               if (unlikely(rc < 0))
-                       goto error_release;
-               fsg_strings[FSG_STRING_INTERFACE].id = rc;
-               fsg_intf_desc.iInterface = rc;
-       }
-
        /*
         * Create the LUNs, open their backing files, and register the
         * LUN devices in sysfs.
@@ -2953,6 +2944,13 @@ static int fsg_bind_config(struct usb_composite_dev *cdev,
        struct fsg_dev *fsg;
        int rc;
 
+       /* allocate device-global string IDs, and patch descriptors */
+       rc = usb_string_id(cdev);
+       if (unlikely(rc < 0))
+               return rc;
+       fsg_strings[FSG_STRING_INTERFACE].id = rc;
+       fsg_intf_desc.iInterface = rc;
+
        fsg = kzalloc(sizeof *fsg, GFP_KERNEL);
        if (unlikely(!fsg))
                return -ENOMEM;
index 4de200a6c4915735bd51331fa36e53ca8b78d8dd..bce3e74e240c196262554a1aed9f68ab1ee02e65 100644 (file)
@@ -1256,14 +1256,11 @@ static int mtp_bind_config(struct usb_configuration *c, bool ptp_config)
 
        printk(KERN_INFO "mtp_bind_config\n");
 
-       /* allocate a string ID for our interface */
-       if (mtp_string_defs[INTERFACE_STRING_INDEX].id == 0) {
-               ret = usb_string_id(c->cdev);
-               if (ret < 0)
-                       return ret;
-               mtp_string_defs[INTERFACE_STRING_INDEX].id = ret;
-               mtp_interface_desc.iInterface = ret;
-       }
+       ret = usb_string_id(c->cdev);
+       if (ret < 0)
+               return ret;
+       mtp_string_defs[INTERFACE_STRING_INDEX].id = ret;
+       mtp_interface_desc.iInterface = ret;
 
        dev->cdev = c->cdev;
        dev->function.name = "mtp";
index e627a276a092b730f57e98abdc2b6cc9aa01cf46..fcdee12863cf945411eccaeead8ffbbcb30406ad 100644 (file)
@@ -847,15 +847,13 @@ rndis_bind_config_vendor(struct usb_configuration *c, u8 ethaddr[ETH_ALEN],
        if (status < 0)
                return status;
 
-       if (rndis_string_defs[0].id == 0) {
-               status = usb_string_ids_tab(c->cdev, rndis_string_defs);
-               if (status)
-                       return status;
-
-               rndis_control_intf.iInterface = rndis_string_defs[0].id;
-               rndis_data_intf.iInterface = rndis_string_defs[1].id;
-               rndis_iad_descriptor.iFunction = rndis_string_defs[2].id;
-       }
+       status = usb_string_ids_tab(c->cdev, rndis_string_defs);
+       if (status)
+               return status;
+
+       rndis_control_intf.iInterface = rndis_string_defs[0].id;
+       rndis_data_intf.iInterface = rndis_string_defs[1].id;
+       rndis_iad_descriptor.iFunction = rndis_string_defs[2].id;
 
        /* allocate and initialize one new instance */
        status = -ENOMEM;