diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/usb/gadget/composite.c | 96 |
1 files changed, 64 insertions, 32 deletions
diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c index eaa9a599df63..717de39627c7 100644 --- a/drivers/usb/gadget/composite.c +++ b/drivers/usb/gadget/composite.c @@ -24,6 +24,7 @@ #include <linux/kernel.h> #include <linux/slab.h> #include <linux/device.h> +#include <linux/utsname.h> #include <linux/usb/composite.h> @@ -69,6 +70,8 @@ static char *iSerialNumber; module_param(iSerialNumber, charp, 0); MODULE_PARM_DESC(iSerialNumber, "SerialNumber string"); +static char composite_manufacturer[50]; + /*-------------------------------------------------------------------------*/ /** @@ -599,6 +602,7 @@ static int get_string(struct usb_composite_dev *cdev, struct usb_configuration *c; struct usb_function *f; int len; + const char *str; /* Yes, not only is USB's I18N support probably more than most * folk will ever care about ... also, it's all supported here. @@ -638,9 +642,29 @@ static int get_string(struct usb_composite_dev *cdev, return s->bLength; } - /* Otherwise, look up and return a specified string. String IDs - * are device-scoped, so we look up each string table we're told - * about. These lookups are infrequent; simpler-is-better here. + /* Otherwise, look up and return a specified string. First + * check if the string has not been overridden. + */ + if (cdev->manufacturer_override == id) + str = iManufacturer ?: composite->iManufacturer ?: + composite_manufacturer; + else if (cdev->product_override == id) + str = iProduct ?: composite->iProduct; + else if (cdev->serial_override == id) + str = iSerialNumber; + else + str = NULL; + if (str) { + struct usb_gadget_strings strings = { + .language = language, + .strings = &(struct usb_string) { 0xff, str } + }; + return usb_gadget_get_string(&strings, 0xff, buf); + } + + /* String IDs are device-scoped, so we look up each string + * table we're told about. These lookups are infrequent; + * simpler-is-better here. */ if (composite->strings) { len = lookup_string(composite->strings, buf, language, id); @@ -1025,26 +1049,17 @@ composite_unbind(struct usb_gadget *gadget) composite = NULL; } -static void -string_override_one(struct usb_gadget_strings *tab, u8 id, const char *s) +static u8 override_id(struct usb_composite_dev *cdev, u8 *desc) { - struct usb_string *str = tab->strings; - - for (str = tab->strings; str->s; str++) { - if (str->id == id) { - str->s = s; - return; - } + if (!*desc) { + int ret = usb_string_id(cdev); + if (unlikely(ret < 0)) + WARNING(cdev, "failed to override string ID\n"); + else + *desc = ret; } -} -static void -string_override(struct usb_gadget_strings **tab, u8 id, const char *s) -{ - while (*tab) { - string_override_one(*tab, id, s); - tab++; - } + return *desc; } static int composite_bind(struct usb_gadget *gadget) @@ -1107,19 +1122,34 @@ static int composite_bind(struct usb_gadget *gadget) cdev->desc = *composite->dev; cdev->desc.bMaxPacketSize0 = gadget->ep0->maxpacket; - /* strings can't be assigned before bind() allocates the - * releavnt identifiers - */ - if (cdev->desc.iManufacturer && iManufacturer) - string_override(composite->strings, - cdev->desc.iManufacturer, iManufacturer); - if (cdev->desc.iProduct && iProduct) - string_override(composite->strings, - cdev->desc.iProduct, iProduct); - if (cdev->desc.iSerialNumber && iSerialNumber) - string_override(composite->strings, - cdev->desc.iSerialNumber, iSerialNumber); + /* stirng overrides */ + if (iManufacturer || !cdev->desc.iManufacturer) { + if (!iManufacturer && !composite->iManufacturer && + !*composite_manufacturer) + snprintf(composite_manufacturer, + sizeof composite_manufacturer, + "%s %s with %s", + init_utsname()->sysname, + init_utsname()->release, + gadget->name); + + cdev->manufacturer_override = + override_id(cdev, &cdev->desc.iManufacturer); + } + + if (iProduct || (!cdev->desc.iProduct && composite->iProduct)) + cdev->product_override = + override_id(cdev, &cdev->desc.iProduct); + + if (iSerialNumber) + cdev->serial_override = + override_id(cdev, &cdev->desc.iSerialNumber); + + /* has userspace failed to provide a serial number? */ + if (composite->needs_serial && !cdev->desc.iSerialNumber) + WARNING(cdev, "userspace failed to provide iSerialNumber\n"); + /* finish up */ status = device_create_file(&gadget->dev, &dev_attr_suspended); if (status) goto fail; @@ -1217,6 +1247,8 @@ int usb_composite_register(struct usb_composite_driver *driver) if (!driver || !driver->dev || !driver->bind || composite) return -EINVAL; + if (!driver->iProduct) + driver->iProduct = driver->name; if (!driver->name) driver->name = "composite"; composite_driver.function = (char *) driver->name; |