summaryrefslogtreecommitdiff
path: root/drivers/usb/gadget/composite.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/gadget/composite.c')
-rw-r--r--drivers/usb/gadget/composite.c96
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;