diff options
Diffstat (limited to 'drivers/usb/gadget/composite.c')
-rw-r--r-- | drivers/usb/gadget/composite.c | 139 |
1 files changed, 93 insertions, 46 deletions
diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c index 1160c55de7f..7b5cc16e4a0 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> @@ -39,6 +40,7 @@ #define USB_BUFSIZ 1024 static struct usb_composite_driver *composite; +static int (*composite_gadget_bind)(struct usb_composite_dev *cdev); /* Some systems will need runtime overrides for the product identifers * published in the device descriptor, either numbers or strings or both. @@ -69,6 +71,8 @@ static char *iSerialNumber; module_param(iSerialNumber, charp, 0); MODULE_PARM_DESC(iSerialNumber, "SerialNumber string"); +static char composite_manufacturer[50]; + /*-------------------------------------------------------------------------*/ /** @@ -470,18 +474,20 @@ done: * usb_add_config() - add a configuration to a device. * @cdev: wraps the USB gadget * @config: the configuration, with bConfigurationValue assigned + * @bind: the configuration's bind function * Context: single threaded during gadget setup * - * One of the main tasks of a composite driver's bind() routine is to + * One of the main tasks of a composite @bind() routine is to * add each of the configurations it supports, using this routine. * - * This function returns the value of the configuration's bind(), which + * This function returns the value of the configuration's @bind(), which * is zero for success else a negative errno value. Binding configurations * assigns global resources including string IDs, and per-configuration * resources such as interface IDs and endpoints. */ int usb_add_config(struct usb_composite_dev *cdev, - struct usb_configuration *config) + struct usb_configuration *config, + int (*bind)(struct usb_configuration *)) { int status = -EINVAL; struct usb_configuration *c; @@ -490,7 +496,7 @@ int usb_add_config(struct usb_composite_dev *cdev, config->bConfigurationValue, config->label, config); - if (!config->bConfigurationValue || !config->bind) + if (!config->bConfigurationValue || !bind) goto done; /* Prevent duplicate configuration identifiers */ @@ -507,7 +513,7 @@ int usb_add_config(struct usb_composite_dev *cdev, INIT_LIST_HEAD(&config->functions); config->next_interface_id = 0; - status = config->bind(config); + status = bind(config); if (status < 0) { list_del(&config->list); config->cdev = NULL; @@ -533,7 +539,7 @@ int usb_add_config(struct usb_composite_dev *cdev, } } - /* set_alt(), or next config->bind(), sets up + /* set_alt(), or next bind(), sets up * ep->driver_data as needed. */ usb_ep_autoconfig_reset(cdev->gadget); @@ -599,6 +605,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 +645,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); @@ -901,7 +928,8 @@ unknown: */ switch (ctrl->bRequestType & USB_RECIP_MASK) { case USB_RECIP_INTERFACE: - f = cdev->config->interface[intf]; + if (cdev->config) + f = cdev->config->interface[intf]; break; case USB_RECIP_ENDPOINT: @@ -1025,26 +1053,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) @@ -1074,7 +1093,13 @@ static int composite_bind(struct usb_gadget *gadget) cdev->bufsiz = USB_BUFSIZ; cdev->driver = composite; - usb_gadget_set_selfpowered(gadget); + /* + * As per USB compliance update, a device that is actively drawing + * more than 100mA from USB must report itself as bus-powered in + * the GetStatus(DEVICE) call. + */ + if (CONFIG_USB_GADGET_VBUS_DRAW <= USB_SELF_POWER_VBUS_MAX_DRAW) + usb_gadget_set_selfpowered(gadget); /* interface and string IDs start at zero via kzalloc. * we force endpoints to start unassigned; few controller @@ -1094,26 +1119,41 @@ static int composite_bind(struct usb_gadget *gadget) * serial number), register function drivers, potentially update * power state and consumption, etc */ - status = composite->bind(cdev); + status = composite_gadget_bind(cdev); if (status < 0) goto fail; 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; @@ -1177,7 +1217,6 @@ composite_resume(struct usb_gadget *gadget) static struct usb_gadget_driver composite_driver = { .speed = USB_SPEED_HIGH, - .bind = composite_bind, .unbind = composite_unbind, .setup = composite_setup, @@ -1192,8 +1231,12 @@ static struct usb_gadget_driver composite_driver = { }; /** - * usb_composite_register() - register a composite driver + * usb_composite_probe() - register a composite driver * @driver: the driver to register + * @bind: the callback used to allocate resources that are shared across the + * whole device, such as string IDs, and add its configurations using + * @usb_add_config(). This may fail by returning a negative errno + * value; it should return zero on successful initialization. * Context: single threaded during gadget setup * * This function is used to register drivers using the composite driver @@ -1206,18 +1249,22 @@ static struct usb_gadget_driver composite_driver = { * while it was binding. That would usually be done in order to wait for * some userspace participation. */ -int usb_composite_register(struct usb_composite_driver *driver) +extern int usb_composite_probe(struct usb_composite_driver *driver, + int (*bind)(struct usb_composite_dev *cdev)) { - if (!driver || !driver->dev || !driver->bind || composite) + if (!driver || !driver->dev || !bind || composite) return -EINVAL; + if (!driver->iProduct) + driver->iProduct = driver->name; if (!driver->name) driver->name = "composite"; composite_driver.function = (char *) driver->name; composite_driver.driver.name = driver->name; composite = driver; + composite_gadget_bind = bind; - return usb_gadget_register_driver(&composite_driver); + return usb_gadget_probe_driver(&composite_driver, composite_bind); } /** |