usb: gadget: configfs: Attach arbitrary strings to cdev
authorDaniel Scally <dan.scally@ideasonboard.com>
Mon, 6 Feb 2023 16:17:58 +0000 (16:17 +0000)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 7 Feb 2023 07:46:36 +0000 (08:46 +0100)
Attach any arbitrary strings that are defined to the composite dev.
We handle the old-style manufacturer, product and serialnumbers
strings in the same function for simplicity.

Signed-off-by: Daniel Scally <dan.scally@ideasonboard.com>
Link: https://lore.kernel.org/r/20230206161802.892954-8-dan.scally@ideasonboard.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/usb/gadget/configfs.c
include/linux/usb/composite.h

index ac275855eeb68a53f580f5dd0693ad8d2e3c8ccf..06a0b73e0546540f683a63a3c93ff86847f52cd6 100644 (file)
@@ -1597,6 +1597,80 @@ static void purge_configs_funcs(struct gadget_info *gi)
        }
 }
 
+static struct usb_string *
+configfs_attach_gadget_strings(struct gadget_info *gi)
+{
+       struct usb_gadget_strings **gadget_strings;
+       struct gadget_language *language;
+       struct gadget_string *string;
+       unsigned int nlangs = 0;
+       struct list_head *iter;
+       struct usb_string *us;
+       unsigned int i = 0;
+       int nstrings = -1;
+       unsigned int j;
+
+       list_for_each(iter, &gi->string_list)
+               nlangs++;
+
+       /* Bail out early if no languages are configured */
+       if (!nlangs)
+               return NULL;
+
+       gadget_strings = kcalloc(nlangs + 1, /* including NULL terminator */
+                                sizeof(struct usb_gadget_strings *), GFP_KERNEL);
+       if (!gadget_strings)
+               return ERR_PTR(-ENOMEM);
+
+       list_for_each_entry(language, &gi->string_list, list) {
+               struct usb_string *stringtab;
+
+               if (nstrings == -1) {
+                       nstrings = language->nstrings;
+               } else if (nstrings != language->nstrings) {
+                       pr_err("languages must contain the same number of strings\n");
+                       us = ERR_PTR(-EINVAL);
+                       goto cleanup;
+               }
+
+               stringtab = kcalloc(language->nstrings + 1, sizeof(struct usb_string),
+                                   GFP_KERNEL);
+               if (!stringtab) {
+                       us = ERR_PTR(-ENOMEM);
+                       goto cleanup;
+               }
+
+               stringtab[USB_GADGET_MANUFACTURER_IDX].id = USB_GADGET_MANUFACTURER_IDX;
+               stringtab[USB_GADGET_MANUFACTURER_IDX].s = language->manufacturer;
+               stringtab[USB_GADGET_PRODUCT_IDX].id = USB_GADGET_PRODUCT_IDX;
+               stringtab[USB_GADGET_PRODUCT_IDX].s = language->product;
+               stringtab[USB_GADGET_SERIAL_IDX].id = USB_GADGET_SERIAL_IDX;
+               stringtab[USB_GADGET_SERIAL_IDX].s = language->serialnumber;
+
+               j = USB_GADGET_FIRST_AVAIL_IDX;
+               list_for_each_entry(string, &language->gadget_strings, list) {
+                       memcpy(&stringtab[j], &string->usb_string, sizeof(struct usb_string));
+                       j++;
+               }
+
+               language->stringtab_dev.strings = stringtab;
+               gadget_strings[i] = &language->stringtab_dev;
+               i++;
+       }
+
+       us = usb_gstrings_attach(&gi->cdev, gadget_strings, nstrings);
+
+cleanup:
+       list_for_each_entry(language, &gi->string_list, list) {
+               kfree(language->stringtab_dev.strings);
+               language->stringtab_dev.strings = NULL;
+       }
+
+       kfree(gadget_strings);
+
+       return us;
+}
+
 static int configfs_composite_bind(struct usb_gadget *gadget,
                struct usb_gadget_driver *gdriver)
 {
@@ -1640,22 +1714,7 @@ static int configfs_composite_bind(struct usb_gadget *gadget,
 
        /* init all strings */
        if (!list_empty(&gi->string_list)) {
-               struct gadget_language *gs;
-
-               i = 0;
-               list_for_each_entry(gs, &gi->string_list, list) {
-
-                       gi->gstrings[i] = &gs->stringtab_dev;
-                       gs->stringtab_dev.strings = gs->strings;
-                       gs->strings[USB_GADGET_MANUFACTURER_IDX].s =
-                               gs->manufacturer;
-                       gs->strings[USB_GADGET_PRODUCT_IDX].s = gs->product;
-                       gs->strings[USB_GADGET_SERIAL_IDX].s = gs->serialnumber;
-                       i++;
-               }
-               gi->gstrings[i] = NULL;
-               s = usb_gstrings_attach(&gi->cdev, gi->gstrings,
-                               USB_GADGET_FIRST_AVAIL_IDX);
+               s = configfs_attach_gadget_strings(gi);
                if (IS_ERR(s)) {
                        ret = PTR_ERR(s);
                        goto err_comp_cleanup;
@@ -1664,6 +1723,8 @@ static int configfs_composite_bind(struct usb_gadget *gadget,
                gi->cdev.desc.iManufacturer = s[USB_GADGET_MANUFACTURER_IDX].id;
                gi->cdev.desc.iProduct = s[USB_GADGET_PRODUCT_IDX].id;
                gi->cdev.desc.iSerialNumber = s[USB_GADGET_SERIAL_IDX].id;
+
+               gi->cdev.usb_strings = s;
        }
 
        if (gi->use_webusb) {
index 7ef8cea67f5053ce27f8c928dd0cf9fa5e084bb6..608dc962748bcb3c301ad603ad927d1f3fc93ff9 100644 (file)
@@ -494,6 +494,7 @@ struct usb_composite_dev {
        struct usb_composite_driver     *driver;
        u8                              next_string_id;
        char                            *def_manufacturer;
+       struct usb_string               *usb_strings;
 
        /* the gadget driver won't enable the data pullup
         * while the deactivation count is nonzero.