diff options
Diffstat (limited to 'drivers/usb/gadget')
75 files changed, 7996 insertions, 6226 deletions
diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index 48cddf3cd6b..ba18e9c110c 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -58,6 +58,20 @@ config USB_GADGET_DEBUG  	   trying to track down.  Never enable these messages for a  	   production build. +config USB_GADGET_VERBOSE +	bool "Verbose debugging Messages (DEVELOPMENT)" +	depends on USB_GADGET_DEBUG +	help +	   Many controller and gadget drivers will print verbose debugging +	   messages if you use this option to ask for those messages. + +	   Avoid enabling these messages, even if you're actively +	   debugging such a driver.  Many drivers will emit so many +	   messages that the driver timings are affected, which will +	   either create new failure modes or remove the one you're +	   trying to track down.  Never enable these messages for a +	   production build. +  config USB_GADGET_DEBUG_FILES  	boolean "Debugging information files (DEVELOPMENT)"  	depends on PROC_FS @@ -143,7 +157,7 @@ config USB_AT91  config USB_LPC32XX  	tristate "LPC32XX USB Peripheral Controller" -	depends on ARCH_LPC32XX +	depends on ARCH_LPC32XX && I2C  	select USB_ISP1301  	help  	   This option selects the USB device controller in the LPC32xx SoC. @@ -202,10 +216,17 @@ config USB_FOTG210_UDC  	   Say "y" to link the driver statically, or "m" to build a  	   dynamically linked module called "fotg210_udc". +config USB_GR_UDC +       tristate "Aeroflex Gaisler GRUSBDC USB Peripheral Controller Driver" +       depends on HAS_DMA +       help +          Select this to support Aeroflex Gaisler GRUSBDC cores from the GRLIB +	  VHDL IP core library. +  config USB_OMAP  	tristate "OMAP USB Device Controller"  	depends on ARCH_OMAP1 -	select ISP1301_OMAP if MACH_OMAP_H2 || MACH_OMAP_H3 || MACH_OMAP_H4_OTG +	depends on ISP1301_OMAP || !(MACH_OMAP_H2 || MACH_OMAP_H3)  	help  	   Many Texas Instruments OMAP processors have flexible full  	   speed USB device controllers, with support for up to 30 @@ -279,13 +300,6 @@ config USB_PXA27X  	   dynamically linked module called "pxa27x_udc" and force all  	   gadget drivers to also be dynamically linked. -config USB_S3C_HSOTG -	tristate "S3C HS/OtG USB Device controller" -	depends on S3C_DEV_USB_HSOTG -	help -	  The Samsung S3C64XX USB2.0 high-speed gadget controller -	  integrated into the S3C64XX series SoC. -  config USB_S3C2410  	tristate "S3C2410 USB Device Controller"  	depends on ARCH_S3C24XX @@ -498,9 +512,6 @@ config USB_U_SERIAL  config USB_U_ETHER  	tristate -config USB_U_RNDIS -	tristate -  config USB_F_SERIAL  	tristate @@ -525,6 +536,12 @@ config USB_F_SUBSET  config USB_F_RNDIS  	tristate +config USB_F_MASS_STORAGE +	tristate + +config USB_F_FS +	tristate +  choice  	tristate "USB Gadget Drivers"  	default USB_ETH @@ -625,7 +642,6 @@ config USB_CONFIGFS_RNDIS  	depends on USB_CONFIGFS  	depends on NET  	select USB_U_ETHER -	select USB_U_RNDIS  	select USB_F_RNDIS  	help  	   Microsoft Windows XP bundles the "Remote NDIS" (RNDIS) protocol, @@ -662,6 +678,42 @@ config USB_CONFIGFS_PHONET  	help  	  The Phonet protocol implementation for USB device. +config USB_CONFIGFS_MASS_STORAGE +	boolean "Mass storage" +	depends on USB_CONFIGFS +	depends on BLOCK +	select USB_F_MASS_STORAGE +	help +	  The Mass Storage Gadget acts as a USB Mass Storage disk drive. +	  As its storage repository it can use a regular file or a block +	  device (in much the same way as the "loop" device driver), +	  specified as a module parameter or sysfs option. + +config USB_CONFIGFS_F_LB_SS +	boolean "Loopback and sourcesink function (for testing)" +	depends on USB_CONFIGFS +	select USB_F_SS_LB +	help +	  Loopback function loops back a configurable number of transfers. +	  Sourcesink function either sinks and sources bulk data. +	  It also implements control requests, for "chapter 9" conformance. +	  Make this be the first driver you try using on top of any new +	  USB peripheral controller driver.  Then you can use host-side +	  test software, like the "usbtest" driver, to put your hardware +	  and its driver through a basic set of functional tests. + +config USB_CONFIGFS_F_FS +	boolean "Function filesystem (FunctionFS)" +	depends on USB_CONFIGFS +	select USB_F_FS +	help +	  The Function Filesystem (FunctionFS) lets one create USB +	  composite functions in user space in the same way GadgetFS +	  lets one create USB gadgets in user space.  This allows creation +	  of composite gadgets such that some of the functions are +	  implemented in kernel space (for instance Ethernet, serial or +	  mass storage) and other are implemented in user space. +  config USB_ZERO  	tristate "Gadget Zero (DEVELOPMENT)"  	select USB_LIBCOMPOSITE @@ -732,7 +784,6 @@ config USB_ETH  	depends on NET  	select USB_LIBCOMPOSITE  	select USB_U_ETHER -	select USB_U_RNDIS  	select USB_F_ECM  	select USB_F_SUBSET  	select CRC32 @@ -836,6 +887,7 @@ config USB_GADGETFS  config USB_FUNCTIONFS  	tristate "Function Filesystem"  	select USB_LIBCOMPOSITE +	select USB_F_FS  	select USB_FUNCTIONFS_GENERIC if !(USB_FUNCTIONFS_ETH || USB_FUNCTIONFS_RNDIS)  	help  	  The Function Filesystem (FunctionFS) lets one create USB @@ -855,6 +907,8 @@ config USB_FUNCTIONFS_ETH  	bool "Include configuration with CDC ECM (Ethernet)"  	depends on USB_FUNCTIONFS && NET  	select USB_U_ETHER +	select USB_F_ECM +	select USB_F_SUBSET  	help  	  Include a configuration with CDC ECM function (Ethernet) and the  	  Function Filesystem. @@ -863,7 +917,7 @@ config USB_FUNCTIONFS_RNDIS  	bool "Include configuration with RNDIS (Ethernet)"  	depends on USB_FUNCTIONFS && NET  	select USB_U_ETHER -	select USB_U_RNDIS +	select USB_F_RNDIS  	help  	  Include a configuration with RNDIS function (Ethernet) and the Filesystem. @@ -878,6 +932,7 @@ config USB_MASS_STORAGE  	tristate "Mass Storage Gadget"  	depends on BLOCK  	select USB_LIBCOMPOSITE +	select USB_F_MASS_STORAGE  	help  	  The Mass Storage Gadget acts as a USB Mass Storage disk drive.  	  As its storage repository it can use a regular file or a block @@ -1001,6 +1056,7 @@ config USB_G_ACM_MS  	select USB_LIBCOMPOSITE  	select USB_U_SERIAL  	select USB_F_ACM +	select USB_F_MASS_STORAGE  	help  	  This driver provides two functions in one configuration:  	  a mass storage, and a CDC ACM (serial port) link. @@ -1015,8 +1071,8 @@ config USB_G_MULTI  	select USB_LIBCOMPOSITE  	select USB_U_SERIAL  	select USB_U_ETHER -	select USB_U_RNDIS  	select USB_F_ACM +	select USB_F_MASS_STORAGE  	help  	  The Multifunction Composite Gadget provides Ethernet (RNDIS  	  and/or CDC Ethernet), mass storage and ACM serial link @@ -1035,6 +1091,7 @@ config USB_G_MULTI  config USB_G_MULTI_RNDIS  	bool "RNDIS + CDC Serial + Storage configuration"  	depends on USB_G_MULTI +	select USB_F_RNDIS  	default y  	help  	  This option enables a configuration with RNDIS, CDC Serial and @@ -1048,6 +1105,7 @@ config USB_G_MULTI_CDC  	bool "CDC Ethernet + CDC Serial + Storage configuration"  	depends on USB_G_MULTI  	default n +	select USB_F_ECM  	help  	  This option enables a configuration with CDC Ethernet (ECM), CDC  	  Serial and Mass Storage functions available in the Multifunction diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile index 386db9daf1d..49514ea60a9 100644 --- a/drivers/usb/gadget/Makefile +++ b/drivers/usb/gadget/Makefile @@ -1,12 +1,13 @@  #  # USB peripheral controller drivers  # -ccflags-$(CONFIG_USB_GADGET_DEBUG) := -DDEBUG +ccflags-$(CONFIG_USB_GADGET_DEBUG)	:= -DDEBUG +ccflags-$(CONFIG_USB_GADGET_VERBOSE)	+= -DVERBOSE_DEBUG  obj-$(CONFIG_USB_GADGET)	+= udc-core.o  obj-$(CONFIG_USB_LIBCOMPOSITE)	+= libcomposite.o  libcomposite-y			:= usbstring.o config.o epautoconf.o -libcomposite-y			+= composite.o functions.o configfs.o +libcomposite-y			+= composite.o functions.o configfs.o u_f.o  obj-$(CONFIG_USB_DUMMY_HCD)	+= dummy_hcd.o  obj-$(CONFIG_USB_NET2272)	+= net2272.o  obj-$(CONFIG_USB_NET2280)	+= net2280.o @@ -25,7 +26,6 @@ fsl_usb2_udc-$(CONFIG_ARCH_MXC)	+= fsl_mxc_udc.o  obj-$(CONFIG_USB_M66592)	+= m66592-udc.o  obj-$(CONFIG_USB_R8A66597)	+= r8a66597-udc.o  obj-$(CONFIG_USB_FSL_QE)	+= fsl_qe_udc.o -obj-$(CONFIG_USB_S3C_HSOTG)	+= s3c-hsotg.o  obj-$(CONFIG_USB_S3C_HSUDC)	+= s3c-hsudc.o  obj-$(CONFIG_USB_LPC32XX)	+= lpc32xx_udc.o  obj-$(CONFIG_USB_EG20T)		+= pch_udc.o @@ -34,6 +34,7 @@ mv_udc-y			:= mv_udc_core.o  obj-$(CONFIG_USB_FUSB300)	+= fusb300_udc.o  obj-$(CONFIG_USB_FOTG210_UDC)	+= fotg210-udc.o  obj-$(CONFIG_USB_MV_U3D)	+= mv_u3d_core.o +obj-$(CONFIG_USB_GR_UDC)	+= gr_udc.o  # USB Functions  usb_f_acm-y			:= f_acm.o @@ -46,8 +47,6 @@ obj-$(CONFIG_USB_F_SERIAL)	+= usb_f_serial.o  usb_f_obex-y			:= f_obex.o  obj-$(CONFIG_USB_F_OBEX)	+= usb_f_obex.o  obj-$(CONFIG_USB_U_ETHER)	+= u_ether.o -u_rndis-y			:= rndis.o -obj-$(CONFIG_USB_U_RNDIS)	+= u_rndis.o  usb_f_ncm-y			:= f_ncm.o  obj-$(CONFIG_USB_F_NCM)		+= usb_f_ncm.o  usb_f_ecm-y			:= f_ecm.o @@ -58,8 +57,12 @@ usb_f_eem-y			:= f_eem.o  obj-$(CONFIG_USB_F_EEM)		+= usb_f_eem.o  usb_f_ecm_subset-y		:= f_subset.o  obj-$(CONFIG_USB_F_SUBSET)	+= usb_f_ecm_subset.o -usb_f_rndis-y			:= f_rndis.o +usb_f_rndis-y			:= f_rndis.o rndis.o  obj-$(CONFIG_USB_F_RNDIS)	+= usb_f_rndis.o +usb_f_mass_storage-y		:= f_mass_storage.o storage_common.o +obj-$(CONFIG_USB_F_MASS_STORAGE)+= usb_f_mass_storage.o +usb_f_fs-y			:= f_fs.o +obj-$(CONFIG_USB_F_FS)		+= usb_f_fs.o  #  # USB gadget drivers diff --git a/drivers/usb/gadget/acm_ms.c b/drivers/usb/gadget/acm_ms.c index 4b947bb50f6..a252444cc0a 100644 --- a/drivers/usb/gadget/acm_ms.c +++ b/drivers/usb/gadget/acm_ms.c @@ -31,16 +31,7 @@  #define ACM_MS_VENDOR_NUM	0x1d6b	/* Linux Foundation */  #define ACM_MS_PRODUCT_NUM	0x0106	/* Composite Gadget: ACM + MS*/ -/*-------------------------------------------------------------------------*/ - -/* - * 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 "f_mass_storage.c" +#include "f_mass_storage.h"  /*-------------------------------------------------------------------------*/  USB_GADGET_COMPOSITE_OPTIONS(); @@ -104,18 +95,35 @@ static struct usb_gadget_strings *dev_strings[] = {  /****************************** Configurations ******************************/  static struct fsg_module_parameters fsg_mod_data = { .stall = 1 }; -FSG_MODULE_PARAMETERS(/* no prefix */, fsg_mod_data); +#ifdef CONFIG_USB_GADGET_DEBUG_FILES -static struct fsg_common fsg_common; +static unsigned int fsg_num_buffers = CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS; + +#else + +/* + * Number of buffers we will use. + * 2 is usually enough for good buffering pipeline + */ +#define fsg_num_buffers	CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS + +#endif /* CONFIG_USB_GADGET_DEBUG_FILES */ + +FSG_MODULE_PARAMETERS(/* no prefix */, fsg_mod_data);  /*-------------------------------------------------------------------------*/  static struct usb_function *f_acm;  static struct usb_function_instance *f_acm_inst; + +static struct usb_function_instance *fi_msg; +static struct usb_function *f_msg; +  /*   * We _always_ have both ACM and mass storage functions.   */  static int __init acm_ms_do_config(struct usb_configuration *c)  { +	struct fsg_opts *opts;  	int	status;  	if (gadget_is_otg(c->cdev->gadget)) { @@ -123,31 +131,37 @@ static int __init acm_ms_do_config(struct usb_configuration *c)  		c->bmAttributes |= USB_CONFIG_ATT_WAKEUP;  	} -	f_acm_inst = usb_get_function_instance("acm"); -	if (IS_ERR(f_acm_inst)) -		return PTR_ERR(f_acm_inst); +	opts = fsg_opts_from_func_inst(fi_msg);  	f_acm = usb_get_function(f_acm_inst); -	if (IS_ERR(f_acm)) { -		status = PTR_ERR(f_acm); -		goto err_func; +	if (IS_ERR(f_acm)) +		return PTR_ERR(f_acm); + +	f_msg = usb_get_function(fi_msg); +	if (IS_ERR(f_msg)) { +		status = PTR_ERR(f_msg); +		goto put_acm;  	}  	status = usb_add_function(c, f_acm);  	if (status < 0) -		goto err_conf; +		goto put_msg; -	status = fsg_bind_config(c->cdev, c, &fsg_common); -	if (status < 0) -		goto err_fsg; +	status = fsg_common_run_thread(opts->common); +	if (status) +		goto remove_acm; + +	status = usb_add_function(c, f_msg); +	if (status) +		goto remove_acm;  	return 0; -err_fsg: +remove_acm:  	usb_remove_function(c, f_acm); -err_conf: +put_msg: +	usb_put_function(f_msg); +put_acm:  	usb_put_function(f_acm); -err_func: -	usb_put_function_instance(f_acm_inst);  	return status;  } @@ -163,45 +177,82 @@ static struct usb_configuration acm_ms_config_driver = {  static int __init acm_ms_bind(struct usb_composite_dev *cdev)  {  	struct usb_gadget	*gadget = cdev->gadget; +	struct fsg_opts		*opts; +	struct fsg_config	config;  	int			status; -	void			*retp; -	/* set up mass storage function */ -	retp = fsg_common_from_params(&fsg_common, cdev, &fsg_mod_data); -	if (IS_ERR(retp)) { -		status = PTR_ERR(retp); -		return PTR_ERR(retp); +	f_acm_inst = usb_get_function_instance("acm"); +	if (IS_ERR(f_acm_inst)) +		return PTR_ERR(f_acm_inst); + +	fi_msg = usb_get_function_instance("mass_storage"); +	if (IS_ERR(fi_msg)) { +		status = PTR_ERR(fi_msg); +		goto fail_get_msg;  	} +	/* set up mass storage function */ +	fsg_config_from_params(&config, &fsg_mod_data, fsg_num_buffers); +	opts = fsg_opts_from_func_inst(fi_msg); + +	opts->no_configfs = true; +	status = fsg_common_set_num_buffers(opts->common, fsg_num_buffers); +	if (status) +		goto fail; + +	status = fsg_common_set_nluns(opts->common, config.nluns); +	if (status) +		goto fail_set_nluns; + +	status = fsg_common_set_cdev(opts->common, cdev, config.can_stall); +	if (status) +		goto fail_set_cdev; + +	fsg_common_set_sysfs(opts->common, true); +	status = fsg_common_create_luns(opts->common, &config); +	if (status) +		goto fail_set_cdev; + +	fsg_common_set_inquiry_string(opts->common, config.vendor_name, +				      config.product_name);  	/*  	 * Allocate string descriptor numbers ... note that string  	 * contents can be overridden by the composite_dev glue.  	 */  	status = usb_string_ids_tab(cdev, strings_dev);  	if (status < 0) -		goto fail1; +		goto fail_string_ids;  	device_desc.iManufacturer = strings_dev[USB_GADGET_MANUFACTURER_IDX].id;  	device_desc.iProduct = strings_dev[USB_GADGET_PRODUCT_IDX].id;  	/* register our configuration */  	status = usb_add_config(cdev, &acm_ms_config_driver, acm_ms_do_config);  	if (status < 0) -		goto fail1; +		goto fail_string_ids;  	usb_composite_overwrite_options(cdev, &coverwrite);  	dev_info(&gadget->dev, "%s, version: " DRIVER_VERSION "\n",  			DRIVER_DESC); -	fsg_common_put(&fsg_common);  	return 0;  	/* error recovery */ -fail1: -	fsg_common_put(&fsg_common); +fail_string_ids: +	fsg_common_remove_luns(opts->common); +fail_set_cdev: +	fsg_common_free_luns(opts->common); +fail_set_nluns: +	fsg_common_free_buffers(opts->common); +fail: +	usb_put_function_instance(fi_msg); +fail_get_msg: +	usb_put_function_instance(f_acm_inst);  	return status;  }  static int __exit acm_ms_unbind(struct usb_composite_dev *cdev)  { +	usb_put_function(f_msg); +	usb_put_function_instance(fi_msg);  	usb_put_function(f_acm);  	usb_put_function_instance(f_acm_inst);  	return 0; diff --git a/drivers/usb/gadget/amd5536udc.c b/drivers/usb/gadget/amd5536udc.c index a9a4346c83a..41b062eb4de 100644 --- a/drivers/usb/gadget/amd5536udc.c +++ b/drivers/usb/gadget/amd5536udc.c @@ -40,7 +40,6 @@  #include <linux/sched.h>  #include <linux/slab.h>  #include <linux/errno.h> -#include <linux/init.h>  #include <linux/timer.h>  #include <linux/list.h>  #include <linux/interrupt.h> @@ -446,7 +445,7 @@ static void ep_init(struct udc_regs __iomem *regs, struct udc_ep *ep)  	ep->ep.ops = &udc_ep_ops;  	INIT_LIST_HEAD(&ep->queue); -	ep->ep.maxpacket = (u16) ~0; +	usb_ep_set_maxpacket_limit(&ep->ep,(u16) ~0);  	/* set NAK */  	tmp = readl(&ep->regs->ctl);  	tmp |= AMD_BIT(UDC_EPCTL_SNAK); @@ -1564,12 +1563,15 @@ static void udc_setup_endpoints(struct udc *dev)  	}  	/* EP0 max packet */  	if (dev->gadget.speed == USB_SPEED_FULL) { -		dev->ep[UDC_EP0IN_IX].ep.maxpacket = UDC_FS_EP0IN_MAX_PKT_SIZE; -		dev->ep[UDC_EP0OUT_IX].ep.maxpacket = -						UDC_FS_EP0OUT_MAX_PKT_SIZE; +		usb_ep_set_maxpacket_limit(&dev->ep[UDC_EP0IN_IX].ep, +					   UDC_FS_EP0IN_MAX_PKT_SIZE); +		usb_ep_set_maxpacket_limit(&dev->ep[UDC_EP0OUT_IX].ep, +					   UDC_FS_EP0OUT_MAX_PKT_SIZE);  	} else if (dev->gadget.speed == USB_SPEED_HIGH) { -		dev->ep[UDC_EP0IN_IX].ep.maxpacket = UDC_EP0IN_MAX_PKT_SIZE; -		dev->ep[UDC_EP0OUT_IX].ep.maxpacket = UDC_EP0OUT_MAX_PKT_SIZE; +		usb_ep_set_maxpacket_limit(&dev->ep[UDC_EP0IN_IX].ep, +					   UDC_EP0IN_MAX_PKT_SIZE); +		usb_ep_set_maxpacket_limit(&dev->ep[UDC_EP0OUT_IX].ep, +					   UDC_EP0OUT_MAX_PKT_SIZE);  	}  	/* @@ -3078,8 +3080,6 @@ static void udc_pci_remove(struct pci_dev *pdev)  	if (dev->active)  		pci_disable_device(pdev); -	pci_set_drvdata(pdev, NULL); -  	udc_remove(dev);  } @@ -3340,7 +3340,7 @@ static int udc_remote_wakeup(struct udc *dev)  }  /* PCI device parameters */ -static DEFINE_PCI_DEVICE_TABLE(pci_id) = { +static const struct pci_device_id pci_id[] = {  	{  		PCI_DEVICE(PCI_VENDOR_ID_AMD, 0x2096),  		.class =	(PCI_CLASS_SERIAL_USB << 8) | 0xfe, diff --git a/drivers/usb/gadget/at91_udc.c b/drivers/usb/gadget/at91_udc.c index 4cc4fd6d147..cfd18bcca72 100644 --- a/drivers/usb/gadget/at91_udc.c +++ b/drivers/usb/gadget/at91_udc.c @@ -21,7 +21,6 @@  #include <linux/ioport.h>  #include <linux/slab.h>  #include <linux/errno.h> -#include <linux/init.h>  #include <linux/list.h>  #include <linux/interrupt.h>  #include <linux/proc_fs.h> @@ -834,7 +833,7 @@ static void udc_reinit(struct at91_udc *udc)  		ep->ep.desc = NULL;  		ep->stopped = 0;  		ep->fifo_bank = 0; -		ep->ep.maxpacket = ep->maxpacket; +		usb_ep_set_maxpacket_limit(&ep->ep, ep->maxpacket);  		ep->creg = (void __iomem *) udc->udp_baseaddr + AT91_UDP_CSR(i);  		/* initialize one queue per endpoint */  		INIT_LIST_HEAD(&ep->queue); @@ -1710,16 +1709,6 @@ static int at91udc_probe(struct platform_device *pdev)  		return -ENODEV;  	} -	if (pdev->num_resources != 2) { -		DBG("invalid num_resources\n"); -		return -ENODEV; -	} -	if ((pdev->resource[0].flags != IORESOURCE_MEM) -			|| (pdev->resource[1].flags != IORESOURCE_IRQ)) { -		DBG("invalid resource type\n"); -		return -ENODEV; -	} -  	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);  	if (!res)  		return -ENXIO; diff --git a/drivers/usb/gadget/atmel_usba_udc.c b/drivers/usb/gadget/atmel_usba_udc.c index 2cb52e0438d..76023ce449a 100644 --- a/drivers/usb/gadget/atmel_usba_udc.c +++ b/drivers/usb/gadget/atmel_usba_udc.c @@ -326,7 +326,7 @@ static int vbus_is_present(struct usba_udc *udc)  #if defined(CONFIG_ARCH_AT91SAM9RL) -#include <mach/at91_pmc.h> +#include <linux/clk/at91_pmc.h>  static void toggle_bias(int is_on)  { @@ -1012,7 +1012,7 @@ static void nop_release(struct device *dev)  } -struct usb_gadget usba_gadget_template = { +static struct usb_gadget usba_gadget_template = {  	.ops		= &usba_udc_ops,  	.max_speed	= USB_SPEED_HIGH,  	.name		= "atmel_usba_udc", @@ -1661,7 +1661,7 @@ static irqreturn_t usba_udc_irq(int irq, void *devid)  	if (dma_status) {  		int i; -		for (i = 1; i < USBA_NR_ENDPOINTS; i++) +		for (i = 1; i < USBA_NR_DMAS; i++)  			if (dma_status & (1 << i))  				usba_dma_irq(udc, &udc->usba_ep[i]);  	} @@ -1670,7 +1670,7 @@ static irqreturn_t usba_udc_irq(int irq, void *devid)  	if (ep_status) {  		int i; -		for (i = 0; i < USBA_NR_ENDPOINTS; i++) +		for (i = 0; i < udc->num_ep; i++)  			if (ep_status & (1 << i)) {  				if (ep_is_control(&udc->usba_ep[i]))  					usba_control_irq(udc, &udc->usba_ep[i]); @@ -1686,7 +1686,7 @@ static irqreturn_t usba_udc_irq(int irq, void *devid)  		reset_all_endpoints(udc);  		if (udc->gadget.speed != USB_SPEED_UNKNOWN -				&& udc->driver->disconnect) { +				&& udc->driver && udc->driver->disconnect) {  			udc->gadget.speed = USB_SPEED_UNKNOWN;  			spin_unlock(&udc->lock);  			udc->driver->disconnect(&udc->gadget); @@ -1827,12 +1827,12 @@ static int atmel_usba_stop(struct usb_gadget *gadget,  	toggle_bias(0);  	usba_writel(udc, CTRL, USBA_DISABLE_MASK); -	udc->driver = NULL; -  	clk_disable_unprepare(udc->hclk);  	clk_disable_unprepare(udc->pclk); -	DBG(DBG_GADGET, "unregistered driver `%s'\n", driver->driver.name); +	DBG(DBG_GADGET, "unregistered driver `%s'\n", udc->driver->driver.name); + +	udc->driver = NULL;  	return 0;  } @@ -1904,7 +1904,7 @@ static struct usba_ep * atmel_udc_of_init(struct platform_device *pdev,  		ep->dma_regs = udc->regs + USBA_DMA_BASE(i);  		ep->fifo = udc->fifo + USBA_FIFO_BASE(i);  		ep->ep.ops = &usba_ep_ops; -		ep->ep.maxpacket = ep->fifo_size; +		usb_ep_set_maxpacket_limit(&ep->ep, ep->fifo_size);  		ep->udc = udc;  		INIT_LIST_HEAD(&ep->queue); @@ -1914,6 +1914,12 @@ static struct usba_ep * atmel_udc_of_init(struct platform_device *pdev,  		i++;  	} +	if (i == 0) { +		dev_err(&pdev->dev, "of_probe: no endpoint specified\n"); +		ret = -EINVAL; +		goto err; +	} +  	return eps;  err:  	return ERR_PTR(ret); @@ -1957,7 +1963,8 @@ static struct usba_ep * usba_udc_pdata(struct platform_device *pdev,  		ep->fifo = udc->fifo + USBA_FIFO_BASE(i);  		ep->ep.ops = &usba_ep_ops;  		ep->ep.name = pdata->ep[i].name; -		ep->fifo_size = ep->ep.maxpacket = pdata->ep[i].fifo_size; +		ep->fifo_size = pdata->ep[i].fifo_size; +		usb_ep_set_maxpacket_limit(&ep->ep, ep->fifo_size);  		ep->udc = udc;  		INIT_LIST_HEAD(&ep->queue);  		ep->nr_banks = pdata->ep[i].nr_banks; @@ -1995,14 +2002,12 @@ static int __init usba_udc_probe(struct platform_device *pdev)  	if (irq < 0)  		return irq; -	pclk = clk_get(&pdev->dev, "pclk"); +	pclk = devm_clk_get(&pdev->dev, "pclk");  	if (IS_ERR(pclk))  		return PTR_ERR(pclk); -	hclk = clk_get(&pdev->dev, "hclk"); -	if (IS_ERR(hclk)) { -		ret = PTR_ERR(hclk); -		goto err_get_hclk; -	} +	hclk = devm_clk_get(&pdev->dev, "hclk"); +	if (IS_ERR(hclk)) +		return PTR_ERR(hclk);  	spin_lock_init(&udc->lock);  	udc->pdev = pdev; @@ -2011,17 +2016,17 @@ static int __init usba_udc_probe(struct platform_device *pdev)  	udc->vbus_pin = -ENODEV;  	ret = -ENOMEM; -	udc->regs = ioremap(regs->start, resource_size(regs)); +	udc->regs = devm_ioremap(&pdev->dev, regs->start, resource_size(regs));  	if (!udc->regs) {  		dev_err(&pdev->dev, "Unable to map I/O memory, aborting.\n"); -		goto err_map_regs; +		return ret;  	}  	dev_info(&pdev->dev, "MMIO registers at 0x%08lx mapped at %p\n",  		 (unsigned long)regs->start, udc->regs); -	udc->fifo = ioremap(fifo->start, resource_size(fifo)); +	udc->fifo = devm_ioremap(&pdev->dev, fifo->start, resource_size(fifo));  	if (!udc->fifo) {  		dev_err(&pdev->dev, "Unable to map FIFO, aborting.\n"); -		goto err_map_fifo; +		return ret;  	}  	dev_info(&pdev->dev, "FIFO at 0x%08lx mapped at %p\n",  		 (unsigned long)fifo->start, udc->fifo); @@ -2032,7 +2037,7 @@ static int __init usba_udc_probe(struct platform_device *pdev)  	ret = clk_prepare_enable(pclk);  	if (ret) {  		dev_err(&pdev->dev, "Unable to enable pclk, aborting.\n"); -		goto err_clk_enable; +		return ret;  	}  	toggle_bias(0);  	usba_writel(udc, CTRL, USBA_DISABLE_MASK); @@ -2043,22 +2048,22 @@ static int __init usba_udc_probe(struct platform_device *pdev)  	else  		udc->usba_ep = usba_udc_pdata(pdev, udc); -	if (IS_ERR(udc->usba_ep)) { -		ret = PTR_ERR(udc->usba_ep); -		goto err_alloc_ep; -	} +	if (IS_ERR(udc->usba_ep)) +		return PTR_ERR(udc->usba_ep); -	ret = request_irq(irq, usba_udc_irq, 0, "atmel_usba_udc", udc); +	ret = devm_request_irq(&pdev->dev, irq, usba_udc_irq, 0, +				"atmel_usba_udc", udc);  	if (ret) {  		dev_err(&pdev->dev, "Cannot request irq %d (error %d)\n",  			irq, ret); -		goto err_request_irq; +		return ret;  	}  	udc->irq = irq;  	if (gpio_is_valid(udc->vbus_pin)) {  		if (!devm_gpio_request(&pdev->dev, udc->vbus_pin, "atmel_usba_udc")) { -			ret = request_irq(gpio_to_irq(udc->vbus_pin), +			ret = devm_request_irq(&pdev->dev, +					gpio_to_irq(udc->vbus_pin),  					usba_vbus_irq, 0,  					"atmel_usba_udc", udc);  			if (ret) { @@ -2077,31 +2082,13 @@ static int __init usba_udc_probe(struct platform_device *pdev)  	ret = usb_add_gadget_udc(&pdev->dev, &udc->gadget);  	if (ret) -		goto err_add_udc; +		return ret;  	usba_init_debugfs(udc);  	for (i = 1; i < udc->num_ep; i++)  		usba_ep_init_debugfs(udc, &udc->usba_ep[i]);  	return 0; - -err_add_udc: -	if (gpio_is_valid(udc->vbus_pin)) -		free_irq(gpio_to_irq(udc->vbus_pin), udc); - -	free_irq(irq, udc); -err_request_irq: -err_alloc_ep: -err_clk_enable: -	iounmap(udc->fifo); -err_map_fifo: -	iounmap(udc->regs); -err_map_regs: -	clk_put(hclk); -err_get_hclk: -	clk_put(pclk); - -	return ret;  }  static int __exit usba_udc_remove(struct platform_device *pdev) @@ -2117,16 +2104,6 @@ static int __exit usba_udc_remove(struct platform_device *pdev)  		usba_ep_cleanup_debugfs(&udc->usba_ep[i]);  	usba_cleanup_debugfs(udc); -	if (gpio_is_valid(udc->vbus_pin)) { -		free_irq(gpio_to_irq(udc->vbus_pin), udc); -	} - -	free_irq(udc->irq, udc); -	iounmap(udc->fifo); -	iounmap(udc->regs); -	clk_put(udc->hclk); -	clk_put(udc->pclk); -  	return 0;  } diff --git a/drivers/usb/gadget/atmel_usba_udc.h b/drivers/usb/gadget/atmel_usba_udc.h index 2922db50bef..a70706e8cb0 100644 --- a/drivers/usb/gadget/atmel_usba_udc.h +++ b/drivers/usb/gadget/atmel_usba_udc.h @@ -210,7 +210,7 @@  #define USBA_FIFO_BASE(x)	((x) << 16)  /* Synth parameters */ -#define USBA_NR_ENDPOINTS	7 +#define USBA_NR_DMAS		7  #define EP0_FIFO_SIZE		64  #define EP0_EPT_SIZE		USBA_EPT_SIZE_64 diff --git a/drivers/usb/gadget/bcm63xx_udc.c b/drivers/usb/gadget/bcm63xx_udc.c index c58fcf1ebe4..e969eb809a8 100644 --- a/drivers/usb/gadget/bcm63xx_udc.c +++ b/drivers/usb/gadget/bcm63xx_udc.c @@ -19,7 +19,6 @@  #include <linux/device.h>  #include <linux/dma-mapping.h>  #include <linux/errno.h> -#include <linux/init.h>  #include <linux/interrupt.h>  #include <linux/ioport.h>  #include <linux/kconfig.h> @@ -361,24 +360,30 @@ static inline void usb_dma_writel(struct bcm63xx_udc *udc, u32 val, u32 off)  	bcm_writel(val, udc->iudma_regs + off);  } -static inline u32 usb_dmac_readl(struct bcm63xx_udc *udc, u32 off) +static inline u32 usb_dmac_readl(struct bcm63xx_udc *udc, u32 off, int chan)  { -	return bcm_readl(udc->iudma_regs + IUDMA_DMAC_OFFSET + off); +	return bcm_readl(udc->iudma_regs + IUDMA_DMAC_OFFSET + off + +			(ENETDMA_CHAN_WIDTH * chan));  } -static inline void usb_dmac_writel(struct bcm63xx_udc *udc, u32 val, u32 off) +static inline void usb_dmac_writel(struct bcm63xx_udc *udc, u32 val, u32 off, +					int chan)  { -	bcm_writel(val, udc->iudma_regs + IUDMA_DMAC_OFFSET + off); +	bcm_writel(val, udc->iudma_regs + IUDMA_DMAC_OFFSET + off + +			(ENETDMA_CHAN_WIDTH * chan));  } -static inline u32 usb_dmas_readl(struct bcm63xx_udc *udc, u32 off) +static inline u32 usb_dmas_readl(struct bcm63xx_udc *udc, u32 off, int chan)  { -	return bcm_readl(udc->iudma_regs + IUDMA_DMAS_OFFSET + off); +	return bcm_readl(udc->iudma_regs + IUDMA_DMAS_OFFSET + off + +			(ENETDMA_CHAN_WIDTH * chan));  } -static inline void usb_dmas_writel(struct bcm63xx_udc *udc, u32 val, u32 off) +static inline void usb_dmas_writel(struct bcm63xx_udc *udc, u32 val, u32 off, +					int chan)  { -	bcm_writel(val, udc->iudma_regs + IUDMA_DMAS_OFFSET + off); +	bcm_writel(val, udc->iudma_regs + IUDMA_DMAS_OFFSET + off + +			(ENETDMA_CHAN_WIDTH * chan));  }  static inline void set_clocks(struct bcm63xx_udc *udc, bool is_enabled) @@ -549,7 +554,7 @@ static void bcm63xx_ep_setup(struct bcm63xx_udc *udc)  		if (idx < 0)  			continue; -		udc->bep[idx].ep.maxpacket = max_pkt; +		usb_ep_set_maxpacket_limit(&udc->bep[idx].ep, max_pkt);  		val = (idx << USBD_CSR_EP_LOG_SHIFT) |  		      (cfg->dir << USBD_CSR_EP_DIR_SHIFT) | @@ -639,7 +644,7 @@ static void iudma_write(struct bcm63xx_udc *udc, struct iudma_ch *iudma,  	} while (!last_bd);  	usb_dmac_writel(udc, ENETDMAC_CHANCFG_EN_MASK, -			ENETDMAC_CHANCFG_REG(iudma->ch_idx)); +			ENETDMAC_CHANCFG_REG, iudma->ch_idx);  }  /** @@ -695,9 +700,9 @@ static void iudma_reset_channel(struct bcm63xx_udc *udc, struct iudma_ch *iudma)  		bcm63xx_fifo_reset_ep(udc, max(0, iudma->ep_num));  	/* stop DMA, then wait for the hardware to wrap up */ -	usb_dmac_writel(udc, 0, ENETDMAC_CHANCFG_REG(ch_idx)); +	usb_dmac_writel(udc, 0, ENETDMAC_CHANCFG_REG, ch_idx); -	while (usb_dmac_readl(udc, ENETDMAC_CHANCFG_REG(ch_idx)) & +	while (usb_dmac_readl(udc, ENETDMAC_CHANCFG_REG, ch_idx) &  				   ENETDMAC_CHANCFG_EN_MASK) {  		udelay(1); @@ -714,10 +719,10 @@ static void iudma_reset_channel(struct bcm63xx_udc *udc, struct iudma_ch *iudma)  			dev_warn(udc->dev, "forcibly halting IUDMA channel %d\n",  				 ch_idx);  			usb_dmac_writel(udc, ENETDMAC_CHANCFG_BUFHALT_MASK, -					ENETDMAC_CHANCFG_REG(ch_idx)); +					ENETDMAC_CHANCFG_REG, ch_idx);  		}  	} -	usb_dmac_writel(udc, ~0, ENETDMAC_IR_REG(ch_idx)); +	usb_dmac_writel(udc, ~0, ENETDMAC_IR_REG, ch_idx);  	/* don't leave "live" HW-owned entries for the next guy to step on */  	for (d = iudma->bd_ring; d <= iudma->end_bd; d++) @@ -729,11 +734,11 @@ static void iudma_reset_channel(struct bcm63xx_udc *udc, struct iudma_ch *iudma)  	/* set up IRQs, UBUS burst size, and BD base for this channel */  	usb_dmac_writel(udc, ENETDMAC_IR_BUFDONE_MASK, -			ENETDMAC_IRMASK_REG(ch_idx)); -	usb_dmac_writel(udc, 8, ENETDMAC_MAXBURST_REG(ch_idx)); +			ENETDMAC_IRMASK_REG, ch_idx); +	usb_dmac_writel(udc, 8, ENETDMAC_MAXBURST_REG, ch_idx); -	usb_dmas_writel(udc, iudma->bd_ring_dma, ENETDMAS_RSTART_REG(ch_idx)); -	usb_dmas_writel(udc, 0, ENETDMAS_SRAM2_REG(ch_idx)); +	usb_dmas_writel(udc, iudma->bd_ring_dma, ENETDMAS_RSTART_REG, ch_idx); +	usb_dmas_writel(udc, 0, ENETDMAS_SRAM2_REG, ch_idx);  }  /** @@ -943,7 +948,7 @@ static int bcm63xx_init_udc_hw(struct bcm63xx_udc *udc)  		bep->ep.ops = &bcm63xx_udc_ep_ops;  		list_add_tail(&bep->ep.ep_list, &udc->gadget.ep_list);  		bep->halted = 0; -		bep->ep.maxpacket = BCM63XX_MAX_CTRL_PKT; +		usb_ep_set_maxpacket_limit(&bep->ep, BCM63XX_MAX_CTRL_PKT);  		bep->udc = udc;  		bep->ep.desc = NULL;  		INIT_LIST_HEAD(&bep->queue); @@ -2036,7 +2041,7 @@ static irqreturn_t bcm63xx_udc_data_isr(int irq, void *dev_id)  	spin_lock(&udc->lock);  	usb_dmac_writel(udc, ENETDMAC_IR_BUFDONE_MASK, -			ENETDMAC_IR_REG(iudma->ch_idx)); +			ENETDMAC_IR_REG, iudma->ch_idx);  	bep = iudma->bep;  	rc = iudma_read(udc, iudma); @@ -2176,18 +2181,18 @@ static int bcm63xx_iudma_dbg_show(struct seq_file *s, void *p)  		seq_printf(s, " [ep%d]:\n",  			   max_t(int, iudma_defaults[ch_idx].ep_num, 0));  		seq_printf(s, "  cfg: %08x; irqstat: %08x; irqmask: %08x; maxburst: %08x\n", -			   usb_dmac_readl(udc, ENETDMAC_CHANCFG_REG(ch_idx)), -			   usb_dmac_readl(udc, ENETDMAC_IR_REG(ch_idx)), -			   usb_dmac_readl(udc, ENETDMAC_IRMASK_REG(ch_idx)), -			   usb_dmac_readl(udc, ENETDMAC_MAXBURST_REG(ch_idx))); +			   usb_dmac_readl(udc, ENETDMAC_CHANCFG_REG, ch_idx), +			   usb_dmac_readl(udc, ENETDMAC_IR_REG, ch_idx), +			   usb_dmac_readl(udc, ENETDMAC_IRMASK_REG, ch_idx), +			   usb_dmac_readl(udc, ENETDMAC_MAXBURST_REG, ch_idx)); -		sram2 = usb_dmas_readl(udc, ENETDMAS_SRAM2_REG(ch_idx)); -		sram3 = usb_dmas_readl(udc, ENETDMAS_SRAM3_REG(ch_idx)); +		sram2 = usb_dmas_readl(udc, ENETDMAS_SRAM2_REG, ch_idx); +		sram3 = usb_dmas_readl(udc, ENETDMAS_SRAM3_REG, ch_idx);  		seq_printf(s, "  base: %08x; index: %04x_%04x; desc: %04x_%04x %08x\n", -			   usb_dmas_readl(udc, ENETDMAS_RSTART_REG(ch_idx)), +			   usb_dmas_readl(udc, ENETDMAS_RSTART_REG, ch_idx),  			   sram2 >> 16, sram2 & 0xffff,  			   sram3 >> 16, sram3 & 0xffff, -			   usb_dmas_readl(udc, ENETDMAS_SRAM4_REG(ch_idx))); +			   usb_dmas_readl(udc, ENETDMAS_SRAM4_REG, ch_idx));  		seq_printf(s, "  desc: %d/%d used", iudma->n_bds_used,  			   iudma->n_bds); diff --git a/drivers/usb/gadget/cdc2.c b/drivers/usb/gadget/cdc2.c index 5a5acf22c69..e126b6b248e 100644 --- a/drivers/usb/gadget/cdc2.c +++ b/drivers/usb/gadget/cdc2.c @@ -113,12 +113,6 @@ static int __init cdc_do_config(struct usb_configuration *c)  		c->bmAttributes |= USB_CONFIG_ATT_WAKEUP;  	} -	fi_ecm = usb_get_function_instance("ecm"); -	if (IS_ERR(fi_ecm)) { -		status = PTR_ERR(fi_ecm); -		goto err_func_ecm; -	} -  	f_ecm = usb_get_function(fi_ecm);  	if (IS_ERR(f_ecm)) {  		status = PTR_ERR(f_ecm); @@ -129,35 +123,24 @@ static int __init cdc_do_config(struct usb_configuration *c)  	if (status)  		goto err_add_ecm; -	fi_serial = usb_get_function_instance("acm"); -	if (IS_ERR(fi_serial)) { -		status = PTR_ERR(fi_serial); -		goto err_get_acm; -	} -  	f_acm = usb_get_function(fi_serial);  	if (IS_ERR(f_acm)) {  		status = PTR_ERR(f_acm); -		goto err_func_acm; +		goto err_get_acm;  	}  	status = usb_add_function(c, f_acm);  	if (status)  		goto err_add_acm; -  	return 0;  err_add_acm:  	usb_put_function(f_acm); -err_func_acm: -	usb_put_function_instance(fi_serial);  err_get_acm:  	usb_remove_function(c, f_ecm);  err_add_ecm:  	usb_put_function(f_ecm);  err_get_ecm: -	usb_put_function_instance(fi_ecm); -err_func_ecm:  	return status;  } diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c index d4f0f330575..f8015193205 100644 --- a/drivers/usb/gadget/composite.c +++ b/drivers/usb/gadget/composite.c @@ -21,6 +21,24 @@  #include <linux/usb/composite.h>  #include <asm/unaligned.h> +#include "u_os_desc.h" + +/** + * struct usb_os_string - represents OS String to be reported by a gadget + * @bLength: total length of the entire descritor, always 0x12 + * @bDescriptorType: USB_DT_STRING + * @qwSignature: the OS String proper + * @bMS_VendorCode: code used by the host for subsequent requests + * @bPad: not used, must be zero + */ +struct usb_os_string { +	__u8	bLength; +	__u8	bDescriptorType; +	__u8	qwSignature[OS_STRING_QW_SIGN_LEN]; +	__u8	bMS_VendorCode; +	__u8	bPad; +} __packed; +  /*   * The code in this file is utility code, used to build a gadget driver   * from one or more "function" drivers, one or more "configuration" @@ -354,7 +372,7 @@ static u8 encode_bMaxPower(enum usb_device_speed speed,  		return DIV_ROUND_UP(val, 8);  	default:  		return DIV_ROUND_UP(val, 2); -	}; +	}  }  static int config_buf(struct usb_configuration *config, @@ -422,6 +440,7 @@ static int config_desc(struct usb_composite_dev *cdev, unsigned w_value)  {  	struct usb_gadget		*gadget = cdev->gadget;  	struct usb_configuration	*c; +	struct list_head		*pos;  	u8				type = w_value >> 8;  	enum usb_device_speed		speed = USB_SPEED_UNKNOWN; @@ -440,7 +459,20 @@ static int config_desc(struct usb_composite_dev *cdev, unsigned w_value)  	/* This is a lookup by config *INDEX* */  	w_value &= 0xff; -	list_for_each_entry(c, &cdev->configs, list) { + +	pos = &cdev->configs; +	c = cdev->os_desc_config; +	if (c) +		goto check_config; + +	while ((pos = pos->next) !=  &cdev->configs) { +		c = list_entry(pos, typeof(*c), list); + +		/* skip OS Descriptors config which is handled separately */ +		if (c == cdev->os_desc_config) +			continue; + +check_config:  		/* ignore configs that won't work at this speed */  		switch (speed) {  		case USB_SPEED_SUPER: @@ -593,6 +625,7 @@ static void reset_config(struct usb_composite_dev *cdev)  		bitmap_zero(f->endpoints, 32);  	}  	cdev->config = NULL; +	cdev->delayed_status = 0;  }  static int set_config(struct usb_composite_dev *cdev, @@ -633,6 +666,7 @@ static int set_config(struct usb_composite_dev *cdev,  	if (!c)  		goto done; +	usb_gadget_set_state(gadget, USB_STATE_CONFIGURED);  	cdev->config = c;  	/* Initialize all interfaces by setting them to altsetting zero. */ @@ -959,6 +993,19 @@ static int get_string(struct usb_composite_dev *cdev,  		return s->bLength;  	} +	if (cdev->use_os_string && language == 0 && id == OS_STRING_IDX) { +		struct usb_os_string *b = buf; +		b->bLength = sizeof(*b); +		b->bDescriptorType = USB_DT_STRING; +		compiletime_assert( +			sizeof(b->qwSignature) == sizeof(cdev->qw_sign), +			"qwSignature size must be equal to qw_sign"); +		memcpy(&b->qwSignature, cdev->qw_sign, sizeof(b->qwSignature)); +		b->bMS_VendorCode = cdev->b_vendor_code; +		b->bPad = 0; +		return sizeof(*b); +	} +  	list_for_each_entry(uc, &cdev->gstrings, list) {  		struct usb_gadget_strings **sp; @@ -1138,7 +1185,7 @@ struct usb_string *usb_gstrings_attach(struct usb_composite_dev *cdev,  	uc = copy_gadget_strings(sp, n_gstrings, n_strings);  	if (IS_ERR(uc)) -		return ERR_PTR(PTR_ERR(uc)); +		return ERR_CAST(uc);  	n_gs = get_containers_gs(uc);  	ret = usb_string_ids_tab(cdev, n_gs[0]->strings); @@ -1205,6 +1252,156 @@ static void composite_setup_complete(struct usb_ep *ep, struct usb_request *req)  				req->status, req->actual, req->length);  } +static int count_ext_compat(struct usb_configuration *c) +{ +	int i, res; + +	res = 0; +	for (i = 0; i < c->next_interface_id; ++i) { +		struct usb_function *f; +		int j; + +		f = c->interface[i]; +		for (j = 0; j < f->os_desc_n; ++j) { +			struct usb_os_desc *d; + +			if (i != f->os_desc_table[j].if_id) +				continue; +			d = f->os_desc_table[j].os_desc; +			if (d && d->ext_compat_id) +				++res; +		} +	} +	BUG_ON(res > 255); +	return res; +} + +static void fill_ext_compat(struct usb_configuration *c, u8 *buf) +{ +	int i, count; + +	count = 16; +	for (i = 0; i < c->next_interface_id; ++i) { +		struct usb_function *f; +		int j; + +		f = c->interface[i]; +		for (j = 0; j < f->os_desc_n; ++j) { +			struct usb_os_desc *d; + +			if (i != f->os_desc_table[j].if_id) +				continue; +			d = f->os_desc_table[j].os_desc; +			if (d && d->ext_compat_id) { +				*buf++ = i; +				*buf++ = 0x01; +				memcpy(buf, d->ext_compat_id, 16); +				buf += 22; +			} else { +				++buf; +				*buf = 0x01; +				buf += 23; +			} +			count += 24; +			if (count >= 4096) +				return; +		} +	} +} + +static int count_ext_prop(struct usb_configuration *c, int interface) +{ +	struct usb_function *f; +	int j; + +	f = c->interface[interface]; +	for (j = 0; j < f->os_desc_n; ++j) { +		struct usb_os_desc *d; + +		if (interface != f->os_desc_table[j].if_id) +			continue; +		d = f->os_desc_table[j].os_desc; +		if (d && d->ext_compat_id) +			return d->ext_prop_count; +	} +	return 0; +} + +static int len_ext_prop(struct usb_configuration *c, int interface) +{ +	struct usb_function *f; +	struct usb_os_desc *d; +	int j, res; + +	res = 10; /* header length */ +	f = c->interface[interface]; +	for (j = 0; j < f->os_desc_n; ++j) { +		if (interface != f->os_desc_table[j].if_id) +			continue; +		d = f->os_desc_table[j].os_desc; +		if (d) +			return min(res + d->ext_prop_len, 4096); +	} +	return res; +} + +static int fill_ext_prop(struct usb_configuration *c, int interface, u8 *buf) +{ +	struct usb_function *f; +	struct usb_os_desc *d; +	struct usb_os_desc_ext_prop *ext_prop; +	int j, count, n, ret; +	u8 *start = buf; + +	f = c->interface[interface]; +	for (j = 0; j < f->os_desc_n; ++j) { +		if (interface != f->os_desc_table[j].if_id) +			continue; +		d = f->os_desc_table[j].os_desc; +		if (d) +			list_for_each_entry(ext_prop, &d->ext_prop, entry) { +				/* 4kB minus header length */ +				n = buf - start; +				if (n >= 4086) +					return 0; + +				count = ext_prop->data_len + +					ext_prop->name_len + 14; +				if (count > 4086 - n) +					return -EINVAL; +				usb_ext_prop_put_size(buf, count); +				usb_ext_prop_put_type(buf, ext_prop->type); +				ret = usb_ext_prop_put_name(buf, ext_prop->name, +							    ext_prop->name_len); +				if (ret < 0) +					return ret; +				switch (ext_prop->type) { +				case USB_EXT_PROP_UNICODE: +				case USB_EXT_PROP_UNICODE_ENV: +				case USB_EXT_PROP_UNICODE_LINK: +					usb_ext_prop_put_unicode(buf, ret, +							 ext_prop->data, +							 ext_prop->data_len); +					break; +				case USB_EXT_PROP_BINARY: +					usb_ext_prop_put_binary(buf, ret, +							ext_prop->data, +							ext_prop->data_len); +					break; +				case USB_EXT_PROP_LE32: +					/* not implemented */ +				case USB_EXT_PROP_BE32: +					/* not implemented */ +				default: +					return -EINVAL; +				} +				buf += count; +			} +	} + +	return 0; +} +  /*   * The setup() callback implements all the ep0 functionality that's   * not handled lower down, in hardware or the hardware driver(like @@ -1414,6 +1611,91 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)  		break;  	default:  unknown: +		/* +		 * OS descriptors handling +		 */ +		if (cdev->use_os_string && cdev->os_desc_config && +		    (ctrl->bRequest & USB_TYPE_VENDOR) && +		    ctrl->bRequest == cdev->b_vendor_code) { +			struct usb_request		*req; +			struct usb_configuration	*os_desc_cfg; +			u8				*buf; +			int				interface; +			int				count = 0; + +			req = cdev->os_desc_req; +			req->complete = composite_setup_complete; +			buf = req->buf; +			os_desc_cfg = cdev->os_desc_config; +			memset(buf, 0, w_length); +			buf[5] = 0x01; +			switch (ctrl->bRequestType & USB_RECIP_MASK) { +			case USB_RECIP_DEVICE: +				if (w_index != 0x4 || (w_value >> 8)) +					break; +				buf[6] = w_index; +				if (w_length == 0x10) { +					/* Number of ext compat interfaces */ +					count = count_ext_compat(os_desc_cfg); +					buf[8] = count; +					count *= 24; /* 24 B/ext compat desc */ +					count += 16; /* header */ +					put_unaligned_le32(count, buf); +					value = w_length; +				} else { +					/* "extended compatibility ID"s */ +					count = count_ext_compat(os_desc_cfg); +					buf[8] = count; +					count *= 24; /* 24 B/ext compat desc */ +					count += 16; /* header */ +					put_unaligned_le32(count, buf); +					buf += 16; +					fill_ext_compat(os_desc_cfg, buf); +					value = w_length; +				} +				break; +			case USB_RECIP_INTERFACE: +				if (w_index != 0x5 || (w_value >> 8)) +					break; +				interface = w_value & 0xFF; +				buf[6] = w_index; +				if (w_length == 0x0A) { +					count = count_ext_prop(os_desc_cfg, +						interface); +					put_unaligned_le16(count, buf + 8); +					count = len_ext_prop(os_desc_cfg, +						interface); +					put_unaligned_le32(count, buf); + +					value = w_length; +				} else { +					count = count_ext_prop(os_desc_cfg, +						interface); +					put_unaligned_le16(count, buf + 8); +					count = len_ext_prop(os_desc_cfg, +						interface); +					put_unaligned_le32(count, buf); +					buf += 10; +					value = fill_ext_prop(os_desc_cfg, +							      interface, buf); +					if (value < 0) +						return value; + +					value = w_length; +				} +				break; +			} +			req->length = value; +			req->zero = value < w_length; +			value = usb_ep_queue(gadget->ep0, req, GFP_ATOMIC); +			if (value < 0) { +				DBG(cdev, "ep_queue --> %d\n", value); +				req->status = 0; +				composite_setup_complete(gadget->ep0, req); +			} +			return value; +		} +  		VDBG(cdev,  			"non-core control req%02x.%02x v%04x i%04x l%d\n",  			ctrl->bRequestType, ctrl->bRequest, @@ -1451,8 +1733,22 @@ unknown:  			struct usb_configuration	*c;  			c = cdev->config; -			if (c && c->setup) +			if (!c) +				goto done; + +			/* try current config's setup */ +			if (c->setup) {  				value = c->setup(c, ctrl); +				goto done; +			} + +			/* try the only function in the current config */ +			if (!list_is_singular(&c->functions)) +				goto done; +			f = list_first_entry(&c->functions, struct usb_function, +					     list); +			if (f->setup) +				value = f->setup(f, ctrl);  		}  		goto done; @@ -1623,6 +1919,29 @@ fail:  	return ret;  } +int composite_os_desc_req_prepare(struct usb_composite_dev *cdev, +				  struct usb_ep *ep0) +{ +	int ret = 0; + +	cdev->os_desc_req = usb_ep_alloc_request(ep0, GFP_KERNEL); +	if (!cdev->os_desc_req) { +		ret = PTR_ERR(cdev->os_desc_req); +		goto end; +	} + +	/* OS feature descriptor length <= 4kB */ +	cdev->os_desc_req->buf = kmalloc(4096, GFP_KERNEL); +	if (!cdev->os_desc_req->buf) { +		ret = PTR_ERR(cdev->os_desc_req->buf); +		kfree(cdev->os_desc_req); +		goto end; +	} +	cdev->os_desc_req->complete = composite_setup_complete; +end: +	return ret; +} +  void composite_dev_cleanup(struct usb_composite_dev *cdev)  {  	struct usb_gadget_string_container *uc, *tmp; @@ -1631,6 +1950,10 @@ void composite_dev_cleanup(struct usb_composite_dev *cdev)  		list_del(&uc->list);  		kfree(uc);  	} +	if (cdev->os_desc_req) { +		kfree(cdev->os_desc_req->buf); +		usb_ep_free_request(cdev->gadget->ep0, cdev->os_desc_req); +	}  	if (cdev->req) {  		kfree(cdev->req->buf);  		usb_ep_free_request(cdev->gadget->ep0, cdev->req); @@ -1668,6 +1991,12 @@ static int composite_bind(struct usb_gadget *gadget,  	if (status < 0)  		goto fail; +	if (cdev->use_os_string) { +		status = composite_os_desc_req_prepare(cdev, gadget->ep0); +		if (status) +			goto fail; +	} +  	update_unchanged_dev_desc(&cdev->desc, composite->dev);  	/* has userspace failed to provide a serial number? */ @@ -1713,7 +2042,7 @@ composite_resume(struct usb_gadget *gadget)  {  	struct usb_composite_dev	*cdev = get_gadget_data(gadget);  	struct usb_function		*f; -	u8				maxpower; +	u16				maxpower;  	/* REVISIT:  should we have config level  	 * suspend/resume callbacks? diff --git a/drivers/usb/gadget/configfs.c b/drivers/usb/gadget/configfs.c index 8f0d6141e5e..97142146eea 100644 --- a/drivers/usb/gadget/configfs.c +++ b/drivers/usb/gadget/configfs.c @@ -2,8 +2,12 @@  #include <linux/module.h>  #include <linux/slab.h>  #include <linux/device.h> +#include <linux/nls.h>  #include <linux/usb/composite.h>  #include <linux/usb/gadget_configfs.h> +#include "configfs.h" +#include "u_f.h" +#include "u_os_desc.h"  int check_user_usb_string(const char *name,  		struct usb_gadget_strings *stringtab_dev) @@ -42,7 +46,8 @@ struct gadget_info {  	struct config_group functions_group;  	struct config_group configs_group;  	struct config_group strings_group; -	struct config_group *default_groups[4]; +	struct config_group os_desc_group; +	struct config_group *default_groups[5];  	struct mutex lock;  	struct usb_gadget_strings *gstrings[MAX_USB_STRING_LANGS + 1]; @@ -55,6 +60,9 @@ struct gadget_info {  #endif  	struct usb_composite_driver composite;  	struct usb_composite_dev cdev; +	bool use_os_desc; +	char b_vendor_code; +	char qw_sign[OS_STRING_QW_SIGN_LEN];  };  struct config_usb_cfg { @@ -78,6 +86,10 @@ struct gadget_strings {  	struct list_head list;  }; +struct os_desc { +	struct config_group group; +}; +  struct gadget_config_name {  	struct usb_gadget_strings stringtab_dev;  	struct usb_string strings; @@ -557,13 +569,20 @@ static struct config_group *function_make(  	fi = usb_get_function_instance(func_name);  	if (IS_ERR(fi)) -		return ERR_PTR(PTR_ERR(fi)); +		return ERR_CAST(fi);  	ret = config_item_set_name(&fi->group.cg_item, name);  	if (ret) {  		usb_put_function_instance(fi);  		return ERR_PTR(ret);  	} +	if (fi->set_inst_name) { +		ret = fi->set_inst_name(fi, instance_name); +		if (ret) { +			usb_put_function_instance(fi); +			return ERR_PTR(ret); +		} +	}  	gi = container_of(group, struct gadget_info, functions_group); @@ -728,6 +747,526 @@ static void gadget_strings_attr_release(struct config_item *item)  USB_CONFIG_STRING_RW_OPS(gadget_strings);  USB_CONFIG_STRINGS_LANG(gadget_strings, gadget_info); +static inline struct os_desc *to_os_desc(struct config_item *item) +{ +	return container_of(to_config_group(item), struct os_desc, group); +} + +CONFIGFS_ATTR_STRUCT(os_desc); +CONFIGFS_ATTR_OPS(os_desc); + +static ssize_t os_desc_use_show(struct os_desc *os_desc, char *page) +{ +	struct gadget_info *gi; + +	gi = to_gadget_info(os_desc->group.cg_item.ci_parent); + +	return sprintf(page, "%d", gi->use_os_desc); +} + +static ssize_t os_desc_use_store(struct os_desc *os_desc, const char *page, +				 size_t len) +{ +	struct gadget_info *gi; +	int ret; +	bool use; + +	gi = to_gadget_info(os_desc->group.cg_item.ci_parent); + +	mutex_lock(&gi->lock); +	ret = strtobool(page, &use); +	if (!ret) { +		gi->use_os_desc = use; +		ret = len; +	} +	mutex_unlock(&gi->lock); + +	return ret; +} + +static struct os_desc_attribute os_desc_use = +	__CONFIGFS_ATTR(use, S_IRUGO | S_IWUSR, +			os_desc_use_show, +			os_desc_use_store); + +static ssize_t os_desc_b_vendor_code_show(struct os_desc *os_desc, char *page) +{ +	struct gadget_info *gi; + +	gi = to_gadget_info(os_desc->group.cg_item.ci_parent); + +	return sprintf(page, "%d", gi->b_vendor_code); +} + +static ssize_t os_desc_b_vendor_code_store(struct os_desc *os_desc, +					   const char *page, size_t len) +{ +	struct gadget_info *gi; +	int ret; +	u8 b_vendor_code; + +	gi = to_gadget_info(os_desc->group.cg_item.ci_parent); + +	mutex_lock(&gi->lock); +	ret = kstrtou8(page, 0, &b_vendor_code); +	if (!ret) { +		gi->b_vendor_code = b_vendor_code; +		ret = len; +	} +	mutex_unlock(&gi->lock); + +	return ret; +} + +static struct os_desc_attribute os_desc_b_vendor_code = +	__CONFIGFS_ATTR(b_vendor_code, S_IRUGO | S_IWUSR, +			os_desc_b_vendor_code_show, +			os_desc_b_vendor_code_store); + +static ssize_t os_desc_qw_sign_show(struct os_desc *os_desc, char *page) +{ +	struct gadget_info *gi; + +	gi = to_gadget_info(os_desc->group.cg_item.ci_parent); + +	memcpy(page, gi->qw_sign, OS_STRING_QW_SIGN_LEN); + +	return OS_STRING_QW_SIGN_LEN; +} + +static ssize_t os_desc_qw_sign_store(struct os_desc *os_desc, const char *page, +				     size_t len) +{ +	struct gadget_info *gi; +	int res, l; + +	gi = to_gadget_info(os_desc->group.cg_item.ci_parent); +	l = min((int)len, OS_STRING_QW_SIGN_LEN >> 1); +	if (page[l - 1] == '\n') +		--l; + +	mutex_lock(&gi->lock); +	res = utf8s_to_utf16s(page, l, +			      UTF16_LITTLE_ENDIAN, (wchar_t *) gi->qw_sign, +			      OS_STRING_QW_SIGN_LEN); +	if (res > 0) +		res = len; +	mutex_unlock(&gi->lock); + +	return res; +} + +static struct os_desc_attribute os_desc_qw_sign = +	__CONFIGFS_ATTR(qw_sign, S_IRUGO | S_IWUSR, +			os_desc_qw_sign_show, +			os_desc_qw_sign_store); + +static struct configfs_attribute *os_desc_attrs[] = { +	&os_desc_use.attr, +	&os_desc_b_vendor_code.attr, +	&os_desc_qw_sign.attr, +	NULL, +}; + +static void os_desc_attr_release(struct config_item *item) +{ +	struct os_desc *os_desc = to_os_desc(item); +	kfree(os_desc); +} + +static int os_desc_link(struct config_item *os_desc_ci, +			struct config_item *usb_cfg_ci) +{ +	struct gadget_info *gi = container_of(to_config_group(os_desc_ci), +					struct gadget_info, os_desc_group); +	struct usb_composite_dev *cdev = &gi->cdev; +	struct config_usb_cfg *c_target = +		container_of(to_config_group(usb_cfg_ci), +			     struct config_usb_cfg, group); +	struct usb_configuration *c; +	int ret; + +	mutex_lock(&gi->lock); +	list_for_each_entry(c, &cdev->configs, list) { +		if (c == &c_target->c) +			break; +	} +	if (c != &c_target->c) { +		ret = -EINVAL; +		goto out; +	} + +	if (cdev->os_desc_config) { +		ret = -EBUSY; +		goto out; +	} + +	cdev->os_desc_config = &c_target->c; +	ret = 0; + +out: +	mutex_unlock(&gi->lock); +	return ret; +} + +static int os_desc_unlink(struct config_item *os_desc_ci, +			  struct config_item *usb_cfg_ci) +{ +	struct gadget_info *gi = container_of(to_config_group(os_desc_ci), +					struct gadget_info, os_desc_group); +	struct usb_composite_dev *cdev = &gi->cdev; + +	mutex_lock(&gi->lock); +	if (gi->udc_name) +		unregister_gadget(gi); +	cdev->os_desc_config = NULL; +	WARN_ON(gi->udc_name); +	mutex_unlock(&gi->lock); +	return 0; +} + +static struct configfs_item_operations os_desc_ops = { +	.release                = os_desc_attr_release, +	.show_attribute         = os_desc_attr_show, +	.store_attribute        = os_desc_attr_store, +	.allow_link		= os_desc_link, +	.drop_link		= os_desc_unlink, +}; + +static struct config_item_type os_desc_type = { +	.ct_item_ops	= &os_desc_ops, +	.ct_attrs	= os_desc_attrs, +	.ct_owner	= THIS_MODULE, +}; + +CONFIGFS_ATTR_STRUCT(usb_os_desc); +CONFIGFS_ATTR_OPS(usb_os_desc); + + +static inline struct usb_os_desc_ext_prop +*to_usb_os_desc_ext_prop(struct config_item *item) +{ +	return container_of(item, struct usb_os_desc_ext_prop, item); +} + +CONFIGFS_ATTR_STRUCT(usb_os_desc_ext_prop); +CONFIGFS_ATTR_OPS(usb_os_desc_ext_prop); + +static ssize_t ext_prop_type_show(struct usb_os_desc_ext_prop *ext_prop, +				  char *page) +{ +	return sprintf(page, "%d", ext_prop->type); +} + +static ssize_t ext_prop_type_store(struct usb_os_desc_ext_prop *ext_prop, +				   const char *page, size_t len) +{ +	struct usb_os_desc *desc = to_usb_os_desc(ext_prop->item.ci_parent); +	u8 type; +	int ret; + +	if (desc->opts_mutex) +		mutex_lock(desc->opts_mutex); +	ret = kstrtou8(page, 0, &type); +	if (ret) +		goto end; +	if (type < USB_EXT_PROP_UNICODE || type > USB_EXT_PROP_UNICODE_MULTI) { +		ret = -EINVAL; +		goto end; +	} + +	if ((ext_prop->type == USB_EXT_PROP_BINARY || +	    ext_prop->type == USB_EXT_PROP_LE32 || +	    ext_prop->type == USB_EXT_PROP_BE32) && +	    (type == USB_EXT_PROP_UNICODE || +	    type == USB_EXT_PROP_UNICODE_ENV || +	    type == USB_EXT_PROP_UNICODE_LINK)) +		ext_prop->data_len <<= 1; +	else if ((ext_prop->type == USB_EXT_PROP_UNICODE || +		   ext_prop->type == USB_EXT_PROP_UNICODE_ENV || +		   ext_prop->type == USB_EXT_PROP_UNICODE_LINK) && +		   (type == USB_EXT_PROP_BINARY || +		   type == USB_EXT_PROP_LE32 || +		   type == USB_EXT_PROP_BE32)) +		ext_prop->data_len >>= 1; +	ext_prop->type = type; +	ret = len; + +end: +	if (desc->opts_mutex) +		mutex_unlock(desc->opts_mutex); +	return ret; +} + +static ssize_t ext_prop_data_show(struct usb_os_desc_ext_prop *ext_prop, +				  char *page) +{ +	int len = ext_prop->data_len; + +	if (ext_prop->type == USB_EXT_PROP_UNICODE || +	    ext_prop->type == USB_EXT_PROP_UNICODE_ENV || +	    ext_prop->type == USB_EXT_PROP_UNICODE_LINK) +		len >>= 1; +	memcpy(page, ext_prop->data, len); + +	return len; +} + +static ssize_t ext_prop_data_store(struct usb_os_desc_ext_prop *ext_prop, +				   const char *page, size_t len) +{ +	struct usb_os_desc *desc = to_usb_os_desc(ext_prop->item.ci_parent); +	char *new_data; +	size_t ret_len = len; + +	if (page[len - 1] == '\n' || page[len - 1] == '\0') +		--len; +	new_data = kzalloc(len, GFP_KERNEL); +	if (!new_data) +		return -ENOMEM; + +	memcpy(new_data, page, len); + +	if (desc->opts_mutex) +		mutex_lock(desc->opts_mutex); +	kfree(ext_prop->data); +	ext_prop->data = new_data; +	desc->ext_prop_len -= ext_prop->data_len; +	ext_prop->data_len = len; +	desc->ext_prop_len += ext_prop->data_len; +	if (ext_prop->type == USB_EXT_PROP_UNICODE || +	    ext_prop->type == USB_EXT_PROP_UNICODE_ENV || +	    ext_prop->type == USB_EXT_PROP_UNICODE_LINK) { +		desc->ext_prop_len -= ext_prop->data_len; +		ext_prop->data_len <<= 1; +		ext_prop->data_len += 2; +		desc->ext_prop_len += ext_prop->data_len; +	} +	if (desc->opts_mutex) +		mutex_unlock(desc->opts_mutex); +	return ret_len; +} + +static struct usb_os_desc_ext_prop_attribute ext_prop_type = +	__CONFIGFS_ATTR(type, S_IRUGO | S_IWUSR, +			ext_prop_type_show, ext_prop_type_store); + +static struct usb_os_desc_ext_prop_attribute ext_prop_data = +	__CONFIGFS_ATTR(data, S_IRUGO | S_IWUSR, +			ext_prop_data_show, ext_prop_data_store); + +static struct configfs_attribute *ext_prop_attrs[] = { +	&ext_prop_type.attr, +	&ext_prop_data.attr, +	NULL, +}; + +static void usb_os_desc_ext_prop_release(struct config_item *item) +{ +	struct usb_os_desc_ext_prop *ext_prop = to_usb_os_desc_ext_prop(item); + +	kfree(ext_prop); /* frees a whole chunk */ +} + +static struct configfs_item_operations ext_prop_ops = { +	.release		= usb_os_desc_ext_prop_release, +	.show_attribute		= usb_os_desc_ext_prop_attr_show, +	.store_attribute	= usb_os_desc_ext_prop_attr_store, +}; + +static struct config_item *ext_prop_make( +		struct config_group *group, +		const char *name) +{ +	struct usb_os_desc_ext_prop *ext_prop; +	struct config_item_type *ext_prop_type; +	struct usb_os_desc *desc; +	char *vlabuf; + +	vla_group(data_chunk); +	vla_item(data_chunk, struct usb_os_desc_ext_prop, ext_prop, 1); +	vla_item(data_chunk, struct config_item_type, ext_prop_type, 1); + +	vlabuf = kzalloc(vla_group_size(data_chunk), GFP_KERNEL); +	if (!vlabuf) +		return ERR_PTR(-ENOMEM); + +	ext_prop = vla_ptr(vlabuf, data_chunk, ext_prop); +	ext_prop_type = vla_ptr(vlabuf, data_chunk, ext_prop_type); + +	desc = container_of(group, struct usb_os_desc, group); +	ext_prop_type->ct_item_ops = &ext_prop_ops; +	ext_prop_type->ct_attrs = ext_prop_attrs; +	ext_prop_type->ct_owner = desc->owner; + +	config_item_init_type_name(&ext_prop->item, name, ext_prop_type); + +	ext_prop->name = kstrdup(name, GFP_KERNEL); +	if (!ext_prop->name) { +		kfree(vlabuf); +		return ERR_PTR(-ENOMEM); +	} +	desc->ext_prop_len += 14; +	ext_prop->name_len = 2 * strlen(ext_prop->name) + 2; +	if (desc->opts_mutex) +		mutex_lock(desc->opts_mutex); +	desc->ext_prop_len += ext_prop->name_len; +	list_add_tail(&ext_prop->entry, &desc->ext_prop); +	++desc->ext_prop_count; +	if (desc->opts_mutex) +		mutex_unlock(desc->opts_mutex); + +	return &ext_prop->item; +} + +static void ext_prop_drop(struct config_group *group, struct config_item *item) +{ +	struct usb_os_desc_ext_prop *ext_prop = to_usb_os_desc_ext_prop(item); +	struct usb_os_desc *desc = to_usb_os_desc(&group->cg_item); + +	if (desc->opts_mutex) +		mutex_lock(desc->opts_mutex); +	list_del(&ext_prop->entry); +	--desc->ext_prop_count; +	kfree(ext_prop->name); +	desc->ext_prop_len -= (ext_prop->name_len + ext_prop->data_len + 14); +	if (desc->opts_mutex) +		mutex_unlock(desc->opts_mutex); +	config_item_put(item); +} + +static struct configfs_group_operations interf_grp_ops = { +	.make_item	= &ext_prop_make, +	.drop_item	= &ext_prop_drop, +}; + +static struct configfs_item_operations interf_item_ops = { +	.show_attribute		= usb_os_desc_attr_show, +	.store_attribute	= usb_os_desc_attr_store, +}; + +static ssize_t interf_grp_compatible_id_show(struct usb_os_desc *desc, +					     char *page) +{ +	memcpy(page, desc->ext_compat_id, 8); +	return 8; +} + +static ssize_t interf_grp_compatible_id_store(struct usb_os_desc *desc, +					      const char *page, size_t len) +{ +	int l; + +	l = min_t(int, 8, len); +	if (page[l - 1] == '\n') +		--l; +	if (desc->opts_mutex) +		mutex_lock(desc->opts_mutex); +	memcpy(desc->ext_compat_id, page, l); +	desc->ext_compat_id[l] = '\0'; + +	if (desc->opts_mutex) +		mutex_unlock(desc->opts_mutex); + +	return len; +} + +static struct usb_os_desc_attribute interf_grp_attr_compatible_id = +	__CONFIGFS_ATTR(compatible_id, S_IRUGO | S_IWUSR, +			interf_grp_compatible_id_show, +			interf_grp_compatible_id_store); + +static ssize_t interf_grp_sub_compatible_id_show(struct usb_os_desc *desc, +						 char *page) +{ +	memcpy(page, desc->ext_compat_id + 8, 8); +	return 8; +} + +static ssize_t interf_grp_sub_compatible_id_store(struct usb_os_desc *desc, +						  const char *page, size_t len) +{ +	int l; + +	l = min_t(int, 8, len); +	if (page[l - 1] == '\n') +		--l; +	if (desc->opts_mutex) +		mutex_lock(desc->opts_mutex); +	memcpy(desc->ext_compat_id + 8, page, l); +	desc->ext_compat_id[l + 8] = '\0'; + +	if (desc->opts_mutex) +		mutex_unlock(desc->opts_mutex); + +	return len; +} + +static struct usb_os_desc_attribute interf_grp_attr_sub_compatible_id = +	__CONFIGFS_ATTR(sub_compatible_id, S_IRUGO | S_IWUSR, +			interf_grp_sub_compatible_id_show, +			interf_grp_sub_compatible_id_store); + +static struct configfs_attribute *interf_grp_attrs[] = { +	&interf_grp_attr_compatible_id.attr, +	&interf_grp_attr_sub_compatible_id.attr, +	NULL +}; + +int usb_os_desc_prepare_interf_dir(struct config_group *parent, +				   int n_interf, +				   struct usb_os_desc **desc, +				   char **names, +				   struct module *owner) +{ +	struct config_group **f_default_groups, *os_desc_group, +				**interface_groups; +	struct config_item_type *os_desc_type, *interface_type; + +	vla_group(data_chunk); +	vla_item(data_chunk, struct config_group *, f_default_groups, 2); +	vla_item(data_chunk, struct config_group, os_desc_group, 1); +	vla_item(data_chunk, struct config_group *, interface_groups, +		 n_interf + 1); +	vla_item(data_chunk, struct config_item_type, os_desc_type, 1); +	vla_item(data_chunk, struct config_item_type, interface_type, 1); + +	char *vlabuf = kzalloc(vla_group_size(data_chunk), GFP_KERNEL); +	if (!vlabuf) +		return -ENOMEM; + +	f_default_groups = vla_ptr(vlabuf, data_chunk, f_default_groups); +	os_desc_group = vla_ptr(vlabuf, data_chunk, os_desc_group); +	os_desc_type = vla_ptr(vlabuf, data_chunk, os_desc_type); +	interface_groups = vla_ptr(vlabuf, data_chunk, interface_groups); +	interface_type = vla_ptr(vlabuf, data_chunk, interface_type); + +	parent->default_groups = f_default_groups; +	os_desc_type->ct_owner = owner; +	config_group_init_type_name(os_desc_group, "os_desc", os_desc_type); +	f_default_groups[0] = os_desc_group; + +	os_desc_group->default_groups = interface_groups; +	interface_type->ct_item_ops = &interf_item_ops; +	interface_type->ct_group_ops = &interf_grp_ops; +	interface_type->ct_attrs = interf_grp_attrs; +	interface_type->ct_owner = owner; + +	while (n_interf--) { +		struct usb_os_desc *d; + +		d = desc[n_interf]; +		d->owner = owner; +		config_group_init_type_name(&d->group, "", interface_type); +		config_item_set_name(&d->group.cg_item, "interface.%s", +				     names[n_interf]); +		interface_groups[n_interf] = &d->group; +	} + +	return 0; +} +EXPORT_SYMBOL(usb_os_desc_prepare_interf_dir); +  static int configfs_do_nothing(struct usb_composite_dev *cdev)  {  	WARN_ON(1); @@ -737,6 +1276,9 @@ static int configfs_do_nothing(struct usb_composite_dev *cdev)  int composite_dev_prepare(struct usb_composite_driver *composite,  		struct usb_composite_dev *dev); +int composite_os_desc_req_prepare(struct usb_composite_dev *cdev, +				  struct usb_ep *ep0); +  static void purge_configs_funcs(struct gadget_info *gi)  {  	struct usb_configuration	*c; @@ -785,7 +1327,7 @@ static int configfs_composite_bind(struct usb_gadget *gadget,  	ret = -EINVAL;  	if (list_empty(&gi->cdev.configs)) { -		pr_err("Need atleast one configuration in %s.\n", +		pr_err("Need at least one configuration in %s.\n",  				gi->composite.name);  		goto err_comp_cleanup;  	} @@ -796,7 +1338,7 @@ static int configfs_composite_bind(struct usb_gadget *gadget,  		cfg = container_of(c, struct config_usb_cfg, c);  		if (list_empty(&cfg->func_list)) { -			pr_err("Config %s/%d of %s needs atleast one function.\n", +			pr_err("Config %s/%d of %s needs at least one function.\n",  			      c->label, c->bConfigurationValue,  			      gi->composite.name);  			goto err_comp_cleanup; @@ -831,6 +1373,12 @@ static int configfs_composite_bind(struct usb_gadget *gadget,  		gi->cdev.desc.iSerialNumber = s[USB_GADGET_SERIAL_IDX].id;  	} +	if (gi->use_os_desc) { +		cdev->use_os_string = true; +		cdev->b_vendor_code = gi->b_vendor_code; +		memcpy(cdev->qw_sign, gi->qw_sign, OS_STRING_QW_SIGN_LEN); +	} +  	/* Go through all configs, attach all functions */  	list_for_each_entry(c, &gi->cdev.configs, list) {  		struct config_usb_cfg *cfg; @@ -866,6 +1414,12 @@ static int configfs_composite_bind(struct usb_gadget *gadget,  		}  		usb_ep_autoconfig_reset(cdev->gadget);  	} +	if (cdev->use_os_string) { +		ret = composite_os_desc_req_prepare(cdev, gadget->ep0); +		if (ret) +			goto err_purge_funcs; +	} +  	usb_ep_autoconfig_reset(cdev->gadget);  	return 0; @@ -921,6 +1475,7 @@ static struct config_group *gadgets_make(  	gi->group.default_groups[0] = &gi->functions_group;  	gi->group.default_groups[1] = &gi->configs_group;  	gi->group.default_groups[2] = &gi->strings_group; +	gi->group.default_groups[3] = &gi->os_desc_group;  	config_group_init_type_name(&gi->functions_group, "functions",  			&functions_type); @@ -928,6 +1483,8 @@ static struct config_group *gadgets_make(  			&config_desc_type);  	config_group_init_type_name(&gi->strings_group, "strings",  			&gadget_strings_strings_type); +	config_group_init_type_name(&gi->os_desc_group, "os_desc", +			&os_desc_type);  	gi->composite.bind = configfs_do_nothing;  	gi->composite.unbind = configfs_do_nothing; @@ -991,6 +1548,14 @@ static struct configfs_subsystem gadget_subsys = {  	.su_mutex = __MUTEX_INITIALIZER(gadget_subsys.su_mutex),  }; +void unregister_gadget_item(struct config_item *item) +{ +	struct gadget_info *gi = to_gadget_info(item); + +	unregister_gadget(gi); +} +EXPORT_SYMBOL_GPL(unregister_gadget_item); +  static int __init gadget_cfs_init(void)  {  	int ret; diff --git a/drivers/usb/gadget/configfs.h b/drivers/usb/gadget/configfs.h new file mode 100644 index 00000000000..36c468c4f5e --- /dev/null +++ b/drivers/usb/gadget/configfs.h @@ -0,0 +1,19 @@ +#ifndef USB__GADGET__CONFIGFS__H +#define USB__GADGET__CONFIGFS__H + +#include <linux/configfs.h> + +void unregister_gadget_item(struct config_item *item); + +int usb_os_desc_prepare_interf_dir(struct config_group *parent, +				   int n_interf, +				   struct usb_os_desc **desc, +				   char **names, +				   struct module *owner); + +static inline struct usb_os_desc *to_usb_os_desc(struct config_item *item) +{ +	return container_of(to_config_group(item), struct usb_os_desc, group); +} + +#endif /*  USB__GADGET__CONFIGFS__H */ diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c index 06ecd08fd57..2b54955d316 100644 --- a/drivers/usb/gadget/dummy_hcd.c +++ b/drivers/usb/gadget/dummy_hcd.c @@ -544,7 +544,7 @@ static int dummy_enable(struct usb_ep *_ep,  		 default:  			 val = "ctrl";  			 break; -		 }; val; }), +		 } val; }),  		max, ep->stream_en ? "enabled" : "disabled");  	/* at this point real hardware should be NAKing transfers @@ -561,7 +561,6 @@ static int dummy_disable(struct usb_ep *_ep)  	struct dummy_ep		*ep;  	struct dummy		*dum;  	unsigned long		flags; -	int			retval;  	ep = usb_ep_to_dummy_ep(_ep);  	if (!_ep || !ep->desc || _ep->name == ep0name) @@ -571,12 +570,11 @@ static int dummy_disable(struct usb_ep *_ep)  	spin_lock_irqsave(&dum->lock, flags);  	ep->desc = NULL;  	ep->stream_en = 0; -	retval = 0;  	nuke(dum, ep);  	spin_unlock_irqrestore(&dum->lock, flags);  	dev_dbg(udc_dev(dum), "disabled %s\n", _ep->name); -	return retval; +	return 0;  }  static struct usb_request *dummy_alloc_request(struct usb_ep *_ep, @@ -923,8 +921,9 @@ static int dummy_udc_stop(struct usb_gadget *g,  	struct dummy_hcd	*dum_hcd = gadget_to_dummy_hcd(g);  	struct dummy		*dum = dum_hcd->dum; -	dev_dbg(udc_dev(dum), "unregister gadget driver '%s'\n", -			driver->driver.name); +	if (driver) +		dev_dbg(udc_dev(dum), "unregister gadget driver '%s'\n", +				driver->driver.name);  	dum->driver = NULL; @@ -950,7 +949,7 @@ static void init_dummy_udc_hw(struct dummy *dum)  		list_add_tail(&ep->ep.ep_list, &dum->gadget.ep_list);  		ep->halted = ep->wedged = ep->already_seen =  				ep->setup_stage = 0; -		ep->ep.maxpacket = ~0; +		usb_ep_set_maxpacket_limit(&ep->ep, ~0);  		ep->ep.max_streams = 16;  		ep->last_io = jiffies;  		ep->gadget = &dum->gadget; @@ -1000,8 +999,8 @@ static int dummy_udc_remove(struct platform_device *pdev)  {  	struct dummy	*dum = platform_get_drvdata(pdev); -	usb_del_gadget_udc(&dum->gadget);  	device_remove_file(&dum->gadget.dev, &dev_attr_function); +	usb_del_gadget_udc(&dum->gadget);  	return 0;  } @@ -2270,7 +2269,7 @@ static inline ssize_t show_urb(char *buf, size_t size, struct urb *urb)  		default:  			s = "?";  			break; -		 }; s; }), +		 } s; }),  		ep, ep ? (usb_pipein(urb->pipe) ? "in" : "out") : "",  		({ char *s; \  		switch (usb_pipetype(urb->pipe)) { \ @@ -2286,7 +2285,7 @@ static inline ssize_t show_urb(char *buf, size_t size, struct urb *urb)  		default: \  			s = "-iso"; \  			break; \ -		}; s; }), +		} s; }),  		urb->actual_length, urb->transfer_buffer_length);  } diff --git a/drivers/usb/gadget/epautoconf.c b/drivers/usb/gadget/epautoconf.c index a777f7bd11b..0567cca1465 100644 --- a/drivers/usb/gadget/epautoconf.c +++ b/drivers/usb/gadget/epautoconf.c @@ -11,7 +11,6 @@  #include <linux/kernel.h>  #include <linux/module.h> -#include <linux/init.h>  #include <linux/types.h>  #include <linux/device.h> @@ -58,7 +57,7 @@ ep_matches (  		return 0;  	/* only support ep0 for portable CONTROL traffic */ -	type = desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK; +	type = usb_endpoint_type(desc);  	if (USB_ENDPOINT_XFER_CONTROL == type)  		return 0; @@ -129,7 +128,7 @@ ep_matches (  	 * and wants to know the maximum possible, provide the info.  	 */  	if (desc->wMaxPacketSize == 0) -		desc->wMaxPacketSize = cpu_to_le16(ep->maxpacket); +		desc->wMaxPacketSize = cpu_to_le16(ep->maxpacket_limit);  	/* endpoint maxpacket size is an input parameter, except for bulk  	 * where it's an output parameter representing the full speed limit. @@ -145,7 +144,7 @@ ep_matches (  	case USB_ENDPOINT_XFER_ISOC:  		/* ISO:  limit 1023 bytes full speed, 1024 high/super speed */ -		if (ep->maxpacket < max) +		if (ep->maxpacket_limit < max)  			return 0;  		if (!gadget_is_dualspeed(gadget) && max > 1023)  			return 0; @@ -178,7 +177,7 @@ ep_matches (  	/* report (variable) full speed bulk maxpacket */  	if ((USB_ENDPOINT_XFER_BULK == type) && !ep_comp) { -		int size = ep->maxpacket; +		int size = ep->maxpacket_limit;  		/* min() doesn't work on bitfields with gcc-3.5 */  		if (size > 64) diff --git a/drivers/usb/gadget/f_ecm.c b/drivers/usb/gadget/f_ecm.c index edab45da374..798760fa7e7 100644 --- a/drivers/usb/gadget/f_ecm.c +++ b/drivers/usb/gadget/f_ecm.c @@ -691,7 +691,6 @@ ecm_bind(struct usb_configuration *c, struct usb_function *f)  	int			status;  	struct usb_ep		*ep; -#ifndef USBF_ECM_INCLUDED  	struct f_ecm_opts	*ecm_opts;  	if (!can_support_ecm(cdev->gadget)) @@ -715,7 +714,7 @@ ecm_bind(struct usb_configuration *c, struct usb_function *f)  			return status;  		ecm_opts->bound = true;  	} -#endif +  	us = usb_gstrings_attach(cdev, ecm_strings,  				 ARRAY_SIZE(ecm_string_defs));  	if (IS_ERR(us)) @@ -834,74 +833,6 @@ fail:  	return status;  } -#ifdef USBF_ECM_INCLUDED - -static void -ecm_old_unbind(struct usb_configuration *c, struct usb_function *f) -{ -	struct f_ecm		*ecm = func_to_ecm(f); - -	DBG(c->cdev, "ecm unbind\n"); - -	usb_free_all_descriptors(f); - -	kfree(ecm->notify_req->buf); -	usb_ep_free_request(ecm->notify, ecm->notify_req); -	kfree(ecm); -} - -/** - * ecm_bind_config - add CDC Ethernet network link to a configuration - * @c: the configuration to support the network link - * @ethaddr: a buffer in which the ethernet address of the host side - *	side of the link was recorded - * @dev: eth_dev structure - * Context: single threaded during gadget setup - * - * Returns zero on success, else negative errno. - * - * Caller must have called @gether_setup().  Caller is also responsible - * for calling @gether_cleanup() before module unload. - */ -int -ecm_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN], -		struct eth_dev *dev) -{ -	struct f_ecm	*ecm; -	int		status; - -	if (!can_support_ecm(c->cdev->gadget) || !ethaddr) -		return -EINVAL; - -	/* allocate and initialize one new instance */ -	ecm = kzalloc(sizeof *ecm, GFP_KERNEL); -	if (!ecm) -		return -ENOMEM; - -	/* export host's Ethernet address in CDC format */ -	snprintf(ecm->ethaddr, sizeof ecm->ethaddr, "%pm", ethaddr); -	ecm_string_defs[1].s = ecm->ethaddr; - -	ecm->port.ioport = dev; -	ecm->port.cdc_filter = DEFAULT_FILTER; - -	ecm->port.func.name = "cdc_ethernet"; -	/* descriptors are per-instance copies */ -	ecm->port.func.bind = ecm_bind; -	ecm->port.func.unbind = ecm_old_unbind; -	ecm->port.func.set_alt = ecm_set_alt; -	ecm->port.func.get_alt = ecm_get_alt; -	ecm->port.func.setup = ecm_setup; -	ecm->port.func.disable = ecm_disable; - -	status = usb_add_function(c, &ecm->port.func); -	if (status) -		kfree(ecm); -	return status; -} - -#else -  static inline struct f_ecm_opts *to_f_ecm_opts(struct config_item *item)  {  	return container_of(to_config_group(item), struct f_ecm_opts, @@ -995,7 +926,7 @@ static void ecm_unbind(struct usb_configuration *c, struct usb_function *f)  	usb_ep_free_request(ecm->notify, ecm->notify_req);  } -struct usb_function *ecm_alloc(struct usb_function_instance *fi) +static struct usb_function *ecm_alloc(struct usb_function_instance *fi)  {  	struct f_ecm	*ecm;  	struct f_ecm_opts *opts; @@ -1040,5 +971,3 @@ struct usb_function *ecm_alloc(struct usb_function_instance *fi)  DECLARE_USB_FUNCTION_INIT(ecm, ecm_alloc_inst, ecm_alloc);  MODULE_LICENSE("GPL");  MODULE_AUTHOR("David Brownell"); - -#endif diff --git a/drivers/usb/gadget/f_eem.c b/drivers/usb/gadget/f_eem.c index d00392d879d..d61c11d765d 100644 --- a/drivers/usb/gadget/f_eem.c +++ b/drivers/usb/gadget/f_eem.c @@ -624,7 +624,7 @@ static void eem_unbind(struct usb_configuration *c, struct usb_function *f)  	usb_free_all_descriptors(f);  } -struct usb_function *eem_alloc(struct usb_function_instance *fi) +static struct usb_function *eem_alloc(struct usb_function_instance *fi)  {  	struct f_eem	*eem;  	struct f_eem_opts *opts; diff --git a/drivers/usb/gadget/f_fs.c b/drivers/usb/gadget/f_fs.c index 1a66c5baa0d..8598c27c7d4 100644 --- a/drivers/usb/gadget/f_fs.c +++ b/drivers/usb/gadget/f_fs.c @@ -22,218 +22,21 @@  #include <linux/pagemap.h>  #include <linux/export.h>  #include <linux/hid.h> +#include <linux/module.h>  #include <asm/unaligned.h>  #include <linux/usb/composite.h>  #include <linux/usb/functionfs.h> +#include <linux/aio.h> +#include <linux/mmu_context.h> +#include <linux/poll.h> -#define FUNCTIONFS_MAGIC	0xa647361 /* Chosen by a honest dice roll ;) */ - - -/* Debugging ****************************************************************/ - -#ifdef VERBOSE_DEBUG -#ifndef pr_vdebug -#  define pr_vdebug pr_debug -#endif /* pr_vdebug */ -#  define ffs_dump_mem(prefix, ptr, len) \ -	print_hex_dump_bytes(pr_fmt(prefix ": "), DUMP_PREFIX_NONE, ptr, len) -#else -#ifndef pr_vdebug -#  define pr_vdebug(...)                 do { } while (0) -#endif /* pr_vdebug */ -#  define ffs_dump_mem(prefix, ptr, len) do { } while (0) -#endif /* VERBOSE_DEBUG */ - -#define ENTER()    pr_vdebug("%s()\n", __func__) - - -/* The data structure and setup file ****************************************/ - -enum ffs_state { -	/* -	 * Waiting for descriptors and strings. -	 * -	 * In this state no open(2), read(2) or write(2) on epfiles -	 * may succeed (which should not be the problem as there -	 * should be no such files opened in the first place). -	 */ -	FFS_READ_DESCRIPTORS, -	FFS_READ_STRINGS, - -	/* -	 * We've got descriptors and strings.  We are or have called -	 * functionfs_ready_callback().  functionfs_bind() may have -	 * been called but we don't know. -	 * -	 * This is the only state in which operations on epfiles may -	 * succeed. -	 */ -	FFS_ACTIVE, - -	/* -	 * All endpoints have been closed.  This state is also set if -	 * we encounter an unrecoverable error.  The only -	 * unrecoverable error is situation when after reading strings -	 * from user space we fail to initialise epfiles or -	 * functionfs_ready_callback() returns with error (<0). -	 * -	 * In this state no open(2), read(2) or write(2) (both on ep0 -	 * as well as epfile) may succeed (at this point epfiles are -	 * unlinked and all closed so this is not a problem; ep0 is -	 * also closed but ep0 file exists and so open(2) on ep0 must -	 * fail). -	 */ -	FFS_CLOSING -}; - - -enum ffs_setup_state { -	/* There is no setup request pending. */ -	FFS_NO_SETUP, -	/* -	 * User has read events and there was a setup request event -	 * there.  The next read/write on ep0 will handle the -	 * request. -	 */ -	FFS_SETUP_PENDING, -	/* -	 * There was event pending but before user space handled it -	 * some other event was introduced which canceled existing -	 * setup.  If this state is set read/write on ep0 return -	 * -EIDRM.  This state is only set when adding event. -	 */ -	FFS_SETUP_CANCELED -}; - - - -struct ffs_epfile; -struct ffs_function; - -struct ffs_data { -	struct usb_gadget		*gadget; - -	/* -	 * Protect access read/write operations, only one read/write -	 * at a time.  As a consequence protects ep0req and company. -	 * While setup request is being processed (queued) this is -	 * held. -	 */ -	struct mutex			mutex; - -	/* -	 * Protect access to endpoint related structures (basically -	 * usb_ep_queue(), usb_ep_dequeue(), etc. calls) except for -	 * endpoint zero. -	 */ -	spinlock_t			eps_lock; +#include "u_fs.h" +#include "u_f.h" +#include "configfs.h" -	/* -	 * XXX REVISIT do we need our own request? Since we are not -	 * handling setup requests immediately user space may be so -	 * slow that another setup will be sent to the gadget but this -	 * time not to us but another function and then there could be -	 * a race.  Is that the case? Or maybe we can use cdev->req -	 * after all, maybe we just need some spinlock for that? -	 */ -	struct usb_request		*ep0req;		/* P: mutex */ -	struct completion		ep0req_completion;	/* P: mutex */ -	int				ep0req_status;		/* P: mutex */ - -	/* reference counter */ -	atomic_t			ref; -	/* how many files are opened (EP0 and others) */ -	atomic_t			opened; - -	/* EP0 state */ -	enum ffs_state			state; - -	/* -	 * Possible transitions: -	 * + FFS_NO_SETUP       -> FFS_SETUP_PENDING  -- P: ev.waitq.lock -	 *               happens only in ep0 read which is P: mutex -	 * + FFS_SETUP_PENDING  -> FFS_NO_SETUP       -- P: ev.waitq.lock -	 *               happens only in ep0 i/o  which is P: mutex -	 * + FFS_SETUP_PENDING  -> FFS_SETUP_CANCELED -- P: ev.waitq.lock -	 * + FFS_SETUP_CANCELED -> FFS_NO_SETUP       -- cmpxchg -	 */ -	enum ffs_setup_state		setup_state; - -#define FFS_SETUP_STATE(ffs)					\ -	((enum ffs_setup_state)cmpxchg(&(ffs)->setup_state,	\ -				       FFS_SETUP_CANCELED, FFS_NO_SETUP)) - -	/* Events & such. */ -	struct { -		u8				types[4]; -		unsigned short			count; -		/* XXX REVISIT need to update it in some places, or do we? */ -		unsigned short			can_stall; -		struct usb_ctrlrequest		setup; - -		wait_queue_head_t		waitq; -	} ev; /* the whole structure, P: ev.waitq.lock */ - -	/* Flags */ -	unsigned long			flags; -#define FFS_FL_CALL_CLOSED_CALLBACK 0 -#define FFS_FL_BOUND                1 - -	/* Active function */ -	struct ffs_function		*func; - -	/* -	 * Device name, write once when file system is mounted. -	 * Intended for user to read if she wants. -	 */ -	const char			*dev_name; -	/* Private data for our user (ie. gadget).  Managed by user. */ -	void				*private_data; - -	/* filled by __ffs_data_got_descs() */ -	/* -	 * Real descriptors are 16 bytes after raw_descs (so you need -	 * to skip 16 bytes (ie. ffs->raw_descs + 16) to get to the -	 * first full speed descriptor).  raw_descs_length and -	 * raw_fs_descs_length do not have those 16 bytes added. -	 */ -	const void			*raw_descs; -	unsigned			raw_descs_length; -	unsigned			raw_fs_descs_length; -	unsigned			fs_descs_count; -	unsigned			hs_descs_count; - -	unsigned short			strings_count; -	unsigned short			interfaces_count; -	unsigned short			eps_count; -	unsigned short			_pad1; - -	/* filled by __ffs_data_got_strings() */ -	/* ids in stringtabs are set in functionfs_bind() */ -	const void			*raw_strings; -	struct usb_gadget_strings	**stringtabs; - -	/* -	 * File system's super block, write once when file system is -	 * mounted. -	 */ -	struct super_block		*sb; - -	/* File permissions, written once when fs is mounted */ -	struct ffs_file_perms { -		umode_t				mode; -		kuid_t				uid; -		kgid_t				gid; -	}				file_perms; - -	/* -	 * The endpoint files, filled by ffs_epfiles_create(), -	 * destroyed by ffs_epfiles_destroy(). -	 */ -	struct ffs_epfile		*epfiles; -}; +#define FUNCTIONFS_MAGIC	0xa647361 /* Chosen by a honest dice roll ;) */  /* Reference counter handling */  static void ffs_data_get(struct ffs_data *ffs); @@ -274,15 +77,20 @@ static struct ffs_function *ffs_func_from_usb(struct usb_function *f)  	return container_of(f, struct ffs_function, function);  } -static void ffs_func_free(struct ffs_function *func); + +static inline enum ffs_setup_state +ffs_setup_state_clear_cancelled(struct ffs_data *ffs) +{ +	return (enum ffs_setup_state) +		cmpxchg(&ffs->setup_state, FFS_SETUP_CANCELLED, FFS_NO_SETUP); +} +  static void ffs_func_eps_disable(struct ffs_function *func);  static int __must_check ffs_func_eps_enable(struct ffs_function *func);  static int ffs_func_bind(struct usb_configuration *,  			 struct usb_function *); -static void ffs_func_unbind(struct usb_configuration *, -			    struct usb_function *);  static int ffs_func_set_alt(struct usb_function *, unsigned, unsigned);  static void ffs_func_disable(struct usb_function *);  static int ffs_func_setup(struct usb_function *, @@ -301,8 +109,8 @@ struct ffs_ep {  	struct usb_ep			*ep;	/* P: ffs->eps_lock */  	struct usb_request		*req;	/* P: epfile->mutex */ -	/* [0]: full speed, [1]: high speed */ -	struct usb_endpoint_descriptor	*descs[2]; +	/* [0]: full speed, [1]: high speed, [2]: super speed */ +	struct usb_endpoint_descriptor	*descs[3];  	u8				num; @@ -327,6 +135,25 @@ struct ffs_epfile {  	unsigned char			_pad;  }; +/*  ffs_io_data structure ***************************************************/ + +struct ffs_io_data { +	bool aio; +	bool read; + +	struct kiocb *kiocb; +	const struct iovec *iovec; +	unsigned long nr_segs; +	char __user *buf; +	size_t len; + +	struct mm_struct *mm; +	struct work_struct work; + +	struct usb_ep *ep; +	struct usb_request *req; +}; +  static int  __must_check ffs_epfiles_create(struct ffs_data *ffs);  static void ffs_epfiles_destroy(struct ffs_epfile *epfiles, unsigned count); @@ -335,6 +162,19 @@ ffs_sb_create_file(struct super_block *sb, const char *name, void *data,  		   const struct file_operations *fops,  		   struct dentry **dentry_p); +/* Devices management *******************************************************/ + +DEFINE_MUTEX(ffs_lock); +EXPORT_SYMBOL_GPL(ffs_lock); + +static struct ffs_dev *_ffs_find_dev(const char *name); +static struct ffs_dev *_ffs_alloc_dev(void); +static int _ffs_name_dev(struct ffs_dev *dev, const char *name); +static void _ffs_free_dev(struct ffs_dev *dev); +static void *ffs_acquire_dev(const char *dev_name); +static void ffs_release_dev(struct ffs_data *ffs_data); +static int ffs_ready(struct ffs_data *ffs); +static void ffs_closed(struct ffs_data *ffs);  /* Misc helper functions ****************************************************/ @@ -373,7 +213,7 @@ static int __ffs_ep0_queue_wait(struct ffs_data *ffs, char *data, size_t len)  	if (req->buf == NULL)  		req->buf = (void *)0xDEADBABE; -	INIT_COMPLETION(ffs->ep0req_completion); +	reinit_completion(&ffs->ep0req_completion);  	ret = usb_ep_queue(ffs->gadget->ep0, req, GFP_ATOMIC);  	if (unlikely(ret < 0)) @@ -386,7 +226,7 @@ static int __ffs_ep0_queue_wait(struct ffs_data *ffs, char *data, size_t len)  	}  	ffs->setup_state = FFS_NO_SETUP; -	return ffs->ep0req_status; +	return req->status ? req->status : req->actual;  }  static int __ffs_ep0_stall(struct ffs_data *ffs) @@ -412,7 +252,7 @@ static ssize_t ffs_ep0_write(struct file *file, const char __user *buf,  	ENTER();  	/* Fast check if setup was canceled */ -	if (FFS_SETUP_STATE(ffs) == FFS_SETUP_CANCELED) +	if (ffs_setup_state_clear_cancelled(ffs) == FFS_SETUP_CANCELLED)  		return -EIDRM;  	/* Acquire mutex */ @@ -460,7 +300,7 @@ static ssize_t ffs_ep0_write(struct file *file, const char __user *buf,  			ffs->state = FFS_ACTIVE;  			mutex_unlock(&ffs->mutex); -			ret = functionfs_ready_callback(ffs); +			ret = ffs_ready(ffs);  			if (unlikely(ret < 0)) {  				ffs->state = FFS_CLOSING;  				return ret; @@ -478,8 +318,8 @@ static ssize_t ffs_ep0_write(struct file *file, const char __user *buf,  		 * rather then _irqsave  		 */  		spin_lock_irq(&ffs->ev.waitq.lock); -		switch (FFS_SETUP_STATE(ffs)) { -		case FFS_SETUP_CANCELED: +		switch (ffs_setup_state_clear_cancelled(ffs)) { +		case FFS_SETUP_CANCELLED:  			ret = -EIDRM;  			goto done_spin; @@ -514,7 +354,7 @@ static ssize_t ffs_ep0_write(struct file *file, const char __user *buf,  		/*  		 * We are guaranteed to be still in FFS_ACTIVE state  		 * but the state of setup could have changed from -		 * FFS_SETUP_PENDING to FFS_SETUP_CANCELED so we need +		 * FFS_SETUP_PENDING to FFS_SETUP_CANCELLED so we need  		 * to check for that.  If that happened we copied data  		 * from user space in vain but it's unlikely.  		 * @@ -523,7 +363,8 @@ static ssize_t ffs_ep0_write(struct file *file, const char __user *buf,  		 * transition can be performed and it's protected by  		 * mutex.  		 */ -		if (FFS_SETUP_STATE(ffs) == FFS_SETUP_CANCELED) { +		if (ffs_setup_state_clear_cancelled(ffs) == +		    FFS_SETUP_CANCELLED) {  			ret = -EIDRM;  done_spin:  			spin_unlock_irq(&ffs->ev.waitq.lock); @@ -589,7 +430,7 @@ static ssize_t ffs_ep0_read(struct file *file, char __user *buf,  	ENTER();  	/* Fast check if setup was canceled */ -	if (FFS_SETUP_STATE(ffs) == FFS_SETUP_CANCELED) +	if (ffs_setup_state_clear_cancelled(ffs) == FFS_SETUP_CANCELLED)  		return -EIDRM;  	/* Acquire mutex */ @@ -609,8 +450,8 @@ static ssize_t ffs_ep0_read(struct file *file, char __user *buf,  	 */  	spin_lock_irq(&ffs->ev.waitq.lock); -	switch (FFS_SETUP_STATE(ffs)) { -	case FFS_SETUP_CANCELED: +	switch (ffs_setup_state_clear_cancelled(ffs)) { +	case FFS_SETUP_CANCELLED:  		ret = -EIDRM;  		break; @@ -657,7 +498,8 @@ static ssize_t ffs_ep0_read(struct file *file, char __user *buf,  		spin_lock_irq(&ffs->ev.waitq.lock);  		/* See ffs_ep0_write() */ -		if (FFS_SETUP_STATE(ffs) == FFS_SETUP_CANCELED) { +		if (ffs_setup_state_clear_cancelled(ffs) == +		    FFS_SETUP_CANCELLED) {  			ret = -EIDRM;  			break;  		} @@ -726,6 +568,45 @@ static long ffs_ep0_ioctl(struct file *file, unsigned code, unsigned long value)  	return ret;  } +static unsigned int ffs_ep0_poll(struct file *file, poll_table *wait) +{ +	struct ffs_data *ffs = file->private_data; +	unsigned int mask = POLLWRNORM; +	int ret; + +	poll_wait(file, &ffs->ev.waitq, wait); + +	ret = ffs_mutex_lock(&ffs->mutex, file->f_flags & O_NONBLOCK); +	if (unlikely(ret < 0)) +		return mask; + +	switch (ffs->state) { +	case FFS_READ_DESCRIPTORS: +	case FFS_READ_STRINGS: +		mask |= POLLOUT; +		break; + +	case FFS_ACTIVE: +		switch (ffs->setup_state) { +		case FFS_NO_SETUP: +			if (ffs->ev.count) +				mask |= POLLIN; +			break; + +		case FFS_SETUP_PENDING: +		case FFS_SETUP_CANCELLED: +			mask |= (POLLIN | POLLOUT); +			break; +		} +	case FFS_CLOSING: +		break; +	} + +	mutex_unlock(&ffs->mutex); + +	return mask; +} +  static const struct file_operations ffs_ep0_operations = {  	.llseek =	no_llseek, @@ -734,6 +615,7 @@ static const struct file_operations ffs_ep0_operations = {  	.read =		ffs_ep0_read,  	.release =	ffs_ep0_release,  	.unlocked_ioctl =	ffs_ep0_ioctl, +	.poll =		ffs_ep0_poll,  }; @@ -749,114 +631,226 @@ static void ffs_epfile_io_complete(struct usb_ep *_ep, struct usb_request *req)  	}  } -static ssize_t ffs_epfile_io(struct file *file, -			     char __user *buf, size_t len, int read) +static void ffs_user_copy_worker(struct work_struct *work) +{ +	struct ffs_io_data *io_data = container_of(work, struct ffs_io_data, +						   work); +	int ret = io_data->req->status ? io_data->req->status : +					 io_data->req->actual; + +	if (io_data->read && ret > 0) { +		int i; +		size_t pos = 0; +		use_mm(io_data->mm); +		for (i = 0; i < io_data->nr_segs; i++) { +			if (unlikely(copy_to_user(io_data->iovec[i].iov_base, +						 &io_data->buf[pos], +						 io_data->iovec[i].iov_len))) { +				ret = -EFAULT; +				break; +			} +			pos += io_data->iovec[i].iov_len; +		} +		unuse_mm(io_data->mm); +	} + +	aio_complete(io_data->kiocb, ret, ret); + +	usb_ep_free_request(io_data->ep, io_data->req); + +	io_data->kiocb->private = NULL; +	if (io_data->read) +		kfree(io_data->iovec); +	kfree(io_data->buf); +	kfree(io_data); +} + +static void ffs_epfile_async_io_complete(struct usb_ep *_ep, +					 struct usb_request *req) +{ +	struct ffs_io_data *io_data = req->context; + +	ENTER(); + +	INIT_WORK(&io_data->work, ffs_user_copy_worker); +	schedule_work(&io_data->work); +} + +static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data)  {  	struct ffs_epfile *epfile = file->private_data;  	struct ffs_ep *ep;  	char *data = NULL; -	ssize_t ret; +	ssize_t ret, data_len;  	int halt; -	goto first_try; -	do { -		spin_unlock_irq(&epfile->ffs->eps_lock); -		mutex_unlock(&epfile->mutex); +	/* Are we still active? */ +	if (WARN_ON(epfile->ffs->state != FFS_ACTIVE)) { +		ret = -ENODEV; +		goto error; +	} -first_try: -		/* Are we still active? */ -		if (WARN_ON(epfile->ffs->state != FFS_ACTIVE)) { -			ret = -ENODEV; +	/* Wait for endpoint to be enabled */ +	ep = epfile->ep; +	if (!ep) { +		if (file->f_flags & O_NONBLOCK) { +			ret = -EAGAIN;  			goto error;  		} -		/* Wait for endpoint to be enabled */ -		ep = epfile->ep; -		if (!ep) { -			if (file->f_flags & O_NONBLOCK) { -				ret = -EAGAIN; -				goto error; -			} - -			if (wait_event_interruptible(epfile->wait, -						     (ep = epfile->ep))) { -				ret = -EINTR; -				goto error; -			} -		} - -		/* Do we halt? */ -		halt = !read == !epfile->in; -		if (halt && epfile->isoc) { -			ret = -EINVAL; +		ret = wait_event_interruptible(epfile->wait, (ep = epfile->ep)); +		if (ret) { +			ret = -EINTR;  			goto error;  		} +	} -		/* Allocate & copy */ -		if (!halt && !data) { -			data = kzalloc(len, GFP_KERNEL); -			if (unlikely(!data)) -				return -ENOMEM; +	/* Do we halt? */ +	halt = (!io_data->read == !epfile->in); +	if (halt && epfile->isoc) { +		ret = -EINVAL; +		goto error; +	} -			if (!read && -			    unlikely(__copy_from_user(data, buf, len))) { +	/* Allocate & copy */ +	if (!halt) { +		/* +		 * if we _do_ wait above, the epfile->ffs->gadget might be NULL +		 * before the waiting completes, so do not assign to 'gadget' earlier +		 */ +		struct usb_gadget *gadget = epfile->ffs->gadget; + +		spin_lock_irq(&epfile->ffs->eps_lock); +		/* In the meantime, endpoint got disabled or changed. */ +		if (epfile->ep != ep) { +			spin_unlock_irq(&epfile->ffs->eps_lock); +			return -ESHUTDOWN; +		} +		/* +		 * Controller may require buffer size to be aligned to +		 * maxpacketsize of an out endpoint. +		 */ +		data_len = io_data->read ? +			   usb_ep_align_maybe(gadget, ep->ep, io_data->len) : +			   io_data->len; +		spin_unlock_irq(&epfile->ffs->eps_lock); + +		data = kmalloc(data_len, GFP_KERNEL); +		if (unlikely(!data)) +			return -ENOMEM; +		if (io_data->aio && !io_data->read) { +			int i; +			size_t pos = 0; +			for (i = 0; i < io_data->nr_segs; i++) { +				if (unlikely(copy_from_user(&data[pos], +					     io_data->iovec[i].iov_base, +					     io_data->iovec[i].iov_len))) { +					ret = -EFAULT; +					goto error; +				} +				pos += io_data->iovec[i].iov_len; +			} +		} else { +			if (!io_data->read && +			    unlikely(__copy_from_user(data, io_data->buf, +						      io_data->len))) {  				ret = -EFAULT;  				goto error;  			}  		} +	} -		/* We will be using request */ -		ret = ffs_mutex_lock(&epfile->mutex, -				     file->f_flags & O_NONBLOCK); -		if (unlikely(ret)) -			goto error; - -		/* -		 * We're called from user space, we can use _irq rather then -		 * _irqsave -		 */ -		spin_lock_irq(&epfile->ffs->eps_lock); +	/* We will be using request */ +	ret = ffs_mutex_lock(&epfile->mutex, file->f_flags & O_NONBLOCK); +	if (unlikely(ret)) +		goto error; -		/* -		 * While we were acquiring mutex endpoint got disabled -		 * or changed? -		 */ -	} while (unlikely(epfile->ep != ep)); +	spin_lock_irq(&epfile->ffs->eps_lock); -	/* Halt */ -	if (unlikely(halt)) { +	if (epfile->ep != ep) { +		/* In the meantime, endpoint got disabled or changed. */ +		ret = -ESHUTDOWN; +		spin_unlock_irq(&epfile->ffs->eps_lock); +	} else if (halt) { +		/* Halt */  		if (likely(epfile->ep == ep) && !WARN_ON(!ep->ep))  			usb_ep_set_halt(ep->ep);  		spin_unlock_irq(&epfile->ffs->eps_lock);  		ret = -EBADMSG;  	} else {  		/* Fire the request */ -		DECLARE_COMPLETION_ONSTACK(done); +		struct usb_request *req; -		struct usb_request *req = ep->req; -		req->context  = &done; -		req->complete = ffs_epfile_io_complete; -		req->buf      = data; -		req->length   = len; +		if (io_data->aio) { +			req = usb_ep_alloc_request(ep->ep, GFP_KERNEL); +			if (unlikely(!req)) +				goto error_lock; -		ret = usb_ep_queue(ep->ep, req, GFP_ATOMIC); +			req->buf      = data; +			req->length   = io_data->len; -		spin_unlock_irq(&epfile->ffs->eps_lock); +			io_data->buf = data; +			io_data->ep = ep->ep; +			io_data->req = req; -		if (unlikely(ret < 0)) { -			/* nop */ -		} else if (unlikely(wait_for_completion_interruptible(&done))) { -			ret = -EINTR; -			usb_ep_dequeue(ep->ep, req); +			req->context  = io_data; +			req->complete = ffs_epfile_async_io_complete; + +			ret = usb_ep_queue(ep->ep, req, GFP_ATOMIC); +			if (unlikely(ret)) { +				usb_ep_free_request(ep->ep, req); +				goto error_lock; +			} +			ret = -EIOCBQUEUED; + +			spin_unlock_irq(&epfile->ffs->eps_lock);  		} else { -			ret = ep->status; -			if (read && ret > 0 && -			    unlikely(copy_to_user(buf, data, ret))) -				ret = -EFAULT; +			DECLARE_COMPLETION_ONSTACK(done); + +			req = ep->req; +			req->buf      = data; +			req->length   = io_data->len; + +			req->context  = &done; +			req->complete = ffs_epfile_io_complete; + +			ret = usb_ep_queue(ep->ep, req, GFP_ATOMIC); + +			spin_unlock_irq(&epfile->ffs->eps_lock); + +			if (unlikely(ret < 0)) { +				/* nop */ +			} else if (unlikely( +				   wait_for_completion_interruptible(&done))) { +				ret = -EINTR; +				usb_ep_dequeue(ep->ep, req); +			} else { +				/* +				 * XXX We may end up silently droping data +				 * here.  Since data_len (i.e. req->length) may +				 * be bigger than len (after being rounded up +				 * to maxpacketsize), we may end up with more +				 * data then user space has space for. +				 */ +				ret = ep->status; +				if (io_data->read && ret > 0) { +					ret = min_t(size_t, ret, io_data->len); + +					if (unlikely(copy_to_user(io_data->buf, +						data, ret))) +						ret = -EFAULT; +				} +			} +			kfree(data);  		}  	}  	mutex_unlock(&epfile->mutex); +	return ret; + +error_lock: +	spin_unlock_irq(&epfile->ffs->eps_lock); +	mutex_unlock(&epfile->mutex);  error:  	kfree(data);  	return ret; @@ -866,17 +860,31 @@ static ssize_t  ffs_epfile_write(struct file *file, const char __user *buf, size_t len,  		 loff_t *ptr)  { +	struct ffs_io_data io_data; +  	ENTER(); -	return ffs_epfile_io(file, (char __user *)buf, len, 0); +	io_data.aio = false; +	io_data.read = false; +	io_data.buf = (char * __user)buf; +	io_data.len = len; + +	return ffs_epfile_io(file, &io_data);  }  static ssize_t  ffs_epfile_read(struct file *file, char __user *buf, size_t len, loff_t *ptr)  { +	struct ffs_io_data io_data; +  	ENTER(); -	return ffs_epfile_io(file, buf, len, 1); +	io_data.aio = false; +	io_data.read = true; +	io_data.buf = buf; +	io_data.len = len; + +	return ffs_epfile_io(file, &io_data);  }  static int @@ -895,6 +903,89 @@ ffs_epfile_open(struct inode *inode, struct file *file)  	return 0;  } +static int ffs_aio_cancel(struct kiocb *kiocb) +{ +	struct ffs_io_data *io_data = kiocb->private; +	struct ffs_epfile *epfile = kiocb->ki_filp->private_data; +	int value; + +	ENTER(); + +	spin_lock_irq(&epfile->ffs->eps_lock); + +	if (likely(io_data && io_data->ep && io_data->req)) +		value = usb_ep_dequeue(io_data->ep, io_data->req); +	else +		value = -EINVAL; + +	spin_unlock_irq(&epfile->ffs->eps_lock); + +	return value; +} + +static ssize_t ffs_epfile_aio_write(struct kiocb *kiocb, +				    const struct iovec *iovec, +				    unsigned long nr_segs, loff_t loff) +{ +	struct ffs_io_data *io_data; + +	ENTER(); + +	io_data = kmalloc(sizeof(*io_data), GFP_KERNEL); +	if (unlikely(!io_data)) +		return -ENOMEM; + +	io_data->aio = true; +	io_data->read = false; +	io_data->kiocb = kiocb; +	io_data->iovec = iovec; +	io_data->nr_segs = nr_segs; +	io_data->len = kiocb->ki_nbytes; +	io_data->mm = current->mm; + +	kiocb->private = io_data; + +	kiocb_set_cancel_fn(kiocb, ffs_aio_cancel); + +	return ffs_epfile_io(kiocb->ki_filp, io_data); +} + +static ssize_t ffs_epfile_aio_read(struct kiocb *kiocb, +				   const struct iovec *iovec, +				   unsigned long nr_segs, loff_t loff) +{ +	struct ffs_io_data *io_data; +	struct iovec *iovec_copy; + +	ENTER(); + +	iovec_copy = kmalloc_array(nr_segs, sizeof(*iovec_copy), GFP_KERNEL); +	if (unlikely(!iovec_copy)) +		return -ENOMEM; + +	memcpy(iovec_copy, iovec, sizeof(struct iovec)*nr_segs); + +	io_data = kmalloc(sizeof(*io_data), GFP_KERNEL); +	if (unlikely(!io_data)) { +		kfree(iovec_copy); +		return -ENOMEM; +	} + +	io_data->aio = true; +	io_data->read = true; +	io_data->kiocb = kiocb; +	io_data->iovec = iovec_copy; +	io_data->nr_segs = nr_segs; +	io_data->len = kiocb->ki_nbytes; +	io_data->mm = current->mm; + +	kiocb->private = io_data; + +	kiocb_set_cancel_fn(kiocb, ffs_aio_cancel); + +	return ffs_epfile_io(kiocb->ki_filp, io_data); +} +  static int  ffs_epfile_release(struct inode *inode, struct file *file)  { @@ -951,6 +1042,8 @@ static const struct file_operations ffs_epfile_operations = {  	.open =		ffs_epfile_open,  	.write =	ffs_epfile_write,  	.read =		ffs_epfile_read, +	.aio_write =	ffs_epfile_aio_write, +	.aio_read =	ffs_epfile_aio_read,  	.release =	ffs_epfile_release,  	.unlocked_ioctl =	ffs_epfile_ioctl,  }; @@ -1034,37 +1127,19 @@ struct ffs_sb_fill_data {  	struct ffs_file_perms perms;  	umode_t root_mode;  	const char *dev_name; -	union { -		/* set by ffs_fs_mount(), read by ffs_sb_fill() */ -		void *private_data; -		/* set by ffs_sb_fill(), read by ffs_fs_mount */ -		struct ffs_data *ffs_data; -	}; +	struct ffs_data *ffs_data;  };  static int ffs_sb_fill(struct super_block *sb, void *_data, int silent)  {  	struct ffs_sb_fill_data *data = _data;  	struct inode	*inode; -	struct ffs_data	*ffs; +	struct ffs_data	*ffs = data->ffs_data;  	ENTER(); -	/* Initialise data */ -	ffs = ffs_data_new(); -	if (unlikely(!ffs)) -		goto Enomem; -  	ffs->sb              = sb; -	ffs->dev_name        = kstrdup(data->dev_name, GFP_KERNEL); -	if (unlikely(!ffs->dev_name)) -		goto Enomem; -	ffs->file_perms      = data->perms; -	ffs->private_data    = data->private_data; - -	/* used by the caller of this function */ -	data->ffs_data       = ffs; - +	data->ffs_data       = NULL;  	sb->s_fs_info        = ffs;  	sb->s_blocksize      = PAGE_CACHE_SIZE;  	sb->s_blocksize_bits = PAGE_CACHE_SHIFT; @@ -1080,17 +1155,14 @@ static int ffs_sb_fill(struct super_block *sb, void *_data, int silent)  				  &data->perms);  	sb->s_root = d_make_root(inode);  	if (unlikely(!sb->s_root)) -		goto Enomem; +		return -ENOMEM;  	/* EP0 file */  	if (unlikely(!ffs_sb_create_file(sb, "ep0", ffs,  					 &ffs_ep0_operations, NULL))) -		goto Enomem; +		return -ENOMEM;  	return 0; - -Enomem: -	return -ENOMEM;  }  static int ffs_fs_parse_opts(struct ffs_sb_fill_data *data, char *opts) @@ -1193,6 +1265,7 @@ ffs_fs_mount(struct file_system_type *t, int flags,  	struct dentry *rv;  	int ret;  	void *ffs_dev; +	struct ffs_data	*ffs;  	ENTER(); @@ -1200,18 +1273,30 @@ ffs_fs_mount(struct file_system_type *t, int flags,  	if (unlikely(ret < 0))  		return ERR_PTR(ret); -	ffs_dev = functionfs_acquire_dev_callback(dev_name); -	if (IS_ERR(ffs_dev)) -		return ffs_dev; +	ffs = ffs_data_new(); +	if (unlikely(!ffs)) +		return ERR_PTR(-ENOMEM); +	ffs->file_perms = data.perms; -	data.dev_name = dev_name; -	data.private_data = ffs_dev; -	rv = mount_nodev(t, flags, &data, ffs_sb_fill); +	ffs->dev_name = kstrdup(dev_name, GFP_KERNEL); +	if (unlikely(!ffs->dev_name)) { +		ffs_data_put(ffs); +		return ERR_PTR(-ENOMEM); +	} -	/* data.ffs_data is set by ffs_sb_fill */ -	if (IS_ERR(rv)) -		functionfs_release_dev_callback(data.ffs_data); +	ffs_dev = ffs_acquire_dev(dev_name); +	if (IS_ERR(ffs_dev)) { +		ffs_data_put(ffs); +		return ERR_CAST(ffs_dev); +	} +	ffs->private_data = ffs_dev; +	data.ffs_data = ffs; +	rv = mount_nodev(t, flags, &data, ffs_sb_fill); +	if (IS_ERR(rv) && data.ffs_data) { +		ffs_release_dev(data.ffs_data); +		ffs_data_put(data.ffs_data); +	}  	return rv;  } @@ -1222,7 +1307,7 @@ ffs_fs_kill_sb(struct super_block *sb)  	kill_litter_super(sb);  	if (sb->s_fs_info) { -		functionfs_release_dev_callback(sb->s_fs_info); +		ffs_release_dev(sb->s_fs_info);  		ffs_data_put(sb->s_fs_info);  	}  } @@ -1312,7 +1397,7 @@ static struct ffs_data *ffs_data_new(void)  {  	struct ffs_data *ffs = kzalloc(sizeof *ffs, GFP_KERNEL);  	if (unlikely(!ffs)) -		return 0; +		return NULL;  	ENTER(); @@ -1335,14 +1420,14 @@ static void ffs_data_clear(struct ffs_data *ffs)  	ENTER();  	if (test_and_clear_bit(FFS_FL_CALL_CLOSED_CALLBACK, &ffs->flags)) -		functionfs_closed_callback(ffs); +		ffs_closed(ffs);  	BUG_ON(ffs->gadget);  	if (ffs->epfiles)  		ffs_epfiles_destroy(ffs->epfiles, ffs->eps_count); -	kfree(ffs->raw_descs); +	kfree(ffs->raw_descs_data);  	kfree(ffs->raw_strings);  	kfree(ffs->stringtabs);  } @@ -1354,14 +1439,15 @@ static void ffs_data_reset(struct ffs_data *ffs)  	ffs_data_clear(ffs);  	ffs->epfiles = NULL; +	ffs->raw_descs_data = NULL;  	ffs->raw_descs = NULL;  	ffs->raw_strings = NULL;  	ffs->stringtabs = NULL;  	ffs->raw_descs_length = 0; -	ffs->raw_fs_descs_length = 0;  	ffs->fs_descs_count = 0;  	ffs->hs_descs_count = 0; +	ffs->ss_descs_count = 0;  	ffs->strings_count = 0;  	ffs->interfaces_count = 0; @@ -1397,11 +1483,13 @@ static int functionfs_bind(struct ffs_data *ffs, struct usb_composite_dev *cdev)  	ffs->ep0req->context = ffs;  	lang = ffs->stringtabs; -	for (lang = ffs->stringtabs; *lang; ++lang) { -		struct usb_string *str = (*lang)->strings; -		int id = first_id; -		for (; str->s; ++id, ++str) -			str->id = id; +	if (lang) { +		for (; *lang; ++lang) { +			struct usb_string *str = (*lang)->strings; +			int id = first_id; +			for (; str->s; ++id, ++str) +				str->id = id; +		}  	}  	ffs->gadget = cdev->gadget; @@ -1471,71 +1559,6 @@ static void ffs_epfiles_destroy(struct ffs_epfile *epfiles, unsigned count)  	kfree(epfiles);  } -static int functionfs_bind_config(struct usb_composite_dev *cdev, -				  struct usb_configuration *c, -				  struct ffs_data *ffs) -{ -	struct ffs_function *func; -	int ret; - -	ENTER(); - -	func = kzalloc(sizeof *func, GFP_KERNEL); -	if (unlikely(!func)) -		return -ENOMEM; - -	func->function.name    = "Function FS Gadget"; -	func->function.strings = ffs->stringtabs; - -	func->function.bind    = ffs_func_bind; -	func->function.unbind  = ffs_func_unbind; -	func->function.set_alt = ffs_func_set_alt; -	func->function.disable = ffs_func_disable; -	func->function.setup   = ffs_func_setup; -	func->function.suspend = ffs_func_suspend; -	func->function.resume  = ffs_func_resume; - -	func->conf   = c; -	func->gadget = cdev->gadget; -	func->ffs = ffs; -	ffs_data_get(ffs); - -	ret = usb_add_function(c, &func->function); -	if (unlikely(ret)) -		ffs_func_free(func); - -	return ret; -} - -static void ffs_func_free(struct ffs_function *func) -{ -	struct ffs_ep *ep         = func->eps; -	unsigned count            = func->ffs->eps_count; -	unsigned long flags; - -	ENTER(); - -	/* cleanup after autoconfig */ -	spin_lock_irqsave(&func->ffs->eps_lock, flags); -	do { -		if (ep->ep && ep->req) -			usb_ep_free_request(ep->ep, ep->req); -		ep->req = NULL; -		++ep; -	} while (--count); -	spin_unlock_irqrestore(&func->ffs->eps_lock, flags); - -	ffs_data_put(func->ffs); - -	kfree(func->eps); -	/* -	 * eps and interfaces_nums are allocated in the same chunk so -	 * only one free is required.  Descriptors are also allocated -	 * in the same chunk. -	 */ - -	kfree(func); -}  static void ffs_func_eps_disable(struct ffs_function *func)  { @@ -1569,7 +1592,24 @@ static int ffs_func_eps_enable(struct ffs_function *func)  	spin_lock_irqsave(&func->ffs->eps_lock, flags);  	do {  		struct usb_endpoint_descriptor *ds; -		ds = ep->descs[ep->descs[1] ? 1 : 0]; +		int desc_idx; + +		if (ffs->gadget->speed == USB_SPEED_SUPER) +			desc_idx = 2; +		else if (ffs->gadget->speed == USB_SPEED_HIGH) +			desc_idx = 1; +		else +			desc_idx = 0; + +		/* fall-back to lower speed if desc missing for current speed */ +		do { +			ds = ep->descs[desc_idx]; +		} while (!ds && --desc_idx >= 0); + +		if (!ds) { +			ret = -EINVAL; +			break; +		}  		ep->ep->driver_data = ep;  		ep->ep->desc = ds; @@ -1704,6 +1744,12 @@ static int __must_check ffs_do_desc(char *data, unsigned len,  	}  		break; +	case USB_DT_SS_ENDPOINT_COMP: +		pr_vdebug("EP SS companion descriptor\n"); +		if (length != sizeof(struct usb_ss_ep_comp_descriptor)) +			goto inv_length; +		break; +  	case USB_DT_OTHER_SPEED_CONFIG:  	case USB_DT_INTERFACE_POWER:  	case USB_DT_DEBUG: @@ -1814,60 +1860,76 @@ static int __ffs_data_do_entity(enum ffs_entity_type type,  static int __ffs_data_got_descs(struct ffs_data *ffs,  				char *const _data, size_t len)  { -	unsigned fs_count, hs_count; -	int fs_len, ret = -EINVAL; -	char *data = _data; +	char *data = _data, *raw_descs; +	unsigned counts[3], flags; +	int ret = -EINVAL, i;  	ENTER(); -	if (unlikely(get_unaligned_le32(data) != FUNCTIONFS_DESCRIPTORS_MAGIC || -		     get_unaligned_le32(data + 4) != len)) +	if (get_unaligned_le32(data + 4) != len)  		goto error; -	fs_count = get_unaligned_le32(data +  8); -	hs_count = get_unaligned_le32(data + 12); - -	if (!fs_count && !hs_count) -		goto einval; -	data += 16; -	len  -= 16; - -	if (likely(fs_count)) { -		fs_len = ffs_do_descs(fs_count, data, len, -				      __ffs_data_do_entity, ffs); -		if (unlikely(fs_len < 0)) { -			ret = fs_len; +	switch (get_unaligned_le32(data)) { +	case FUNCTIONFS_DESCRIPTORS_MAGIC: +		flags = FUNCTIONFS_HAS_FS_DESC | FUNCTIONFS_HAS_HS_DESC; +		data += 8; +		len  -= 8; +		break; +	case FUNCTIONFS_DESCRIPTORS_MAGIC_V2: +		flags = get_unaligned_le32(data + 8); +		if (flags & ~(FUNCTIONFS_HAS_FS_DESC | +			      FUNCTIONFS_HAS_HS_DESC | +			      FUNCTIONFS_HAS_SS_DESC)) { +			ret = -ENOSYS;  			goto error;  		} +		data += 12; +		len  -= 12; +		break; +	default: +		goto error; +	} -		data += fs_len; -		len  -= fs_len; -	} else { -		fs_len = 0; +	/* Read fs_count, hs_count and ss_count (if present) */ +	for (i = 0; i < 3; ++i) { +		if (!(flags & (1 << i))) { +			counts[i] = 0; +		} else if (len < 4) { +			goto error; +		} else { +			counts[i] = get_unaligned_le32(data); +			data += 4; +			len  -= 4; +		}  	} -	if (likely(hs_count)) { -		ret = ffs_do_descs(hs_count, data, len, +	/* Read descriptors */ +	raw_descs = data; +	for (i = 0; i < 3; ++i) { +		if (!counts[i]) +			continue; +		ret = ffs_do_descs(counts[i], data, len,  				   __ffs_data_do_entity, ffs); -		if (unlikely(ret < 0)) +		if (ret < 0)  			goto error; -	} else { -		ret = 0; +		data += ret; +		len  -= ret;  	} -	if (unlikely(len != ret)) -		goto einval; +	if (raw_descs == data || len) { +		ret = -EINVAL; +		goto error; +	} -	ffs->raw_fs_descs_length = fs_len; -	ffs->raw_descs_length    = fs_len + ret; -	ffs->raw_descs           = _data; -	ffs->fs_descs_count      = fs_count; -	ffs->hs_descs_count      = hs_count; +	ffs->raw_descs_data	= _data; +	ffs->raw_descs		= raw_descs; +	ffs->raw_descs_length	= data - raw_descs; +	ffs->fs_descs_count	= counts[0]; +	ffs->hs_descs_count	= counts[1]; +	ffs->ss_descs_count	= counts[2];  	return 0; -einval: -	ret = -EINVAL;  error:  	kfree(_data);  	return ret; @@ -1909,30 +1971,34 @@ static int __ffs_data_got_strings(struct ffs_data *ffs,  	/* Allocate everything in one chunk so there's less maintenance. */  	{ -		struct { -			struct usb_gadget_strings *stringtabs[lang_count + 1]; -			struct usb_gadget_strings stringtab[lang_count]; -			struct usb_string strings[lang_count*(needed_count+1)]; -		} *d;  		unsigned i = 0; +		vla_group(d); +		vla_item(d, struct usb_gadget_strings *, stringtabs, +			lang_count + 1); +		vla_item(d, struct usb_gadget_strings, stringtab, lang_count); +		vla_item(d, struct usb_string, strings, +			lang_count*(needed_count+1)); + +		char *vlabuf = kmalloc(vla_group_size(d), GFP_KERNEL); -		d = kmalloc(sizeof *d, GFP_KERNEL); -		if (unlikely(!d)) { +		if (unlikely(!vlabuf)) {  			kfree(_data);  			return -ENOMEM;  		} -		stringtabs = d->stringtabs; -		t = d->stringtab; +		/* Initialize the VLA pointers */ +		stringtabs = vla_ptr(vlabuf, d, stringtabs); +		t = vla_ptr(vlabuf, d, stringtab);  		i = lang_count;  		do {  			*stringtabs++ = t++;  		} while (--i);  		*stringtabs = NULL; -		stringtabs = d->stringtabs; -		t = d->stringtab; -		s = d->strings; +		/* stringtabs = vlabuf = d_stringtabs for later kfree */ +		stringtabs = vla_ptr(vlabuf, d, stringtabs); +		t = vla_ptr(vlabuf, d, stringtab); +		s = vla_ptr(vlabuf, d, strings);  		strings = s;  	} @@ -2020,7 +2086,7 @@ static void __ffs_event_add(struct ffs_data *ffs,  	 * the source does nothing.  	 */  	if (ffs->setup_state == FFS_SETUP_PENDING) -		ffs->setup_state = FFS_SETUP_CANCELED; +		ffs->setup_state = FFS_SETUP_CANCELLED;  	switch (type) {  	case FUNCTIONFS_RESUME: @@ -2081,21 +2147,28 @@ static int __ffs_func_bind_do_descs(enum ffs_entity_type type, u8 *valuep,  	struct usb_endpoint_descriptor *ds = (void *)desc;  	struct ffs_function *func = priv;  	struct ffs_ep *ffs_ep; - -	/* -	 * If hs_descriptors is not NULL then we are reading hs -	 * descriptors now -	 */ -	const int isHS = func->function.hs_descriptors != NULL; -	unsigned idx; +	unsigned ep_desc_id, idx; +	static const char *speed_names[] = { "full", "high", "super" };  	if (type != FFS_DESCRIPTOR)  		return 0; -	if (isHS) +	/* +	 * If ss_descriptors is not NULL, we are reading super speed +	 * descriptors; if hs_descriptors is not NULL, we are reading high +	 * speed descriptors; otherwise, we are reading full speed +	 * descriptors. +	 */ +	if (func->function.ss_descriptors) { +		ep_desc_id = 2; +		func->function.ss_descriptors[(long)valuep] = desc; +	} else if (func->function.hs_descriptors) { +		ep_desc_id = 1;  		func->function.hs_descriptors[(long)valuep] = desc; -	else +	} else { +		ep_desc_id = 0;  		func->function.fs_descriptors[(long)valuep]    = desc; +	}  	if (!desc || desc->bDescriptorType != USB_DT_ENDPOINT)  		return 0; @@ -2103,13 +2176,13 @@ static int __ffs_func_bind_do_descs(enum ffs_entity_type type, u8 *valuep,  	idx = (ds->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK) - 1;  	ffs_ep = func->eps + idx; -	if (unlikely(ffs_ep->descs[isHS])) { -		pr_vdebug("two %sspeed descriptors for EP %d\n", -			  isHS ? "high" : "full", +	if (unlikely(ffs_ep->descs[ep_desc_id])) { +		pr_err("two %sspeed descriptors for EP %d\n", +			  speed_names[ep_desc_id],  			  ds->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK);  		return -EINVAL;  	} -	ffs_ep->descs[isHS] = ds; +	ffs_ep->descs[ep_desc_id] = ds;  	ffs_dump_mem(": Original  ep desc", ds, ds->bLength);  	if (ffs_ep->ep) { @@ -2195,8 +2268,57 @@ static int __ffs_func_bind_do_nums(enum ffs_entity_type type, u8 *valuep,  	return 0;  } -static int ffs_func_bind(struct usb_configuration *c, -			 struct usb_function *f) +static inline struct f_fs_opts *ffs_do_functionfs_bind(struct usb_function *f, +						struct usb_configuration *c) +{ +	struct ffs_function *func = ffs_func_from_usb(f); +	struct f_fs_opts *ffs_opts = +		container_of(f->fi, struct f_fs_opts, func_inst); +	int ret; + +	ENTER(); + +	/* +	 * Legacy gadget triggers binding in functionfs_ready_callback, +	 * which already uses locking; taking the same lock here would +	 * cause a deadlock. +	 * +	 * Configfs-enabled gadgets however do need ffs_dev_lock. +	 */ +	if (!ffs_opts->no_configfs) +		ffs_dev_lock(); +	ret = ffs_opts->dev->desc_ready ? 0 : -ENODEV; +	func->ffs = ffs_opts->dev->ffs_data; +	if (!ffs_opts->no_configfs) +		ffs_dev_unlock(); +	if (ret) +		return ERR_PTR(ret); + +	func->conf = c; +	func->gadget = c->cdev->gadget; + +	ffs_data_get(func->ffs); + +	/* +	 * in drivers/usb/gadget/configfs.c:configfs_composite_bind() +	 * configurations are bound in sequence with list_for_each_entry, +	 * in each configuration its functions are bound in sequence +	 * with list_for_each_entry, so we assume no race condition +	 * with regard to ffs_opts->bound access +	 */ +	if (!ffs_opts->refcnt) { +		ret = functionfs_bind(func->ffs, c->cdev); +		if (ret) +			return ERR_PTR(ret); +	} +	ffs_opts->refcnt++; +	func->function.strings = func->ffs->stringtabs; + +	return ffs_opts; +} + +static int _ffs_func_bind(struct usb_configuration *c, +			  struct usb_function *f)  {  	struct ffs_function *func = ffs_func_from_usb(f);  	struct ffs_data *ffs = func->ffs; @@ -2204,42 +2326,54 @@ static int ffs_func_bind(struct usb_configuration *c,  	const int full = !!func->ffs->fs_descs_count;  	const int high = gadget_is_dualspeed(func->gadget) &&  		func->ffs->hs_descs_count; +	const int super = gadget_is_superspeed(func->gadget) && +		func->ffs->ss_descs_count; -	int ret; +	int fs_len, hs_len, ret;  	/* Make it a single chunk, less management later on */ -	struct { -		struct ffs_ep eps[ffs->eps_count]; -		struct usb_descriptor_header -			*fs_descs[full ? ffs->fs_descs_count + 1 : 0]; -		struct usb_descriptor_header -			*hs_descs[high ? ffs->hs_descs_count + 1 : 0]; -		short inums[ffs->interfaces_count]; -		char raw_descs[high ? ffs->raw_descs_length -				    : ffs->raw_fs_descs_length]; -	} *data; +	vla_group(d); +	vla_item_with_sz(d, struct ffs_ep, eps, ffs->eps_count); +	vla_item_with_sz(d, struct usb_descriptor_header *, fs_descs, +		full ? ffs->fs_descs_count + 1 : 0); +	vla_item_with_sz(d, struct usb_descriptor_header *, hs_descs, +		high ? ffs->hs_descs_count + 1 : 0); +	vla_item_with_sz(d, struct usb_descriptor_header *, ss_descs, +		super ? ffs->ss_descs_count + 1 : 0); +	vla_item_with_sz(d, short, inums, ffs->interfaces_count); +	vla_item_with_sz(d, char, raw_descs, ffs->raw_descs_length); +	char *vlabuf;  	ENTER(); -	/* Only high speed but not supported by gadget? */ -	if (unlikely(!(full | high))) +	/* Has descriptors only for speeds gadget does not support */ +	if (unlikely(!(full | high | super)))  		return -ENOTSUPP; -	/* Allocate */ -	data = kmalloc(sizeof *data, GFP_KERNEL); -	if (unlikely(!data)) +	/* Allocate a single chunk, less management later on */ +	vlabuf = kmalloc(vla_group_size(d), GFP_KERNEL); +	if (unlikely(!vlabuf))  		return -ENOMEM;  	/* Zero */ -	memset(data->eps, 0, sizeof data->eps); -	memcpy(data->raw_descs, ffs->raw_descs + 16, sizeof data->raw_descs); -	memset(data->inums, 0xff, sizeof data->inums); -	for (ret = ffs->eps_count; ret; --ret) -		data->eps[ret].num = -1; +	memset(vla_ptr(vlabuf, d, eps), 0, d_eps__sz); +	/* Copy descriptors  */ +	memcpy(vla_ptr(vlabuf, d, raw_descs), ffs->raw_descs, +	       ffs->raw_descs_length); -	/* Save pointers */ -	func->eps             = data->eps; -	func->interfaces_nums = data->inums; +	memset(vla_ptr(vlabuf, d, inums), 0xff, d_inums__sz); +	for (ret = ffs->eps_count; ret; --ret) { +		struct ffs_ep *ptr; + +		ptr = vla_ptr(vlabuf, d, eps); +		ptr[ret].num = -1; +	} + +	/* Save pointers +	 * d_eps == vlabuf, func->eps used to kfree vlabuf later +	*/ +	func->eps             = vla_ptr(vlabuf, d, eps); +	func->interfaces_nums = vla_ptr(vlabuf, d, inums);  	/*  	 * Go through all the endpoint descriptors and allocate @@ -2247,23 +2381,41 @@ static int ffs_func_bind(struct usb_configuration *c,  	 * numbers without worrying that it may be described later on.  	 */  	if (likely(full)) { -		func->function.fs_descriptors = data->fs_descs; -		ret = ffs_do_descs(ffs->fs_descs_count, -				   data->raw_descs, -				   sizeof data->raw_descs, -				   __ffs_func_bind_do_descs, func); -		if (unlikely(ret < 0)) +		func->function.fs_descriptors = vla_ptr(vlabuf, d, fs_descs); +		fs_len = ffs_do_descs(ffs->fs_descs_count, +				      vla_ptr(vlabuf, d, raw_descs), +				      d_raw_descs__sz, +				      __ffs_func_bind_do_descs, func); +		if (unlikely(fs_len < 0)) { +			ret = fs_len;  			goto error; +		}  	} else { -		ret = 0; +		fs_len = 0;  	}  	if (likely(high)) { -		func->function.hs_descriptors = data->hs_descs; -		ret = ffs_do_descs(ffs->hs_descs_count, -				   data->raw_descs + ret, -				   (sizeof data->raw_descs) - ret, -				   __ffs_func_bind_do_descs, func); +		func->function.hs_descriptors = vla_ptr(vlabuf, d, hs_descs); +		hs_len = ffs_do_descs(ffs->hs_descs_count, +				      vla_ptr(vlabuf, d, raw_descs) + fs_len, +				      d_raw_descs__sz - fs_len, +				      __ffs_func_bind_do_descs, func); +		if (unlikely(hs_len < 0)) { +			ret = hs_len; +			goto error; +		} +	} else { +		hs_len = 0; +	} + +	if (likely(super)) { +		func->function.ss_descriptors = vla_ptr(vlabuf, d, ss_descs); +		ret = ffs_do_descs(ffs->ss_descs_count, +				vla_ptr(vlabuf, d, raw_descs) + fs_len + hs_len, +				d_raw_descs__sz - fs_len - hs_len, +				__ffs_func_bind_do_descs, func); +		if (unlikely(ret < 0)) +			goto error;  	}  	/* @@ -2272,8 +2424,9 @@ static int ffs_func_bind(struct usb_configuration *c,  	 * now.  	 */  	ret = ffs_do_descs(ffs->fs_descs_count + -			   (high ? ffs->hs_descs_count : 0), -			   data->raw_descs, sizeof data->raw_descs, +			   (high ? ffs->hs_descs_count : 0) + +			   (super ? ffs->ss_descs_count : 0), +			   vla_ptr(vlabuf, d, raw_descs), d_raw_descs__sz,  			   __ffs_func_bind_do_nums, func);  	if (unlikely(ret < 0))  		goto error; @@ -2287,26 +2440,19 @@ error:  	return ret;  } - -/* Other USB function hooks *************************************************/ - -static void ffs_func_unbind(struct usb_configuration *c, -			    struct usb_function *f) +static int ffs_func_bind(struct usb_configuration *c, +			 struct usb_function *f)  { -	struct ffs_function *func = ffs_func_from_usb(f); -	struct ffs_data *ffs = func->ffs; +	struct f_fs_opts *ffs_opts = ffs_do_functionfs_bind(f, c); -	ENTER(); +	if (IS_ERR(ffs_opts)) +		return PTR_ERR(ffs_opts); -	if (ffs->func == func) { -		ffs_func_eps_disable(func); -		ffs->func = NULL; -	} +	return _ffs_func_bind(c, f); +} -	ffs_event_add(ffs, FUNCTIONFS_UNBIND); -	ffs_func_free(func); -} +/* Other USB function hooks *************************************************/  static int ffs_func_set_alt(struct usb_function *f,  			    unsigned interface, unsigned alt) @@ -2434,6 +2580,413 @@ static int ffs_func_revmap_intf(struct ffs_function *func, u8 intf)  } +/* Devices management *******************************************************/ + +static LIST_HEAD(ffs_devices); + +static struct ffs_dev *_ffs_do_find_dev(const char *name) +{ +	struct ffs_dev *dev; + +	list_for_each_entry(dev, &ffs_devices, entry) { +		if (!dev->name || !name) +			continue; +		if (strcmp(dev->name, name) == 0) +			return dev; +	} + +	return NULL; +} + +/* + * ffs_lock must be taken by the caller of this function + */ +static struct ffs_dev *_ffs_get_single_dev(void) +{ +	struct ffs_dev *dev; + +	if (list_is_singular(&ffs_devices)) { +		dev = list_first_entry(&ffs_devices, struct ffs_dev, entry); +		if (dev->single) +			return dev; +	} + +	return NULL; +} + +/* + * ffs_lock must be taken by the caller of this function + */ +static struct ffs_dev *_ffs_find_dev(const char *name) +{ +	struct ffs_dev *dev; + +	dev = _ffs_get_single_dev(); +	if (dev) +		return dev; + +	return _ffs_do_find_dev(name); +} + +/* Configfs support *********************************************************/ + +static inline struct f_fs_opts *to_ffs_opts(struct config_item *item) +{ +	return container_of(to_config_group(item), struct f_fs_opts, +			    func_inst.group); +} + +static void ffs_attr_release(struct config_item *item) +{ +	struct f_fs_opts *opts = to_ffs_opts(item); + +	usb_put_function_instance(&opts->func_inst); +} + +static struct configfs_item_operations ffs_item_ops = { +	.release	= ffs_attr_release, +}; + +static struct config_item_type ffs_func_type = { +	.ct_item_ops	= &ffs_item_ops, +	.ct_owner	= THIS_MODULE, +}; + + +/* Function registration interface ******************************************/ + +static void ffs_free_inst(struct usb_function_instance *f) +{ +	struct f_fs_opts *opts; + +	opts = to_f_fs_opts(f); +	ffs_dev_lock(); +	_ffs_free_dev(opts->dev); +	ffs_dev_unlock(); +	kfree(opts); +} + +#define MAX_INST_NAME_LEN	40 + +static int ffs_set_inst_name(struct usb_function_instance *fi, const char *name) +{ +	struct f_fs_opts *opts; +	char *ptr; +	const char *tmp; +	int name_len, ret; + +	name_len = strlen(name) + 1; +	if (name_len > MAX_INST_NAME_LEN) +		return -ENAMETOOLONG; + +	ptr = kstrndup(name, name_len, GFP_KERNEL); +	if (!ptr) +		return -ENOMEM; + +	opts = to_f_fs_opts(fi); +	tmp = NULL; + +	ffs_dev_lock(); + +	tmp = opts->dev->name_allocated ? opts->dev->name : NULL; +	ret = _ffs_name_dev(opts->dev, ptr); +	if (ret) { +		kfree(ptr); +		ffs_dev_unlock(); +		return ret; +	} +	opts->dev->name_allocated = true; + +	ffs_dev_unlock(); + +	kfree(tmp); + +	return 0; +} + +static struct usb_function_instance *ffs_alloc_inst(void) +{ +	struct f_fs_opts *opts; +	struct ffs_dev *dev; + +	opts = kzalloc(sizeof(*opts), GFP_KERNEL); +	if (!opts) +		return ERR_PTR(-ENOMEM); + +	opts->func_inst.set_inst_name = ffs_set_inst_name; +	opts->func_inst.free_func_inst = ffs_free_inst; +	ffs_dev_lock(); +	dev = _ffs_alloc_dev(); +	ffs_dev_unlock(); +	if (IS_ERR(dev)) { +		kfree(opts); +		return ERR_CAST(dev); +	} +	opts->dev = dev; +	dev->opts = opts; + +	config_group_init_type_name(&opts->func_inst.group, "", +				    &ffs_func_type); +	return &opts->func_inst; +} + +static void ffs_free(struct usb_function *f) +{ +	kfree(ffs_func_from_usb(f)); +} + +static void ffs_func_unbind(struct usb_configuration *c, +			    struct usb_function *f) +{ +	struct ffs_function *func = ffs_func_from_usb(f); +	struct ffs_data *ffs = func->ffs; +	struct f_fs_opts *opts = +		container_of(f->fi, struct f_fs_opts, func_inst); +	struct ffs_ep *ep = func->eps; +	unsigned count = ffs->eps_count; +	unsigned long flags; + +	ENTER(); +	if (ffs->func == func) { +		ffs_func_eps_disable(func); +		ffs->func = NULL; +	} + +	if (!--opts->refcnt) +		functionfs_unbind(ffs); + +	/* cleanup after autoconfig */ +	spin_lock_irqsave(&func->ffs->eps_lock, flags); +	do { +		if (ep->ep && ep->req) +			usb_ep_free_request(ep->ep, ep->req); +		ep->req = NULL; +		++ep; +	} while (--count); +	spin_unlock_irqrestore(&func->ffs->eps_lock, flags); +	kfree(func->eps); +	func->eps = NULL; +	/* +	 * eps, descriptors and interfaces_nums are allocated in the +	 * same chunk so only one free is required. +	 */ +	func->function.fs_descriptors = NULL; +	func->function.hs_descriptors = NULL; +	func->function.ss_descriptors = NULL; +	func->interfaces_nums = NULL; + +	ffs_event_add(ffs, FUNCTIONFS_UNBIND); +} + +static struct usb_function *ffs_alloc(struct usb_function_instance *fi) +{ +	struct ffs_function *func; + +	ENTER(); + +	func = kzalloc(sizeof(*func), GFP_KERNEL); +	if (unlikely(!func)) +		return ERR_PTR(-ENOMEM); + +	func->function.name    = "Function FS Gadget"; + +	func->function.bind    = ffs_func_bind; +	func->function.unbind  = ffs_func_unbind; +	func->function.set_alt = ffs_func_set_alt; +	func->function.disable = ffs_func_disable; +	func->function.setup   = ffs_func_setup; +	func->function.suspend = ffs_func_suspend; +	func->function.resume  = ffs_func_resume; +	func->function.free_func = ffs_free; + +	return &func->function; +} + +/* + * ffs_lock must be taken by the caller of this function + */ +static struct ffs_dev *_ffs_alloc_dev(void) +{ +	struct ffs_dev *dev; +	int ret; + +	if (_ffs_get_single_dev()) +			return ERR_PTR(-EBUSY); + +	dev = kzalloc(sizeof(*dev), GFP_KERNEL); +	if (!dev) +		return ERR_PTR(-ENOMEM); + +	if (list_empty(&ffs_devices)) { +		ret = functionfs_init(); +		if (ret) { +			kfree(dev); +			return ERR_PTR(ret); +		} +	} + +	list_add(&dev->entry, &ffs_devices); + +	return dev; +} + +/* + * ffs_lock must be taken by the caller of this function + * The caller is responsible for "name" being available whenever f_fs needs it + */ +static int _ffs_name_dev(struct ffs_dev *dev, const char *name) +{ +	struct ffs_dev *existing; + +	existing = _ffs_do_find_dev(name); +	if (existing) +		return -EBUSY; + +	dev->name = name; + +	return 0; +} + +/* + * The caller is responsible for "name" being available whenever f_fs needs it + */ +int ffs_name_dev(struct ffs_dev *dev, const char *name) +{ +	int ret; + +	ffs_dev_lock(); +	ret = _ffs_name_dev(dev, name); +	ffs_dev_unlock(); + +	return ret; +} +EXPORT_SYMBOL_GPL(ffs_name_dev); + +int ffs_single_dev(struct ffs_dev *dev) +{ +	int ret; + +	ret = 0; +	ffs_dev_lock(); + +	if (!list_is_singular(&ffs_devices)) +		ret = -EBUSY; +	else +		dev->single = true; + +	ffs_dev_unlock(); +	return ret; +} +EXPORT_SYMBOL_GPL(ffs_single_dev); + +/* + * ffs_lock must be taken by the caller of this function + */ +static void _ffs_free_dev(struct ffs_dev *dev) +{ +	list_del(&dev->entry); +	if (dev->name_allocated) +		kfree(dev->name); +	kfree(dev); +	if (list_empty(&ffs_devices)) +		functionfs_cleanup(); +} + +static void *ffs_acquire_dev(const char *dev_name) +{ +	struct ffs_dev *ffs_dev; + +	ENTER(); +	ffs_dev_lock(); + +	ffs_dev = _ffs_find_dev(dev_name); +	if (!ffs_dev) +		ffs_dev = ERR_PTR(-ENODEV); +	else if (ffs_dev->mounted) +		ffs_dev = ERR_PTR(-EBUSY); +	else if (ffs_dev->ffs_acquire_dev_callback && +	    ffs_dev->ffs_acquire_dev_callback(ffs_dev)) +		ffs_dev = ERR_PTR(-ENODEV); +	else +		ffs_dev->mounted = true; + +	ffs_dev_unlock(); +	return ffs_dev; +} + +static void ffs_release_dev(struct ffs_data *ffs_data) +{ +	struct ffs_dev *ffs_dev; + +	ENTER(); +	ffs_dev_lock(); + +	ffs_dev = ffs_data->private_data; +	if (ffs_dev) { +		ffs_dev->mounted = false; + +		if (ffs_dev->ffs_release_dev_callback) +			ffs_dev->ffs_release_dev_callback(ffs_dev); +	} + +	ffs_dev_unlock(); +} + +static int ffs_ready(struct ffs_data *ffs) +{ +	struct ffs_dev *ffs_obj; +	int ret = 0; + +	ENTER(); +	ffs_dev_lock(); + +	ffs_obj = ffs->private_data; +	if (!ffs_obj) { +		ret = -EINVAL; +		goto done; +	} +	if (WARN_ON(ffs_obj->desc_ready)) { +		ret = -EBUSY; +		goto done; +	} + +	ffs_obj->desc_ready = true; +	ffs_obj->ffs_data = ffs; + +	if (ffs_obj->ffs_ready_callback) +		ret = ffs_obj->ffs_ready_callback(ffs); + +done: +	ffs_dev_unlock(); +	return ret; +} + +static void ffs_closed(struct ffs_data *ffs) +{ +	struct ffs_dev *ffs_obj; + +	ENTER(); +	ffs_dev_lock(); + +	ffs_obj = ffs->private_data; +	if (!ffs_obj) +		goto done; + +	ffs_obj->desc_ready = false; + +	if (ffs_obj->ffs_closed_callback) +		ffs_obj->ffs_closed_callback(ffs); + +	if (!ffs_obj->opts || ffs_obj->opts->no_configfs +	    || !ffs_obj->opts->func_inst.group.cg_item.ci_parent) +		goto done; + +	unregister_gadget_item(ffs_obj->opts-> +			       func_inst.group.cg_item.ci_parent->ci_parent); +done: +	ffs_dev_unlock(); +} +  /* Misc helper functions ****************************************************/  static int ffs_mutex_lock(struct mutex *mutex, unsigned nonblock) @@ -2464,3 +3017,7 @@ static char *ffs_prepare_buffer(const char __user *buf, size_t len)  	return data;  } + +DECLARE_USB_FUNCTION_INIT(ffs, ffs_alloc_inst, ffs_alloc); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Michal Nazarewicz"); diff --git a/drivers/usb/gadget/f_hid.c b/drivers/usb/gadget/f_hid.c index 6e69a8e8d22..a95290a1289 100644 --- a/drivers/usb/gadget/f_hid.c +++ b/drivers/usb/gadget/f_hid.c @@ -20,6 +20,8 @@  #include <linux/sched.h>  #include <linux/usb/g_hid.h> +#include "u_f.h" +  static int major, minors;  static struct class *hidg_class; @@ -334,20 +336,10 @@ static int f_hidg_open(struct inode *inode, struct file *fd)  /*-------------------------------------------------------------------------*/  /*                                usb_function                             */ -static struct usb_request *hidg_alloc_ep_req(struct usb_ep *ep, unsigned length) +static inline struct usb_request *hidg_alloc_ep_req(struct usb_ep *ep, +						    unsigned length)  { -	struct usb_request *req; - -	req = usb_ep_alloc_request(ep, GFP_ATOMIC); -	if (req) { -		req->length = length; -		req->buf = kmalloc(length, GFP_ATOMIC); -		if (!req->buf) { -			usb_ep_free_request(ep, req); -			req = NULL; -		} -	} -	return req; +	return alloc_ep_req(ep, length, length);  }  static void hidg_set_report_complete(struct usb_ep *ep, struct usb_request *req) diff --git a/drivers/usb/gadget/f_loopback.c b/drivers/usb/gadget/f_loopback.c index 4a3873a0f2d..4557cd03f0b 100644 --- a/drivers/usb/gadget/f_loopback.c +++ b/drivers/usb/gadget/f_loopback.c @@ -20,6 +20,7 @@  #include <linux/usb/composite.h>  #include "g_zero.h" +#include "u_f.h"  /*   * LOOPBACK FUNCTION ... a testing vehicle for USB peripherals, @@ -119,7 +120,7 @@ static struct usb_endpoint_descriptor ss_loop_source_desc = {  	.wMaxPacketSize =	cpu_to_le16(1024),  }; -struct usb_ss_ep_comp_descriptor ss_loop_source_comp_desc = { +static struct usb_ss_ep_comp_descriptor ss_loop_source_comp_desc = {  	.bLength =		USB_DT_SS_EP_COMP_SIZE,  	.bDescriptorType =	USB_DT_SS_ENDPOINT_COMP,  	.bMaxBurst =		0, @@ -135,7 +136,7 @@ static struct usb_endpoint_descriptor ss_loop_sink_desc = {  	.wMaxPacketSize =	cpu_to_le16(1024),  }; -struct usb_ss_ep_comp_descriptor ss_loop_sink_comp_desc = { +static struct usb_ss_ep_comp_descriptor ss_loop_sink_comp_desc = {  	.bLength =		USB_DT_SS_EP_COMP_SIZE,  	.bDescriptorType =	USB_DT_SS_ENDPOINT_COMP,  	.bMaxBurst =		0, @@ -230,6 +231,14 @@ autoconf_fail:  static void lb_free_func(struct usb_function *f)  { +	struct f_lb_opts *opts; + +	opts = container_of(f->fi, struct f_lb_opts, func_inst); + +	mutex_lock(&opts->lock); +	opts->refcnt--; +	mutex_unlock(&opts->lock); +  	usb_free_all_descriptors(f);  	kfree(func_to_loop(f));  } @@ -293,6 +302,11 @@ static void disable_loopback(struct f_loopback *loop)  	VDBG(cdev, "%s disabled\n", loop->function.name);  } +static inline struct usb_request *lb_alloc_ep_req(struct usb_ep *ep, int len) +{ +	return alloc_ep_req(ep, len, buflen); +} +  static int  enable_loopback(struct usb_composite_dev *cdev, struct f_loopback *loop)  { @@ -332,7 +346,7 @@ fail0:  	 * than 'buflen' bytes each.  	 */  	for (i = 0; i < qlen && result == 0; i++) { -		req = alloc_ep_req(ep, 0); +		req = lb_alloc_ep_req(ep, 0);  		if (req) {  			req->complete = loopback_complete;  			result = usb_ep_queue(ep, req, GFP_ATOMIC); @@ -380,6 +394,11 @@ static struct usb_function *loopback_alloc(struct usb_function_instance *fi)  		return ERR_PTR(-ENOMEM);  	lb_opts = container_of(fi, struct f_lb_opts, func_inst); + +	mutex_lock(&lb_opts->lock); +	lb_opts->refcnt++; +	mutex_unlock(&lb_opts->lock); +  	buflen = lb_opts->bulk_buflen;  	qlen = lb_opts->qlen;  	if (!qlen) @@ -396,6 +415,118 @@ static struct usb_function *loopback_alloc(struct usb_function_instance *fi)  	return &loop->function;  } +static inline struct f_lb_opts *to_f_lb_opts(struct config_item *item) +{ +	return container_of(to_config_group(item), struct f_lb_opts, +			    func_inst.group); +} + +CONFIGFS_ATTR_STRUCT(f_lb_opts); +CONFIGFS_ATTR_OPS(f_lb_opts); + +static void lb_attr_release(struct config_item *item) +{ +	struct f_lb_opts *lb_opts = to_f_lb_opts(item); + +	usb_put_function_instance(&lb_opts->func_inst); +} + +static struct configfs_item_operations lb_item_ops = { +	.release		= lb_attr_release, +	.show_attribute		= f_lb_opts_attr_show, +	.store_attribute	= f_lb_opts_attr_store, +}; + +static ssize_t f_lb_opts_qlen_show(struct f_lb_opts *opts, char *page) +{ +	int result; + +	mutex_lock(&opts->lock); +	result = sprintf(page, "%d", opts->qlen); +	mutex_unlock(&opts->lock); + +	return result; +} + +static ssize_t f_lb_opts_qlen_store(struct f_lb_opts *opts, +				    const char *page, size_t len) +{ +	int ret; +	u32 num; + +	mutex_lock(&opts->lock); +	if (opts->refcnt) { +		ret = -EBUSY; +		goto end; +	} + +	ret = kstrtou32(page, 0, &num); +	if (ret) +		goto end; + +	opts->qlen = num; +	ret = len; +end: +	mutex_unlock(&opts->lock); +	return ret; +} + +static struct f_lb_opts_attribute f_lb_opts_qlen = +	__CONFIGFS_ATTR(qlen, S_IRUGO | S_IWUSR, +			f_lb_opts_qlen_show, +			f_lb_opts_qlen_store); + +static ssize_t f_lb_opts_bulk_buflen_show(struct f_lb_opts *opts, char *page) +{ +	int result; + +	mutex_lock(&opts->lock); +	result = sprintf(page, "%d", opts->bulk_buflen); +	mutex_unlock(&opts->lock); + +	return result; +} + +static ssize_t f_lb_opts_bulk_buflen_store(struct f_lb_opts *opts, +				    const char *page, size_t len) +{ +	int ret; +	u32 num; + +	mutex_lock(&opts->lock); +	if (opts->refcnt) { +		ret = -EBUSY; +		goto end; +	} + +	ret = kstrtou32(page, 0, &num); +	if (ret) +		goto end; + +	opts->bulk_buflen = num; +	ret = len; +end: +	mutex_unlock(&opts->lock); +	return ret; +} + +static struct f_lb_opts_attribute f_lb_opts_bulk_buflen = +	__CONFIGFS_ATTR(buflen, S_IRUGO | S_IWUSR, +			f_lb_opts_bulk_buflen_show, +			f_lb_opts_bulk_buflen_store); + +static struct configfs_attribute *lb_attrs[] = { +	&f_lb_opts_qlen.attr, +	&f_lb_opts_bulk_buflen.attr, +	NULL, +}; + +static struct config_item_type lb_func_type = { +	.ct_item_ops    = &lb_item_ops, +	.ct_attrs	= lb_attrs, +	.ct_owner       = THIS_MODULE, +}; +  static void lb_free_instance(struct usb_function_instance *fi)  {  	struct f_lb_opts *lb_opts; @@ -411,7 +542,14 @@ static struct usb_function_instance *loopback_alloc_instance(void)  	lb_opts = kzalloc(sizeof(*lb_opts), GFP_KERNEL);  	if (!lb_opts)  		return ERR_PTR(-ENOMEM); +	mutex_init(&lb_opts->lock);  	lb_opts->func_inst.free_func_inst = lb_free_instance; +	lb_opts->bulk_buflen = GZERO_BULK_BUFLEN; +	lb_opts->qlen = GZERO_QLEN; + +	config_group_init_type_name(&lb_opts->func_inst.group, "", +				    &lb_func_type); +  	return  &lb_opts->func_inst;  }  DECLARE_USB_FUNCTION(Loopback, loopback_alloc_instance, loopback_alloc); diff --git a/drivers/usb/gadget/f_mass_storage.c b/drivers/usb/gadget/f_mass_storage.c index 313b835eedf..b9639390886 100644 --- a/drivers/usb/gadget/f_mass_storage.c +++ b/drivers/usb/gadget/f_mass_storage.c @@ -213,12 +213,14 @@  #include <linux/spinlock.h>  #include <linux/string.h>  #include <linux/freezer.h> +#include <linux/module.h>  #include <linux/usb/ch9.h>  #include <linux/usb/gadget.h>  #include <linux/usb/composite.h>  #include "gadget_chips.h" +#include "configfs.h"  /*------------------------------------------------------------------------*/ @@ -228,26 +230,30 @@  static const char fsg_string_interface[] = "Mass Storage"; -#include "storage_common.c" +#include "storage_common.h" +#include "f_mass_storage.h" +/* Static strings, in UTF-8 (for simplicity we use only ASCII characters) */ +static struct usb_string		fsg_strings[] = { +	{FSG_STRING_INTERFACE,		fsg_string_interface}, +	{} +}; + +static struct usb_gadget_strings	fsg_stringtab = { +	.language	= 0x0409,		/* en-us */ +	.strings	= fsg_strings, +}; + +static struct usb_gadget_strings *fsg_strings_array[] = { +	&fsg_stringtab, +	NULL, +};  /*-------------------------------------------------------------------------*/  struct fsg_dev;  struct fsg_common; -/* FSF callback functions */ -struct fsg_operations { -	/* -	 * Callback function to call when thread exits.  If no -	 * callback is set or it returns value lower then zero MSF -	 * will force eject all LUNs it operates on (including those -	 * marked as non-removable or with prevent_medium_removal flag -	 * set). -	 */ -	int (*thread_exits)(struct fsg_common *common); -}; -  /* Data shared by all the FSG instances. */  struct fsg_common {  	struct usb_gadget	*gadget; @@ -268,13 +274,14 @@ struct fsg_common {  	struct fsg_buffhd	*next_buffhd_to_fill;  	struct fsg_buffhd	*next_buffhd_to_drain;  	struct fsg_buffhd	*buffhds; +	unsigned int		fsg_num_buffers;  	int			cmnd_size;  	u8			cmnd[MAX_COMMAND_SIZE];  	unsigned int		nluns;  	unsigned int		lun; -	struct fsg_lun		*luns; +	struct fsg_lun		**luns;  	struct fsg_lun		*curlun;  	unsigned int		bulk_out_maxpacket; @@ -294,6 +301,7 @@ struct fsg_common {  	unsigned int		short_packet_received:1;  	unsigned int		bad_lun_okay:1;  	unsigned int		running:1; +	unsigned int		sysfs:1;  	int			thread_wakeup_needed;  	struct completion	thread_notifier; @@ -313,27 +321,6 @@ struct fsg_common {  	struct kref		ref;  }; -struct fsg_config { -	unsigned nluns; -	struct fsg_lun_config { -		const char *filename; -		char ro; -		char removable; -		char cdrom; -		char nofua; -	} luns[FSG_MAX_LUNS]; - -	/* Callback functions. */ -	const struct fsg_operations	*ops; -	/* Gadget's private data. */ -	void			*private_data; - -	const char *vendor_name;		/*  8 characters or less */ -	const char *product_name;		/* 16 characters or less */ - -	char			can_stall; -}; -  struct fsg_dev {  	struct usb_function	function;  	struct usb_gadget	*gadget;	/* Copy of cdev->gadget */ @@ -536,7 +523,7 @@ static int fsg_setup(struct usb_function *f,  		 */  		DBG(fsg, "bulk reset request\n");  		raise_exception(fsg->common, FSG_STATE_RESET); -		return DELAYED_STATUS; +		return USB_GADGET_DELAYED_STATUS;  	case US_BULK_GET_MAX_LUN:  		if (ctrl->bRequestType != @@ -615,13 +602,14 @@ static bool start_out_transfer(struct fsg_common *common, struct fsg_buffhd *bh)  	return true;  } -static int sleep_thread(struct fsg_common *common) +static int sleep_thread(struct fsg_common *common, bool can_freeze)  {  	int	rc = 0;  	/* Wait until a signal arrives or we are woken up */  	for (;;) { -		try_to_freeze(); +		if (can_freeze) +			try_to_freeze();  		set_current_state(TASK_INTERRUPTIBLE);  		if (signal_pending(current)) {  			rc = -EINTR; @@ -695,7 +683,7 @@ static int do_read(struct fsg_common *common)  		/* Wait for the next buffer to become available */  		bh = common->next_buffhd_to_fill;  		while (bh->state != BUF_STATE_EMPTY) { -			rc = sleep_thread(common); +			rc = sleep_thread(common, false);  			if (rc)  				return rc;  		} @@ -950,7 +938,7 @@ static int do_write(struct fsg_common *common)  		}  		/* Wait for something to happen */ -		rc = sleep_thread(common); +		rc = sleep_thread(common, false);  		if (rc)  			return rc;  	} @@ -1517,7 +1505,7 @@ static int throw_away_data(struct fsg_common *common)  		}  		/* Otherwise wait for something to happen */ -		rc = sleep_thread(common); +		rc = sleep_thread(common, true);  		if (rc)  			return rc;  	} @@ -1638,7 +1626,7 @@ static int send_status(struct fsg_common *common)  	/* Wait for the next buffer to become available */  	bh = common->next_buffhd_to_fill;  	while (bh->state != BUF_STATE_EMPTY) { -		rc = sleep_thread(common); +		rc = sleep_thread(common, true);  		if (rc)  			return rc;  	} @@ -1841,7 +1829,7 @@ static int do_scsi_command(struct fsg_common *common)  	bh = common->next_buffhd_to_fill;  	common->next_buffhd_to_drain = bh;  	while (bh->state != BUF_STATE_EMPTY) { -		rc = sleep_thread(common); +		rc = sleep_thread(common, true);  		if (rc)  			return rc;  	} @@ -2172,7 +2160,7 @@ static int received_cbw(struct fsg_dev *fsg, struct fsg_buffhd *bh)  		common->data_dir = DATA_DIR_NONE;  	common->lun = cbw->Lun;  	if (common->lun < common->nluns) -		common->curlun = &common->luns[common->lun]; +		common->curlun = common->luns[common->lun];  	else  		common->curlun = NULL;  	common->tag = cbw->Tag; @@ -2187,7 +2175,7 @@ static int get_next_command(struct fsg_common *common)  	/* Wait for the next buffer to become available */  	bh = common->next_buffhd_to_fill;  	while (bh->state != BUF_STATE_EMPTY) { -		rc = sleep_thread(common); +		rc = sleep_thread(common, true);  		if (rc)  			return rc;  	} @@ -2206,7 +2194,7 @@ static int get_next_command(struct fsg_common *common)  	/* Wait for the CBW to arrive */  	while (bh->state != BUF_STATE_FULL) { -		rc = sleep_thread(common); +		rc = sleep_thread(common, true);  		if (rc)  			return rc;  	} @@ -2244,7 +2232,7 @@ reset:  	if (common->fsg) {  		fsg = common->fsg; -		for (i = 0; i < fsg_num_buffers; ++i) { +		for (i = 0; i < common->fsg_num_buffers; ++i) {  			struct fsg_buffhd *bh = &common->buffhds[i];  			if (bh->inreq) { @@ -2260,10 +2248,12 @@ reset:  		/* Disable the endpoints */  		if (fsg->bulk_in_enabled) {  			usb_ep_disable(fsg->bulk_in); +			fsg->bulk_in->driver_data = NULL;  			fsg->bulk_in_enabled = 0;  		}  		if (fsg->bulk_out_enabled) {  			usb_ep_disable(fsg->bulk_out); +			fsg->bulk_out->driver_data = NULL;  			fsg->bulk_out_enabled = 0;  		} @@ -2301,7 +2291,7 @@ reset:  	clear_bit(IGNORE_BULK_OUT, &fsg->atomic_bitflags);  	/* Allocate the requests */ -	for (i = 0; i < fsg_num_buffers; ++i) { +	for (i = 0; i < common->fsg_num_buffers; ++i) {  		struct fsg_buffhd	*bh = &common->buffhds[i];  		rc = alloc_request(common, fsg->bulk_in, &bh->inreq); @@ -2318,7 +2308,9 @@ reset:  	common->running = 1;  	for (i = 0; i < common->nluns; ++i) -		common->luns[i].unit_attention_data = SS_RESET_OCCURRED; +		if (common->luns[i]) +			common->luns[i]->unit_attention_data = +				SS_RESET_OCCURRED;  	return rc;  } @@ -2370,7 +2362,7 @@ static void handle_exception(struct fsg_common *common)  	/* Cancel all the pending transfers */  	if (likely(common->fsg)) { -		for (i = 0; i < fsg_num_buffers; ++i) { +		for (i = 0; i < common->fsg_num_buffers; ++i) {  			bh = &common->buffhds[i];  			if (bh->inreq_busy)  				usb_ep_dequeue(common->fsg->bulk_in, bh->inreq); @@ -2382,13 +2374,13 @@ static void handle_exception(struct fsg_common *common)  		/* Wait until everything is idle */  		for (;;) {  			int num_active = 0; -			for (i = 0; i < fsg_num_buffers; ++i) { +			for (i = 0; i < common->fsg_num_buffers; ++i) {  				bh = &common->buffhds[i];  				num_active += bh->inreq_busy + bh->outreq_busy;  			}  			if (num_active == 0)  				break; -			if (sleep_thread(common)) +			if (sleep_thread(common, true))  				return;  		} @@ -2405,7 +2397,7 @@ static void handle_exception(struct fsg_common *common)  	 */  	spin_lock_irq(&common->lock); -	for (i = 0; i < fsg_num_buffers; ++i) { +	for (i = 0; i < common->fsg_num_buffers; ++i) {  		bh = &common->buffhds[i];  		bh->state = BUF_STATE_EMPTY;  	} @@ -2418,7 +2410,9 @@ static void handle_exception(struct fsg_common *common)  		common->state = FSG_STATE_STATUS_PHASE;  	else {  		for (i = 0; i < common->nluns; ++i) { -			curlun = &common->luns[i]; +			curlun = common->luns[i]; +			if (!curlun) +				continue;  			curlun->prevent_medium_removal = 0;  			curlun->sense_data = SS_NO_SENSE;  			curlun->unit_attention_data = SS_NO_SENSE; @@ -2460,8 +2454,9 @@ static void handle_exception(struct fsg_common *common)  		 * CONFIG_CHANGE cases.  		 */  		/* for (i = 0; i < common->nluns; ++i) */ -		/*	common->luns[i].unit_attention_data = */ -		/*		SS_RESET_OCCURRED;  */ +		/*	if (common->luns[i]) */ +		/*		common->luns[i]->unit_attention_data = */ +		/*			SS_RESET_OCCURRED;  */  		break;  	case FSG_STATE_CONFIG_CHANGE: @@ -2522,7 +2517,7 @@ static int fsg_main_thread(void *common_)  		}  		if (!common->running) { -			sleep_thread(common); +			sleep_thread(common, true);  			continue;  		} @@ -2557,12 +2552,13 @@ static int fsg_main_thread(void *common_)  	if (!common->ops || !common->ops->thread_exits  	 || common->ops->thread_exits(common) < 0) { -		struct fsg_lun *curlun = common->luns; +		struct fsg_lun **curlun_it = common->luns;  		unsigned i = common->nluns;  		down_write(&common->filesem); -		for (; i--; ++curlun) { -			if (!fsg_lun_is_open(curlun)) +		for (; i--; ++curlun_it) { +			struct fsg_lun *curlun = *curlun_it; +			if (!curlun || !fsg_lun_is_open(curlun))  				continue;  			fsg_lun_close(curlun); @@ -2578,6 +2574,56 @@ static int fsg_main_thread(void *common_)  /*************************** DEVICE ATTRIBUTES ***************************/ +static ssize_t ro_show(struct device *dev, struct device_attribute *attr, char *buf) +{ +	struct fsg_lun		*curlun = fsg_lun_from_dev(dev); + +	return fsg_show_ro(curlun, buf); +} + +static ssize_t nofua_show(struct device *dev, struct device_attribute *attr, +			  char *buf) +{ +	struct fsg_lun		*curlun = fsg_lun_from_dev(dev); + +	return fsg_show_nofua(curlun, buf); +} + +static ssize_t file_show(struct device *dev, struct device_attribute *attr, +			 char *buf) +{ +	struct fsg_lun		*curlun = fsg_lun_from_dev(dev); +	struct rw_semaphore	*filesem = dev_get_drvdata(dev); + +	return fsg_show_file(curlun, filesem, buf); +} + +static ssize_t ro_store(struct device *dev, struct device_attribute *attr, +			const char *buf, size_t count) +{ +	struct fsg_lun		*curlun = fsg_lun_from_dev(dev); +	struct rw_semaphore	*filesem = dev_get_drvdata(dev); + +	return fsg_store_ro(curlun, filesem, buf, count); +} + +static ssize_t nofua_store(struct device *dev, struct device_attribute *attr, +			   const char *buf, size_t count) +{ +	struct fsg_lun		*curlun = fsg_lun_from_dev(dev); + +	return fsg_store_nofua(curlun, buf, count); +} + +static ssize_t file_store(struct device *dev, struct device_attribute *attr, +			  const char *buf, size_t count) +{ +	struct fsg_lun		*curlun = fsg_lun_from_dev(dev); +	struct rw_semaphore	*filesem = dev_get_drvdata(dev); + +	return fsg_store_file(curlun, filesem, buf, count); +} +  static DEVICE_ATTR_RW(ro);  static DEVICE_ATTR_RW(nofua);  static DEVICE_ATTR_RW(file); @@ -2595,221 +2641,422 @@ static void fsg_lun_release(struct device *dev)  	/* Nothing needs to be done */  } -static inline void fsg_common_get(struct fsg_common *common) +void fsg_common_get(struct fsg_common *common)  {  	kref_get(&common->ref);  } +EXPORT_SYMBOL_GPL(fsg_common_get); -static inline void fsg_common_put(struct fsg_common *common) +void fsg_common_put(struct fsg_common *common)  {  	kref_put(&common->ref, fsg_common_release);  } +EXPORT_SYMBOL_GPL(fsg_common_put); -static struct fsg_common *fsg_common_init(struct fsg_common *common, -					  struct usb_composite_dev *cdev, -					  struct fsg_config *cfg) +/* check if fsg_num_buffers is within a valid range */ +static inline int fsg_num_buffers_validate(unsigned int fsg_num_buffers)  { -	struct usb_gadget *gadget = cdev->gadget; -	struct fsg_buffhd *bh; -	struct fsg_lun *curlun; -	struct fsg_lun_config *lcfg; -	int nluns, i, rc; -	char *pathbuf; - -	rc = fsg_num_buffers_validate(); -	if (rc != 0) -		return ERR_PTR(rc); - -	/* Find out how many LUNs there should be */ -	nluns = cfg->nluns; -	if (nluns < 1 || nluns > FSG_MAX_LUNS) { -		dev_err(&gadget->dev, "invalid number of LUNs: %u\n", nluns); -		return ERR_PTR(-EINVAL); -	} +	if (fsg_num_buffers >= 2 && fsg_num_buffers <= 4) +		return 0; +	pr_err("fsg_num_buffers %u is out of range (%d to %d)\n", +	       fsg_num_buffers, 2, 4); +	return -EINVAL; +} -	/* Allocate? */ +static struct fsg_common *fsg_common_setup(struct fsg_common *common) +{  	if (!common) { -		common = kzalloc(sizeof *common, GFP_KERNEL); +		common = kzalloc(sizeof(*common), GFP_KERNEL);  		if (!common)  			return ERR_PTR(-ENOMEM);  		common->free_storage_on_release = 1;  	} else { -		memset(common, 0, sizeof *common);  		common->free_storage_on_release = 0;  	} +	init_rwsem(&common->filesem); +	spin_lock_init(&common->lock); +	kref_init(&common->ref); +	init_completion(&common->thread_notifier); +	init_waitqueue_head(&common->fsg_wait); +	common->state = FSG_STATE_TERMINATED; -	common->buffhds = kcalloc(fsg_num_buffers, -				  sizeof *(common->buffhds), GFP_KERNEL); -	if (!common->buffhds) { -		if (common->free_storage_on_release) -			kfree(common); -		return ERR_PTR(-ENOMEM); +	return common; +} + +void fsg_common_set_sysfs(struct fsg_common *common, bool sysfs) +{ +	common->sysfs = sysfs; +} +EXPORT_SYMBOL_GPL(fsg_common_set_sysfs); + +static void _fsg_common_free_buffers(struct fsg_buffhd *buffhds, unsigned n) +{ +	if (buffhds) { +		struct fsg_buffhd *bh = buffhds; +		while (n--) { +			kfree(bh->buf); +			++bh; +		} +		kfree(buffhds);  	} +} -	common->ops = cfg->ops; -	common->private_data = cfg->private_data; +int fsg_common_set_num_buffers(struct fsg_common *common, unsigned int n) +{ +	struct fsg_buffhd *bh, *buffhds; +	int i, rc; -	common->gadget = gadget; -	common->ep0 = gadget->ep0; -	common->ep0req = cdev->req; -	common->cdev = cdev; +	rc = fsg_num_buffers_validate(n); +	if (rc != 0) +		return rc; + +	buffhds = kcalloc(n, sizeof(*buffhds), GFP_KERNEL); +	if (!buffhds) +		return -ENOMEM; -	/* Maybe allocate device-global string IDs, and patch descriptors */ -	if (fsg_strings[FSG_STRING_INTERFACE].id == 0) { -		rc = usb_string_id(cdev); -		if (unlikely(rc < 0)) +	/* Data buffers cyclic list */ +	bh = buffhds; +	i = n; +	goto buffhds_first_it; +	do { +		bh->next = bh + 1; +		++bh; +buffhds_first_it: +		bh->buf = kmalloc(FSG_BUFLEN, GFP_KERNEL); +		if (unlikely(!bh->buf))  			goto error_release; -		fsg_strings[FSG_STRING_INTERFACE].id = rc; -		fsg_intf_desc.iInterface = rc; -	} +	} while (--i); +	bh->next = buffhds; +	_fsg_common_free_buffers(common->buffhds, common->fsg_num_buffers); +	common->fsg_num_buffers = n; +	common->buffhds = buffhds; + +	return 0; + +error_release:  	/* -	 * Create the LUNs, open their backing files, and register the -	 * LUN devices in sysfs. +	 * "buf"s pointed to by heads after n - i are NULL +	 * so releasing them won't hurt  	 */ -	curlun = kcalloc(nluns, sizeof(*curlun), GFP_KERNEL); -	if (unlikely(!curlun)) { -		rc = -ENOMEM; -		goto error_release; +	_fsg_common_free_buffers(buffhds, n); + +	return -ENOMEM; +} +EXPORT_SYMBOL_GPL(fsg_common_set_num_buffers); + +static inline void fsg_common_remove_sysfs(struct fsg_lun *lun) +{ +	device_remove_file(&lun->dev, &dev_attr_nofua); +	/* +	 * device_remove_file() => +	 * +	 * here the attr (e.g. dev_attr_ro) is only used to be passed to: +	 * +	 *	sysfs_remove_file() => +	 * +	 *	here e.g. both dev_attr_ro_cdrom and dev_attr_ro are in +	 *	the same namespace and +	 *	from here only attr->name is passed to: +	 * +	 *		sysfs_hash_and_remove() +	 * +	 *		attr->name is the same for dev_attr_ro_cdrom and +	 *		dev_attr_ro +	 *		attr->name is the same for dev_attr_file and +	 *		dev_attr_file_nonremovable +	 * +	 * so we don't differentiate between removing e.g. dev_attr_ro_cdrom +	 * and dev_attr_ro +	 */ +	device_remove_file(&lun->dev, &dev_attr_ro); +	device_remove_file(&lun->dev, &dev_attr_file); +} + +void fsg_common_remove_lun(struct fsg_lun *lun, bool sysfs) +{ +	if (sysfs) { +		fsg_common_remove_sysfs(lun); +		device_unregister(&lun->dev);  	} -	common->luns = curlun; +	fsg_lun_close(lun); +	kfree(lun); +} +EXPORT_SYMBOL_GPL(fsg_common_remove_lun); -	init_rwsem(&common->filesem); +static void _fsg_common_remove_luns(struct fsg_common *common, int n) +{ +	int i; -	for (i = 0, lcfg = cfg->luns; i < nluns; ++i, ++curlun, ++lcfg) { -		curlun->cdrom = !!lcfg->cdrom; -		curlun->ro = lcfg->cdrom || lcfg->ro; -		curlun->initially_ro = curlun->ro; -		curlun->removable = lcfg->removable; -		curlun->dev.release = fsg_lun_release; -		curlun->dev.parent = &gadget->dev; -		/* curlun->dev.driver = &fsg_driver.driver; XXX */ -		dev_set_drvdata(&curlun->dev, &common->filesem); -		dev_set_name(&curlun->dev, "lun%d", i); - -		rc = device_register(&curlun->dev); -		if (rc) { -			INFO(common, "failed to register LUN%d: %d\n", i, rc); -			common->nluns = i; -			put_device(&curlun->dev); -			goto error_release; +	for (i = 0; i < n; ++i) +		if (common->luns[i]) { +			fsg_common_remove_lun(common->luns[i], common->sysfs); +			common->luns[i] = NULL;  		} +} +EXPORT_SYMBOL_GPL(fsg_common_remove_luns); -		rc = device_create_file(&curlun->dev, -					curlun->cdrom -				      ? &dev_attr_ro_cdrom -				      : &dev_attr_ro); -		if (rc) -			goto error_luns; -		rc = device_create_file(&curlun->dev, -					curlun->removable -				      ? &dev_attr_file -				      : &dev_attr_file_nonremovable); -		if (rc) -			goto error_luns; -		rc = device_create_file(&curlun->dev, &dev_attr_nofua); -		if (rc) -			goto error_luns; +void fsg_common_remove_luns(struct fsg_common *common) +{ +	_fsg_common_remove_luns(common, common->nluns); +} -		if (lcfg->filename) { -			rc = fsg_lun_open(curlun, lcfg->filename); -			if (rc) -				goto error_luns; -		} else if (!curlun->removable) { -			ERROR(common, "no file given for LUN%d\n", i); -			rc = -EINVAL; -			goto error_luns; -		} +void fsg_common_free_luns(struct fsg_common *common) +{ +	fsg_common_remove_luns(common); +	kfree(common->luns); +	common->luns = NULL; +} +EXPORT_SYMBOL_GPL(fsg_common_free_luns); + +int fsg_common_set_nluns(struct fsg_common *common, int nluns) +{ +	struct fsg_lun **curlun; + +	/* Find out how many LUNs there should be */ +	if (nluns < 1 || nluns > FSG_MAX_LUNS) { +		pr_err("invalid number of LUNs: %u\n", nluns); +		return -EINVAL;  	} + +	curlun = kcalloc(nluns, sizeof(*curlun), GFP_KERNEL); +	if (unlikely(!curlun)) +		return -ENOMEM; + +	if (common->luns) +		fsg_common_free_luns(common); + +	common->luns = curlun;  	common->nluns = nluns; -	/* Data buffers cyclic list */ -	bh = common->buffhds; -	i = fsg_num_buffers; -	goto buffhds_first_it; -	do { -		bh->next = bh + 1; -		++bh; -buffhds_first_it: -		bh->buf = kmalloc(FSG_BUFLEN, GFP_KERNEL); -		if (unlikely(!bh->buf)) { -			rc = -ENOMEM; -			goto error_release; -		} -	} while (--i); -	bh->next = common->buffhds; +	pr_info("Number of LUNs=%d\n", common->nluns); -	/* Prepare inquiryString */ -	i = get_default_bcdDevice(); -	snprintf(common->inquiry_string, sizeof common->inquiry_string, -		 "%-8s%-16s%04x", cfg->vendor_name ?: "Linux", -		 /* Assume product name dependent on the first LUN */ -		 cfg->product_name ?: (common->luns->cdrom -				     ? "File-CD Gadget" -				     : "File-Stor Gadget"), -		 i); +	return 0; +} +EXPORT_SYMBOL_GPL(fsg_common_set_nluns); + +void fsg_common_set_ops(struct fsg_common *common, +			const struct fsg_operations *ops) +{ +	common->ops = ops; +} +EXPORT_SYMBOL_GPL(fsg_common_set_ops); + +void fsg_common_free_buffers(struct fsg_common *common) +{ +	_fsg_common_free_buffers(common->buffhds, common->fsg_num_buffers); +	common->buffhds = NULL; +} +EXPORT_SYMBOL_GPL(fsg_common_free_buffers); + +int fsg_common_set_cdev(struct fsg_common *common, +			 struct usb_composite_dev *cdev, bool can_stall) +{ +	struct usb_string *us; + +	common->gadget = cdev->gadget; +	common->ep0 = cdev->gadget->ep0; +	common->ep0req = cdev->req; +	common->cdev = cdev; + +	us = usb_gstrings_attach(cdev, fsg_strings_array, +				 ARRAY_SIZE(fsg_strings)); +	if (IS_ERR(us)) +		return PTR_ERR(us); + +	fsg_intf_desc.iInterface = us[FSG_STRING_INTERFACE].id;  	/*  	 * Some peripheral controllers are known not to be able to  	 * halt bulk endpoints correctly.  If one of them is present,  	 * disable stalls.  	 */ -	common->can_stall = cfg->can_stall && -		!(gadget_is_at91(common->gadget)); +	common->can_stall = can_stall && !(gadget_is_at91(common->gadget)); -	spin_lock_init(&common->lock); -	kref_init(&common->ref); +	return 0; +} +EXPORT_SYMBOL_GPL(fsg_common_set_cdev); -	/* Tell the thread to start working */ -	common->thread_task = -		kthread_create(fsg_main_thread, common, "file-storage"); -	if (IS_ERR(common->thread_task)) { -		rc = PTR_ERR(common->thread_task); -		goto error_release; +static inline int fsg_common_add_sysfs(struct fsg_common *common, +				       struct fsg_lun *lun) +{ +	int rc; + +	rc = device_register(&lun->dev); +	if (rc) { +		put_device(&lun->dev); +		return rc;  	} -	init_completion(&common->thread_notifier); -	init_waitqueue_head(&common->fsg_wait); -	/* Information */ -	INFO(common, FSG_DRIVER_DESC ", version: " FSG_DRIVER_VERSION "\n"); -	INFO(common, "Number of LUNs=%d\n", common->nluns); +	rc = device_create_file(&lun->dev, +				lun->cdrom +			      ? &dev_attr_ro_cdrom +			      : &dev_attr_ro); +	if (rc) +		goto error; +	rc = device_create_file(&lun->dev, +				lun->removable +			      ? &dev_attr_file +			      : &dev_attr_file_nonremovable); +	if (rc) +		goto error; +	rc = device_create_file(&lun->dev, &dev_attr_nofua); +	if (rc) +		goto error; + +	return 0; + +error: +	/* removing nonexistent files is a no-op */ +	fsg_common_remove_sysfs(lun); +	device_unregister(&lun->dev); +	return rc; +} + +int fsg_common_create_lun(struct fsg_common *common, struct fsg_lun_config *cfg, +			  unsigned int id, const char *name, +			  const char **name_pfx) +{ +	struct fsg_lun *lun; +	char *pathbuf, *p; +	int rc = -ENOMEM; + +	if (!common->nluns || !common->luns) +		return -ENODEV; + +	if (common->luns[id]) +		return -EBUSY; + +	if (!cfg->filename && !cfg->removable) { +		pr_err("no file given for LUN%d\n", id); +		return -EINVAL; +	} + +	lun = kzalloc(sizeof(*lun), GFP_KERNEL); +	if (!lun) +		return -ENOMEM; + +	lun->name_pfx = name_pfx; + +	lun->cdrom = !!cfg->cdrom; +	lun->ro = cfg->cdrom || cfg->ro; +	lun->initially_ro = lun->ro; +	lun->removable = !!cfg->removable; + +	if (!common->sysfs) { +		/* we DON'T own the name!*/ +		lun->name = name; +	} else { +		lun->dev.release = fsg_lun_release; +		lun->dev.parent = &common->gadget->dev; +		dev_set_drvdata(&lun->dev, &common->filesem); +		dev_set_name(&lun->dev, "%s", name); +		lun->name = dev_name(&lun->dev); + +		rc = fsg_common_add_sysfs(common, lun); +		if (rc) { +			pr_info("failed to register LUN%d: %d\n", id, rc); +			goto error_sysfs; +		} +	} + +	common->luns[id] = lun; + +	if (cfg->filename) { +		rc = fsg_lun_open(lun, cfg->filename); +		if (rc) +			goto error_lun; +	}  	pathbuf = kmalloc(PATH_MAX, GFP_KERNEL); -	for (i = 0, nluns = common->nluns, curlun = common->luns; -	     i < nluns; -	     ++curlun, ++i) { -		char *p = "(no medium)"; -		if (fsg_lun_is_open(curlun)) { -			p = "(error)"; -			if (pathbuf) { -				p = d_path(&curlun->filp->f_path, -					   pathbuf, PATH_MAX); -				if (IS_ERR(p)) -					p = "(error)"; -			} +	p = "(no medium)"; +	if (fsg_lun_is_open(lun)) { +		p = "(error)"; +		if (pathbuf) { +			p = d_path(&lun->filp->f_path, pathbuf, PATH_MAX); +			if (IS_ERR(p)) +				p = "(error)";  		} -		LINFO(curlun, "LUN: %s%s%sfile: %s\n", -		      curlun->removable ? "removable " : "", -		      curlun->ro ? "read only " : "", -		      curlun->cdrom ? "CD-ROM " : "", -		      p);  	} +	pr_info("LUN: %s%s%sfile: %s\n", +	      lun->removable ? "removable " : "", +	      lun->ro ? "read only " : "", +	      lun->cdrom ? "CD-ROM " : "", +	      p);  	kfree(pathbuf); +	return 0; + +error_lun: +	if (common->sysfs) { +		fsg_common_remove_sysfs(lun); +		device_unregister(&lun->dev); +	} +	fsg_lun_close(lun); +	common->luns[id] = NULL; +error_sysfs: +	kfree(lun); +	return rc; +} +EXPORT_SYMBOL_GPL(fsg_common_create_lun); + +int fsg_common_create_luns(struct fsg_common *common, struct fsg_config *cfg) +{ +	char buf[8]; /* enough for 100000000 different numbers, decimal */ +	int i, rc; + +	for (i = 0; i < common->nluns; ++i) { +		snprintf(buf, sizeof(buf), "lun%d", i); +		rc = fsg_common_create_lun(common, &cfg->luns[i], i, buf, NULL); +		if (rc) +			goto fail; +	} + +	pr_info("Number of LUNs=%d\n", common->nluns); + +	return 0; + +fail: +	_fsg_common_remove_luns(common, i); +	return rc; +} +EXPORT_SYMBOL_GPL(fsg_common_create_luns); + +void fsg_common_set_inquiry_string(struct fsg_common *common, const char *vn, +				   const char *pn) +{ +	int i; + +	/* Prepare inquiryString */ +	i = get_default_bcdDevice(); +	snprintf(common->inquiry_string, sizeof(common->inquiry_string), +		 "%-8s%-16s%04x", vn ?: "Linux", +		 /* Assume product name dependent on the first LUN */ +		 pn ?: ((*common->luns)->cdrom +		     ? "File-CD Gadget" +		     : "File-Stor Gadget"), +		 i); +} +EXPORT_SYMBOL_GPL(fsg_common_set_inquiry_string); + +int fsg_common_run_thread(struct fsg_common *common) +{ +	common->state = FSG_STATE_IDLE; +	/* Tell the thread to start working */ +	common->thread_task = +		kthread_create(fsg_main_thread, common, "file-storage"); +	if (IS_ERR(common->thread_task)) { +		common->state = FSG_STATE_TERMINATED; +		return PTR_ERR(common->thread_task); +	} +  	DBG(common, "I/O thread pid: %d\n", task_pid_nr(common->thread_task));  	wake_up_process(common->thread_task); -	return common; - -error_luns: -	common->nluns = i + 1; -error_release: -	common->state = FSG_STATE_TERMINATED;	/* The thread is dead */ -	/* Call fsg_common_release() directly, ref might be not initialised. */ -	fsg_common_release(&common->ref); -	return ERR_PTR(rc); +	return 0;  } +EXPORT_SYMBOL_GPL(fsg_common_run_thread);  static void fsg_common_release(struct kref *ref)  { @@ -2822,36 +3069,26 @@ static void fsg_common_release(struct kref *ref)  	}  	if (likely(common->luns)) { -		struct fsg_lun *lun = common->luns; +		struct fsg_lun **lun_it = common->luns;  		unsigned i = common->nluns;  		/* In error recovery common->nluns may be zero. */ -		for (; i; --i, ++lun) { -			device_remove_file(&lun->dev, &dev_attr_nofua); -			device_remove_file(&lun->dev, -					   lun->cdrom -					 ? &dev_attr_ro_cdrom -					 : &dev_attr_ro); -			device_remove_file(&lun->dev, -					   lun->removable -					 ? &dev_attr_file -					 : &dev_attr_file_nonremovable); +		for (; i; --i, ++lun_it) { +			struct fsg_lun *lun = *lun_it; +			if (!lun) +				continue; +			if (common->sysfs) +				fsg_common_remove_sysfs(lun);  			fsg_lun_close(lun); -			device_unregister(&lun->dev); +			if (common->sysfs) +				device_unregister(&lun->dev); +			kfree(lun);  		}  		kfree(common->luns);  	} -	{ -		struct fsg_buffhd *bh = common->buffhds; -		unsigned i = fsg_num_buffers; -		do { -			kfree(bh->buf); -		} while (++bh, --i); -	} - -	kfree(common->buffhds); +	_fsg_common_free_buffers(common->buffhds, common->fsg_num_buffers);  	if (common->free_storage_on_release)  		kfree(common);  } @@ -2859,24 +3096,6 @@ static void fsg_common_release(struct kref *ref)  /*-------------------------------------------------------------------------*/ -static void fsg_unbind(struct usb_configuration *c, struct usb_function *f) -{ -	struct fsg_dev		*fsg = fsg_from_func(f); -	struct fsg_common	*common = fsg->common; - -	DBG(fsg, "unbind\n"); -	if (fsg->common->fsg == fsg) { -		fsg->common->new_fsg = NULL; -		raise_exception(fsg->common, FSG_STATE_CONFIG_CHANGE); -		/* FIXME: make interruptible or killable somehow? */ -		wait_event(common->fsg_wait, common->fsg != fsg); -	} - -	fsg_common_put(common); -	usb_free_all_descriptors(&fsg->function); -	kfree(fsg); -} -  static int fsg_bind(struct usb_configuration *c, struct usb_function *f)  {  	struct fsg_dev		*fsg = fsg_from_func(f); @@ -2885,6 +3104,19 @@ static int fsg_bind(struct usb_configuration *c, struct usb_function *f)  	struct usb_ep		*ep;  	unsigned		max_burst;  	int			ret; +	struct fsg_opts		*opts; + +	opts = fsg_opts_from_func_inst(f->fi); +	if (!opts->no_configfs) { +		ret = fsg_common_set_cdev(fsg->common, c->cdev, +					  fsg->common->can_stall); +		if (ret) +			return ret; +		fsg_common_set_inquiry_string(fsg->common, NULL, NULL); +		ret = fsg_common_run_thread(fsg->common); +		if (ret) +			return ret; +	}  	fsg->gadget = gadget; @@ -2937,95 +3169,472 @@ autoconf_fail:  	return -ENOTSUPP;  } -/****************************** ADD FUNCTION ******************************/ +/****************************** ALLOCATE FUNCTION *************************/ -static struct usb_gadget_strings *fsg_strings_array[] = { -	&fsg_stringtab, +static void fsg_unbind(struct usb_configuration *c, struct usb_function *f) +{ +	struct fsg_dev		*fsg = fsg_from_func(f); +	struct fsg_common	*common = fsg->common; + +	DBG(fsg, "unbind\n"); +	if (fsg->common->fsg == fsg) { +		fsg->common->new_fsg = NULL; +		raise_exception(fsg->common, FSG_STATE_CONFIG_CHANGE); +		/* FIXME: make interruptible or killable somehow? */ +		wait_event(common->fsg_wait, common->fsg != fsg); +	} + +	usb_free_all_descriptors(&fsg->function); +} + +static inline struct fsg_lun_opts *to_fsg_lun_opts(struct config_item *item) +{ +	return container_of(to_config_group(item), struct fsg_lun_opts, group); +} + +static inline struct fsg_opts *to_fsg_opts(struct config_item *item) +{ +	return container_of(to_config_group(item), struct fsg_opts, +			    func_inst.group); +} + +CONFIGFS_ATTR_STRUCT(fsg_lun_opts); +CONFIGFS_ATTR_OPS(fsg_lun_opts); + +static void fsg_lun_attr_release(struct config_item *item) +{ +	struct fsg_lun_opts *lun_opts; + +	lun_opts = to_fsg_lun_opts(item); +	kfree(lun_opts); +} + +static struct configfs_item_operations fsg_lun_item_ops = { +	.release		= fsg_lun_attr_release, +	.show_attribute		= fsg_lun_opts_attr_show, +	.store_attribute	= fsg_lun_opts_attr_store, +}; + +static ssize_t fsg_lun_opts_file_show(struct fsg_lun_opts *opts, char *page) +{ +	struct fsg_opts *fsg_opts; + +	fsg_opts = to_fsg_opts(opts->group.cg_item.ci_parent); + +	return fsg_show_file(opts->lun, &fsg_opts->common->filesem, page); +} + +static ssize_t fsg_lun_opts_file_store(struct fsg_lun_opts *opts, +				       const char *page, size_t len) +{ +	struct fsg_opts *fsg_opts; + +	fsg_opts = to_fsg_opts(opts->group.cg_item.ci_parent); + +	return fsg_store_file(opts->lun, &fsg_opts->common->filesem, page, len); +} + +static struct fsg_lun_opts_attribute fsg_lun_opts_file = +	__CONFIGFS_ATTR(file, S_IRUGO | S_IWUSR, fsg_lun_opts_file_show, +			fsg_lun_opts_file_store); + +static ssize_t fsg_lun_opts_ro_show(struct fsg_lun_opts *opts, char *page) +{ +	return fsg_show_ro(opts->lun, page); +} + +static ssize_t fsg_lun_opts_ro_store(struct fsg_lun_opts *opts, +				       const char *page, size_t len) +{ +	struct fsg_opts *fsg_opts; + +	fsg_opts = to_fsg_opts(opts->group.cg_item.ci_parent); + +	return fsg_store_ro(opts->lun, &fsg_opts->common->filesem, page, len); +} + +static struct fsg_lun_opts_attribute fsg_lun_opts_ro = +	__CONFIGFS_ATTR(ro, S_IRUGO | S_IWUSR, fsg_lun_opts_ro_show, +			fsg_lun_opts_ro_store); + +static ssize_t fsg_lun_opts_removable_show(struct fsg_lun_opts *opts, +					   char *page) +{ +	return fsg_show_removable(opts->lun, page); +} + +static ssize_t fsg_lun_opts_removable_store(struct fsg_lun_opts *opts, +				       const char *page, size_t len) +{ +	return fsg_store_removable(opts->lun, page, len); +} + +static struct fsg_lun_opts_attribute fsg_lun_opts_removable = +	__CONFIGFS_ATTR(removable, S_IRUGO | S_IWUSR, +			fsg_lun_opts_removable_show, +			fsg_lun_opts_removable_store); + +static ssize_t fsg_lun_opts_cdrom_show(struct fsg_lun_opts *opts, char *page) +{ +	return fsg_show_cdrom(opts->lun, page); +} + +static ssize_t fsg_lun_opts_cdrom_store(struct fsg_lun_opts *opts, +				       const char *page, size_t len) +{ +	struct fsg_opts *fsg_opts; + +	fsg_opts = to_fsg_opts(opts->group.cg_item.ci_parent); + +	return fsg_store_cdrom(opts->lun, &fsg_opts->common->filesem, page, +			       len); +} + +static struct fsg_lun_opts_attribute fsg_lun_opts_cdrom = +	__CONFIGFS_ATTR(cdrom, S_IRUGO | S_IWUSR, fsg_lun_opts_cdrom_show, +			fsg_lun_opts_cdrom_store); + +static ssize_t fsg_lun_opts_nofua_show(struct fsg_lun_opts *opts, char *page) +{ +	return fsg_show_nofua(opts->lun, page); +} + +static ssize_t fsg_lun_opts_nofua_store(struct fsg_lun_opts *opts, +				       const char *page, size_t len) +{ +	return fsg_store_nofua(opts->lun, page, len); +} + +static struct fsg_lun_opts_attribute fsg_lun_opts_nofua = +	__CONFIGFS_ATTR(nofua, S_IRUGO | S_IWUSR, fsg_lun_opts_nofua_show, +			fsg_lun_opts_nofua_store); + +static struct configfs_attribute *fsg_lun_attrs[] = { +	&fsg_lun_opts_file.attr, +	&fsg_lun_opts_ro.attr, +	&fsg_lun_opts_removable.attr, +	&fsg_lun_opts_cdrom.attr, +	&fsg_lun_opts_nofua.attr,  	NULL,  }; -static int fsg_bind_config(struct usb_composite_dev *cdev, -			   struct usb_configuration *c, -			   struct fsg_common *common) +static struct config_item_type fsg_lun_type = { +	.ct_item_ops	= &fsg_lun_item_ops, +	.ct_attrs	= fsg_lun_attrs, +	.ct_owner	= THIS_MODULE, +}; + +static struct config_group *fsg_lun_make(struct config_group *group, +					 const char *name)  { -	struct fsg_dev *fsg; +	struct fsg_lun_opts *opts; +	struct fsg_opts *fsg_opts; +	struct fsg_lun_config config; +	char *num_str; +	u8 num; +	int ret; + +	num_str = strchr(name, '.'); +	if (!num_str) { +		pr_err("Unable to locate . in LUN.NUMBER\n"); +		return ERR_PTR(-EINVAL); +	} +	num_str++; + +	ret = kstrtou8(num_str, 0, &num); +	if (ret) +		return ERR_PTR(ret); + +	fsg_opts = to_fsg_opts(&group->cg_item); +	if (num >= FSG_MAX_LUNS) +		return ERR_PTR(-ERANGE); + +	mutex_lock(&fsg_opts->lock); +	if (fsg_opts->refcnt || fsg_opts->common->luns[num]) { +		ret = -EBUSY; +		goto out; +	} + +	opts = kzalloc(sizeof(*opts), GFP_KERNEL); +	if (!opts) { +		ret = -ENOMEM; +		goto out; +	} + +	memset(&config, 0, sizeof(config)); +	config.removable = true; + +	ret = fsg_common_create_lun(fsg_opts->common, &config, num, name, +				    (const char **)&group->cg_item.ci_name); +	if (ret) { +		kfree(opts); +		goto out; +	} +	opts->lun = fsg_opts->common->luns[num]; +	opts->lun_id = num; +	mutex_unlock(&fsg_opts->lock); + +	config_group_init_type_name(&opts->group, name, &fsg_lun_type); + +	return &opts->group; +out: +	mutex_unlock(&fsg_opts->lock); +	return ERR_PTR(ret); +} + +static void fsg_lun_drop(struct config_group *group, struct config_item *item) +{ +	struct fsg_lun_opts *lun_opts; +	struct fsg_opts *fsg_opts; + +	lun_opts = to_fsg_lun_opts(item); +	fsg_opts = to_fsg_opts(&group->cg_item); + +	mutex_lock(&fsg_opts->lock); +	if (fsg_opts->refcnt) { +		struct config_item *gadget; + +		gadget = group->cg_item.ci_parent->ci_parent; +		unregister_gadget_item(gadget); +	} + +	fsg_common_remove_lun(lun_opts->lun, fsg_opts->common->sysfs); +	fsg_opts->common->luns[lun_opts->lun_id] = NULL; +	lun_opts->lun_id = 0; +	mutex_unlock(&fsg_opts->lock); + +	config_item_put(item); +} + +CONFIGFS_ATTR_STRUCT(fsg_opts); +CONFIGFS_ATTR_OPS(fsg_opts); + +static void fsg_attr_release(struct config_item *item) +{ +	struct fsg_opts *opts = to_fsg_opts(item); + +	usb_put_function_instance(&opts->func_inst); +} + +static struct configfs_item_operations fsg_item_ops = { +	.release		= fsg_attr_release, +	.show_attribute		= fsg_opts_attr_show, +	.store_attribute	= fsg_opts_attr_store, +}; + +static ssize_t fsg_opts_stall_show(struct fsg_opts *opts, char *page) +{ +	int result; + +	mutex_lock(&opts->lock); +	result = sprintf(page, "%d", opts->common->can_stall); +	mutex_unlock(&opts->lock); + +	return result; +} + +static ssize_t fsg_opts_stall_store(struct fsg_opts *opts, const char *page, +				    size_t len) +{ +	int ret; +	bool stall; + +	mutex_lock(&opts->lock); + +	if (opts->refcnt) { +		mutex_unlock(&opts->lock); +		return -EBUSY; +	} + +	ret = strtobool(page, &stall); +	if (!ret) { +		opts->common->can_stall = stall; +		ret = len; +	} + +	mutex_unlock(&opts->lock); + +	return ret; +} + +static struct fsg_opts_attribute fsg_opts_stall = +	__CONFIGFS_ATTR(stall, S_IRUGO | S_IWUSR, fsg_opts_stall_show, +			fsg_opts_stall_store); + +#ifdef CONFIG_USB_GADGET_DEBUG_FILES +static ssize_t fsg_opts_num_buffers_show(struct fsg_opts *opts, char *page) +{ +	int result; + +	mutex_lock(&opts->lock); +	result = sprintf(page, "%d", opts->common->fsg_num_buffers); +	mutex_unlock(&opts->lock); + +	return result; +} + +static ssize_t fsg_opts_num_buffers_store(struct fsg_opts *opts, +					  const char *page, size_t len) +{ +	int ret; +	u8 num; + +	mutex_lock(&opts->lock); +	if (opts->refcnt) { +		ret = -EBUSY; +		goto end; +	} +	ret = kstrtou8(page, 0, &num); +	if (ret) +		goto end; + +	ret = fsg_num_buffers_validate(num); +	if (ret) +		goto end; + +	fsg_common_set_num_buffers(opts->common, num); +	ret = len; + +end: +	mutex_unlock(&opts->lock); +	return ret; +} + +static struct fsg_opts_attribute fsg_opts_num_buffers = +	__CONFIGFS_ATTR(num_buffers, S_IRUGO | S_IWUSR, +			fsg_opts_num_buffers_show, +			fsg_opts_num_buffers_store); + +#endif + +static struct configfs_attribute *fsg_attrs[] = { +	&fsg_opts_stall.attr, +#ifdef CONFIG_USB_GADGET_DEBUG_FILES +	&fsg_opts_num_buffers.attr, +#endif +	NULL, +}; + +static struct configfs_group_operations fsg_group_ops = { +	.make_group	= fsg_lun_make, +	.drop_item	= fsg_lun_drop, +}; + +static struct config_item_type fsg_func_type = { +	.ct_item_ops	= &fsg_item_ops, +	.ct_group_ops	= &fsg_group_ops, +	.ct_attrs	= fsg_attrs, +	.ct_owner	= THIS_MODULE, +}; + +static void fsg_free_inst(struct usb_function_instance *fi) +{ +	struct fsg_opts *opts; + +	opts = fsg_opts_from_func_inst(fi); +	fsg_common_put(opts->common); +	kfree(opts); +} + +static struct usb_function_instance *fsg_alloc_inst(void) +{ +	struct fsg_opts *opts; +	struct fsg_lun_config config;  	int rc; -	fsg = kzalloc(sizeof *fsg, GFP_KERNEL); +	opts = kzalloc(sizeof(*opts), GFP_KERNEL); +	if (!opts) +		return ERR_PTR(-ENOMEM); +	mutex_init(&opts->lock); +	opts->func_inst.free_func_inst = fsg_free_inst; +	opts->common = fsg_common_setup(opts->common); +	if (IS_ERR(opts->common)) { +		rc = PTR_ERR(opts->common); +		goto release_opts; +	} +	rc = fsg_common_set_nluns(opts->common, FSG_MAX_LUNS); +	if (rc) +		goto release_opts; + +	rc = fsg_common_set_num_buffers(opts->common, +					CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS); +	if (rc) +		goto release_luns; + +	pr_info(FSG_DRIVER_DESC ", version: " FSG_DRIVER_VERSION "\n"); + +	memset(&config, 0, sizeof(config)); +	config.removable = true; +	rc = fsg_common_create_lun(opts->common, &config, 0, "lun.0", +			(const char **)&opts->func_inst.group.cg_item.ci_name); +	opts->lun0.lun = opts->common->luns[0]; +	opts->lun0.lun_id = 0; +	config_group_init_type_name(&opts->lun0.group, "lun.0", &fsg_lun_type); +	opts->default_groups[0] = &opts->lun0.group; +	opts->func_inst.group.default_groups = opts->default_groups; + +	config_group_init_type_name(&opts->func_inst.group, "", &fsg_func_type); + +	return &opts->func_inst; + +release_luns: +	kfree(opts->common->luns); +release_opts: +	kfree(opts); +	return ERR_PTR(rc); +} + +static void fsg_free(struct usb_function *f) +{ +	struct fsg_dev *fsg; +	struct fsg_opts *opts; + +	fsg = container_of(f, struct fsg_dev, function); +	opts = container_of(f->fi, struct fsg_opts, func_inst); + +	mutex_lock(&opts->lock); +	opts->refcnt--; +	mutex_unlock(&opts->lock); + +	kfree(fsg); +} + +static struct usb_function *fsg_alloc(struct usb_function_instance *fi) +{ +	struct fsg_opts *opts = fsg_opts_from_func_inst(fi); +	struct fsg_common *common = opts->common; +	struct fsg_dev *fsg; + +	fsg = kzalloc(sizeof(*fsg), GFP_KERNEL);  	if (unlikely(!fsg)) -		return -ENOMEM; +		return ERR_PTR(-ENOMEM); -	fsg->function.name        = FSG_DRIVER_DESC; -	fsg->function.strings     = fsg_strings_array; -	fsg->function.bind        = fsg_bind; -	fsg->function.unbind      = fsg_unbind; -	fsg->function.setup       = fsg_setup; -	fsg->function.set_alt     = fsg_set_alt; -	fsg->function.disable     = fsg_disable; +	mutex_lock(&opts->lock); +	opts->refcnt++; +	mutex_unlock(&opts->lock); +	fsg->function.name	= FSG_DRIVER_DESC; +	fsg->function.bind	= fsg_bind; +	fsg->function.unbind	= fsg_unbind; +	fsg->function.setup	= fsg_setup; +	fsg->function.set_alt	= fsg_set_alt; +	fsg->function.disable	= fsg_disable; +	fsg->function.free_func	= fsg_free;  	fsg->common               = common; -	/* -	 * Our caller holds a reference to common structure so we -	 * don't have to be worry about it being freed until we return -	 * from this function.  So instead of incrementing counter now -	 * and decrement in error recovery we increment it only when -	 * call to usb_add_function() was successful. -	 */ -	rc = usb_add_function(c, &fsg->function); -	if (unlikely(rc)) -		kfree(fsg); -	else -		fsg_common_get(fsg->common); -	return rc; +	return &fsg->function;  } +DECLARE_USB_FUNCTION_INIT(mass_storage, fsg_alloc_inst, fsg_alloc); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Michal Nazarewicz");  /************************* Module parameters *************************/ -struct fsg_module_parameters { -	char		*file[FSG_MAX_LUNS]; -	bool		ro[FSG_MAX_LUNS]; -	bool		removable[FSG_MAX_LUNS]; -	bool		cdrom[FSG_MAX_LUNS]; -	bool		nofua[FSG_MAX_LUNS]; - -	unsigned int	file_count, ro_count, removable_count, cdrom_count; -	unsigned int	nofua_count; -	unsigned int	luns;	/* nluns */ -	bool		stall;	/* can_stall */ -}; -#define _FSG_MODULE_PARAM_ARRAY(prefix, params, name, type, desc)	\ -	module_param_array_named(prefix ## name, params.name, type,	\ -				 &prefix ## params.name ## _count,	\ -				 S_IRUGO);				\ -	MODULE_PARM_DESC(prefix ## name, desc) - -#define _FSG_MODULE_PARAM(prefix, params, name, type, desc)		\ -	module_param_named(prefix ## name, params.name, type,		\ -			   S_IRUGO);					\ -	MODULE_PARM_DESC(prefix ## name, desc) - -#define FSG_MODULE_PARAMETERS(prefix, params)				\ -	_FSG_MODULE_PARAM_ARRAY(prefix, params, file, charp,		\ -				"names of backing files or devices");	\ -	_FSG_MODULE_PARAM_ARRAY(prefix, params, ro, bool,		\ -				"true to force read-only");		\ -	_FSG_MODULE_PARAM_ARRAY(prefix, params, removable, bool,	\ -				"true to simulate removable media");	\ -	_FSG_MODULE_PARAM_ARRAY(prefix, params, cdrom, bool,		\ -				"true to simulate CD-ROM instead of disk"); \ -	_FSG_MODULE_PARAM_ARRAY(prefix, params, nofua, bool,		\ -				"true to ignore SCSI WRITE(10,12) FUA bit"); \ -	_FSG_MODULE_PARAM(prefix, params, luns, uint,			\ -			  "number of LUNs");				\ -	_FSG_MODULE_PARAM(prefix, params, stall, bool,			\ -			  "false to prevent bulk stalls") - -static void -fsg_config_from_params(struct fsg_config *cfg, -		       const struct fsg_module_parameters *params) +void fsg_config_from_params(struct fsg_config *cfg, +		       const struct fsg_module_parameters *params, +		       unsigned int fsg_num_buffers)  {  	struct fsg_lun_config *lun;  	unsigned i; @@ -3053,19 +3662,7 @@ fsg_config_from_params(struct fsg_config *cfg,  	/* Finalise */  	cfg->can_stall = params->stall; +	cfg->fsg_num_buffers = fsg_num_buffers;  } +EXPORT_SYMBOL_GPL(fsg_config_from_params); -static inline struct fsg_common * -fsg_common_from_params(struct fsg_common *common, -		       struct usb_composite_dev *cdev, -		       const struct fsg_module_parameters *params) -	__attribute__((unused)); -static inline struct fsg_common * -fsg_common_from_params(struct fsg_common *common, -		       struct usb_composite_dev *cdev, -		       const struct fsg_module_parameters *params) -{ -	struct fsg_config cfg; -	fsg_config_from_params(&cfg, params); -	return fsg_common_init(common, cdev, &cfg); -} diff --git a/drivers/usb/gadget/f_mass_storage.h b/drivers/usb/gadget/f_mass_storage.h new file mode 100644 index 00000000000..b4866fcef30 --- /dev/null +++ b/drivers/usb/gadget/f_mass_storage.h @@ -0,0 +1,166 @@ +#ifndef USB_F_MASS_STORAGE_H +#define USB_F_MASS_STORAGE_H + +#include <linux/usb/composite.h> +#include "storage_common.h" + +struct fsg_module_parameters { +	char		*file[FSG_MAX_LUNS]; +	bool		ro[FSG_MAX_LUNS]; +	bool		removable[FSG_MAX_LUNS]; +	bool		cdrom[FSG_MAX_LUNS]; +	bool		nofua[FSG_MAX_LUNS]; + +	unsigned int	file_count, ro_count, removable_count, cdrom_count; +	unsigned int	nofua_count; +	unsigned int	luns;	/* nluns */ +	bool		stall;	/* can_stall */ +}; + +#define _FSG_MODULE_PARAM_ARRAY(prefix, params, name, type, desc)	\ +	module_param_array_named(prefix ## name, params.name, type,	\ +				 &prefix ## params.name ## _count,	\ +				 S_IRUGO);				\ +	MODULE_PARM_DESC(prefix ## name, desc) + +#define _FSG_MODULE_PARAM(prefix, params, name, type, desc)		\ +	module_param_named(prefix ## name, params.name, type,		\ +			   S_IRUGO);					\ +	MODULE_PARM_DESC(prefix ## name, desc) + +#define __FSG_MODULE_PARAMETERS(prefix, params)				\ +	_FSG_MODULE_PARAM_ARRAY(prefix, params, file, charp,		\ +				"names of backing files or devices");	\ +	_FSG_MODULE_PARAM_ARRAY(prefix, params, ro, bool,		\ +				"true to force read-only");		\ +	_FSG_MODULE_PARAM_ARRAY(prefix, params, removable, bool,	\ +				"true to simulate removable media");	\ +	_FSG_MODULE_PARAM_ARRAY(prefix, params, cdrom, bool,		\ +				"true to simulate CD-ROM instead of disk"); \ +	_FSG_MODULE_PARAM_ARRAY(prefix, params, nofua, bool,		\ +				"true to ignore SCSI WRITE(10,12) FUA bit"); \ +	_FSG_MODULE_PARAM(prefix, params, luns, uint,			\ +			  "number of LUNs");				\ +	_FSG_MODULE_PARAM(prefix, params, stall, bool,			\ +			  "false to prevent bulk stalls") + +#ifdef CONFIG_USB_GADGET_DEBUG_FILES + +#define FSG_MODULE_PARAMETERS(prefix, params)				\ +	__FSG_MODULE_PARAMETERS(prefix, params);			\ +	module_param_named(num_buffers, fsg_num_buffers, uint, S_IRUGO);\ +	MODULE_PARM_DESC(num_buffers, "Number of pipeline buffers") +#else + +#define FSG_MODULE_PARAMETERS(prefix, params)				\ +	__FSG_MODULE_PARAMETERS(prefix, params) + +#endif + +struct fsg_common; + +/* FSF callback functions */ +struct fsg_operations { +	/* +	 * Callback function to call when thread exits.  If no +	 * callback is set or it returns value lower then zero MSF +	 * will force eject all LUNs it operates on (including those +	 * marked as non-removable or with prevent_medium_removal flag +	 * set). +	 */ +	int (*thread_exits)(struct fsg_common *common); +}; + +struct fsg_lun_opts { +	struct config_group group; +	struct fsg_lun *lun; +	int lun_id; +}; + +struct fsg_opts { +	struct fsg_common *common; +	struct usb_function_instance func_inst; +	struct fsg_lun_opts lun0; +	struct config_group *default_groups[2]; +	bool no_configfs; /* for legacy gadgets */ + +	/* +	 * Read/write access to configfs attributes is handled by configfs. +	 * +	 * This is to protect the data from concurrent access by read/write +	 * and create symlink/remove symlink. +	 */ +	struct mutex			lock; +	int				refcnt; +}; + +struct fsg_lun_config { +	const char *filename; +	char ro; +	char removable; +	char cdrom; +	char nofua; +}; + +struct fsg_config { +	unsigned nluns; +	struct fsg_lun_config luns[FSG_MAX_LUNS]; + +	/* Callback functions. */ +	const struct fsg_operations	*ops; +	/* Gadget's private data. */ +	void			*private_data; + +	const char *vendor_name;		/*  8 characters or less */ +	const char *product_name;		/* 16 characters or less */ + +	char			can_stall; +	unsigned int		fsg_num_buffers; +}; + +static inline struct fsg_opts * +fsg_opts_from_func_inst(const struct usb_function_instance *fi) +{ +	return container_of(fi, struct fsg_opts, func_inst); +} + +void fsg_common_get(struct fsg_common *common); + +void fsg_common_put(struct fsg_common *common); + +void fsg_common_set_sysfs(struct fsg_common *common, bool sysfs); + +int fsg_common_set_num_buffers(struct fsg_common *common, unsigned int n); + +void fsg_common_free_buffers(struct fsg_common *common); + +int fsg_common_set_cdev(struct fsg_common *common, +			struct usb_composite_dev *cdev, bool can_stall); + +void fsg_common_remove_lun(struct fsg_lun *lun, bool sysfs); + +void fsg_common_remove_luns(struct fsg_common *common); + +void fsg_common_free_luns(struct fsg_common *common); + +int fsg_common_set_nluns(struct fsg_common *common, int nluns); + +void fsg_common_set_ops(struct fsg_common *common, +			const struct fsg_operations *ops); + +int fsg_common_create_lun(struct fsg_common *common, struct fsg_lun_config *cfg, +			  unsigned int id, const char *name, +			  const char **name_pfx); + +int fsg_common_create_luns(struct fsg_common *common, struct fsg_config *cfg); + +void fsg_common_set_inquiry_string(struct fsg_common *common, const char *vn, +				   const char *pn); + +int fsg_common_run_thread(struct fsg_common *common); + +void fsg_config_from_params(struct fsg_config *cfg, +			    const struct fsg_module_parameters *params, +			    unsigned int fsg_num_buffers); + +#endif /* USB_F_MASS_STORAGE_H */ diff --git a/drivers/usb/gadget/f_midi.c b/drivers/usb/gadget/f_midi.c index 263e721c269..807b31c0edc 100644 --- a/drivers/usb/gadget/f_midi.c +++ b/drivers/usb/gadget/f_midi.c @@ -32,6 +32,8 @@  #include <linux/usb/audio.h>  #include <linux/usb/midi.h> +#include "u_f.h" +  MODULE_AUTHOR("Ben Williamson");  MODULE_LICENSE("GPL v2"); @@ -191,20 +193,10 @@ static struct usb_gadget_strings *midi_strings[] = {  	NULL,  }; -static struct usb_request *alloc_ep_req(struct usb_ep *ep, unsigned length) +static inline struct usb_request *midi_alloc_ep_req(struct usb_ep *ep, +						    unsigned length)  { -	struct usb_request *req; - -	req = usb_ep_alloc_request(ep, GFP_ATOMIC); -	if (req) { -		req->length = length; -		req->buf = kmalloc(length, GFP_ATOMIC); -		if (!req->buf) { -			usb_ep_free_request(ep, req); -			req = NULL; -		} -	} -	return req; +	return alloc_ep_req(ep, length, length);  }  static void free_ep_req(struct usb_ep *ep, struct usb_request *req) @@ -365,7 +357,7 @@ static int f_midi_set_alt(struct usb_function *f, unsigned intf, unsigned alt)  	/* allocate a bunch of read buffers and queue them all at once. */  	for (i = 0; i < midi->qlen && err == 0; i++) {  		struct usb_request *req = -			alloc_ep_req(midi->out_ep, midi->buflen); +			midi_alloc_ep_req(midi->out_ep, midi->buflen);  		if (req == NULL)  			return -ENOMEM; @@ -546,7 +538,7 @@ static void f_midi_transmit(struct f_midi *midi, struct usb_request *req)  		return;  	if (!req) -		req = alloc_ep_req(ep, midi->buflen); +		req = midi_alloc_ep_req(ep, midi->buflen);  	if (!req) {  		ERROR(midi, "gmidi_transmit: alloc_ep_request failed\n"); @@ -672,9 +664,10 @@ static int f_midi_register_card(struct f_midi *midi)  		.dev_free = f_midi_snd_free,  	}; -	err = snd_card_create(midi->index, midi->id, THIS_MODULE, 0, &card); +	err = snd_card_new(&midi->gadget->dev, midi->index, midi->id, +			   THIS_MODULE, 0, &card);  	if (err < 0) { -		ERROR(midi, "snd_card_create() failed\n"); +		ERROR(midi, "snd_card_new() failed\n");  		goto fail;  	}  	midi->card = card; @@ -711,8 +704,6 @@ static int f_midi_register_card(struct f_midi *midi)  	snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, &gmidi_in_ops);  	snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT, &gmidi_out_ops); -	snd_card_set_dev(card, &midi->gadget->dev); -  	/* register it - we're ready to go */  	err = snd_card_register(card);  	if (err < 0) { diff --git a/drivers/usb/gadget/f_ncm.c b/drivers/usb/gadget/f_ncm.c index 1c28fe13328..a9499fd3079 100644 --- a/drivers/usb/gadget/f_ncm.c +++ b/drivers/usb/gadget/f_ncm.c @@ -1386,7 +1386,7 @@ static void ncm_unbind(struct usb_configuration *c, struct usb_function *f)  	usb_ep_free_request(ncm->notify, ncm->notify_req);  } -struct usb_function *ncm_alloc(struct usb_function_instance *fi) +static struct usb_function *ncm_alloc(struct usb_function_instance *fi)  {  	struct f_ncm		*ncm;  	struct f_ncm_opts	*opts; diff --git a/drivers/usb/gadget/f_obex.c b/drivers/usb/gadget/f_obex.c index ad39f1dacba..aebae1853bc 100644 --- a/drivers/usb/gadget/f_obex.c +++ b/drivers/usb/gadget/f_obex.c @@ -499,7 +499,7 @@ static void obex_unbind(struct usb_configuration *c, struct usb_function *f)  	usb_free_all_descriptors(f);  } -struct usb_function *obex_alloc(struct usb_function_instance *fi) +static struct usb_function *obex_alloc(struct usb_function_instance *fi)  {  	struct f_obex	*obex;  	struct f_serial_opts *opts; diff --git a/drivers/usb/gadget/f_phonet.c b/drivers/usb/gadget/f_phonet.c index eb3aa817a66..f2b781773ee 100644 --- a/drivers/usb/gadget/f_phonet.c +++ b/drivers/usb/gadget/f_phonet.c @@ -689,7 +689,7 @@ static void pn_unbind(struct usb_configuration *c, struct usb_function *f)  	usb_free_all_descriptors(f);  } -struct usb_function *phonet_alloc(struct usb_function_instance *fi) +static struct usb_function *phonet_alloc(struct usb_function_instance *fi)  {  	struct f_phonet *fp;  	struct f_phonet_opts *opts; diff --git a/drivers/usb/gadget/f_rndis.c b/drivers/usb/gadget/f_rndis.c index 717ed7f9563..9c41e9515b8 100644 --- a/drivers/usb/gadget/f_rndis.c +++ b/drivers/usb/gadget/f_rndis.c @@ -27,6 +27,7 @@  #include "u_ether_configfs.h"  #include "u_rndis.h"  #include "rndis.h" +#include "configfs.h"  /*   * This function is an RNDIS Ethernet port -- a Microsoft protocol that's @@ -377,7 +378,7 @@ static struct sk_buff *rndis_add_header(struct gether *port,  	if (skb2)  		rndis_add_hdr(skb2); -	dev_kfree_skb_any(skb); +	dev_kfree_skb(skb);  	return skb2;  } @@ -675,7 +676,6 @@ rndis_bind(struct usb_configuration *c, struct usb_function *f)  	int			status;  	struct usb_ep		*ep; -#ifndef USB_FRNDIS_INCLUDED  	struct f_rndis_opts *rndis_opts;  	if (!can_support_rndis(c)) @@ -683,6 +683,15 @@ rndis_bind(struct usb_configuration *c, struct usb_function *f)  	rndis_opts = container_of(f->fi, struct f_rndis_opts, func_inst); +	if (cdev->use_os_string) { +		f->os_desc_table = kzalloc(sizeof(*f->os_desc_table), +					   GFP_KERNEL); +		if (!f->os_desc_table) +			return -ENOMEM; +		f->os_desc_n = 1; +		f->os_desc_table[0].os_desc = &rndis_opts->rndis_os_desc; +	} +  	/*  	 * in drivers/usb/gadget/configfs.c:configfs_composite_bind()  	 * configurations are bound in sequence with list_for_each_entry, @@ -694,14 +703,16 @@ rndis_bind(struct usb_configuration *c, struct usb_function *f)  		gether_set_gadget(rndis_opts->net, cdev->gadget);  		status = gether_register_netdev(rndis_opts->net);  		if (status) -			return status; +			goto fail;  		rndis_opts->bound = true;  	} -#endif +  	us = usb_gstrings_attach(cdev, rndis_strings,  				 ARRAY_SIZE(rndis_string_defs)); -	if (IS_ERR(us)) -		return PTR_ERR(us); +	if (IS_ERR(us)) { +		status = PTR_ERR(us); +		goto fail; +	}  	rndis_control_intf.iInterface = us[0].id;  	rndis_data_intf.iInterface = us[1].id;  	rndis_iad_descriptor.iFunction = us[2].id; @@ -782,13 +793,6 @@ rndis_bind(struct usb_configuration *c, struct usb_function *f)  	rndis->port.open = rndis_open;  	rndis->port.close = rndis_close; -#ifdef USB_FRNDIS_INCLUDED -	status = rndis_register(rndis_response_available, rndis); -	if (status < 0) -		goto fail; -	rndis->config = status; -#endif -  	rndis_set_param_medium(rndis->config, RNDIS_MEDIUM_802_3, 0);  	rndis_set_host_mac(rndis->config, rndis->ethaddr); @@ -810,6 +814,8 @@ rndis_bind(struct usb_configuration *c, struct usb_function *f)  	return 0;  fail: +	kfree(f->os_desc_table); +	f->os_desc_n = 0;  	usb_free_all_descriptors(f);  	if (rndis->notify_req) { @@ -830,66 +836,6 @@ fail:  	return status;  } -#ifdef USB_FRNDIS_INCLUDED - -static void -rndis_old_unbind(struct usb_configuration *c, struct usb_function *f) -{ -	struct f_rndis		*rndis = func_to_rndis(f); - -	rndis_deregister(rndis->config); - -	usb_free_all_descriptors(f); - -	kfree(rndis->notify_req->buf); -	usb_ep_free_request(rndis->notify, rndis->notify_req); - -	kfree(rndis); -} - -int -rndis_bind_config_vendor(struct usb_configuration *c, u8 ethaddr[ETH_ALEN], -		u32 vendorID, const char *manufacturer, struct eth_dev *dev) -{ -	struct f_rndis	*rndis; -	int		status; - -	/* allocate and initialize one new instance */ -	status = -ENOMEM; -	rndis = kzalloc(sizeof *rndis, GFP_KERNEL); -	if (!rndis) -		goto fail; - -	memcpy(rndis->ethaddr, ethaddr, ETH_ALEN); -	rndis->vendorID = vendorID; -	rndis->manufacturer = manufacturer; - -	rndis->port.ioport = dev; -	/* RNDIS activates when the host changes this filter */ -	rndis->port.cdc_filter = 0; - -	/* RNDIS has special (and complex) framing */ -	rndis->port.header_len = sizeof(struct rndis_packet_msg_type); -	rndis->port.wrap = rndis_add_header; -	rndis->port.unwrap = rndis_rm_hdr; - -	rndis->port.func.name = "rndis"; -	/* descriptors are per-instance copies */ -	rndis->port.func.bind = rndis_bind; -	rndis->port.func.unbind = rndis_old_unbind; -	rndis->port.func.set_alt = rndis_set_alt; -	rndis->port.func.setup = rndis_setup; -	rndis->port.func.disable = rndis_disable; - -	status = usb_add_function(c, &rndis->port.func); -	if (status) -		kfree(rndis); -fail: -	return status; -} - -#else -  void rndis_borrow_net(struct usb_function_instance *f, struct net_device *net)  {  	struct f_rndis_opts *opts; @@ -902,7 +848,7 @@ void rndis_borrow_net(struct usb_function_instance *f, struct net_device *net)  	opts->borrowed_net = opts->bound = true;  	opts->net = net;  } -EXPORT_SYMBOL(rndis_borrow_net); +EXPORT_SYMBOL_GPL(rndis_borrow_net);  static inline struct f_rndis_opts *to_f_rndis_opts(struct config_item *item)  { @@ -950,16 +896,22 @@ static void rndis_free_inst(struct usb_function_instance *f)  		else  			free_netdev(opts->net);  	} + +	kfree(opts->rndis_os_desc.group.default_groups); /* single VLA chunk */  	kfree(opts);  }  static struct usb_function_instance *rndis_alloc_inst(void)  {  	struct f_rndis_opts *opts; +	struct usb_os_desc *descs[1]; +	char *names[1];  	opts = kzalloc(sizeof(*opts), GFP_KERNEL);  	if (!opts)  		return ERR_PTR(-ENOMEM); +	opts->rndis_os_desc.ext_compat_id = opts->rndis_ext_compat_id; +  	mutex_init(&opts->lock);  	opts->func_inst.free_func_inst = rndis_free_inst;  	opts->net = gether_setup_default(); @@ -968,7 +920,12 @@ static struct usb_function_instance *rndis_alloc_inst(void)  		kfree(opts);  		return ERR_CAST(net);  	} +	INIT_LIST_HEAD(&opts->rndis_os_desc.ext_prop); +	descs[0] = &opts->rndis_os_desc; +	names[0] = "rndis"; +	usb_os_desc_prepare_interf_dir(&opts->func_inst.group, 1, descs, +				       names, THIS_MODULE);  	config_group_init_type_name(&opts->func_inst.group, "",  				    &rndis_func_type); @@ -993,6 +950,8 @@ static void rndis_unbind(struct usb_configuration *c, struct usb_function *f)  {  	struct f_rndis		*rndis = func_to_rndis(f); +	kfree(f->os_desc_table); +	f->os_desc_n = 0;  	usb_free_all_descriptors(f);  	kfree(rndis->notify_req->buf); @@ -1047,8 +1006,26 @@ static struct usb_function *rndis_alloc(struct usb_function_instance *fi)  	return &rndis->port.func;  } -DECLARE_USB_FUNCTION_INIT(rndis, rndis_alloc_inst, rndis_alloc); +DECLARE_USB_FUNCTION(rndis, rndis_alloc_inst, rndis_alloc); + +static int __init rndis_mod_init(void) +{ +	int ret; + +	ret = rndis_init(); +	if (ret) +		return ret; + +	return usb_function_register(&rndisusb_func); +} +module_init(rndis_mod_init); + +static void __exit rndis_mod_exit(void) +{ +	usb_function_unregister(&rndisusb_func); +	rndis_exit(); +} +module_exit(rndis_mod_exit); +  MODULE_LICENSE("GPL");  MODULE_AUTHOR("David Brownell"); - -#endif diff --git a/drivers/usb/gadget/f_serial.c b/drivers/usb/gadget/f_serial.c index 981113c9924..9ecbcbf36a4 100644 --- a/drivers/usb/gadget/f_serial.c +++ b/drivers/usb/gadget/f_serial.c @@ -354,7 +354,7 @@ static void gser_unbind(struct usb_configuration *c, struct usb_function *f)  	usb_free_all_descriptors(f);  } -struct usb_function *gser_alloc(struct usb_function_instance *fi) +static struct usb_function *gser_alloc(struct usb_function_instance *fi)  {  	struct f_gser	*gser;  	struct f_serial_opts *opts; diff --git a/drivers/usb/gadget/f_sourcesink.c b/drivers/usb/gadget/f_sourcesink.c index a8895859a22..d3cd52db78f 100644 --- a/drivers/usb/gadget/f_sourcesink.c +++ b/drivers/usb/gadget/f_sourcesink.c @@ -21,6 +21,7 @@  #include "g_zero.h"  #include "gadget_chips.h" +#include "u_f.h"  /*   * SOURCE/SINK FUNCTION ... a primary testing vehicle for USB peripheral @@ -201,7 +202,7 @@ static struct usb_endpoint_descriptor ss_source_desc = {  	.wMaxPacketSize =	cpu_to_le16(1024),  }; -struct usb_ss_ep_comp_descriptor ss_source_comp_desc = { +static struct usb_ss_ep_comp_descriptor ss_source_comp_desc = {  	.bLength =		USB_DT_SS_EP_COMP_SIZE,  	.bDescriptorType =	USB_DT_SS_ENDPOINT_COMP, @@ -218,7 +219,7 @@ static struct usb_endpoint_descriptor ss_sink_desc = {  	.wMaxPacketSize =	cpu_to_le16(1024),  }; -struct usb_ss_ep_comp_descriptor ss_sink_comp_desc = { +static struct usb_ss_ep_comp_descriptor ss_sink_comp_desc = {  	.bLength =		USB_DT_SS_EP_COMP_SIZE,  	.bDescriptorType =	USB_DT_SS_ENDPOINT_COMP, @@ -236,7 +237,7 @@ static struct usb_endpoint_descriptor ss_iso_source_desc = {  	.bInterval =		4,  }; -struct usb_ss_ep_comp_descriptor ss_iso_source_comp_desc = { +static struct usb_ss_ep_comp_descriptor ss_iso_source_comp_desc = {  	.bLength =		USB_DT_SS_EP_COMP_SIZE,  	.bDescriptorType =	USB_DT_SS_ENDPOINT_COMP, @@ -254,7 +255,7 @@ static struct usb_endpoint_descriptor ss_iso_sink_desc = {  	.bInterval =		4,  }; -struct usb_ss_ep_comp_descriptor ss_iso_sink_comp_desc = { +static struct usb_ss_ep_comp_descriptor ss_iso_sink_comp_desc = {  	.bLength =		USB_DT_SS_EP_COMP_SIZE,  	.bDescriptorType =	USB_DT_SS_ENDPOINT_COMP, @@ -301,23 +302,9 @@ static struct usb_gadget_strings *sourcesink_strings[] = {  /*-------------------------------------------------------------------------*/ -struct usb_request *alloc_ep_req(struct usb_ep *ep, int len) +static inline struct usb_request *ss_alloc_ep_req(struct usb_ep *ep, int len)  { -	struct usb_request      *req; - -	req = usb_ep_alloc_request(ep, GFP_ATOMIC); -	if (req) { -		if (len) -			req->length = len; -		else -			req->length = buflen; -		req->buf = kmalloc(req->length, GFP_ATOMIC); -		if (!req->buf) { -			usb_ep_free_request(ep, req); -			req = NULL; -		} -	} -	return req; +	return alloc_ep_req(ep, len, buflen);  }  void free_ep_req(struct usb_ep *ep, struct usb_request *req) @@ -490,6 +477,14 @@ no_iso:  static void  sourcesink_free_func(struct usb_function *f)  { +	struct f_ss_opts *opts; + +	opts = container_of(f->fi, struct f_ss_opts, func_inst); + +	mutex_lock(&opts->lock); +	opts->refcnt--; +	mutex_unlock(&opts->lock); +  	usb_free_all_descriptors(f);  	kfree(func_to_ss(f));  } @@ -628,10 +623,10 @@ static int source_sink_start_ep(struct f_sourcesink *ss, bool is_in,  				break;  			}  			ep = is_in ? ss->iso_in_ep : ss->iso_out_ep; -			req = alloc_ep_req(ep, size); +			req = ss_alloc_ep_req(ep, size);  		} else {  			ep = is_in ? ss->in_ep : ss->out_ep; -			req = alloc_ep_req(ep, 0); +			req = ss_alloc_ep_req(ep, 0);  		}  		if (!req) @@ -878,6 +873,11 @@ static struct usb_function *source_sink_alloc_func(  		return NULL;  	ss_opts =  container_of(fi, struct f_ss_opts, func_inst); + +	mutex_lock(&ss_opts->lock); +	ss_opts->refcnt++; +	mutex_unlock(&ss_opts->lock); +  	pattern = ss_opts->pattern;  	isoc_interval = ss_opts->isoc_interval;  	isoc_maxpacket = ss_opts->isoc_maxpacket; @@ -898,6 +898,303 @@ static struct usb_function *source_sink_alloc_func(  	return &ss->function;  } +static inline struct f_ss_opts *to_f_ss_opts(struct config_item *item) +{ +	return container_of(to_config_group(item), struct f_ss_opts, +			    func_inst.group); +} + +CONFIGFS_ATTR_STRUCT(f_ss_opts); +CONFIGFS_ATTR_OPS(f_ss_opts); + +static void ss_attr_release(struct config_item *item) +{ +	struct f_ss_opts *ss_opts = to_f_ss_opts(item); + +	usb_put_function_instance(&ss_opts->func_inst); +} + +static struct configfs_item_operations ss_item_ops = { +	.release		= ss_attr_release, +	.show_attribute		= f_ss_opts_attr_show, +	.store_attribute	= f_ss_opts_attr_store, +}; + +static ssize_t f_ss_opts_pattern_show(struct f_ss_opts *opts, char *page) +{ +	int result; + +	mutex_lock(&opts->lock); +	result = sprintf(page, "%d", opts->pattern); +	mutex_unlock(&opts->lock); + +	return result; +} + +static ssize_t f_ss_opts_pattern_store(struct f_ss_opts *opts, +				       const char *page, size_t len) +{ +	int ret; +	u8 num; + +	mutex_lock(&opts->lock); +	if (opts->refcnt) { +		ret = -EBUSY; +		goto end; +	} + +	ret = kstrtou8(page, 0, &num); +	if (ret) +		goto end; + +	if (num != 0 && num != 1 && num != 2) { +		ret = -EINVAL; +		goto end; +	} + +	opts->pattern = num; +	ret = len; +end: +	mutex_unlock(&opts->lock); +	return ret; +} + +static struct f_ss_opts_attribute f_ss_opts_pattern = +	__CONFIGFS_ATTR(pattern, S_IRUGO | S_IWUSR, +			f_ss_opts_pattern_show, +			f_ss_opts_pattern_store); + +static ssize_t f_ss_opts_isoc_interval_show(struct f_ss_opts *opts, char *page) +{ +	int result; + +	mutex_lock(&opts->lock); +	result = sprintf(page, "%d", opts->isoc_interval); +	mutex_unlock(&opts->lock); + +	return result; +} + +static ssize_t f_ss_opts_isoc_interval_store(struct f_ss_opts *opts, +				       const char *page, size_t len) +{ +	int ret; +	u8 num; + +	mutex_lock(&opts->lock); +	if (opts->refcnt) { +		ret = -EBUSY; +		goto end; +	} + +	ret = kstrtou8(page, 0, &num); +	if (ret) +		goto end; + +	if (num > 16) { +		ret = -EINVAL; +		goto end; +	} + +	opts->isoc_interval = num; +	ret = len; +end: +	mutex_unlock(&opts->lock); +	return ret; +} + +static struct f_ss_opts_attribute f_ss_opts_isoc_interval = +	__CONFIGFS_ATTR(isoc_interval, S_IRUGO | S_IWUSR, +			f_ss_opts_isoc_interval_show, +			f_ss_opts_isoc_interval_store); + +static ssize_t f_ss_opts_isoc_maxpacket_show(struct f_ss_opts *opts, char *page) +{ +	int result; + +	mutex_lock(&opts->lock); +	result = sprintf(page, "%d", opts->isoc_maxpacket); +	mutex_unlock(&opts->lock); + +	return result; +} + +static ssize_t f_ss_opts_isoc_maxpacket_store(struct f_ss_opts *opts, +				       const char *page, size_t len) +{ +	int ret; +	u16 num; + +	mutex_lock(&opts->lock); +	if (opts->refcnt) { +		ret = -EBUSY; +		goto end; +	} + +	ret = kstrtou16(page, 0, &num); +	if (ret) +		goto end; + +	if (num > 1024) { +		ret = -EINVAL; +		goto end; +	} + +	opts->isoc_maxpacket = num; +	ret = len; +end: +	mutex_unlock(&opts->lock); +	return ret; +} + +static struct f_ss_opts_attribute f_ss_opts_isoc_maxpacket = +	__CONFIGFS_ATTR(isoc_maxpacket, S_IRUGO | S_IWUSR, +			f_ss_opts_isoc_maxpacket_show, +			f_ss_opts_isoc_maxpacket_store); + +static ssize_t f_ss_opts_isoc_mult_show(struct f_ss_opts *opts, char *page) +{ +	int result; + +	mutex_lock(&opts->lock); +	result = sprintf(page, "%d", opts->isoc_mult); +	mutex_unlock(&opts->lock); + +	return result; +} + +static ssize_t f_ss_opts_isoc_mult_store(struct f_ss_opts *opts, +				       const char *page, size_t len) +{ +	int ret; +	u8 num; + +	mutex_lock(&opts->lock); +	if (opts->refcnt) { +		ret = -EBUSY; +		goto end; +	} + +	ret = kstrtou8(page, 0, &num); +	if (ret) +		goto end; + +	if (num > 2) { +		ret = -EINVAL; +		goto end; +	} + +	opts->isoc_mult = num; +	ret = len; +end: +	mutex_unlock(&opts->lock); +	return ret; +} + +static struct f_ss_opts_attribute f_ss_opts_isoc_mult = +	__CONFIGFS_ATTR(isoc_mult, S_IRUGO | S_IWUSR, +			f_ss_opts_isoc_mult_show, +			f_ss_opts_isoc_mult_store); + +static ssize_t f_ss_opts_isoc_maxburst_show(struct f_ss_opts *opts, char *page) +{ +	int result; + +	mutex_lock(&opts->lock); +	result = sprintf(page, "%d", opts->isoc_maxburst); +	mutex_unlock(&opts->lock); + +	return result; +} + +static ssize_t f_ss_opts_isoc_maxburst_store(struct f_ss_opts *opts, +				       const char *page, size_t len) +{ +	int ret; +	u8 num; + +	mutex_lock(&opts->lock); +	if (opts->refcnt) { +		ret = -EBUSY; +		goto end; +	} + +	ret = kstrtou8(page, 0, &num); +	if (ret) +		goto end; + +	if (num > 15) { +		ret = -EINVAL; +		goto end; +	} + +	opts->isoc_maxburst = num; +	ret = len; +end: +	mutex_unlock(&opts->lock); +	return ret; +} + +static struct f_ss_opts_attribute f_ss_opts_isoc_maxburst = +	__CONFIGFS_ATTR(isoc_maxburst, S_IRUGO | S_IWUSR, +			f_ss_opts_isoc_maxburst_show, +			f_ss_opts_isoc_maxburst_store); + +static ssize_t f_ss_opts_bulk_buflen_show(struct f_ss_opts *opts, char *page) +{ +	int result; + +	mutex_lock(&opts->lock); +	result = sprintf(page, "%d", opts->bulk_buflen); +	mutex_unlock(&opts->lock); + +	return result; +} + +static ssize_t f_ss_opts_bulk_buflen_store(struct f_ss_opts *opts, +					   const char *page, size_t len) +{ +	int ret; +	u32 num; + +	mutex_lock(&opts->lock); +	if (opts->refcnt) { +		ret = -EBUSY; +		goto end; +	} + +	ret = kstrtou32(page, 0, &num); +	if (ret) +		goto end; + +	opts->bulk_buflen = num; +	ret = len; +end: +	mutex_unlock(&opts->lock); +	return ret; +} + +static struct f_ss_opts_attribute f_ss_opts_bulk_buflen = +	__CONFIGFS_ATTR(buflen, S_IRUGO | S_IWUSR, +			f_ss_opts_bulk_buflen_show, +			f_ss_opts_bulk_buflen_store); + +static struct configfs_attribute *ss_attrs[] = { +	&f_ss_opts_pattern.attr, +	&f_ss_opts_isoc_interval.attr, +	&f_ss_opts_isoc_maxpacket.attr, +	&f_ss_opts_isoc_mult.attr, +	&f_ss_opts_isoc_maxburst.attr, +	&f_ss_opts_bulk_buflen.attr, +	NULL, +}; + +static struct config_item_type ss_func_type = { +	.ct_item_ops    = &ss_item_ops, +	.ct_attrs	= ss_attrs, +	.ct_owner       = THIS_MODULE, +}; +  static void source_sink_free_instance(struct usb_function_instance *fi)  {  	struct f_ss_opts *ss_opts; @@ -913,7 +1210,15 @@ static struct usb_function_instance *source_sink_alloc_inst(void)  	ss_opts = kzalloc(sizeof(*ss_opts), GFP_KERNEL);  	if (!ss_opts)  		return ERR_PTR(-ENOMEM); +	mutex_init(&ss_opts->lock);  	ss_opts->func_inst.free_func_inst = source_sink_free_instance; +	ss_opts->isoc_interval = GZERO_ISOC_INTERVAL; +	ss_opts->isoc_maxpacket = GZERO_ISOC_MAXPACKET; +	ss_opts->bulk_buflen = GZERO_BULK_BUFLEN; + +	config_group_init_type_name(&ss_opts->func_inst.group, "", +				    &ss_func_type); +  	return &ss_opts->func_inst;  }  DECLARE_USB_FUNCTION(SourceSink, source_sink_alloc_inst, diff --git a/drivers/usb/gadget/f_subset.c b/drivers/usb/gadget/f_subset.c index 7c8674fa7e8..1ea8baf3333 100644 --- a/drivers/usb/gadget/f_subset.c +++ b/drivers/usb/gadget/f_subset.c @@ -276,7 +276,7 @@ static int geth_set_alt(struct usb_function *f, unsigned intf, unsigned alt)  	}  	net = gether_connect(&geth->port); -	return IS_ERR(net) ? PTR_ERR(net) : 0; +	return PTR_ERR_OR_ZERO(net);  }  static void geth_disable(struct usb_function *f) @@ -301,7 +301,6 @@ geth_bind(struct usb_configuration *c, struct usb_function *f)  	int			status;  	struct usb_ep		*ep; -#ifndef USB_FSUBSET_INCLUDED  	struct f_gether_opts	*gether_opts;  	gether_opts = container_of(f->fi, struct f_gether_opts, func_inst); @@ -322,7 +321,7 @@ geth_bind(struct usb_configuration *c, struct usb_function *f)  			return status;  		gether_opts->bound = true;  	} -#endif +  	us = usb_gstrings_attach(cdev, geth_strings,  				 ARRAY_SIZE(geth_string_defs));  	if (IS_ERR(us)) @@ -393,61 +392,6 @@ fail:  	return status;  } -#ifdef USB_FSUBSET_INCLUDED - -static void -geth_old_unbind(struct usb_configuration *c, struct usb_function *f) -{ -	geth_string_defs[0].id = 0; -	usb_free_all_descriptors(f); -	kfree(func_to_geth(f)); -} - -/** - * geth_bind_config - add CDC Subset network link to a configuration - * @c: the configuration to support the network link - * @ethaddr: a buffer in which the ethernet address of the host side - *	side of the link was recorded - * @dev: eth_dev structure - * Context: single threaded during gadget setup - * - * Returns zero on success, else negative errno. - * - * Caller must have called @gether_setup().  Caller is also responsible - * for calling @gether_cleanup() before module unload. - */ -int geth_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN], -		struct eth_dev *dev) -{ -	struct f_gether	*geth; -	int		status; - -	/* allocate and initialize one new instance */ -	geth = kzalloc(sizeof *geth, GFP_KERNEL); -	if (!geth) -		return -ENOMEM; - -	/* export host's Ethernet address in CDC format */ -	snprintf(geth->ethaddr, sizeof geth->ethaddr, "%pm", ethaddr); -	geth_string_defs[1].s = geth->ethaddr; - -	geth->port.ioport = dev; -	geth->port.cdc_filter = DEFAULT_FILTER; - -	geth->port.func.name = "cdc_subset"; -	geth->port.func.bind = geth_bind; -	geth->port.func.unbind = geth_old_unbind; -	geth->port.func.set_alt = geth_set_alt; -	geth->port.func.disable = geth_disable; - -	status = usb_add_function(c, &geth->port.func); -	if (status) -		kfree(geth); -	return status; -} - -#else -  static inline struct f_gether_opts *to_f_gether_opts(struct config_item *item)  {  	return container_of(to_config_group(item), struct f_gether_opts, @@ -573,5 +517,3 @@ static struct usb_function *geth_alloc(struct usb_function_instance *fi)  DECLARE_USB_FUNCTION_INIT(geth, geth_alloc_inst, geth_alloc);  MODULE_LICENSE("GPL");  MODULE_AUTHOR("David Brownell"); - -#endif diff --git a/drivers/usb/gadget/f_uac2.c b/drivers/usb/gadget/f_uac2.c index 2f23566e53d..6261db4a991 100644 --- a/drivers/usb/gadget/f_uac2.c +++ b/drivers/usb/gadget/f_uac2.c @@ -196,7 +196,7 @@ agdev_iso_complete(struct usb_ep *ep, struct usb_request *req)  	struct snd_uac2_chip *uac2 = prm->uac2;  	/* i/f shutting down */ -	if (!prm->ep_enabled) +	if (!prm->ep_enabled || req->status == -ESHUTDOWN)  		return;  	/* @@ -394,7 +394,7 @@ static int snd_uac2_probe(struct platform_device *pdev)  	int err;  	/* Choose any slot, with no id */ -	err = snd_card_create(-1, NULL, THIS_MODULE, 0, &card); +	err = snd_card_new(&pdev->dev, -1, NULL, THIS_MODULE, 0, &card);  	if (err < 0)  		return err; @@ -421,8 +421,6 @@ static int snd_uac2_probe(struct platform_device *pdev)  	strcpy(card->shortname, "UAC2_Gadget");  	sprintf(card->longname, "UAC2_Gadget %i", pdev->id); -	snd_card_set_dev(card, &pdev->dev); -  	snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS,  		snd_dma_continuous_data(GFP_KERNEL), 0, BUFF_SIZE_MAX); @@ -976,8 +974,6 @@ afunc_bind(struct usb_configuration *cfg, struct usb_function *fn)  	prm->rbuf = kzalloc(prm->max_psize * USB_XFERS, GFP_KERNEL);  	if (!prm->rbuf) {  		prm->max_psize = 0; -		dev_err(&uac2->pdev.dev, -			"%s:%d Error!\n", __func__, __LINE__);  		goto err;  	} @@ -986,8 +982,6 @@ afunc_bind(struct usb_configuration *cfg, struct usb_function *fn)  	prm->rbuf = kzalloc(prm->max_psize * USB_XFERS, GFP_KERNEL);  	if (!prm->rbuf) {  		prm->max_psize = 0; -		dev_err(&uac2->pdev.dev, -			"%s:%d Error!\n", __func__, __LINE__);  		goto err;  	} @@ -1300,10 +1294,8 @@ static int audio_bind_config(struct usb_configuration *cfg)  	int res;  	agdev_g = kzalloc(sizeof *agdev_g, GFP_KERNEL); -	if (agdev_g == NULL) { -		printk(KERN_ERR "Unable to allocate audio gadget\n"); +	if (agdev_g == NULL)  		return -ENOMEM; -	}  	res = usb_string_ids_tab(cfg->cdev, strings_fn);  	if (res) diff --git a/drivers/usb/gadget/fotg210-udc.c b/drivers/usb/gadget/fotg210-udc.c index 32db2eee2d8..e143d69f601 100644 --- a/drivers/usb/gadget/fotg210-udc.c +++ b/drivers/usb/gadget/fotg210-udc.c @@ -1112,17 +1112,13 @@ static int fotg210_udc_probe(struct platform_device *pdev)  	/* initialize udc */  	fotg210 = kzalloc(sizeof(struct fotg210_udc), GFP_KERNEL); -	if (fotg210 == NULL) { -		pr_err("kzalloc error\n"); +	if (fotg210 == NULL)  		goto err_alloc; -	}  	for (i = 0; i < FOTG210_MAX_NUM_EP; i++) {  		_ep[i] = kzalloc(sizeof(struct fotg210_ep), GFP_KERNEL); -		if (_ep[i] == NULL) { -			pr_err("_ep kzalloc error\n"); +		if (_ep[i] == NULL)  			goto err_alloc; -		}  		fotg210->ep[i] = _ep[i];  	} @@ -1157,8 +1153,9 @@ static int fotg210_udc_probe(struct platform_device *pdev)  		INIT_LIST_HEAD(&ep->queue);  		ep->ep.name = fotg210_ep_name[i];  		ep->ep.ops = &fotg210_ep_ops; +		usb_ep_set_maxpacket_limit(&ep->ep, (unsigned short) ~0);  	} -	fotg210->ep[0]->ep.maxpacket = 0x40; +	usb_ep_set_maxpacket_limit(&fotg210->ep[0]->ep, 0x40);  	fotg210->gadget.ep0 = &fotg210->ep[0]->ep;  	INIT_LIST_HEAD(&fotg210->gadget.ep0->ep_list); @@ -1214,6 +1211,6 @@ static struct platform_driver fotg210_driver = {  module_platform_driver(fotg210_driver); -MODULE_AUTHOR("Yuan-Hsin Chen <yhchen@faraday-tech.com>"); +MODULE_AUTHOR("Yuan-Hsin Chen, Feng-Hsin Chiang <john453@faraday-tech.com>");  MODULE_LICENSE("GPL");  MODULE_DESCRIPTION(DRIVER_DESC); diff --git a/drivers/usb/gadget/fsl_qe_udc.c b/drivers/usb/gadget/fsl_qe_udc.c index f3bb363f1d4..ad548333516 100644 --- a/drivers/usb/gadget/fsl_qe_udc.c +++ b/drivers/usb/gadget/fsl_qe_udc.c @@ -22,7 +22,6 @@  #include <linux/module.h>  #include <linux/kernel.h> -#include <linux/init.h>  #include <linux/ioport.h>  #include <linux/types.h>  #include <linux/errno.h> @@ -33,6 +32,7 @@  #include <linux/io.h>  #include <linux/moduleparam.h>  #include <linux/of_address.h> +#include <linux/of_irq.h>  #include <linux/of_platform.h>  #include <linux/dma-mapping.h>  #include <linux/usb/ch9.h> @@ -2428,7 +2428,7 @@ static int qe_ep_config(struct qe_udc *udc, unsigned char pipe_num)  	ep->ep.ops = &qe_ep_ops;  	ep->stopped = 1; -	ep->ep.maxpacket = (unsigned short) ~0; +	usb_ep_set_maxpacket_limit(&ep->ep, (unsigned short) ~0);  	ep->ep.desc = NULL;  	ep->dir = 0xff;  	ep->epnum = (u8)pipe_num; @@ -2716,7 +2716,7 @@ MODULE_DEVICE_TABLE(of, qe_udc_match);  static struct platform_driver udc_driver = {  	.driver = { -		.name = (char *)driver_name, +		.name = driver_name,  		.owner = THIS_MODULE,  		.of_match_table = qe_udc_match,  	}, diff --git a/drivers/usb/gadget/fsl_udc_core.c b/drivers/usb/gadget/fsl_udc_core.c index 36ac7cfba91..28e4fc95702 100644 --- a/drivers/usb/gadget/fsl_udc_core.c +++ b/drivers/usb/gadget/fsl_udc_core.c @@ -1219,6 +1219,10 @@ static int fsl_pullup(struct usb_gadget *gadget, int is_on)  	struct fsl_udc *udc;  	udc = container_of(gadget, struct fsl_udc, gadget); + +	if (!udc->vbus_active) +		return -EOPNOTSUPP; +  	udc->softconnect = (is_on != 0);  	if (can_pullup(udc))  		fsl_writel((fsl_readl(&dr_regs->usbcmd) | USB_CMD_RUN_STOP), @@ -2252,10 +2256,8 @@ static int __init struct_udc_setup(struct fsl_udc *udc,  	udc->phy_mode = pdata->phy_mode;  	udc->eps = kzalloc(sizeof(struct fsl_ep) * udc->max_ep, GFP_KERNEL); -	if (!udc->eps) { -		ERR("malloc fsl_ep failed\n"); +	if (!udc->eps)  		return -1; -	}  	/* initialized QHs, take care of alignment */  	size = udc->max_ep * sizeof(struct ep_queue_head); @@ -2311,7 +2313,7 @@ static int __init struct_ep_setup(struct fsl_udc *udc, unsigned char index,  	/* for ep0: maxP defined in desc  	 * for other eps, maxP is set by epautoconfig() called by gadget layer  	 */ -	ep->ep.maxpacket = (unsigned short) ~0; +	usb_ep_set_maxpacket_limit(&ep->ep, (unsigned short) ~0);  	/* the queue lists any req for this ep */  	INIT_LIST_HEAD(&ep->queue); @@ -2338,10 +2340,8 @@ static int __init fsl_udc_probe(struct platform_device *pdev)  	u32 dccparams;  	udc_controller = kzalloc(sizeof(struct fsl_udc), GFP_KERNEL); -	if (udc_controller == NULL) { -		ERR("malloc udc failed\n"); +	if (udc_controller == NULL)  		return -ENOMEM; -	}  	pdata = dev_get_platdata(&pdev->dev);  	udc_controller->pdata = pdata; @@ -2469,7 +2469,8 @@ static int __init fsl_udc_probe(struct platform_device *pdev)  	 * for other eps, gadget layer called ep_enable with defined desc  	 */  	udc_controller->eps[0].ep.desc = &fsl_ep0_desc; -	udc_controller->eps[0].ep.maxpacket = USB_MAX_CTRL_PAYLOAD; +	usb_ep_set_maxpacket_limit(&udc_controller->eps[0].ep, +				   USB_MAX_CTRL_PAYLOAD);  	/* setup the udc->eps[] for non-control endpoints and link  	 * to gadget.ep_list */ @@ -2531,8 +2532,8 @@ static int __exit fsl_udc_remove(struct platform_device *pdev)  	if (!udc_controller)  		return -ENODEV; -	usb_del_gadget_udc(&udc_controller->gadget);  	udc_controller->done = &done; +	usb_del_gadget_udc(&udc_controller->gadget);  	fsl_udc_clk_release(); @@ -2666,7 +2667,7 @@ static struct platform_driver udc_driver = {  	.suspend	= fsl_udc_suspend,  	.resume		= fsl_udc_resume,  	.driver		= { -			.name = (char *)driver_name, +			.name = driver_name,  			.owner = THIS_MODULE,  			/* udc suspend/resume called from OTG driver */  			.suspend = fsl_udc_otg_suspend, diff --git a/drivers/usb/gadget/fusb300_udc.c b/drivers/usb/gadget/fusb300_udc.c index f1dd6daabe2..3deb4e93807 100644 --- a/drivers/usb/gadget/fusb300_udc.c +++ b/drivers/usb/gadget/fusb300_udc.c @@ -22,7 +22,7 @@  MODULE_DESCRIPTION("FUSB300  USB gadget driver");  MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Yuan Hsin Chen <yhchen@faraday-tech.com>"); +MODULE_AUTHOR("Yuan-Hsin Chen, Feng-Hsin Chiang <john453@faraday-tech.com>");  MODULE_ALIAS("platform:fusb300_udc");  #define DRIVER_VERSION	"20 October 2010" @@ -1400,17 +1400,13 @@ static int __init fusb300_probe(struct platform_device *pdev)  	/* initialize udc */  	fusb300 = kzalloc(sizeof(struct fusb300), GFP_KERNEL); -	if (fusb300 == NULL) { -		pr_err("kzalloc error\n"); +	if (fusb300 == NULL)  		goto clean_up; -	}  	for (i = 0; i < FUSB300_MAX_NUM_EP; i++) {  		_ep[i] = kzalloc(sizeof(struct fusb300_ep), GFP_KERNEL); -		if (_ep[i] == NULL) { -			pr_err("_ep kzalloc error\n"); +		if (_ep[i] == NULL)  			goto clean_up; -		}  		fusb300->ep[i] = _ep[i];  	} @@ -1452,9 +1448,9 @@ static int __init fusb300_probe(struct platform_device *pdev)  		INIT_LIST_HEAD(&ep->queue);  		ep->ep.name = fusb300_ep_name[i];  		ep->ep.ops = &fusb300_ep_ops; -		ep->ep.maxpacket = HS_BULK_MAX_PACKET_SIZE; +		usb_ep_set_maxpacket_limit(&ep->ep, HS_BULK_MAX_PACKET_SIZE);  	} -	fusb300->ep[0]->ep.maxpacket = HS_CTL_MAX_PACKET_SIZE; +	usb_ep_set_maxpacket_limit(&fusb300->ep[0]->ep, HS_CTL_MAX_PACKET_SIZE);  	fusb300->ep[0]->epnum = 0;  	fusb300->gadget.ep0 = &fusb300->ep[0]->ep;  	INIT_LIST_HEAD(&fusb300->gadget.ep0->ep_list); diff --git a/drivers/usb/gadget/g_ffs.c b/drivers/usb/gadget/g_ffs.c index 5327c82472e..fe12e6a2744 100644 --- a/drivers/usb/gadget/g_ffs.c +++ b/drivers/usb/gadget/g_ffs.c @@ -13,14 +13,10 @@  #define pr_fmt(fmt) "g_ffs: " fmt  #include <linux/module.h> -/* - * 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. - */ +  #if defined CONFIG_USB_FUNCTIONFS_ETH || defined CONFIG_USB_FUNCTIONFS_RNDIS +#include <linux/netdevice.h> +  #  if defined USB_ETH_RNDIS  #    undef USB_ETH_RNDIS  #  endif @@ -28,31 +24,31 @@  #    define USB_ETH_RNDIS y  #  endif -#define USBF_ECM_INCLUDED -#  include "f_ecm.c" -#define USB_FSUBSET_INCLUDED -#  include "f_subset.c" +#  include "u_ecm.h" +#  include "u_gether.h"  #  ifdef USB_ETH_RNDIS -#    define USB_FRNDIS_INCLUDED -#    include "f_rndis.c" +#    include "u_rndis.h"  #    include "rndis.h"  #  endif  #  include "u_ether.h" -static u8 gfs_host_mac[ETH_ALEN]; -static struct eth_dev *the_dev; +USB_ETHERNET_MODULE_PARAMETERS(); +  #  ifdef CONFIG_USB_FUNCTIONFS_ETH -static int eth_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN], -		struct eth_dev *dev); +static int eth_bind_config(struct usb_configuration *c); +static struct usb_function_instance *fi_ecm; +static struct usb_function *f_ecm; +static struct usb_function_instance *fi_geth; +static struct usb_function *f_geth; +#  endif +#  ifdef CONFIG_USB_FUNCTIONFS_RNDIS +static int bind_rndis_config(struct usb_configuration *c); +static struct usb_function_instance *fi_rndis; +static struct usb_function *f_rndis;  #  endif -#else -#  define the_dev	NULL -#  define gether_cleanup(dev) do { } while (0) -#  define gfs_host_mac NULL -struct eth_dev;  #endif -#include "f_fs.c" +#include "u_fs.h"  #define DRIVER_NAME	"g_ffs"  #define DRIVER_DESC	"USB Function Filesystem" @@ -67,17 +63,8 @@ MODULE_LICENSE("GPL");  #define GFS_MAX_DEVS	10 -struct gfs_ffs_obj { -	const char *name; -	bool mounted; -	bool desc_ready; -	struct ffs_data *ffs_data; -}; -  USB_GADGET_COMPOSITE_OPTIONS(); -USB_ETHERNET_MODULE_PARAMETERS(); -  static struct usb_device_descriptor gfs_dev_desc = {  	.bLength		= sizeof gfs_dev_desc,  	.bDescriptorType	= USB_DT_DEVICE, @@ -144,12 +131,12 @@ static struct usb_gadget_strings *gfs_dev_strings[] = {  struct gfs_configuration {  	struct usb_configuration c; -	int (*eth)(struct usb_configuration *c, u8 *ethaddr, -			struct eth_dev *dev); +	int (*eth)(struct usb_configuration *c); +	int num;  } gfs_configurations[] = {  #ifdef CONFIG_USB_FUNCTIONFS_RNDIS  	{ -		.eth		= rndis_bind_config, +		.eth		= bind_rndis_config,  	},  #endif @@ -165,10 +152,15 @@ struct gfs_configuration {  #endif  }; +static void *functionfs_acquire_dev(struct ffs_dev *dev); +static void functionfs_release_dev(struct ffs_dev *dev); +static int functionfs_ready_callback(struct ffs_data *ffs); +static void functionfs_closed_callback(struct ffs_data *ffs);  static int gfs_bind(struct usb_composite_dev *cdev);  static int gfs_unbind(struct usb_composite_dev *cdev);  static int gfs_do_config(struct usb_configuration *c); +  static __refdata struct usb_composite_driver gfs_driver = {  	.name		= DRIVER_NAME,  	.dev		= &gfs_dev_desc, @@ -178,206 +170,244 @@ static __refdata struct usb_composite_driver gfs_driver = {  	.unbind		= gfs_unbind,  }; -static DEFINE_MUTEX(gfs_lock);  static unsigned int missing_funcs; -static bool gfs_ether_setup;  static bool gfs_registered;  static bool gfs_single_func; -static struct gfs_ffs_obj *ffs_tab; +static struct usb_function_instance **fi_ffs; +static struct usb_function **f_ffs[] = { +#ifdef CONFIG_USB_FUNCTIONFS_RNDIS +	NULL, +#endif + +#ifdef CONFIG_USB_FUNCTIONFS_ETH +	NULL, +#endif + +#ifdef CONFIG_USB_FUNCTIONFS_GENERIC +	NULL, +#endif +}; + +#define N_CONF ARRAY_SIZE(f_ffs)  static int __init gfs_init(void)  { +	struct f_fs_opts *opts;  	int i; +	int ret = 0;  	ENTER(); -	if (!func_num) { +	if (func_num < 2) {  		gfs_single_func = true;  		func_num = 1;  	} -	ffs_tab = kcalloc(func_num, sizeof *ffs_tab, GFP_KERNEL); -	if (!ffs_tab) -		return -ENOMEM; +	/* +	 * Allocate in one chunk for easier maintenance +	 */ +	f_ffs[0] = kcalloc(func_num * N_CONF, sizeof(*f_ffs), GFP_KERNEL); +	if (!f_ffs[0]) { +		ret = -ENOMEM; +		goto no_func; +	} +	for (i = 1; i < N_CONF; ++i) +		f_ffs[i] = f_ffs[0] + i * func_num; + +	fi_ffs = kcalloc(func_num, sizeof(*fi_ffs), GFP_KERNEL); +	if (!fi_ffs) { +		ret = -ENOMEM; +		goto no_func; +	} -	if (!gfs_single_func) -		for (i = 0; i < func_num; i++) -			ffs_tab[i].name = func_names[i]; +	for (i = 0; i < func_num; i++) { +		fi_ffs[i] = usb_get_function_instance("ffs"); +		if (IS_ERR(fi_ffs[i])) { +			ret = PTR_ERR(fi_ffs[i]); +			--i; +			goto no_dev; +		} +		opts = to_f_fs_opts(fi_ffs[i]); +		if (gfs_single_func) +			ret = ffs_single_dev(opts->dev); +		else +			ret = ffs_name_dev(opts->dev, func_names[i]); +		if (ret) +			goto no_dev; +		opts->dev->ffs_ready_callback = functionfs_ready_callback; +		opts->dev->ffs_closed_callback = functionfs_closed_callback; +		opts->dev->ffs_acquire_dev_callback = functionfs_acquire_dev; +		opts->dev->ffs_release_dev_callback = functionfs_release_dev; +		opts->no_configfs = true; +	}  	missing_funcs = func_num; -	return functionfs_init(); +	return 0; +no_dev: +	while (i >= 0) +		usb_put_function_instance(fi_ffs[i--]); +	kfree(fi_ffs); +no_func: +	kfree(f_ffs[0]); +	return ret;  }  module_init(gfs_init);  static void __exit gfs_exit(void)  { +	int i; +  	ENTER(); -	mutex_lock(&gfs_lock);  	if (gfs_registered)  		usb_composite_unregister(&gfs_driver);  	gfs_registered = false; -	functionfs_cleanup(); +	kfree(f_ffs[0]); -	mutex_unlock(&gfs_lock); -	kfree(ffs_tab); +	for (i = 0; i < func_num; i++) +		usb_put_function_instance(fi_ffs[i]); + +	kfree(fi_ffs);  }  module_exit(gfs_exit); -static struct gfs_ffs_obj *gfs_find_dev(const char *dev_name) +static void *functionfs_acquire_dev(struct ffs_dev *dev)  { -	int i; - -	ENTER(); - -	if (gfs_single_func) -		return &ffs_tab[0]; - -	for (i = 0; i < func_num; i++) -		if (strcmp(ffs_tab[i].name, dev_name) == 0) -			return &ffs_tab[i]; +	if (!try_module_get(THIS_MODULE)) +		return ERR_PTR(-ENODEV); +	 +	return 0; +} -	return NULL; +static void functionfs_release_dev(struct ffs_dev *dev) +{ +	module_put(THIS_MODULE);  } +/* + * The caller of this function takes ffs_lock  + */  static int functionfs_ready_callback(struct ffs_data *ffs)  { -	struct gfs_ffs_obj *ffs_obj; -	int ret; - -	ENTER(); -	mutex_lock(&gfs_lock); +	int ret = 0; -	ffs_obj = ffs->private_data; -	if (!ffs_obj) { -		ret = -EINVAL; -		goto done; -	} - -	if (WARN_ON(ffs_obj->desc_ready)) { -		ret = -EBUSY; -		goto done; -	} -	ffs_obj->desc_ready = true; -	ffs_obj->ffs_data = ffs; +	if (--missing_funcs) +		return 0; -	if (--missing_funcs) { -		ret = 0; -		goto done; -	} +	if (gfs_registered) +		return -EBUSY; -	if (gfs_registered) { -		ret = -EBUSY; -		goto done; -	}  	gfs_registered = true;  	ret = usb_composite_probe(&gfs_driver);  	if (unlikely(ret < 0))  		gfs_registered = false; - -done: -	mutex_unlock(&gfs_lock); +	  	return ret;  } +/* + * The caller of this function takes ffs_lock  + */  static void functionfs_closed_callback(struct ffs_data *ffs)  { -	struct gfs_ffs_obj *ffs_obj; - -	ENTER(); -	mutex_lock(&gfs_lock); - -	ffs_obj = ffs->private_data; -	if (!ffs_obj) -		goto done; - -	ffs_obj->desc_ready = false;  	missing_funcs++;  	if (gfs_registered)  		usb_composite_unregister(&gfs_driver);  	gfs_registered = false; - -done: -	mutex_unlock(&gfs_lock);  } -static void *functionfs_acquire_dev_callback(const char *dev_name) +/* + * It is assumed that gfs_bind is called from a context where ffs_lock is held + */ +static int gfs_bind(struct usb_composite_dev *cdev)  { -	struct gfs_ffs_obj *ffs_dev; +#if defined CONFIG_USB_FUNCTIONFS_ETH || defined CONFIG_USB_FUNCTIONFS_RNDIS +	struct net_device *net; +#endif +	int ret, i;  	ENTER(); -	mutex_lock(&gfs_lock); -	ffs_dev = gfs_find_dev(dev_name); -	if (!ffs_dev) { -		ffs_dev = ERR_PTR(-ENODEV); -		goto done; -	} - -	if (ffs_dev->mounted) { -		ffs_dev = ERR_PTR(-EBUSY); -		goto done; +	if (missing_funcs) +		return -ENODEV; +#if defined CONFIG_USB_FUNCTIONFS_ETH +	if (can_support_ecm(cdev->gadget)) { +		struct f_ecm_opts *ecm_opts; + +		fi_ecm = usb_get_function_instance("ecm"); +		if (IS_ERR(fi_ecm)) +			return PTR_ERR(fi_ecm); +		ecm_opts = container_of(fi_ecm, struct f_ecm_opts, func_inst); +		net = ecm_opts->net; +	} else { +		struct f_gether_opts *geth_opts; + +		fi_geth = usb_get_function_instance("geth"); +		if (IS_ERR(fi_geth)) +			return PTR_ERR(fi_geth); +		geth_opts = container_of(fi_geth, struct f_gether_opts, +					 func_inst); +		net = geth_opts->net;  	} -	ffs_dev->mounted = true; +#endif -done: -	mutex_unlock(&gfs_lock); -	return ffs_dev; -} +#ifdef CONFIG_USB_FUNCTIONFS_RNDIS +	{ +		struct f_rndis_opts *rndis_opts; -static void functionfs_release_dev_callback(struct ffs_data *ffs_data) -{ -	struct gfs_ffs_obj *ffs_dev; +		fi_rndis = usb_get_function_instance("rndis"); +		if (IS_ERR(fi_rndis)) { +			ret = PTR_ERR(fi_rndis); +			goto error; +		} +		rndis_opts = container_of(fi_rndis, struct f_rndis_opts, +					  func_inst); +#ifndef CONFIG_USB_FUNCTIONFS_ETH +		net = rndis_opts->net; +#endif +	} +#endif -	ENTER(); -	mutex_lock(&gfs_lock); +#if defined CONFIG_USB_FUNCTIONFS_ETH || defined CONFIG_USB_FUNCTIONFS_RNDIS +	gether_set_qmult(net, qmult); +	if (!gether_set_host_addr(net, host_addr)) +		pr_info("using host ethernet address: %s", host_addr); +	if (!gether_set_dev_addr(net, dev_addr)) +		pr_info("using self ethernet address: %s", dev_addr); +#endif -	ffs_dev = ffs_data->private_data; -	if (ffs_dev) -		ffs_dev->mounted = false; +#if defined CONFIG_USB_FUNCTIONFS_RNDIS && defined CONFIG_USB_FUNCTIONFS_ETH +	gether_set_gadget(net, cdev->gadget); +	ret = gether_register_netdev(net); +	if (ret) +		goto error_rndis; -	mutex_unlock(&gfs_lock); -} +	if (can_support_ecm(cdev->gadget)) { +		struct f_ecm_opts *ecm_opts; -/* - * It is assumed that gfs_bind is called from a context where gfs_lock is held - */ -static int gfs_bind(struct usb_composite_dev *cdev) -{ -	int ret, i; +		ecm_opts = container_of(fi_ecm, struct f_ecm_opts, func_inst); +		ecm_opts->bound = true; +	} else { +		struct f_gether_opts *geth_opts; -	ENTER(); +		geth_opts = container_of(fi_geth, struct f_gether_opts, +					 func_inst); +		geth_opts->bound = true; +	} -	if (missing_funcs) -		return -ENODEV; -#if defined CONFIG_USB_FUNCTIONFS_ETH || defined CONFIG_USB_FUNCTIONFS_RNDIS -	the_dev = gether_setup(cdev->gadget, dev_addr, host_addr, gfs_host_mac, -			       qmult); +	rndis_borrow_net(fi_rndis, net);  #endif -	if (IS_ERR(the_dev)) { -		ret = PTR_ERR(the_dev); -		goto error_quick; -	} -	gfs_ether_setup = true; +	/* TODO: gstrings_attach? */  	ret = usb_string_ids_tab(cdev, gfs_strings);  	if (unlikely(ret < 0)) -		goto error; +		goto error_rndis;  	gfs_dev_desc.iProduct = gfs_strings[USB_GADGET_PRODUCT_IDX].id; -	for (i = func_num; i--; ) { -		ret = functionfs_bind(ffs_tab[i].ffs_data, cdev); -		if (unlikely(ret < 0)) { -			while (++i < func_num) -				functionfs_unbind(ffs_tab[i].ffs_data); -			goto error; -		} -	} -  	for (i = 0; i < ARRAY_SIZE(gfs_configurations); ++i) {  		struct gfs_configuration *c = gfs_configurations + i;  		int sid = USB_GADGET_FIRST_AVAIL_IDX + i; @@ -387,6 +417,8 @@ static int gfs_bind(struct usb_composite_dev *cdev)  		c->c.bConfigurationValue	= 1 + i;  		c->c.bmAttributes		= USB_CONFIG_ATT_SELFPOWER; +		c->num = i; +  		ret = usb_add_config(cdev, &c->c, gfs_do_config);  		if (unlikely(ret < 0))  			goto error_unbind; @@ -394,18 +426,24 @@ static int gfs_bind(struct usb_composite_dev *cdev)  	usb_composite_overwrite_options(cdev, &coverwrite);  	return 0; +/* TODO */  error_unbind: -	for (i = 0; i < func_num; i++) -		functionfs_unbind(ffs_tab[i].ffs_data); +error_rndis: +#ifdef CONFIG_USB_FUNCTIONFS_RNDIS +	usb_put_function_instance(fi_rndis);  error: -	gether_cleanup(the_dev); -error_quick: -	gfs_ether_setup = false; +#endif +#if defined CONFIG_USB_FUNCTIONFS_ETH +	if (can_support_ecm(cdev->gadget)) +		usb_put_function_instance(fi_ecm); +	else +		usb_put_function_instance(fi_geth); +#endif  	return ret;  }  /* - * It is assumed that gfs_unbind is called from a context where gfs_lock is held + * It is assumed that gfs_unbind is called from a context where ffs_lock is held   */  static int gfs_unbind(struct usb_composite_dev *cdev)  { @@ -413,28 +451,30 @@ static int gfs_unbind(struct usb_composite_dev *cdev)  	ENTER(); -	/* -	 * We may have been called in an error recovery from -	 * composite_bind() after gfs_unbind() failure so we need to -	 * check if gfs_ffs_data is not NULL since gfs_bind() handles -	 * all error recovery itself.  I'd rather we werent called -	 * from composite on orror recovery, but what you're gonna -	 * do...? -	 */ -	if (gfs_ether_setup) -		gether_cleanup(the_dev); -	gfs_ether_setup = false; -	for (i = func_num; i--; ) -		if (ffs_tab[i].ffs_data) -			functionfs_unbind(ffs_tab[i].ffs_data); +#ifdef CONFIG_USB_FUNCTIONFS_RNDIS +	usb_put_function(f_rndis); +	usb_put_function_instance(fi_rndis); +#endif + +#if defined CONFIG_USB_FUNCTIONFS_ETH +	if (can_support_ecm(cdev->gadget)) { +		usb_put_function(f_ecm); +		usb_put_function_instance(fi_ecm); +	} else { +		usb_put_function(f_geth); +		usb_put_function_instance(fi_geth); +	} +#endif +	for (i = 0; i < N_CONF * func_num; ++i) +		usb_put_function(*(f_ffs[0] + i));  	return 0;  }  /*   * It is assumed that gfs_do_config is called from a context where - * gfs_lock is held + * ffs_lock is held   */  static int gfs_do_config(struct usb_configuration *c)  { @@ -452,15 +492,22 @@ static int gfs_do_config(struct usb_configuration *c)  	}  	if (gc->eth) { -		ret = gc->eth(c, gfs_host_mac, the_dev); +		ret = gc->eth(c);  		if (unlikely(ret < 0))  			return ret;  	}  	for (i = 0; i < func_num; i++) { -		ret = functionfs_bind_config(c->cdev, c, ffs_tab[i].ffs_data); -		if (unlikely(ret < 0)) -			return ret; +		f_ffs[gc->num][i] = usb_get_function(fi_ffs[i]); +		if (IS_ERR(f_ffs[gc->num][i])) { +			ret = PTR_ERR(f_ffs[gc->num][i]); +			goto error; +		} +		ret = usb_add_function(c, f_ffs[gc->num][i]); +		if (ret < 0) { +			usb_put_function(f_ffs[gc->num][i]); +			goto error; +		}  	}  	/* @@ -477,16 +524,59 @@ static int gfs_do_config(struct usb_configuration *c)  		c->interface[c->next_interface_id] = NULL;  	return 0; +error: +	while (--i >= 0) { +		if (!IS_ERR(f_ffs[gc->num][i])) +			usb_remove_function(c, f_ffs[gc->num][i]); +		usb_put_function(f_ffs[gc->num][i]); +	} +	return ret;  }  #ifdef CONFIG_USB_FUNCTIONFS_ETH -static int eth_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN], -		struct eth_dev *dev) +static int eth_bind_config(struct usb_configuration *c)  { -	return can_support_ecm(c->cdev->gadget) -		? ecm_bind_config(c, ethaddr, dev) -		: geth_bind_config(c, ethaddr, dev); +	int status = 0; + +	if (can_support_ecm(c->cdev->gadget)) { +		f_ecm = usb_get_function(fi_ecm); +		if (IS_ERR(f_ecm)) +			return PTR_ERR(f_ecm); + +		status = usb_add_function(c, f_ecm); +		if (status < 0) +			usb_put_function(f_ecm); + +	} else { +		f_geth = usb_get_function(fi_geth); +		if (IS_ERR(f_geth)) +			return PTR_ERR(f_geth); + +		status = usb_add_function(c, f_geth); +		if (status < 0) +			usb_put_function(f_geth); +	} +	return status; +} + +#endif + +#ifdef CONFIG_USB_FUNCTIONFS_RNDIS + +static int bind_rndis_config(struct usb_configuration *c) +{ +	int status = 0; + +	f_rndis = usb_get_function(fi_rndis); +	if (IS_ERR(f_rndis)) +		return PTR_ERR(f_rndis); + +	status = usb_add_function(c, f_rndis); +	if (status < 0) +		usb_put_function(f_rndis); + +	return status;  }  #endif diff --git a/drivers/usb/gadget/g_zero.h b/drivers/usb/gadget/g_zero.h index ef3e8515272..15f180904f8 100644 --- a/drivers/usb/gadget/g_zero.h +++ b/drivers/usb/gadget/g_zero.h @@ -6,6 +6,11 @@  #ifndef __G_ZERO_H  #define __G_ZERO_H +#define GZERO_BULK_BUFLEN	4096 +#define GZERO_QLEN		32 +#define GZERO_ISOC_INTERVAL	4 +#define GZERO_ISOC_MAXPACKET	1024 +  struct usb_zero_options {  	unsigned pattern;  	unsigned isoc_interval; @@ -24,19 +29,36 @@ struct f_ss_opts {  	unsigned isoc_mult;  	unsigned isoc_maxburst;  	unsigned bulk_buflen; + +	/* +	 * Read/write access to configfs attributes is handled by configfs. +	 * +	 * This is to protect the data from concurrent access by read/write +	 * and create symlink/remove symlink. +	 */ +	struct mutex			lock; +	int				refcnt;  };  struct f_lb_opts {  	struct usb_function_instance func_inst;  	unsigned bulk_buflen;  	unsigned qlen; + +	/* +	 * Read/write access to configfs attributes is handled by configfs. +	 * +	 * This is to protect the data from concurrent access by read/write +	 * and create symlink/remove symlink. +	 */ +	struct mutex			lock; +	int				refcnt;  };  void lb_modexit(void);  int lb_modinit(void);  /* common utilities */ -struct usb_request *alloc_ep_req(struct usb_ep *ep, int len);  void free_ep_req(struct usb_ep *ep, struct usb_request *req);  void disable_endpoints(struct usb_composite_dev *cdev,  		struct usb_ep *in, struct usb_ep *out, diff --git a/drivers/usb/gadget/goku_udc.c b/drivers/usb/gadget/goku_udc.c index c64deb9e3d6..6c85839e15a 100644 --- a/drivers/usb/gadget/goku_udc.c +++ b/drivers/usb/gadget/goku_udc.c @@ -30,7 +30,6 @@  #include <linux/ioport.h>  #include <linux/slab.h>  #include <linux/errno.h> -#include <linux/init.h>  #include <linux/timer.h>  #include <linux/list.h>  #include <linux/interrupt.h> @@ -231,7 +230,7 @@ static void ep_reset(struct goku_udc_regs __iomem *regs, struct goku_ep *ep)  		}  	} -	ep->ep.maxpacket = MAX_FIFO_SIZE; +	usb_ep_set_maxpacket_limit(&ep->ep, MAX_FIFO_SIZE);  	ep->ep.desc = NULL;  	ep->stopped = 1;  	ep->irqs = 0; @@ -1165,7 +1164,7 @@ static int udc_proc_read(struct seq_file *m, void *v)  				s = "invalid"; break;  			default:  				s = "?"; break; -			}; s; }), +			} s; }),  			(tmp & EPxSTATUS_TOGGLE) ? "data1" : "data0",  			(tmp & EPxSTATUS_SUSPEND) ? " suspend" : "",  			(tmp & EPxSTATUS_FIFO_DISABLE) ? " disable" : "", @@ -1251,7 +1250,7 @@ static void udc_reinit (struct goku_udc *dev)  	}  	dev->ep[0].reg_mode = NULL; -	dev->ep[0].ep.maxpacket = MAX_EP0_SIZE; +	usb_ep_set_maxpacket_limit(&dev->ep[0].ep, MAX_EP0_SIZE);  	list_del_init (&dev->ep[0].ep.ep_list);  } @@ -1350,16 +1349,12 @@ static int goku_udc_start(struct usb_gadget *g,  	return 0;  } -static void -stop_activity(struct goku_udc *dev, struct usb_gadget_driver *driver) +static void stop_activity(struct goku_udc *dev)  {  	unsigned	i;  	DBG (dev, "%s\n", __func__); -	if (dev->gadget.speed == USB_SPEED_UNKNOWN) -		driver = NULL; -  	/* disconnect gadget driver after quiesceing hw and the driver */  	udc_reset (dev);  	for (i = 0; i < 4; i++) @@ -1377,7 +1372,7 @@ static int goku_udc_stop(struct usb_gadget *g,  	spin_lock_irqsave(&dev->lock, flags);  	dev->driver = NULL; -	stop_activity(dev, driver); +	stop_activity(dev);  	spin_unlock_irqrestore(&dev->lock, flags);  	return 0; @@ -1521,7 +1516,7 @@ rescan:  	if (unlikely(stat & INT_DEVWIDE)) {  		if (stat & INT_SYSERROR) {  			ERROR(dev, "system error\n"); -			stop_activity(dev, dev->driver); +			stop_activity(dev);  			stat = 0;  			handled = 1;  			// FIXME have a neater way to prevent re-enumeration @@ -1536,7 +1531,7 @@ rescan:  			} else {  				DBG(dev, "disconnect\n");  				if (dev->gadget.speed == USB_SPEED_FULL) -					stop_activity(dev, dev->driver); +					stop_activity(dev);  				dev->ep0state = EP0_DISCONNECT;  				dev->int_enable = INT_DEVWIDE;  				writel(dev->int_enable, &dev->regs->int_enable); @@ -1701,7 +1696,6 @@ static void goku_remove(struct pci_dev *pdev)  	if (dev->enabled)  		pci_disable_device(pdev); -	pci_set_drvdata(pdev, NULL);  	dev->regs = NULL;  	INFO(dev, "unbind\n"); diff --git a/drivers/usb/gadget/gr_udc.c b/drivers/usb/gadget/gr_udc.c new file mode 100644 index 00000000000..c7004ee89c9 --- /dev/null +++ b/drivers/usb/gadget/gr_udc.c @@ -0,0 +1,2236 @@ +/* + * USB Peripheral Controller driver for Aeroflex Gaisler GRUSBDC. + * + * 2013 (c) Aeroflex Gaisler AB + * + * This driver supports GRUSBDC USB Device Controller cores available in the + * GRLIB VHDL IP core library. + * + * Full documentation of the GRUSBDC core can be found here: + * http://www.gaisler.com/products/grlib/grip.pdf + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * Contributors: + * - Andreas Larsson <andreas@gaisler.com> + * - Marko Isomaki + */ + +/* + * A GRUSBDC core can have up to 16 IN endpoints and 16 OUT endpoints each + * individually configurable to any of the four USB transfer types. This driver + * only supports cores in DMA mode. + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/slab.h> +#include <linux/spinlock.h> +#include <linux/errno.h> +#include <linux/list.h> +#include <linux/interrupt.h> +#include <linux/device.h> +#include <linux/usb/ch9.h> +#include <linux/usb/gadget.h> +#include <linux/dma-mapping.h> +#include <linux/dmapool.h> +#include <linux/debugfs.h> +#include <linux/seq_file.h> +#include <linux/of_platform.h> +#include <linux/of_irq.h> +#include <linux/of_address.h> + +#include <asm/byteorder.h> + +#include "gr_udc.h" + +#define	DRIVER_NAME	"gr_udc" +#define	DRIVER_DESC	"Aeroflex Gaisler GRUSBDC USB Peripheral Controller" + +static const char driver_name[] = DRIVER_NAME; +static const char driver_desc[] = DRIVER_DESC; + +#define gr_read32(x) (ioread32be((x))) +#define gr_write32(x, v) (iowrite32be((v), (x))) + +/* USB speed and corresponding string calculated from status register value */ +#define GR_SPEED(status) \ +	((status & GR_STATUS_SP) ? USB_SPEED_FULL : USB_SPEED_HIGH) +#define GR_SPEED_STR(status) usb_speed_string(GR_SPEED(status)) + +/* Size of hardware buffer calculated from epctrl register value */ +#define GR_BUFFER_SIZE(epctrl)					      \ +	((((epctrl) & GR_EPCTRL_BUFSZ_MASK) >> GR_EPCTRL_BUFSZ_POS) * \ +	 GR_EPCTRL_BUFSZ_SCALER) + +/* ---------------------------------------------------------------------- */ +/* Debug printout functionality */ + +static const char * const gr_modestring[] = {"control", "iso", "bulk", "int"}; + +static const char *gr_ep0state_string(enum gr_ep0state state) +{ +	static const char *const names[] = { +		[GR_EP0_DISCONNECT] = "disconnect", +		[GR_EP0_SETUP] = "setup", +		[GR_EP0_IDATA] = "idata", +		[GR_EP0_ODATA] = "odata", +		[GR_EP0_ISTATUS] = "istatus", +		[GR_EP0_OSTATUS] = "ostatus", +		[GR_EP0_STALL] = "stall", +		[GR_EP0_SUSPEND] = "suspend", +	}; + +	if (state < 0 || state >= ARRAY_SIZE(names)) +		return "UNKNOWN"; + +	return names[state]; +} + +#ifdef VERBOSE_DEBUG + +static void gr_dbgprint_request(const char *str, struct gr_ep *ep, +				struct gr_request *req) +{ +	int buflen = ep->is_in ? req->req.length : req->req.actual; +	int rowlen = 32; +	int plen = min(rowlen, buflen); + +	dev_dbg(ep->dev->dev, "%s: 0x%p, %d bytes data%s:\n", str, req, buflen, +		(buflen > plen ? " (truncated)" : "")); +	print_hex_dump_debug("   ", DUMP_PREFIX_NONE, +			     rowlen, 4, req->req.buf, plen, false); +} + +static void gr_dbgprint_devreq(struct gr_udc *dev, u8 type, u8 request, +			       u16 value, u16 index, u16 length) +{ +	dev_vdbg(dev->dev, "REQ: %02x.%02x v%04x i%04x l%04x\n", +		 type, request, value, index, length); +} +#else /* !VERBOSE_DEBUG */ + +static void gr_dbgprint_request(const char *str, struct gr_ep *ep, +				struct gr_request *req) {} + +static void gr_dbgprint_devreq(struct gr_udc *dev, u8 type, u8 request, +			       u16 value, u16 index, u16 length) {} + +#endif /* VERBOSE_DEBUG */ + +/* ---------------------------------------------------------------------- */ +/* Debugfs functionality */ + +#ifdef CONFIG_USB_GADGET_DEBUG_FS + +static void gr_seq_ep_show(struct seq_file *seq, struct gr_ep *ep) +{ +	u32 epctrl = gr_read32(&ep->regs->epctrl); +	u32 epstat = gr_read32(&ep->regs->epstat); +	int mode = (epctrl & GR_EPCTRL_TT_MASK) >> GR_EPCTRL_TT_POS; +	struct gr_request *req; + +	seq_printf(seq, "%s:\n", ep->ep.name); +	seq_printf(seq, "  mode = %s\n", gr_modestring[mode]); +	seq_printf(seq, "  halted: %d\n", !!(epctrl & GR_EPCTRL_EH)); +	seq_printf(seq, "  disabled: %d\n", !!(epctrl & GR_EPCTRL_ED)); +	seq_printf(seq, "  valid: %d\n", !!(epctrl & GR_EPCTRL_EV)); +	seq_printf(seq, "  dma_start = %d\n", ep->dma_start); +	seq_printf(seq, "  stopped = %d\n", ep->stopped); +	seq_printf(seq, "  wedged = %d\n", ep->wedged); +	seq_printf(seq, "  callback = %d\n", ep->callback); +	seq_printf(seq, "  maxpacket = %d\n", ep->ep.maxpacket); +	seq_printf(seq, "  maxpacket_limit = %d\n", ep->ep.maxpacket_limit); +	seq_printf(seq, "  bytes_per_buffer = %d\n", ep->bytes_per_buffer); +	if (mode == 1 || mode == 3) +		seq_printf(seq, "  nt = %d\n", +			   (epctrl & GR_EPCTRL_NT_MASK) >> GR_EPCTRL_NT_POS); + +	seq_printf(seq, "  Buffer 0: %s %s%d\n", +		   epstat & GR_EPSTAT_B0 ? "valid" : "invalid", +		   epstat & GR_EPSTAT_BS ? " " : "selected ", +		   (epstat & GR_EPSTAT_B0CNT_MASK) >> GR_EPSTAT_B0CNT_POS); +	seq_printf(seq, "  Buffer 1: %s %s%d\n", +		   epstat & GR_EPSTAT_B1 ? "valid" : "invalid", +		   epstat & GR_EPSTAT_BS ? "selected " : " ", +		   (epstat & GR_EPSTAT_B1CNT_MASK) >> GR_EPSTAT_B1CNT_POS); + +	if (list_empty(&ep->queue)) { +		seq_puts(seq, "  Queue: empty\n\n"); +		return; +	} + +	seq_puts(seq, "  Queue:\n"); +	list_for_each_entry(req, &ep->queue, queue) { +		struct gr_dma_desc *desc; +		struct gr_dma_desc *next; + +		seq_printf(seq, "    0x%p: 0x%p %d %d\n", req, +			   &req->req.buf, req->req.actual, req->req.length); + +		next = req->first_desc; +		do { +			desc = next; +			next = desc->next_desc; +			seq_printf(seq, "    %c 0x%p (0x%08x): 0x%05x 0x%08x\n", +				   desc == req->curr_desc ? 'c' : ' ', +				   desc, desc->paddr, desc->ctrl, desc->data); +		} while (desc != req->last_desc); +	} +	seq_puts(seq, "\n"); +} + + +static int gr_seq_show(struct seq_file *seq, void *v) +{ +	struct gr_udc *dev = seq->private; +	u32 control = gr_read32(&dev->regs->control); +	u32 status = gr_read32(&dev->regs->status); +	struct gr_ep *ep; + +	seq_printf(seq, "usb state = %s\n", +		   usb_state_string(dev->gadget.state)); +	seq_printf(seq, "address = %d\n", +		   (control & GR_CONTROL_UA_MASK) >> GR_CONTROL_UA_POS); +	seq_printf(seq, "speed = %s\n", GR_SPEED_STR(status)); +	seq_printf(seq, "ep0state = %s\n", gr_ep0state_string(dev->ep0state)); +	seq_printf(seq, "irq_enabled = %d\n", dev->irq_enabled); +	seq_printf(seq, "remote_wakeup = %d\n", dev->remote_wakeup); +	seq_printf(seq, "test_mode = %d\n", dev->test_mode); +	seq_puts(seq, "\n"); + +	list_for_each_entry(ep, &dev->ep_list, ep_list) +		gr_seq_ep_show(seq, ep); + +	return 0; +} + +static int gr_dfs_open(struct inode *inode, struct file *file) +{ +	return single_open(file, gr_seq_show, inode->i_private); +} + +static const struct file_operations gr_dfs_fops = { +	.owner		= THIS_MODULE, +	.open		= gr_dfs_open, +	.read		= seq_read, +	.llseek		= seq_lseek, +	.release	= single_release, +}; + +static void gr_dfs_create(struct gr_udc *dev) +{ +	const char *name = "gr_udc_state"; + +	dev->dfs_root = debugfs_create_dir(dev_name(dev->dev), NULL); +	dev->dfs_state = debugfs_create_file(name, 0444, dev->dfs_root, dev, +					     &gr_dfs_fops); +} + +static void gr_dfs_delete(struct gr_udc *dev) +{ +	/* Handles NULL and ERR pointers internally */ +	debugfs_remove(dev->dfs_state); +	debugfs_remove(dev->dfs_root); +} + +#else /* !CONFIG_USB_GADGET_DEBUG_FS */ + +static void gr_dfs_create(struct gr_udc *dev) {} +static void gr_dfs_delete(struct gr_udc *dev) {} + +#endif /* CONFIG_USB_GADGET_DEBUG_FS */ + +/* ---------------------------------------------------------------------- */ +/* DMA and request handling */ + +/* Allocates a new struct gr_dma_desc, sets paddr and zeroes the rest */ +static struct gr_dma_desc *gr_alloc_dma_desc(struct gr_ep *ep, gfp_t gfp_flags) +{ +	dma_addr_t paddr; +	struct gr_dma_desc *dma_desc; + +	dma_desc = dma_pool_alloc(ep->dev->desc_pool, gfp_flags, &paddr); +	if (!dma_desc) { +		dev_err(ep->dev->dev, "Could not allocate from DMA pool\n"); +		return NULL; +	} + +	memset(dma_desc, 0, sizeof(*dma_desc)); +	dma_desc->paddr = paddr; + +	return dma_desc; +} + +static inline void gr_free_dma_desc(struct gr_udc *dev, +				    struct gr_dma_desc *desc) +{ +	dma_pool_free(dev->desc_pool, desc, (dma_addr_t)desc->paddr); +} + +/* Frees the chain of struct gr_dma_desc for the given request */ +static void gr_free_dma_desc_chain(struct gr_udc *dev, struct gr_request *req) +{ +	struct gr_dma_desc *desc; +	struct gr_dma_desc *next; + +	next = req->first_desc; +	if (!next) +		return; + +	do { +		desc = next; +		next = desc->next_desc; +		gr_free_dma_desc(dev, desc); +	} while (desc != req->last_desc); + +	req->first_desc = NULL; +	req->curr_desc = NULL; +	req->last_desc = NULL; +} + +static void gr_ep0_setup(struct gr_udc *dev, struct gr_request *req); + +/* + * Frees allocated resources and calls the appropriate completion function/setup + * package handler for a finished request. + * + * Must be called with dev->lock held and irqs disabled. + */ +static void gr_finish_request(struct gr_ep *ep, struct gr_request *req, +			      int status) +	__releases(&dev->lock) +	__acquires(&dev->lock) +{ +	struct gr_udc *dev; + +	list_del_init(&req->queue); + +	if (likely(req->req.status == -EINPROGRESS)) +		req->req.status = status; +	else +		status = req->req.status; + +	dev = ep->dev; +	usb_gadget_unmap_request(&dev->gadget, &req->req, ep->is_in); +	gr_free_dma_desc_chain(dev, req); + +	if (ep->is_in) /* For OUT, actual gets updated bit by bit */ +		req->req.actual = req->req.length; + +	if (!status) { +		if (ep->is_in) +			gr_dbgprint_request("SENT", ep, req); +		else +			gr_dbgprint_request("RECV", ep, req); +	} + +	/* Prevent changes to ep->queue during callback */ +	ep->callback = 1; +	if (req == dev->ep0reqo && !status) { +		if (req->setup) +			gr_ep0_setup(dev, req); +		else +			dev_err(dev->dev, +				"Unexpected non setup packet on ep0in\n"); +	} else if (req->req.complete) { +		spin_unlock(&dev->lock); + +		req->req.complete(&ep->ep, &req->req); + +		spin_lock(&dev->lock); +	} +	ep->callback = 0; +} + +static struct usb_request *gr_alloc_request(struct usb_ep *_ep, gfp_t gfp_flags) +{ +	struct gr_request *req; + +	req = kzalloc(sizeof(*req), gfp_flags); +	if (!req) +		return NULL; + +	INIT_LIST_HEAD(&req->queue); + +	return &req->req; +} + +/* + * Starts DMA for endpoint ep if there are requests in the queue. + * + * Must be called with dev->lock held and with !ep->stopped. + */ +static void gr_start_dma(struct gr_ep *ep) +{ +	struct gr_request *req; +	u32 dmactrl; + +	if (list_empty(&ep->queue)) { +		ep->dma_start = 0; +		return; +	} + +	req = list_first_entry(&ep->queue, struct gr_request, queue); + +	/* A descriptor should already have been allocated */ +	BUG_ON(!req->curr_desc); + +	wmb(); /* Make sure all is settled before handing it over to DMA */ + +	/* Set the descriptor pointer in the hardware */ +	gr_write32(&ep->regs->dmaaddr, req->curr_desc->paddr); + +	/* Announce available descriptors */ +	dmactrl = gr_read32(&ep->regs->dmactrl); +	gr_write32(&ep->regs->dmactrl, dmactrl | GR_DMACTRL_DA); + +	ep->dma_start = 1; +} + +/* + * Finishes the first request in the ep's queue and, if available, starts the + * next request in queue. + * + * Must be called with dev->lock held, irqs disabled and with !ep->stopped. + */ +static void gr_dma_advance(struct gr_ep *ep, int status) +{ +	struct gr_request *req; + +	req = list_first_entry(&ep->queue, struct gr_request, queue); +	gr_finish_request(ep, req, status); +	gr_start_dma(ep); /* Regardless of ep->dma_start */ +} + +/* + * Abort DMA for an endpoint. Sets the abort DMA bit which causes an ongoing DMA + * transfer to be canceled and clears GR_DMACTRL_DA. + * + * Must be called with dev->lock held. + */ +static void gr_abort_dma(struct gr_ep *ep) +{ +	u32 dmactrl; + +	dmactrl = gr_read32(&ep->regs->dmactrl); +	gr_write32(&ep->regs->dmactrl, dmactrl | GR_DMACTRL_AD); +} + +/* + * Allocates and sets up a struct gr_dma_desc and putting it on the descriptor + * chain. + * + * Size is not used for OUT endpoints. Hardware can not be instructed to handle + * smaller buffer than MAXPL in the OUT direction. + */ +static int gr_add_dma_desc(struct gr_ep *ep, struct gr_request *req, +			   dma_addr_t data, unsigned size, gfp_t gfp_flags) +{ +	struct gr_dma_desc *desc; + +	desc = gr_alloc_dma_desc(ep, gfp_flags); +	if (!desc) +		return -ENOMEM; + +	desc->data = data; +	if (ep->is_in) +		desc->ctrl = +			(GR_DESC_IN_CTRL_LEN_MASK & size) | GR_DESC_IN_CTRL_EN; +	else +		desc->ctrl = GR_DESC_OUT_CTRL_IE; + +	if (!req->first_desc) { +		req->first_desc = desc; +		req->curr_desc = desc; +	} else { +		req->last_desc->next_desc = desc; +		req->last_desc->next = desc->paddr; +		req->last_desc->ctrl |= GR_DESC_OUT_CTRL_NX; +	} +	req->last_desc = desc; + +	return 0; +} + +/* + * Sets up a chain of struct gr_dma_descriptors pointing to buffers that + * together covers req->req.length bytes of the buffer at DMA address + * req->req.dma for the OUT direction. + * + * The first descriptor in the chain is enabled, the rest disabled. The + * interrupt handler will later enable them one by one when needed so we can + * find out when the transfer is finished. For OUT endpoints, all descriptors + * therefore generate interrutps. + */ +static int gr_setup_out_desc_list(struct gr_ep *ep, struct gr_request *req, +				  gfp_t gfp_flags) +{ +	u16 bytes_left; /* Bytes left to provide descriptors for */ +	u16 bytes_used; /* Bytes accommodated for */ +	int ret = 0; + +	req->first_desc = NULL; /* Signals that no allocation is done yet */ +	bytes_left = req->req.length; +	bytes_used = 0; +	while (bytes_left > 0) { +		dma_addr_t start = req->req.dma + bytes_used; +		u16 size = min(bytes_left, ep->bytes_per_buffer); + +		/* Should not happen however - gr_queue stops such lengths */ +		if (size < ep->bytes_per_buffer) +			dev_warn(ep->dev->dev, +				 "Buffer overrun risk: %u < %u bytes/buffer\n", +				 size, ep->bytes_per_buffer); + +		ret = gr_add_dma_desc(ep, req, start, size, gfp_flags); +		if (ret) +			goto alloc_err; + +		bytes_left -= size; +		bytes_used += size; +	} + +	req->first_desc->ctrl |= GR_DESC_OUT_CTRL_EN; + +	return 0; + +alloc_err: +	gr_free_dma_desc_chain(ep->dev, req); + +	return ret; +} + +/* + * Sets up a chain of struct gr_dma_descriptors pointing to buffers that + * together covers req->req.length bytes of the buffer at DMA address + * req->req.dma for the IN direction. + * + * When more data is provided than the maximum payload size, the hardware splits + * this up into several payloads automatically. Moreover, ep->bytes_per_buffer + * is always set to a multiple of the maximum payload (restricted to the valid + * number of maximum payloads during high bandwidth isochronous or interrupt + * transfers) + * + * All descriptors are enabled from the beginning and we only generate an + * interrupt for the last one indicating that the entire request has been pushed + * to hardware. + */ +static int gr_setup_in_desc_list(struct gr_ep *ep, struct gr_request *req, +				 gfp_t gfp_flags) +{ +	u16 bytes_left; /* Bytes left in req to provide descriptors for */ +	u16 bytes_used; /* Bytes in req accommodated for */ +	int ret = 0; + +	req->first_desc = NULL; /* Signals that no allocation is done yet */ +	bytes_left = req->req.length; +	bytes_used = 0; +	do { /* Allow for zero length packets */ +		dma_addr_t start = req->req.dma + bytes_used; +		u16 size = min(bytes_left, ep->bytes_per_buffer); + +		ret = gr_add_dma_desc(ep, req, start, size, gfp_flags); +		if (ret) +			goto alloc_err; + +		bytes_left -= size; +		bytes_used += size; +	} while (bytes_left > 0); + +	/* +	 * Send an extra zero length packet to indicate that no more data is +	 * available when req->req.zero is set and the data length is even +	 * multiples of ep->ep.maxpacket. +	 */ +	if (req->req.zero && (req->req.length % ep->ep.maxpacket == 0)) { +		ret = gr_add_dma_desc(ep, req, 0, 0, gfp_flags); +		if (ret) +			goto alloc_err; +	} + +	/* +	 * For IN packets we only want to know when the last packet has been +	 * transmitted (not just put into internal buffers). +	 */ +	req->last_desc->ctrl |= GR_DESC_IN_CTRL_PI; + +	return 0; + +alloc_err: +	gr_free_dma_desc_chain(ep->dev, req); + +	return ret; +} + +/* Must be called with dev->lock held */ +static int gr_queue(struct gr_ep *ep, struct gr_request *req, gfp_t gfp_flags) +{ +	struct gr_udc *dev = ep->dev; +	int ret; + +	if (unlikely(!ep->ep.desc && ep->num != 0)) { +		dev_err(dev->dev, "No ep descriptor for %s\n", ep->ep.name); +		return -EINVAL; +	} + +	if (unlikely(!req->req.buf || !list_empty(&req->queue))) { +		dev_err(dev->dev, +			"Invalid request for %s: buf=%p list_empty=%d\n", +			ep->ep.name, req->req.buf, list_empty(&req->queue)); +		return -EINVAL; +	} + +	/* +	 * The DMA controller can not handle smaller OUT buffers than +	 * maxpacket. It could lead to buffer overruns if unexpectedly long +	 * packet are received. +	 */ +	if (!ep->is_in && (req->req.length % ep->ep.maxpacket) != 0) { +		dev_err(dev->dev, +			"OUT request length %d is not multiple of maxpacket\n", +			req->req.length); +		return -EMSGSIZE; +	} + +	if (unlikely(!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN)) { +		dev_err(dev->dev, "-ESHUTDOWN"); +		return -ESHUTDOWN; +	} + +	/* Can't touch registers when suspended */ +	if (dev->ep0state == GR_EP0_SUSPEND) { +		dev_err(dev->dev, "-EBUSY"); +		return -EBUSY; +	} + +	/* Set up DMA mapping in case the caller didn't */ +	ret = usb_gadget_map_request(&dev->gadget, &req->req, ep->is_in); +	if (ret) { +		dev_err(dev->dev, "usb_gadget_map_request"); +		return ret; +	} + +	if (ep->is_in) +		ret = gr_setup_in_desc_list(ep, req, gfp_flags); +	else +		ret = gr_setup_out_desc_list(ep, req, gfp_flags); +	if (ret) +		return ret; + +	req->req.status = -EINPROGRESS; +	req->req.actual = 0; +	list_add_tail(&req->queue, &ep->queue); + +	/* Start DMA if not started, otherwise interrupt handler handles it */ +	if (!ep->dma_start && likely(!ep->stopped)) +		gr_start_dma(ep); + +	return 0; +} + +/* + * Queue a request from within the driver. + * + * Must be called with dev->lock held. + */ +static inline int gr_queue_int(struct gr_ep *ep, struct gr_request *req, +			       gfp_t gfp_flags) +{ +	if (ep->is_in) +		gr_dbgprint_request("RESP", ep, req); + +	return gr_queue(ep, req, gfp_flags); +} + +/* ---------------------------------------------------------------------- */ +/* General helper functions */ + +/* + * Dequeue ALL requests. + * + * Must be called with dev->lock held and irqs disabled. + */ +static void gr_ep_nuke(struct gr_ep *ep) +{ +	struct gr_request *req; + +	ep->stopped = 1; +	ep->dma_start = 0; +	gr_abort_dma(ep); + +	while (!list_empty(&ep->queue)) { +		req = list_first_entry(&ep->queue, struct gr_request, queue); +		gr_finish_request(ep, req, -ESHUTDOWN); +	} +} + +/* + * Reset the hardware state of this endpoint. + * + * Must be called with dev->lock held. + */ +static void gr_ep_reset(struct gr_ep *ep) +{ +	gr_write32(&ep->regs->epctrl, 0); +	gr_write32(&ep->regs->dmactrl, 0); + +	ep->ep.maxpacket = MAX_CTRL_PL_SIZE; +	ep->ep.desc = NULL; +	ep->stopped = 1; +	ep->dma_start = 0; +} + +/* + * Generate STALL on ep0in/out. + * + * Must be called with dev->lock held. + */ +static void gr_control_stall(struct gr_udc *dev) +{ +	u32 epctrl; + +	epctrl = gr_read32(&dev->epo[0].regs->epctrl); +	gr_write32(&dev->epo[0].regs->epctrl, epctrl | GR_EPCTRL_CS); +	epctrl = gr_read32(&dev->epi[0].regs->epctrl); +	gr_write32(&dev->epi[0].regs->epctrl, epctrl | GR_EPCTRL_CS); + +	dev->ep0state = GR_EP0_STALL; +} + +/* + * Halts, halts and wedges, or clears halt for an endpoint. + * + * Must be called with dev->lock held. + */ +static int gr_ep_halt_wedge(struct gr_ep *ep, int halt, int wedge, int fromhost) +{ +	u32 epctrl; +	int retval = 0; + +	if (ep->num && !ep->ep.desc) +		return -EINVAL; + +	if (ep->num && ep->ep.desc->bmAttributes == USB_ENDPOINT_XFER_ISOC) +		return -EOPNOTSUPP; + +	/* Never actually halt ep0, and therefore never clear halt for ep0 */ +	if (!ep->num) { +		if (halt && !fromhost) { +			/* ep0 halt from gadget - generate protocol stall */ +			gr_control_stall(ep->dev); +			dev_dbg(ep->dev->dev, "EP: stall ep0\n"); +			return 0; +		} +		return -EINVAL; +	} + +	dev_dbg(ep->dev->dev, "EP: %s halt %s\n", +		(halt ? (wedge ? "wedge" : "set") : "clear"), ep->ep.name); + +	epctrl = gr_read32(&ep->regs->epctrl); +	if (halt) { +		/* Set HALT */ +		gr_write32(&ep->regs->epctrl, epctrl | GR_EPCTRL_EH); +		ep->stopped = 1; +		if (wedge) +			ep->wedged = 1; +	} else { +		gr_write32(&ep->regs->epctrl, epctrl & ~GR_EPCTRL_EH); +		ep->stopped = 0; +		ep->wedged = 0; + +		/* Things might have been queued up in the meantime */ +		if (!ep->dma_start) +			gr_start_dma(ep); +	} + +	return retval; +} + +/* Must be called with dev->lock held */ +static inline void gr_set_ep0state(struct gr_udc *dev, enum gr_ep0state value) +{ +	if (dev->ep0state != value) +		dev_vdbg(dev->dev, "STATE:  ep0state=%s\n", +			 gr_ep0state_string(value)); +	dev->ep0state = value; +} + +/* + * Should only be called when endpoints can not generate interrupts. + * + * Must be called with dev->lock held. + */ +static void gr_disable_interrupts_and_pullup(struct gr_udc *dev) +{ +	gr_write32(&dev->regs->control, 0); +	wmb(); /* Make sure that we do not deny one of our interrupts */ +	dev->irq_enabled = 0; +} + +/* + * Stop all device activity and disable data line pullup. + * + * Must be called with dev->lock held and irqs disabled. + */ +static void gr_stop_activity(struct gr_udc *dev) +{ +	struct gr_ep *ep; + +	list_for_each_entry(ep, &dev->ep_list, ep_list) +		gr_ep_nuke(ep); + +	gr_disable_interrupts_and_pullup(dev); + +	gr_set_ep0state(dev, GR_EP0_DISCONNECT); +	usb_gadget_set_state(&dev->gadget, USB_STATE_NOTATTACHED); +} + +/* ---------------------------------------------------------------------- */ +/* ep0 setup packet handling */ + +static void gr_ep0_testmode_complete(struct usb_ep *_ep, +				     struct usb_request *_req) +{ +	struct gr_ep *ep; +	struct gr_udc *dev; +	u32 control; + +	ep = container_of(_ep, struct gr_ep, ep); +	dev = ep->dev; + +	spin_lock(&dev->lock); + +	control = gr_read32(&dev->regs->control); +	control |= GR_CONTROL_TM | (dev->test_mode << GR_CONTROL_TS_POS); +	gr_write32(&dev->regs->control, control); + +	spin_unlock(&dev->lock); +} + +static void gr_ep0_dummy_complete(struct usb_ep *_ep, struct usb_request *_req) +{ +	/* Nothing needs to be done here */ +} + +/* + * Queue a response on ep0in. + * + * Must be called with dev->lock held. + */ +static int gr_ep0_respond(struct gr_udc *dev, u8 *buf, int length, +			  void (*complete)(struct usb_ep *ep, +					   struct usb_request *req)) +{ +	u8 *reqbuf = dev->ep0reqi->req.buf; +	int status; +	int i; + +	for (i = 0; i < length; i++) +		reqbuf[i] = buf[i]; +	dev->ep0reqi->req.length = length; +	dev->ep0reqi->req.complete = complete; + +	status = gr_queue_int(&dev->epi[0], dev->ep0reqi, GFP_ATOMIC); +	if (status < 0) +		dev_err(dev->dev, +			"Could not queue ep0in setup response: %d\n", status); + +	return status; +} + +/* + * Queue a 2 byte response on ep0in. + * + * Must be called with dev->lock held. + */ +static inline int gr_ep0_respond_u16(struct gr_udc *dev, u16 response) +{ +	__le16 le_response = cpu_to_le16(response); + +	return gr_ep0_respond(dev, (u8 *)&le_response, 2, +			      gr_ep0_dummy_complete); +} + +/* + * Queue a ZLP response on ep0in. + * + * Must be called with dev->lock held. + */ +static inline int gr_ep0_respond_empty(struct gr_udc *dev) +{ +	return gr_ep0_respond(dev, NULL, 0, gr_ep0_dummy_complete); +} + +/* + * This is run when a SET_ADDRESS request is received. First writes + * the new address to the control register which is updated internally + * when the next IN packet is ACKED. + * + * Must be called with dev->lock held. + */ +static void gr_set_address(struct gr_udc *dev, u8 address) +{ +	u32 control; + +	control = gr_read32(&dev->regs->control) & ~GR_CONTROL_UA_MASK; +	control |= (address << GR_CONTROL_UA_POS) & GR_CONTROL_UA_MASK; +	control |= GR_CONTROL_SU; +	gr_write32(&dev->regs->control, control); +} + +/* + * Returns negative for STALL, 0 for successful handling and positive for + * delegation. + * + * Must be called with dev->lock held. + */ +static int gr_device_request(struct gr_udc *dev, u8 type, u8 request, +			     u16 value, u16 index) +{ +	u16 response; +	u8 test; + +	switch (request) { +	case USB_REQ_SET_ADDRESS: +		dev_dbg(dev->dev, "STATUS: address %d\n", value & 0xff); +		gr_set_address(dev, value & 0xff); +		if (value) +			usb_gadget_set_state(&dev->gadget, USB_STATE_ADDRESS); +		else +			usb_gadget_set_state(&dev->gadget, USB_STATE_DEFAULT); +		return gr_ep0_respond_empty(dev); + +	case USB_REQ_GET_STATUS: +		/* Self powered | remote wakeup */ +		response = 0x0001 | (dev->remote_wakeup ? 0x0002 : 0); +		return gr_ep0_respond_u16(dev, response); + +	case USB_REQ_SET_FEATURE: +		switch (value) { +		case USB_DEVICE_REMOTE_WAKEUP: +			/* Allow remote wakeup */ +			dev->remote_wakeup = 1; +			return gr_ep0_respond_empty(dev); + +		case USB_DEVICE_TEST_MODE: +			/* The hardware does not support TEST_FORCE_EN */ +			test = index >> 8; +			if (test >= TEST_J && test <= TEST_PACKET) { +				dev->test_mode = test; +				return gr_ep0_respond(dev, NULL, 0, +						      gr_ep0_testmode_complete); +			} +		} +		break; + +	case USB_REQ_CLEAR_FEATURE: +		switch (value) { +		case USB_DEVICE_REMOTE_WAKEUP: +			/* Disallow remote wakeup */ +			dev->remote_wakeup = 0; +			return gr_ep0_respond_empty(dev); +		} +		break; +	} + +	return 1; /* Delegate the rest */ +} + +/* + * Returns negative for STALL, 0 for successful handling and positive for + * delegation. + * + * Must be called with dev->lock held. + */ +static int gr_interface_request(struct gr_udc *dev, u8 type, u8 request, +				u16 value, u16 index) +{ +	if (dev->gadget.state != USB_STATE_CONFIGURED) +		return -1; + +	/* +	 * Should return STALL for invalid interfaces, but udc driver does not +	 * know anything about that. However, many gadget drivers do not handle +	 * GET_STATUS so we need to take care of that. +	 */ + +	switch (request) { +	case USB_REQ_GET_STATUS: +		return gr_ep0_respond_u16(dev, 0x0000); + +	case USB_REQ_SET_FEATURE: +	case USB_REQ_CLEAR_FEATURE: +		/* +		 * No possible valid standard requests. Still let gadget drivers +		 * have a go at it. +		 */ +		break; +	} + +	return 1; /* Delegate the rest */ +} + +/* + * Returns negative for STALL, 0 for successful handling and positive for + * delegation. + * + * Must be called with dev->lock held. + */ +static int gr_endpoint_request(struct gr_udc *dev, u8 type, u8 request, +			       u16 value, u16 index) +{ +	struct gr_ep *ep; +	int status; +	int halted; +	u8 epnum = index & USB_ENDPOINT_NUMBER_MASK; +	u8 is_in = index & USB_ENDPOINT_DIR_MASK; + +	if ((is_in && epnum >= dev->nepi) || (!is_in && epnum >= dev->nepo)) +		return -1; + +	if (dev->gadget.state != USB_STATE_CONFIGURED && epnum != 0) +		return -1; + +	ep = (is_in ? &dev->epi[epnum] : &dev->epo[epnum]); + +	switch (request) { +	case USB_REQ_GET_STATUS: +		halted = gr_read32(&ep->regs->epctrl) & GR_EPCTRL_EH; +		return gr_ep0_respond_u16(dev, halted ? 0x0001 : 0); + +	case USB_REQ_SET_FEATURE: +		switch (value) { +		case USB_ENDPOINT_HALT: +			status = gr_ep_halt_wedge(ep, 1, 0, 1); +			if (status >= 0) +				status = gr_ep0_respond_empty(dev); +			return status; +		} +		break; + +	case USB_REQ_CLEAR_FEATURE: +		switch (value) { +		case USB_ENDPOINT_HALT: +			if (ep->wedged) +				return -1; +			status = gr_ep_halt_wedge(ep, 0, 0, 1); +			if (status >= 0) +				status = gr_ep0_respond_empty(dev); +			return status; +		} +		break; +	} + +	return 1; /* Delegate the rest */ +} + +/* Must be called with dev->lock held */ +static void gr_ep0out_requeue(struct gr_udc *dev) +{ +	int ret = gr_queue_int(&dev->epo[0], dev->ep0reqo, GFP_ATOMIC); + +	if (ret) +		dev_err(dev->dev, "Could not queue ep0out setup request: %d\n", +			ret); +} + +/* + * The main function dealing with setup requests on ep0. + * + * Must be called with dev->lock held and irqs disabled + */ +static void gr_ep0_setup(struct gr_udc *dev, struct gr_request *req) +	__releases(&dev->lock) +	__acquires(&dev->lock) +{ +	union { +		struct usb_ctrlrequest ctrl; +		u8 raw[8]; +		u32 word[2]; +	} u; +	u8 type; +	u8 request; +	u16 value; +	u16 index; +	u16 length; +	int i; +	int status; + +	/* Restore from ep0 halt */ +	if (dev->ep0state == GR_EP0_STALL) { +		gr_set_ep0state(dev, GR_EP0_SETUP); +		if (!req->req.actual) +			goto out; +	} + +	if (dev->ep0state == GR_EP0_ISTATUS) { +		gr_set_ep0state(dev, GR_EP0_SETUP); +		if (req->req.actual > 0) +			dev_dbg(dev->dev, +				"Unexpected setup packet at state %s\n", +				gr_ep0state_string(GR_EP0_ISTATUS)); +		else +			goto out; /* Got expected ZLP */ +	} else if (dev->ep0state != GR_EP0_SETUP) { +		dev_info(dev->dev, +			 "Unexpected ep0out request at state %s - stalling\n", +			 gr_ep0state_string(dev->ep0state)); +		gr_control_stall(dev); +		gr_set_ep0state(dev, GR_EP0_SETUP); +		goto out; +	} else if (!req->req.actual) { +		dev_dbg(dev->dev, "Unexpected ZLP at state %s\n", +			gr_ep0state_string(dev->ep0state)); +		goto out; +	} + +	/* Handle SETUP packet */ +	for (i = 0; i < req->req.actual; i++) +		u.raw[i] = ((u8 *)req->req.buf)[i]; + +	type = u.ctrl.bRequestType; +	request = u.ctrl.bRequest; +	value = le16_to_cpu(u.ctrl.wValue); +	index = le16_to_cpu(u.ctrl.wIndex); +	length = le16_to_cpu(u.ctrl.wLength); + +	gr_dbgprint_devreq(dev, type, request, value, index, length); + +	/* Check for data stage */ +	if (length) { +		if (type & USB_DIR_IN) +			gr_set_ep0state(dev, GR_EP0_IDATA); +		else +			gr_set_ep0state(dev, GR_EP0_ODATA); +	} + +	status = 1; /* Positive status flags delegation */ +	if ((type & USB_TYPE_MASK) == USB_TYPE_STANDARD) { +		switch (type & USB_RECIP_MASK) { +		case USB_RECIP_DEVICE: +			status = gr_device_request(dev, type, request, +						   value, index); +			break; +		case USB_RECIP_ENDPOINT: +			status =  gr_endpoint_request(dev, type, request, +						      value, index); +			break; +		case USB_RECIP_INTERFACE: +			status = gr_interface_request(dev, type, request, +						      value, index); +			break; +		} +	} + +	if (status > 0) { +		spin_unlock(&dev->lock); + +		dev_vdbg(dev->dev, "DELEGATE\n"); +		status = dev->driver->setup(&dev->gadget, &u.ctrl); + +		spin_lock(&dev->lock); +	} + +	/* Generate STALL on both ep0out and ep0in if requested */ +	if (unlikely(status < 0)) { +		dev_vdbg(dev->dev, "STALL\n"); +		gr_control_stall(dev); +	} + +	if ((type & USB_TYPE_MASK) == USB_TYPE_STANDARD && +	    request == USB_REQ_SET_CONFIGURATION) { +		if (!value) { +			dev_dbg(dev->dev, "STATUS: deconfigured\n"); +			usb_gadget_set_state(&dev->gadget, USB_STATE_ADDRESS); +		} else if (status >= 0) { +			/* Not configured unless gadget OK:s it */ +			dev_dbg(dev->dev, "STATUS: configured: %d\n", value); +			usb_gadget_set_state(&dev->gadget, +					     USB_STATE_CONFIGURED); +		} +	} + +	/* Get ready for next stage */ +	if (dev->ep0state == GR_EP0_ODATA) +		gr_set_ep0state(dev, GR_EP0_OSTATUS); +	else if (dev->ep0state == GR_EP0_IDATA) +		gr_set_ep0state(dev, GR_EP0_ISTATUS); +	else +		gr_set_ep0state(dev, GR_EP0_SETUP); + +out: +	gr_ep0out_requeue(dev); +} + +/* ---------------------------------------------------------------------- */ +/* VBUS and USB reset handling */ + +/* Must be called with dev->lock held and irqs disabled  */ +static void gr_vbus_connected(struct gr_udc *dev, u32 status) +{ +	u32 control; + +	dev->gadget.speed = GR_SPEED(status); +	usb_gadget_set_state(&dev->gadget, USB_STATE_POWERED); + +	/* Turn on full interrupts and pullup */ +	control = (GR_CONTROL_SI | GR_CONTROL_UI | GR_CONTROL_VI | +		   GR_CONTROL_SP | GR_CONTROL_EP); +	gr_write32(&dev->regs->control, control); +} + +/* Must be called with dev->lock held */ +static void gr_enable_vbus_detect(struct gr_udc *dev) +{ +	u32 status; + +	dev->irq_enabled = 1; +	wmb(); /* Make sure we do not ignore an interrupt */ +	gr_write32(&dev->regs->control, GR_CONTROL_VI); + +	/* Take care of the case we are already plugged in at this point */ +	status = gr_read32(&dev->regs->status); +	if (status & GR_STATUS_VB) +		gr_vbus_connected(dev, status); +} + +/* Must be called with dev->lock held and irqs disabled */ +static void gr_vbus_disconnected(struct gr_udc *dev) +{ +	gr_stop_activity(dev); + +	/* Report disconnect */ +	if (dev->driver && dev->driver->disconnect) { +		spin_unlock(&dev->lock); + +		dev->driver->disconnect(&dev->gadget); + +		spin_lock(&dev->lock); +	} + +	gr_enable_vbus_detect(dev); +} + +/* Must be called with dev->lock held and irqs disabled */ +static void gr_udc_usbreset(struct gr_udc *dev, u32 status) +{ +	gr_set_address(dev, 0); +	gr_set_ep0state(dev, GR_EP0_SETUP); +	usb_gadget_set_state(&dev->gadget, USB_STATE_DEFAULT); +	dev->gadget.speed = GR_SPEED(status); + +	gr_ep_nuke(&dev->epo[0]); +	gr_ep_nuke(&dev->epi[0]); +	dev->epo[0].stopped = 0; +	dev->epi[0].stopped = 0; +	gr_ep0out_requeue(dev); +} + +/* ---------------------------------------------------------------------- */ +/* Irq handling */ + +/* + * Handles interrupts from in endpoints. Returns whether something was handled. + * + * Must be called with dev->lock held, irqs disabled and with !ep->stopped. + */ +static int gr_handle_in_ep(struct gr_ep *ep) +{ +	struct gr_request *req; + +	req = list_first_entry(&ep->queue, struct gr_request, queue); +	if (!req->last_desc) +		return 0; + +	if (ACCESS_ONCE(req->last_desc->ctrl) & GR_DESC_IN_CTRL_EN) +		return 0; /* Not put in hardware buffers yet */ + +	if (gr_read32(&ep->regs->epstat) & (GR_EPSTAT_B1 | GR_EPSTAT_B0)) +		return 0; /* Not transmitted yet, still in hardware buffers */ + +	/* Write complete */ +	gr_dma_advance(ep, 0); + +	return 1; +} + +/* + * Handles interrupts from out endpoints. Returns whether something was handled. + * + * Must be called with dev->lock held, irqs disabled and with !ep->stopped. + */ +static int gr_handle_out_ep(struct gr_ep *ep) +{ +	u32 ep_dmactrl; +	u32 ctrl; +	u16 len; +	struct gr_request *req; +	struct gr_udc *dev = ep->dev; + +	req = list_first_entry(&ep->queue, struct gr_request, queue); +	if (!req->curr_desc) +		return 0; + +	ctrl = ACCESS_ONCE(req->curr_desc->ctrl); +	if (ctrl & GR_DESC_OUT_CTRL_EN) +		return 0; /* Not received yet */ + +	/* Read complete */ +	len = ctrl & GR_DESC_OUT_CTRL_LEN_MASK; +	req->req.actual += len; +	if (ctrl & GR_DESC_OUT_CTRL_SE) +		req->setup = 1; + +	if (len < ep->ep.maxpacket || req->req.actual == req->req.length) { +		/* Short packet or the expected size - we are done */ + +		if ((ep == &dev->epo[0]) && (dev->ep0state == GR_EP0_OSTATUS)) { +			/* +			 * Send a status stage ZLP to ack the DATA stage in the +			 * OUT direction. This needs to be done before +			 * gr_dma_advance as that can lead to a call to +			 * ep0_setup that can change dev->ep0state. +			 */ +			gr_ep0_respond_empty(dev); +			gr_set_ep0state(dev, GR_EP0_SETUP); +		} + +		gr_dma_advance(ep, 0); +	} else { +		/* Not done yet. Enable the next descriptor to receive more. */ +		req->curr_desc = req->curr_desc->next_desc; +		req->curr_desc->ctrl |= GR_DESC_OUT_CTRL_EN; + +		ep_dmactrl = gr_read32(&ep->regs->dmactrl); +		gr_write32(&ep->regs->dmactrl, ep_dmactrl | GR_DMACTRL_DA); +	} + +	return 1; +} + +/* + * Handle state changes. Returns whether something was handled. + * + * Must be called with dev->lock held and irqs disabled. + */ +static int gr_handle_state_changes(struct gr_udc *dev) +{ +	u32 status = gr_read32(&dev->regs->status); +	int handled = 0; +	int powstate = !(dev->gadget.state == USB_STATE_NOTATTACHED || +			 dev->gadget.state == USB_STATE_ATTACHED); + +	/* VBUS valid detected */ +	if (!powstate && (status & GR_STATUS_VB)) { +		dev_dbg(dev->dev, "STATUS: vbus valid detected\n"); +		gr_vbus_connected(dev, status); +		handled = 1; +	} + +	/* Disconnect */ +	if (powstate && !(status & GR_STATUS_VB)) { +		dev_dbg(dev->dev, "STATUS: vbus invalid detected\n"); +		gr_vbus_disconnected(dev); +		handled = 1; +	} + +	/* USB reset detected */ +	if (status & GR_STATUS_UR) { +		dev_dbg(dev->dev, "STATUS: USB reset - speed is %s\n", +			GR_SPEED_STR(status)); +		gr_write32(&dev->regs->status, GR_STATUS_UR); +		gr_udc_usbreset(dev, status); +		handled = 1; +	} + +	/* Speed change */ +	if (dev->gadget.speed != GR_SPEED(status)) { +		dev_dbg(dev->dev, "STATUS: USB Speed change to %s\n", +			GR_SPEED_STR(status)); +		dev->gadget.speed = GR_SPEED(status); +		handled = 1; +	} + +	/* Going into suspend */ +	if ((dev->ep0state != GR_EP0_SUSPEND) && !(status & GR_STATUS_SU)) { +		dev_dbg(dev->dev, "STATUS: USB suspend\n"); +		gr_set_ep0state(dev, GR_EP0_SUSPEND); +		dev->suspended_from = dev->gadget.state; +		usb_gadget_set_state(&dev->gadget, USB_STATE_SUSPENDED); + +		if ((dev->gadget.speed != USB_SPEED_UNKNOWN) && +		    dev->driver && dev->driver->suspend) { +			spin_unlock(&dev->lock); + +			dev->driver->suspend(&dev->gadget); + +			spin_lock(&dev->lock); +		} +		handled = 1; +	} + +	/* Coming out of suspend */ +	if ((dev->ep0state == GR_EP0_SUSPEND) && (status & GR_STATUS_SU)) { +		dev_dbg(dev->dev, "STATUS: USB resume\n"); +		if (dev->suspended_from == USB_STATE_POWERED) +			gr_set_ep0state(dev, GR_EP0_DISCONNECT); +		else +			gr_set_ep0state(dev, GR_EP0_SETUP); +		usb_gadget_set_state(&dev->gadget, dev->suspended_from); + +		if ((dev->gadget.speed != USB_SPEED_UNKNOWN) && +		    dev->driver && dev->driver->resume) { +			spin_unlock(&dev->lock); + +			dev->driver->resume(&dev->gadget); + +			spin_lock(&dev->lock); +		} +		handled = 1; +	} + +	return handled; +} + +/* Non-interrupt context irq handler */ +static irqreturn_t gr_irq_handler(int irq, void *_dev) +{ +	struct gr_udc *dev = _dev; +	struct gr_ep *ep; +	int handled = 0; +	int i; +	unsigned long flags; + +	spin_lock_irqsave(&dev->lock, flags); + +	if (!dev->irq_enabled) +		goto out; + +	/* +	 * Check IN ep interrupts. We check these before the OUT eps because +	 * some gadgets reuse the request that might already be currently +	 * outstanding and needs to be completed (mainly setup requests). +	 */ +	for (i = 0; i < dev->nepi; i++) { +		ep = &dev->epi[i]; +		if (!ep->stopped && !ep->callback && !list_empty(&ep->queue)) +			handled = gr_handle_in_ep(ep) || handled; +	} + +	/* Check OUT ep interrupts */ +	for (i = 0; i < dev->nepo; i++) { +		ep = &dev->epo[i]; +		if (!ep->stopped && !ep->callback && !list_empty(&ep->queue)) +			handled = gr_handle_out_ep(ep) || handled; +	} + +	/* Check status interrupts */ +	handled = gr_handle_state_changes(dev) || handled; + +	/* +	 * Check AMBA DMA errors. Only check if we didn't find anything else to +	 * handle because this shouldn't happen if we did everything right. +	 */ +	if (!handled) { +		list_for_each_entry(ep, &dev->ep_list, ep_list) { +			if (gr_read32(&ep->regs->dmactrl) & GR_DMACTRL_AE) { +				dev_err(dev->dev, +					"AMBA Error occurred for %s\n", +					ep->ep.name); +				handled = 1; +			} +		} +	} + +out: +	spin_unlock_irqrestore(&dev->lock, flags); + +	return handled ? IRQ_HANDLED : IRQ_NONE; +} + +/* Interrupt context irq handler */ +static irqreturn_t gr_irq(int irq, void *_dev) +{ +	struct gr_udc *dev = _dev; + +	if (!dev->irq_enabled) +		return IRQ_NONE; + +	return IRQ_WAKE_THREAD; +} + +/* ---------------------------------------------------------------------- */ +/* USB ep ops */ + +/* Enable endpoint. Not for ep0in and ep0out that are handled separately. */ +static int gr_ep_enable(struct usb_ep *_ep, +			const struct usb_endpoint_descriptor *desc) +{ +	struct gr_udc *dev; +	struct gr_ep *ep; +	u8 mode; +	u8 nt; +	u16 max; +	u16 buffer_size = 0; +	u32 epctrl; + +	ep = container_of(_ep, struct gr_ep, ep); +	if (!_ep || !desc || desc->bDescriptorType != USB_DT_ENDPOINT) +		return -EINVAL; + +	dev = ep->dev; + +	/* 'ep0' IN and OUT are reserved */ +	if (ep == &dev->epo[0] || ep == &dev->epi[0]) +		return -EINVAL; + +	if (!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN) +		return -ESHUTDOWN; + +	/* Make sure we are clear for enabling */ +	epctrl = gr_read32(&ep->regs->epctrl); +	if (epctrl & GR_EPCTRL_EV) +		return -EBUSY; + +	/* Check that directions match */ +	if (!ep->is_in != !usb_endpoint_dir_in(desc)) +		return -EINVAL; + +	/* Check ep num */ +	if ((!ep->is_in && ep->num >= dev->nepo) || +	    (ep->is_in && ep->num >= dev->nepi)) +		return -EINVAL; + +	if (usb_endpoint_xfer_control(desc)) { +		mode = 0; +	} else if (usb_endpoint_xfer_isoc(desc)) { +		mode = 1; +	} else if (usb_endpoint_xfer_bulk(desc)) { +		mode = 2; +	} else if (usb_endpoint_xfer_int(desc)) { +		mode = 3; +	} else { +		dev_err(dev->dev, "Unknown transfer type for %s\n", +			ep->ep.name); +		return -EINVAL; +	} + +	/* +	 * Bits 10-0 set the max payload. 12-11 set the number of +	 * additional transactions. +	 */ +	max = 0x7ff & usb_endpoint_maxp(desc); +	nt = 0x3 & (usb_endpoint_maxp(desc) >> 11); +	buffer_size = GR_BUFFER_SIZE(epctrl); +	if (nt && (mode == 0 || mode == 2)) { +		dev_err(dev->dev, +			"%s mode: multiple trans./microframe not valid\n", +			(mode == 2 ? "Bulk" : "Control")); +		return -EINVAL; +	} else if (nt == 0x3) { +		dev_err(dev->dev, +			"Invalid value 0x3 for additional trans./microframe\n"); +		return -EINVAL; +	} else if ((nt + 1) * max > buffer_size) { +		dev_err(dev->dev, "Hw buffer size %d < max payload %d * %d\n", +			buffer_size, (nt + 1), max); +		return -EINVAL; +	} else if (max == 0) { +		dev_err(dev->dev, "Max payload cannot be set to 0\n"); +		return -EINVAL; +	} else if (max > ep->ep.maxpacket_limit) { +		dev_err(dev->dev, "Requested max payload %d > limit %d\n", +			max, ep->ep.maxpacket_limit); +		return -EINVAL; +	} + +	spin_lock(&ep->dev->lock); + +	if (!ep->stopped) { +		spin_unlock(&ep->dev->lock); +		return -EBUSY; +	} + +	ep->stopped = 0; +	ep->wedged = 0; +	ep->ep.desc = desc; +	ep->ep.maxpacket = max; +	ep->dma_start = 0; + + +	if (nt) { +		/* +		 * Maximum possible size of all payloads in one microframe +		 * regardless of direction when using high-bandwidth mode. +		 */ +		ep->bytes_per_buffer = (nt + 1) * max; +	} else if (ep->is_in) { +		/* +		 * The biggest multiple of maximum packet size that fits into +		 * the buffer. The hardware will split up into many packets in +		 * the IN direction. +		 */ +		ep->bytes_per_buffer = (buffer_size / max) * max; +	} else { +		/* +		 * Only single packets will be placed the buffers in the OUT +		 * direction. +		 */ +		ep->bytes_per_buffer = max; +	} + +	epctrl = (max << GR_EPCTRL_MAXPL_POS) +		| (nt << GR_EPCTRL_NT_POS) +		| (mode << GR_EPCTRL_TT_POS) +		| GR_EPCTRL_EV; +	if (ep->is_in) +		epctrl |= GR_EPCTRL_PI; +	gr_write32(&ep->regs->epctrl, epctrl); + +	gr_write32(&ep->regs->dmactrl, GR_DMACTRL_IE | GR_DMACTRL_AI); + +	spin_unlock(&ep->dev->lock); + +	dev_dbg(ep->dev->dev, "EP: %s enabled - %s with %d bytes/buffer\n", +		ep->ep.name, gr_modestring[mode], ep->bytes_per_buffer); +	return 0; +} + +/* Disable endpoint. Not for ep0in and ep0out that are handled separately. */ +static int gr_ep_disable(struct usb_ep *_ep) +{ +	struct gr_ep *ep; +	struct gr_udc *dev; +	unsigned long flags; + +	ep = container_of(_ep, struct gr_ep, ep); +	if (!_ep || !ep->ep.desc) +		return -ENODEV; + +	dev = ep->dev; + +	/* 'ep0' IN and OUT are reserved */ +	if (ep == &dev->epo[0] || ep == &dev->epi[0]) +		return -EINVAL; + +	if (dev->ep0state == GR_EP0_SUSPEND) +		return -EBUSY; + +	dev_dbg(ep->dev->dev, "EP: disable %s\n", ep->ep.name); + +	spin_lock_irqsave(&dev->lock, flags); + +	gr_ep_nuke(ep); +	gr_ep_reset(ep); +	ep->ep.desc = NULL; + +	spin_unlock_irqrestore(&dev->lock, flags); + +	return 0; +} + +/* + * Frees a request, but not any DMA buffers associated with it + * (gr_finish_request should already have taken care of that). + */ +static void gr_free_request(struct usb_ep *_ep, struct usb_request *_req) +{ +	struct gr_request *req; + +	if (!_ep || !_req) +		return; +	req = container_of(_req, struct gr_request, req); + +	/* Leads to memory leak */ +	WARN(!list_empty(&req->queue), +	     "request not dequeued properly before freeing\n"); + +	kfree(req); +} + +/* Queue a request from the gadget */ +static int gr_queue_ext(struct usb_ep *_ep, struct usb_request *_req, +			gfp_t gfp_flags) +{ +	struct gr_ep *ep; +	struct gr_request *req; +	struct gr_udc *dev; +	int ret; + +	if (unlikely(!_ep || !_req)) +		return -EINVAL; + +	ep = container_of(_ep, struct gr_ep, ep); +	req = container_of(_req, struct gr_request, req); +	dev = ep->dev; + +	spin_lock(&ep->dev->lock); + +	/* +	 * The ep0 pointer in the gadget struct is used both for ep0in and +	 * ep0out. In a data stage in the out direction ep0out needs to be used +	 * instead of the default ep0in. Completion functions might use +	 * driver_data, so that needs to be copied as well. +	 */ +	if ((ep == &dev->epi[0]) && (dev->ep0state == GR_EP0_ODATA)) { +		ep = &dev->epo[0]; +		ep->ep.driver_data = dev->epi[0].ep.driver_data; +	} + +	if (ep->is_in) +		gr_dbgprint_request("EXTERN", ep, req); + +	ret = gr_queue(ep, req, GFP_ATOMIC); + +	spin_unlock(&ep->dev->lock); + +	return ret; +} + +/* Dequeue JUST ONE request */ +static int gr_dequeue(struct usb_ep *_ep, struct usb_request *_req) +{ +	struct gr_request *req; +	struct gr_ep *ep; +	struct gr_udc *dev; +	int ret = 0; +	unsigned long flags; + +	ep = container_of(_ep, struct gr_ep, ep); +	if (!_ep || !_req || (!ep->ep.desc && ep->num != 0)) +		return -EINVAL; +	dev = ep->dev; +	if (!dev->driver) +		return -ESHUTDOWN; + +	/* We can't touch (DMA) registers when suspended */ +	if (dev->ep0state == GR_EP0_SUSPEND) +		return -EBUSY; + +	spin_lock_irqsave(&dev->lock, flags); + +	/* Make sure it's actually queued on this endpoint */ +	list_for_each_entry(req, &ep->queue, queue) { +		if (&req->req == _req) +			break; +	} +	if (&req->req != _req) { +		ret = -EINVAL; +		goto out; +	} + +	if (list_first_entry(&ep->queue, struct gr_request, queue) == req) { +		/* This request is currently being processed */ +		gr_abort_dma(ep); +		if (ep->stopped) +			gr_finish_request(ep, req, -ECONNRESET); +		else +			gr_dma_advance(ep, -ECONNRESET); +	} else if (!list_empty(&req->queue)) { +		/* Not being processed - gr_finish_request dequeues it */ +		gr_finish_request(ep, req, -ECONNRESET); +	} else { +		ret = -EOPNOTSUPP; +	} + +out: +	spin_unlock_irqrestore(&dev->lock, flags); + +	return ret; +} + +/* Helper for gr_set_halt and gr_set_wedge */ +static int gr_set_halt_wedge(struct usb_ep *_ep, int halt, int wedge) +{ +	int ret; +	struct gr_ep *ep; + +	if (!_ep) +		return -ENODEV; +	ep = container_of(_ep, struct gr_ep, ep); + +	spin_lock(&ep->dev->lock); + +	/* Halting an IN endpoint should fail if queue is not empty */ +	if (halt && ep->is_in && !list_empty(&ep->queue)) { +		ret = -EAGAIN; +		goto out; +	} + +	ret = gr_ep_halt_wedge(ep, halt, wedge, 0); + +out: +	spin_unlock(&ep->dev->lock); + +	return ret; +} + +/* Halt endpoint */ +static int gr_set_halt(struct usb_ep *_ep, int halt) +{ +	return gr_set_halt_wedge(_ep, halt, 0); +} + +/* Halt and wedge endpoint */ +static int gr_set_wedge(struct usb_ep *_ep) +{ +	return gr_set_halt_wedge(_ep, 1, 1); +} + +/* + * Return the total number of bytes currently stored in the internal buffers of + * the endpoint. + */ +static int gr_fifo_status(struct usb_ep *_ep) +{ +	struct gr_ep *ep; +	u32 epstat; +	u32 bytes = 0; + +	if (!_ep) +		return -ENODEV; +	ep = container_of(_ep, struct gr_ep, ep); + +	epstat = gr_read32(&ep->regs->epstat); + +	if (epstat & GR_EPSTAT_B0) +		bytes += (epstat & GR_EPSTAT_B0CNT_MASK) >> GR_EPSTAT_B0CNT_POS; +	if (epstat & GR_EPSTAT_B1) +		bytes += (epstat & GR_EPSTAT_B1CNT_MASK) >> GR_EPSTAT_B1CNT_POS; + +	return bytes; +} + + +/* Empty data from internal buffers of an endpoint. */ +static void gr_fifo_flush(struct usb_ep *_ep) +{ +	struct gr_ep *ep; +	u32 epctrl; + +	if (!_ep) +		return; +	ep = container_of(_ep, struct gr_ep, ep); +	dev_vdbg(ep->dev->dev, "EP: flush fifo %s\n", ep->ep.name); + +	spin_lock(&ep->dev->lock); + +	epctrl = gr_read32(&ep->regs->epctrl); +	epctrl |= GR_EPCTRL_CB; +	gr_write32(&ep->regs->epctrl, epctrl); + +	spin_unlock(&ep->dev->lock); +} + +static struct usb_ep_ops gr_ep_ops = { +	.enable		= gr_ep_enable, +	.disable	= gr_ep_disable, + +	.alloc_request	= gr_alloc_request, +	.free_request	= gr_free_request, + +	.queue		= gr_queue_ext, +	.dequeue	= gr_dequeue, + +	.set_halt	= gr_set_halt, +	.set_wedge	= gr_set_wedge, +	.fifo_status	= gr_fifo_status, +	.fifo_flush	= gr_fifo_flush, +}; + +/* ---------------------------------------------------------------------- */ +/* USB Gadget ops */ + +static int gr_get_frame(struct usb_gadget *_gadget) +{ +	struct gr_udc *dev; + +	if (!_gadget) +		return -ENODEV; +	dev = container_of(_gadget, struct gr_udc, gadget); +	return gr_read32(&dev->regs->status) & GR_STATUS_FN_MASK; +} + +static int gr_wakeup(struct usb_gadget *_gadget) +{ +	struct gr_udc *dev; + +	if (!_gadget) +		return -ENODEV; +	dev = container_of(_gadget, struct gr_udc, gadget); + +	/* Remote wakeup feature not enabled by host*/ +	if (!dev->remote_wakeup) +		return -EINVAL; + +	spin_lock(&dev->lock); + +	gr_write32(&dev->regs->control, +		   gr_read32(&dev->regs->control) | GR_CONTROL_RW); + +	spin_unlock(&dev->lock); + +	return 0; +} + +static int gr_pullup(struct usb_gadget *_gadget, int is_on) +{ +	struct gr_udc *dev; +	u32 control; + +	if (!_gadget) +		return -ENODEV; +	dev = container_of(_gadget, struct gr_udc, gadget); + +	spin_lock(&dev->lock); + +	control = gr_read32(&dev->regs->control); +	if (is_on) +		control |= GR_CONTROL_EP; +	else +		control &= ~GR_CONTROL_EP; +	gr_write32(&dev->regs->control, control); + +	spin_unlock(&dev->lock); + +	return 0; +} + +static int gr_udc_start(struct usb_gadget *gadget, +			struct usb_gadget_driver *driver) +{ +	struct gr_udc *dev = to_gr_udc(gadget); + +	spin_lock(&dev->lock); + +	/* Hook up the driver */ +	driver->driver.bus = NULL; +	dev->driver = driver; + +	/* Get ready for host detection */ +	gr_enable_vbus_detect(dev); + +	spin_unlock(&dev->lock); + +	dev_info(dev->dev, "Started with gadget driver '%s'\n", +		 driver->driver.name); + +	return 0; +} + +static int gr_udc_stop(struct usb_gadget *gadget, +		       struct usb_gadget_driver *driver) +{ +	struct gr_udc *dev = to_gr_udc(gadget); +	unsigned long flags; + +	spin_lock_irqsave(&dev->lock, flags); + +	dev->driver = NULL; +	gr_stop_activity(dev); + +	spin_unlock_irqrestore(&dev->lock, flags); + +	dev_info(dev->dev, "Stopped\n"); + +	return 0; +} + +static const struct usb_gadget_ops gr_ops = { +	.get_frame	= gr_get_frame, +	.wakeup         = gr_wakeup, +	.pullup         = gr_pullup, +	.udc_start	= gr_udc_start, +	.udc_stop	= gr_udc_stop, +	/* Other operations not supported */ +}; + +/* ---------------------------------------------------------------------- */ +/* Module probe, removal and of-matching */ + +static const char * const onames[] = { +	"ep0out", "ep1out", "ep2out", "ep3out", "ep4out", "ep5out", +	"ep6out", "ep7out", "ep8out", "ep9out", "ep10out", "ep11out", +	"ep12out", "ep13out", "ep14out", "ep15out" +}; + +static const char * const inames[] = { +	"ep0in", "ep1in", "ep2in", "ep3in", "ep4in", "ep5in", +	"ep6in", "ep7in", "ep8in", "ep9in", "ep10in", "ep11in", +	"ep12in", "ep13in", "ep14in", "ep15in" +}; + +/* Must be called with dev->lock held */ +static int gr_ep_init(struct gr_udc *dev, int num, int is_in, u32 maxplimit) +{ +	struct gr_ep *ep; +	struct gr_request *req; +	struct usb_request *_req; +	void *buf; + +	if (is_in) { +		ep = &dev->epi[num]; +		ep->ep.name = inames[num]; +		ep->regs = &dev->regs->epi[num]; +	} else { +		ep = &dev->epo[num]; +		ep->ep.name = onames[num]; +		ep->regs = &dev->regs->epo[num]; +	} + +	gr_ep_reset(ep); +	ep->num = num; +	ep->is_in = is_in; +	ep->dev = dev; +	ep->ep.ops = &gr_ep_ops; +	INIT_LIST_HEAD(&ep->queue); + +	if (num == 0) { +		_req = gr_alloc_request(&ep->ep, GFP_ATOMIC); +		buf = devm_kzalloc(dev->dev, PAGE_SIZE, GFP_DMA | GFP_ATOMIC); +		if (!_req || !buf) { +			/* possible _req freed by gr_probe via gr_remove */ +			return -ENOMEM; +		} + +		req = container_of(_req, struct gr_request, req); +		req->req.buf = buf; +		req->req.length = MAX_CTRL_PL_SIZE; + +		if (is_in) +			dev->ep0reqi = req; /* Complete gets set as used */ +		else +			dev->ep0reqo = req; /* Completion treated separately */ + +		usb_ep_set_maxpacket_limit(&ep->ep, MAX_CTRL_PL_SIZE); +		ep->bytes_per_buffer = MAX_CTRL_PL_SIZE; +	} else { +		usb_ep_set_maxpacket_limit(&ep->ep, (u16)maxplimit); +		list_add_tail(&ep->ep.ep_list, &dev->gadget.ep_list); +	} +	list_add_tail(&ep->ep_list, &dev->ep_list); + +	return 0; +} + +/* Must be called with dev->lock held */ +static int gr_udc_init(struct gr_udc *dev) +{ +	struct device_node *np = dev->dev->of_node; +	u32 epctrl_val; +	u32 dmactrl_val; +	int i; +	int ret = 0; +	u32 bufsize; + +	gr_set_address(dev, 0); + +	INIT_LIST_HEAD(&dev->gadget.ep_list); +	dev->gadget.speed = USB_SPEED_UNKNOWN; +	dev->gadget.ep0 = &dev->epi[0].ep; + +	INIT_LIST_HEAD(&dev->ep_list); +	gr_set_ep0state(dev, GR_EP0_DISCONNECT); + +	for (i = 0; i < dev->nepo; i++) { +		if (of_property_read_u32_index(np, "epobufsizes", i, &bufsize)) +			bufsize = 1024; +		ret = gr_ep_init(dev, i, 0, bufsize); +		if (ret) +			return ret; +	} + +	for (i = 0; i < dev->nepi; i++) { +		if (of_property_read_u32_index(np, "epibufsizes", i, &bufsize)) +			bufsize = 1024; +		ret = gr_ep_init(dev, i, 1, bufsize); +		if (ret) +			return ret; +	} + +	/* Must be disabled by default */ +	dev->remote_wakeup = 0; + +	/* Enable ep0out and ep0in */ +	epctrl_val = (MAX_CTRL_PL_SIZE << GR_EPCTRL_MAXPL_POS) | GR_EPCTRL_EV; +	dmactrl_val = GR_DMACTRL_IE | GR_DMACTRL_AI; +	gr_write32(&dev->epo[0].regs->epctrl, epctrl_val); +	gr_write32(&dev->epi[0].regs->epctrl, epctrl_val | GR_EPCTRL_PI); +	gr_write32(&dev->epo[0].regs->dmactrl, dmactrl_val); +	gr_write32(&dev->epi[0].regs->dmactrl, dmactrl_val); + +	return 0; +} + +static int gr_remove(struct platform_device *pdev) +{ +	struct gr_udc *dev = platform_get_drvdata(pdev); + +	if (dev->added) +		usb_del_gadget_udc(&dev->gadget); /* Shuts everything down */ +	if (dev->driver) +		return -EBUSY; + +	gr_dfs_delete(dev); +	if (dev->desc_pool) +		dma_pool_destroy(dev->desc_pool); +	platform_set_drvdata(pdev, NULL); + +	gr_free_request(&dev->epi[0].ep, &dev->ep0reqi->req); +	gr_free_request(&dev->epo[0].ep, &dev->ep0reqo->req); + +	return 0; +} +static int gr_request_irq(struct gr_udc *dev, int irq) +{ +	return devm_request_threaded_irq(dev->dev, irq, gr_irq, gr_irq_handler, +					 IRQF_SHARED, driver_name, dev); +} + +static int gr_probe(struct platform_device *pdev) +{ +	struct gr_udc *dev; +	struct resource *res; +	struct gr_regs __iomem *regs; +	int retval; +	u32 status; + +	dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL); +	if (!dev) +		return -ENOMEM; +	dev->dev = &pdev->dev; + +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0); +	regs = devm_ioremap_resource(dev->dev, res); +	if (IS_ERR(regs)) +		return PTR_ERR(regs); + +	dev->irq = platform_get_irq(pdev, 0); +	if (dev->irq <= 0) { +		dev_err(dev->dev, "No irq found\n"); +		return -ENODEV; +	} + +	/* Some core configurations has separate irqs for IN and OUT events */ +	dev->irqi = platform_get_irq(pdev, 1); +	if (dev->irqi > 0) { +		dev->irqo = platform_get_irq(pdev, 2); +		if (dev->irqo <= 0) { +			dev_err(dev->dev, "Found irqi but not irqo\n"); +			return -ENODEV; +		} +	} else { +		dev->irqi = 0; +	} + +	dev->gadget.name = driver_name; +	dev->gadget.max_speed = USB_SPEED_HIGH; +	dev->gadget.ops = &gr_ops; +	dev->gadget.quirk_ep_out_aligned_size = true; + +	spin_lock_init(&dev->lock); +	dev->regs = regs; + +	platform_set_drvdata(pdev, dev); + +	/* Determine number of endpoints and data interface mode */ +	status = gr_read32(&dev->regs->status); +	dev->nepi = ((status & GR_STATUS_NEPI_MASK) >> GR_STATUS_NEPI_POS) + 1; +	dev->nepo = ((status & GR_STATUS_NEPO_MASK) >> GR_STATUS_NEPO_POS) + 1; + +	if (!(status & GR_STATUS_DM)) { +		dev_err(dev->dev, "Slave mode cores are not supported\n"); +		return -ENODEV; +	} + +	/* --- Effects of the following calls might need explicit cleanup --- */ + +	/* Create DMA pool for descriptors */ +	dev->desc_pool = dma_pool_create("desc_pool", dev->dev, +					 sizeof(struct gr_dma_desc), 4, 0); +	if (!dev->desc_pool) { +		dev_err(dev->dev, "Could not allocate DMA pool"); +		return -ENOMEM; +	} + +	spin_lock(&dev->lock); + +	/* Inside lock so that no gadget can use this udc until probe is done */ +	retval = usb_add_gadget_udc(dev->dev, &dev->gadget); +	if (retval) { +		dev_err(dev->dev, "Could not add gadget udc"); +		goto out; +	} +	dev->added = 1; + +	retval = gr_udc_init(dev); +	if (retval) +		goto out; + +	gr_dfs_create(dev); + +	/* Clear all interrupt enables that might be left on since last boot */ +	gr_disable_interrupts_and_pullup(dev); + +	retval = gr_request_irq(dev, dev->irq); +	if (retval) { +		dev_err(dev->dev, "Failed to request irq %d\n", dev->irq); +		goto out; +	} + +	if (dev->irqi) { +		retval = gr_request_irq(dev, dev->irqi); +		if (retval) { +			dev_err(dev->dev, "Failed to request irqi %d\n", +				dev->irqi); +			goto out; +		} +		retval = gr_request_irq(dev, dev->irqo); +		if (retval) { +			dev_err(dev->dev, "Failed to request irqo %d\n", +				dev->irqo); +			goto out; +		} +	} + +	if (dev->irqi) +		dev_info(dev->dev, "regs: %p, irqs %d, %d, %d\n", dev->regs, +			 dev->irq, dev->irqi, dev->irqo); +	else +		dev_info(dev->dev, "regs: %p, irq %d\n", dev->regs, dev->irq); + +out: +	spin_unlock(&dev->lock); + +	if (retval) +		gr_remove(pdev); + +	return retval; +} + +static struct of_device_id gr_match[] = { +	{.name = "GAISLER_USBDC"}, +	{.name = "01_021"}, +	{}, +}; +MODULE_DEVICE_TABLE(of, gr_match); + +static struct platform_driver gr_driver = { +	.driver = { +		.name = DRIVER_NAME, +		.owner = THIS_MODULE, +		.of_match_table = gr_match, +	}, +	.probe = gr_probe, +	.remove = gr_remove, +}; +module_platform_driver(gr_driver); + +MODULE_AUTHOR("Aeroflex Gaisler AB."); +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_LICENSE("GPL"); diff --git a/drivers/usb/gadget/gr_udc.h b/drivers/usb/gadget/gr_udc.h new file mode 100644 index 00000000000..8388897d9ec --- /dev/null +++ b/drivers/usb/gadget/gr_udc.h @@ -0,0 +1,220 @@ +/* + * USB Peripheral Controller driver for Aeroflex Gaisler GRUSBDC. + * + * 2013 (c) Aeroflex Gaisler AB + * + * This driver supports GRUSBDC USB Device Controller cores available in the + * GRLIB VHDL IP core library. + * + * Full documentation of the GRUSBDC core can be found here: + * http://www.gaisler.com/products/grlib/grip.pdf + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * Contributors: + * - Andreas Larsson <andreas@gaisler.com> + * - Marko Isomaki + */ + +/* Control registers on the AMBA bus */ + +#define GR_MAXEP	16	/* Max # endpoints for *each* direction */ + +struct gr_epregs { +	u32 epctrl; +	union { +		struct { /* Slave mode*/ +			u32 slvctrl; +			u32 slvdata; +		}; +		struct { /* DMA mode*/ +			u32 dmactrl; +			u32 dmaaddr; +		}; +	}; +	u32 epstat; +}; + +struct gr_regs { +	struct gr_epregs	epo[GR_MAXEP];	/* 0x000 - 0x0fc */ +	struct gr_epregs	epi[GR_MAXEP];	/* 0x100 - 0x1fc */ +	u32			control;	/* 0x200 */ +	u32			status;		/* 0x204 */ +}; + +#define GR_EPCTRL_BUFSZ_SCALER	8 +#define GR_EPCTRL_BUFSZ_MASK	0xffe00000 +#define GR_EPCTRL_BUFSZ_POS	21 +#define GR_EPCTRL_PI		BIT(20) +#define GR_EPCTRL_CB		BIT(19) +#define GR_EPCTRL_CS		BIT(18) +#define GR_EPCTRL_MAXPL_MASK	0x0003ff80 +#define GR_EPCTRL_MAXPL_POS	7 +#define GR_EPCTRL_NT_MASK	0x00000060 +#define GR_EPCTRL_NT_POS	5 +#define GR_EPCTRL_TT_MASK	0x00000018 +#define GR_EPCTRL_TT_POS	3 +#define GR_EPCTRL_EH		BIT(2) +#define GR_EPCTRL_ED		BIT(1) +#define GR_EPCTRL_EV		BIT(0) + +#define GR_DMACTRL_AE		BIT(10) +#define GR_DMACTRL_AD		BIT(3) +#define GR_DMACTRL_AI		BIT(2) +#define GR_DMACTRL_IE		BIT(1) +#define GR_DMACTRL_DA		BIT(0) + +#define GR_EPSTAT_PT		BIT(29) +#define GR_EPSTAT_PR		BIT(29) +#define GR_EPSTAT_B1CNT_MASK	0x1fff0000 +#define GR_EPSTAT_B1CNT_POS	16 +#define GR_EPSTAT_B0CNT_MASK	0x0000fff8 +#define GR_EPSTAT_B0CNT_POS	3 +#define GR_EPSTAT_B1		BIT(2) +#define GR_EPSTAT_B0		BIT(1) +#define GR_EPSTAT_BS		BIT(0) + +#define GR_CONTROL_SI		BIT(31) +#define GR_CONTROL_UI		BIT(30) +#define GR_CONTROL_VI		BIT(29) +#define GR_CONTROL_SP		BIT(28) +#define GR_CONTROL_FI		BIT(27) +#define GR_CONTROL_EP		BIT(14) +#define GR_CONTROL_DH		BIT(13) +#define GR_CONTROL_RW		BIT(12) +#define GR_CONTROL_TS_MASK	0x00000e00 +#define GR_CONTROL_TS_POS	9 +#define GR_CONTROL_TM		BIT(8) +#define GR_CONTROL_UA_MASK	0x000000fe +#define GR_CONTROL_UA_POS	1 +#define GR_CONTROL_SU		BIT(0) + +#define GR_STATUS_NEPI_MASK	0xf0000000 +#define GR_STATUS_NEPI_POS	28 +#define GR_STATUS_NEPO_MASK	0x0f000000 +#define GR_STATUS_NEPO_POS	24 +#define GR_STATUS_DM		BIT(23) +#define GR_STATUS_SU		BIT(17) +#define GR_STATUS_UR		BIT(16) +#define GR_STATUS_VB		BIT(15) +#define GR_STATUS_SP		BIT(14) +#define GR_STATUS_AF_MASK	0x00003800 +#define GR_STATUS_AF_POS	11 +#define GR_STATUS_FN_MASK	0x000007ff +#define GR_STATUS_FN_POS	0 + + +#define MAX_CTRL_PL_SIZE 64 /* As per USB standard for full and high speed */ + +/*-------------------------------------------------------------------------*/ + +/* Driver data structures and utilities */ + +struct gr_dma_desc { +	u32 ctrl; +	u32 data; +	u32 next; + +	/* These must be last because hw uses the previous three */ +	u32 paddr; +	struct gr_dma_desc *next_desc; +}; + +#define GR_DESC_OUT_CTRL_SE		BIT(17) +#define GR_DESC_OUT_CTRL_IE		BIT(15) +#define GR_DESC_OUT_CTRL_NX		BIT(14) +#define GR_DESC_OUT_CTRL_EN		BIT(13) +#define GR_DESC_OUT_CTRL_LEN_MASK	0x00001fff + +#define GR_DESC_IN_CTRL_MO		BIT(18) +#define GR_DESC_IN_CTRL_PI		BIT(17) +#define GR_DESC_IN_CTRL_ML		BIT(16) +#define GR_DESC_IN_CTRL_IE		BIT(15) +#define GR_DESC_IN_CTRL_NX		BIT(14) +#define GR_DESC_IN_CTRL_EN		BIT(13) +#define GR_DESC_IN_CTRL_LEN_MASK	0x00001fff + +#define GR_DESC_DMAADDR_MASK		0xfffffffc + +struct gr_ep { +	struct usb_ep ep; +	struct gr_udc *dev; +	u16 bytes_per_buffer; +	unsigned int dma_start; +	struct gr_epregs __iomem *regs; + +	unsigned num:8; +	unsigned is_in:1; +	unsigned stopped:1; +	unsigned wedged:1; +	unsigned callback:1; + +	/* analogous to a host-side qh */ +	struct list_head queue; + +	struct list_head ep_list; +}; + +struct gr_request { +	struct usb_request req; +	struct list_head queue; + +	/* Chain of dma descriptors */ +	struct gr_dma_desc *first_desc; /* First in the chain */ +	struct gr_dma_desc *curr_desc; /* Current descriptor */ +	struct gr_dma_desc *last_desc; /* Last in the chain */ + +	u8 setup; /* Setup packet */ +}; + +enum gr_ep0state { +	GR_EP0_DISCONNECT = 0,	/* No host */ +	GR_EP0_SETUP,		/* Between STATUS ack and SETUP report */ +	GR_EP0_IDATA,		/* IN data stage */ +	GR_EP0_ODATA,		/* OUT data stage */ +	GR_EP0_ISTATUS,		/* Status stage after IN data stage */ +	GR_EP0_OSTATUS,		/* Status stage after OUT data stage */ +	GR_EP0_STALL,		/* Data or status stages */ +	GR_EP0_SUSPEND,		/* USB suspend */ +}; + +struct gr_udc { +	struct usb_gadget gadget; +	struct gr_ep epi[GR_MAXEP]; +	struct gr_ep epo[GR_MAXEP]; +	struct usb_gadget_driver *driver; +	struct dma_pool *desc_pool; +	struct device *dev; + +	enum gr_ep0state ep0state; +	struct gr_request *ep0reqo; +	struct gr_request *ep0reqi; + +	struct gr_regs __iomem *regs; +	int irq; +	int irqi; +	int irqo; + +	unsigned added:1; +	unsigned irq_enabled:1; +	unsigned remote_wakeup:1; + +	u8 test_mode; + +	enum usb_device_state suspended_from; + +	unsigned int nepi; +	unsigned int nepo; + +	struct list_head ep_list; + +	spinlock_t lock; /* General lock, a.k.a. "dev->lock" in comments */ + +	struct dentry *dfs_root; +	struct dentry *dfs_state; +}; + +#define to_gr_udc(gadget)	(container_of((gadget), struct gr_udc, gadget)) diff --git a/drivers/usb/gadget/inode.c b/drivers/usb/gadget/inode.c index b94c049ab0d..2e4ce770490 100644 --- a/drivers/usb/gadget/inode.c +++ b/drivers/usb/gadget/inode.c @@ -439,11 +439,9 @@ ep_write (struct file *fd, const char __user *buf, size_t len, loff_t *ptr)  	/* FIXME writebehind for O_NONBLOCK and poll(), qlen = 1 */  	value = -ENOMEM; -	kbuf = kmalloc (len, GFP_KERNEL); -	if (!kbuf) -		goto free1; -	if (copy_from_user (kbuf, buf, len)) { -		value = -EFAULT; +	kbuf = memdup_user(buf, len); +	if (!kbuf) { +		value = PTR_ERR(kbuf);  		goto free1;  	} @@ -452,7 +450,6 @@ ep_write (struct file *fd, const char __user *buf, size_t len, loff_t *ptr)  		data->name, len, (int) value);  free1:  	mutex_unlock(&data->lock); -	kfree (kbuf);  	return value;  } @@ -1267,8 +1264,13 @@ dev_release (struct inode *inode, struct file *fd)  	kfree (dev->buf);  	dev->buf = NULL; -	put_dev (dev); +	/* other endpoints were all decoupled from this device */ +	spin_lock_irq(&dev->lock); +	dev->state = STATE_DEV_DISABLED; +	spin_unlock_irq(&dev->lock); + +	put_dev (dev);  	return 0;  } @@ -1497,6 +1499,7 @@ gadgetfs_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)  		 */  		if (value == 0) {  			INFO (dev, "configuration #%d\n", dev->current_config); +			usb_gadget_set_state(gadget, USB_STATE_CONFIGURED);  			if (dev->usermode_setup) {  				dev->setup_can_stall = 0;  				goto delegate; @@ -1504,7 +1507,7 @@ gadgetfs_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)  		}  		break; -#ifndef	CONFIG_USB_GADGET_PXA25X +#ifndef	CONFIG_USB_PXA25X  	/* PXA automagically handles this request too */  	case USB_REQ_GET_CONFIGURATION:  		if (ctrl->bRequestType != 0x80) @@ -2046,6 +2049,7 @@ gadgetfs_fill_super (struct super_block *sb, void *opts, int silent)  		return -ESRCH;  	/* fake probe to determine $CHIP */ +	CHIP = NULL;  	usb_gadget_probe_driver(&probe_driver);  	if (!CHIP)  		return -ENODEV; diff --git a/drivers/usb/gadget/lpc32xx_udc.c b/drivers/usb/gadget/lpc32xx_udc.c index 67128be1e1b..e471580a2a3 100644 --- a/drivers/usb/gadget/lpc32xx_udc.c +++ b/drivers/usb/gadget/lpc32xx_udc.c @@ -55,7 +55,6 @@  #include <mach/hardware.h>  #include <linux/io.h>  #include <asm/irq.h> -#include <asm/system.h>  #include <mach/platform.h>  #include <mach/irqs.h> @@ -1449,7 +1448,7 @@ static void udc_reinit(struct lpc32xx_udc *udc)  		if (i != 0)  			list_add_tail(&ep->ep.ep_list, &udc->gadget.ep_list); -		ep->ep.maxpacket = ep->maxpacket; +		usb_ep_set_maxpacket_limit(&ep->ep, ep->maxpacket);  		INIT_LIST_HEAD(&ep->queue);  		ep->req_pending = 0;  	} @@ -3078,7 +3077,9 @@ static int __init lpc32xx_udc_probe(struct platform_device *pdev)  		 udc->isp1301_i2c_client->addr);  	pdev->dev.dma_mask = &lpc32xx_usbd_dmamask; -	pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32); +	retval = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32)); +	if (retval) +		goto resource_fail;  	udc->board = &lpc32xx_usbddata; @@ -3293,9 +3294,9 @@ usb_clk_enable_fail:  pll_set_fail:  	clk_disable(udc->usb_pll_clk);  pll_enable_fail: -	clk_put(udc->usb_slv_clk); -usb_otg_clk_get_fail:  	clk_put(udc->usb_otg_clk); +usb_otg_clk_get_fail: +	clk_put(udc->usb_slv_clk);  usb_clk_get_fail:  	clk_put(udc->usb_pll_clk);  pll_get_fail: diff --git a/drivers/usb/gadget/m66592-udc.c b/drivers/usb/gadget/m66592-udc.c index d5f050d30ed..0d17174b86f 100644 --- a/drivers/usb/gadget/m66592-udc.c +++ b/drivers/usb/gadget/m66592-udc.c @@ -1594,7 +1594,6 @@ static int __init m66592_probe(struct platform_device *pdev)  	m66592 = kzalloc(sizeof(struct m66592), GFP_KERNEL);  	if (m66592 == NULL) {  		ret = -ENOMEM; -		pr_err("kzalloc error\n");  		goto clean_up;  	} @@ -1647,9 +1646,9 @@ static int __init m66592_probe(struct platform_device *pdev)  		INIT_LIST_HEAD(&ep->queue);  		ep->ep.name = m66592_ep_name[i];  		ep->ep.ops = &m66592_ep_ops; -		ep->ep.maxpacket = 512; +		usb_ep_set_maxpacket_limit(&ep->ep, 512);  	} -	m66592->ep[0].ep.maxpacket = 64; +	usb_ep_set_maxpacket_limit(&m66592->ep[0].ep, 64);  	m66592->ep[0].pipenum = 0;  	m66592->ep[0].fifoaddr = M66592_CFIFO;  	m66592->ep[0].fifosel = M66592_CFIFOSEL; diff --git a/drivers/usb/gadget/mass_storage.c b/drivers/usb/gadget/mass_storage.c index 080e577773d..8e27a8c9644 100644 --- a/drivers/usb/gadget/mass_storage.c +++ b/drivers/usb/gadget/mass_storage.c @@ -37,16 +37,16 @@  #define DRIVER_DESC		"Mass Storage Gadget"  #define DRIVER_VERSION		"2009/09/11" -/*-------------------------------------------------------------------------*/ -  /* - * 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. + * Thanks to NetChip Technologies for donating this product ID. + * + * DO NOT REUSE THESE IDs with any other driver!!  Ever!! + * Instead:  allocate your own, using normal USB-IF procedures.   */ -#include "f_mass_storage.c" +#define FSG_VENDOR_ID	0x0525	/* NetChip */ +#define FSG_PRODUCT_ID	0xa4a5	/* Linux-USB File-backed Storage Gadget */ + +#include "f_mass_storage.h"  /*-------------------------------------------------------------------------*/  USB_GADGET_COMPOSITE_OPTIONS(); @@ -97,11 +97,28 @@ static struct usb_gadget_strings *dev_strings[] = {  	NULL,  }; +static struct usb_function_instance *fi_msg; +static struct usb_function *f_msg; +  /****************************** Configurations ******************************/  static struct fsg_module_parameters mod_data = {  	.stall = 1  }; +#ifdef CONFIG_USB_GADGET_DEBUG_FILES + +static unsigned int fsg_num_buffers = CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS; + +#else + +/* + * Number of buffers we will use. + * 2 is usually enough for good buffering pipeline + */ +#define fsg_num_buffers	CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS + +#endif /* CONFIG_USB_GADGET_DEBUG_FILES */ +  FSG_MODULE_PARAMETERS(/* no prefix */, mod_data);  static unsigned long msg_registered; @@ -115,13 +132,7 @@ static int msg_thread_exits(struct fsg_common *common)  static int __init msg_do_config(struct usb_configuration *c)  { -	static const struct fsg_operations ops = { -		.thread_exits = msg_thread_exits, -	}; -	static struct fsg_common common; - -	struct fsg_common *retp; -	struct fsg_config config; +	struct fsg_opts *opts;  	int ret;  	if (gadget_is_otg(c->cdev->gadget)) { @@ -129,15 +140,24 @@ static int __init msg_do_config(struct usb_configuration *c)  		c->bmAttributes |= USB_CONFIG_ATT_WAKEUP;  	} -	fsg_config_from_params(&config, &mod_data); -	config.ops = &ops; +	opts = fsg_opts_from_func_inst(fi_msg); + +	f_msg = usb_get_function(fi_msg); +	if (IS_ERR(f_msg)) +		return PTR_ERR(f_msg); + +	ret = fsg_common_run_thread(opts->common); +	if (ret) +		goto put_func; + +	ret = usb_add_function(c, f_msg); +	if (ret) +		goto put_func; -	retp = fsg_common_init(&common, c->cdev, &config); -	if (IS_ERR(retp)) -		return PTR_ERR(retp); +	return 0; -	ret = fsg_bind_config(c->cdev, c, &common); -	fsg_common_put(&common); +put_func: +	usb_put_function(f_msg);  	return ret;  } @@ -152,23 +172,79 @@ static struct usb_configuration msg_config_driver = {  static int __init msg_bind(struct usb_composite_dev *cdev)  { +	static const struct fsg_operations ops = { +		.thread_exits = msg_thread_exits, +	}; +	struct fsg_opts *opts; +	struct fsg_config config;  	int status; +	fi_msg = usb_get_function_instance("mass_storage"); +	if (IS_ERR(fi_msg)) +		return PTR_ERR(fi_msg); + +	fsg_config_from_params(&config, &mod_data, fsg_num_buffers); +	opts = fsg_opts_from_func_inst(fi_msg); + +	opts->no_configfs = true; +	status = fsg_common_set_num_buffers(opts->common, fsg_num_buffers); +	if (status) +		goto fail; + +	status = fsg_common_set_nluns(opts->common, config.nluns); +	if (status) +		goto fail_set_nluns; + +	fsg_common_set_ops(opts->common, &ops); + +	status = fsg_common_set_cdev(opts->common, cdev, config.can_stall); +	if (status) +		goto fail_set_cdev; + +	fsg_common_set_sysfs(opts->common, true); +	status = fsg_common_create_luns(opts->common, &config); +	if (status) +		goto fail_set_cdev; + +	fsg_common_set_inquiry_string(opts->common, config.vendor_name, +				      config.product_name); +  	status = usb_string_ids_tab(cdev, strings_dev);  	if (status < 0) -		return status; +		goto fail_string_ids;  	msg_device_desc.iProduct = strings_dev[USB_GADGET_PRODUCT_IDX].id;  	status = usb_add_config(cdev, &msg_config_driver, msg_do_config);  	if (status < 0) -		return status; +		goto fail_string_ids; +  	usb_composite_overwrite_options(cdev, &coverwrite);  	dev_info(&cdev->gadget->dev,  		 DRIVER_DESC ", version: " DRIVER_VERSION "\n");  	set_bit(0, &msg_registered);  	return 0; + +fail_string_ids: +	fsg_common_remove_luns(opts->common); +fail_set_cdev: +	fsg_common_free_luns(opts->common); +fail_set_nluns: +	fsg_common_free_buffers(opts->common); +fail: +	usb_put_function_instance(fi_msg); +	return status;  } +static int msg_unbind(struct usb_composite_dev *cdev) +{ +	if (!IS_ERR(f_msg)) +		usb_put_function(f_msg); + +	if (!IS_ERR(fi_msg)) +		usb_put_function_instance(fi_msg); + +	return 0; +}  /****************************** Some noise ******************************/ @@ -179,6 +255,7 @@ static __refdata struct usb_composite_driver msg_driver = {  	.needs_serial	= 1,  	.strings	= dev_strings,  	.bind		= msg_bind, +	.unbind		= msg_unbind,  };  MODULE_DESCRIPTION(DRIVER_DESC); diff --git a/drivers/usb/gadget/multi.c b/drivers/usb/gadget/multi.c index 2a1ebefd8f9..940f6cde8e8 100644 --- a/drivers/usb/gadget/multi.c +++ b/drivers/usb/gadget/multi.c @@ -15,6 +15,7 @@  #include <linux/kernel.h>  #include <linux/module.h> +#include <linux/netdevice.h>  #include "u_serial.h"  #if defined USB_ETH_RNDIS @@ -32,22 +33,11 @@ MODULE_AUTHOR("Michal Nazarewicz");  MODULE_LICENSE("GPL"); -/***************************** All the files... *****************************/ +#include "f_mass_storage.h" -/* - * 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 "f_mass_storage.c" - -#define USBF_ECM_INCLUDED -#include "f_ecm.c" +#include "u_ecm.h"  #ifdef USB_ETH_RNDIS -#  define USB_FRNDIS_INCLUDED -#  include "f_rndis.c" +#  include "u_rndis.h"  #  include "rndis.h"  #endif  #include "u_ether.h" @@ -132,22 +122,36 @@ static struct usb_gadget_strings *dev_strings[] = {  /****************************** Configurations ******************************/  static struct fsg_module_parameters fsg_mod_data = { .stall = 1 }; -FSG_MODULE_PARAMETERS(/* no prefix */, fsg_mod_data); +#ifdef CONFIG_USB_GADGET_DEBUG_FILES + +static unsigned int fsg_num_buffers = CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS; -static struct fsg_common fsg_common; +#else + +/* + * Number of buffers we will use. + * 2 is usually enough for good buffering pipeline + */ +#define fsg_num_buffers	CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS -static u8 host_mac[ETH_ALEN]; +#endif /* CONFIG_USB_GADGET_DEBUG_FILES */ + +FSG_MODULE_PARAMETERS(/* no prefix */, fsg_mod_data);  static struct usb_function_instance *fi_acm; -static struct eth_dev *the_dev; +static struct usb_function_instance *fi_msg;  /********** RNDIS **********/  #ifdef USB_ETH_RNDIS +static struct usb_function_instance *fi_rndis;  static struct usb_function *f_acm_rndis; +static struct usb_function *f_rndis; +static struct usb_function *f_msg_rndis;  static __init int rndis_do_config(struct usb_configuration *c)  { +	struct fsg_opts *fsg_opts;  	int ret;  	if (gadget_is_otg(c->cdev->gadget)) { @@ -155,31 +159,54 @@ static __init int rndis_do_config(struct usb_configuration *c)  		c->bmAttributes |= USB_CONFIG_ATT_WAKEUP;  	} -	ret = rndis_bind_config(c, host_mac, the_dev); +	f_rndis = usb_get_function(fi_rndis); +	if (IS_ERR(f_rndis)) +		return PTR_ERR(f_rndis); + +	ret = usb_add_function(c, f_rndis);  	if (ret < 0) -		return ret; +		goto err_func_rndis;  	f_acm_rndis = usb_get_function(fi_acm); -	if (IS_ERR(f_acm_rndis)) -		return PTR_ERR(f_acm_rndis); +	if (IS_ERR(f_acm_rndis)) { +		ret = PTR_ERR(f_acm_rndis); +		goto err_func_acm; +	}  	ret = usb_add_function(c, f_acm_rndis);  	if (ret)  		goto err_conf; -	ret = fsg_bind_config(c->cdev, c, &fsg_common); -	if (ret < 0) +	f_msg_rndis = usb_get_function(fi_msg); +	if (IS_ERR(f_msg_rndis)) { +		ret = PTR_ERR(f_msg_rndis);  		goto err_fsg; +	} + +	fsg_opts = fsg_opts_from_func_inst(fi_msg); +	ret = fsg_common_run_thread(fsg_opts->common); +	if (ret) +		goto err_run; + +	ret = usb_add_function(c, f_msg_rndis); +	if (ret) +		goto err_run;  	return 0; +err_run: +	usb_put_function(f_msg_rndis);  err_fsg:  	usb_remove_function(c, f_acm_rndis);  err_conf:  	usb_put_function(f_acm_rndis); +err_func_acm: +	usb_remove_function(c, f_rndis); +err_func_rndis: +	usb_put_function(f_rndis);  	return ret;  } -static int rndis_config_register(struct usb_composite_dev *cdev) +static __ref int rndis_config_register(struct usb_composite_dev *cdev)  {  	static struct usb_configuration config = {  		.bConfigurationValue	= MULTI_RNDIS_CONFIG_NUM, @@ -194,7 +221,7 @@ static int rndis_config_register(struct usb_composite_dev *cdev)  #else -static int rndis_config_register(struct usb_composite_dev *cdev) +static __ref int rndis_config_register(struct usb_composite_dev *cdev)  {  	return 0;  } @@ -205,10 +232,14 @@ static int rndis_config_register(struct usb_composite_dev *cdev)  /********** CDC ECM **********/  #ifdef CONFIG_USB_G_MULTI_CDC +static struct usb_function_instance *fi_ecm;  static struct usb_function *f_acm_multi; +static struct usb_function *f_ecm; +static struct usb_function *f_msg_multi;  static __init int cdc_do_config(struct usb_configuration *c)  { +	struct fsg_opts *fsg_opts;  	int ret;  	if (gadget_is_otg(c->cdev->gadget)) { @@ -216,32 +247,55 @@ static __init int cdc_do_config(struct usb_configuration *c)  		c->bmAttributes |= USB_CONFIG_ATT_WAKEUP;  	} -	ret = ecm_bind_config(c, host_mac, the_dev); +	f_ecm = usb_get_function(fi_ecm); +	if (IS_ERR(f_ecm)) +		return PTR_ERR(f_ecm); + +	ret = usb_add_function(c, f_ecm);  	if (ret < 0) -		return ret; +		goto err_func_ecm;  	/* implicit port_num is zero */  	f_acm_multi = usb_get_function(fi_acm); -	if (IS_ERR(f_acm_multi)) -		return PTR_ERR(f_acm_multi); +	if (IS_ERR(f_acm_multi)) { +		ret = PTR_ERR(f_acm_multi); +		goto err_func_acm; +	}  	ret = usb_add_function(c, f_acm_multi);  	if (ret)  		goto err_conf; -	ret = fsg_bind_config(c->cdev, c, &fsg_common); -	if (ret < 0) +	f_msg_multi = usb_get_function(fi_msg); +	if (IS_ERR(f_msg_multi)) { +		ret = PTR_ERR(f_msg_multi);  		goto err_fsg; +	} + +	fsg_opts = fsg_opts_from_func_inst(fi_msg); +	ret = fsg_common_run_thread(fsg_opts->common); +	if (ret) +		goto err_run; + +	ret = usb_add_function(c, f_msg_multi); +	if (ret) +		goto err_run;  	return 0; +err_run: +	usb_put_function(f_msg_multi);  err_fsg:  	usb_remove_function(c, f_acm_multi);  err_conf:  	usb_put_function(f_acm_multi); +err_func_acm: +	usb_remove_function(c, f_ecm); +err_func_ecm: +	usb_put_function(f_ecm);  	return ret;  } -static int cdc_config_register(struct usb_composite_dev *cdev) +static __ref int cdc_config_register(struct usb_composite_dev *cdev)  {  	static struct usb_configuration config = {  		.bConfigurationValue	= MULTI_CDC_CONFIG_NUM, @@ -256,7 +310,7 @@ static int cdc_config_register(struct usb_composite_dev *cdev)  #else -static int cdc_config_register(struct usb_composite_dev *cdev) +static __ref int cdc_config_register(struct usb_composite_dev *cdev)  {  	return 0;  } @@ -270,19 +324,67 @@ static int cdc_config_register(struct usb_composite_dev *cdev)  static int __ref multi_bind(struct usb_composite_dev *cdev)  {  	struct usb_gadget *gadget = cdev->gadget; +#ifdef CONFIG_USB_G_MULTI_CDC +	struct f_ecm_opts *ecm_opts; +#endif +#ifdef USB_ETH_RNDIS +	struct f_rndis_opts *rndis_opts; +#endif +	struct fsg_opts *fsg_opts; +	struct fsg_config config;  	int status;  	if (!can_support_ecm(cdev->gadget)) {  		dev_err(&gadget->dev, "controller '%s' not usable\n", -		        gadget->name); +			gadget->name);  		return -EINVAL;  	} -	/* set up network link layer */ -	the_dev = gether_setup(cdev->gadget, dev_addr, host_addr, host_mac, -			       qmult); -	if (IS_ERR(the_dev)) -		return PTR_ERR(the_dev); +#ifdef CONFIG_USB_G_MULTI_CDC +	fi_ecm = usb_get_function_instance("ecm"); +	if (IS_ERR(fi_ecm)) +		return PTR_ERR(fi_ecm); + +	ecm_opts = container_of(fi_ecm, struct f_ecm_opts, func_inst); + +	gether_set_qmult(ecm_opts->net, qmult); +	if (!gether_set_host_addr(ecm_opts->net, host_addr)) +		pr_info("using host ethernet address: %s", host_addr); +	if (!gether_set_dev_addr(ecm_opts->net, dev_addr)) +		pr_info("using self ethernet address: %s", dev_addr); +#endif + +#ifdef USB_ETH_RNDIS +	fi_rndis = usb_get_function_instance("rndis"); +	if (IS_ERR(fi_rndis)) { +		status = PTR_ERR(fi_rndis); +		goto fail; +	} + +	rndis_opts = container_of(fi_rndis, struct f_rndis_opts, func_inst); + +	gether_set_qmult(rndis_opts->net, qmult); +	if (!gether_set_host_addr(rndis_opts->net, host_addr)) +		pr_info("using host ethernet address: %s", host_addr); +	if (!gether_set_dev_addr(rndis_opts->net, dev_addr)) +		pr_info("using self ethernet address: %s", dev_addr); +#endif + +#if (defined CONFIG_USB_G_MULTI_CDC && defined USB_ETH_RNDIS) +	/* +	 * If both ecm and rndis are selected then: +	 *	1) rndis borrows the net interface from ecm +	 *	2) since the interface is shared it must not be bound +	 *	twice - in ecm's _and_ rndis' binds, so do it here. +	 */ +	gether_set_gadget(ecm_opts->net, cdev->gadget); +	status = gether_register_netdev(ecm_opts->net); +	if (status) +		goto fail0; + +	rndis_borrow_net(fi_rndis, ecm_opts->net); +	ecm_opts->bound = true; +#endif  	/* set up serial link layer */  	fi_acm = usb_get_function_instance("acm"); @@ -292,57 +394,102 @@ static int __ref multi_bind(struct usb_composite_dev *cdev)  	}  	/* set up mass storage function */ -	{ -		void *retp; -		retp = fsg_common_from_params(&fsg_common, cdev, &fsg_mod_data); -		if (IS_ERR(retp)) { -			status = PTR_ERR(retp); -			goto fail1; -		} +	fi_msg = usb_get_function_instance("mass_storage"); +	if (IS_ERR(fi_msg)) { +		status = PTR_ERR(fi_msg); +		goto fail1;  	} +	fsg_config_from_params(&config, &fsg_mod_data, fsg_num_buffers); +	fsg_opts = fsg_opts_from_func_inst(fi_msg); + +	fsg_opts->no_configfs = true; +	status = fsg_common_set_num_buffers(fsg_opts->common, fsg_num_buffers); +	if (status) +		goto fail2; + +	status = fsg_common_set_nluns(fsg_opts->common, config.nluns); +	if (status) +		goto fail_set_nluns; + +	status = fsg_common_set_cdev(fsg_opts->common, cdev, config.can_stall); +	if (status) +		goto fail_set_cdev; + +	fsg_common_set_sysfs(fsg_opts->common, true); +	status = fsg_common_create_luns(fsg_opts->common, &config); +	if (status) +		goto fail_set_cdev; + +	fsg_common_set_inquiry_string(fsg_opts->common, config.vendor_name, +				      config.product_name);  	/* allocate string IDs */  	status = usb_string_ids_tab(cdev, strings_dev);  	if (unlikely(status < 0)) -		goto fail2; +		goto fail_string_ids;  	device_desc.iProduct = strings_dev[USB_GADGET_PRODUCT_IDX].id;  	/* register configurations */  	status = rndis_config_register(cdev);  	if (unlikely(status < 0)) -		goto fail2; +		goto fail_string_ids;  	status = cdc_config_register(cdev);  	if (unlikely(status < 0)) -		goto fail2; +		goto fail_string_ids;  	usb_composite_overwrite_options(cdev, &coverwrite);  	/* we're done */  	dev_info(&gadget->dev, DRIVER_DESC "\n"); -	fsg_common_put(&fsg_common);  	return 0;  	/* error recovery */ +fail_string_ids: +	fsg_common_remove_luns(fsg_opts->common); +fail_set_cdev: +	fsg_common_free_luns(fsg_opts->common); +fail_set_nluns: +	fsg_common_free_buffers(fsg_opts->common);  fail2: -	fsg_common_put(&fsg_common); +	usb_put_function_instance(fi_msg);  fail1:  	usb_put_function_instance(fi_acm);  fail0: -	gether_cleanup(the_dev); +#ifdef USB_ETH_RNDIS +	usb_put_function_instance(fi_rndis); +fail: +#endif +#ifdef CONFIG_USB_G_MULTI_CDC +	usb_put_function_instance(fi_ecm); +#endif  	return status;  }  static int __exit multi_unbind(struct usb_composite_dev *cdev)  {  #ifdef CONFIG_USB_G_MULTI_CDC +	usb_put_function(f_msg_multi); +#endif +#ifdef USB_ETH_RNDIS +	usb_put_function(f_msg_rndis); +#endif +	usb_put_function_instance(fi_msg); +#ifdef CONFIG_USB_G_MULTI_CDC  	usb_put_function(f_acm_multi);  #endif  #ifdef USB_ETH_RNDIS  	usb_put_function(f_acm_rndis);  #endif  	usb_put_function_instance(fi_acm); -	gether_cleanup(the_dev); +#ifdef USB_ETH_RNDIS +	usb_put_function(f_rndis); +	usb_put_function_instance(fi_rndis); +#endif +#ifdef CONFIG_USB_G_MULTI_CDC +	usb_put_function(f_ecm); +	usb_put_function_instance(fi_ecm); +#endif  	return 0;  } diff --git a/drivers/usb/gadget/mv_u3d_core.c b/drivers/usb/gadget/mv_u3d_core.c index bbb6e98c438..16248711c15 100644 --- a/drivers/usb/gadget/mv_u3d_core.c +++ b/drivers/usb/gadget/mv_u3d_core.c @@ -15,7 +15,6 @@  #include <linux/sched.h>  #include <linux/slab.h>  #include <linux/errno.h> -#include <linux/init.h>  #include <linux/timer.h>  #include <linux/list.h>  #include <linux/notifier.h> @@ -298,10 +297,8 @@ static struct mv_u3d_trb *mv_u3d_build_trb_one(struct mv_u3d_req *req,  	u3d = req->ep->u3d;  	trb = kzalloc(sizeof(*trb), GFP_ATOMIC); -	if (!trb) { -		dev_err(u3d->dev, "%s, trb alloc fail\n", __func__); +	if (!trb)  		return NULL; -	}  	/*  	 * Be careful that no _GFP_HIGHMEM is set, @@ -310,6 +307,7 @@ static struct mv_u3d_trb *mv_u3d_build_trb_one(struct mv_u3d_req *req,  	 */  	trb_hw = dma_pool_alloc(u3d->trb_pool, GFP_ATOMIC, dma);  	if (!trb_hw) { +		kfree(trb);  		dev_err(u3d->dev,  			"%s, dma_pool_alloc fail\n", __func__);  		return NULL; @@ -446,16 +444,12 @@ static int mv_u3d_req_to_trb(struct mv_u3d_req *req)  			trb_num++;  		trb = kcalloc(trb_num, sizeof(*trb), GFP_ATOMIC); -		if (!trb) { -			dev_err(u3d->dev, -					"%s, trb alloc fail\n", __func__); +		if (!trb)  			return -ENOMEM; -		}  		trb_hw = kcalloc(trb_num, sizeof(*trb_hw), GFP_ATOMIC);  		if (!trb_hw) { -			dev_err(u3d->dev, -					"%s, trb_hw alloc fail\n", __func__); +			kfree(trb);  			return -ENOMEM;  		} @@ -645,6 +639,7 @@ static int  mv_u3d_ep_disable(struct usb_ep *_ep)  	struct mv_u3d_ep *ep;  	struct mv_u3d_ep_context *ep_context;  	u32 epxcr, direction; +	unsigned long flags;  	if (!_ep)  		return -EINVAL; @@ -661,7 +656,9 @@ static int  mv_u3d_ep_disable(struct usb_ep *_ep)  	direction = mv_u3d_ep_dir(ep);  	/* nuke all pending requests (does flush) */ +	spin_lock_irqsave(&u3d->lock, flags);  	mv_u3d_nuke(ep, -ESHUTDOWN); +	spin_unlock_irqrestore(&u3d->lock, flags);  	/* Disable the endpoint for Rx or Tx and reset the endpoint type */  	if (direction == MV_U3D_EP_DIR_OUT) { @@ -1331,7 +1328,7 @@ static int mv_u3d_eps_init(struct mv_u3d *u3d)  	ep->ep.name = ep->name;  	ep->ep.ops = &mv_u3d_ep_ops;  	ep->wedge = 0; -	ep->ep.maxpacket = MV_U3D_EP0_MAX_PKT_SIZE; +	usb_ep_set_maxpacket_limit(&ep->ep, MV_U3D_EP0_MAX_PKT_SIZE);  	ep->ep_num = 0;  	ep->ep.desc = &mv_u3d_ep0_desc;  	INIT_LIST_HEAD(&ep->queue); @@ -1356,7 +1353,7 @@ static int mv_u3d_eps_init(struct mv_u3d *u3d)  		ep->ep.name = ep->name;  		ep->ep.ops = &mv_u3d_ep_ops; -		ep->ep.maxpacket = (unsigned short) ~0; +		usb_ep_set_maxpacket_limit(&ep->ep, (unsigned short) ~0);  		ep->ep_num = i / 2;  		INIT_LIST_HEAD(&ep->queue); @@ -1807,7 +1804,6 @@ static int mv_u3d_probe(struct platform_device *dev)  	u3d = kzalloc(sizeof(*u3d), GFP_KERNEL);  	if (!u3d) { -		dev_err(&dev->dev, "failed to allocate memory for u3d\n");  		retval = -ENOMEM;  		goto err_alloc_private;  	} @@ -1901,7 +1897,6 @@ static int mv_u3d_probe(struct platform_device *dev)  	size = u3d->max_eps * sizeof(struct mv_u3d_ep) * 2;  	u3d->eps = kzalloc(size, GFP_KERNEL);  	if (!u3d->eps) { -		dev_err(&dev->dev, "allocate ep memory failed\n");  		retval = -ENOMEM;  		goto err_alloc_eps;  	} @@ -1909,7 +1904,6 @@ static int mv_u3d_probe(struct platform_device *dev)  	/* initialize ep0 status request structure */  	u3d->status_req = kzalloc(sizeof(struct mv_u3d_req) + 8, GFP_KERNEL);  	if (!u3d->status_req) { -		dev_err(&dev->dev, "allocate status_req memory failed\n");  		retval = -ENOMEM;  		goto err_alloc_status_req;  	} @@ -1933,7 +1927,7 @@ static int mv_u3d_probe(struct platform_device *dev)  	}  	u3d->irq = r->start;  	if (request_irq(u3d->irq, mv_u3d_irq, -		IRQF_DISABLED | IRQF_SHARED, driver_name, u3d)) { +		IRQF_SHARED, driver_name, u3d)) {  		u3d->irq = 0;  		dev_err(&dev->dev, "Request irq %d for u3d failed\n",  			u3d->irq); diff --git a/drivers/usb/gadget/mv_udc_core.c b/drivers/usb/gadget/mv_udc_core.c index 104cdbea635..fcff3a571b4 100644 --- a/drivers/usb/gadget/mv_udc_core.c +++ b/drivers/usb/gadget/mv_udc_core.c @@ -20,7 +20,6 @@  #include <linux/slab.h>  #include <linux/errno.h>  #include <linux/err.h> -#include <linux/init.h>  #include <linux/timer.h>  #include <linux/list.h>  #include <linux/interrupt.h> @@ -1261,7 +1260,7 @@ static int eps_init(struct mv_udc *udc)  	ep->ep.ops = &mv_ep_ops;  	ep->wedge = 0;  	ep->stopped = 0; -	ep->ep.maxpacket = EP0_MAX_PKT_SIZE; +	usb_ep_set_maxpacket_limit(&ep->ep, EP0_MAX_PKT_SIZE);  	ep->ep_num = 0;  	ep->ep.desc = &mv_ep0_desc;  	INIT_LIST_HEAD(&ep->queue); @@ -1284,7 +1283,7 @@ static int eps_init(struct mv_udc *udc)  		ep->ep.ops = &mv_ep_ops;  		ep->stopped = 0; -		ep->ep.maxpacket = (unsigned short) ~0; +		usb_ep_set_maxpacket_limit(&ep->ep, (unsigned short) ~0);  		ep->ep_num = i / 2;  		INIT_LIST_HEAD(&ep->queue); diff --git a/drivers/usb/gadget/net2272.c b/drivers/usb/gadget/net2272.c index bf2bb39f35a..ca15405583e 100644 --- a/drivers/usb/gadget/net2272.c +++ b/drivers/usb/gadget/net2272.c @@ -266,7 +266,7 @@ static void net2272_ep_reset(struct net2272_ep *ep)  	ep->desc = NULL;  	INIT_LIST_HEAD(&ep->queue); -	ep->ep.maxpacket = ~0; +	usb_ep_set_maxpacket_limit(&ep->ep, ~0);  	ep->ep.ops = &net2272_ep_ops;  	/* disable irqs, endpoint */ @@ -1409,7 +1409,7 @@ net2272_usb_reinit(struct net2272 *dev)  			ep->fifo_size = 64;  		net2272_ep_reset(ep);  	} -	dev->ep[0].ep.maxpacket = 64; +	usb_ep_set_maxpacket_limit(&dev->ep[0].ep, 64);  	dev->gadget.ep0 = &dev->ep[0].ep;  	dev->ep[0].stopped = 0; diff --git a/drivers/usb/gadget/net2280.c b/drivers/usb/gadget/net2280.c index 0781bff7001..300b3a71383 100644 --- a/drivers/usb/gadget/net2280.c +++ b/drivers/usb/gadget/net2280.c @@ -129,7 +129,7 @@ static char *type_string (u8 bmAttributes)  	case USB_ENDPOINT_XFER_BULK:	return "bulk";  	case USB_ENDPOINT_XFER_ISOC:	return "iso";  	case USB_ENDPOINT_XFER_INT:	return "intr"; -	}; +	}  	return "control";  }  #endif @@ -293,7 +293,7 @@ static void ep_reset (struct net2280_regs __iomem *regs, struct net2280_ep *ep)  	ep->desc = NULL;  	INIT_LIST_HEAD (&ep->queue); -	ep->ep.maxpacket = ~0; +	usb_ep_set_maxpacket_limit(&ep->ep, ~0);  	ep->ep.ops = &net2280_ep_ops;  	/* disable the dma, irqs, endpoint... */ @@ -1630,7 +1630,7 @@ static ssize_t queues_show(struct device *_dev, struct device_attribute *attr,  					val = "intr"; break;  				 default:  					val = "iso"; break; -				 }; val; }), +				 } val; }),  				usb_endpoint_maxp (d) & 0x1fff,  				ep->dma ? "dma" : "pio", ep->fifo_size  				); @@ -1805,9 +1805,9 @@ static void usb_reinit (struct net2280 *dev)  		ep->regs = &dev->epregs [tmp];  		ep_reset (dev->regs, ep);  	} -	dev->ep [0].ep.maxpacket = 64; -	dev->ep [5].ep.maxpacket = 64; -	dev->ep [6].ep.maxpacket = 64; +	usb_ep_set_maxpacket_limit(&dev->ep [0].ep, 64); +	usb_ep_set_maxpacket_limit(&dev->ep [5].ep, 64); +	usb_ep_set_maxpacket_limit(&dev->ep [6].ep, 64);  	dev->gadget.ep0 = &dev->ep [0].ep;  	dev->ep [0].stopped = 0; @@ -1972,7 +1972,9 @@ static int net2280_stop(struct usb_gadget *_gadget,  	device_remove_file (&dev->pdev->dev, &dev_attr_function);  	device_remove_file (&dev->pdev->dev, &dev_attr_queues); -	DEBUG (dev, "unregistered driver '%s'\n", driver->driver.name); +	DEBUG(dev, "unregistered driver '%s'\n", +			driver ? driver->driver.name : ""); +  	return 0;  } @@ -2680,7 +2682,6 @@ static void net2280_remove (struct pci_dev *pdev)  	if (dev->enabled)  		pci_disable_device (pdev);  	device_remove_file (&pdev->dev, &dev_attr_registers); -	pci_set_drvdata (pdev, NULL);  	INFO (dev, "unbind\n");  } diff --git a/drivers/usb/gadget/nokia.c b/drivers/usb/gadget/nokia.c index 0a8099a488c..3ab38616751 100644 --- a/drivers/usb/gadget/nokia.c +++ b/drivers/usb/gadget/nokia.c @@ -126,9 +126,9 @@ static int __init nokia_bind_config(struct usb_configuration *c)  	struct usb_function *f_ecm;  	struct usb_function *f_obex2 = NULL;  	int status = 0; -	int obex1_stat = 0; -	int obex2_stat = 0; -	int phonet_stat = 0; +	int obex1_stat = -1; +	int obex2_stat = -1; +	int phonet_stat = -1;  	if (!IS_ERR(fi_phonet)) {  		f_phonet = usb_get_function(fi_phonet); diff --git a/drivers/usb/gadget/omap_udc.c b/drivers/usb/gadget/omap_udc.c index 83957cc225d..2ae4f6d69f7 100644 --- a/drivers/usb/gadget/omap_udc.c +++ b/drivers/usb/gadget/omap_udc.c @@ -22,7 +22,6 @@  #include <linux/errno.h>  #include <linux/delay.h>  #include <linux/slab.h> -#include <linux/init.h>  #include <linux/timer.h>  #include <linux/list.h>  #include <linux/interrupt.h> @@ -2586,7 +2585,8 @@ omap_ep_setup(char *name, u8 addr, u8 type,  	ep->ep.name = ep->name;  	ep->ep.ops = &omap_ep_ops; -	ep->ep.maxpacket = ep->maxpacket = maxp; +	ep->maxpacket = maxp; +	usb_ep_set_maxpacket_limit(&ep->ep, ep->maxpacket);  	list_add_tail(&ep->ep.ep_list, &udc->gadget.ep_list);  	return buf; diff --git a/drivers/usb/gadget/pch_udc.c b/drivers/usb/gadget/pch_udc.c index 24174e1d156..eb8c3bedb57 100644 --- a/drivers/usb/gadget/pch_udc.c +++ b/drivers/usb/gadget/pch_udc.c @@ -2896,12 +2896,12 @@ static void pch_udc_pcd_reinit(struct pch_udc_dev *dev)  			ep->offset_addr = (UDC_EPINT_OUT_SHIFT + ep->num) *  					  UDC_EP_REG_SHIFT;  		/* need to set ep->ep.maxpacket and set Default Configuration?*/ -		ep->ep.maxpacket = UDC_BULK_MAX_PKT_SIZE; +		usb_ep_set_maxpacket_limit(&ep->ep, UDC_BULK_MAX_PKT_SIZE);  		list_add_tail(&ep->ep.ep_list, &dev->gadget.ep_list);  		INIT_LIST_HEAD(&ep->queue);  	} -	dev->ep[UDC_EP0IN_IDX].ep.maxpacket = UDC_EP0IN_MAX_PKT_SIZE; -	dev->ep[UDC_EP0OUT_IDX].ep.maxpacket = UDC_EP0OUT_MAX_PKT_SIZE; +	usb_ep_set_maxpacket_limit(&dev->ep[UDC_EP0IN_IDX].ep, UDC_EP0IN_MAX_PKT_SIZE); +	usb_ep_set_maxpacket_limit(&dev->ep[UDC_EP0OUT_IDX].ep, UDC_EP0OUT_MAX_PKT_SIZE);  	/* remove ep0 in and out from the list.  They have own pointer */  	list_del_init(&dev->ep[UDC_EP0IN_IDX].ep.ep_list); @@ -3080,7 +3080,6 @@ static void pch_udc_remove(struct pci_dev *pdev)  	if (dev->active)  		pci_disable_device(pdev);  	kfree(dev); -	pci_set_drvdata(pdev, NULL);  }  #ifdef CONFIG_PM @@ -3211,7 +3210,7 @@ finished:  	return retval;  } -static DEFINE_PCI_DEVICE_TABLE(pch_udc_pcidev_id) = { +static const struct pci_device_id pch_udc_pcidev_id[] = {  	{  		PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_EG20T_UDC),  		.class = (PCI_CLASS_SERIAL_USB << 8) | 0xfe, diff --git a/drivers/usb/gadget/printer.c b/drivers/usb/gadget/printer.c index bf7a56b6d48..6474081dcba 100644 --- a/drivers/usb/gadget/printer.c +++ b/drivers/usb/gadget/printer.c @@ -427,12 +427,17 @@ setup_rx_reqs(struct printer_dev *dev)  		req->length = USB_BUFSIZE;  		req->complete = rx_complete; +		/* here, we unlock, and only unlock, to avoid deadlock. */ +		spin_unlock(&dev->lock);  		error = usb_ep_queue(dev->out_ep, req, GFP_ATOMIC); +		spin_lock(&dev->lock);  		if (error) {  			DBG(dev, "rx submit --> %d\n", error);  			list_add(&req->list, &dev->rx_reqs);  			break; -		} else { +		} +		/* if the req is empty, then add it into dev->rx_reqs_active. */ +		else if (list_empty(&req->list)) {  			list_add(&req->list, &dev->rx_reqs_active);  		}  	} @@ -1133,6 +1138,7 @@ static int __init printer_bind_config(struct usb_configuration *c)  				  NULL, "g_printer");  	if (IS_ERR(dev->pdev)) {  		ERROR(dev, "Failed to create device: g_printer\n"); +		status = PTR_ERR(dev->pdev);  		goto fail;  	} @@ -1157,7 +1163,7 @@ static int __init printer_bind_config(struct usb_configuration *c)  	usb_gadget_set_selfpowered(gadget); -	if (gadget->is_otg) { +	if (gadget_is_otg(gadget)) {  		otg_descriptor.bmAttributes |= USB_OTG_HNP;  		printer_cfg_driver.descriptors = otg_desc;  		printer_cfg_driver.bmAttributes |= USB_CONFIG_ATT_WAKEUP; diff --git a/drivers/usb/gadget/pxa25x_udc.c b/drivers/usb/gadget/pxa25x_udc.c index cc9207473db..9984437d295 100644 --- a/drivers/usb/gadget/pxa25x_udc.c +++ b/drivers/usb/gadget/pxa25x_udc.c @@ -24,7 +24,6 @@  #include <linux/err.h>  #include <linux/delay.h>  #include <linux/slab.h> -#include <linux/init.h>  #include <linux/timer.h>  #include <linux/list.h>  #include <linux/interrupt.h> @@ -54,6 +53,7 @@   */  #ifdef CONFIG_ARCH_PXA  #include <mach/pxa25x-udc.h> +#include <mach/hardware.h>  #endif  #ifdef CONFIG_ARCH_LUBBOCK @@ -1193,6 +1193,7 @@ static void udc_reinit(struct pxa25x_udc *dev)  		ep->stopped = 0;  		INIT_LIST_HEAD (&ep->queue);  		ep->pio_irqs = 0; +		usb_ep_set_maxpacket_limit(&ep->ep, ep->ep.maxpacket);  	}  	/* the rest was statically initialized, and is read-only */ @@ -2054,7 +2055,7 @@ static struct pxa25x_udc memory = {  /*   *	probe - binds to the platform device   */ -static int __init pxa25x_udc_probe(struct platform_device *pdev) +static int pxa25x_udc_probe(struct platform_device *pdev)  {  	struct pxa25x_udc *dev = &memory;  	int retval, irq; @@ -2203,7 +2204,7 @@ static void pxa25x_udc_shutdown(struct platform_device *_dev)  	pullup_off();  } -static int __exit pxa25x_udc_remove(struct platform_device *pdev) +static int pxa25x_udc_remove(struct platform_device *pdev)  {  	struct pxa25x_udc *dev = platform_get_drvdata(pdev); @@ -2294,7 +2295,8 @@ static int pxa25x_udc_resume(struct platform_device *dev)  static struct platform_driver udc_driver = {  	.shutdown	= pxa25x_udc_shutdown, -	.remove		= __exit_p(pxa25x_udc_remove), +	.probe		= pxa25x_udc_probe, +	.remove		= pxa25x_udc_remove,  	.suspend	= pxa25x_udc_suspend,  	.resume		= pxa25x_udc_resume,  	.driver		= { @@ -2303,7 +2305,7 @@ static struct platform_driver udc_driver = {  	},  }; -module_platform_driver_probe(udc_driver, pxa25x_udc_probe); +module_platform_driver(udc_driver);  MODULE_DESCRIPTION(DRIVER_DESC);  MODULE_AUTHOR("Frank Becker, Robert Schwebel, David Brownell"); diff --git a/drivers/usb/gadget/pxa27x_udc.c b/drivers/usb/gadget/pxa27x_udc.c index 3c97da7760d..cdf4d678be9 100644 --- a/drivers/usb/gadget/pxa27x_udc.c +++ b/drivers/usb/gadget/pxa27x_udc.c @@ -1737,9 +1737,12 @@ static void udc_init_data(struct pxa_udc *dev)  	}  	/* USB endpoints init */ -	for (i = 1; i < NR_USB_ENDPOINTS; i++) +	for (i = 1; i < NR_USB_ENDPOINTS; i++) {  		list_add_tail(&dev->udc_usb_ep[i].usb_ep.ep_list,  				&dev->gadget.ep_list); +		usb_ep_set_maxpacket_limit(&dev->udc_usb_ep[i].usb_ep, +					   dev->udc_usb_ep[i].usb_ep.maxpacket); +	}  }  /** diff --git a/drivers/usb/gadget/r8a66597-udc.c b/drivers/usb/gadget/r8a66597-udc.c index 68be48d3340..b698a490cc7 100644 --- a/drivers/usb/gadget/r8a66597-udc.c +++ b/drivers/usb/gadget/r8a66597-udc.c @@ -1833,7 +1833,7 @@ static int __exit r8a66597_remove(struct platform_device *pdev)  	r8a66597_free_request(&r8a66597->ep[0].ep, r8a66597->ep0_req);  	if (r8a66597->pdata->on_chip) { -		clk_disable(r8a66597->clk); +		clk_disable_unprepare(r8a66597->clk);  		clk_put(r8a66597->clk);  	} @@ -1904,7 +1904,6 @@ static int __init r8a66597_probe(struct platform_device *pdev)  	r8a66597 = kzalloc(sizeof(struct r8a66597), GFP_KERNEL);  	if (r8a66597 == NULL) {  		ret = -ENOMEM; -		dev_err(&pdev->dev, "kzalloc error\n");  		goto clean_up;  	} @@ -1931,7 +1930,7 @@ static int __init r8a66597_probe(struct platform_device *pdev)  			ret = PTR_ERR(r8a66597->clk);  			goto clean_up;  		} -		clk_enable(r8a66597->clk); +		clk_prepare_enable(r8a66597->clk);  	}  	if (r8a66597->pdata->sudmac) { @@ -1964,9 +1963,9 @@ static int __init r8a66597_probe(struct platform_device *pdev)  		INIT_LIST_HEAD(&ep->queue);  		ep->ep.name = r8a66597_ep_name[i];  		ep->ep.ops = &r8a66597_ep_ops; -		ep->ep.maxpacket = 512; +		usb_ep_set_maxpacket_limit(&ep->ep, 512);  	} -	r8a66597->ep[0].ep.maxpacket = 64; +	usb_ep_set_maxpacket_limit(&r8a66597->ep[0].ep, 64);  	r8a66597->ep[0].pipenum = 0;  	r8a66597->ep[0].fifoaddr = CFIFO;  	r8a66597->ep[0].fifosel = CFIFOSEL; @@ -1996,7 +1995,7 @@ clean_up3:  	free_irq(irq, r8a66597);  clean_up2:  	if (r8a66597->pdata->on_chip) { -		clk_disable(r8a66597->clk); +		clk_disable_unprepare(r8a66597->clk);  		clk_put(r8a66597->clk);  	}  clean_up: diff --git a/drivers/usb/gadget/rndis.c b/drivers/usb/gadget/rndis.c index 9575085ded8..95d2324f697 100644 --- a/drivers/usb/gadget/rndis.c +++ b/drivers/usb/gadget/rndis.c @@ -25,7 +25,6 @@  #include <linux/moduleparam.h>  #include <linux/kernel.h>  #include <linux/errno.h> -#include <linux/init.h>  #include <linux/list.h>  #include <linux/proc_fs.h>  #include <linux/slab.h> @@ -36,6 +35,7 @@  #include <asm/byteorder.h>  #include <asm/unaligned.h> +#include "u_rndis.h"  #undef	VERBOSE_DEBUG @@ -761,7 +761,7 @@ int rndis_signal_connect(int configNr)  	return rndis_indicate_status_msg(configNr,  					  RNDIS_STATUS_MEDIA_CONNECT);  } -EXPORT_SYMBOL(rndis_signal_connect); +EXPORT_SYMBOL_GPL(rndis_signal_connect);  int rndis_signal_disconnect(int configNr)  { @@ -770,7 +770,7 @@ int rndis_signal_disconnect(int configNr)  	return rndis_indicate_status_msg(configNr,  					  RNDIS_STATUS_MEDIA_DISCONNECT);  } -EXPORT_SYMBOL(rndis_signal_disconnect); +EXPORT_SYMBOL_GPL(rndis_signal_disconnect);  void rndis_uninit(int configNr)  { @@ -785,13 +785,13 @@ void rndis_uninit(int configNr)  	while ((buf = rndis_get_next_response(configNr, &length)))  		rndis_free_response(configNr, buf);  } -EXPORT_SYMBOL(rndis_uninit); +EXPORT_SYMBOL_GPL(rndis_uninit);  void rndis_set_host_mac(int configNr, const u8 *addr)  {  	rndis_per_dev_params[configNr].host_mac = addr;  } -EXPORT_SYMBOL(rndis_set_host_mac); +EXPORT_SYMBOL_GPL(rndis_set_host_mac);  /*   * Message Parser @@ -874,7 +874,7 @@ int rndis_msg_parser(u8 configNr, u8 *buf)  	return -ENOTSUPP;  } -EXPORT_SYMBOL(rndis_msg_parser); +EXPORT_SYMBOL_GPL(rndis_msg_parser);  int rndis_register(void (*resp_avail)(void *v), void *v)  { @@ -896,7 +896,7 @@ int rndis_register(void (*resp_avail)(void *v), void *v)  	return -ENODEV;  } -EXPORT_SYMBOL(rndis_register); +EXPORT_SYMBOL_GPL(rndis_register);  void rndis_deregister(int configNr)  { @@ -905,7 +905,7 @@ void rndis_deregister(int configNr)  	if (configNr >= RNDIS_MAX_CONFIGS) return;  	rndis_per_dev_params[configNr].used = 0;  } -EXPORT_SYMBOL(rndis_deregister); +EXPORT_SYMBOL_GPL(rndis_deregister);  int rndis_set_param_dev(u8 configNr, struct net_device *dev, u16 *cdc_filter)  { @@ -919,7 +919,7 @@ int rndis_set_param_dev(u8 configNr, struct net_device *dev, u16 *cdc_filter)  	return 0;  } -EXPORT_SYMBOL(rndis_set_param_dev); +EXPORT_SYMBOL_GPL(rndis_set_param_dev);  int rndis_set_param_vendor(u8 configNr, u32 vendorID, const char *vendorDescr)  { @@ -932,7 +932,7 @@ int rndis_set_param_vendor(u8 configNr, u32 vendorID, const char *vendorDescr)  	return 0;  } -EXPORT_SYMBOL(rndis_set_param_vendor); +EXPORT_SYMBOL_GPL(rndis_set_param_vendor);  int rndis_set_param_medium(u8 configNr, u32 medium, u32 speed)  { @@ -944,7 +944,7 @@ int rndis_set_param_medium(u8 configNr, u32 medium, u32 speed)  	return 0;  } -EXPORT_SYMBOL(rndis_set_param_medium); +EXPORT_SYMBOL_GPL(rndis_set_param_medium);  void rndis_add_hdr(struct sk_buff *skb)  { @@ -959,7 +959,7 @@ void rndis_add_hdr(struct sk_buff *skb)  	header->DataOffset = cpu_to_le32(36);  	header->DataLength = cpu_to_le32(skb->len - sizeof(*header));  } -EXPORT_SYMBOL(rndis_add_hdr); +EXPORT_SYMBOL_GPL(rndis_add_hdr);  void rndis_free_response(int configNr, u8 *buf)  { @@ -976,7 +976,7 @@ void rndis_free_response(int configNr, u8 *buf)  		}  	}  } -EXPORT_SYMBOL(rndis_free_response); +EXPORT_SYMBOL_GPL(rndis_free_response);  u8 *rndis_get_next_response(int configNr, u32 *length)  { @@ -998,7 +998,7 @@ u8 *rndis_get_next_response(int configNr, u32 *length)  	return NULL;  } -EXPORT_SYMBOL(rndis_get_next_response); +EXPORT_SYMBOL_GPL(rndis_get_next_response);  static rndis_resp_t *rndis_add_response(int configNr, u32 length)  { @@ -1042,7 +1042,7 @@ int rndis_rm_hdr(struct gether *port,  	skb_queue_tail(list, skb);  	return 0;  } -EXPORT_SYMBOL(rndis_rm_hdr); +EXPORT_SYMBOL_GPL(rndis_rm_hdr);  #ifdef CONFIG_USB_GADGET_DEBUG_FILES @@ -1068,7 +1068,7 @@ static int rndis_proc_show(struct seq_file *m, void *v)  				s = "RNDIS_INITIALIZED"; break;  			 case RNDIS_DATA_INITIALIZED:  				s = "RNDIS_DATA_INITIALIZED"; break; -			}; s; }), +			} s; }),  			 param->medium,  			 (param->media_state) ? 0 : param->speed*100,  			 (param->media_state) ? "disconnected" : "connected", @@ -1142,7 +1142,7 @@ static struct proc_dir_entry *rndis_connect_state [RNDIS_MAX_CONFIGS];  #endif /* CONFIG_USB_GADGET_DEBUG_FILES */ -static int rndis_init(void) +int rndis_init(void)  {  	u8 i; @@ -1174,9 +1174,8 @@ static int rndis_init(void)  	return 0;  } -module_init(rndis_init); -static void rndis_exit(void) +void rndis_exit(void)  {  #ifdef CONFIG_USB_GADGET_DEBUG_FILES  	u8 i; @@ -1188,6 +1187,4 @@ static void rndis_exit(void)  	}  #endif  } -module_exit(rndis_exit); -MODULE_LICENSE("GPL"); diff --git a/drivers/usb/gadget/s3c-hsotg.c b/drivers/usb/gadget/s3c-hsotg.c deleted file mode 100644 index d69b36a99db..00000000000 --- a/drivers/usb/gadget/s3c-hsotg.c +++ /dev/null @@ -1,3677 +0,0 @@ -/** - * linux/drivers/usb/gadget/s3c-hsotg.c - * - * Copyright (c) 2011 Samsung Electronics Co., Ltd. - *		http://www.samsung.com - * - * Copyright 2008 Openmoko, Inc. - * Copyright 2008 Simtec Electronics - *      Ben Dooks <ben@simtec.co.uk> - *      http://armlinux.simtec.co.uk/ - * - * S3C USB2.0 High-speed / OtG driver - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/spinlock.h> -#include <linux/interrupt.h> -#include <linux/platform_device.h> -#include <linux/dma-mapping.h> -#include <linux/debugfs.h> -#include <linux/seq_file.h> -#include <linux/delay.h> -#include <linux/io.h> -#include <linux/slab.h> -#include <linux/clk.h> -#include <linux/regulator/consumer.h> -#include <linux/of_platform.h> - -#include <linux/usb/ch9.h> -#include <linux/usb/gadget.h> -#include <linux/usb/phy.h> -#include <linux/platform_data/s3c-hsotg.h> - -#include <mach/map.h> - -#include "s3c-hsotg.h" - -static const char * const s3c_hsotg_supply_names[] = { -	"vusb_d",		/* digital USB supply, 1.2V */ -	"vusb_a",		/* analog USB supply, 1.1V */ -}; - -/* - * EP0_MPS_LIMIT - * - * Unfortunately there seems to be a limit of the amount of data that can - * be transferred by IN transactions on EP0. This is either 127 bytes or 3 - * packets (which practically means 1 packet and 63 bytes of data) when the - * MPS is set to 64. - * - * This means if we are wanting to move >127 bytes of data, we need to - * split the transactions up, but just doing one packet at a time does - * not work (this may be an implicit DATA0 PID on first packet of the - * transaction) and doing 2 packets is outside the controller's limits. - * - * If we try to lower the MPS size for EP0, then no transfers work properly - * for EP0, and the system will fail basic enumeration. As no cause for this - * has currently been found, we cannot support any large IN transfers for - * EP0. - */ -#define EP0_MPS_LIMIT	64 - -struct s3c_hsotg; -struct s3c_hsotg_req; - -/** - * struct s3c_hsotg_ep - driver endpoint definition. - * @ep: The gadget layer representation of the endpoint. - * @name: The driver generated name for the endpoint. - * @queue: Queue of requests for this endpoint. - * @parent: Reference back to the parent device structure. - * @req: The current request that the endpoint is processing. This is - *       used to indicate an request has been loaded onto the endpoint - *       and has yet to be completed (maybe due to data move, or simply - *	 awaiting an ack from the core all the data has been completed). - * @debugfs: File entry for debugfs file for this endpoint. - * @lock: State lock to protect contents of endpoint. - * @dir_in: Set to true if this endpoint is of the IN direction, which - *	    means that it is sending data to the Host. - * @index: The index for the endpoint registers. - * @name: The name array passed to the USB core. - * @halted: Set if the endpoint has been halted. - * @periodic: Set if this is a periodic ep, such as Interrupt - * @sent_zlp: Set if we've sent a zero-length packet. - * @total_data: The total number of data bytes done. - * @fifo_size: The size of the FIFO (for periodic IN endpoints) - * @fifo_load: The amount of data loaded into the FIFO (periodic IN) - * @last_load: The offset of data for the last start of request. - * @size_loaded: The last loaded size for DxEPTSIZE for periodic IN - * - * This is the driver's state for each registered enpoint, allowing it - * to keep track of transactions that need doing. Each endpoint has a - * lock to protect the state, to try and avoid using an overall lock - * for the host controller as much as possible. - * - * For periodic IN endpoints, we have fifo_size and fifo_load to try - * and keep track of the amount of data in the periodic FIFO for each - * of these as we don't have a status register that tells us how much - * is in each of them. (note, this may actually be useless information - * as in shared-fifo mode periodic in acts like a single-frame packet - * buffer than a fifo) - */ -struct s3c_hsotg_ep { -	struct usb_ep		ep; -	struct list_head	queue; -	struct s3c_hsotg	*parent; -	struct s3c_hsotg_req	*req; -	struct dentry		*debugfs; - - -	unsigned long		total_data; -	unsigned int		size_loaded; -	unsigned int		last_load; -	unsigned int		fifo_load; -	unsigned short		fifo_size; - -	unsigned char		dir_in; -	unsigned char		index; - -	unsigned int		halted:1; -	unsigned int		periodic:1; -	unsigned int		sent_zlp:1; - -	char			name[10]; -}; - -/** - * struct s3c_hsotg - driver state. - * @dev: The parent device supplied to the probe function - * @driver: USB gadget driver - * @phy: The otg phy transceiver structure for phy control. - * @plat: The platform specific configuration data. This can be removed once - * all SoCs support usb transceiver. - * @regs: The memory area mapped for accessing registers. - * @irq: The IRQ number we are using - * @supplies: Definition of USB power supplies - * @dedicated_fifos: Set if the hardware has dedicated IN-EP fifos. - * @num_of_eps: Number of available EPs (excluding EP0) - * @debug_root: root directrory for debugfs. - * @debug_file: main status file for debugfs. - * @debug_fifo: FIFO status file for debugfs. - * @ep0_reply: Request used for ep0 reply. - * @ep0_buff: Buffer for EP0 reply data, if needed. - * @ctrl_buff: Buffer for EP0 control requests. - * @ctrl_req: Request for EP0 control packets. - * @setup: NAK management for EP0 SETUP - * @last_rst: Time of last reset - * @eps: The endpoints being supplied to the gadget framework - */ -struct s3c_hsotg { -	struct device		 *dev; -	struct usb_gadget_driver *driver; -	struct usb_phy		*phy; -	struct s3c_hsotg_plat	 *plat; - -	spinlock_t              lock; - -	void __iomem		*regs; -	int			irq; -	struct clk		*clk; - -	struct regulator_bulk_data supplies[ARRAY_SIZE(s3c_hsotg_supply_names)]; - -	unsigned int		dedicated_fifos:1; -	unsigned char           num_of_eps; - -	struct dentry		*debug_root; -	struct dentry		*debug_file; -	struct dentry		*debug_fifo; - -	struct usb_request	*ep0_reply; -	struct usb_request	*ctrl_req; -	u8			ep0_buff[8]; -	u8			ctrl_buff[8]; - -	struct usb_gadget	gadget; -	unsigned int		setup; -	unsigned long           last_rst; -	struct s3c_hsotg_ep	*eps; -}; - -/** - * struct s3c_hsotg_req - data transfer request - * @req: The USB gadget request - * @queue: The list of requests for the endpoint this is queued for. - * @in_progress: Has already had size/packets written to core - * @mapped: DMA buffer for this request has been mapped via dma_map_single(). - */ -struct s3c_hsotg_req { -	struct usb_request	req; -	struct list_head	queue; -	unsigned char		in_progress; -	unsigned char		mapped; -}; - -/* conversion functions */ -static inline struct s3c_hsotg_req *our_req(struct usb_request *req) -{ -	return container_of(req, struct s3c_hsotg_req, req); -} - -static inline struct s3c_hsotg_ep *our_ep(struct usb_ep *ep) -{ -	return container_of(ep, struct s3c_hsotg_ep, ep); -} - -static inline struct s3c_hsotg *to_hsotg(struct usb_gadget *gadget) -{ -	return container_of(gadget, struct s3c_hsotg, gadget); -} - -static inline void __orr32(void __iomem *ptr, u32 val) -{ -	writel(readl(ptr) | val, ptr); -} - -static inline void __bic32(void __iomem *ptr, u32 val) -{ -	writel(readl(ptr) & ~val, ptr); -} - -/* forward decleration of functions */ -static void s3c_hsotg_dump(struct s3c_hsotg *hsotg); - -/** - * using_dma - return the DMA status of the driver. - * @hsotg: The driver state. - * - * Return true if we're using DMA. - * - * Currently, we have the DMA support code worked into everywhere - * that needs it, but the AMBA DMA implementation in the hardware can - * only DMA from 32bit aligned addresses. This means that gadgets such - * as the CDC Ethernet cannot work as they often pass packets which are - * not 32bit aligned. - * - * Unfortunately the choice to use DMA or not is global to the controller - * and seems to be only settable when the controller is being put through - * a core reset. This means we either need to fix the gadgets to take - * account of DMA alignment, or add bounce buffers (yuerk). - * - * Until this issue is sorted out, we always return 'false'. - */ -static inline bool using_dma(struct s3c_hsotg *hsotg) -{ -	return false;	/* support is not complete */ -} - -/** - * s3c_hsotg_en_gsint - enable one or more of the general interrupt - * @hsotg: The device state - * @ints: A bitmask of the interrupts to enable - */ -static void s3c_hsotg_en_gsint(struct s3c_hsotg *hsotg, u32 ints) -{ -	u32 gsintmsk = readl(hsotg->regs + GINTMSK); -	u32 new_gsintmsk; - -	new_gsintmsk = gsintmsk | ints; - -	if (new_gsintmsk != gsintmsk) { -		dev_dbg(hsotg->dev, "gsintmsk now 0x%08x\n", new_gsintmsk); -		writel(new_gsintmsk, hsotg->regs + GINTMSK); -	} -} - -/** - * s3c_hsotg_disable_gsint - disable one or more of the general interrupt - * @hsotg: The device state - * @ints: A bitmask of the interrupts to enable - */ -static void s3c_hsotg_disable_gsint(struct s3c_hsotg *hsotg, u32 ints) -{ -	u32 gsintmsk = readl(hsotg->regs + GINTMSK); -	u32 new_gsintmsk; - -	new_gsintmsk = gsintmsk & ~ints; - -	if (new_gsintmsk != gsintmsk) -		writel(new_gsintmsk, hsotg->regs + GINTMSK); -} - -/** - * s3c_hsotg_ctrl_epint - enable/disable an endpoint irq - * @hsotg: The device state - * @ep: The endpoint index - * @dir_in: True if direction is in. - * @en: The enable value, true to enable - * - * Set or clear the mask for an individual endpoint's interrupt - * request. - */ -static void s3c_hsotg_ctrl_epint(struct s3c_hsotg *hsotg, -				 unsigned int ep, unsigned int dir_in, -				 unsigned int en) -{ -	unsigned long flags; -	u32 bit = 1 << ep; -	u32 daint; - -	if (!dir_in) -		bit <<= 16; - -	local_irq_save(flags); -	daint = readl(hsotg->regs + DAINTMSK); -	if (en) -		daint |= bit; -	else -		daint &= ~bit; -	writel(daint, hsotg->regs + DAINTMSK); -	local_irq_restore(flags); -} - -/** - * s3c_hsotg_init_fifo - initialise non-periodic FIFOs - * @hsotg: The device instance. - */ -static void s3c_hsotg_init_fifo(struct s3c_hsotg *hsotg) -{ -	unsigned int ep; -	unsigned int addr; -	unsigned int size; -	int timeout; -	u32 val; - -	/* set FIFO sizes to 2048/1024 */ - -	writel(2048, hsotg->regs + GRXFSIZ); -	writel(GNPTXFSIZ_NPTxFStAddr(2048) | -	       GNPTXFSIZ_NPTxFDep(1024), -	       hsotg->regs + GNPTXFSIZ); - -	/* -	 * arange all the rest of the TX FIFOs, as some versions of this -	 * block have overlapping default addresses. This also ensures -	 * that if the settings have been changed, then they are set to -	 * known values. -	 */ - -	/* start at the end of the GNPTXFSIZ, rounded up */ -	addr = 2048 + 1024; -	size = 768; - -	/* -	 * currently we allocate TX FIFOs for all possible endpoints, -	 * and assume that they are all the same size. -	 */ - -	for (ep = 1; ep <= 15; ep++) { -		val = addr; -		val |= size << DPTXFSIZn_DPTxFSize_SHIFT; -		addr += size; - -		writel(val, hsotg->regs + DPTXFSIZn(ep)); -	} - -	/* -	 * according to p428 of the design guide, we need to ensure that -	 * all fifos are flushed before continuing -	 */ - -	writel(GRSTCTL_TxFNum(0x10) | GRSTCTL_TxFFlsh | -	       GRSTCTL_RxFFlsh, hsotg->regs + GRSTCTL); - -	/* wait until the fifos are both flushed */ -	timeout = 100; -	while (1) { -		val = readl(hsotg->regs + GRSTCTL); - -		if ((val & (GRSTCTL_TxFFlsh | GRSTCTL_RxFFlsh)) == 0) -			break; - -		if (--timeout == 0) { -			dev_err(hsotg->dev, -				"%s: timeout flushing fifos (GRSTCTL=%08x)\n", -				__func__, val); -		} - -		udelay(1); -	} - -	dev_dbg(hsotg->dev, "FIFOs reset, timeout at %d\n", timeout); -} - -/** - * @ep: USB endpoint to allocate request for. - * @flags: Allocation flags - * - * Allocate a new USB request structure appropriate for the specified endpoint - */ -static struct usb_request *s3c_hsotg_ep_alloc_request(struct usb_ep *ep, -						      gfp_t flags) -{ -	struct s3c_hsotg_req *req; - -	req = kzalloc(sizeof(struct s3c_hsotg_req), flags); -	if (!req) -		return NULL; - -	INIT_LIST_HEAD(&req->queue); - -	return &req->req; -} - -/** - * is_ep_periodic - return true if the endpoint is in periodic mode. - * @hs_ep: The endpoint to query. - * - * Returns true if the endpoint is in periodic mode, meaning it is being - * used for an Interrupt or ISO transfer. - */ -static inline int is_ep_periodic(struct s3c_hsotg_ep *hs_ep) -{ -	return hs_ep->periodic; -} - -/** - * s3c_hsotg_unmap_dma - unmap the DMA memory being used for the request - * @hsotg: The device state. - * @hs_ep: The endpoint for the request - * @hs_req: The request being processed. - * - * This is the reverse of s3c_hsotg_map_dma(), called for the completion - * of a request to ensure the buffer is ready for access by the caller. - */ -static void s3c_hsotg_unmap_dma(struct s3c_hsotg *hsotg, -				struct s3c_hsotg_ep *hs_ep, -				struct s3c_hsotg_req *hs_req) -{ -	struct usb_request *req = &hs_req->req; - -	/* ignore this if we're not moving any data */ -	if (hs_req->req.length == 0) -		return; - -	usb_gadget_unmap_request(&hsotg->gadget, req, hs_ep->dir_in); -} - -/** - * s3c_hsotg_write_fifo - write packet Data to the TxFIFO - * @hsotg: The controller state. - * @hs_ep: The endpoint we're going to write for. - * @hs_req: The request to write data for. - * - * This is called when the TxFIFO has some space in it to hold a new - * transmission and we have something to give it. The actual setup of - * the data size is done elsewhere, so all we have to do is to actually - * write the data. - * - * The return value is zero if there is more space (or nothing was done) - * otherwise -ENOSPC is returned if the FIFO space was used up. - * - * This routine is only needed for PIO - */ -static int s3c_hsotg_write_fifo(struct s3c_hsotg *hsotg, -				struct s3c_hsotg_ep *hs_ep, -				struct s3c_hsotg_req *hs_req) -{ -	bool periodic = is_ep_periodic(hs_ep); -	u32 gnptxsts = readl(hsotg->regs + GNPTXSTS); -	int buf_pos = hs_req->req.actual; -	int to_write = hs_ep->size_loaded; -	void *data; -	int can_write; -	int pkt_round; - -	to_write -= (buf_pos - hs_ep->last_load); - -	/* if there's nothing to write, get out early */ -	if (to_write == 0) -		return 0; - -	if (periodic && !hsotg->dedicated_fifos) { -		u32 epsize = readl(hsotg->regs + DIEPTSIZ(hs_ep->index)); -		int size_left; -		int size_done; - -		/* -		 * work out how much data was loaded so we can calculate -		 * how much data is left in the fifo. -		 */ - -		size_left = DxEPTSIZ_XferSize_GET(epsize); - -		/* -		 * if shared fifo, we cannot write anything until the -		 * previous data has been completely sent. -		 */ -		if (hs_ep->fifo_load != 0) { -			s3c_hsotg_en_gsint(hsotg, GINTSTS_PTxFEmp); -			return -ENOSPC; -		} - -		dev_dbg(hsotg->dev, "%s: left=%d, load=%d, fifo=%d, size %d\n", -			__func__, size_left, -			hs_ep->size_loaded, hs_ep->fifo_load, hs_ep->fifo_size); - -		/* how much of the data has moved */ -		size_done = hs_ep->size_loaded - size_left; - -		/* how much data is left in the fifo */ -		can_write = hs_ep->fifo_load - size_done; -		dev_dbg(hsotg->dev, "%s: => can_write1=%d\n", -			__func__, can_write); - -		can_write = hs_ep->fifo_size - can_write; -		dev_dbg(hsotg->dev, "%s: => can_write2=%d\n", -			__func__, can_write); - -		if (can_write <= 0) { -			s3c_hsotg_en_gsint(hsotg, GINTSTS_PTxFEmp); -			return -ENOSPC; -		} -	} else if (hsotg->dedicated_fifos && hs_ep->index != 0) { -		can_write = readl(hsotg->regs + DTXFSTS(hs_ep->index)); - -		can_write &= 0xffff; -		can_write *= 4; -	} else { -		if (GNPTXSTS_NPTxQSpcAvail_GET(gnptxsts) == 0) { -			dev_dbg(hsotg->dev, -				"%s: no queue slots available (0x%08x)\n", -				__func__, gnptxsts); - -			s3c_hsotg_en_gsint(hsotg, GINTSTS_NPTxFEmp); -			return -ENOSPC; -		} - -		can_write = GNPTXSTS_NPTxFSpcAvail_GET(gnptxsts); -		can_write *= 4;	/* fifo size is in 32bit quantities. */ -	} - -	dev_dbg(hsotg->dev, "%s: GNPTXSTS=%08x, can=%d, to=%d, mps %d\n", -		 __func__, gnptxsts, can_write, to_write, hs_ep->ep.maxpacket); - -	/* -	 * limit to 512 bytes of data, it seems at least on the non-periodic -	 * FIFO, requests of >512 cause the endpoint to get stuck with a -	 * fragment of the end of the transfer in it. -	 */ -	if (can_write > 512) -		can_write = 512; - -	/* -	 * limit the write to one max-packet size worth of data, but allow -	 * the transfer to return that it did not run out of fifo space -	 * doing it. -	 */ -	if (to_write > hs_ep->ep.maxpacket) { -		to_write = hs_ep->ep.maxpacket; - -		s3c_hsotg_en_gsint(hsotg, -				   periodic ? GINTSTS_PTxFEmp : -				   GINTSTS_NPTxFEmp); -	} - -	/* see if we can write data */ - -	if (to_write > can_write) { -		to_write = can_write; -		pkt_round = to_write % hs_ep->ep.maxpacket; - -		/* -		 * Round the write down to an -		 * exact number of packets. -		 * -		 * Note, we do not currently check to see if we can ever -		 * write a full packet or not to the FIFO. -		 */ - -		if (pkt_round) -			to_write -= pkt_round; - -		/* -		 * enable correct FIFO interrupt to alert us when there -		 * is more room left. -		 */ - -		s3c_hsotg_en_gsint(hsotg, -				   periodic ? GINTSTS_PTxFEmp : -				   GINTSTS_NPTxFEmp); -	} - -	dev_dbg(hsotg->dev, "write %d/%d, can_write %d, done %d\n", -		 to_write, hs_req->req.length, can_write, buf_pos); - -	if (to_write <= 0) -		return -ENOSPC; - -	hs_req->req.actual = buf_pos + to_write; -	hs_ep->total_data += to_write; - -	if (periodic) -		hs_ep->fifo_load += to_write; - -	to_write = DIV_ROUND_UP(to_write, 4); -	data = hs_req->req.buf + buf_pos; - -	writesl(hsotg->regs + EPFIFO(hs_ep->index), data, to_write); - -	return (to_write >= can_write) ? -ENOSPC : 0; -} - -/** - * get_ep_limit - get the maximum data legnth for this endpoint - * @hs_ep: The endpoint - * - * Return the maximum data that can be queued in one go on a given endpoint - * so that transfers that are too long can be split. - */ -static unsigned get_ep_limit(struct s3c_hsotg_ep *hs_ep) -{ -	int index = hs_ep->index; -	unsigned maxsize; -	unsigned maxpkt; - -	if (index != 0) { -		maxsize = DxEPTSIZ_XferSize_LIMIT + 1; -		maxpkt = DxEPTSIZ_PktCnt_LIMIT + 1; -	} else { -		maxsize = 64+64; -		if (hs_ep->dir_in) -			maxpkt = DIEPTSIZ0_PktCnt_LIMIT + 1; -		else -			maxpkt = 2; -	} - -	/* we made the constant loading easier above by using +1 */ -	maxpkt--; -	maxsize--; - -	/* -	 * constrain by packet count if maxpkts*pktsize is greater -	 * than the length register size. -	 */ - -	if ((maxpkt * hs_ep->ep.maxpacket) < maxsize) -		maxsize = maxpkt * hs_ep->ep.maxpacket; - -	return maxsize; -} - -/** - * s3c_hsotg_start_req - start a USB request from an endpoint's queue - * @hsotg: The controller state. - * @hs_ep: The endpoint to process a request for - * @hs_req: The request to start. - * @continuing: True if we are doing more for the current request. - * - * Start the given request running by setting the endpoint registers - * appropriately, and writing any data to the FIFOs. - */ -static void s3c_hsotg_start_req(struct s3c_hsotg *hsotg, -				struct s3c_hsotg_ep *hs_ep, -				struct s3c_hsotg_req *hs_req, -				bool continuing) -{ -	struct usb_request *ureq = &hs_req->req; -	int index = hs_ep->index; -	int dir_in = hs_ep->dir_in; -	u32 epctrl_reg; -	u32 epsize_reg; -	u32 epsize; -	u32 ctrl; -	unsigned length; -	unsigned packets; -	unsigned maxreq; - -	if (index != 0) { -		if (hs_ep->req && !continuing) { -			dev_err(hsotg->dev, "%s: active request\n", __func__); -			WARN_ON(1); -			return; -		} else if (hs_ep->req != hs_req && continuing) { -			dev_err(hsotg->dev, -				"%s: continue different req\n", __func__); -			WARN_ON(1); -			return; -		} -	} - -	epctrl_reg = dir_in ? DIEPCTL(index) : DOEPCTL(index); -	epsize_reg = dir_in ? DIEPTSIZ(index) : DOEPTSIZ(index); - -	dev_dbg(hsotg->dev, "%s: DxEPCTL=0x%08x, ep %d, dir %s\n", -		__func__, readl(hsotg->regs + epctrl_reg), index, -		hs_ep->dir_in ? "in" : "out"); - -	/* If endpoint is stalled, we will restart request later */ -	ctrl = readl(hsotg->regs + epctrl_reg); - -	if (ctrl & DxEPCTL_Stall) { -		dev_warn(hsotg->dev, "%s: ep%d is stalled\n", __func__, index); -		return; -	} - -	length = ureq->length - ureq->actual; -	dev_dbg(hsotg->dev, "ureq->length:%d ureq->actual:%d\n", -		ureq->length, ureq->actual); -	if (0) -		dev_dbg(hsotg->dev, -			"REQ buf %p len %d dma 0x%08x noi=%d zp=%d snok=%d\n", -			ureq->buf, length, ureq->dma, -			ureq->no_interrupt, ureq->zero, ureq->short_not_ok); - -	maxreq = get_ep_limit(hs_ep); -	if (length > maxreq) { -		int round = maxreq % hs_ep->ep.maxpacket; - -		dev_dbg(hsotg->dev, "%s: length %d, max-req %d, r %d\n", -			__func__, length, maxreq, round); - -		/* round down to multiple of packets */ -		if (round) -			maxreq -= round; - -		length = maxreq; -	} - -	if (length) -		packets = DIV_ROUND_UP(length, hs_ep->ep.maxpacket); -	else -		packets = 1;	/* send one packet if length is zero. */ - -	if (dir_in && index != 0) -		epsize = DxEPTSIZ_MC(1); -	else -		epsize = 0; - -	if (index != 0 && ureq->zero) { -		/* -		 * test for the packets being exactly right for the -		 * transfer -		 */ - -		if (length == (packets * hs_ep->ep.maxpacket)) -			packets++; -	} - -	epsize |= DxEPTSIZ_PktCnt(packets); -	epsize |= DxEPTSIZ_XferSize(length); - -	dev_dbg(hsotg->dev, "%s: %d@%d/%d, 0x%08x => 0x%08x\n", -		__func__, packets, length, ureq->length, epsize, epsize_reg); - -	/* store the request as the current one we're doing */ -	hs_ep->req = hs_req; - -	/* write size / packets */ -	writel(epsize, hsotg->regs + epsize_reg); - -	if (using_dma(hsotg) && !continuing) { -		unsigned int dma_reg; - -		/* -		 * write DMA address to control register, buffer already -		 * synced by s3c_hsotg_ep_queue(). -		 */ - -		dma_reg = dir_in ? DIEPDMA(index) : DOEPDMA(index); -		writel(ureq->dma, hsotg->regs + dma_reg); - -		dev_dbg(hsotg->dev, "%s: 0x%08x => 0x%08x\n", -			__func__, ureq->dma, dma_reg); -	} - -	ctrl |= DxEPCTL_EPEna;	/* ensure ep enabled */ -	ctrl |= DxEPCTL_USBActEp; - -	dev_dbg(hsotg->dev, "setup req:%d\n", hsotg->setup); - -	/* For Setup request do not clear NAK */ -	if (hsotg->setup && index == 0) -		hsotg->setup = 0; -	else -		ctrl |= DxEPCTL_CNAK;	/* clear NAK set by core */ - - -	dev_dbg(hsotg->dev, "%s: DxEPCTL=0x%08x\n", __func__, ctrl); -	writel(ctrl, hsotg->regs + epctrl_reg); - -	/* -	 * set these, it seems that DMA support increments past the end -	 * of the packet buffer so we need to calculate the length from -	 * this information. -	 */ -	hs_ep->size_loaded = length; -	hs_ep->last_load = ureq->actual; - -	if (dir_in && !using_dma(hsotg)) { -		/* set these anyway, we may need them for non-periodic in */ -		hs_ep->fifo_load = 0; - -		s3c_hsotg_write_fifo(hsotg, hs_ep, hs_req); -	} - -	/* -	 * clear the INTknTXFEmpMsk when we start request, more as a aide -	 * to debugging to see what is going on. -	 */ -	if (dir_in) -		writel(DIEPMSK_INTknTXFEmpMsk, -		       hsotg->regs + DIEPINT(index)); - -	/* -	 * Note, trying to clear the NAK here causes problems with transmit -	 * on the S3C6400 ending up with the TXFIFO becoming full. -	 */ - -	/* check ep is enabled */ -	if (!(readl(hsotg->regs + epctrl_reg) & DxEPCTL_EPEna)) -		dev_warn(hsotg->dev, -			 "ep%d: failed to become enabled (DxEPCTL=0x%08x)?\n", -			 index, readl(hsotg->regs + epctrl_reg)); - -	dev_dbg(hsotg->dev, "%s: DxEPCTL=0x%08x\n", -		__func__, readl(hsotg->regs + epctrl_reg)); -} - -/** - * s3c_hsotg_map_dma - map the DMA memory being used for the request - * @hsotg: The device state. - * @hs_ep: The endpoint the request is on. - * @req: The request being processed. - * - * We've been asked to queue a request, so ensure that the memory buffer - * is correctly setup for DMA. If we've been passed an extant DMA address - * then ensure the buffer has been synced to memory. If our buffer has no - * DMA memory, then we map the memory and mark our request to allow us to - * cleanup on completion. - */ -static int s3c_hsotg_map_dma(struct s3c_hsotg *hsotg, -			     struct s3c_hsotg_ep *hs_ep, -			     struct usb_request *req) -{ -	struct s3c_hsotg_req *hs_req = our_req(req); -	int ret; - -	/* if the length is zero, ignore the DMA data */ -	if (hs_req->req.length == 0) -		return 0; - -	ret = usb_gadget_map_request(&hsotg->gadget, req, hs_ep->dir_in); -	if (ret) -		goto dma_error; - -	return 0; - -dma_error: -	dev_err(hsotg->dev, "%s: failed to map buffer %p, %d bytes\n", -		__func__, req->buf, req->length); - -	return -EIO; -} - -static int s3c_hsotg_ep_queue(struct usb_ep *ep, struct usb_request *req, -			      gfp_t gfp_flags) -{ -	struct s3c_hsotg_req *hs_req = our_req(req); -	struct s3c_hsotg_ep *hs_ep = our_ep(ep); -	struct s3c_hsotg *hs = hs_ep->parent; -	bool first; - -	dev_dbg(hs->dev, "%s: req %p: %d@%p, noi=%d, zero=%d, snok=%d\n", -		ep->name, req, req->length, req->buf, req->no_interrupt, -		req->zero, req->short_not_ok); - -	/* initialise status of the request */ -	INIT_LIST_HEAD(&hs_req->queue); -	req->actual = 0; -	req->status = -EINPROGRESS; - -	/* if we're using DMA, sync the buffers as necessary */ -	if (using_dma(hs)) { -		int ret = s3c_hsotg_map_dma(hs, hs_ep, req); -		if (ret) -			return ret; -	} - -	first = list_empty(&hs_ep->queue); -	list_add_tail(&hs_req->queue, &hs_ep->queue); - -	if (first) -		s3c_hsotg_start_req(hs, hs_ep, hs_req, false); - -	return 0; -} - -static int s3c_hsotg_ep_queue_lock(struct usb_ep *ep, struct usb_request *req, -			      gfp_t gfp_flags) -{ -	struct s3c_hsotg_ep *hs_ep = our_ep(ep); -	struct s3c_hsotg *hs = hs_ep->parent; -	unsigned long flags = 0; -	int ret = 0; - -	spin_lock_irqsave(&hs->lock, flags); -	ret = s3c_hsotg_ep_queue(ep, req, gfp_flags); -	spin_unlock_irqrestore(&hs->lock, flags); - -	return ret; -} - -static void s3c_hsotg_ep_free_request(struct usb_ep *ep, -				      struct usb_request *req) -{ -	struct s3c_hsotg_req *hs_req = our_req(req); - -	kfree(hs_req); -} - -/** - * s3c_hsotg_complete_oursetup - setup completion callback - * @ep: The endpoint the request was on. - * @req: The request completed. - * - * Called on completion of any requests the driver itself - * submitted that need cleaning up. - */ -static void s3c_hsotg_complete_oursetup(struct usb_ep *ep, -					struct usb_request *req) -{ -	struct s3c_hsotg_ep *hs_ep = our_ep(ep); -	struct s3c_hsotg *hsotg = hs_ep->parent; - -	dev_dbg(hsotg->dev, "%s: ep %p, req %p\n", __func__, ep, req); - -	s3c_hsotg_ep_free_request(ep, req); -} - -/** - * ep_from_windex - convert control wIndex value to endpoint - * @hsotg: The driver state. - * @windex: The control request wIndex field (in host order). - * - * Convert the given wIndex into a pointer to an driver endpoint - * structure, or return NULL if it is not a valid endpoint. - */ -static struct s3c_hsotg_ep *ep_from_windex(struct s3c_hsotg *hsotg, -					   u32 windex) -{ -	struct s3c_hsotg_ep *ep = &hsotg->eps[windex & 0x7F]; -	int dir = (windex & USB_DIR_IN) ? 1 : 0; -	int idx = windex & 0x7F; - -	if (windex >= 0x100) -		return NULL; - -	if (idx > hsotg->num_of_eps) -		return NULL; - -	if (idx && ep->dir_in != dir) -		return NULL; - -	return ep; -} - -/** - * s3c_hsotg_send_reply - send reply to control request - * @hsotg: The device state - * @ep: Endpoint 0 - * @buff: Buffer for request - * @length: Length of reply. - * - * Create a request and queue it on the given endpoint. This is useful as - * an internal method of sending replies to certain control requests, etc. - */ -static int s3c_hsotg_send_reply(struct s3c_hsotg *hsotg, -				struct s3c_hsotg_ep *ep, -				void *buff, -				int length) -{ -	struct usb_request *req; -	int ret; - -	dev_dbg(hsotg->dev, "%s: buff %p, len %d\n", __func__, buff, length); - -	req = s3c_hsotg_ep_alloc_request(&ep->ep, GFP_ATOMIC); -	hsotg->ep0_reply = req; -	if (!req) { -		dev_warn(hsotg->dev, "%s: cannot alloc req\n", __func__); -		return -ENOMEM; -	} - -	req->buf = hsotg->ep0_buff; -	req->length = length; -	req->zero = 1; /* always do zero-length final transfer */ -	req->complete = s3c_hsotg_complete_oursetup; - -	if (length) -		memcpy(req->buf, buff, length); -	else -		ep->sent_zlp = 1; - -	ret = s3c_hsotg_ep_queue(&ep->ep, req, GFP_ATOMIC); -	if (ret) { -		dev_warn(hsotg->dev, "%s: cannot queue req\n", __func__); -		return ret; -	} - -	return 0; -} - -/** - * s3c_hsotg_process_req_status - process request GET_STATUS - * @hsotg: The device state - * @ctrl: USB control request - */ -static int s3c_hsotg_process_req_status(struct s3c_hsotg *hsotg, -					struct usb_ctrlrequest *ctrl) -{ -	struct s3c_hsotg_ep *ep0 = &hsotg->eps[0]; -	struct s3c_hsotg_ep *ep; -	__le16 reply; -	int ret; - -	dev_dbg(hsotg->dev, "%s: USB_REQ_GET_STATUS\n", __func__); - -	if (!ep0->dir_in) { -		dev_warn(hsotg->dev, "%s: direction out?\n", __func__); -		return -EINVAL; -	} - -	switch (ctrl->bRequestType & USB_RECIP_MASK) { -	case USB_RECIP_DEVICE: -		reply = cpu_to_le16(0); /* bit 0 => self powered, -					 * bit 1 => remote wakeup */ -		break; - -	case USB_RECIP_INTERFACE: -		/* currently, the data result should be zero */ -		reply = cpu_to_le16(0); -		break; - -	case USB_RECIP_ENDPOINT: -		ep = ep_from_windex(hsotg, le16_to_cpu(ctrl->wIndex)); -		if (!ep) -			return -ENOENT; - -		reply = cpu_to_le16(ep->halted ? 1 : 0); -		break; - -	default: -		return 0; -	} - -	if (le16_to_cpu(ctrl->wLength) != 2) -		return -EINVAL; - -	ret = s3c_hsotg_send_reply(hsotg, ep0, &reply, 2); -	if (ret) { -		dev_err(hsotg->dev, "%s: failed to send reply\n", __func__); -		return ret; -	} - -	return 1; -} - -static int s3c_hsotg_ep_sethalt(struct usb_ep *ep, int value); - -/** - * get_ep_head - return the first request on the endpoint - * @hs_ep: The controller endpoint to get - * - * Get the first request on the endpoint. - */ -static struct s3c_hsotg_req *get_ep_head(struct s3c_hsotg_ep *hs_ep) -{ -	if (list_empty(&hs_ep->queue)) -		return NULL; - -	return list_first_entry(&hs_ep->queue, struct s3c_hsotg_req, queue); -} - -/** - * s3c_hsotg_process_req_featire - process request {SET,CLEAR}_FEATURE - * @hsotg: The device state - * @ctrl: USB control request - */ -static int s3c_hsotg_process_req_feature(struct s3c_hsotg *hsotg, -					 struct usb_ctrlrequest *ctrl) -{ -	struct s3c_hsotg_ep *ep0 = &hsotg->eps[0]; -	struct s3c_hsotg_req *hs_req; -	bool restart; -	bool set = (ctrl->bRequest == USB_REQ_SET_FEATURE); -	struct s3c_hsotg_ep *ep; -	int ret; - -	dev_dbg(hsotg->dev, "%s: %s_FEATURE\n", -		__func__, set ? "SET" : "CLEAR"); - -	if (ctrl->bRequestType == USB_RECIP_ENDPOINT) { -		ep = ep_from_windex(hsotg, le16_to_cpu(ctrl->wIndex)); -		if (!ep) { -			dev_dbg(hsotg->dev, "%s: no endpoint for 0x%04x\n", -				__func__, le16_to_cpu(ctrl->wIndex)); -			return -ENOENT; -		} - -		switch (le16_to_cpu(ctrl->wValue)) { -		case USB_ENDPOINT_HALT: -			s3c_hsotg_ep_sethalt(&ep->ep, set); - -			ret = s3c_hsotg_send_reply(hsotg, ep0, NULL, 0); -			if (ret) { -				dev_err(hsotg->dev, -					"%s: failed to send reply\n", __func__); -				return ret; -			} - -			if (!set) { -				/* -				 * If we have request in progress, -				 * then complete it -				 */ -				if (ep->req) { -					hs_req = ep->req; -					ep->req = NULL; -					list_del_init(&hs_req->queue); -					hs_req->req.complete(&ep->ep, -							     &hs_req->req); -				} - -				/* If we have pending request, then start it */ -				restart = !list_empty(&ep->queue); -				if (restart) { -					hs_req = get_ep_head(ep); -					s3c_hsotg_start_req(hsotg, ep, -							    hs_req, false); -				} -			} - -			break; - -		default: -			return -ENOENT; -		} -	} else -		return -ENOENT;  /* currently only deal with endpoint */ - -	return 1; -} - -/** - * s3c_hsotg_process_control - process a control request - * @hsotg: The device state - * @ctrl: The control request received - * - * The controller has received the SETUP phase of a control request, and - * needs to work out what to do next (and whether to pass it on to the - * gadget driver). - */ -static void s3c_hsotg_process_control(struct s3c_hsotg *hsotg, -				      struct usb_ctrlrequest *ctrl) -{ -	struct s3c_hsotg_ep *ep0 = &hsotg->eps[0]; -	int ret = 0; -	u32 dcfg; - -	ep0->sent_zlp = 0; - -	dev_dbg(hsotg->dev, "ctrl Req=%02x, Type=%02x, V=%04x, L=%04x\n", -		 ctrl->bRequest, ctrl->bRequestType, -		 ctrl->wValue, ctrl->wLength); - -	/* -	 * record the direction of the request, for later use when enquing -	 * packets onto EP0. -	 */ - -	ep0->dir_in = (ctrl->bRequestType & USB_DIR_IN) ? 1 : 0; -	dev_dbg(hsotg->dev, "ctrl: dir_in=%d\n", ep0->dir_in); - -	/* -	 * if we've no data with this request, then the last part of the -	 * transaction is going to implicitly be IN. -	 */ -	if (ctrl->wLength == 0) -		ep0->dir_in = 1; - -	if ((ctrl->bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD) { -		switch (ctrl->bRequest) { -		case USB_REQ_SET_ADDRESS: -			dcfg = readl(hsotg->regs + DCFG); -			dcfg &= ~DCFG_DevAddr_MASK; -			dcfg |= ctrl->wValue << DCFG_DevAddr_SHIFT; -			writel(dcfg, hsotg->regs + DCFG); - -			dev_info(hsotg->dev, "new address %d\n", ctrl->wValue); - -			ret = s3c_hsotg_send_reply(hsotg, ep0, NULL, 0); -			return; - -		case USB_REQ_GET_STATUS: -			ret = s3c_hsotg_process_req_status(hsotg, ctrl); -			break; - -		case USB_REQ_CLEAR_FEATURE: -		case USB_REQ_SET_FEATURE: -			ret = s3c_hsotg_process_req_feature(hsotg, ctrl); -			break; -		} -	} - -	/* as a fallback, try delivering it to the driver to deal with */ - -	if (ret == 0 && hsotg->driver) { -		ret = hsotg->driver->setup(&hsotg->gadget, ctrl); -		if (ret < 0) -			dev_dbg(hsotg->dev, "driver->setup() ret %d\n", ret); -	} - -	/* -	 * the request is either unhandlable, or is not formatted correctly -	 * so respond with a STALL for the status stage to indicate failure. -	 */ - -	if (ret < 0) { -		u32 reg; -		u32 ctrl; - -		dev_dbg(hsotg->dev, "ep0 stall (dir=%d)\n", ep0->dir_in); -		reg = (ep0->dir_in) ? DIEPCTL0 : DOEPCTL0; - -		/* -		 * DxEPCTL_Stall will be cleared by EP once it has -		 * taken effect, so no need to clear later. -		 */ - -		ctrl = readl(hsotg->regs + reg); -		ctrl |= DxEPCTL_Stall; -		ctrl |= DxEPCTL_CNAK; -		writel(ctrl, hsotg->regs + reg); - -		dev_dbg(hsotg->dev, -			"written DxEPCTL=0x%08x to %08x (DxEPCTL=0x%08x)\n", -			ctrl, reg, readl(hsotg->regs + reg)); - -		/* -		 * don't believe we need to anything more to get the EP -		 * to reply with a STALL packet -		 */ -	} -} - -static void s3c_hsotg_enqueue_setup(struct s3c_hsotg *hsotg); - -/** - * s3c_hsotg_complete_setup - completion of a setup transfer - * @ep: The endpoint the request was on. - * @req: The request completed. - * - * Called on completion of any requests the driver itself submitted for - * EP0 setup packets - */ -static void s3c_hsotg_complete_setup(struct usb_ep *ep, -				     struct usb_request *req) -{ -	struct s3c_hsotg_ep *hs_ep = our_ep(ep); -	struct s3c_hsotg *hsotg = hs_ep->parent; - -	if (req->status < 0) { -		dev_dbg(hsotg->dev, "%s: failed %d\n", __func__, req->status); -		return; -	} - -	if (req->actual == 0) -		s3c_hsotg_enqueue_setup(hsotg); -	else -		s3c_hsotg_process_control(hsotg, req->buf); -} - -/** - * s3c_hsotg_enqueue_setup - start a request for EP0 packets - * @hsotg: The device state. - * - * Enqueue a request on EP0 if necessary to received any SETUP packets - * received from the host. - */ -static void s3c_hsotg_enqueue_setup(struct s3c_hsotg *hsotg) -{ -	struct usb_request *req = hsotg->ctrl_req; -	struct s3c_hsotg_req *hs_req = our_req(req); -	int ret; - -	dev_dbg(hsotg->dev, "%s: queueing setup request\n", __func__); - -	req->zero = 0; -	req->length = 8; -	req->buf = hsotg->ctrl_buff; -	req->complete = s3c_hsotg_complete_setup; - -	if (!list_empty(&hs_req->queue)) { -		dev_dbg(hsotg->dev, "%s already queued???\n", __func__); -		return; -	} - -	hsotg->eps[0].dir_in = 0; - -	ret = s3c_hsotg_ep_queue(&hsotg->eps[0].ep, req, GFP_ATOMIC); -	if (ret < 0) { -		dev_err(hsotg->dev, "%s: failed queue (%d)\n", __func__, ret); -		/* -		 * Don't think there's much we can do other than watch the -		 * driver fail. -		 */ -	} -} - -/** - * s3c_hsotg_complete_request - complete a request given to us - * @hsotg: The device state. - * @hs_ep: The endpoint the request was on. - * @hs_req: The request to complete. - * @result: The result code (0 => Ok, otherwise errno) - * - * The given request has finished, so call the necessary completion - * if it has one and then look to see if we can start a new request - * on the endpoint. - * - * Note, expects the ep to already be locked as appropriate. - */ -static void s3c_hsotg_complete_request(struct s3c_hsotg *hsotg, -				       struct s3c_hsotg_ep *hs_ep, -				       struct s3c_hsotg_req *hs_req, -				       int result) -{ -	bool restart; - -	if (!hs_req) { -		dev_dbg(hsotg->dev, "%s: nothing to complete?\n", __func__); -		return; -	} - -	dev_dbg(hsotg->dev, "complete: ep %p %s, req %p, %d => %p\n", -		hs_ep, hs_ep->ep.name, hs_req, result, hs_req->req.complete); - -	/* -	 * only replace the status if we've not already set an error -	 * from a previous transaction -	 */ - -	if (hs_req->req.status == -EINPROGRESS) -		hs_req->req.status = result; - -	hs_ep->req = NULL; -	list_del_init(&hs_req->queue); - -	if (using_dma(hsotg)) -		s3c_hsotg_unmap_dma(hsotg, hs_ep, hs_req); - -	/* -	 * call the complete request with the locks off, just in case the -	 * request tries to queue more work for this endpoint. -	 */ - -	if (hs_req->req.complete) { -		spin_unlock(&hsotg->lock); -		hs_req->req.complete(&hs_ep->ep, &hs_req->req); -		spin_lock(&hsotg->lock); -	} - -	/* -	 * Look to see if there is anything else to do. Note, the completion -	 * of the previous request may have caused a new request to be started -	 * so be careful when doing this. -	 */ - -	if (!hs_ep->req && result >= 0) { -		restart = !list_empty(&hs_ep->queue); -		if (restart) { -			hs_req = get_ep_head(hs_ep); -			s3c_hsotg_start_req(hsotg, hs_ep, hs_req, false); -		} -	} -} - -/** - * s3c_hsotg_rx_data - receive data from the FIFO for an endpoint - * @hsotg: The device state. - * @ep_idx: The endpoint index for the data - * @size: The size of data in the fifo, in bytes - * - * The FIFO status shows there is data to read from the FIFO for a given - * endpoint, so sort out whether we need to read the data into a request - * that has been made for that endpoint. - */ -static void s3c_hsotg_rx_data(struct s3c_hsotg *hsotg, int ep_idx, int size) -{ -	struct s3c_hsotg_ep *hs_ep = &hsotg->eps[ep_idx]; -	struct s3c_hsotg_req *hs_req = hs_ep->req; -	void __iomem *fifo = hsotg->regs + EPFIFO(ep_idx); -	int to_read; -	int max_req; -	int read_ptr; - - -	if (!hs_req) { -		u32 epctl = readl(hsotg->regs + DOEPCTL(ep_idx)); -		int ptr; - -		dev_warn(hsotg->dev, -			 "%s: FIFO %d bytes on ep%d but no req (DxEPCTl=0x%08x)\n", -			 __func__, size, ep_idx, epctl); - -		/* dump the data from the FIFO, we've nothing we can do */ -		for (ptr = 0; ptr < size; ptr += 4) -			(void)readl(fifo); - -		return; -	} - -	to_read = size; -	read_ptr = hs_req->req.actual; -	max_req = hs_req->req.length - read_ptr; - -	dev_dbg(hsotg->dev, "%s: read %d/%d, done %d/%d\n", -		__func__, to_read, max_req, read_ptr, hs_req->req.length); - -	if (to_read > max_req) { -		/* -		 * more data appeared than we where willing -		 * to deal with in this request. -		 */ - -		/* currently we don't deal this */ -		WARN_ON_ONCE(1); -	} - -	hs_ep->total_data += to_read; -	hs_req->req.actual += to_read; -	to_read = DIV_ROUND_UP(to_read, 4); - -	/* -	 * note, we might over-write the buffer end by 3 bytes depending on -	 * alignment of the data. -	 */ -	readsl(fifo, hs_req->req.buf + read_ptr, to_read); -} - -/** - * s3c_hsotg_send_zlp - send zero-length packet on control endpoint - * @hsotg: The device instance - * @req: The request currently on this endpoint - * - * Generate a zero-length IN packet request for terminating a SETUP - * transaction. - * - * Note, since we don't write any data to the TxFIFO, then it is - * currently believed that we do not need to wait for any space in - * the TxFIFO. - */ -static void s3c_hsotg_send_zlp(struct s3c_hsotg *hsotg, -			       struct s3c_hsotg_req *req) -{ -	u32 ctrl; - -	if (!req) { -		dev_warn(hsotg->dev, "%s: no request?\n", __func__); -		return; -	} - -	if (req->req.length == 0) { -		hsotg->eps[0].sent_zlp = 1; -		s3c_hsotg_enqueue_setup(hsotg); -		return; -	} - -	hsotg->eps[0].dir_in = 1; -	hsotg->eps[0].sent_zlp = 1; - -	dev_dbg(hsotg->dev, "sending zero-length packet\n"); - -	/* issue a zero-sized packet to terminate this */ -	writel(DxEPTSIZ_MC(1) | DxEPTSIZ_PktCnt(1) | -	       DxEPTSIZ_XferSize(0), hsotg->regs + DIEPTSIZ(0)); - -	ctrl = readl(hsotg->regs + DIEPCTL0); -	ctrl |= DxEPCTL_CNAK;  /* clear NAK set by core */ -	ctrl |= DxEPCTL_EPEna; /* ensure ep enabled */ -	ctrl |= DxEPCTL_USBActEp; -	writel(ctrl, hsotg->regs + DIEPCTL0); -} - -/** - * s3c_hsotg_handle_outdone - handle receiving OutDone/SetupDone from RXFIFO - * @hsotg: The device instance - * @epnum: The endpoint received from - * @was_setup: Set if processing a SetupDone event. - * - * The RXFIFO has delivered an OutDone event, which means that the data - * transfer for an OUT endpoint has been completed, either by a short - * packet or by the finish of a transfer. - */ -static void s3c_hsotg_handle_outdone(struct s3c_hsotg *hsotg, -				     int epnum, bool was_setup) -{ -	u32 epsize = readl(hsotg->regs + DOEPTSIZ(epnum)); -	struct s3c_hsotg_ep *hs_ep = &hsotg->eps[epnum]; -	struct s3c_hsotg_req *hs_req = hs_ep->req; -	struct usb_request *req = &hs_req->req; -	unsigned size_left = DxEPTSIZ_XferSize_GET(epsize); -	int result = 0; - -	if (!hs_req) { -		dev_dbg(hsotg->dev, "%s: no request active\n", __func__); -		return; -	} - -	if (using_dma(hsotg)) { -		unsigned size_done; - -		/* -		 * Calculate the size of the transfer by checking how much -		 * is left in the endpoint size register and then working it -		 * out from the amount we loaded for the transfer. -		 * -		 * We need to do this as DMA pointers are always 32bit aligned -		 * so may overshoot/undershoot the transfer. -		 */ - -		size_done = hs_ep->size_loaded - size_left; -		size_done += hs_ep->last_load; - -		req->actual = size_done; -	} - -	/* if there is more request to do, schedule new transfer */ -	if (req->actual < req->length && size_left == 0) { -		s3c_hsotg_start_req(hsotg, hs_ep, hs_req, true); -		return; -	} else if (epnum == 0) { -		/* -		 * After was_setup = 1 => -		 * set CNAK for non Setup requests -		 */ -		hsotg->setup = was_setup ? 0 : 1; -	} - -	if (req->actual < req->length && req->short_not_ok) { -		dev_dbg(hsotg->dev, "%s: got %d/%d (short not ok) => error\n", -			__func__, req->actual, req->length); - -		/* -		 * todo - what should we return here? there's no one else -		 * even bothering to check the status. -		 */ -	} - -	if (epnum == 0) { -		/* -		 * Condition req->complete != s3c_hsotg_complete_setup says: -		 * send ZLP when we have an asynchronous request from gadget -		 */ -		if (!was_setup && req->complete != s3c_hsotg_complete_setup) -			s3c_hsotg_send_zlp(hsotg, hs_req); -	} - -	s3c_hsotg_complete_request(hsotg, hs_ep, hs_req, result); -} - -/** - * s3c_hsotg_read_frameno - read current frame number - * @hsotg: The device instance - * - * Return the current frame number - */ -static u32 s3c_hsotg_read_frameno(struct s3c_hsotg *hsotg) -{ -	u32 dsts; - -	dsts = readl(hsotg->regs + DSTS); -	dsts &= DSTS_SOFFN_MASK; -	dsts >>= DSTS_SOFFN_SHIFT; - -	return dsts; -} - -/** - * s3c_hsotg_handle_rx - RX FIFO has data - * @hsotg: The device instance - * - * The IRQ handler has detected that the RX FIFO has some data in it - * that requires processing, so find out what is in there and do the - * appropriate read. - * - * The RXFIFO is a true FIFO, the packets coming out are still in packet - * chunks, so if you have x packets received on an endpoint you'll get x - * FIFO events delivered, each with a packet's worth of data in it. - * - * When using DMA, we should not be processing events from the RXFIFO - * as the actual data should be sent to the memory directly and we turn - * on the completion interrupts to get notifications of transfer completion. - */ -static void s3c_hsotg_handle_rx(struct s3c_hsotg *hsotg) -{ -	u32 grxstsr = readl(hsotg->regs + GRXSTSP); -	u32 epnum, status, size; - -	WARN_ON(using_dma(hsotg)); - -	epnum = grxstsr & GRXSTS_EPNum_MASK; -	status = grxstsr & GRXSTS_PktSts_MASK; - -	size = grxstsr & GRXSTS_ByteCnt_MASK; -	size >>= GRXSTS_ByteCnt_SHIFT; - -	if (1) -		dev_dbg(hsotg->dev, "%s: GRXSTSP=0x%08x (%d@%d)\n", -			__func__, grxstsr, size, epnum); - -#define __status(x) ((x) >> GRXSTS_PktSts_SHIFT) - -	switch (status >> GRXSTS_PktSts_SHIFT) { -	case __status(GRXSTS_PktSts_GlobalOutNAK): -		dev_dbg(hsotg->dev, "GlobalOutNAK\n"); -		break; - -	case __status(GRXSTS_PktSts_OutDone): -		dev_dbg(hsotg->dev, "OutDone (Frame=0x%08x)\n", -			s3c_hsotg_read_frameno(hsotg)); - -		if (!using_dma(hsotg)) -			s3c_hsotg_handle_outdone(hsotg, epnum, false); -		break; - -	case __status(GRXSTS_PktSts_SetupDone): -		dev_dbg(hsotg->dev, -			"SetupDone (Frame=0x%08x, DOPEPCTL=0x%08x)\n", -			s3c_hsotg_read_frameno(hsotg), -			readl(hsotg->regs + DOEPCTL(0))); - -		s3c_hsotg_handle_outdone(hsotg, epnum, true); -		break; - -	case __status(GRXSTS_PktSts_OutRX): -		s3c_hsotg_rx_data(hsotg, epnum, size); -		break; - -	case __status(GRXSTS_PktSts_SetupRX): -		dev_dbg(hsotg->dev, -			"SetupRX (Frame=0x%08x, DOPEPCTL=0x%08x)\n", -			s3c_hsotg_read_frameno(hsotg), -			readl(hsotg->regs + DOEPCTL(0))); - -		s3c_hsotg_rx_data(hsotg, epnum, size); -		break; - -	default: -		dev_warn(hsotg->dev, "%s: unknown status %08x\n", -			 __func__, grxstsr); - -		s3c_hsotg_dump(hsotg); -		break; -	} -} - -/** - * s3c_hsotg_ep0_mps - turn max packet size into register setting - * @mps: The maximum packet size in bytes. - */ -static u32 s3c_hsotg_ep0_mps(unsigned int mps) -{ -	switch (mps) { -	case 64: -		return D0EPCTL_MPS_64; -	case 32: -		return D0EPCTL_MPS_32; -	case 16: -		return D0EPCTL_MPS_16; -	case 8: -		return D0EPCTL_MPS_8; -	} - -	/* bad max packet size, warn and return invalid result */ -	WARN_ON(1); -	return (u32)-1; -} - -/** - * s3c_hsotg_set_ep_maxpacket - set endpoint's max-packet field - * @hsotg: The driver state. - * @ep: The index number of the endpoint - * @mps: The maximum packet size in bytes - * - * Configure the maximum packet size for the given endpoint, updating - * the hardware control registers to reflect this. - */ -static void s3c_hsotg_set_ep_maxpacket(struct s3c_hsotg *hsotg, -				       unsigned int ep, unsigned int mps) -{ -	struct s3c_hsotg_ep *hs_ep = &hsotg->eps[ep]; -	void __iomem *regs = hsotg->regs; -	u32 mpsval; -	u32 reg; - -	if (ep == 0) { -		/* EP0 is a special case */ -		mpsval = s3c_hsotg_ep0_mps(mps); -		if (mpsval > 3) -			goto bad_mps; -	} else { -		if (mps >= DxEPCTL_MPS_LIMIT+1) -			goto bad_mps; - -		mpsval = mps; -	} - -	hs_ep->ep.maxpacket = mps; - -	/* -	 * update both the in and out endpoint controldir_ registers, even -	 * if one of the directions may not be in use. -	 */ - -	reg = readl(regs + DIEPCTL(ep)); -	reg &= ~DxEPCTL_MPS_MASK; -	reg |= mpsval; -	writel(reg, regs + DIEPCTL(ep)); - -	if (ep) { -		reg = readl(regs + DOEPCTL(ep)); -		reg &= ~DxEPCTL_MPS_MASK; -		reg |= mpsval; -		writel(reg, regs + DOEPCTL(ep)); -	} - -	return; - -bad_mps: -	dev_err(hsotg->dev, "ep%d: bad mps of %d\n", ep, mps); -} - -/** - * s3c_hsotg_txfifo_flush - flush Tx FIFO - * @hsotg: The driver state - * @idx: The index for the endpoint (0..15) - */ -static void s3c_hsotg_txfifo_flush(struct s3c_hsotg *hsotg, unsigned int idx) -{ -	int timeout; -	int val; - -	writel(GRSTCTL_TxFNum(idx) | GRSTCTL_TxFFlsh, -		hsotg->regs + GRSTCTL); - -	/* wait until the fifo is flushed */ -	timeout = 100; - -	while (1) { -		val = readl(hsotg->regs + GRSTCTL); - -		if ((val & (GRSTCTL_TxFFlsh)) == 0) -			break; - -		if (--timeout == 0) { -			dev_err(hsotg->dev, -				"%s: timeout flushing fifo (GRSTCTL=%08x)\n", -				__func__, val); -		} - -		udelay(1); -	} -} - -/** - * s3c_hsotg_trytx - check to see if anything needs transmitting - * @hsotg: The driver state - * @hs_ep: The driver endpoint to check. - * - * Check to see if there is a request that has data to send, and if so - * make an attempt to write data into the FIFO. - */ -static int s3c_hsotg_trytx(struct s3c_hsotg *hsotg, -			   struct s3c_hsotg_ep *hs_ep) -{ -	struct s3c_hsotg_req *hs_req = hs_ep->req; - -	if (!hs_ep->dir_in || !hs_req) -		return 0; - -	if (hs_req->req.actual < hs_req->req.length) { -		dev_dbg(hsotg->dev, "trying to write more for ep%d\n", -			hs_ep->index); -		return s3c_hsotg_write_fifo(hsotg, hs_ep, hs_req); -	} - -	return 0; -} - -/** - * s3c_hsotg_complete_in - complete IN transfer - * @hsotg: The device state. - * @hs_ep: The endpoint that has just completed. - * - * An IN transfer has been completed, update the transfer's state and then - * call the relevant completion routines. - */ -static void s3c_hsotg_complete_in(struct s3c_hsotg *hsotg, -				  struct s3c_hsotg_ep *hs_ep) -{ -	struct s3c_hsotg_req *hs_req = hs_ep->req; -	u32 epsize = readl(hsotg->regs + DIEPTSIZ(hs_ep->index)); -	int size_left, size_done; - -	if (!hs_req) { -		dev_dbg(hsotg->dev, "XferCompl but no req\n"); -		return; -	} - -	/* Finish ZLP handling for IN EP0 transactions */ -	if (hsotg->eps[0].sent_zlp) { -		dev_dbg(hsotg->dev, "zlp packet received\n"); -		s3c_hsotg_complete_request(hsotg, hs_ep, hs_req, 0); -		return; -	} - -	/* -	 * Calculate the size of the transfer by checking how much is left -	 * in the endpoint size register and then working it out from -	 * the amount we loaded for the transfer. -	 * -	 * We do this even for DMA, as the transfer may have incremented -	 * past the end of the buffer (DMA transfers are always 32bit -	 * aligned). -	 */ - -	size_left = DxEPTSIZ_XferSize_GET(epsize); - -	size_done = hs_ep->size_loaded - size_left; -	size_done += hs_ep->last_load; - -	if (hs_req->req.actual != size_done) -		dev_dbg(hsotg->dev, "%s: adjusting size done %d => %d\n", -			__func__, hs_req->req.actual, size_done); - -	hs_req->req.actual = size_done; -	dev_dbg(hsotg->dev, "req->length:%d req->actual:%d req->zero:%d\n", -		hs_req->req.length, hs_req->req.actual, hs_req->req.zero); - -	/* -	 * Check if dealing with Maximum Packet Size(MPS) IN transfer at EP0 -	 * When sent data is a multiple MPS size (e.g. 64B ,128B ,192B -	 * ,256B ... ), after last MPS sized packet send IN ZLP packet to -	 * inform the host that no more data is available. -	 * The state of req.zero member is checked to be sure that the value to -	 * send is smaller than wValue expected from host. -	 * Check req.length to NOT send another ZLP when the current one is -	 * under completion (the one for which this completion has been called). -	 */ -	if (hs_req->req.length && hs_ep->index == 0 && hs_req->req.zero && -	    hs_req->req.length == hs_req->req.actual && -	    !(hs_req->req.length % hs_ep->ep.maxpacket)) { - -		dev_dbg(hsotg->dev, "ep0 zlp IN packet sent\n"); -		s3c_hsotg_send_zlp(hsotg, hs_req); - -		return; -	} - -	if (!size_left && hs_req->req.actual < hs_req->req.length) { -		dev_dbg(hsotg->dev, "%s trying more for req...\n", __func__); -		s3c_hsotg_start_req(hsotg, hs_ep, hs_req, true); -	} else -		s3c_hsotg_complete_request(hsotg, hs_ep, hs_req, 0); -} - -/** - * s3c_hsotg_epint - handle an in/out endpoint interrupt - * @hsotg: The driver state - * @idx: The index for the endpoint (0..15) - * @dir_in: Set if this is an IN endpoint - * - * Process and clear any interrupt pending for an individual endpoint - */ -static void s3c_hsotg_epint(struct s3c_hsotg *hsotg, unsigned int idx, -			    int dir_in) -{ -	struct s3c_hsotg_ep *hs_ep = &hsotg->eps[idx]; -	u32 epint_reg = dir_in ? DIEPINT(idx) : DOEPINT(idx); -	u32 epctl_reg = dir_in ? DIEPCTL(idx) : DOEPCTL(idx); -	u32 epsiz_reg = dir_in ? DIEPTSIZ(idx) : DOEPTSIZ(idx); -	u32 ints; - -	ints = readl(hsotg->regs + epint_reg); - -	/* Clear endpoint interrupts */ -	writel(ints, hsotg->regs + epint_reg); - -	dev_dbg(hsotg->dev, "%s: ep%d(%s) DxEPINT=0x%08x\n", -		__func__, idx, dir_in ? "in" : "out", ints); - -	if (ints & DxEPINT_XferCompl) { -		dev_dbg(hsotg->dev, -			"%s: XferCompl: DxEPCTL=0x%08x, DxEPTSIZ=%08x\n", -			__func__, readl(hsotg->regs + epctl_reg), -			readl(hsotg->regs + epsiz_reg)); - -		/* -		 * we get OutDone from the FIFO, so we only need to look -		 * at completing IN requests here -		 */ -		if (dir_in) { -			s3c_hsotg_complete_in(hsotg, hs_ep); - -			if (idx == 0 && !hs_ep->req) -				s3c_hsotg_enqueue_setup(hsotg); -		} else if (using_dma(hsotg)) { -			/* -			 * We're using DMA, we need to fire an OutDone here -			 * as we ignore the RXFIFO. -			 */ - -			s3c_hsotg_handle_outdone(hsotg, idx, false); -		} -	} - -	if (ints & DxEPINT_EPDisbld) { -		dev_dbg(hsotg->dev, "%s: EPDisbld\n", __func__); - -		if (dir_in) { -			int epctl = readl(hsotg->regs + epctl_reg); - -			s3c_hsotg_txfifo_flush(hsotg, idx); - -			if ((epctl & DxEPCTL_Stall) && -				(epctl & DxEPCTL_EPType_Bulk)) { -				int dctl = readl(hsotg->regs + DCTL); - -				dctl |= DCTL_CGNPInNAK; -				writel(dctl, hsotg->regs + DCTL); -			} -		} -	} - -	if (ints & DxEPINT_AHBErr) -		dev_dbg(hsotg->dev, "%s: AHBErr\n", __func__); - -	if (ints & DxEPINT_Setup) {  /* Setup or Timeout */ -		dev_dbg(hsotg->dev, "%s: Setup/Timeout\n",  __func__); - -		if (using_dma(hsotg) && idx == 0) { -			/* -			 * this is the notification we've received a -			 * setup packet. In non-DMA mode we'd get this -			 * from the RXFIFO, instead we need to process -			 * the setup here. -			 */ - -			if (dir_in) -				WARN_ON_ONCE(1); -			else -				s3c_hsotg_handle_outdone(hsotg, 0, true); -		} -	} - -	if (ints & DxEPINT_Back2BackSetup) -		dev_dbg(hsotg->dev, "%s: B2BSetup/INEPNakEff\n", __func__); - -	if (dir_in) { -		/* not sure if this is important, but we'll clear it anyway */ -		if (ints & DIEPMSK_INTknTXFEmpMsk) { -			dev_dbg(hsotg->dev, "%s: ep%d: INTknTXFEmpMsk\n", -				__func__, idx); -		} - -		/* this probably means something bad is happening */ -		if (ints & DIEPMSK_INTknEPMisMsk) { -			dev_warn(hsotg->dev, "%s: ep%d: INTknEP\n", -				 __func__, idx); -		} - -		/* FIFO has space or is empty (see GAHBCFG) */ -		if (hsotg->dedicated_fifos && -		    ints & DIEPMSK_TxFIFOEmpty) { -			dev_dbg(hsotg->dev, "%s: ep%d: TxFIFOEmpty\n", -				__func__, idx); -			if (!using_dma(hsotg)) -				s3c_hsotg_trytx(hsotg, hs_ep); -		} -	} -} - -/** - * s3c_hsotg_irq_enumdone - Handle EnumDone interrupt (enumeration done) - * @hsotg: The device state. - * - * Handle updating the device settings after the enumeration phase has - * been completed. - */ -static void s3c_hsotg_irq_enumdone(struct s3c_hsotg *hsotg) -{ -	u32 dsts = readl(hsotg->regs + DSTS); -	int ep0_mps = 0, ep_mps; - -	/* -	 * This should signal the finish of the enumeration phase -	 * of the USB handshaking, so we should now know what rate -	 * we connected at. -	 */ - -	dev_dbg(hsotg->dev, "EnumDone (DSTS=0x%08x)\n", dsts); - -	/* -	 * note, since we're limited by the size of transfer on EP0, and -	 * it seems IN transfers must be a even number of packets we do -	 * not advertise a 64byte MPS on EP0. -	 */ - -	/* catch both EnumSpd_FS and EnumSpd_FS48 */ -	switch (dsts & DSTS_EnumSpd_MASK) { -	case DSTS_EnumSpd_FS: -	case DSTS_EnumSpd_FS48: -		hsotg->gadget.speed = USB_SPEED_FULL; -		ep0_mps = EP0_MPS_LIMIT; -		ep_mps = 64; -		break; - -	case DSTS_EnumSpd_HS: -		hsotg->gadget.speed = USB_SPEED_HIGH; -		ep0_mps = EP0_MPS_LIMIT; -		ep_mps = 512; -		break; - -	case DSTS_EnumSpd_LS: -		hsotg->gadget.speed = USB_SPEED_LOW; -		/* -		 * note, we don't actually support LS in this driver at the -		 * moment, and the documentation seems to imply that it isn't -		 * supported by the PHYs on some of the devices. -		 */ -		break; -	} -	dev_info(hsotg->dev, "new device is %s\n", -		 usb_speed_string(hsotg->gadget.speed)); - -	/* -	 * we should now know the maximum packet size for an -	 * endpoint, so set the endpoints to a default value. -	 */ - -	if (ep0_mps) { -		int i; -		s3c_hsotg_set_ep_maxpacket(hsotg, 0, ep0_mps); -		for (i = 1; i < hsotg->num_of_eps; i++) -			s3c_hsotg_set_ep_maxpacket(hsotg, i, ep_mps); -	} - -	/* ensure after enumeration our EP0 is active */ - -	s3c_hsotg_enqueue_setup(hsotg); - -	dev_dbg(hsotg->dev, "EP0: DIEPCTL0=0x%08x, DOEPCTL0=0x%08x\n", -		readl(hsotg->regs + DIEPCTL0), -		readl(hsotg->regs + DOEPCTL0)); -} - -/** - * kill_all_requests - remove all requests from the endpoint's queue - * @hsotg: The device state. - * @ep: The endpoint the requests may be on. - * @result: The result code to use. - * @force: Force removal of any current requests - * - * Go through the requests on the given endpoint and mark them - * completed with the given result code. - */ -static void kill_all_requests(struct s3c_hsotg *hsotg, -			      struct s3c_hsotg_ep *ep, -			      int result, bool force) -{ -	struct s3c_hsotg_req *req, *treq; - -	list_for_each_entry_safe(req, treq, &ep->queue, queue) { -		/* -		 * currently, we can't do much about an already -		 * running request on an in endpoint -		 */ - -		if (ep->req == req && ep->dir_in && !force) -			continue; - -		s3c_hsotg_complete_request(hsotg, ep, req, -					   result); -	} -} - -#define call_gadget(_hs, _entry) \ -	if ((_hs)->gadget.speed != USB_SPEED_UNKNOWN &&	\ -	    (_hs)->driver && (_hs)->driver->_entry) { \ -		spin_unlock(&_hs->lock); \ -		(_hs)->driver->_entry(&(_hs)->gadget); \ -		spin_lock(&_hs->lock); \ -		} - -/** - * s3c_hsotg_disconnect - disconnect service - * @hsotg: The device state. - * - * The device has been disconnected. Remove all current - * transactions and signal the gadget driver that this - * has happened. - */ -static void s3c_hsotg_disconnect(struct s3c_hsotg *hsotg) -{ -	unsigned ep; - -	for (ep = 0; ep < hsotg->num_of_eps; ep++) -		kill_all_requests(hsotg, &hsotg->eps[ep], -ESHUTDOWN, true); - -	call_gadget(hsotg, disconnect); -} - -/** - * s3c_hsotg_irq_fifoempty - TX FIFO empty interrupt handler - * @hsotg: The device state: - * @periodic: True if this is a periodic FIFO interrupt - */ -static void s3c_hsotg_irq_fifoempty(struct s3c_hsotg *hsotg, bool periodic) -{ -	struct s3c_hsotg_ep *ep; -	int epno, ret; - -	/* look through for any more data to transmit */ - -	for (epno = 0; epno < hsotg->num_of_eps; epno++) { -		ep = &hsotg->eps[epno]; - -		if (!ep->dir_in) -			continue; - -		if ((periodic && !ep->periodic) || -		    (!periodic && ep->periodic)) -			continue; - -		ret = s3c_hsotg_trytx(hsotg, ep); -		if (ret < 0) -			break; -	} -} - -/* IRQ flags which will trigger a retry around the IRQ loop */ -#define IRQ_RETRY_MASK (GINTSTS_NPTxFEmp | \ -			GINTSTS_PTxFEmp |  \ -			GINTSTS_RxFLvl) - -/** - * s3c_hsotg_corereset - issue softreset to the core - * @hsotg: The device state - * - * Issue a soft reset to the core, and await the core finishing it. - */ -static int s3c_hsotg_corereset(struct s3c_hsotg *hsotg) -{ -	int timeout; -	u32 grstctl; - -	dev_dbg(hsotg->dev, "resetting core\n"); - -	/* issue soft reset */ -	writel(GRSTCTL_CSftRst, hsotg->regs + GRSTCTL); - -	timeout = 10000; -	do { -		grstctl = readl(hsotg->regs + GRSTCTL); -	} while ((grstctl & GRSTCTL_CSftRst) && timeout-- > 0); - -	if (grstctl & GRSTCTL_CSftRst) { -		dev_err(hsotg->dev, "Failed to get CSftRst asserted\n"); -		return -EINVAL; -	} - -	timeout = 10000; - -	while (1) { -		u32 grstctl = readl(hsotg->regs + GRSTCTL); - -		if (timeout-- < 0) { -			dev_info(hsotg->dev, -				 "%s: reset failed, GRSTCTL=%08x\n", -				 __func__, grstctl); -			return -ETIMEDOUT; -		} - -		if (!(grstctl & GRSTCTL_AHBIdle)) -			continue; - -		break;		/* reset done */ -	} - -	dev_dbg(hsotg->dev, "reset successful\n"); -	return 0; -} - -/** - * s3c_hsotg_core_init - issue softreset to the core - * @hsotg: The device state - * - * Issue a soft reset to the core, and await the core finishing it. - */ -static void s3c_hsotg_core_init(struct s3c_hsotg *hsotg) -{ -	s3c_hsotg_corereset(hsotg); - -	/* -	 * we must now enable ep0 ready for host detection and then -	 * set configuration. -	 */ - -	/* set the PLL on, remove the HNP/SRP and set the PHY */ -	writel(GUSBCFG_PHYIf16 | GUSBCFG_TOutCal(7) | -	       (0x5 << 10), hsotg->regs + GUSBCFG); - -	s3c_hsotg_init_fifo(hsotg); - -	__orr32(hsotg->regs + DCTL, DCTL_SftDiscon); - -	writel(1 << 18 | DCFG_DevSpd_HS,  hsotg->regs + DCFG); - -	/* Clear any pending OTG interrupts */ -	writel(0xffffffff, hsotg->regs + GOTGINT); - -	/* Clear any pending interrupts */ -	writel(0xffffffff, hsotg->regs + GINTSTS); - -	writel(GINTSTS_ErlySusp | GINTSTS_SessReqInt | -	       GINTSTS_GOUTNakEff | GINTSTS_GINNakEff | -	       GINTSTS_ConIDStsChng | GINTSTS_USBRst | -	       GINTSTS_EnumDone | GINTSTS_OTGInt | -	       GINTSTS_USBSusp | GINTSTS_WkUpInt, -	       hsotg->regs + GINTMSK); - -	if (using_dma(hsotg)) -		writel(GAHBCFG_GlblIntrEn | GAHBCFG_DMAEn | -		       GAHBCFG_HBstLen_Incr4, -		       hsotg->regs + GAHBCFG); -	else -		writel(GAHBCFG_GlblIntrEn, hsotg->regs + GAHBCFG); - -	/* -	 * Enabling INTknTXFEmpMsk here seems to be a big mistake, we end -	 * up being flooded with interrupts if the host is polling the -	 * endpoint to try and read data. -	 */ - -	writel(((hsotg->dedicated_fifos) ? DIEPMSK_TxFIFOEmpty : 0) | -	       DIEPMSK_EPDisbldMsk | DIEPMSK_XferComplMsk | -	       DIEPMSK_TimeOUTMsk | DIEPMSK_AHBErrMsk | -	       DIEPMSK_INTknEPMisMsk, -	       hsotg->regs + DIEPMSK); - -	/* -	 * don't need XferCompl, we get that from RXFIFO in slave mode. In -	 * DMA mode we may need this. -	 */ -	writel((using_dma(hsotg) ? (DIEPMSK_XferComplMsk | -				    DIEPMSK_TimeOUTMsk) : 0) | -	       DOEPMSK_EPDisbldMsk | DOEPMSK_AHBErrMsk | -	       DOEPMSK_SetupMsk, -	       hsotg->regs + DOEPMSK); - -	writel(0, hsotg->regs + DAINTMSK); - -	dev_dbg(hsotg->dev, "EP0: DIEPCTL0=0x%08x, DOEPCTL0=0x%08x\n", -		readl(hsotg->regs + DIEPCTL0), -		readl(hsotg->regs + DOEPCTL0)); - -	/* enable in and out endpoint interrupts */ -	s3c_hsotg_en_gsint(hsotg, GINTSTS_OEPInt | GINTSTS_IEPInt); - -	/* -	 * Enable the RXFIFO when in slave mode, as this is how we collect -	 * the data. In DMA mode, we get events from the FIFO but also -	 * things we cannot process, so do not use it. -	 */ -	if (!using_dma(hsotg)) -		s3c_hsotg_en_gsint(hsotg, GINTSTS_RxFLvl); - -	/* Enable interrupts for EP0 in and out */ -	s3c_hsotg_ctrl_epint(hsotg, 0, 0, 1); -	s3c_hsotg_ctrl_epint(hsotg, 0, 1, 1); - -	__orr32(hsotg->regs + DCTL, DCTL_PWROnPrgDone); -	udelay(10);  /* see openiboot */ -	__bic32(hsotg->regs + DCTL, DCTL_PWROnPrgDone); - -	dev_dbg(hsotg->dev, "DCTL=0x%08x\n", readl(hsotg->regs + DCTL)); - -	/* -	 * DxEPCTL_USBActEp says RO in manual, but seems to be set by -	 * writing to the EPCTL register.. -	 */ - -	/* set to read 1 8byte packet */ -	writel(DxEPTSIZ_MC(1) | DxEPTSIZ_PktCnt(1) | -	       DxEPTSIZ_XferSize(8), hsotg->regs + DOEPTSIZ0); - -	writel(s3c_hsotg_ep0_mps(hsotg->eps[0].ep.maxpacket) | -	       DxEPCTL_CNAK | DxEPCTL_EPEna | -	       DxEPCTL_USBActEp, -	       hsotg->regs + DOEPCTL0); - -	/* enable, but don't activate EP0in */ -	writel(s3c_hsotg_ep0_mps(hsotg->eps[0].ep.maxpacket) | -	       DxEPCTL_USBActEp, hsotg->regs + DIEPCTL0); - -	s3c_hsotg_enqueue_setup(hsotg); - -	dev_dbg(hsotg->dev, "EP0: DIEPCTL0=0x%08x, DOEPCTL0=0x%08x\n", -		readl(hsotg->regs + DIEPCTL0), -		readl(hsotg->regs + DOEPCTL0)); - -	/* clear global NAKs */ -	writel(DCTL_CGOUTNak | DCTL_CGNPInNAK, -	       hsotg->regs + DCTL); - -	/* must be at-least 3ms to allow bus to see disconnect */ -	mdelay(3); - -	/* remove the soft-disconnect and let's go */ -	__bic32(hsotg->regs + DCTL, DCTL_SftDiscon); -} - -/** - * s3c_hsotg_irq - handle device interrupt - * @irq: The IRQ number triggered - * @pw: The pw value when registered the handler. - */ -static irqreturn_t s3c_hsotg_irq(int irq, void *pw) -{ -	struct s3c_hsotg *hsotg = pw; -	int retry_count = 8; -	u32 gintsts; -	u32 gintmsk; - -	spin_lock(&hsotg->lock); -irq_retry: -	gintsts = readl(hsotg->regs + GINTSTS); -	gintmsk = readl(hsotg->regs + GINTMSK); - -	dev_dbg(hsotg->dev, "%s: %08x %08x (%08x) retry %d\n", -		__func__, gintsts, gintsts & gintmsk, gintmsk, retry_count); - -	gintsts &= gintmsk; - -	if (gintsts & GINTSTS_OTGInt) { -		u32 otgint = readl(hsotg->regs + GOTGINT); - -		dev_info(hsotg->dev, "OTGInt: %08x\n", otgint); - -		writel(otgint, hsotg->regs + GOTGINT); -	} - -	if (gintsts & GINTSTS_SessReqInt) { -		dev_dbg(hsotg->dev, "%s: SessReqInt\n", __func__); -		writel(GINTSTS_SessReqInt, hsotg->regs + GINTSTS); -	} - -	if (gintsts & GINTSTS_EnumDone) { -		writel(GINTSTS_EnumDone, hsotg->regs + GINTSTS); - -		s3c_hsotg_irq_enumdone(hsotg); -	} - -	if (gintsts & GINTSTS_ConIDStsChng) { -		dev_dbg(hsotg->dev, "ConIDStsChg (DSTS=0x%08x, GOTCTL=%08x)\n", -			readl(hsotg->regs + DSTS), -			readl(hsotg->regs + GOTGCTL)); - -		writel(GINTSTS_ConIDStsChng, hsotg->regs + GINTSTS); -	} - -	if (gintsts & (GINTSTS_OEPInt | GINTSTS_IEPInt)) { -		u32 daint = readl(hsotg->regs + DAINT); -		u32 daint_out = daint >> DAINT_OutEP_SHIFT; -		u32 daint_in = daint & ~(daint_out << DAINT_OutEP_SHIFT); -		int ep; - -		dev_dbg(hsotg->dev, "%s: daint=%08x\n", __func__, daint); - -		for (ep = 0; ep < 15 && daint_out; ep++, daint_out >>= 1) { -			if (daint_out & 1) -				s3c_hsotg_epint(hsotg, ep, 0); -		} - -		for (ep = 0; ep < 15 && daint_in; ep++, daint_in >>= 1) { -			if (daint_in & 1) -				s3c_hsotg_epint(hsotg, ep, 1); -		} -	} - -	if (gintsts & GINTSTS_USBRst) { - -		u32 usb_status = readl(hsotg->regs + GOTGCTL); - -		dev_info(hsotg->dev, "%s: USBRst\n", __func__); -		dev_dbg(hsotg->dev, "GNPTXSTS=%08x\n", -			readl(hsotg->regs + GNPTXSTS)); - -		writel(GINTSTS_USBRst, hsotg->regs + GINTSTS); - -		if (usb_status & GOTGCTL_BSESVLD) { -			if (time_after(jiffies, hsotg->last_rst + -				       msecs_to_jiffies(200))) { - -				kill_all_requests(hsotg, &hsotg->eps[0], -							  -ECONNRESET, true); - -				s3c_hsotg_core_init(hsotg); -				hsotg->last_rst = jiffies; -			} -		} -	} - -	/* check both FIFOs */ - -	if (gintsts & GINTSTS_NPTxFEmp) { -		dev_dbg(hsotg->dev, "NPTxFEmp\n"); - -		/* -		 * Disable the interrupt to stop it happening again -		 * unless one of these endpoint routines decides that -		 * it needs re-enabling -		 */ - -		s3c_hsotg_disable_gsint(hsotg, GINTSTS_NPTxFEmp); -		s3c_hsotg_irq_fifoempty(hsotg, false); -	} - -	if (gintsts & GINTSTS_PTxFEmp) { -		dev_dbg(hsotg->dev, "PTxFEmp\n"); - -		/* See note in GINTSTS_NPTxFEmp */ - -		s3c_hsotg_disable_gsint(hsotg, GINTSTS_PTxFEmp); -		s3c_hsotg_irq_fifoempty(hsotg, true); -	} - -	if (gintsts & GINTSTS_RxFLvl) { -		/* -		 * note, since GINTSTS_RxFLvl doubles as FIFO-not-empty, -		 * we need to retry s3c_hsotg_handle_rx if this is still -		 * set. -		 */ - -		s3c_hsotg_handle_rx(hsotg); -	} - -	if (gintsts & GINTSTS_ModeMis) { -		dev_warn(hsotg->dev, "warning, mode mismatch triggered\n"); -		writel(GINTSTS_ModeMis, hsotg->regs + GINTSTS); -	} - -	if (gintsts & GINTSTS_USBSusp) { -		dev_info(hsotg->dev, "GINTSTS_USBSusp\n"); -		writel(GINTSTS_USBSusp, hsotg->regs + GINTSTS); - -		call_gadget(hsotg, suspend); -		s3c_hsotg_disconnect(hsotg); -	} - -	if (gintsts & GINTSTS_WkUpInt) { -		dev_info(hsotg->dev, "GINTSTS_WkUpIn\n"); -		writel(GINTSTS_WkUpInt, hsotg->regs + GINTSTS); - -		call_gadget(hsotg, resume); -	} - -	if (gintsts & GINTSTS_ErlySusp) { -		dev_dbg(hsotg->dev, "GINTSTS_ErlySusp\n"); -		writel(GINTSTS_ErlySusp, hsotg->regs + GINTSTS); - -		s3c_hsotg_disconnect(hsotg); -	} - -	/* -	 * these next two seem to crop-up occasionally causing the core -	 * to shutdown the USB transfer, so try clearing them and logging -	 * the occurrence. -	 */ - -	if (gintsts & GINTSTS_GOUTNakEff) { -		dev_info(hsotg->dev, "GOUTNakEff triggered\n"); - -		writel(DCTL_CGOUTNak, hsotg->regs + DCTL); - -		s3c_hsotg_dump(hsotg); -	} - -	if (gintsts & GINTSTS_GINNakEff) { -		dev_info(hsotg->dev, "GINNakEff triggered\n"); - -		writel(DCTL_CGNPInNAK, hsotg->regs + DCTL); - -		s3c_hsotg_dump(hsotg); -	} - -	/* -	 * if we've had fifo events, we should try and go around the -	 * loop again to see if there's any point in returning yet. -	 */ - -	if (gintsts & IRQ_RETRY_MASK && --retry_count > 0) -			goto irq_retry; - -	spin_unlock(&hsotg->lock); - -	return IRQ_HANDLED; -} - -/** - * s3c_hsotg_ep_enable - enable the given endpoint - * @ep: The USB endpint to configure - * @desc: The USB endpoint descriptor to configure with. - * - * This is called from the USB gadget code's usb_ep_enable(). - */ -static int s3c_hsotg_ep_enable(struct usb_ep *ep, -			       const struct usb_endpoint_descriptor *desc) -{ -	struct s3c_hsotg_ep *hs_ep = our_ep(ep); -	struct s3c_hsotg *hsotg = hs_ep->parent; -	unsigned long flags; -	int index = hs_ep->index; -	u32 epctrl_reg; -	u32 epctrl; -	u32 mps; -	int dir_in; -	int ret = 0; - -	dev_dbg(hsotg->dev, -		"%s: ep %s: a 0x%02x, attr 0x%02x, mps 0x%04x, intr %d\n", -		__func__, ep->name, desc->bEndpointAddress, desc->bmAttributes, -		desc->wMaxPacketSize, desc->bInterval); - -	/* not to be called for EP0 */ -	WARN_ON(index == 0); - -	dir_in = (desc->bEndpointAddress & USB_ENDPOINT_DIR_MASK) ? 1 : 0; -	if (dir_in != hs_ep->dir_in) { -		dev_err(hsotg->dev, "%s: direction mismatch!\n", __func__); -		return -EINVAL; -	} - -	mps = usb_endpoint_maxp(desc); - -	/* note, we handle this here instead of s3c_hsotg_set_ep_maxpacket */ - -	epctrl_reg = dir_in ? DIEPCTL(index) : DOEPCTL(index); -	epctrl = readl(hsotg->regs + epctrl_reg); - -	dev_dbg(hsotg->dev, "%s: read DxEPCTL=0x%08x from 0x%08x\n", -		__func__, epctrl, epctrl_reg); - -	spin_lock_irqsave(&hsotg->lock, flags); - -	epctrl &= ~(DxEPCTL_EPType_MASK | DxEPCTL_MPS_MASK); -	epctrl |= DxEPCTL_MPS(mps); - -	/* -	 * mark the endpoint as active, otherwise the core may ignore -	 * transactions entirely for this endpoint -	 */ -	epctrl |= DxEPCTL_USBActEp; - -	/* -	 * set the NAK status on the endpoint, otherwise we might try and -	 * do something with data that we've yet got a request to process -	 * since the RXFIFO will take data for an endpoint even if the -	 * size register hasn't been set. -	 */ - -	epctrl |= DxEPCTL_SNAK; - -	/* update the endpoint state */ -	hs_ep->ep.maxpacket = mps; - -	/* default, set to non-periodic */ -	hs_ep->periodic = 0; - -	switch (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) { -	case USB_ENDPOINT_XFER_ISOC: -		dev_err(hsotg->dev, "no current ISOC support\n"); -		ret = -EINVAL; -		goto out; - -	case USB_ENDPOINT_XFER_BULK: -		epctrl |= DxEPCTL_EPType_Bulk; -		break; - -	case USB_ENDPOINT_XFER_INT: -		if (dir_in) { -			/* -			 * Allocate our TxFNum by simply using the index -			 * of the endpoint for the moment. We could do -			 * something better if the host indicates how -			 * many FIFOs we are expecting to use. -			 */ - -			hs_ep->periodic = 1; -			epctrl |= DxEPCTL_TxFNum(index); -		} - -		epctrl |= DxEPCTL_EPType_Intterupt; -		break; - -	case USB_ENDPOINT_XFER_CONTROL: -		epctrl |= DxEPCTL_EPType_Control; -		break; -	} - -	/* -	 * if the hardware has dedicated fifos, we must give each IN EP -	 * a unique tx-fifo even if it is non-periodic. -	 */ -	if (dir_in && hsotg->dedicated_fifos) -		epctrl |= DxEPCTL_TxFNum(index); - -	/* for non control endpoints, set PID to D0 */ -	if (index) -		epctrl |= DxEPCTL_SetD0PID; - -	dev_dbg(hsotg->dev, "%s: write DxEPCTL=0x%08x\n", -		__func__, epctrl); - -	writel(epctrl, hsotg->regs + epctrl_reg); -	dev_dbg(hsotg->dev, "%s: read DxEPCTL=0x%08x\n", -		__func__, readl(hsotg->regs + epctrl_reg)); - -	/* enable the endpoint interrupt */ -	s3c_hsotg_ctrl_epint(hsotg, index, dir_in, 1); - -out: -	spin_unlock_irqrestore(&hsotg->lock, flags); -	return ret; -} - -/** - * s3c_hsotg_ep_disable - disable given endpoint - * @ep: The endpoint to disable. - */ -static int s3c_hsotg_ep_disable(struct usb_ep *ep) -{ -	struct s3c_hsotg_ep *hs_ep = our_ep(ep); -	struct s3c_hsotg *hsotg = hs_ep->parent; -	int dir_in = hs_ep->dir_in; -	int index = hs_ep->index; -	unsigned long flags; -	u32 epctrl_reg; -	u32 ctrl; - -	dev_info(hsotg->dev, "%s(ep %p)\n", __func__, ep); - -	if (ep == &hsotg->eps[0].ep) { -		dev_err(hsotg->dev, "%s: called for ep0\n", __func__); -		return -EINVAL; -	} - -	epctrl_reg = dir_in ? DIEPCTL(index) : DOEPCTL(index); - -	spin_lock_irqsave(&hsotg->lock, flags); -	/* terminate all requests with shutdown */ -	kill_all_requests(hsotg, hs_ep, -ESHUTDOWN, false); - - -	ctrl = readl(hsotg->regs + epctrl_reg); -	ctrl &= ~DxEPCTL_EPEna; -	ctrl &= ~DxEPCTL_USBActEp; -	ctrl |= DxEPCTL_SNAK; - -	dev_dbg(hsotg->dev, "%s: DxEPCTL=0x%08x\n", __func__, ctrl); -	writel(ctrl, hsotg->regs + epctrl_reg); - -	/* disable endpoint interrupts */ -	s3c_hsotg_ctrl_epint(hsotg, hs_ep->index, hs_ep->dir_in, 0); - -	spin_unlock_irqrestore(&hsotg->lock, flags); -	return 0; -} - -/** - * on_list - check request is on the given endpoint - * @ep: The endpoint to check. - * @test: The request to test if it is on the endpoint. - */ -static bool on_list(struct s3c_hsotg_ep *ep, struct s3c_hsotg_req *test) -{ -	struct s3c_hsotg_req *req, *treq; - -	list_for_each_entry_safe(req, treq, &ep->queue, queue) { -		if (req == test) -			return true; -	} - -	return false; -} - -/** - * s3c_hsotg_ep_dequeue - dequeue given endpoint - * @ep: The endpoint to dequeue. - * @req: The request to be removed from a queue. - */ -static int s3c_hsotg_ep_dequeue(struct usb_ep *ep, struct usb_request *req) -{ -	struct s3c_hsotg_req *hs_req = our_req(req); -	struct s3c_hsotg_ep *hs_ep = our_ep(ep); -	struct s3c_hsotg *hs = hs_ep->parent; -	unsigned long flags; - -	dev_info(hs->dev, "ep_dequeue(%p,%p)\n", ep, req); - -	spin_lock_irqsave(&hs->lock, flags); - -	if (!on_list(hs_ep, hs_req)) { -		spin_unlock_irqrestore(&hs->lock, flags); -		return -EINVAL; -	} - -	s3c_hsotg_complete_request(hs, hs_ep, hs_req, -ECONNRESET); -	spin_unlock_irqrestore(&hs->lock, flags); - -	return 0; -} - -/** - * s3c_hsotg_ep_sethalt - set halt on a given endpoint - * @ep: The endpoint to set halt. - * @value: Set or unset the halt. - */ -static int s3c_hsotg_ep_sethalt(struct usb_ep *ep, int value) -{ -	struct s3c_hsotg_ep *hs_ep = our_ep(ep); -	struct s3c_hsotg *hs = hs_ep->parent; -	int index = hs_ep->index; -	u32 epreg; -	u32 epctl; -	u32 xfertype; - -	dev_info(hs->dev, "%s(ep %p %s, %d)\n", __func__, ep, ep->name, value); - -	/* write both IN and OUT control registers */ - -	epreg = DIEPCTL(index); -	epctl = readl(hs->regs + epreg); - -	if (value) { -		epctl |= DxEPCTL_Stall + DxEPCTL_SNAK; -		if (epctl & DxEPCTL_EPEna) -			epctl |= DxEPCTL_EPDis; -	} else { -		epctl &= ~DxEPCTL_Stall; -		xfertype = epctl & DxEPCTL_EPType_MASK; -		if (xfertype == DxEPCTL_EPType_Bulk || -			xfertype == DxEPCTL_EPType_Intterupt) -				epctl |= DxEPCTL_SetD0PID; -	} - -	writel(epctl, hs->regs + epreg); - -	epreg = DOEPCTL(index); -	epctl = readl(hs->regs + epreg); - -	if (value) -		epctl |= DxEPCTL_Stall; -	else { -		epctl &= ~DxEPCTL_Stall; -		xfertype = epctl & DxEPCTL_EPType_MASK; -		if (xfertype == DxEPCTL_EPType_Bulk || -			xfertype == DxEPCTL_EPType_Intterupt) -				epctl |= DxEPCTL_SetD0PID; -	} - -	writel(epctl, hs->regs + epreg); - -	return 0; -} - -/** - * s3c_hsotg_ep_sethalt_lock - set halt on a given endpoint with lock held - * @ep: The endpoint to set halt. - * @value: Set or unset the halt. - */ -static int s3c_hsotg_ep_sethalt_lock(struct usb_ep *ep, int value) -{ -	struct s3c_hsotg_ep *hs_ep = our_ep(ep); -	struct s3c_hsotg *hs = hs_ep->parent; -	unsigned long flags = 0; -	int ret = 0; - -	spin_lock_irqsave(&hs->lock, flags); -	ret = s3c_hsotg_ep_sethalt(ep, value); -	spin_unlock_irqrestore(&hs->lock, flags); - -	return ret; -} - -static struct usb_ep_ops s3c_hsotg_ep_ops = { -	.enable		= s3c_hsotg_ep_enable, -	.disable	= s3c_hsotg_ep_disable, -	.alloc_request	= s3c_hsotg_ep_alloc_request, -	.free_request	= s3c_hsotg_ep_free_request, -	.queue		= s3c_hsotg_ep_queue_lock, -	.dequeue	= s3c_hsotg_ep_dequeue, -	.set_halt	= s3c_hsotg_ep_sethalt_lock, -	/* note, don't believe we have any call for the fifo routines */ -}; - -/** - * s3c_hsotg_phy_enable - enable platform phy dev - * @hsotg: The driver state - * - * A wrapper for platform code responsible for controlling - * low-level USB code - */ -static void s3c_hsotg_phy_enable(struct s3c_hsotg *hsotg) -{ -	struct platform_device *pdev = to_platform_device(hsotg->dev); - -	dev_dbg(hsotg->dev, "pdev 0x%p\n", pdev); - -	if (hsotg->phy) -		usb_phy_init(hsotg->phy); -	else if (hsotg->plat->phy_init) -		hsotg->plat->phy_init(pdev, hsotg->plat->phy_type); -} - -/** - * s3c_hsotg_phy_disable - disable platform phy dev - * @hsotg: The driver state - * - * A wrapper for platform code responsible for controlling - * low-level USB code - */ -static void s3c_hsotg_phy_disable(struct s3c_hsotg *hsotg) -{ -	struct platform_device *pdev = to_platform_device(hsotg->dev); - -	if (hsotg->phy) -		usb_phy_shutdown(hsotg->phy); -	else if (hsotg->plat->phy_exit) -		hsotg->plat->phy_exit(pdev, hsotg->plat->phy_type); -} - -/** - * s3c_hsotg_init - initalize the usb core - * @hsotg: The driver state - */ -static void s3c_hsotg_init(struct s3c_hsotg *hsotg) -{ -	/* unmask subset of endpoint interrupts */ - -	writel(DIEPMSK_TimeOUTMsk | DIEPMSK_AHBErrMsk | -	       DIEPMSK_EPDisbldMsk | DIEPMSK_XferComplMsk, -	       hsotg->regs + DIEPMSK); - -	writel(DOEPMSK_SetupMsk | DOEPMSK_AHBErrMsk | -	       DOEPMSK_EPDisbldMsk | DOEPMSK_XferComplMsk, -	       hsotg->regs + DOEPMSK); - -	writel(0, hsotg->regs + DAINTMSK); - -	/* Be in disconnected state until gadget is registered */ -	__orr32(hsotg->regs + DCTL, DCTL_SftDiscon); - -	if (0) { -		/* post global nak until we're ready */ -		writel(DCTL_SGNPInNAK | DCTL_SGOUTNak, -		       hsotg->regs + DCTL); -	} - -	/* setup fifos */ - -	dev_dbg(hsotg->dev, "GRXFSIZ=0x%08x, GNPTXFSIZ=0x%08x\n", -		readl(hsotg->regs + GRXFSIZ), -		readl(hsotg->regs + GNPTXFSIZ)); - -	s3c_hsotg_init_fifo(hsotg); - -	/* set the PLL on, remove the HNP/SRP and set the PHY */ -	writel(GUSBCFG_PHYIf16 | GUSBCFG_TOutCal(7) | (0x5 << 10), -	       hsotg->regs + GUSBCFG); - -	writel(using_dma(hsotg) ? GAHBCFG_DMAEn : 0x0, -	       hsotg->regs + GAHBCFG); -} - -/** - * s3c_hsotg_udc_start - prepare the udc for work - * @gadget: The usb gadget state - * @driver: The usb gadget driver - * - * Perform initialization to prepare udc device and driver - * to work. - */ -static int s3c_hsotg_udc_start(struct usb_gadget *gadget, -			   struct usb_gadget_driver *driver) -{ -	struct s3c_hsotg *hsotg = to_hsotg(gadget); -	int ret; - -	if (!hsotg) { -		printk(KERN_ERR "%s: called with no device\n", __func__); -		return -ENODEV; -	} - -	if (!driver) { -		dev_err(hsotg->dev, "%s: no driver\n", __func__); -		return -EINVAL; -	} - -	if (driver->max_speed < USB_SPEED_FULL) -		dev_err(hsotg->dev, "%s: bad speed\n", __func__); - -	if (!driver->setup) { -		dev_err(hsotg->dev, "%s: missing entry points\n", __func__); -		return -EINVAL; -	} - -	WARN_ON(hsotg->driver); - -	driver->driver.bus = NULL; -	hsotg->driver = driver; -	hsotg->gadget.dev.of_node = hsotg->dev->of_node; -	hsotg->gadget.speed = USB_SPEED_UNKNOWN; - -	ret = regulator_bulk_enable(ARRAY_SIZE(hsotg->supplies), -				    hsotg->supplies); -	if (ret) { -		dev_err(hsotg->dev, "failed to enable supplies: %d\n", ret); -		goto err; -	} - -	hsotg->last_rst = jiffies; -	dev_info(hsotg->dev, "bound driver %s\n", driver->driver.name); -	return 0; - -err: -	hsotg->driver = NULL; -	return ret; -} - -/** - * s3c_hsotg_udc_stop - stop the udc - * @gadget: The usb gadget state - * @driver: The usb gadget driver - * - * Stop udc hw block and stay tunned for future transmissions - */ -static int s3c_hsotg_udc_stop(struct usb_gadget *gadget, -			  struct usb_gadget_driver *driver) -{ -	struct s3c_hsotg *hsotg = to_hsotg(gadget); -	unsigned long flags = 0; -	int ep; - -	if (!hsotg) -		return -ENODEV; - -	if (!driver || driver != hsotg->driver || !driver->unbind) -		return -EINVAL; - -	/* all endpoints should be shutdown */ -	for (ep = 0; ep < hsotg->num_of_eps; ep++) -		s3c_hsotg_ep_disable(&hsotg->eps[ep].ep); - -	spin_lock_irqsave(&hsotg->lock, flags); - -	s3c_hsotg_phy_disable(hsotg); -	regulator_bulk_disable(ARRAY_SIZE(hsotg->supplies), hsotg->supplies); - -	hsotg->driver = NULL; -	hsotg->gadget.speed = USB_SPEED_UNKNOWN; - -	spin_unlock_irqrestore(&hsotg->lock, flags); - -	dev_info(hsotg->dev, "unregistered gadget driver '%s'\n", -		 driver->driver.name); - -	return 0; -} - -/** - * s3c_hsotg_gadget_getframe - read the frame number - * @gadget: The usb gadget state - * - * Read the {micro} frame number - */ -static int s3c_hsotg_gadget_getframe(struct usb_gadget *gadget) -{ -	return s3c_hsotg_read_frameno(to_hsotg(gadget)); -} - -/** - * s3c_hsotg_pullup - connect/disconnect the USB PHY - * @gadget: The usb gadget state - * @is_on: Current state of the USB PHY - * - * Connect/Disconnect the USB PHY pullup - */ -static int s3c_hsotg_pullup(struct usb_gadget *gadget, int is_on) -{ -	struct s3c_hsotg *hsotg = to_hsotg(gadget); -	unsigned long flags = 0; - -	dev_dbg(hsotg->dev, "%s: is_in: %d\n", __func__, is_on); - -	spin_lock_irqsave(&hsotg->lock, flags); -	if (is_on) { -		s3c_hsotg_phy_enable(hsotg); -		s3c_hsotg_core_init(hsotg); -	} else { -		s3c_hsotg_disconnect(hsotg); -		s3c_hsotg_phy_disable(hsotg); -	} - -	hsotg->gadget.speed = USB_SPEED_UNKNOWN; -	spin_unlock_irqrestore(&hsotg->lock, flags); - -	return 0; -} - -static const struct usb_gadget_ops s3c_hsotg_gadget_ops = { -	.get_frame	= s3c_hsotg_gadget_getframe, -	.udc_start		= s3c_hsotg_udc_start, -	.udc_stop		= s3c_hsotg_udc_stop, -	.pullup                 = s3c_hsotg_pullup, -}; - -/** - * s3c_hsotg_initep - initialise a single endpoint - * @hsotg: The device state. - * @hs_ep: The endpoint to be initialised. - * @epnum: The endpoint number - * - * Initialise the given endpoint (as part of the probe and device state - * creation) to give to the gadget driver. Setup the endpoint name, any - * direction information and other state that may be required. - */ -static void s3c_hsotg_initep(struct s3c_hsotg *hsotg, -				       struct s3c_hsotg_ep *hs_ep, -				       int epnum) -{ -	u32 ptxfifo; -	char *dir; - -	if (epnum == 0) -		dir = ""; -	else if ((epnum % 2) == 0) { -		dir = "out"; -	} else { -		dir = "in"; -		hs_ep->dir_in = 1; -	} - -	hs_ep->index = epnum; - -	snprintf(hs_ep->name, sizeof(hs_ep->name), "ep%d%s", epnum, dir); - -	INIT_LIST_HEAD(&hs_ep->queue); -	INIT_LIST_HEAD(&hs_ep->ep.ep_list); - -	/* add to the list of endpoints known by the gadget driver */ -	if (epnum) -		list_add_tail(&hs_ep->ep.ep_list, &hsotg->gadget.ep_list); - -	hs_ep->parent = hsotg; -	hs_ep->ep.name = hs_ep->name; -	hs_ep->ep.maxpacket = epnum ? 512 : EP0_MPS_LIMIT; -	hs_ep->ep.ops = &s3c_hsotg_ep_ops; - -	/* -	 * Read the FIFO size for the Periodic TX FIFO, even if we're -	 * an OUT endpoint, we may as well do this if in future the -	 * code is changed to make each endpoint's direction changeable. -	 */ - -	ptxfifo = readl(hsotg->regs + DPTXFSIZn(epnum)); -	hs_ep->fifo_size = DPTXFSIZn_DPTxFSize_GET(ptxfifo) * 4; - -	/* -	 * if we're using dma, we need to set the next-endpoint pointer -	 * to be something valid. -	 */ - -	if (using_dma(hsotg)) { -		u32 next = DxEPCTL_NextEp((epnum + 1) % 15); -		writel(next, hsotg->regs + DIEPCTL(epnum)); -		writel(next, hsotg->regs + DOEPCTL(epnum)); -	} -} - -/** - * s3c_hsotg_hw_cfg - read HW configuration registers - * @param: The device state - * - * Read the USB core HW configuration registers - */ -static void s3c_hsotg_hw_cfg(struct s3c_hsotg *hsotg) -{ -	u32 cfg2, cfg4; -	/* check hardware configuration */ - -	cfg2 = readl(hsotg->regs + 0x48); -	hsotg->num_of_eps = (cfg2 >> 10) & 0xF; - -	dev_info(hsotg->dev, "EPs:%d\n", hsotg->num_of_eps); - -	cfg4 = readl(hsotg->regs + 0x50); -	hsotg->dedicated_fifos = (cfg4 >> 25) & 1; - -	dev_info(hsotg->dev, "%s fifos\n", -		 hsotg->dedicated_fifos ? "dedicated" : "shared"); -} - -/** - * s3c_hsotg_dump - dump state of the udc - * @param: The device state - */ -static void s3c_hsotg_dump(struct s3c_hsotg *hsotg) -{ -#ifdef DEBUG -	struct device *dev = hsotg->dev; -	void __iomem *regs = hsotg->regs; -	u32 val; -	int idx; - -	dev_info(dev, "DCFG=0x%08x, DCTL=0x%08x, DIEPMSK=%08x\n", -		 readl(regs + DCFG), readl(regs + DCTL), -		 readl(regs + DIEPMSK)); - -	dev_info(dev, "GAHBCFG=0x%08x, 0x44=0x%08x\n", -		 readl(regs + GAHBCFG), readl(regs + 0x44)); - -	dev_info(dev, "GRXFSIZ=0x%08x, GNPTXFSIZ=0x%08x\n", -		 readl(regs + GRXFSIZ), readl(regs + GNPTXFSIZ)); - -	/* show periodic fifo settings */ - -	for (idx = 1; idx <= 15; idx++) { -		val = readl(regs + DPTXFSIZn(idx)); -		dev_info(dev, "DPTx[%d] FSize=%d, StAddr=0x%08x\n", idx, -			 val >> DPTXFSIZn_DPTxFSize_SHIFT, -			 val & DPTXFSIZn_DPTxFStAddr_MASK); -	} - -	for (idx = 0; idx < 15; idx++) { -		dev_info(dev, -			 "ep%d-in: EPCTL=0x%08x, SIZ=0x%08x, DMA=0x%08x\n", idx, -			 readl(regs + DIEPCTL(idx)), -			 readl(regs + DIEPTSIZ(idx)), -			 readl(regs + DIEPDMA(idx))); - -		val = readl(regs + DOEPCTL(idx)); -		dev_info(dev, -			 "ep%d-out: EPCTL=0x%08x, SIZ=0x%08x, DMA=0x%08x\n", -			 idx, readl(regs + DOEPCTL(idx)), -			 readl(regs + DOEPTSIZ(idx)), -			 readl(regs + DOEPDMA(idx))); - -	} - -	dev_info(dev, "DVBUSDIS=0x%08x, DVBUSPULSE=%08x\n", -		 readl(regs + DVBUSDIS), readl(regs + DVBUSPULSE)); -#endif -} - -/** - * state_show - debugfs: show overall driver and device state. - * @seq: The seq file to write to. - * @v: Unused parameter. - * - * This debugfs entry shows the overall state of the hardware and - * some general information about each of the endpoints available - * to the system. - */ -static int state_show(struct seq_file *seq, void *v) -{ -	struct s3c_hsotg *hsotg = seq->private; -	void __iomem *regs = hsotg->regs; -	int idx; - -	seq_printf(seq, "DCFG=0x%08x, DCTL=0x%08x, DSTS=0x%08x\n", -		 readl(regs + DCFG), -		 readl(regs + DCTL), -		 readl(regs + DSTS)); - -	seq_printf(seq, "DIEPMSK=0x%08x, DOEPMASK=0x%08x\n", -		   readl(regs + DIEPMSK), readl(regs + DOEPMSK)); - -	seq_printf(seq, "GINTMSK=0x%08x, GINTSTS=0x%08x\n", -		   readl(regs + GINTMSK), -		   readl(regs + GINTSTS)); - -	seq_printf(seq, "DAINTMSK=0x%08x, DAINT=0x%08x\n", -		   readl(regs + DAINTMSK), -		   readl(regs + DAINT)); - -	seq_printf(seq, "GNPTXSTS=0x%08x, GRXSTSR=%08x\n", -		   readl(regs + GNPTXSTS), -		   readl(regs + GRXSTSR)); - -	seq_printf(seq, "\nEndpoint status:\n"); - -	for (idx = 0; idx < 15; idx++) { -		u32 in, out; - -		in = readl(regs + DIEPCTL(idx)); -		out = readl(regs + DOEPCTL(idx)); - -		seq_printf(seq, "ep%d: DIEPCTL=0x%08x, DOEPCTL=0x%08x", -			   idx, in, out); - -		in = readl(regs + DIEPTSIZ(idx)); -		out = readl(regs + DOEPTSIZ(idx)); - -		seq_printf(seq, ", DIEPTSIZ=0x%08x, DOEPTSIZ=0x%08x", -			   in, out); - -		seq_printf(seq, "\n"); -	} - -	return 0; -} - -static int state_open(struct inode *inode, struct file *file) -{ -	return single_open(file, state_show, inode->i_private); -} - -static const struct file_operations state_fops = { -	.owner		= THIS_MODULE, -	.open		= state_open, -	.read		= seq_read, -	.llseek		= seq_lseek, -	.release	= single_release, -}; - -/** - * fifo_show - debugfs: show the fifo information - * @seq: The seq_file to write data to. - * @v: Unused parameter. - * - * Show the FIFO information for the overall fifo and all the - * periodic transmission FIFOs. - */ -static int fifo_show(struct seq_file *seq, void *v) -{ -	struct s3c_hsotg *hsotg = seq->private; -	void __iomem *regs = hsotg->regs; -	u32 val; -	int idx; - -	seq_printf(seq, "Non-periodic FIFOs:\n"); -	seq_printf(seq, "RXFIFO: Size %d\n", readl(regs + GRXFSIZ)); - -	val = readl(regs + GNPTXFSIZ); -	seq_printf(seq, "NPTXFIFO: Size %d, Start 0x%08x\n", -		   val >> GNPTXFSIZ_NPTxFDep_SHIFT, -		   val & GNPTXFSIZ_NPTxFStAddr_MASK); - -	seq_printf(seq, "\nPeriodic TXFIFOs:\n"); - -	for (idx = 1; idx <= 15; idx++) { -		val = readl(regs + DPTXFSIZn(idx)); - -		seq_printf(seq, "\tDPTXFIFO%2d: Size %d, Start 0x%08x\n", idx, -			   val >> DPTXFSIZn_DPTxFSize_SHIFT, -			   val & DPTXFSIZn_DPTxFStAddr_MASK); -	} - -	return 0; -} - -static int fifo_open(struct inode *inode, struct file *file) -{ -	return single_open(file, fifo_show, inode->i_private); -} - -static const struct file_operations fifo_fops = { -	.owner		= THIS_MODULE, -	.open		= fifo_open, -	.read		= seq_read, -	.llseek		= seq_lseek, -	.release	= single_release, -}; - - -static const char *decode_direction(int is_in) -{ -	return is_in ? "in" : "out"; -} - -/** - * ep_show - debugfs: show the state of an endpoint. - * @seq: The seq_file to write data to. - * @v: Unused parameter. - * - * This debugfs entry shows the state of the given endpoint (one is - * registered for each available). - */ -static int ep_show(struct seq_file *seq, void *v) -{ -	struct s3c_hsotg_ep *ep = seq->private; -	struct s3c_hsotg *hsotg = ep->parent; -	struct s3c_hsotg_req *req; -	void __iomem *regs = hsotg->regs; -	int index = ep->index; -	int show_limit = 15; -	unsigned long flags; - -	seq_printf(seq, "Endpoint index %d, named %s,  dir %s:\n", -		   ep->index, ep->ep.name, decode_direction(ep->dir_in)); - -	/* first show the register state */ - -	seq_printf(seq, "\tDIEPCTL=0x%08x, DOEPCTL=0x%08x\n", -		   readl(regs + DIEPCTL(index)), -		   readl(regs + DOEPCTL(index))); - -	seq_printf(seq, "\tDIEPDMA=0x%08x, DOEPDMA=0x%08x\n", -		   readl(regs + DIEPDMA(index)), -		   readl(regs + DOEPDMA(index))); - -	seq_printf(seq, "\tDIEPINT=0x%08x, DOEPINT=0x%08x\n", -		   readl(regs + DIEPINT(index)), -		   readl(regs + DOEPINT(index))); - -	seq_printf(seq, "\tDIEPTSIZ=0x%08x, DOEPTSIZ=0x%08x\n", -		   readl(regs + DIEPTSIZ(index)), -		   readl(regs + DOEPTSIZ(index))); - -	seq_printf(seq, "\n"); -	seq_printf(seq, "mps %d\n", ep->ep.maxpacket); -	seq_printf(seq, "total_data=%ld\n", ep->total_data); - -	seq_printf(seq, "request list (%p,%p):\n", -		   ep->queue.next, ep->queue.prev); - -	spin_lock_irqsave(&hsotg->lock, flags); - -	list_for_each_entry(req, &ep->queue, queue) { -		if (--show_limit < 0) { -			seq_printf(seq, "not showing more requests...\n"); -			break; -		} - -		seq_printf(seq, "%c req %p: %d bytes @%p, ", -			   req == ep->req ? '*' : ' ', -			   req, req->req.length, req->req.buf); -		seq_printf(seq, "%d done, res %d\n", -			   req->req.actual, req->req.status); -	} - -	spin_unlock_irqrestore(&hsotg->lock, flags); - -	return 0; -} - -static int ep_open(struct inode *inode, struct file *file) -{ -	return single_open(file, ep_show, inode->i_private); -} - -static const struct file_operations ep_fops = { -	.owner		= THIS_MODULE, -	.open		= ep_open, -	.read		= seq_read, -	.llseek		= seq_lseek, -	.release	= single_release, -}; - -/** - * s3c_hsotg_create_debug - create debugfs directory and files - * @hsotg: The driver state - * - * Create the debugfs files to allow the user to get information - * about the state of the system. The directory name is created - * with the same name as the device itself, in case we end up - * with multiple blocks in future systems. - */ -static void s3c_hsotg_create_debug(struct s3c_hsotg *hsotg) -{ -	struct dentry *root; -	unsigned epidx; - -	root = debugfs_create_dir(dev_name(hsotg->dev), NULL); -	hsotg->debug_root = root; -	if (IS_ERR(root)) { -		dev_err(hsotg->dev, "cannot create debug root\n"); -		return; -	} - -	/* create general state file */ - -	hsotg->debug_file = debugfs_create_file("state", 0444, root, -						hsotg, &state_fops); - -	if (IS_ERR(hsotg->debug_file)) -		dev_err(hsotg->dev, "%s: failed to create state\n", __func__); - -	hsotg->debug_fifo = debugfs_create_file("fifo", 0444, root, -						hsotg, &fifo_fops); - -	if (IS_ERR(hsotg->debug_fifo)) -		dev_err(hsotg->dev, "%s: failed to create fifo\n", __func__); - -	/* create one file for each endpoint */ - -	for (epidx = 0; epidx < hsotg->num_of_eps; epidx++) { -		struct s3c_hsotg_ep *ep = &hsotg->eps[epidx]; - -		ep->debugfs = debugfs_create_file(ep->name, 0444, -						  root, ep, &ep_fops); - -		if (IS_ERR(ep->debugfs)) -			dev_err(hsotg->dev, "failed to create %s debug file\n", -				ep->name); -	} -} - -/** - * s3c_hsotg_delete_debug - cleanup debugfs entries - * @hsotg: The driver state - * - * Cleanup (remove) the debugfs files for use on module exit. - */ -static void s3c_hsotg_delete_debug(struct s3c_hsotg *hsotg) -{ -	unsigned epidx; - -	for (epidx = 0; epidx < hsotg->num_of_eps; epidx++) { -		struct s3c_hsotg_ep *ep = &hsotg->eps[epidx]; -		debugfs_remove(ep->debugfs); -	} - -	debugfs_remove(hsotg->debug_file); -	debugfs_remove(hsotg->debug_fifo); -	debugfs_remove(hsotg->debug_root); -} - -/** - * s3c_hsotg_probe - probe function for hsotg driver - * @pdev: The platform information for the driver - */ - -static int s3c_hsotg_probe(struct platform_device *pdev) -{ -	struct s3c_hsotg_plat *plat = dev_get_platdata(&pdev->dev); -	struct usb_phy *phy; -	struct device *dev = &pdev->dev; -	struct s3c_hsotg_ep *eps; -	struct s3c_hsotg *hsotg; -	struct resource *res; -	int epnum; -	int ret; -	int i; - -	hsotg = devm_kzalloc(&pdev->dev, sizeof(struct s3c_hsotg), GFP_KERNEL); -	if (!hsotg) { -		dev_err(dev, "cannot get memory\n"); -		return -ENOMEM; -	} - -	phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB2); -	if (IS_ERR(phy)) { -		/* Fallback for pdata */ -		plat = dev_get_platdata(&pdev->dev); -		if (!plat) { -			dev_err(&pdev->dev, "no platform data or transceiver defined\n"); -			return -EPROBE_DEFER; -		} else { -			hsotg->plat = plat; -		} -	} else { -		hsotg->phy = phy; -	} - -	hsotg->dev = dev; - -	hsotg->clk = devm_clk_get(&pdev->dev, "otg"); -	if (IS_ERR(hsotg->clk)) { -		dev_err(dev, "cannot get otg clock\n"); -		return PTR_ERR(hsotg->clk); -	} - -	platform_set_drvdata(pdev, hsotg); - -	res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - -	hsotg->regs = devm_ioremap_resource(&pdev->dev, res); -	if (IS_ERR(hsotg->regs)) { -		ret = PTR_ERR(hsotg->regs); -		goto err_clk; -	} - -	ret = platform_get_irq(pdev, 0); -	if (ret < 0) { -		dev_err(dev, "cannot find IRQ\n"); -		goto err_clk; -	} - -	spin_lock_init(&hsotg->lock); - -	hsotg->irq = ret; - -	ret = devm_request_irq(&pdev->dev, hsotg->irq, s3c_hsotg_irq, 0, -				dev_name(dev), hsotg); -	if (ret < 0) { -		dev_err(dev, "cannot claim IRQ\n"); -		goto err_clk; -	} - -	dev_info(dev, "regs %p, irq %d\n", hsotg->regs, hsotg->irq); - -	hsotg->gadget.max_speed = USB_SPEED_HIGH; -	hsotg->gadget.ops = &s3c_hsotg_gadget_ops; -	hsotg->gadget.name = dev_name(dev); - -	/* reset the system */ - -	clk_prepare_enable(hsotg->clk); - -	/* regulators */ - -	for (i = 0; i < ARRAY_SIZE(hsotg->supplies); i++) -		hsotg->supplies[i].supply = s3c_hsotg_supply_names[i]; - -	ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(hsotg->supplies), -				 hsotg->supplies); -	if (ret) { -		dev_err(dev, "failed to request supplies: %d\n", ret); -		goto err_clk; -	} - -	ret = regulator_bulk_enable(ARRAY_SIZE(hsotg->supplies), -				    hsotg->supplies); - -	if (ret) { -		dev_err(hsotg->dev, "failed to enable supplies: %d\n", ret); -		goto err_supplies; -	} - -	/* usb phy enable */ -	s3c_hsotg_phy_enable(hsotg); - -	s3c_hsotg_corereset(hsotg); -	s3c_hsotg_init(hsotg); -	s3c_hsotg_hw_cfg(hsotg); - -	/* hsotg->num_of_eps holds number of EPs other than ep0 */ - -	if (hsotg->num_of_eps == 0) { -		dev_err(dev, "wrong number of EPs (zero)\n"); -		ret = -EINVAL; -		goto err_supplies; -	} - -	eps = kcalloc(hsotg->num_of_eps + 1, sizeof(struct s3c_hsotg_ep), -		      GFP_KERNEL); -	if (!eps) { -		dev_err(dev, "cannot get memory\n"); -		ret = -ENOMEM; -		goto err_supplies; -	} - -	hsotg->eps = eps; - -	/* setup endpoint information */ - -	INIT_LIST_HEAD(&hsotg->gadget.ep_list); -	hsotg->gadget.ep0 = &hsotg->eps[0].ep; - -	/* allocate EP0 request */ - -	hsotg->ctrl_req = s3c_hsotg_ep_alloc_request(&hsotg->eps[0].ep, -						     GFP_KERNEL); -	if (!hsotg->ctrl_req) { -		dev_err(dev, "failed to allocate ctrl req\n"); -		ret = -ENOMEM; -		goto err_ep_mem; -	} - -	/* initialise the endpoints now the core has been initialised */ -	for (epnum = 0; epnum < hsotg->num_of_eps; epnum++) -		s3c_hsotg_initep(hsotg, &hsotg->eps[epnum], epnum); - -	/* disable power and clock */ - -	ret = regulator_bulk_disable(ARRAY_SIZE(hsotg->supplies), -				    hsotg->supplies); -	if (ret) { -		dev_err(hsotg->dev, "failed to disable supplies: %d\n", ret); -		goto err_ep_mem; -	} - -	s3c_hsotg_phy_disable(hsotg); - -	ret = usb_add_gadget_udc(&pdev->dev, &hsotg->gadget); -	if (ret) -		goto err_ep_mem; - -	s3c_hsotg_create_debug(hsotg); - -	s3c_hsotg_dump(hsotg); - -	return 0; - -err_ep_mem: -	kfree(eps); -err_supplies: -	s3c_hsotg_phy_disable(hsotg); -err_clk: -	clk_disable_unprepare(hsotg->clk); - -	return ret; -} - -/** - * s3c_hsotg_remove - remove function for hsotg driver - * @pdev: The platform information for the driver - */ -static int s3c_hsotg_remove(struct platform_device *pdev) -{ -	struct s3c_hsotg *hsotg = platform_get_drvdata(pdev); - -	usb_del_gadget_udc(&hsotg->gadget); - -	s3c_hsotg_delete_debug(hsotg); - -	if (hsotg->driver) { -		/* should have been done already by driver model core */ -		usb_gadget_unregister_driver(hsotg->driver); -	} - -	s3c_hsotg_phy_disable(hsotg); -	clk_disable_unprepare(hsotg->clk); - -	return 0; -} - -#if 1 -#define s3c_hsotg_suspend NULL -#define s3c_hsotg_resume NULL -#endif - -#ifdef CONFIG_OF -static const struct of_device_id s3c_hsotg_of_ids[] = { -	{ .compatible = "samsung,s3c6400-hsotg", }, -	{ /* sentinel */ } -}; -MODULE_DEVICE_TABLE(of, s3c_hsotg_of_ids); -#endif - -static struct platform_driver s3c_hsotg_driver = { -	.driver		= { -		.name	= "s3c-hsotg", -		.owner	= THIS_MODULE, -		.of_match_table = of_match_ptr(s3c_hsotg_of_ids), -	}, -	.probe		= s3c_hsotg_probe, -	.remove		= s3c_hsotg_remove, -	.suspend	= s3c_hsotg_suspend, -	.resume		= s3c_hsotg_resume, -}; - -module_platform_driver(s3c_hsotg_driver); - -MODULE_DESCRIPTION("Samsung S3C USB High-speed/OtG device"); -MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:s3c-hsotg"); diff --git a/drivers/usb/gadget/s3c-hsotg.h b/drivers/usb/gadget/s3c-hsotg.h deleted file mode 100644 index d650b129583..00000000000 --- a/drivers/usb/gadget/s3c-hsotg.h +++ /dev/null @@ -1,377 +0,0 @@ -/* drivers/usb/gadget/s3c-hsotg.h - * - * Copyright 2008 Openmoko, Inc. - * Copyright 2008 Simtec Electronics - *      http://armlinux.simtec.co.uk/ - *      Ben Dooks <ben@simtec.co.uk> - * - * USB2.0 Highspeed/OtG Synopsis DWC2 device block registers - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. -*/ - -#ifndef __REGS_USB_HSOTG_H -#define __REGS_USB_HSOTG_H __FILE__ - -#define HSOTG_REG(x) (x) - -#define GOTGCTL				HSOTG_REG(0x000) -#define GOTGCTL_BSESVLD			(1 << 19) -#define GOTGCTL_ASESVLD			(1 << 18) -#define GOTGCTL_DBNC_SHORT			(1 << 17) -#define GOTGCTL_CONID_B			(1 << 16) -#define GOTGCTL_DEVHNPEN			(1 << 11) -#define GOTGCTL_HSSETHNPEN			(1 << 10) -#define GOTGCTL_HNPREQ				(1 << 9) -#define GOTGCTL_HSTNEGSCS			(1 << 8) -#define GOTGCTL_SESREQ				(1 << 1) -#define GOTGCTL_SESREQSCS			(1 << 0) - -#define GOTGINT				HSOTG_REG(0x004) -#define GOTGINT_DbnceDone			(1 << 19) -#define GOTGINT_ADevTOUTChg			(1 << 18) -#define GOTGINT_HstNegDet			(1 << 17) -#define GOTGINT_HstnegSucStsChng		(1 << 9) -#define GOTGINT_SesReqSucStsChng		(1 << 8) -#define GOTGINT_SesEndDet			(1 << 2) - -#define GAHBCFG				HSOTG_REG(0x008) -#define GAHBCFG_PTxFEmpLvl			(1 << 8) -#define GAHBCFG_NPTxFEmpLvl			(1 << 7) -#define GAHBCFG_DMAEn				(1 << 5) -#define GAHBCFG_HBstLen_MASK			(0xf << 1) -#define GAHBCFG_HBstLen_SHIFT			(1) -#define GAHBCFG_HBstLen_Single			(0x0 << 1) -#define GAHBCFG_HBstLen_Incr			(0x1 << 1) -#define GAHBCFG_HBstLen_Incr4			(0x3 << 1) -#define GAHBCFG_HBstLen_Incr8			(0x5 << 1) -#define GAHBCFG_HBstLen_Incr16			(0x7 << 1) -#define GAHBCFG_GlblIntrEn			(1 << 0) - -#define GUSBCFG				HSOTG_REG(0x00C) -#define GUSBCFG_PHYLPClkSel			(1 << 15) -#define GUSBCFG_HNPCap				(1 << 9) -#define GUSBCFG_SRPCap				(1 << 8) -#define GUSBCFG_PHYIf16			(1 << 3) -#define GUSBCFG_TOutCal_MASK			(0x7 << 0) -#define GUSBCFG_TOutCal_SHIFT			(0) -#define GUSBCFG_TOutCal_LIMIT			(0x7) -#define GUSBCFG_TOutCal(_x)			((_x) << 0) - -#define GRSTCTL				HSOTG_REG(0x010) - -#define GRSTCTL_AHBIdle			(1 << 31) -#define GRSTCTL_DMAReq				(1 << 30) -#define GRSTCTL_TxFNum_MASK			(0x1f << 6) -#define GRSTCTL_TxFNum_SHIFT			(6) -#define GRSTCTL_TxFNum_LIMIT			(0x1f) -#define GRSTCTL_TxFNum(_x)			((_x) << 6) -#define GRSTCTL_TxFFlsh			(1 << 5) -#define GRSTCTL_RxFFlsh			(1 << 4) -#define GRSTCTL_INTknQFlsh			(1 << 3) -#define GRSTCTL_FrmCntrRst			(1 << 2) -#define GRSTCTL_HSftRst			(1 << 1) -#define GRSTCTL_CSftRst			(1 << 0) - -#define GINTSTS				HSOTG_REG(0x014) -#define GINTMSK				HSOTG_REG(0x018) - -#define GINTSTS_WkUpInt			(1 << 31) -#define GINTSTS_SessReqInt			(1 << 30) -#define GINTSTS_DisconnInt			(1 << 29) -#define GINTSTS_ConIDStsChng			(1 << 28) -#define GINTSTS_PTxFEmp			(1 << 26) -#define GINTSTS_HChInt				(1 << 25) -#define GINTSTS_PrtInt				(1 << 24) -#define GINTSTS_FetSusp			(1 << 22) -#define GINTSTS_incompIP			(1 << 21) -#define GINTSTS_IncomplSOIN			(1 << 20) -#define GINTSTS_OEPInt				(1 << 19) -#define GINTSTS_IEPInt				(1 << 18) -#define GINTSTS_EPMis				(1 << 17) -#define GINTSTS_EOPF				(1 << 15) -#define GINTSTS_ISOutDrop			(1 << 14) -#define GINTSTS_EnumDone			(1 << 13) -#define GINTSTS_USBRst				(1 << 12) -#define GINTSTS_USBSusp			(1 << 11) -#define GINTSTS_ErlySusp			(1 << 10) -#define GINTSTS_GOUTNakEff			(1 << 7) -#define GINTSTS_GINNakEff			(1 << 6) -#define GINTSTS_NPTxFEmp			(1 << 5) -#define GINTSTS_RxFLvl				(1 << 4) -#define GINTSTS_SOF				(1 << 3) -#define GINTSTS_OTGInt				(1 << 2) -#define GINTSTS_ModeMis			(1 << 1) -#define GINTSTS_CurMod_Host			(1 << 0) - -#define GRXSTSR				HSOTG_REG(0x01C) -#define GRXSTSP				HSOTG_REG(0x020) - -#define GRXSTS_FN_MASK				(0x7f << 25) -#define GRXSTS_FN_SHIFT			(25) - -#define GRXSTS_PktSts_MASK			(0xf << 17) -#define GRXSTS_PktSts_SHIFT			(17) -#define GRXSTS_PktSts_GlobalOutNAK		(0x1 << 17) -#define GRXSTS_PktSts_OutRX			(0x2 << 17) -#define GRXSTS_PktSts_OutDone			(0x3 << 17) -#define GRXSTS_PktSts_SetupDone		(0x4 << 17) -#define GRXSTS_PktSts_SetupRX			(0x6 << 17) - -#define GRXSTS_DPID_MASK			(0x3 << 15) -#define GRXSTS_DPID_SHIFT			(15) -#define GRXSTS_ByteCnt_MASK			(0x7ff << 4) -#define GRXSTS_ByteCnt_SHIFT			(4) -#define GRXSTS_EPNum_MASK			(0xf << 0) -#define GRXSTS_EPNum_SHIFT			(0) - -#define GRXFSIZ				HSOTG_REG(0x024) - -#define GNPTXFSIZ				HSOTG_REG(0x028) - -#define GNPTXFSIZ_NPTxFDep_MASK		(0xffff << 16) -#define GNPTXFSIZ_NPTxFDep_SHIFT		(16) -#define GNPTXFSIZ_NPTxFDep_LIMIT		(0xffff) -#define GNPTXFSIZ_NPTxFDep(_x)			((_x) << 16) -#define GNPTXFSIZ_NPTxFStAddr_MASK		(0xffff << 0) -#define GNPTXFSIZ_NPTxFStAddr_SHIFT		(0) -#define GNPTXFSIZ_NPTxFStAddr_LIMIT		(0xffff) -#define GNPTXFSIZ_NPTxFStAddr(_x)		((_x) << 0) - -#define GNPTXSTS				HSOTG_REG(0x02C) - -#define GNPTXSTS_NPtxQTop_MASK			(0x7f << 24) -#define GNPTXSTS_NPtxQTop_SHIFT		(24) - -#define GNPTXSTS_NPTxQSpcAvail_MASK		(0xff << 16) -#define GNPTXSTS_NPTxQSpcAvail_SHIFT		(16) -#define GNPTXSTS_NPTxQSpcAvail_GET(_v)		(((_v) >> 16) & 0xff) - -#define GNPTXSTS_NPTxFSpcAvail_MASK		(0xffff << 0) -#define GNPTXSTS_NPTxFSpcAvail_SHIFT		(0) -#define GNPTXSTS_NPTxFSpcAvail_GET(_v)		(((_v) >> 0) & 0xffff) - - -#define HPTXFSIZ				HSOTG_REG(0x100) - -#define DPTXFSIZn(_a)		HSOTG_REG(0x104 + (((_a) - 1) * 4)) - -#define DPTXFSIZn_DPTxFSize_MASK		(0xffff << 16) -#define DPTXFSIZn_DPTxFSize_SHIFT		(16) -#define DPTXFSIZn_DPTxFSize_GET(_v)		(((_v) >> 16) & 0xffff) -#define DPTXFSIZn_DPTxFSize_LIMIT		(0xffff) -#define DPTXFSIZn_DPTxFSize(_x)		((_x) << 16) - -#define DPTXFSIZn_DPTxFStAddr_MASK		(0xffff << 0) -#define DPTXFSIZn_DPTxFStAddr_SHIFT		(0) - -/* Device mode registers */ -#define DCFG					HSOTG_REG(0x800) - -#define DCFG_EPMisCnt_MASK			(0x1f << 18) -#define DCFG_EPMisCnt_SHIFT			(18) -#define DCFG_EPMisCnt_LIMIT			(0x1f) -#define DCFG_EPMisCnt(_x)			((_x) << 18) - -#define DCFG_PerFrInt_MASK			(0x3 << 11) -#define DCFG_PerFrInt_SHIFT			(11) -#define DCFG_PerFrInt_LIMIT			(0x3) -#define DCFG_PerFrInt(_x)			((_x) << 11) - -#define DCFG_DevAddr_MASK			(0x7f << 4) -#define DCFG_DevAddr_SHIFT			(4) -#define DCFG_DevAddr_LIMIT			(0x7f) -#define DCFG_DevAddr(_x)			((_x) << 4) - -#define DCFG_NZStsOUTHShk			(1 << 2) - -#define DCFG_DevSpd_MASK			(0x3 << 0) -#define DCFG_DevSpd_SHIFT			(0) -#define DCFG_DevSpd_HS				(0x0 << 0) -#define DCFG_DevSpd_FS				(0x1 << 0) -#define DCFG_DevSpd_LS				(0x2 << 0) -#define DCFG_DevSpd_FS48			(0x3 << 0) - -#define DCTL					HSOTG_REG(0x804) - -#define DCTL_PWROnPrgDone			(1 << 11) -#define DCTL_CGOUTNak				(1 << 10) -#define DCTL_SGOUTNak				(1 << 9) -#define DCTL_CGNPInNAK				(1 << 8) -#define DCTL_SGNPInNAK				(1 << 7) -#define DCTL_TstCtl_MASK			(0x7 << 4) -#define DCTL_TstCtl_SHIFT			(4) -#define DCTL_GOUTNakSts			(1 << 3) -#define DCTL_GNPINNakSts			(1 << 2) -#define DCTL_SftDiscon				(1 << 1) -#define DCTL_RmtWkUpSig			(1 << 0) - -#define DSTS					HSOTG_REG(0x808) - -#define DSTS_SOFFN_MASK			(0x3fff << 8) -#define DSTS_SOFFN_SHIFT			(8) -#define DSTS_SOFFN_LIMIT			(0x3fff) -#define DSTS_SOFFN(_x)				((_x) << 8) -#define DSTS_ErraticErr			(1 << 3) -#define DSTS_EnumSpd_MASK			(0x3 << 1) -#define DSTS_EnumSpd_SHIFT			(1) -#define DSTS_EnumSpd_HS			(0x0 << 1) -#define DSTS_EnumSpd_FS			(0x1 << 1) -#define DSTS_EnumSpd_LS			(0x2 << 1) -#define DSTS_EnumSpd_FS48			(0x3 << 1) - -#define DSTS_SuspSts				(1 << 0) - -#define DIEPMSK				HSOTG_REG(0x810) - -#define DIEPMSK_TxFIFOEmpty			(1 << 7) -#define DIEPMSK_INEPNakEffMsk			(1 << 6) -#define DIEPMSK_INTknEPMisMsk			(1 << 5) -#define DIEPMSK_INTknTXFEmpMsk			(1 << 4) -#define DIEPMSK_TimeOUTMsk			(1 << 3) -#define DIEPMSK_AHBErrMsk			(1 << 2) -#define DIEPMSK_EPDisbldMsk			(1 << 1) -#define DIEPMSK_XferComplMsk			(1 << 0) - -#define DOEPMSK				HSOTG_REG(0x814) - -#define DOEPMSK_Back2BackSetup			(1 << 6) -#define DOEPMSK_OUTTknEPdisMsk			(1 << 4) -#define DOEPMSK_SetupMsk			(1 << 3) -#define DOEPMSK_AHBErrMsk			(1 << 2) -#define DOEPMSK_EPDisbldMsk			(1 << 1) -#define DOEPMSK_XferComplMsk			(1 << 0) - -#define DAINT					HSOTG_REG(0x818) -#define DAINTMSK				HSOTG_REG(0x81C) - -#define DAINT_OutEP_SHIFT			(16) -#define DAINT_OutEP(x)				(1 << ((x) + 16)) -#define DAINT_InEP(x)				(1 << (x)) - -#define DTKNQR1				HSOTG_REG(0x820) -#define DTKNQR2				HSOTG_REG(0x824) -#define DTKNQR3				HSOTG_REG(0x830) -#define DTKNQR4				HSOTG_REG(0x834) - -#define DVBUSDIS				HSOTG_REG(0x828) -#define DVBUSPULSE				HSOTG_REG(0x82C) - -#define DIEPCTL0				HSOTG_REG(0x900) -#define DOEPCTL0				HSOTG_REG(0xB00) -#define DIEPCTL(_a)			HSOTG_REG(0x900 + ((_a) * 0x20)) -#define DOEPCTL(_a)			HSOTG_REG(0xB00 + ((_a) * 0x20)) - -/* EP0 specialness: - * bits[29..28] - reserved (no SetD0PID, SetD1PID) - * bits[25..22] - should always be zero, this isn't a periodic endpoint - * bits[10..0] - MPS setting differenct for EP0 - */ -#define D0EPCTL_MPS_MASK			(0x3 << 0) -#define D0EPCTL_MPS_SHIFT			(0) -#define D0EPCTL_MPS_64				(0x0 << 0) -#define D0EPCTL_MPS_32				(0x1 << 0) -#define D0EPCTL_MPS_16				(0x2 << 0) -#define D0EPCTL_MPS_8				(0x3 << 0) - -#define DxEPCTL_EPEna				(1 << 31) -#define DxEPCTL_EPDis				(1 << 30) -#define DxEPCTL_SetD1PID			(1 << 29) -#define DxEPCTL_SetOddFr			(1 << 29) -#define DxEPCTL_SetD0PID			(1 << 28) -#define DxEPCTL_SetEvenFr			(1 << 28) -#define DxEPCTL_SNAK				(1 << 27) -#define DxEPCTL_CNAK				(1 << 26) -#define DxEPCTL_TxFNum_MASK			(0xf << 22) -#define DxEPCTL_TxFNum_SHIFT			(22) -#define DxEPCTL_TxFNum_LIMIT			(0xf) -#define DxEPCTL_TxFNum(_x)			((_x) << 22) - -#define DxEPCTL_Stall				(1 << 21) -#define DxEPCTL_Snp				(1 << 20) -#define DxEPCTL_EPType_MASK			(0x3 << 18) -#define DxEPCTL_EPType_SHIFT			(18) -#define DxEPCTL_EPType_Control			(0x0 << 18) -#define DxEPCTL_EPType_Iso			(0x1 << 18) -#define DxEPCTL_EPType_Bulk			(0x2 << 18) -#define DxEPCTL_EPType_Intterupt		(0x3 << 18) - -#define DxEPCTL_NAKsts				(1 << 17) -#define DxEPCTL_DPID				(1 << 16) -#define DxEPCTL_EOFrNum			(1 << 16) -#define DxEPCTL_USBActEp			(1 << 15) -#define DxEPCTL_NextEp_MASK			(0xf << 11) -#define DxEPCTL_NextEp_SHIFT			(11) -#define DxEPCTL_NextEp_LIMIT			(0xf) -#define DxEPCTL_NextEp(_x)			((_x) << 11) - -#define DxEPCTL_MPS_MASK			(0x7ff << 0) -#define DxEPCTL_MPS_SHIFT			(0) -#define DxEPCTL_MPS_LIMIT			(0x7ff) -#define DxEPCTL_MPS(_x)			((_x) << 0) - -#define DIEPINT(_a)			HSOTG_REG(0x908 + ((_a) * 0x20)) -#define DOEPINT(_a)			HSOTG_REG(0xB08 + ((_a) * 0x20)) - -#define DxEPINT_INEPNakEff			(1 << 6) -#define DxEPINT_Back2BackSetup			(1 << 6) -#define DxEPINT_INTknEPMis			(1 << 5) -#define DxEPINT_INTknTXFEmp			(1 << 4) -#define DxEPINT_OUTTknEPdis			(1 << 4) -#define DxEPINT_Timeout			(1 << 3) -#define DxEPINT_Setup				(1 << 3) -#define DxEPINT_AHBErr				(1 << 2) -#define DxEPINT_EPDisbld			(1 << 1) -#define DxEPINT_XferCompl			(1 << 0) - -#define DIEPTSIZ0				HSOTG_REG(0x910) - -#define DIEPTSIZ0_PktCnt_MASK			(0x3 << 19) -#define DIEPTSIZ0_PktCnt_SHIFT			(19) -#define DIEPTSIZ0_PktCnt_LIMIT			(0x3) -#define DIEPTSIZ0_PktCnt(_x)			((_x) << 19) - -#define DIEPTSIZ0_XferSize_MASK		(0x7f << 0) -#define DIEPTSIZ0_XferSize_SHIFT		(0) -#define DIEPTSIZ0_XferSize_LIMIT		(0x7f) -#define DIEPTSIZ0_XferSize(_x)			((_x) << 0) - -#define DOEPTSIZ0				HSOTG_REG(0xB10) -#define DOEPTSIZ0_SUPCnt_MASK			(0x3 << 29) -#define DOEPTSIZ0_SUPCnt_SHIFT			(29) -#define DOEPTSIZ0_SUPCnt_LIMIT			(0x3) -#define DOEPTSIZ0_SUPCnt(_x)			((_x) << 29) - -#define DOEPTSIZ0_PktCnt			(1 << 19) -#define DOEPTSIZ0_XferSize_MASK		(0x7f << 0) -#define DOEPTSIZ0_XferSize_SHIFT		(0) - -#define DIEPTSIZ(_a)			HSOTG_REG(0x910 + ((_a) * 0x20)) -#define DOEPTSIZ(_a)			HSOTG_REG(0xB10 + ((_a) * 0x20)) - -#define DxEPTSIZ_MC_MASK			(0x3 << 29) -#define DxEPTSIZ_MC_SHIFT			(29) -#define DxEPTSIZ_MC_LIMIT			(0x3) -#define DxEPTSIZ_MC(_x)			((_x) << 29) - -#define DxEPTSIZ_PktCnt_MASK			(0x3ff << 19) -#define DxEPTSIZ_PktCnt_SHIFT			(19) -#define DxEPTSIZ_PktCnt_GET(_v)		(((_v) >> 19) & 0x3ff) -#define DxEPTSIZ_PktCnt_LIMIT			(0x3ff) -#define DxEPTSIZ_PktCnt(_x)			((_x) << 19) - -#define DxEPTSIZ_XferSize_MASK			(0x7ffff << 0) -#define DxEPTSIZ_XferSize_SHIFT		(0) -#define DxEPTSIZ_XferSize_GET(_v)		(((_v) >> 0) & 0x7ffff) -#define DxEPTSIZ_XferSize_LIMIT		(0x7ffff) -#define DxEPTSIZ_XferSize(_x)			((_x) << 0) - -#define DIEPDMA(_a)			HSOTG_REG(0x914 + ((_a) * 0x20)) -#define DOEPDMA(_a)			HSOTG_REG(0xB14 + ((_a) * 0x20)) -#define DTXFSTS(_a)			HSOTG_REG(0x918 + ((_a) * 0x20)) - -#define EPFIFO(_a)			HSOTG_REG(0x1000 + ((_a) * 0x1000)) - -#endif /* __REGS_USB_HSOTG_H */ diff --git a/drivers/usb/gadget/s3c-hsudc.c b/drivers/usb/gadget/s3c-hsudc.c index 1a1a41498db..10c6a128250 100644 --- a/drivers/usb/gadget/s3c-hsudc.c +++ b/drivers/usb/gadget/s3c-hsudc.c @@ -999,7 +999,7 @@ static void s3c_hsudc_initep(struct s3c_hsudc *hsudc,  	hsep->dev = hsudc;  	hsep->ep.name = hsep->name; -	hsep->ep.maxpacket = epnum ? 512 : 64; +	usb_ep_set_maxpacket_limit(&hsep->ep, epnum ? 512 : 64);  	hsep->ep.ops = &s3c_hsudc_ep_ops;  	hsep->fifo = hsudc->regs + S3C_BR(epnum);  	hsep->ep.desc = NULL; @@ -1344,7 +1344,6 @@ static int s3c_hsudc_probe(struct platform_device *pdev)  	return 0;  err_add_udc: -err_add_device:  	clk_disable(hsudc->uclk);  err_res:  	if (!IS_ERR_OR_NULL(hsudc->transceiver)) diff --git a/drivers/usb/gadget/s3c2410_udc.c b/drivers/usb/gadget/s3c2410_udc.c index c72d810e6b3..7987aa049fa 100644 --- a/drivers/usb/gadget/s3c2410_udc.c +++ b/drivers/usb/gadget/s3c2410_udc.c @@ -117,7 +117,8 @@ static int dprintk(int level, const char *fmt, ...)  			sizeof(printk_buf)-len, fmt, args);  	va_end(args); -	return pr_debug("%s", printk_buf); +	pr_debug("%s", printk_buf); +	return len;  }  #else  static int dprintk(int level, const char *fmt, ...) @@ -1629,6 +1630,7 @@ static void s3c2410_udc_reinit(struct s3c2410_udc *dev)  		ep->ep.desc = NULL;  		ep->halted = 0;  		INIT_LIST_HEAD(&ep->queue); +		usb_ep_set_maxpacket_limit(&ep->ep, ep->ep.maxpacket);  	}  } diff --git a/drivers/usb/gadget/storage_common.c b/drivers/usb/gadget/storage_common.c index 08a1a3210a2..648f9e489b3 100644 --- a/drivers/usb/gadget/storage_common.c +++ b/drivers/usb/gadget/storage_common.c @@ -23,242 +23,17 @@   * The valid range of num_buffers is: num >= 2 && num <= 4.   */ +#include <linux/module.h> +#include <linux/blkdev.h> +#include <linux/file.h> +#include <linux/fs.h> +#include <linux/usb/composite.h> -#include <linux/usb/storage.h> -#include <scsi/scsi.h> -#include <asm/unaligned.h> - - -/* - * Thanks to NetChip Technologies for donating this product ID. - * - * DO NOT REUSE THESE IDs with any other driver!!  Ever!! - * Instead:  allocate your own, using normal USB-IF procedures. - */ -#define FSG_VENDOR_ID	0x0525	/* NetChip */ -#define FSG_PRODUCT_ID	0xa4a5	/* Linux-USB File-backed Storage Gadget */ - - -/*-------------------------------------------------------------------------*/ - - -#ifndef DEBUG -#undef VERBOSE_DEBUG -#undef DUMP_MSGS -#endif /* !DEBUG */ - -#ifdef VERBOSE_DEBUG -#define VLDBG	LDBG -#else -#define VLDBG(lun, fmt, args...) do { } while (0) -#endif /* VERBOSE_DEBUG */ - -#define LDBG(lun, fmt, args...)   dev_dbg (&(lun)->dev, fmt, ## args) -#define LERROR(lun, fmt, args...) dev_err (&(lun)->dev, fmt, ## args) -#define LWARN(lun, fmt, args...)  dev_warn(&(lun)->dev, fmt, ## args) -#define LINFO(lun, fmt, args...)  dev_info(&(lun)->dev, fmt, ## args) - - -#ifdef DUMP_MSGS - -#  define dump_msg(fsg, /* const char * */ label,			\ -		   /* const u8 * */ buf, /* unsigned */ length) do {	\ -	if (length < 512) {						\ -		DBG(fsg, "%s, length %u:\n", label, length);		\ -		print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET,	\ -			       16, 1, buf, length, 0);			\ -	}								\ -} while (0) - -#  define dump_cdb(fsg) do { } while (0) - -#else - -#  define dump_msg(fsg, /* const char * */ label, \ -		   /* const u8 * */ buf, /* unsigned */ length) do { } while (0) - -#  ifdef VERBOSE_DEBUG - -#    define dump_cdb(fsg)						\ -	print_hex_dump(KERN_DEBUG, "SCSI CDB: ", DUMP_PREFIX_NONE,	\ -		       16, 1, (fsg)->cmnd, (fsg)->cmnd_size, 0)		\ - -#  else - -#    define dump_cdb(fsg) do { } while (0) - -#  endif /* VERBOSE_DEBUG */ - -#endif /* DUMP_MSGS */ - -/*-------------------------------------------------------------------------*/ - -/* Length of a SCSI Command Data Block */ -#define MAX_COMMAND_SIZE	16 - -/* SCSI Sense Key/Additional Sense Code/ASC Qualifier values */ -#define SS_NO_SENSE				0 -#define SS_COMMUNICATION_FAILURE		0x040800 -#define SS_INVALID_COMMAND			0x052000 -#define SS_INVALID_FIELD_IN_CDB			0x052400 -#define SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE	0x052100 -#define SS_LOGICAL_UNIT_NOT_SUPPORTED		0x052500 -#define SS_MEDIUM_NOT_PRESENT			0x023a00 -#define SS_MEDIUM_REMOVAL_PREVENTED		0x055302 -#define SS_NOT_READY_TO_READY_TRANSITION	0x062800 -#define SS_RESET_OCCURRED			0x062900 -#define SS_SAVING_PARAMETERS_NOT_SUPPORTED	0x053900 -#define SS_UNRECOVERED_READ_ERROR		0x031100 -#define SS_WRITE_ERROR				0x030c02 -#define SS_WRITE_PROTECTED			0x072700 - -#define SK(x)		((u8) ((x) >> 16))	/* Sense Key byte, etc. */ -#define ASC(x)		((u8) ((x) >> 8)) -#define ASCQ(x)		((u8) (x)) - - -/*-------------------------------------------------------------------------*/ - - -struct fsg_lun { -	struct file	*filp; -	loff_t		file_length; -	loff_t		num_sectors; - -	unsigned int	initially_ro:1; -	unsigned int	ro:1; -	unsigned int	removable:1; -	unsigned int	cdrom:1; -	unsigned int	prevent_medium_removal:1; -	unsigned int	registered:1; -	unsigned int	info_valid:1; -	unsigned int	nofua:1; - -	u32		sense_data; -	u32		sense_data_info; -	u32		unit_attention_data; - -	unsigned int	blkbits;	/* Bits of logical block size of bound block device */ -	unsigned int	blksize;	/* logical block size of bound block device */ -	struct device	dev; -}; - -static inline bool fsg_lun_is_open(struct fsg_lun *curlun) -{ -	return curlun->filp != NULL; -} - -static inline struct fsg_lun *fsg_lun_from_dev(struct device *dev) -{ -	return container_of(dev, struct fsg_lun, dev); -} - - -/* Big enough to hold our biggest descriptor */ -#define EP0_BUFSIZE	256 -#define DELAYED_STATUS	(EP0_BUFSIZE + 999)	/* An impossibly large value */ - -#ifdef CONFIG_USB_GADGET_DEBUG_FILES - -static unsigned int fsg_num_buffers = CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS; -module_param_named(num_buffers, fsg_num_buffers, uint, S_IRUGO); -MODULE_PARM_DESC(num_buffers, "Number of pipeline buffers"); - -#else - -/* - * Number of buffers we will use. - * 2 is usually enough for good buffering pipeline - */ -#define fsg_num_buffers	CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS - -#endif /* CONFIG_USB_GADGET_DEBUG_FILES */ - -/* check if fsg_num_buffers is within a valid range */ -static inline int fsg_num_buffers_validate(void) -{ -	if (fsg_num_buffers >= 2 && fsg_num_buffers <= 4) -		return 0; -	pr_err("fsg_num_buffers %u is out of range (%d to %d)\n", -	       fsg_num_buffers, 2 ,4); -	return -EINVAL; -} - -/* Default size of buffer length. */ -#define FSG_BUFLEN	((u32)16384) - -/* Maximal number of LUNs supported in mass storage function */ -#define FSG_MAX_LUNS	8 - -enum fsg_buffer_state { -	BUF_STATE_EMPTY = 0, -	BUF_STATE_FULL, -	BUF_STATE_BUSY -}; - -struct fsg_buffhd { -	void				*buf; -	enum fsg_buffer_state		state; -	struct fsg_buffhd		*next; - -	/* -	 * The NetChip 2280 is faster, and handles some protocol faults -	 * better, if we don't submit any short bulk-out read requests. -	 * So we will record the intended request length here. -	 */ -	unsigned int			bulk_out_intended_length; - -	struct usb_request		*inreq; -	int				inreq_busy; -	struct usb_request		*outreq; -	int				outreq_busy; -}; - -enum fsg_state { -	/* This one isn't used anywhere */ -	FSG_STATE_COMMAND_PHASE = -10, -	FSG_STATE_DATA_PHASE, -	FSG_STATE_STATUS_PHASE, - -	FSG_STATE_IDLE = 0, -	FSG_STATE_ABORT_BULK_OUT, -	FSG_STATE_RESET, -	FSG_STATE_INTERFACE_CHANGE, -	FSG_STATE_CONFIG_CHANGE, -	FSG_STATE_DISCONNECT, -	FSG_STATE_EXIT, -	FSG_STATE_TERMINATED -}; - -enum data_direction { -	DATA_DIR_UNKNOWN = 0, -	DATA_DIR_FROM_HOST, -	DATA_DIR_TO_HOST, -	DATA_DIR_NONE -}; - - -/*-------------------------------------------------------------------------*/ - - -static inline u32 get_unaligned_be24(u8 *buf) -{ -	return 0xffffff & (u32) get_unaligned_be32(buf - 1); -} - - -/*-------------------------------------------------------------------------*/ - - -enum { -	FSG_STRING_INTERFACE -}; - +#include "storage_common.h"  /* There is only one interface. */ -static struct usb_interface_descriptor -fsg_intf_desc = { +struct usb_interface_descriptor fsg_intf_desc = {  	.bLength =		sizeof fsg_intf_desc,  	.bDescriptorType =	USB_DT_INTERFACE, @@ -268,14 +43,14 @@ fsg_intf_desc = {  	.bInterfaceProtocol =	USB_PR_BULK,	/* Adjusted during fsg_bind() */  	.iInterface =		FSG_STRING_INTERFACE,  }; +EXPORT_SYMBOL_GPL(fsg_intf_desc);  /*   * Three full-speed endpoint descriptors: bulk-in, bulk-out, and   * interrupt-in.   */ -static struct usb_endpoint_descriptor -fsg_fs_bulk_in_desc = { +struct usb_endpoint_descriptor fsg_fs_bulk_in_desc = {  	.bLength =		USB_DT_ENDPOINT_SIZE,  	.bDescriptorType =	USB_DT_ENDPOINT, @@ -283,9 +58,9 @@ fsg_fs_bulk_in_desc = {  	.bmAttributes =		USB_ENDPOINT_XFER_BULK,  	/* wMaxPacketSize set by autoconfiguration */  }; +EXPORT_SYMBOL_GPL(fsg_fs_bulk_in_desc); -static struct usb_endpoint_descriptor -fsg_fs_bulk_out_desc = { +struct usb_endpoint_descriptor fsg_fs_bulk_out_desc = {  	.bLength =		USB_DT_ENDPOINT_SIZE,  	.bDescriptorType =	USB_DT_ENDPOINT, @@ -293,13 +68,15 @@ fsg_fs_bulk_out_desc = {  	.bmAttributes =		USB_ENDPOINT_XFER_BULK,  	/* wMaxPacketSize set by autoconfiguration */  }; +EXPORT_SYMBOL_GPL(fsg_fs_bulk_out_desc); -static struct usb_descriptor_header *fsg_fs_function[] = { +struct usb_descriptor_header *fsg_fs_function[] = {  	(struct usb_descriptor_header *) &fsg_intf_desc,  	(struct usb_descriptor_header *) &fsg_fs_bulk_in_desc,  	(struct usb_descriptor_header *) &fsg_fs_bulk_out_desc,  	NULL,  }; +EXPORT_SYMBOL_GPL(fsg_fs_function);  /* @@ -310,8 +87,7 @@ static struct usb_descriptor_header *fsg_fs_function[] = {   * and a "device qualifier" ... plus more construction options   * for the configuration descriptor.   */ -static struct usb_endpoint_descriptor -fsg_hs_bulk_in_desc = { +struct usb_endpoint_descriptor fsg_hs_bulk_in_desc = {  	.bLength =		USB_DT_ENDPOINT_SIZE,  	.bDescriptorType =	USB_DT_ENDPOINT, @@ -319,9 +95,9 @@ fsg_hs_bulk_in_desc = {  	.bmAttributes =		USB_ENDPOINT_XFER_BULK,  	.wMaxPacketSize =	cpu_to_le16(512),  }; +EXPORT_SYMBOL_GPL(fsg_hs_bulk_in_desc); -static struct usb_endpoint_descriptor -fsg_hs_bulk_out_desc = { +struct usb_endpoint_descriptor fsg_hs_bulk_out_desc = {  	.bLength =		USB_DT_ENDPOINT_SIZE,  	.bDescriptorType =	USB_DT_ENDPOINT, @@ -330,17 +106,18 @@ fsg_hs_bulk_out_desc = {  	.wMaxPacketSize =	cpu_to_le16(512),  	.bInterval =		1,	/* NAK every 1 uframe */  }; +EXPORT_SYMBOL_GPL(fsg_hs_bulk_out_desc); -static struct usb_descriptor_header *fsg_hs_function[] = { +struct usb_descriptor_header *fsg_hs_function[] = {  	(struct usb_descriptor_header *) &fsg_intf_desc,  	(struct usb_descriptor_header *) &fsg_hs_bulk_in_desc,  	(struct usb_descriptor_header *) &fsg_hs_bulk_out_desc,  	NULL,  }; +EXPORT_SYMBOL_GPL(fsg_hs_function); -static struct usb_endpoint_descriptor -fsg_ss_bulk_in_desc = { +struct usb_endpoint_descriptor fsg_ss_bulk_in_desc = {  	.bLength =		USB_DT_ENDPOINT_SIZE,  	.bDescriptorType =	USB_DT_ENDPOINT, @@ -348,16 +125,17 @@ fsg_ss_bulk_in_desc = {  	.bmAttributes =		USB_ENDPOINT_XFER_BULK,  	.wMaxPacketSize =	cpu_to_le16(1024),  }; +EXPORT_SYMBOL_GPL(fsg_ss_bulk_in_desc); -static struct usb_ss_ep_comp_descriptor fsg_ss_bulk_in_comp_desc = { +struct usb_ss_ep_comp_descriptor fsg_ss_bulk_in_comp_desc = {  	.bLength =		sizeof(fsg_ss_bulk_in_comp_desc),  	.bDescriptorType =	USB_DT_SS_ENDPOINT_COMP,  	/*.bMaxBurst =		DYNAMIC, */  }; +EXPORT_SYMBOL_GPL(fsg_ss_bulk_in_comp_desc); -static struct usb_endpoint_descriptor -fsg_ss_bulk_out_desc = { +struct usb_endpoint_descriptor fsg_ss_bulk_out_desc = {  	.bLength =		USB_DT_ENDPOINT_SIZE,  	.bDescriptorType =	USB_DT_ENDPOINT, @@ -365,15 +143,17 @@ fsg_ss_bulk_out_desc = {  	.bmAttributes =		USB_ENDPOINT_XFER_BULK,  	.wMaxPacketSize =	cpu_to_le16(1024),  }; +EXPORT_SYMBOL_GPL(fsg_ss_bulk_out_desc); -static struct usb_ss_ep_comp_descriptor fsg_ss_bulk_out_comp_desc = { +struct usb_ss_ep_comp_descriptor fsg_ss_bulk_out_comp_desc = {  	.bLength =		sizeof(fsg_ss_bulk_in_comp_desc),  	.bDescriptorType =	USB_DT_SS_ENDPOINT_COMP,  	/*.bMaxBurst =		DYNAMIC, */  }; +EXPORT_SYMBOL_GPL(fsg_ss_bulk_out_comp_desc); -static struct usb_descriptor_header *fsg_ss_function[] = { +struct usb_descriptor_header *fsg_ss_function[] = {  	(struct usb_descriptor_header *) &fsg_intf_desc,  	(struct usb_descriptor_header *) &fsg_ss_bulk_in_desc,  	(struct usb_descriptor_header *) &fsg_ss_bulk_in_comp_desc, @@ -381,17 +161,7 @@ static struct usb_descriptor_header *fsg_ss_function[] = {  	(struct usb_descriptor_header *) &fsg_ss_bulk_out_comp_desc,  	NULL,  }; - -/* Static strings, in UTF-8 (for simplicity we use only ASCII characters) */ -static struct usb_string		fsg_strings[] = { -	{FSG_STRING_INTERFACE,		fsg_string_interface}, -	{} -}; - -static struct usb_gadget_strings	fsg_stringtab = { -	.language	= 0x0409,		/* en-us */ -	.strings	= fsg_strings, -}; +EXPORT_SYMBOL_GPL(fsg_ss_function);   /*-------------------------------------------------------------------------*/ @@ -401,7 +171,7 @@ static struct usb_gadget_strings	fsg_stringtab = {   * the caller must own fsg->filesem for writing.   */ -static void fsg_lun_close(struct fsg_lun *curlun) +void fsg_lun_close(struct fsg_lun *curlun)  {  	if (curlun->filp) {  		LDBG(curlun, "close backing file\n"); @@ -409,9 +179,9 @@ static void fsg_lun_close(struct fsg_lun *curlun)  		curlun->filp = NULL;  	}  } +EXPORT_SYMBOL_GPL(fsg_lun_close); - -static int fsg_lun_open(struct fsg_lun *curlun, const char *filename) +int fsg_lun_open(struct fsg_lun *curlun, const char *filename)  {  	int				ro;  	struct file			*filp = NULL; @@ -450,11 +220,11 @@ static int fsg_lun_open(struct fsg_lun *curlun, const char *filename)  	 * If we can't read the file, it's no good.  	 * If we can't write the file, use it read-only.  	 */ -	if (!(filp->f_op->read || filp->f_op->aio_read)) { +	if (!(filp->f_mode & FMODE_CAN_READ)) {  		LINFO(curlun, "file not readable: %s\n", filename);  		goto out;  	} -	if (!(filp->f_op->write || filp->f_op->aio_write)) +	if (!(filp->f_mode & FMODE_CAN_WRITE))  		ro = 1;  	size = i_size_read(inode->i_mapping->host); @@ -508,6 +278,7 @@ out:  	fput(filp);  	return rc;  } +EXPORT_SYMBOL_GPL(fsg_lun_open);  /*-------------------------------------------------------------------------*/ @@ -516,7 +287,7 @@ out:   * Sync the file data, don't bother with the metadata.   * This code was copied from fs/buffer.c:sys_fdatasync().   */ -static int fsg_lun_fsync_sub(struct fsg_lun *curlun) +int fsg_lun_fsync_sub(struct fsg_lun *curlun)  {  	struct file	*filp = curlun->filp; @@ -524,8 +295,9 @@ static int fsg_lun_fsync_sub(struct fsg_lun *curlun)  		return 0;  	return vfs_fsync(filp, 1);  } +EXPORT_SYMBOL_GPL(fsg_lun_fsync_sub); -static void store_cdrom_address(u8 *dest, int msf, u32 addr) +void store_cdrom_address(u8 *dest, int msf, u32 addr)  {  	if (msf) {  		/* Convert to Minutes-Seconds-Frames */ @@ -542,34 +314,28 @@ static void store_cdrom_address(u8 *dest, int msf, u32 addr)  		put_unaligned_be32(addr, dest);  	}  } - +EXPORT_SYMBOL_GPL(store_cdrom_address);  /*-------------------------------------------------------------------------*/ -static ssize_t ro_show(struct device *dev, struct device_attribute *attr, -		       char *buf) +ssize_t fsg_show_ro(struct fsg_lun *curlun, char *buf)  { -	struct fsg_lun	*curlun = fsg_lun_from_dev(dev); -  	return sprintf(buf, "%d\n", fsg_lun_is_open(curlun)  				  ? curlun->ro  				  : curlun->initially_ro);  } +EXPORT_SYMBOL_GPL(fsg_show_ro); -static ssize_t nofua_show(struct device *dev, struct device_attribute *attr, -			  char *buf) +ssize_t fsg_show_nofua(struct fsg_lun *curlun, char *buf)  { -	struct fsg_lun	*curlun = fsg_lun_from_dev(dev); -  	return sprintf(buf, "%u\n", curlun->nofua);  } +EXPORT_SYMBOL_GPL(fsg_show_nofua); -static ssize_t file_show(struct device *dev, struct device_attribute *attr, -			 char *buf) +ssize_t fsg_show_file(struct fsg_lun *curlun, struct rw_semaphore *filesem, +		      char *buf)  { -	struct fsg_lun	*curlun = fsg_lun_from_dev(dev); -	struct rw_semaphore	*filesem = dev_get_drvdata(dev);  	char		*p;  	ssize_t		rc; @@ -591,17 +357,44 @@ static ssize_t file_show(struct device *dev, struct device_attribute *attr,  	up_read(filesem);  	return rc;  } +EXPORT_SYMBOL_GPL(fsg_show_file); +ssize_t fsg_show_cdrom(struct fsg_lun *curlun, char *buf) +{ +	return sprintf(buf, "%u\n", curlun->cdrom); +} +EXPORT_SYMBOL_GPL(fsg_show_cdrom); -static ssize_t ro_store(struct device *dev, struct device_attribute *attr, -			const char *buf, size_t count) +ssize_t fsg_show_removable(struct fsg_lun *curlun, char *buf) +{ +	return sprintf(buf, "%u\n", curlun->removable); +} +EXPORT_SYMBOL_GPL(fsg_show_removable); + +/* + * The caller must hold fsg->filesem for reading when calling this function. + */ +static ssize_t _fsg_store_ro(struct fsg_lun *curlun, bool ro) +{ +	if (fsg_lun_is_open(curlun)) { +		LDBG(curlun, "read-only status change prevented\n"); +		return -EBUSY; +	} + +	curlun->ro = ro; +	curlun->initially_ro = ro; +	LDBG(curlun, "read-only status set to %d\n", curlun->ro); + +	return 0; +} + +ssize_t fsg_store_ro(struct fsg_lun *curlun, struct rw_semaphore *filesem, +		     const char *buf, size_t count)  {  	ssize_t		rc; -	struct fsg_lun	*curlun = fsg_lun_from_dev(dev); -	struct rw_semaphore	*filesem = dev_get_drvdata(dev); -	unsigned	ro; +	bool		ro; -	rc = kstrtouint(buf, 2, &ro); +	rc = strtobool(buf, &ro);  	if (rc)  		return rc; @@ -610,27 +403,21 @@ static ssize_t ro_store(struct device *dev, struct device_attribute *attr,  	 * backing file is closed.  	 */  	down_read(filesem); -	if (fsg_lun_is_open(curlun)) { -		LDBG(curlun, "read-only status change prevented\n"); -		rc = -EBUSY; -	} else { -		curlun->ro = ro; -		curlun->initially_ro = ro; -		LDBG(curlun, "read-only status set to %d\n", curlun->ro); +	rc = _fsg_store_ro(curlun, ro); +	if (!rc)  		rc = count; -	}  	up_read(filesem); +  	return rc;  } +EXPORT_SYMBOL_GPL(fsg_store_ro); -static ssize_t nofua_store(struct device *dev, struct device_attribute *attr, -			   const char *buf, size_t count) +ssize_t fsg_store_nofua(struct fsg_lun *curlun, const char *buf, size_t count)  { -	struct fsg_lun	*curlun = fsg_lun_from_dev(dev); -	unsigned	nofua; +	bool		nofua;  	int		ret; -	ret = kstrtouint(buf, 2, &nofua); +	ret = strtobool(buf, &nofua);  	if (ret)  		return ret; @@ -642,12 +429,11 @@ static ssize_t nofua_store(struct device *dev, struct device_attribute *attr,  	return count;  } +EXPORT_SYMBOL_GPL(fsg_store_nofua); -static ssize_t file_store(struct device *dev, struct device_attribute *attr, -			  const char *buf, size_t count) +ssize_t fsg_store_file(struct fsg_lun *curlun, struct rw_semaphore *filesem, +		       const char *buf, size_t count)  { -	struct fsg_lun	*curlun = fsg_lun_from_dev(dev); -	struct rw_semaphore	*filesem = dev_get_drvdata(dev);  	int		rc = 0;  	if (curlun->prevent_medium_removal && fsg_lun_is_open(curlun)) { @@ -674,3 +460,45 @@ static ssize_t file_store(struct device *dev, struct device_attribute *attr,  	up_write(filesem);  	return (rc < 0 ? rc : count);  } +EXPORT_SYMBOL_GPL(fsg_store_file); + +ssize_t fsg_store_cdrom(struct fsg_lun *curlun, struct rw_semaphore *filesem, +			const char *buf, size_t count) +{ +	bool		cdrom; +	int		ret; + +	ret = strtobool(buf, &cdrom); +	if (ret) +		return ret; + +	down_read(filesem); +	ret = cdrom ? _fsg_store_ro(curlun, true) : 0; + +	if (!ret) { +		curlun->cdrom = cdrom; +		ret = count; +	} +	up_read(filesem); + +	return ret; +} +EXPORT_SYMBOL_GPL(fsg_store_cdrom); + +ssize_t fsg_store_removable(struct fsg_lun *curlun, const char *buf, +			    size_t count) +{ +	bool		removable; +	int		ret; + +	ret = strtobool(buf, &removable); +	if (ret) +		return ret; + +	curlun->removable = removable; + +	return count; +} +EXPORT_SYMBOL_GPL(fsg_store_removable); + +MODULE_LICENSE("GPL"); diff --git a/drivers/usb/gadget/storage_common.h b/drivers/usb/gadget/storage_common.h new file mode 100644 index 00000000000..70c891469f5 --- /dev/null +++ b/drivers/usb/gadget/storage_common.h @@ -0,0 +1,225 @@ +#ifndef USB_STORAGE_COMMON_H +#define USB_STORAGE_COMMON_H + +#include <linux/device.h> +#include <linux/usb/storage.h> +#include <scsi/scsi.h> +#include <asm/unaligned.h> + +#ifndef DEBUG +#undef VERBOSE_DEBUG +#undef DUMP_MSGS +#endif /* !DEBUG */ + +#ifdef VERBOSE_DEBUG +#define VLDBG	LDBG +#else +#define VLDBG(lun, fmt, args...) do { } while (0) +#endif /* VERBOSE_DEBUG */ + +#define _LMSG(func, lun, fmt, args...)					\ +	do {								\ +		if ((lun)->name_pfx && *(lun)->name_pfx)		\ +			func("%s/%s: " fmt, *(lun)->name_pfx,		\ +				 (lun)->name, ## args);			\ +		else							\ +			func("%s: " fmt, (lun)->name, ## args);		\ +	} while (0) + +#define LDBG(lun, fmt, args...)		_LMSG(pr_debug, lun, fmt, ## args) +#define LERROR(lun, fmt, args...)	_LMSG(pr_err, lun, fmt, ## args) +#define LWARN(lun, fmt, args...)	_LMSG(pr_warn, lun, fmt, ## args) +#define LINFO(lun, fmt, args...)	_LMSG(pr_info, lun, fmt, ## args) + + +#ifdef DUMP_MSGS + +#  define dump_msg(fsg, /* const char * */ label,			\ +		   /* const u8 * */ buf, /* unsigned */ length)		\ +do {									\ +	if (length < 512) {						\ +		DBG(fsg, "%s, length %u:\n", label, length);		\ +		print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET,	\ +			       16, 1, buf, length, 0);			\ +	}								\ +} while (0) + +#  define dump_cdb(fsg) do { } while (0) + +#else + +#  define dump_msg(fsg, /* const char * */ label, \ +		   /* const u8 * */ buf, /* unsigned */ length) do { } while (0) + +#  ifdef VERBOSE_DEBUG + +#    define dump_cdb(fsg)						\ +	print_hex_dump(KERN_DEBUG, "SCSI CDB: ", DUMP_PREFIX_NONE,	\ +		       16, 1, (fsg)->cmnd, (fsg)->cmnd_size, 0)		\ + +#  else + +#    define dump_cdb(fsg) do { } while (0) + +#  endif /* VERBOSE_DEBUG */ + +#endif /* DUMP_MSGS */ + +/* Length of a SCSI Command Data Block */ +#define MAX_COMMAND_SIZE	16 + +/* SCSI Sense Key/Additional Sense Code/ASC Qualifier values */ +#define SS_NO_SENSE				0 +#define SS_COMMUNICATION_FAILURE		0x040800 +#define SS_INVALID_COMMAND			0x052000 +#define SS_INVALID_FIELD_IN_CDB			0x052400 +#define SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE	0x052100 +#define SS_LOGICAL_UNIT_NOT_SUPPORTED		0x052500 +#define SS_MEDIUM_NOT_PRESENT			0x023a00 +#define SS_MEDIUM_REMOVAL_PREVENTED		0x055302 +#define SS_NOT_READY_TO_READY_TRANSITION	0x062800 +#define SS_RESET_OCCURRED			0x062900 +#define SS_SAVING_PARAMETERS_NOT_SUPPORTED	0x053900 +#define SS_UNRECOVERED_READ_ERROR		0x031100 +#define SS_WRITE_ERROR				0x030c02 +#define SS_WRITE_PROTECTED			0x072700 + +#define SK(x)		((u8) ((x) >> 16))	/* Sense Key byte, etc. */ +#define ASC(x)		((u8) ((x) >> 8)) +#define ASCQ(x)		((u8) (x)) + +struct fsg_lun { +	struct file	*filp; +	loff_t		file_length; +	loff_t		num_sectors; + +	unsigned int	initially_ro:1; +	unsigned int	ro:1; +	unsigned int	removable:1; +	unsigned int	cdrom:1; +	unsigned int	prevent_medium_removal:1; +	unsigned int	registered:1; +	unsigned int	info_valid:1; +	unsigned int	nofua:1; + +	u32		sense_data; +	u32		sense_data_info; +	u32		unit_attention_data; + +	unsigned int	blkbits; /* Bits of logical block size +						       of bound block device */ +	unsigned int	blksize; /* logical block size of bound block device */ +	struct device	dev; +	const char	*name;		/* "lun.name" */ +	const char	**name_pfx;	/* "function.name" */ +}; + +static inline bool fsg_lun_is_open(struct fsg_lun *curlun) +{ +	return curlun->filp != NULL; +} + +/* Default size of buffer length. */ +#define FSG_BUFLEN	((u32)16384) + +/* Maximal number of LUNs supported in mass storage function */ +#define FSG_MAX_LUNS	8 + +enum fsg_buffer_state { +	BUF_STATE_EMPTY = 0, +	BUF_STATE_FULL, +	BUF_STATE_BUSY +}; + +struct fsg_buffhd { +	void				*buf; +	enum fsg_buffer_state		state; +	struct fsg_buffhd		*next; + +	/* +	 * The NetChip 2280 is faster, and handles some protocol faults +	 * better, if we don't submit any short bulk-out read requests. +	 * So we will record the intended request length here. +	 */ +	unsigned int			bulk_out_intended_length; + +	struct usb_request		*inreq; +	int				inreq_busy; +	struct usb_request		*outreq; +	int				outreq_busy; +}; + +enum fsg_state { +	/* This one isn't used anywhere */ +	FSG_STATE_COMMAND_PHASE = -10, +	FSG_STATE_DATA_PHASE, +	FSG_STATE_STATUS_PHASE, + +	FSG_STATE_IDLE = 0, +	FSG_STATE_ABORT_BULK_OUT, +	FSG_STATE_RESET, +	FSG_STATE_INTERFACE_CHANGE, +	FSG_STATE_CONFIG_CHANGE, +	FSG_STATE_DISCONNECT, +	FSG_STATE_EXIT, +	FSG_STATE_TERMINATED +}; + +enum data_direction { +	DATA_DIR_UNKNOWN = 0, +	DATA_DIR_FROM_HOST, +	DATA_DIR_TO_HOST, +	DATA_DIR_NONE +}; + +static inline u32 get_unaligned_be24(u8 *buf) +{ +	return 0xffffff & (u32) get_unaligned_be32(buf - 1); +} + +static inline struct fsg_lun *fsg_lun_from_dev(struct device *dev) +{ +	return container_of(dev, struct fsg_lun, dev); +} + +enum { +	FSG_STRING_INTERFACE +}; + +extern struct usb_interface_descriptor fsg_intf_desc; + +extern struct usb_endpoint_descriptor fsg_fs_bulk_in_desc; +extern struct usb_endpoint_descriptor fsg_fs_bulk_out_desc; +extern struct usb_descriptor_header *fsg_fs_function[]; + +extern struct usb_endpoint_descriptor fsg_hs_bulk_in_desc; +extern struct usb_endpoint_descriptor fsg_hs_bulk_out_desc; +extern struct usb_descriptor_header *fsg_hs_function[]; + +extern struct usb_endpoint_descriptor fsg_ss_bulk_in_desc; +extern struct usb_ss_ep_comp_descriptor fsg_ss_bulk_in_comp_desc; +extern struct usb_endpoint_descriptor fsg_ss_bulk_out_desc; +extern struct usb_ss_ep_comp_descriptor fsg_ss_bulk_out_comp_desc; +extern struct usb_descriptor_header *fsg_ss_function[]; + +void fsg_lun_close(struct fsg_lun *curlun); +int fsg_lun_open(struct fsg_lun *curlun, const char *filename); +int fsg_lun_fsync_sub(struct fsg_lun *curlun); +void store_cdrom_address(u8 *dest, int msf, u32 addr); +ssize_t fsg_show_ro(struct fsg_lun *curlun, char *buf); +ssize_t fsg_show_nofua(struct fsg_lun *curlun, char *buf); +ssize_t fsg_show_file(struct fsg_lun *curlun, struct rw_semaphore *filesem, +		      char *buf); +ssize_t fsg_show_cdrom(struct fsg_lun *curlun, char *buf); +ssize_t fsg_show_removable(struct fsg_lun *curlun, char *buf); +ssize_t fsg_store_ro(struct fsg_lun *curlun, struct rw_semaphore *filesem, +		     const char *buf, size_t count); +ssize_t fsg_store_nofua(struct fsg_lun *curlun, const char *buf, size_t count); +ssize_t fsg_store_file(struct fsg_lun *curlun, struct rw_semaphore *filesem, +		       const char *buf, size_t count); +ssize_t fsg_store_cdrom(struct fsg_lun *curlun, struct rw_semaphore *filesem, +			const char *buf, size_t count); +ssize_t fsg_store_removable(struct fsg_lun *curlun, const char *buf, +			    size_t count); + +#endif /* USB_STORAGE_COMMON_H */ diff --git a/drivers/usb/gadget/tcm_usb_gadget.c b/drivers/usb/gadget/tcm_usb_gadget.c index 0ff33396eef..6cdb7a534f2 100644 --- a/drivers/usb/gadget/tcm_usb_gadget.c +++ b/drivers/usb/gadget/tcm_usb_gadget.c @@ -370,7 +370,7 @@ err:  	return -ENOMEM;  } -void bot_cleanup_old_alt(struct f_uas *fu) +static void bot_cleanup_old_alt(struct f_uas *fu)  {  	if (!(fu->flags & USBG_ENABLED))  		return; @@ -472,7 +472,7 @@ static int usbg_bot_setup(struct usb_function *f,  		bot_enqueue_cmd_cbw(fu);  		return 0;  		break; -	}; +	}  	return -ENOTSUPP;  } @@ -617,7 +617,7 @@ static void uasp_status_data_cmpl(struct usb_ep *ep, struct usb_request *req)  	default:  		BUG(); -	}; +	}  	return;  cleanup: @@ -1383,10 +1383,8 @@ static struct se_node_acl *usbg_alloc_fabric_acl(struct se_portal_group *se_tpg)  	struct usbg_nacl *nacl;  	nacl = kzalloc(sizeof(struct usbg_nacl), GFP_KERNEL); -	if (!nacl) { -		printk(KERN_ERR "Unable to allocate struct usbg_nacl\n"); +	if (!nacl)  		return NULL; -	}  	return &nacl->se_node_acl;  } @@ -1471,6 +1469,11 @@ static void usbg_queue_tm_rsp(struct se_cmd *se_cmd)  {  } +static void usbg_aborted_task(struct se_cmd *se_cmd) +{ +	return; +} +  static const char *usbg_check_wwn(const char *name)  {  	const char *n; @@ -1556,10 +1559,8 @@ static struct se_portal_group *usbg_make_tpg(  	}  	tpg = kzalloc(sizeof(struct usbg_tpg), GFP_KERNEL); -	if (!tpg) { -		printk(KERN_ERR "Unable to allocate struct usbg_tpg"); +	if (!tpg)  		return ERR_PTR(-ENOMEM); -	}  	mutex_init(&tpg->tpg_mutex);  	atomic_set(&tpg->tpg_port_count, 0);  	tpg->workqueue = alloc_workqueue("tcm_usb_gadget", 0, 1); @@ -1608,12 +1609,10 @@ static struct se_wwn *usbg_make_tport(  		return ERR_PTR(-EINVAL);  	tport = kzalloc(sizeof(struct usbg_tport), GFP_KERNEL); -	if (!(tport)) { -		printk(KERN_ERR "Unable to allocate struct usbg_tport"); +	if (!(tport))  		return ERR_PTR(-ENOMEM); -	}  	tport->tport_wwpn = wwpn; -	snprintf(tport->tport_name, sizeof(tport->tport_name), wnn_name); +	snprintf(tport->tport_name, sizeof(tport->tport_name), "%s", wnn_name);  	return &tport->tport_wwn;  } @@ -1722,11 +1721,9 @@ static int tcm_usbg_make_nexus(struct usbg_tpg *tpg, char *name)  	ret = -ENOMEM;  	tv_nexus = kzalloc(sizeof(*tv_nexus), GFP_KERNEL); -	if (!tv_nexus) { -		pr_err("Unable to allocate struct tcm_vhost_nexus\n"); +	if (!tv_nexus)  		goto err_unlock; -	} -	tv_nexus->tvn_se_sess = transport_init_session(); +	tv_nexus->tvn_se_sess = transport_init_session(TARGET_PROT_NORMAL);  	if (IS_ERR(tv_nexus->tvn_se_sess))  		goto err_free; @@ -1846,7 +1843,7 @@ static int usbg_port_link(struct se_portal_group *se_tpg, struct se_lun *lun)  	struct usbg_tpg *tpg = container_of(se_tpg, struct usbg_tpg, se_tpg);  	atomic_inc(&tpg->tpg_port_count); -	smp_mb__after_atomic_inc(); +	smp_mb__after_atomic();  	return 0;  } @@ -1856,7 +1853,7 @@ static void usbg_port_unlink(struct se_portal_group *se_tpg,  	struct usbg_tpg *tpg = container_of(se_tpg, struct usbg_tpg, se_tpg);  	atomic_dec(&tpg->tpg_port_count); -	smp_mb__after_atomic_dec(); +	smp_mb__after_atomic();  }  static int usbg_check_stop_free(struct se_cmd *se_cmd) @@ -1897,6 +1894,7 @@ static struct target_core_fabric_ops usbg_ops = {  	.queue_data_in			= usbg_send_read_response,  	.queue_status			= usbg_send_status_response,  	.queue_tm_rsp			= usbg_queue_tm_rsp, +	.aborted_task			= usbg_aborted_task,  	.check_stop_free		= usbg_check_stop_free,  	.fabric_make_wwn		= usbg_make_tport, @@ -1923,15 +1921,15 @@ static int usbg_register_configfs(void)  	}  	fabric->tf_ops = usbg_ops; -	TF_CIT_TMPL(fabric)->tfc_wwn_cit.ct_attrs = usbg_wwn_attrs; -	TF_CIT_TMPL(fabric)->tfc_tpg_base_cit.ct_attrs = usbg_base_attrs; -	TF_CIT_TMPL(fabric)->tfc_tpg_attrib_cit.ct_attrs = NULL; -	TF_CIT_TMPL(fabric)->tfc_tpg_param_cit.ct_attrs = NULL; -	TF_CIT_TMPL(fabric)->tfc_tpg_np_base_cit.ct_attrs = NULL; -	TF_CIT_TMPL(fabric)->tfc_tpg_nacl_base_cit.ct_attrs = NULL; -	TF_CIT_TMPL(fabric)->tfc_tpg_nacl_attrib_cit.ct_attrs = NULL; -	TF_CIT_TMPL(fabric)->tfc_tpg_nacl_auth_cit.ct_attrs = NULL; -	TF_CIT_TMPL(fabric)->tfc_tpg_nacl_param_cit.ct_attrs = NULL; +	fabric->tf_cit_tmpl.tfc_wwn_cit.ct_attrs = usbg_wwn_attrs; +	fabric->tf_cit_tmpl.tfc_tpg_base_cit.ct_attrs = usbg_base_attrs; +	fabric->tf_cit_tmpl.tfc_tpg_attrib_cit.ct_attrs = NULL; +	fabric->tf_cit_tmpl.tfc_tpg_param_cit.ct_attrs = NULL; +	fabric->tf_cit_tmpl.tfc_tpg_np_base_cit.ct_attrs = NULL; +	fabric->tf_cit_tmpl.tfc_tpg_nacl_base_cit.ct_attrs = NULL; +	fabric->tf_cit_tmpl.tfc_tpg_nacl_attrib_cit.ct_attrs = NULL; +	fabric->tf_cit_tmpl.tfc_tpg_nacl_auth_cit.ct_attrs = NULL; +	fabric->tf_cit_tmpl.tfc_tpg_nacl_param_cit.ct_attrs = NULL;  	ret = target_fabric_configfs_register(fabric);  	if (ret < 0) {  		printk(KERN_ERR "target_fabric_configfs_register() failed" diff --git a/drivers/usb/gadget/u_ether.c b/drivers/usb/gadget/u_ether.c index 2aae0d61bb1..97b027724ee 100644 --- a/drivers/usb/gadget/u_ether.c +++ b/drivers/usb/gadget/u_ether.c @@ -753,7 +753,7 @@ static struct device_type gadget_type = {   * gadget driver using this framework.  The link layer addresses are   * set up using module parameters.   * - * Returns negative errno, or zero on success + * Returns an eth_dev pointer on success, or an ERR_PTR on failure.   */  struct eth_dev *gether_setup_name(struct usb_gadget *g,  		const char *dev_addr, const char *host_addr, @@ -793,7 +793,7 @@ struct eth_dev *gether_setup_name(struct usb_gadget *g,  	net->netdev_ops = ð_netdev_ops; -	SET_ETHTOOL_OPS(net, &ops); +	net->ethtool_ops = &ops;  	dev->gadget = g;  	SET_NETDEV_DEV(net, &g->dev); @@ -818,7 +818,7 @@ struct eth_dev *gether_setup_name(struct usb_gadget *g,  	return dev;  } -EXPORT_SYMBOL(gether_setup_name); +EXPORT_SYMBOL_GPL(gether_setup_name);  struct net_device *gether_setup_name_default(const char *netname)  { @@ -850,12 +850,12 @@ struct net_device *gether_setup_name_default(const char *netname)  	net->netdev_ops = ð_netdev_ops; -	SET_ETHTOOL_OPS(net, &ops); +	net->ethtool_ops = &ops;  	SET_NETDEV_DEVTYPE(net, &gadget_type);  	return net;  } -EXPORT_SYMBOL(gether_setup_name_default); +EXPORT_SYMBOL_GPL(gether_setup_name_default);  int gether_register_netdev(struct net_device *net)  { @@ -893,7 +893,7 @@ int gether_register_netdev(struct net_device *net)  	return status;  } -EXPORT_SYMBOL(gether_register_netdev); +EXPORT_SYMBOL_GPL(gether_register_netdev);  void gether_set_gadget(struct net_device *net, struct usb_gadget *g)  { @@ -903,7 +903,7 @@ void gether_set_gadget(struct net_device *net, struct usb_gadget *g)  	dev->gadget = g;  	SET_NETDEV_DEV(net, &g->dev);  } -EXPORT_SYMBOL(gether_set_gadget); +EXPORT_SYMBOL_GPL(gether_set_gadget);  int gether_set_dev_addr(struct net_device *net, const char *dev_addr)  { @@ -916,7 +916,7 @@ int gether_set_dev_addr(struct net_device *net, const char *dev_addr)  	memcpy(dev->dev_mac, new_addr, ETH_ALEN);  	return 0;  } -EXPORT_SYMBOL(gether_set_dev_addr); +EXPORT_SYMBOL_GPL(gether_set_dev_addr);  int gether_get_dev_addr(struct net_device *net, char *dev_addr, int len)  { @@ -925,7 +925,7 @@ int gether_get_dev_addr(struct net_device *net, char *dev_addr, int len)  	dev = netdev_priv(net);  	return get_ether_addr_str(dev->dev_mac, dev_addr, len);  } -EXPORT_SYMBOL(gether_get_dev_addr); +EXPORT_SYMBOL_GPL(gether_get_dev_addr);  int gether_set_host_addr(struct net_device *net, const char *host_addr)  { @@ -938,7 +938,7 @@ int gether_set_host_addr(struct net_device *net, const char *host_addr)  	memcpy(dev->host_mac, new_addr, ETH_ALEN);  	return 0;  } -EXPORT_SYMBOL(gether_set_host_addr); +EXPORT_SYMBOL_GPL(gether_set_host_addr);  int gether_get_host_addr(struct net_device *net, char *host_addr, int len)  { @@ -947,7 +947,7 @@ int gether_get_host_addr(struct net_device *net, char *host_addr, int len)  	dev = netdev_priv(net);  	return get_ether_addr_str(dev->host_mac, host_addr, len);  } -EXPORT_SYMBOL(gether_get_host_addr); +EXPORT_SYMBOL_GPL(gether_get_host_addr);  int gether_get_host_addr_cdc(struct net_device *net, char *host_addr, int len)  { @@ -961,7 +961,7 @@ int gether_get_host_addr_cdc(struct net_device *net, char *host_addr, int len)  	return strlen(host_addr);  } -EXPORT_SYMBOL(gether_get_host_addr_cdc); +EXPORT_SYMBOL_GPL(gether_get_host_addr_cdc);  void gether_get_host_addr_u8(struct net_device *net, u8 host_mac[ETH_ALEN])  { @@ -970,7 +970,7 @@ void gether_get_host_addr_u8(struct net_device *net, u8 host_mac[ETH_ALEN])  	dev = netdev_priv(net);  	memcpy(host_mac, dev->host_mac, ETH_ALEN);  } -EXPORT_SYMBOL(gether_get_host_addr_u8); +EXPORT_SYMBOL_GPL(gether_get_host_addr_u8);  void gether_set_qmult(struct net_device *net, unsigned qmult)  { @@ -979,7 +979,7 @@ void gether_set_qmult(struct net_device *net, unsigned qmult)  	dev = netdev_priv(net);  	dev->qmult = qmult;  } -EXPORT_SYMBOL(gether_set_qmult); +EXPORT_SYMBOL_GPL(gether_set_qmult);  unsigned gether_get_qmult(struct net_device *net)  { @@ -988,7 +988,7 @@ unsigned gether_get_qmult(struct net_device *net)  	dev = netdev_priv(net);  	return dev->qmult;  } -EXPORT_SYMBOL(gether_get_qmult); +EXPORT_SYMBOL_GPL(gether_get_qmult);  int gether_get_ifname(struct net_device *net, char *name, int len)  { @@ -997,7 +997,7 @@ int gether_get_ifname(struct net_device *net, char *name, int len)  	rtnl_unlock();  	return strlen(name);  } -EXPORT_SYMBOL(gether_get_ifname); +EXPORT_SYMBOL_GPL(gether_get_ifname);  /**   * gether_cleanup - remove Ethernet-over-USB device @@ -1014,7 +1014,7 @@ void gether_cleanup(struct eth_dev *dev)  	flush_work(&dev->work);  	free_netdev(dev->net);  } -EXPORT_SYMBOL(gether_cleanup); +EXPORT_SYMBOL_GPL(gether_cleanup);  /**   * gether_connect - notify network layer that USB link is active @@ -1095,7 +1095,7 @@ fail0:  		return ERR_PTR(result);  	return dev->net;  } -EXPORT_SYMBOL(gether_connect); +EXPORT_SYMBOL_GPL(gether_connect);  /**   * gether_disconnect - notify network layer that USB link is inactive @@ -1120,7 +1120,10 @@ void gether_disconnect(struct gether *link)  	DBG(dev, "%s\n", __func__); +	netif_tx_lock(dev->net);  	netif_stop_queue(dev->net); +	netif_tx_unlock(dev->net); +  	netif_carrier_off(dev->net);  	/* disable endpoints, forcing (synchronous) completion @@ -1166,7 +1169,7 @@ void gether_disconnect(struct gether *link)  	dev->port_usb = NULL;  	spin_unlock(&dev->lock);  } -EXPORT_SYMBOL(gether_disconnect); +EXPORT_SYMBOL_GPL(gether_disconnect);  MODULE_LICENSE("GPL");  MODULE_AUTHOR("David Brownell"); diff --git a/drivers/usb/gadget/u_ether.h b/drivers/usb/gadget/u_ether.h index fb23d1fde8e..0f0290acea7 100644 --- a/drivers/usb/gadget/u_ether.h +++ b/drivers/usb/gadget/u_ether.h @@ -106,7 +106,7 @@ struct eth_dev *gether_setup_name(struct usb_gadget *g,   * gadget driver using this framework.  The link layer addresses are   * set up using module parameters.   * - * Returns negative errno, or zero on success + * Returns a eth_dev pointer on success, or an ERR_PTR on failure   */  static inline struct eth_dev *gether_setup(struct usb_gadget *g,  		const char *dev_addr, const char *host_addr, @@ -267,45 +267,4 @@ static inline bool can_support_ecm(struct usb_gadget *gadget)  	return true;  } -/* each configuration may bind one instance of an ethernet link */ -int geth_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN], -		struct eth_dev *dev); -int ecm_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN], -		struct eth_dev *dev); - -#ifdef USB_ETH_RNDIS - -int rndis_bind_config_vendor(struct usb_configuration *c, u8 ethaddr[ETH_ALEN], -		u32 vendorID, const char *manufacturer, struct eth_dev *dev); - -#else - -static inline int -rndis_bind_config_vendor(struct usb_configuration *c, u8 ethaddr[ETH_ALEN], -		u32 vendorID, const char *manufacturer, struct eth_dev *dev) -{ -	return 0; -} - -#endif - -/** - * rndis_bind_config - add RNDIS network link to a configuration - * @c: the configuration to support the network link - * @ethaddr: a buffer in which the ethernet address of the host side - *	side of the link was recorded - * Context: single threaded during gadget setup - * - * Returns zero on success, else negative errno. - * - * Caller must have called @gether_setup().  Caller is also responsible - * for calling @gether_cleanup() before module unload. - */ -static inline int rndis_bind_config(struct usb_configuration *c, -		u8 ethaddr[ETH_ALEN], struct eth_dev *dev) -{ -	return rndis_bind_config_vendor(c, ethaddr, 0, NULL, dev); -} - -  #endif /* __U_ETHER_H */ diff --git a/drivers/usb/gadget/u_f.c b/drivers/usb/gadget/u_f.c new file mode 100644 index 00000000000..c6276f0268a --- /dev/null +++ b/drivers/usb/gadget/u_f.c @@ -0,0 +1,32 @@ +/* + * u_f.c -- USB function utilities for Gadget stack + * + * Copyright (c) 2013 Samsung Electronics Co., Ltd. + *		http://www.samsung.com + * + * Author: Andrzej Pietrasiewicz <andrzej.p@samsung.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/usb/gadget.h> +#include "u_f.h" + +struct usb_request *alloc_ep_req(struct usb_ep *ep, int len, int default_len) +{ +	struct usb_request      *req; + +	req = usb_ep_alloc_request(ep, GFP_ATOMIC); +	if (req) { +		req->length = len ?: default_len; +		req->buf = kmalloc(req->length, GFP_ATOMIC); +		if (!req->buf) { +			usb_ep_free_request(ep, req); +			req = NULL; +		} +	} +	return req; +} +EXPORT_SYMBOL_GPL(alloc_ep_req); diff --git a/drivers/usb/gadget/u_f.h b/drivers/usb/gadget/u_f.h new file mode 100644 index 00000000000..1d5f0eb6855 --- /dev/null +++ b/drivers/usb/gadget/u_f.h @@ -0,0 +1,52 @@ +/* + * u_f.h + * + * Utility definitions for USB functions + * + * Copyright (c) 2013 Samsung Electronics Co., Ltd. + *		http://www.samsung.com + * + * Author: Andrzej Pietrasiewicz <andrzej.p@samsung.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef __U_F_H__ +#define __U_F_H__ + +/* Variable Length Array Macros **********************************************/ +#define vla_group(groupname) size_t groupname##__next = 0 +#define vla_group_size(groupname) groupname##__next + +#define vla_item(groupname, type, name, n) \ +	size_t groupname##_##name##__offset = ({			       \ +		size_t align_mask = __alignof__(type) - 1;		       \ +		size_t offset = (groupname##__next + align_mask) & ~align_mask;\ +		size_t size = (n) * sizeof(type);			       \ +		groupname##__next = offset + size;			       \ +		offset;							       \ +	}) + +#define vla_item_with_sz(groupname, type, name, n) \ +	size_t groupname##_##name##__sz = (n) * sizeof(type);		       \ +	size_t groupname##_##name##__offset = ({			       \ +		size_t align_mask = __alignof__(type) - 1;		       \ +		size_t offset = (groupname##__next + align_mask) & ~align_mask;\ +		size_t size = groupname##_##name##__sz;			       \ +		groupname##__next = offset + size;			       \ +		offset;							       \ +	}) + +#define vla_ptr(ptr, groupname, name) \ +	((void *) ((char *)ptr + groupname##_##name##__offset)) + +struct usb_ep; +struct usb_request; + +struct usb_request *alloc_ep_req(struct usb_ep *ep, int len, int default_len); + +#endif /* __U_F_H__ */ + + diff --git a/drivers/usb/gadget/u_fs.h b/drivers/usb/gadget/u_fs.h new file mode 100644 index 00000000000..bf0ba375d45 --- /dev/null +++ b/drivers/usb/gadget/u_fs.h @@ -0,0 +1,263 @@ +/* + * u_fs.h + * + * Utility definitions for the FunctionFS + * + * Copyright (c) 2013 Samsung Electronics Co., Ltd. + *		http://www.samsung.com + * + * Author: Andrzej Pietrasiewicz <andrzej.p@samsung.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef U_FFS_H +#define U_FFS_H + +#include <linux/usb/composite.h> +#include <linux/list.h> +#include <linux/mutex.h> + +#ifdef VERBOSE_DEBUG +#ifndef pr_vdebug +#  define pr_vdebug pr_debug +#endif /* pr_vdebug */ +#  define ffs_dump_mem(prefix, ptr, len) \ +	print_hex_dump_bytes(pr_fmt(prefix ": "), DUMP_PREFIX_NONE, ptr, len) +#else +#ifndef pr_vdebug +#  define pr_vdebug(...)                 do { } while (0) +#endif /* pr_vdebug */ +#  define ffs_dump_mem(prefix, ptr, len) do { } while (0) +#endif /* VERBOSE_DEBUG */ + +#define ENTER()    pr_vdebug("%s()\n", __func__) + +struct f_fs_opts; + +struct ffs_dev { +	const char *name; +	bool name_allocated; +	bool mounted; +	bool desc_ready; +	bool single; +	struct ffs_data *ffs_data; +	struct f_fs_opts *opts; +	struct list_head entry; + +	int (*ffs_ready_callback)(struct ffs_data *ffs); +	void (*ffs_closed_callback)(struct ffs_data *ffs); +	void *(*ffs_acquire_dev_callback)(struct ffs_dev *dev); +	void (*ffs_release_dev_callback)(struct ffs_dev *dev); +}; + +extern struct mutex ffs_lock; + +static inline void ffs_dev_lock(void) +{ +	mutex_lock(&ffs_lock); +} + +static inline void ffs_dev_unlock(void) +{ +	mutex_unlock(&ffs_lock); +} + +int ffs_name_dev(struct ffs_dev *dev, const char *name); +int ffs_single_dev(struct ffs_dev *dev); + +struct ffs_epfile; +struct ffs_function; + +enum ffs_state { +	/* +	 * Waiting for descriptors and strings. +	 * +	 * In this state no open(2), read(2) or write(2) on epfiles +	 * may succeed (which should not be the problem as there +	 * should be no such files opened in the first place). +	 */ +	FFS_READ_DESCRIPTORS, +	FFS_READ_STRINGS, + +	/* +	 * We've got descriptors and strings.  We are or have called +	 * functionfs_ready_callback().  functionfs_bind() may have +	 * been called but we don't know. +	 * +	 * This is the only state in which operations on epfiles may +	 * succeed. +	 */ +	FFS_ACTIVE, + +	/* +	 * All endpoints have been closed.  This state is also set if +	 * we encounter an unrecoverable error.  The only +	 * unrecoverable error is situation when after reading strings +	 * from user space we fail to initialise epfiles or +	 * functionfs_ready_callback() returns with error (<0). +	 * +	 * In this state no open(2), read(2) or write(2) (both on ep0 +	 * as well as epfile) may succeed (at this point epfiles are +	 * unlinked and all closed so this is not a problem; ep0 is +	 * also closed but ep0 file exists and so open(2) on ep0 must +	 * fail). +	 */ +	FFS_CLOSING +}; + +enum ffs_setup_state { +	/* There is no setup request pending. */ +	FFS_NO_SETUP, +	/* +	 * User has read events and there was a setup request event +	 * there.  The next read/write on ep0 will handle the +	 * request. +	 */ +	FFS_SETUP_PENDING, +	/* +	 * There was event pending but before user space handled it +	 * some other event was introduced which canceled existing +	 * setup.  If this state is set read/write on ep0 return +	 * -EIDRM.  This state is only set when adding event. +	 */ +	FFS_SETUP_CANCELLED +}; + +struct ffs_data { +	struct usb_gadget		*gadget; + +	/* +	 * Protect access read/write operations, only one read/write +	 * at a time.  As a consequence protects ep0req and company. +	 * While setup request is being processed (queued) this is +	 * held. +	 */ +	struct mutex			mutex; + +	/* +	 * Protect access to endpoint related structures (basically +	 * usb_ep_queue(), usb_ep_dequeue(), etc. calls) except for +	 * endpoint zero. +	 */ +	spinlock_t			eps_lock; + +	/* +	 * XXX REVISIT do we need our own request? Since we are not +	 * handling setup requests immediately user space may be so +	 * slow that another setup will be sent to the gadget but this +	 * time not to us but another function and then there could be +	 * a race.  Is that the case? Or maybe we can use cdev->req +	 * after all, maybe we just need some spinlock for that? +	 */ +	struct usb_request		*ep0req;		/* P: mutex */ +	struct completion		ep0req_completion;	/* P: mutex */ + +	/* reference counter */ +	atomic_t			ref; +	/* how many files are opened (EP0 and others) */ +	atomic_t			opened; + +	/* EP0 state */ +	enum ffs_state			state; + +	/* +	 * Possible transitions: +	 * + FFS_NO_SETUP        -> FFS_SETUP_PENDING  -- P: ev.waitq.lock +	 *               happens only in ep0 read which is P: mutex +	 * + FFS_SETUP_PENDING   -> FFS_NO_SETUP       -- P: ev.waitq.lock +	 *               happens only in ep0 i/o  which is P: mutex +	 * + FFS_SETUP_PENDING   -> FFS_SETUP_CANCELLED -- P: ev.waitq.lock +	 * + FFS_SETUP_CANCELLED -> FFS_NO_SETUP        -- cmpxchg +	 * +	 * This field should never be accessed directly and instead +	 * ffs_setup_state_clear_cancelled function should be used. +	 */ +	enum ffs_setup_state		setup_state; + +	/* Events & such. */ +	struct { +		u8				types[4]; +		unsigned short			count; +		/* XXX REVISIT need to update it in some places, or do we? */ +		unsigned short			can_stall; +		struct usb_ctrlrequest		setup; + +		wait_queue_head_t		waitq; +	} ev; /* the whole structure, P: ev.waitq.lock */ + +	/* Flags */ +	unsigned long			flags; +#define FFS_FL_CALL_CLOSED_CALLBACK 0 +#define FFS_FL_BOUND                1 + +	/* Active function */ +	struct ffs_function		*func; + +	/* +	 * Device name, write once when file system is mounted. +	 * Intended for user to read if she wants. +	 */ +	const char			*dev_name; +	/* Private data for our user (ie. gadget).  Managed by user. */ +	void				*private_data; + +	/* filled by __ffs_data_got_descs() */ +	/* +	 * raw_descs is what you kfree, real_descs points inside of raw_descs, +	 * where full speed, high speed and super speed descriptors start. +	 * real_descs_length is the length of all those descriptors. +	 */ +	const void			*raw_descs_data; +	const void			*raw_descs; +	unsigned			raw_descs_length; +	unsigned			fs_descs_count; +	unsigned			hs_descs_count; +	unsigned			ss_descs_count; + +	unsigned short			strings_count; +	unsigned short			interfaces_count; +	unsigned short			eps_count; +	unsigned short			_pad1; + +	/* filled by __ffs_data_got_strings() */ +	/* ids in stringtabs are set in functionfs_bind() */ +	const void			*raw_strings; +	struct usb_gadget_strings	**stringtabs; + +	/* +	 * File system's super block, write once when file system is +	 * mounted. +	 */ +	struct super_block		*sb; + +	/* File permissions, written once when fs is mounted */ +	struct ffs_file_perms { +		umode_t				mode; +		kuid_t				uid; +		kgid_t				gid; +	}				file_perms; + +	/* +	 * The endpoint files, filled by ffs_epfiles_create(), +	 * destroyed by ffs_epfiles_destroy(). +	 */ +	struct ffs_epfile		*epfiles; +}; + + +struct f_fs_opts { +	struct usb_function_instance	func_inst; +	struct ffs_dev			*dev; +	unsigned			refcnt; +	bool				no_configfs; +}; + +static inline struct f_fs_opts *to_f_fs_opts(struct usb_function_instance *fi) +{ +	return container_of(fi, struct f_fs_opts, func_inst); +} + +#endif /* U_FFS_H */ diff --git a/drivers/usb/gadget/u_os_desc.h b/drivers/usb/gadget/u_os_desc.h new file mode 100644 index 00000000000..ea5cf8c2da2 --- /dev/null +++ b/drivers/usb/gadget/u_os_desc.h @@ -0,0 +1,90 @@ +/* + * u_os_desc.h + * + * Utility definitions for "OS Descriptors" support + * + * Copyright (c) 2014 Samsung Electronics Co., Ltd. + *		http://www.samsung.com + * + * Author: Andrzej Pietrasiewicz <andrzej.p@samsung.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef __U_OS_DESC_H__ +#define __U_OS_DESC_H__ + +#include <asm/unaligned.h> +#include <linux/nls.h> + +#define USB_EXT_PROP_DW_SIZE			0 +#define USB_EXT_PROP_DW_PROPERTY_DATA_TYPE	4 +#define USB_EXT_PROP_W_PROPERTY_NAME_LENGTH	8 +#define USB_EXT_PROP_B_PROPERTY_NAME		10 +#define USB_EXT_PROP_DW_PROPERTY_DATA_LENGTH	10 +#define USB_EXT_PROP_B_PROPERTY_DATA		14 + +#define USB_EXT_PROP_RESERVED			0 +#define USB_EXT_PROP_UNICODE			1 +#define USB_EXT_PROP_UNICODE_ENV		2 +#define USB_EXT_PROP_BINARY			3 +#define USB_EXT_PROP_LE32			4 +#define USB_EXT_PROP_BE32			5 +#define USB_EXT_PROP_UNICODE_LINK		6 +#define USB_EXT_PROP_UNICODE_MULTI		7 + +static inline void usb_ext_prop_put_size(u8 *buf, int dw_size) +{ +	put_unaligned_le32(dw_size, &buf[USB_EXT_PROP_DW_SIZE]); +} + +static inline void usb_ext_prop_put_type(u8 *buf, int type) +{ +	put_unaligned_le32(type, &buf[USB_EXT_PROP_DW_PROPERTY_DATA_TYPE]); +} + +static inline int usb_ext_prop_put_name(u8 *buf, const char *name, int pnl) +{ +	int result; + +	put_unaligned_le16(pnl, &buf[USB_EXT_PROP_W_PROPERTY_NAME_LENGTH]); +	result = utf8s_to_utf16s(name, strlen(name), UTF16_LITTLE_ENDIAN, +		(wchar_t *) &buf[USB_EXT_PROP_B_PROPERTY_NAME], pnl - 2); +	if (result < 0) +		return result; + +	put_unaligned_le16(0, &buf[USB_EXT_PROP_B_PROPERTY_NAME + pnl]); + +	return pnl; +} + +static inline void usb_ext_prop_put_binary(u8 *buf, int pnl, const u8 *data, +					   int data_len) +{ +	put_unaligned_le32(data_len, +			   &buf[USB_EXT_PROP_DW_PROPERTY_DATA_LENGTH + pnl]); +	memcpy(&buf[USB_EXT_PROP_B_PROPERTY_DATA + pnl], data, data_len); +} + +static inline int usb_ext_prop_put_unicode(u8 *buf, int pnl, const char *string, +					   int data_len) +{ +	int result; +	put_unaligned_le32(data_len, +			&buf[USB_EXT_PROP_DW_PROPERTY_DATA_LENGTH + pnl]); + +	result = utf8s_to_utf16s(string, data_len >> 1, UTF16_LITTLE_ENDIAN, +			(wchar_t *) &buf[USB_EXT_PROP_B_PROPERTY_DATA + pnl], +			data_len - 2); +	if (result < 0) +		return result; + +	put_unaligned_le16(0, +			&buf[USB_EXT_PROP_B_PROPERTY_DATA + pnl + data_len]); + +	return data_len; +} + +#endif /* __U_OS_DESC_H__ */ diff --git a/drivers/usb/gadget/u_rndis.h b/drivers/usb/gadget/u_rndis.h index c62ba82e960..e902aa42a29 100644 --- a/drivers/usb/gadget/u_rndis.h +++ b/drivers/usb/gadget/u_rndis.h @@ -26,6 +26,9 @@ struct f_rndis_opts {  	bool				bound;  	bool				borrowed_net; +	struct usb_os_desc		rndis_os_desc; +	char				rndis_ext_compat_id[16]; +  	/*  	 * Read/write access to configfs attributes is handled by configfs.  	 * @@ -36,6 +39,8 @@ struct f_rndis_opts {  	int				refcnt;  }; +int rndis_init(void); +void rndis_exit(void);  void rndis_borrow_net(struct usb_function_instance *f, struct net_device *net);  #endif /* U_RNDIS_H */ diff --git a/drivers/usb/gadget/u_serial.c b/drivers/usb/gadget/u_serial.c index b369292d4b9..ad0aca81200 100644 --- a/drivers/usb/gadget/u_serial.c +++ b/drivers/usb/gadget/u_serial.c @@ -549,8 +549,8 @@ static void gs_rx_push(unsigned long _port)  		port->read_started--;  	} -	/* Push from tty to ldisc; without low_latency set this is handled by -	 * a workqueue, so we won't get callbacks and can hold port_lock +	/* Push from tty to ldisc; this is handled by a workqueue, +	 * so we won't get callbacks and can hold port_lock  	 */  	if (do_push)  		tty_flip_buffer_push(&port->port); diff --git a/drivers/usb/gadget/udc-core.c b/drivers/usb/gadget/udc-core.c index 59891b1c48f..b0d98172bc0 100644 --- a/drivers/usb/gadget/udc-core.c +++ b/drivers/usb/gadget/udc-core.c @@ -356,7 +356,8 @@ static int udc_bind_to_driver(struct usb_udc *udc, struct usb_gadget_driver *dri  	kobject_uevent(&udc->dev.kobj, KOBJ_CHANGE);  	return 0;  err1: -	dev_err(&udc->dev, "failed to start %s: %d\n", +	if (ret != -EISNAM) +		dev_err(&udc->dev, "failed to start %s: %d\n",  			udc->driver->function, ret);  	udc->driver = NULL;  	udc->dev.driver = NULL; @@ -427,6 +428,8 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)  	list_for_each_entry(udc, &udc_list, list)  		if (udc->driver == driver) {  			usb_gadget_remove_driver(udc); +			usb_gadget_set_state(udc->gadget, +					USB_STATE_NOTATTACHED);  			ret = 0;  			break;  		} diff --git a/drivers/usb/gadget/usbstring.c b/drivers/usb/gadget/usbstring.c index 1f49fce0f0b..73a4dfba0ed 100644 --- a/drivers/usb/gadget/usbstring.c +++ b/drivers/usb/gadget/usbstring.c @@ -13,7 +13,6 @@  #include <linux/list.h>  #include <linux/string.h>  #include <linux/device.h> -#include <linux/init.h>  #include <linux/nls.h>  #include <linux/usb/ch9.h> diff --git a/drivers/usb/gadget/uvc_queue.c b/drivers/usb/gadget/uvc_queue.c index 0bb5d50075d..1c29bc954db 100644 --- a/drivers/usb/gadget/uvc_queue.c +++ b/drivers/usb/gadget/uvc_queue.c @@ -20,6 +20,7 @@  #include <linux/vmalloc.h>  #include <linux/wait.h> +#include <media/v4l2-common.h>  #include <media/videobuf2-vmalloc.h>  #include "uvc.h" @@ -136,6 +137,8 @@ static int uvc_queue_init(struct uvc_video_queue *queue,  	queue->queue.buf_struct_size = sizeof(struct uvc_buffer);  	queue->queue.ops = &uvc_queue_qops;  	queue->queue.mem_ops = &vb2_vmalloc_memops; +	queue->queue.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC +				     | V4L2_BUF_FLAG_TSTAMP_SRC_EOF;  	ret = vb2_queue_init(&queue->queue);  	if (ret)  		return ret; @@ -379,14 +382,9 @@ static struct uvc_buffer *uvc_queue_next_buffer(struct uvc_video_queue *queue,  	else  		nextbuf = NULL; -	/* -	 * FIXME: with videobuf2, the sequence number or timestamp fields -	 * are valid only for video capture devices and the UVC gadget usually -	 * is a video output device. Keeping these until the specs are clear on -	 * this aspect. -	 */ +	buf->buf.v4l2_buf.field = V4L2_FIELD_NONE;  	buf->buf.v4l2_buf.sequence = queue->sequence++; -	do_gettimeofday(&buf->buf.v4l2_buf.timestamp); +	v4l2_get_timestamp(&buf->buf.v4l2_buf.timestamp);  	vb2_set_plane_payload(&buf->buf, 0, buf->bytesused);  	vb2_buffer_done(&buf->buf, VB2_BUF_STATE_DONE); diff --git a/drivers/usb/gadget/zero.c b/drivers/usb/gadget/zero.c index 0deb9d6cde2..134f354ede6 100644 --- a/drivers/usb/gadget/zero.c +++ b/drivers/usb/gadget/zero.c @@ -64,10 +64,10 @@ static bool loopdefault = 0;  module_param(loopdefault, bool, S_IRUGO|S_IWUSR);  static struct usb_zero_options gzero_options = { -	.isoc_interval = 4, -	.isoc_maxpacket = 1024, -	.bulk_buflen = 4096, -	.qlen = 32, +	.isoc_interval = GZERO_ISOC_INTERVAL, +	.isoc_maxpacket = GZERO_ISOC_MAXPACKET, +	.bulk_buflen = GZERO_BULK_BUFLEN, +	.qlen = GZERO_QLEN,  };  /*-------------------------------------------------------------------------*/ @@ -91,10 +91,22 @@ static struct usb_zero_options gzero_options = {   * functional coverage for the "USBCV" test harness from USB-IF.   * It's always set if OTG mode is enabled.   */ -unsigned autoresume = DEFAULT_AUTORESUME; +static unsigned autoresume = DEFAULT_AUTORESUME;  module_param(autoresume, uint, S_IRUGO);  MODULE_PARM_DESC(autoresume, "zero, or seconds before remote wakeup"); +/* Maximum Autoresume time */ +static unsigned max_autoresume; +module_param(max_autoresume, uint, S_IRUGO); +MODULE_PARM_DESC(max_autoresume, "maximum seconds before remote wakeup"); + +/* Interval between two remote wakeups */ +static unsigned autoresume_interval_ms; +module_param(autoresume_interval_ms, uint, S_IRUGO); +MODULE_PARM_DESC(autoresume_interval_ms, +		"milliseconds to increase successive wakeup delays"); + +static unsigned autoresume_step_ms;  /*-------------------------------------------------------------------------*/  static struct usb_device_descriptor device_desc = { @@ -183,8 +195,16 @@ static void zero_suspend(struct usb_composite_dev *cdev)  		return;  	if (autoresume) { -		mod_timer(&autoresume_timer, jiffies + (HZ * autoresume)); -		DBG(cdev, "suspend, wakeup in %d seconds\n", autoresume); +		if (max_autoresume && +			(autoresume_step_ms > max_autoresume * 1000)) +				autoresume_step_ms = autoresume * 1000; + +		mod_timer(&autoresume_timer, jiffies + +			msecs_to_jiffies(autoresume_step_ms)); +		DBG(cdev, "suspend, wakeup in %d milliseconds\n", +			autoresume_step_ms); + +		autoresume_step_ms += autoresume_interval_ms;  	} else  		DBG(cdev, "%s\n", __func__);  } @@ -280,7 +300,7 @@ static int __init zero_bind(struct usb_composite_dev *cdev)  	ss_opts->isoc_interval = gzero_options.isoc_interval;  	ss_opts->isoc_maxpacket = gzero_options.isoc_maxpacket;  	ss_opts->isoc_mult = gzero_options.isoc_mult; -	ss_opts->isoc_maxburst = gzero_options.isoc_maxpacket; +	ss_opts->isoc_maxburst = gzero_options.isoc_maxburst;  	ss_opts->bulk_buflen = gzero_options.bulk_buflen;  	func_ss = usb_get_function(func_inst_ss); @@ -316,6 +336,7 @@ static int __init zero_bind(struct usb_composite_dev *cdev)  	if (autoresume) {  		sourcesink_driver.bmAttributes |= USB_CONFIG_ATT_WAKEUP;  		loopback_driver.bmAttributes |= USB_CONFIG_ATT_WAKEUP; +		autoresume_step_ms = autoresume * 1000;  	}  	/* support OTG systems */  | 
