USB: gadget: composite: Better string override handling
[platform/adaptation/renesas_rcar/renesas_kernel.git] / drivers / usb / gadget / composite.c
index eaa9a59..717de39 100644 (file)
@@ -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;