mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-08-05 16:54:27 +00:00
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>
This commit is contained in:
parent
15a7cf8caa
commit
c033563220
2 changed files with 78 additions and 16 deletions
|
@ -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,
|
static int configfs_composite_bind(struct usb_gadget *gadget,
|
||||||
struct usb_gadget_driver *gdriver)
|
struct usb_gadget_driver *gdriver)
|
||||||
{
|
{
|
||||||
|
@ -1640,22 +1714,7 @@ static int configfs_composite_bind(struct usb_gadget *gadget,
|
||||||
|
|
||||||
/* init all strings */
|
/* init all strings */
|
||||||
if (!list_empty(&gi->string_list)) {
|
if (!list_empty(&gi->string_list)) {
|
||||||
struct gadget_language *gs;
|
s = configfs_attach_gadget_strings(gi);
|
||||||
|
|
||||||
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);
|
|
||||||
if (IS_ERR(s)) {
|
if (IS_ERR(s)) {
|
||||||
ret = PTR_ERR(s);
|
ret = PTR_ERR(s);
|
||||||
goto err_comp_cleanup;
|
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.iManufacturer = s[USB_GADGET_MANUFACTURER_IDX].id;
|
||||||
gi->cdev.desc.iProduct = s[USB_GADGET_PRODUCT_IDX].id;
|
gi->cdev.desc.iProduct = s[USB_GADGET_PRODUCT_IDX].id;
|
||||||
gi->cdev.desc.iSerialNumber = s[USB_GADGET_SERIAL_IDX].id;
|
gi->cdev.desc.iSerialNumber = s[USB_GADGET_SERIAL_IDX].id;
|
||||||
|
|
||||||
|
gi->cdev.usb_strings = s;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (gi->use_webusb) {
|
if (gi->use_webusb) {
|
||||||
|
|
|
@ -494,6 +494,7 @@ struct usb_composite_dev {
|
||||||
struct usb_composite_driver *driver;
|
struct usb_composite_driver *driver;
|
||||||
u8 next_string_id;
|
u8 next_string_id;
|
||||||
char *def_manufacturer;
|
char *def_manufacturer;
|
||||||
|
struct usb_string *usb_strings;
|
||||||
|
|
||||||
/* the gadget driver won't enable the data pullup
|
/* the gadget driver won't enable the data pullup
|
||||||
* while the deactivation count is nonzero.
|
* while the deactivation count is nonzero.
|
||||||
|
|
Loading…
Add table
Reference in a new issue