diff options
Diffstat (limited to 'drivers/usb/gadget/serial.c')
| -rw-r--r-- | drivers/usb/gadget/serial.c | 190 | 
1 files changed, 92 insertions, 98 deletions
diff --git a/drivers/usb/gadget/serial.c b/drivers/usb/gadget/serial.c index 1ac57a973aa..1f5f978d35d 100644 --- a/drivers/usb/gadget/serial.c +++ b/drivers/usb/gadget/serial.c @@ -11,8 +11,8 @@   */  #include <linux/kernel.h> -#include <linux/utsname.h>  #include <linux/device.h> +#include <linux/module.h>  #include <linux/tty.h>  #include <linux/tty_flip.h> @@ -29,25 +29,7 @@  #define GS_VERSION_NAME			GS_LONG_NAME " " GS_VERSION_STR  /*-------------------------------------------------------------------------*/ - -/* - * Kbuild is not very cooperative with respect to linking separately - * compiled library objects into one module.  So for now we won't use - * separate compilation ... ensuring init/exit sections work to shrink - * the runtime footprint, and giving us at least some parts of what - * a "gcc --combine ... part1.c part2.c part3.c ... " build would. - */ -#include "composite.c" -#include "usbstring.c" -#include "config.c" -#include "epautoconf.c" - -#include "f_acm.c" -#include "f_obex.c" -#include "f_serial.c" -#include "u_serial.c" - -/*-------------------------------------------------------------------------*/ +USB_GADGET_COMPOSITE_OPTIONS();  /* Thanks to NetChip Technologies for donating this product ID.  * @@ -61,15 +43,12 @@  /* string IDs are assigned dynamically */ -#define STRING_MANUFACTURER_IDX		0 -#define STRING_PRODUCT_IDX		1 -#define STRING_DESCRIPTION_IDX		2 - -static char manufacturer[50]; +#define STRING_DESCRIPTION_IDX		USB_GADGET_FIRST_AVAIL_IDX  static struct usb_string strings_dev[] = { -	[STRING_MANUFACTURER_IDX].s = manufacturer, -	[STRING_PRODUCT_IDX].s = GS_VERSION_NAME, +	[USB_GADGET_MANUFACTURER_IDX].s = "", +	[USB_GADGET_PRODUCT_IDX].s = GS_VERSION_NAME, +	[USB_GADGET_SERIAL_IDX].s = "",  	[STRING_DESCRIPTION_IDX].s = NULL /* updated; f(use_acm) */,  	{  } /* end of list */  }; @@ -94,7 +73,7 @@ static struct usb_device_descriptor device_desc = {  	/* .bMaxPacketSize0 = f(hardware) */  	.idVendor =		cpu_to_le16(GS_VENDOR_ID),  	/* .idProduct =	f(use_acm) */ -	/* .bcdDevice = f(hardware) */ +	.bcdDevice = cpu_to_le16(GS_VERSION_NUM),  	/* .iManufacturer = DYNAMIC */  	/* .iProduct = DYNAMIC */  	.bNumConfigurations =	1, @@ -123,11 +102,11 @@ MODULE_AUTHOR("Al Borchers");  MODULE_AUTHOR("David Brownell");  MODULE_LICENSE("GPL"); -static int use_acm = true; +static bool use_acm = true;  module_param(use_acm, bool, 0);  MODULE_PARM_DESC(use_acm, "Use CDC ACM, default=yes"); -static int use_obex = false; +static bool use_obex = false;  module_param(use_obex, bool, 0);  MODULE_PARM_DESC(use_obex, "Use CDC OBEX, default=no"); @@ -137,22 +116,6 @@ MODULE_PARM_DESC(n_ports, "number of ports to create, default=1");  /*-------------------------------------------------------------------------*/ -static int __init serial_bind_config(struct usb_configuration *c) -{ -	unsigned i; -	int status = 0; - -	for (i = 0; i < n_ports && status == 0; i++) { -		if (use_acm) -			status = acm_bind_config(c, i); -		else if (use_obex) -			status = obex_bind_config(c, i); -		else -			status = gser_bind_config(c, i); -	} -	return status; -} -  static struct usb_configuration serial_config_driver = {  	/* .label = f(use_acm) */  	/* .bConfigurationValue = f(use_acm) */ @@ -160,88 +123,120 @@ static struct usb_configuration serial_config_driver = {  	.bmAttributes	= USB_CONFIG_ATT_SELFPOWER,  }; +static struct usb_function_instance *fi_serial[MAX_U_SERIAL_PORTS]; +static struct usb_function *f_serial[MAX_U_SERIAL_PORTS]; + +static int serial_register_ports(struct usb_composite_dev *cdev, +		struct usb_configuration *c, const char *f_name) +{ +	int i; +	int ret; + +	ret = usb_add_config_only(cdev, c); +	if (ret) +		goto out; + +	for (i = 0; i < n_ports; i++) { + +		fi_serial[i] = usb_get_function_instance(f_name); +		if (IS_ERR(fi_serial[i])) { +			ret = PTR_ERR(fi_serial[i]); +			goto fail; +		} + +		f_serial[i] = usb_get_function(fi_serial[i]); +		if (IS_ERR(f_serial[i])) { +			ret = PTR_ERR(f_serial[i]); +			goto err_get_func; +		} + +		ret = usb_add_function(c, f_serial[i]); +		if (ret) +			goto err_add_func; +	} + +	return 0; + +err_add_func: +	usb_put_function(f_serial[i]); +err_get_func: +	usb_put_function_instance(fi_serial[i]); + +fail: +	i--; +	while (i >= 0) { +		usb_remove_function(c, f_serial[i]); +		usb_put_function(f_serial[i]); +		usb_put_function_instance(fi_serial[i]); +		i--; +	} +out: +	return ret; +} +  static int __init gs_bind(struct usb_composite_dev *cdev)  { -	int			gcnum; -	struct usb_gadget	*gadget = cdev->gadget;  	int			status; -	status = gserial_setup(cdev->gadget, n_ports); -	if (status < 0) -		return status; -  	/* Allocate string descriptor numbers ... note that string  	 * contents can be overridden by the composite_dev glue.  	 */ -	/* device description: manufacturer, product */ -	snprintf(manufacturer, sizeof manufacturer, "%s %s with %s", -		init_utsname()->sysname, init_utsname()->release, -		gadget->name); -	status = usb_string_id(cdev); -	if (status < 0) -		goto fail; -	strings_dev[STRING_MANUFACTURER_IDX].id = status; - -	device_desc.iManufacturer = status; - -	status = usb_string_id(cdev); +	status = usb_string_ids_tab(cdev, strings_dev);  	if (status < 0)  		goto fail; -	strings_dev[STRING_PRODUCT_IDX].id = status; - -	device_desc.iProduct = status; - -	/* config description */ -	status = usb_string_id(cdev); -	if (status < 0) -		goto fail; -	strings_dev[STRING_DESCRIPTION_IDX].id = status; - +	device_desc.iManufacturer = strings_dev[USB_GADGET_MANUFACTURER_IDX].id; +	device_desc.iProduct = strings_dev[USB_GADGET_PRODUCT_IDX].id; +	status = strings_dev[STRING_DESCRIPTION_IDX].id;  	serial_config_driver.iConfiguration = status; -	/* set up other descriptors */ -	gcnum = usb_gadget_controller_number(gadget); -	if (gcnum >= 0) -		device_desc.bcdDevice = cpu_to_le16(GS_VERSION_NUM | gcnum); -	else { -		/* this is so simple (for now, no altsettings) that it -		 * SHOULD NOT have problems with bulk-capable hardware. -		 * so warn about unrcognized controllers -- don't panic. -		 * -		 * things like configuration and altsetting numbering -		 * can need hardware-specific attention though. -		 */ -		pr_warning("gs_bind: controller '%s' not recognized\n", -			gadget->name); -		device_desc.bcdDevice = -			cpu_to_le16(GS_VERSION_NUM | 0x0099); -	} -  	if (gadget_is_otg(cdev->gadget)) {  		serial_config_driver.descriptors = otg_desc;  		serial_config_driver.bmAttributes |= USB_CONFIG_ATT_WAKEUP;  	}  	/* register our configuration */ -	status = usb_add_config(cdev, &serial_config_driver, -			serial_bind_config); +	if (use_acm) { +		status  = serial_register_ports(cdev, &serial_config_driver, +				"acm"); +		usb_ep_autoconfig_reset(cdev->gadget); +	} else if (use_obex) +		status = serial_register_ports(cdev, &serial_config_driver, +				"obex"); +	else { +		status = serial_register_ports(cdev, &serial_config_driver, +				"gser"); +	}  	if (status < 0)  		goto fail; +	usb_composite_overwrite_options(cdev, &coverwrite);  	INFO(cdev, "%s\n", GS_VERSION_NAME);  	return 0;  fail: -	gserial_cleanup();  	return status;  } -static struct usb_composite_driver gserial_driver = { +static int gs_unbind(struct usb_composite_dev *cdev) +{ +	int i; + +	for (i = 0; i < n_ports; i++) { +		usb_put_function(f_serial[i]); +		usb_put_function_instance(fi_serial[i]); +	} +	return 0; +} + +static __refdata struct usb_composite_driver gserial_driver = {  	.name		= "g_serial",  	.dev		= &device_desc,  	.strings	= dev_strings, +	.max_speed	= USB_SPEED_SUPER, +	.bind		= gs_bind, +	.unbind		= gs_unbind,  };  static int __init init(void) @@ -270,13 +265,12 @@ static int __init init(void)  	}  	strings_dev[STRING_DESCRIPTION_IDX].s = serial_config_driver.label; -	return usb_composite_probe(&gserial_driver, gs_bind); +	return usb_composite_probe(&gserial_driver);  }  module_init(init);  static void __exit cleanup(void)  {  	usb_composite_unregister(&gserial_driver); -	gserial_cleanup();  }  module_exit(cleanup);  | 
