diff options
Diffstat (limited to 'drivers/usb/gadget/composite.c')
| -rw-r--r-- | drivers/usb/gadget/composite.c | 107 | 
1 files changed, 78 insertions, 29 deletions
diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c index baaebf2830f..390749bbb0c 100644 --- a/drivers/usb/gadget/composite.c +++ b/drivers/usb/gadget/composite.c @@ -40,27 +40,27 @@ static int (*composite_gadget_bind)(struct usb_composite_dev *cdev);   */  static ushort idVendor; -module_param(idVendor, ushort, 0); +module_param(idVendor, ushort, 0644);  MODULE_PARM_DESC(idVendor, "USB Vendor ID");  static ushort idProduct; -module_param(idProduct, ushort, 0); +module_param(idProduct, ushort, 0644);  MODULE_PARM_DESC(idProduct, "USB Product ID");  static ushort bcdDevice; -module_param(bcdDevice, ushort, 0); +module_param(bcdDevice, ushort, 0644);  MODULE_PARM_DESC(bcdDevice, "USB Device version (BCD)");  static char *iManufacturer; -module_param(iManufacturer, charp, 0); +module_param(iManufacturer, charp, 0644);  MODULE_PARM_DESC(iManufacturer, "USB Manufacturer string");  static char *iProduct; -module_param(iProduct, charp, 0); +module_param(iProduct, charp, 0644);  MODULE_PARM_DESC(iProduct, "USB Product string");  static char *iSerialNumber; -module_param(iSerialNumber, charp, 0); +module_param(iSerialNumber, charp, 0644);  MODULE_PARM_DESC(iSerialNumber, "SerialNumber string");  static char composite_manufacturer[50]; @@ -734,9 +734,23 @@ int usb_add_config(struct usb_composite_dev *cdev,  	INIT_LIST_HEAD(&config->functions);  	config->next_interface_id = 0; +	memset(config->interface, 0, sizeof(config->interface));  	status = bind(config);  	if (status < 0) { +		while (!list_empty(&config->functions)) { +			struct usb_function		*f; + +			f = list_first_entry(&config->functions, +					struct usb_function, list); +			list_del(&f->list); +			if (f->unbind) { +				DBG(cdev, "unbind function '%s'/%p\n", +					f->name, f); +				f->unbind(config, f); +				/* may free memory for "f" */ +			} +		}  		list_del(&config->list);  		config->cdev = NULL;  	} else { @@ -774,6 +788,53 @@ done:  	return status;  } +static void remove_config(struct usb_composite_dev *cdev, +			      struct usb_configuration *config) +{ +	while (!list_empty(&config->functions)) { +		struct usb_function		*f; + +		f = list_first_entry(&config->functions, +				struct usb_function, list); +		list_del(&f->list); +		if (f->unbind) { +			DBG(cdev, "unbind function '%s'/%p\n", f->name, f); +			f->unbind(config, f); +			/* may free memory for "f" */ +		} +	} +	list_del(&config->list); +	if (config->unbind) { +		DBG(cdev, "unbind config '%s'/%p\n", config->label, config); +		config->unbind(config); +			/* may free memory for "c" */ +	} +} + +/** + * usb_remove_config() - remove a configuration from a device. + * @cdev: wraps the USB gadget + * @config: the configuration + * + * Drivers must call usb_gadget_disconnect before calling this function + * to disconnect the device from the host and make sure the host will not + * try to enumerate the device while we are changing the config list. + */ +void usb_remove_config(struct usb_composite_dev *cdev, +		      struct usb_configuration *config) +{ +	unsigned long flags; + +	spin_lock_irqsave(&cdev->lock, flags); + +	if (cdev->config == config) +		reset_config(cdev); + +	spin_unlock_irqrestore(&cdev->lock, flags); + +	remove_config(cdev, config); +} +  /*-------------------------------------------------------------------------*/  /* We support strings in multiple languages ... string descriptor zero @@ -785,7 +846,7 @@ done:  static void collect_langs(struct usb_gadget_strings **sp, __le16 *buf)  {  	const struct usb_gadget_strings	*s; -	u16				language; +	__le16				language;  	__le16				*tmp;  	while (*sp) { @@ -877,7 +938,7 @@ static int get_string(struct usb_composite_dev *cdev,  	else if (cdev->product_override == id)  		str = iProduct ?: composite->iProduct;  	else if (cdev->serial_override == id) -		str = iSerialNumber; +		str = iSerialNumber ?: composite->iSerialNumber;  	else  		str = NULL;  	if (str) { @@ -1328,28 +1389,9 @@ composite_unbind(struct usb_gadget *gadget)  	while (!list_empty(&cdev->configs)) {  		struct usb_configuration	*c; -  		c = list_first_entry(&cdev->configs,  				struct usb_configuration, list); -		while (!list_empty(&c->functions)) { -			struct usb_function		*f; - -			f = list_first_entry(&c->functions, -					struct usb_function, list); -			list_del(&f->list); -			if (f->unbind) { -				DBG(cdev, "unbind function '%s'/%p\n", -						f->name, f); -				f->unbind(c, f); -				/* may free memory for "f" */ -			} -		} -		list_del(&c->list); -		if (c->unbind) { -			DBG(cdev, "unbind config '%s'/%p\n", c->label, c); -			c->unbind(c); -			/* may free memory for "c" */ -		} +		remove_config(cdev, c);  	}  	if (composite->unbind)  		composite->unbind(cdev); @@ -1431,10 +1473,16 @@ static int composite_bind(struct usb_gadget *gadget)  	/* 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) { @@ -1455,7 +1503,8 @@ static int composite_bind(struct usb_gadget *gadget)  		cdev->product_override =  			override_id(cdev, &cdev->desc.iProduct); -	if (iSerialNumber) +	if (iSerialNumber || +	    (!cdev->desc.iSerialNumber && composite->iSerialNumber))  		cdev->serial_override =  			override_id(cdev, &cdev->desc.iSerialNumber);  |