aboutsummaryrefslogtreecommitdiffstats
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.c139
1 files changed, 93 insertions, 46 deletions
diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c
index 1160c55de7f2..7b5cc16e4a0b 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);
}
/**