diff options
Diffstat (limited to 'drivers/usb/gadget/composite.c')
| -rw-r--r-- | drivers/usb/gadget/composite.c | 288 | 
1 files changed, 142 insertions, 146 deletions
diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c index 3f72110da1b..957f973dd96 100644 --- a/drivers/usb/gadget/composite.c +++ b/drivers/usb/gadget/composite.c @@ -28,44 +28,6 @@   * with the relevant device-wide data.   */ -/* big enough to hold our biggest descriptor */ -#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 identifiers - * published in the device descriptor, either numbers or strings or both. - * String parameters are in UTF-8 (superset of ASCII's 7 bit characters). - */ - -static ushort idVendor; -module_param(idVendor, ushort, 0644); -MODULE_PARM_DESC(idVendor, "USB Vendor ID"); - -static ushort idProduct; -module_param(idProduct, ushort, 0644); -MODULE_PARM_DESC(idProduct, "USB Product ID"); - -static ushort bcdDevice; -module_param(bcdDevice, ushort, 0644); -MODULE_PARM_DESC(bcdDevice, "USB Device version (BCD)"); - -static char *iManufacturer; -module_param(iManufacturer, charp, 0644); -MODULE_PARM_DESC(iManufacturer, "USB Manufacturer string"); - -static char *iProduct; -module_param(iProduct, charp, 0644); -MODULE_PARM_DESC(iProduct, "USB Product string"); - -static char *iSerialNumber; -module_param(iSerialNumber, charp, 0644); -MODULE_PARM_DESC(iSerialNumber, "SerialNumber string"); - -static char composite_manufacturer[50]; - -/*-------------------------------------------------------------------------*/  /**   * next_ep_desc() - advance to the next EP descriptor   * @t: currect pointer within descriptor array @@ -192,6 +154,7 @@ ep_found:  	}  	return 0;  } +EXPORT_SYMBOL_GPL(config_ep_by_speed);  /**   * usb_add_function() - add a function to a configuration @@ -250,6 +213,7 @@ done:  				function->name, function, value);  	return value;  } +EXPORT_SYMBOL_GPL(usb_add_function);  /**   * usb_function_deactivate - prevent function and gadget enumeration @@ -286,6 +250,7 @@ int usb_function_deactivate(struct usb_function *function)  	spin_unlock_irqrestore(&cdev->lock, flags);  	return status;  } +EXPORT_SYMBOL_GPL(usb_function_deactivate);  /**   * usb_function_activate - allow function and gadget enumeration @@ -300,9 +265,10 @@ int usb_function_deactivate(struct usb_function *function)  int usb_function_activate(struct usb_function *function)  {  	struct usb_composite_dev	*cdev = function->config->cdev; +	unsigned long			flags;  	int				status = 0; -	spin_lock(&cdev->lock); +	spin_lock_irqsave(&cdev->lock, flags);  	if (WARN_ON(cdev->deactivations == 0))  		status = -EINVAL; @@ -312,9 +278,10 @@ int usb_function_activate(struct usb_function *function)  			status = usb_gadget_connect(cdev->gadget);  	} -	spin_unlock(&cdev->lock); +	spin_unlock_irqrestore(&cdev->lock, flags);  	return status;  } +EXPORT_SYMBOL_GPL(usb_function_activate);  /**   * usb_interface_id() - allocate an unused interface ID @@ -351,16 +318,18 @@ int usb_interface_id(struct usb_configuration *config,  	}  	return -ENODEV;  } +EXPORT_SYMBOL_GPL(usb_interface_id);  static int config_buf(struct usb_configuration *config,  		enum usb_device_speed speed, void *buf, u8 type)  {  	struct usb_config_descriptor	*c = buf;  	void				*next = buf + USB_DT_CONFIG_SIZE; -	int				len = USB_BUFSIZ - USB_DT_CONFIG_SIZE; +	int				len;  	struct usb_function		*f;  	int				status; +	len = USB_COMP_EP0_BUFSIZ - USB_DT_CONFIG_SIZE;  	/* write the config descriptor */  	c = buf;  	c->bLength = USB_DT_CONFIG_SIZE; @@ -790,6 +759,7 @@ done:  				config->bConfigurationValue, status);  	return status;  } +EXPORT_SYMBOL_GPL(usb_add_config);  static void remove_config(struct usb_composite_dev *cdev,  			      struct usb_configuration *config) @@ -889,10 +859,10 @@ static int lookup_string(  static int get_string(struct usb_composite_dev *cdev,  		void *buf, u16 language, int id)  { +	struct usb_composite_driver	*composite = cdev->driver;  	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. @@ -932,26 +902,6 @@ static int get_string(struct usb_composite_dev *cdev,  		return s->bLength;  	} -	/* 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 ?: composite->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. @@ -1003,6 +953,7 @@ int usb_string_id(struct usb_composite_dev *cdev)  	}  	return -ENODEV;  } +EXPORT_SYMBOL_GPL(usb_string_id);  /**   * usb_string_ids() - allocate unused string IDs in batch @@ -1034,6 +985,7 @@ int usb_string_ids_tab(struct usb_composite_dev *cdev, struct usb_string *str)  	return 0;  } +EXPORT_SYMBOL_GPL(usb_string_ids_tab);  /**   * usb_string_ids_n() - allocate unused string IDs in batch @@ -1062,7 +1014,7 @@ int usb_string_ids_n(struct usb_composite_dev *c, unsigned n)  	c->next_string_id += n;  	return next + 1;  } - +EXPORT_SYMBOL_GPL(usb_string_ids_n);  /*-------------------------------------------------------------------------*/ @@ -1359,8 +1311,8 @@ static void composite_disconnect(struct usb_gadget *gadget)  	spin_lock_irqsave(&cdev->lock, flags);  	if (cdev->config)  		reset_config(cdev); -	if (composite->disconnect) -		composite->disconnect(cdev); +	if (cdev->driver->disconnect) +		cdev->driver->disconnect(cdev);  	spin_unlock_irqrestore(&cdev->lock, flags);  } @@ -1396,35 +1348,67 @@ composite_unbind(struct usb_gadget *gadget)  				struct usb_configuration, list);  		remove_config(cdev, c);  	} -	if (composite->unbind) -		composite->unbind(cdev); +	if (cdev->driver->unbind) +		cdev->driver->unbind(cdev);  	if (cdev->req) {  		kfree(cdev->req->buf);  		usb_ep_free_request(gadget->ep0, cdev->req);  	}  	device_remove_file(&gadget->dev, &dev_attr_suspended); +	kfree(cdev->def_manufacturer);  	kfree(cdev);  	set_gadget_data(gadget, NULL); -	composite = NULL;  } -static u8 override_id(struct usb_composite_dev *cdev, u8 *desc) +static void update_unchanged_dev_desc(struct usb_device_descriptor *new, +		const struct usb_device_descriptor *old)  { -	if (!*desc) { -		int ret = usb_string_id(cdev); -		if (unlikely(ret < 0)) -			WARNING(cdev, "failed to override string ID\n"); -		else -			*desc = ret; -	} +	__le16 idVendor; +	__le16 idProduct; +	__le16 bcdDevice; +	u8 iSerialNumber; +	u8 iManufacturer; +	u8 iProduct; + +	/* +	 * these variables may have been set in +	 * usb_composite_overwrite_options() +	 */ +	idVendor = new->idVendor; +	idProduct = new->idProduct; +	bcdDevice = new->bcdDevice; +	iSerialNumber = new->iSerialNumber; +	iManufacturer = new->iManufacturer; +	iProduct = new->iProduct; + +	*new = *old; +	if (idVendor) +		new->idVendor = idVendor; +	if (idProduct) +		new->idProduct = idProduct; +	if (bcdDevice) +		new->bcdDevice = bcdDevice; +	else +		new->bcdDevice = cpu_to_le16(get_default_bcdDevice()); +	if (iSerialNumber) +		new->iSerialNumber = iSerialNumber; +	if (iManufacturer) +		new->iManufacturer = iManufacturer; +	if (iProduct) +		new->iProduct = iProduct; +} -	return *desc; +static struct usb_composite_driver *to_cdriver(struct usb_gadget_driver *gdrv) +{ +	return container_of(gdrv, struct usb_composite_driver, gadget_driver);  } -static int composite_bind(struct usb_gadget *gadget) +static int composite_bind(struct usb_gadget *gadget, +		struct usb_gadget_driver *gdriver)  {  	struct usb_composite_dev	*cdev; +	struct usb_composite_driver	*composite = to_cdriver(gdriver);  	int				status = -ENOMEM;  	cdev = kzalloc(sizeof *cdev, GFP_KERNEL); @@ -1440,13 +1424,12 @@ static int composite_bind(struct usb_gadget *gadget)  	cdev->req = usb_ep_alloc_request(gadget->ep0, GFP_KERNEL);  	if (!cdev->req)  		goto fail; -	cdev->req->buf = kmalloc(USB_BUFSIZ, GFP_KERNEL); +	cdev->req->buf = kmalloc(USB_COMP_EP0_BUFSIZ, GFP_KERNEL);  	if (!cdev->req->buf)  		goto fail;  	cdev->req->complete = composite_setup_complete;  	gadget->ep0->driver_data = cdev; -	cdev->bufsiz = USB_BUFSIZ;  	cdev->driver = composite;  	/* @@ -1467,49 +1450,11 @@ static int composite_bind(struct usb_gadget *gadget)  	 * serial number), register function drivers, potentially update  	 * power state and consumption, etc  	 */ -	status = composite_gadget_bind(cdev); +	status = composite->bind(cdev);  	if (status < 0)  		goto fail; -	cdev->desc = *composite->dev; - -	/* standardized runtime overrides for device ID data */ -	if (idVendor) -		cdev->desc.idVendor = cpu_to_le16(idVendor); -	else -		idVendor = le16_to_cpu(cdev->desc.idVendor); -	if (idProduct) -		cdev->desc.idProduct = cpu_to_le16(idProduct); -	else -		idProduct = le16_to_cpu(cdev->desc.idProduct); -	if (bcdDevice) -		cdev->desc.bcdDevice = cpu_to_le16(bcdDevice); -	else -		bcdDevice = le16_to_cpu(cdev->desc.bcdDevice); - -	/* string 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->desc.iSerialNumber && composite->iSerialNumber)) -		cdev->serial_override = -			override_id(cdev, &cdev->desc.iSerialNumber); +	update_unchanged_dev_desc(&cdev->desc, composite->dev);  	/* has userspace failed to provide a serial number? */  	if (composite->needs_serial && !cdev->desc.iSerialNumber) @@ -1546,8 +1491,8 @@ composite_suspend(struct usb_gadget *gadget)  				f->suspend(f);  		}  	} -	if (composite->suspend) -		composite->suspend(cdev); +	if (cdev->driver->suspend) +		cdev->driver->suspend(cdev);  	cdev->suspended = 1; @@ -1565,8 +1510,8 @@ composite_resume(struct usb_gadget *gadget)  	 * suspend/resume callbacks?  	 */  	DBG(cdev, "resume\n"); -	if (composite->resume) -		composite->resume(cdev); +	if (cdev->driver->resume) +		cdev->driver->resume(cdev);  	if (cdev->config) {  		list_for_each_entry(f, &cdev->config->functions, list) {  			if (f->resume) @@ -1584,13 +1529,8 @@ composite_resume(struct usb_gadget *gadget)  /*-------------------------------------------------------------------------*/ -static struct usb_gadget_driver composite_driver = { -#ifdef CONFIG_USB_GADGET_SUPERSPEED -	.max_speed	= USB_SPEED_SUPER, -#else -	.max_speed	= USB_SPEED_HIGH, -#endif - +static const struct usb_gadget_driver composite_driver_template = { +	.bind		= composite_bind,  	.unbind		= composite_unbind,  	.setup		= composite_setup, @@ -1623,25 +1563,26 @@ 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_probe(struct usb_composite_driver *driver, -			       int (*bind)(struct usb_composite_dev *cdev)) +int usb_composite_probe(struct usb_composite_driver *driver)  { -	if (!driver || !driver->dev || !bind || composite) +	struct usb_gadget_driver *gadget_driver; + +	if (!driver || !driver->dev || !driver->bind)  		return -EINVAL;  	if (!driver->name)  		driver->name = "composite"; -	if (!driver->iProduct) -		driver->iProduct = driver->name; -	composite_driver.function =  (char *) driver->name; -	composite_driver.driver.name = driver->name; -	composite_driver.max_speed = -		min_t(u8, composite_driver.max_speed, driver->max_speed); -	composite = driver; -	composite_gadget_bind = bind; -	return usb_gadget_probe_driver(&composite_driver, composite_bind); +	driver->gadget_driver = composite_driver_template; +	gadget_driver = &driver->gadget_driver; + +	gadget_driver->function =  (char *) driver->name; +	gadget_driver->driver.name = driver->name; +	gadget_driver->max_speed = driver->max_speed; + +	return usb_gadget_probe_driver(gadget_driver);  } +EXPORT_SYMBOL_GPL(usb_composite_probe);  /**   * usb_composite_unregister() - unregister a composite driver @@ -1652,10 +1593,9 @@ int usb_composite_probe(struct usb_composite_driver *driver,   */  void usb_composite_unregister(struct usb_composite_driver *driver)  { -	if (composite != driver) -		return; -	usb_gadget_unregister_driver(&composite_driver); +	usb_gadget_unregister_driver(&driver->gadget_driver);  } +EXPORT_SYMBOL_GPL(usb_composite_unregister);  /**   * usb_composite_setup_continue() - Continue with the control transfer @@ -1692,4 +1632,60 @@ void usb_composite_setup_continue(struct usb_composite_dev *cdev)  	spin_unlock_irqrestore(&cdev->lock, flags);  } +EXPORT_SYMBOL_GPL(usb_composite_setup_continue); + +static char *composite_default_mfr(struct usb_gadget *gadget) +{ +	char *mfr; +	int len; + +	len = snprintf(NULL, 0, "%s %s with %s", init_utsname()->sysname, +			init_utsname()->release, gadget->name); +	len++; +	mfr = kmalloc(len, GFP_KERNEL); +	if (!mfr) +		return NULL; +	snprintf(mfr, len, "%s %s with %s", init_utsname()->sysname, +			init_utsname()->release, gadget->name); +	return mfr; +} + +void usb_composite_overwrite_options(struct usb_composite_dev *cdev, +		struct usb_composite_overwrite *covr) +{ +	struct usb_device_descriptor	*desc = &cdev->desc; +	struct usb_gadget_strings	*gstr = cdev->driver->strings[0]; +	struct usb_string		*dev_str = gstr->strings; + +	if (covr->idVendor) +		desc->idVendor = cpu_to_le16(covr->idVendor); + +	if (covr->idProduct) +		desc->idProduct = cpu_to_le16(covr->idProduct); + +	if (covr->bcdDevice) +		desc->bcdDevice = cpu_to_le16(covr->bcdDevice); + +	if (covr->serial_number) { +		desc->iSerialNumber = dev_str[USB_GADGET_SERIAL_IDX].id; +		dev_str[USB_GADGET_SERIAL_IDX].s = covr->serial_number; +	} +	if (covr->manufacturer) { +		desc->iManufacturer = dev_str[USB_GADGET_MANUFACTURER_IDX].id; +		dev_str[USB_GADGET_MANUFACTURER_IDX].s = covr->manufacturer; + +	} else if (!strlen(dev_str[USB_GADGET_MANUFACTURER_IDX].s)) { +		desc->iManufacturer = dev_str[USB_GADGET_MANUFACTURER_IDX].id; +		cdev->def_manufacturer = composite_default_mfr(cdev->gadget); +		dev_str[USB_GADGET_MANUFACTURER_IDX].s = cdev->def_manufacturer; +	} + +	if (covr->product) { +		desc->iProduct = dev_str[USB_GADGET_PRODUCT_IDX].id; +		dev_str[USB_GADGET_PRODUCT_IDX].s = covr->product; +	} +} +EXPORT_SYMBOL_GPL(usb_composite_overwrite_options); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("David Brownell");  |