diff options
author | Daniel Scally <dan.scally@ideasonboard.com> | 2023-02-06 17:17:58 +0100 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2023-02-07 08:46:36 +0100 |
commit | c033563220e0f7a82f4ae8d698284cced94fd6cf (patch) | |
tree | 1003623500505a1b8c8196291909be0230af097d /drivers/usb/gadget | |
parent | usb: gadget: configfs: Support arbitrary string descriptors (diff) | |
download | linux-c033563220e0f7a82f4ae8d698284cced94fd6cf.tar.xz linux-c033563220e0f7a82f4ae8d698284cced94fd6cf.zip |
usb: gadget: configfs: Attach arbitrary strings to cdev
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>
Diffstat (limited to 'drivers/usb/gadget')
-rw-r--r-- | drivers/usb/gadget/configfs.c | 93 |
1 files changed, 77 insertions, 16 deletions
diff --git a/drivers/usb/gadget/configfs.c b/drivers/usb/gadget/configfs.c index ac275855eeb6..06a0b73e0546 100644 --- a/drivers/usb/gadget/configfs.c +++ b/drivers/usb/gadget/configfs.c @@ -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) { |