|
@@ -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;
|