diff options
| author | Takashi Iwai <tiwai@suse.de> | 2011-08-08 14:30:29 +0200 | 
|---|---|---|
| committer | Takashi Iwai <tiwai@suse.de> | 2011-08-08 14:30:29 +0200 | 
| commit | 0a2d31b62dba9b5b92a38c67c9cc42630513662a (patch) | |
| tree | f755d74ec85248de645e10c45ed1a2ed467530f6 /drivers/usb/gadget | |
| parent | 8039290a91c5dc4414093c086987a5d7738fe2fd (diff) | |
| parent | df944f66784e6d4f2f50739263a4947885d8b6ae (diff) | |
Merge branch 'fix/kconfig' into for-linus
Diffstat (limited to 'drivers/usb/gadget')
75 files changed, 6410 insertions, 1557 deletions
| diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index 58456d1aec21..44b6b40aafb4 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -96,9 +96,6 @@ config USB_GADGET_VBUS_DRAW  	   This value will be used except for system-specific gadget  	   drivers that have more specific information. -config	USB_GADGET_SELECTED -	boolean -  #  # USB Peripheral Controller Support  # @@ -122,10 +119,9 @@ choice  # Integrated controllers  # -config USB_GADGET_AT91 -	boolean "Atmel AT91 USB Device Port" +config USB_AT91 +	tristate "Atmel AT91 USB Device Port"  	depends on ARCH_AT91 && !ARCH_AT91SAM9RL && !ARCH_AT91CAP9 && !ARCH_AT91SAM9G45 -	select USB_GADGET_SELECTED  	help  	   Many Atmel AT91 processors (such as the AT91RM2000) have a  	   full speed USB Device Port with support for five configurable @@ -135,27 +131,16 @@ config USB_GADGET_AT91  	   dynamically linked module called "at91_udc" and force all  	   gadget drivers to also be dynamically linked. -config USB_AT91 -	tristate -	depends on USB_GADGET_AT91 -	default USB_GADGET - -config USB_GADGET_ATMEL_USBA -	boolean "Atmel USBA" +config USB_ATMEL_USBA +	tristate "Atmel USBA"  	select USB_GADGET_DUALSPEED  	depends on AVR32 || ARCH_AT91CAP9 || ARCH_AT91SAM9RL || ARCH_AT91SAM9G45  	help  	  USBA is the integrated high-speed USB Device controller on  	  the AT32AP700x, some AT91SAM9 and AT91CAP9 processors from Atmel. -config USB_ATMEL_USBA -	tristate -	depends on USB_GADGET_ATMEL_USBA -	default USB_GADGET -	select USB_GADGET_SELECTED - -config USB_GADGET_FSL_USB2 -	boolean "Freescale Highspeed USB DR Peripheral Controller" +config USB_FSL_USB2 +	tristate "Freescale Highspeed USB DR Peripheral Controller"  	depends on FSL_SOC || ARCH_MXC  	select USB_GADGET_DUALSPEED  	select USB_FSL_MPH_DR_OF if OF @@ -170,26 +155,15 @@ config USB_GADGET_FSL_USB2  	   dynamically linked module called "fsl_usb2_udc" and force  	   all gadget drivers to also be dynamically linked. -config USB_FSL_USB2 -	tristate -	depends on USB_GADGET_FSL_USB2 -	default USB_GADGET -	select USB_GADGET_SELECTED - -config USB_GADGET_FUSB300 -	boolean "Faraday FUSB300 USB Peripheral Controller" +config USB_FUSB300 +	tristate "Faraday FUSB300 USB Peripheral Controller" +	depends on !PHYS_ADDR_T_64BIT  	select USB_GADGET_DUALSPEED  	help  	   Faraday usb device controller FUSB300 driver -config USB_FUSB300 -	tristate -	depends on USB_GADGET_FUSB300 -	default USB_GADGET -	select USB_GADGET_SELECTED - -config USB_GADGET_OMAP -	boolean "OMAP USB Device Controller" +config USB_OMAP +	tristate "OMAP USB Device Controller"  	depends on ARCH_OMAP  	select ISP1301_OMAP if MACH_OMAP_H2 || MACH_OMAP_H3 || MACH_OMAP_H4_OTG  	select USB_OTG_UTILS if ARCH_OMAP @@ -204,14 +178,8 @@ config USB_GADGET_OMAP  	   dynamically linked module called "omap_udc" and force all  	   gadget drivers to also be dynamically linked. -config USB_OMAP -	tristate -	depends on USB_GADGET_OMAP -	default USB_GADGET -	select USB_GADGET_SELECTED - -config USB_GADGET_PXA25X -	boolean "PXA 25x or IXP 4xx" +config USB_PXA25X +	tristate "PXA 25x or IXP 4xx"  	depends on (ARCH_PXA && PXA25x) || ARCH_IXP4XX  	select USB_OTG_UTILS  	help @@ -226,24 +194,18 @@ config USB_GADGET_PXA25X  	   dynamically linked module called "pxa25x_udc" and force all  	   gadget drivers to also be dynamically linked. -config USB_PXA25X -	tristate -	depends on USB_GADGET_PXA25X -	default USB_GADGET -	select USB_GADGET_SELECTED -  # if there's only one gadget driver, using only two bulk endpoints,  # don't waste memory for the other endpoints  config USB_PXA25X_SMALL -	depends on USB_GADGET_PXA25X +	depends on USB_PXA25X  	bool  	default n if USB_ETH_RNDIS  	default y if USB_ZERO  	default y if USB_ETH  	default y if USB_G_SERIAL -config USB_GADGET_R8A66597 -	boolean "Renesas R8A66597 USB Peripheral Controller" +config USB_R8A66597 +	tristate "Renesas R8A66597 USB Peripheral Controller"  	select USB_GADGET_DUALSPEED  	help  	   R8A66597 is a discrete USB host and peripheral controller chip that @@ -254,32 +216,22 @@ config USB_GADGET_R8A66597  	   dynamically linked module called "r8a66597_udc" and force all  	   gadget drivers to also be dynamically linked. -config USB_R8A66597 -	tristate -	depends on USB_GADGET_R8A66597 -	default USB_GADGET -	select USB_GADGET_SELECTED - -config USB_GADGET_RENESAS_USBHS -	boolean "Renesas USBHS" +config USB_RENESAS_USBHS_UDC +	tristate 'Renesas USBHS controller' +	depends on SUPERH || ARCH_SHMOBILE  	depends on USB_RENESAS_USBHS  	select USB_GADGET_DUALSPEED  	help -	   Renesas USBHS is a discrete USB host and peripheral controller -	   chip that supports both full and high speed USB 2.0 data transfers. -	   platform is able to configure endpoint (pipe) style - -	   Say "y" to enable the gadget specific portion of the USBHS driver. +	   Renesas USBHS is a discrete USB host and peripheral controller chip +	   that supports both full and high speed USB 2.0 data transfers. +	   It has nine or more configurable endpoints, and endpoint zero. +	   Say "y" to link the driver statically, or "m" to build a +	   dynamically linked module called "renesas_usbhs" and force all +	   gadget drivers to also be dynamically linked. -config USB_RENESAS_USBHS_UDC -	tristate -	depends on USB_GADGET_RENESAS_USBHS -	default USB_GADGET -	select USB_GADGET_SELECTED - -config USB_GADGET_PXA27X -	boolean "PXA 27x" +config USB_PXA27X +	tristate "PXA 27x"  	depends on ARCH_PXA && (PXA27x || PXA3xx)  	select USB_OTG_UTILS  	help @@ -293,14 +245,8 @@ config USB_GADGET_PXA27X  	   dynamically linked module called "pxa27x_udc" and force all  	   gadget drivers to also be dynamically linked. -config USB_PXA27X -	tristate -	depends on USB_GADGET_PXA27X -	default USB_GADGET -	select USB_GADGET_SELECTED - -config USB_GADGET_S3C_HSOTG -	boolean "S3C HS/OtG USB Device controller" +config USB_S3C_HSOTG +	tristate "S3C HS/OtG USB Device controller"  	depends on S3C_DEV_USB_HSOTG  	select USB_GADGET_S3C_HSOTG_PIO  	select USB_GADGET_DUALSPEED @@ -308,14 +254,8 @@ config USB_GADGET_S3C_HSOTG  	  The Samsung S3C64XX USB2.0 high-speed gadget controller  	  integrated into the S3C64XX series SoC. -config USB_S3C_HSOTG -	tristate -	depends on USB_GADGET_S3C_HSOTG -	default USB_GADGET -	select USB_GADGET_SELECTED - -config USB_GADGET_IMX -	boolean "Freescale IMX USB Peripheral Controller" +config USB_IMX +	tristate "Freescale IMX USB Peripheral Controller"  	depends on ARCH_MX1  	help  	   Freescale's IMX series include an integrated full speed @@ -329,14 +269,8 @@ config USB_GADGET_IMX  	   dynamically linked module called "imx_udc" and force all  	   gadget drivers to also be dynamically linked. -config USB_IMX -	tristate -	depends on USB_GADGET_IMX -	default USB_GADGET -	select USB_GADGET_SELECTED - -config USB_GADGET_S3C2410 -	boolean "S3C2410 USB Device Controller" +config USB_S3C2410 +	tristate "S3C2410 USB Device Controller"  	depends on ARCH_S3C2410  	help  	  Samsung's S3C2410 is an ARM-4 processor with an integrated @@ -346,18 +280,12 @@ config USB_GADGET_S3C2410  	  This driver has been tested on the S3C2410, S3C2412, and  	  S3C2440 processors. -config USB_S3C2410 -	tristate -	depends on USB_GADGET_S3C2410 -	default USB_GADGET -	select USB_GADGET_SELECTED -  config USB_S3C2410_DEBUG  	boolean "S3C2410 udc debug messages" -	depends on USB_GADGET_S3C2410 +	depends on USB_S3C2410 -config USB_GADGET_S3C_HSUDC -	boolean "S3C2416, S3C2443 and S3C2450 USB Device Controller" +config USB_S3C_HSUDC +	tristate "S3C2416, S3C2443 and S3C2450 USB Device Controller"  	depends on ARCH_S3C2410  	select USB_GADGET_DUALSPEED  	help @@ -367,41 +295,29 @@ config USB_GADGET_S3C_HSUDC  	  This driver has been tested on S3C2416 and S3C2450 processors. -config USB_S3C_HSUDC -	tristate -	depends on USB_GADGET_S3C_HSUDC -	default USB_GADGET -	select USB_GADGET_SELECTED - -config USB_GADGET_PXA_U2O -	boolean "PXA9xx Processor USB2.0 controller" +config USB_PXA_U2O +	tristate "PXA9xx Processor USB2.0 controller" +	depends on ARCH_MMP  	select USB_GADGET_DUALSPEED  	help  	  PXA9xx Processor series include a high speed USB2.0 device  	  controller, which support high speed and full speed USB peripheral. -config USB_PXA_U2O -	tristate -	depends on USB_GADGET_PXA_U2O -	default USB_GADGET -	select USB_GADGET_SELECTED -  #  # Controllers available in both integrated and discrete versions  #  # musb builds in ../musb along with host support  config USB_GADGET_MUSB_HDRC -	boolean "Inventra HDRC USB Peripheral (TI, ADI, ...)" +	tristate "Inventra HDRC USB Peripheral (TI, ADI, ...)"  	depends on USB_MUSB_HDRC && (USB_MUSB_PERIPHERAL || USB_MUSB_OTG)  	select USB_GADGET_DUALSPEED -	select USB_GADGET_SELECTED  	help  	  This OTG-capable silicon IP is used in dual designs including  	  the TI DaVinci, OMAP 243x, OMAP 343x, TUSB 6010, and ADI Blackfin -config USB_GADGET_M66592 -	boolean "Renesas M66592 USB Peripheral Controller" +config USB_M66592 +	tristate "Renesas M66592 USB Peripheral Controller"  	select USB_GADGET_DUALSPEED  	help  	   M66592 is a discrete USB peripheral controller chip that @@ -412,18 +328,12 @@ config USB_GADGET_M66592  	   dynamically linked module called "m66592_udc" and force all  	   gadget drivers to also be dynamically linked. -config USB_M66592 -	tristate -	depends on USB_GADGET_M66592 -	default USB_GADGET -	select USB_GADGET_SELECTED -  #  # Controllers available only in discrete form (and all PCI controllers)  # -config USB_GADGET_AMD5536UDC -	boolean "AMD5536 UDC" +config USB_AMD5536UDC +	tristate "AMD5536 UDC"  	depends on PCI  	select USB_GADGET_DUALSPEED  	help @@ -437,14 +347,8 @@ config USB_GADGET_AMD5536UDC  	   dynamically linked module called "amd5536udc" and force all  	   gadget drivers to also be dynamically linked. -config USB_AMD5536UDC -	tristate -	depends on USB_GADGET_AMD5536UDC -	default USB_GADGET -	select USB_GADGET_SELECTED - -config USB_GADGET_FSL_QE -	boolean "Freescale QE/CPM USB Device Controller" +config USB_FSL_QE +	tristate "Freescale QE/CPM USB Device Controller"  	depends on FSL_SOC && (QUICC_ENGINE || CPM)  	help  	   Some of Freescale PowerPC processors have a Full Speed @@ -456,14 +360,8 @@ config USB_GADGET_FSL_QE  	   Set CONFIG_USB_GADGET to "m" to build this driver as a  	   dynamically linked module called "fsl_qe_udc". -config USB_FSL_QE -	tristate -	depends on USB_GADGET_FSL_QE -	default USB_GADGET -	select USB_GADGET_SELECTED - -config USB_GADGET_CI13XXX_PCI -	boolean "MIPS USB CI13xxx PCI UDC" +config USB_CI13XXX_PCI +	tristate "MIPS USB CI13xxx PCI UDC"  	depends on PCI  	select USB_GADGET_DUALSPEED  	help @@ -474,14 +372,31 @@ config USB_GADGET_CI13XXX_PCI  	  dynamically linked module called "ci13xxx_udc" and force all  	  gadget drivers to also be dynamically linked. -config USB_CI13XXX_PCI -	tristate -	depends on USB_GADGET_CI13XXX_PCI -	default USB_GADGET -	select USB_GADGET_SELECTED +config USB_NET2272 +	tristate "PLX NET2272" +	select USB_GADGET_DUALSPEED +	help +	  PLX NET2272 is a USB peripheral controller which supports +	  both full and high speed USB 2.0 data transfers. -config USB_GADGET_NET2280 -	boolean "NetChip 228x" +	  It has three configurable endpoints, as well as endpoint zero +	  (for control transfer). +	  Say "y" to link the driver statically, or "m" to build a +	  dynamically linked module called "net2272" and force all +	  gadget drivers to also be dynamically linked. + +config USB_NET2272_DMA +	boolean "Support external DMA controller" +	depends on USB_NET2272 +	help +	  The NET2272 part can optionally support an external DMA +	  controller, but your board has to have support in the +	  driver itself. + +	  If unsure, say "N" here.  The driver works fine in PIO mode. + +config USB_NET2280 +	tristate "NetChip 228x"  	depends on PCI  	select USB_GADGET_DUALSPEED  	help @@ -496,14 +411,8 @@ config USB_GADGET_NET2280  	   dynamically linked module called "net2280" and force all  	   gadget drivers to also be dynamically linked. -config USB_NET2280 -	tristate -	depends on USB_GADGET_NET2280 -	default USB_GADGET -	select USB_GADGET_SELECTED - -config USB_GADGET_GOKU -	boolean "Toshiba TC86C001 'Goku-S'" +config USB_GOKU +	tristate "Toshiba TC86C001 'Goku-S'"  	depends on PCI  	help  	   The Toshiba TC86C001 is a PCI device which includes controllers @@ -516,15 +425,10 @@ config USB_GADGET_GOKU  	   dynamically linked module called "goku_udc" and to force all  	   gadget drivers to also be dynamically linked. -config USB_GOKU -	tristate -	depends on USB_GADGET_GOKU -	default USB_GADGET -	select USB_GADGET_SELECTED - -config USB_GADGET_LANGWELL -	boolean "Intel Langwell USB Device Controller" +config USB_LANGWELL +	tristate "Intel Langwell USB Device Controller"  	depends on PCI +	depends on !PHYS_ADDR_T_64BIT  	select USB_GADGET_DUALSPEED  	help  	   Intel Langwell USB Device Controller is a High-Speed USB @@ -537,14 +441,8 @@ config USB_GADGET_LANGWELL  	   dynamically linked module called "langwell_udc" and force all  	   gadget drivers to also be dynamically linked. -config USB_LANGWELL -	tristate -	depends on USB_GADGET_LANGWELL -	default USB_GADGET -	select USB_GADGET_SELECTED - -config USB_GADGET_EG20T -	boolean "Intel EG20T PCH/OKI SEMICONDUCTOR ML7213 IOH UDC" +config USB_EG20T +	tristate "Intel EG20T PCH/OKI SEMICONDUCTOR ML7213 IOH UDC"  	depends on PCI  	select USB_GADGET_DUALSPEED  	help @@ -565,14 +463,8 @@ config USB_GADGET_EG20T  	  ML7213 is companion chip for Intel Atom E6xx series.  	  ML7213 is completely compatible for Intel EG20T PCH. -config USB_EG20T -	tristate -	depends on USB_GADGET_EG20T -	default USB_GADGET -	select USB_GADGET_SELECTED - -config USB_GADGET_CI13XXX_MSM -	boolean "MIPS USB CI13xxx for MSM" +config USB_CI13XXX_MSM +	tristate "MIPS USB CI13xxx for MSM"  	depends on ARCH_MSM  	select USB_GADGET_DUALSPEED  	select USB_MSM_OTG @@ -588,31 +480,26 @@ config USB_GADGET_CI13XXX_MSM  	  dynamically linked module called "ci13xxx_msm" and force all  	  gadget drivers to also be dynamically linked. -config USB_CI13XXX_MSM -	tristate -	depends on USB_GADGET_CI13XXX_MSM -	default USB_GADGET -	select USB_GADGET_SELECTED -  #  # LAST -- dummy/emulated controller  # -config USB_GADGET_DUMMY_HCD -	boolean "Dummy HCD (DEVELOPMENT)" +config USB_DUMMY_HCD +	tristate "Dummy HCD (DEVELOPMENT)"  	depends on USB=y || (USB=m && USB_GADGET=m)  	select USB_GADGET_DUALSPEED +	select USB_GADGET_SUPERSPEED  	help  	  This host controller driver emulates USB, looping all data transfer  	  requests back to a USB "gadget driver" in the same host.  The host  	  side is the master; the gadget side is the slave.  Gadget drivers  	  can be high, full, or low speed; and they have access to endpoints  	  like those from NET2280, PXA2xx, or SA1100 hardware. -	   +  	  This may help in some stages of creating a driver to embed in a  	  Linux device, since it lets you debug several parts of the gadget  	  driver without its hardware or drivers being involved. -	   +  	  Since such a gadget side driver needs to interoperate with a host  	  side Linux-USB device driver, this may help to debug both sides  	  of a USB protocol stack. @@ -621,31 +508,28 @@ config USB_GADGET_DUMMY_HCD  	  dynamically linked module called "dummy_hcd" and force all  	  gadget drivers to also be dynamically linked. -config USB_DUMMY_HCD -	tristate -	depends on USB_GADGET_DUMMY_HCD -	default USB_GADGET -	select USB_GADGET_SELECTED -  # NOTE:  Please keep dummy_hcd LAST so that "real hardware" appears  # first and will be selected by default.  endchoice +# Selected by UDC drivers that support high-speed operation.  config USB_GADGET_DUALSPEED  	bool  	depends on USB_GADGET -	default n -	help -	  Means that gadget drivers should include extra descriptors -	  and code to handle dual-speed controllers. + +# Selected by UDC drivers that support super-speed opperation +config USB_GADGET_SUPERSPEED +	bool +	depends on USB_GADGET +	depends on USB_GADGET_DUALSPEED  #  # USB Gadget Drivers  #  choice  	tristate "USB Gadget Drivers" -	depends on USB_GADGET && USB_GADGET_SELECTED +	depends on USB_GADGET  	default USB_ETH  	help  	  A Linux "Gadget Driver" talks to the USB Peripheral Controller @@ -851,7 +735,7 @@ config USB_FUNCTIONFS_GENERIC  	  no Ethernet interface.  config USB_FILE_STORAGE -	tristate "File-backed Storage Gadget" +	tristate "File-backed Storage Gadget (DEPRECATED)"  	depends on BLOCK  	help  	  The File-backed Storage Gadget acts as a USB Mass Storage @@ -862,6 +746,9 @@ config USB_FILE_STORAGE  	  Say "y" to link the driver statically, or "m" to build a  	  dynamically linked module called "g_file_storage". +	  NOTE: This driver is deprecated.  Its replacement is the +	  Mass Storage Gadget. +  config USB_FILE_STORAGE_TEST  	bool "File-backed Storage Gadget testing version"  	depends on USB_FILE_STORAGE @@ -881,14 +768,11 @@ config USB_MASS_STORAGE  	  device (in much the same way as the "loop" device driver),  	  specified as a module parameter or sysfs option. -	  This is heavily based on File-backed Storage Gadget and in most -	  cases you will want to use FSG instead.  This gadget is mostly -	  here to test the functionality of the Mass Storage Function -	  which may be used with composite framework. +	  This driver is an updated replacement for the deprecated +	  File-backed Storage Gadget (g_file_storage).  	  Say "y" to link the driver statically, or "m" to build -	  a dynamically linked module called "g_mass_storage".  If unsure, -	  consider File-backed Storage Gadget. +	  a dynamically linked module called "g_mass_storage".  config USB_G_SERIAL  	tristate "Serial Gadget (with CDC ACM and CDC OBEX support)" diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile index 4fe92b18a055..9ba725af4a08 100644 --- a/drivers/usb/gadget/Makefile +++ b/drivers/usb/gadget/Makefile @@ -3,7 +3,9 @@  #  ccflags-$(CONFIG_USB_GADGET_DEBUG) := -DDEBUG +obj-$(CONFIG_USB_GADGET)	+= udc-core.o  obj-$(CONFIG_USB_DUMMY_HCD)	+= dummy_hcd.o +obj-$(CONFIG_USB_NET2272)	+= net2272.o  obj-$(CONFIG_USB_NET2280)	+= net2280.o  obj-$(CONFIG_USB_AMD5536UDC)	+= amd5536udc.o  obj-$(CONFIG_USB_PXA25X)	+= pxa25x_udc.o diff --git a/drivers/usb/gadget/amd5536udc.c b/drivers/usb/gadget/amd5536udc.c index 6e42aab75806..70f2b376c86d 100644 --- a/drivers/usb/gadget/amd5536udc.c +++ b/drivers/usb/gadget/amd5536udc.c @@ -60,6 +60,7 @@  #include <linux/device.h>  #include <linux/io.h>  #include <linux/irq.h> +#include <linux/prefetch.h>  #include <asm/byteorder.h>  #include <asm/system.h> @@ -1437,10 +1438,15 @@ static int udc_wakeup(struct usb_gadget *gadget)  	return 0;  } +static int amd5536_start(struct usb_gadget_driver *driver, +		int (*bind)(struct usb_gadget *)); +static int amd5536_stop(struct usb_gadget_driver *driver);  /* gadget operations */  static const struct usb_gadget_ops udc_ops = {  	.wakeup		= udc_wakeup,  	.get_frame	= udc_get_frame, +	.start		= amd5536_start, +	.stop		= amd5536_stop,  };  /* Setups endpoint parameters, adds endpoints to linked list */ @@ -1954,7 +1960,7 @@ static int setup_ep0(struct udc *dev)  }  /* Called by gadget driver to register itself */ -int usb_gadget_probe_driver(struct usb_gadget_driver *driver, +static int amd5536_start(struct usb_gadget_driver *driver,  		int (*bind)(struct usb_gadget *))  {  	struct udc		*dev = udc; @@ -2001,7 +2007,6 @@ int usb_gadget_probe_driver(struct usb_gadget_driver *driver,  	return 0;  } -EXPORT_SYMBOL(usb_gadget_probe_driver);  /* shutdown requests and disconnect from gadget */  static void @@ -2026,7 +2031,7 @@ __acquires(dev->lock)  }  /* Called by gadget driver to unregister itself */ -int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) +static int amd5536_stop(struct usb_gadget_driver *driver)  {  	struct udc	*dev = udc;  	unsigned long	flags; @@ -2056,8 +2061,6 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)  	return 0;  } -EXPORT_SYMBOL(usb_gadget_unregister_driver); -  /* Clear pending NAK bits */  static void udc_process_cnak_queue(struct udc *dev) @@ -3133,6 +3136,7 @@ static void udc_pci_remove(struct pci_dev *pdev)  	dev = pci_get_drvdata(pdev); +	usb_del_gadget_udc(&udc->gadget);  	/* gadget driver must not be registered */  	BUG_ON(dev->driver != NULL); @@ -3381,8 +3385,13 @@ static int udc_probe(struct udc *dev)  		"driver version: %s(for Geode5536 B1)\n", tmp);  	udc = dev; +	retval = usb_add_gadget_udc(&udc->pdev->dev, &dev->gadget); +	if (retval) +		goto finished; +  	retval = device_register(&dev->gadget.dev);  	if (retval) { +		usb_del_gadget_udc(&dev->gadget);  		put_device(&dev->gadget.dev);  		goto finished;  	} diff --git a/drivers/usb/gadget/at91_udc.c b/drivers/usb/gadget/at91_udc.c index 41dc093c0a1b..98cbc06c30fd 100644 --- a/drivers/usb/gadget/at91_udc.c +++ b/drivers/usb/gadget/at91_udc.c @@ -38,6 +38,7 @@  #include <linux/clk.h>  #include <linux/usb/ch9.h>  #include <linux/usb/gadget.h> +#include <linux/prefetch.h>  #include <asm/byteorder.h>  #include <mach/hardware.h> @@ -984,12 +985,18 @@ static int at91_set_selfpowered(struct usb_gadget *gadget, int is_on)  	return 0;  } +static int at91_start(struct usb_gadget_driver *driver, +		int (*bind)(struct usb_gadget *)); +static int at91_stop(struct usb_gadget_driver *driver); +  static const struct usb_gadget_ops at91_udc_ops = {  	.get_frame		= at91_get_frame,  	.wakeup			= at91_wakeup,  	.set_selfpowered	= at91_set_selfpowered,  	.vbus_session		= at91_vbus_session,  	.pullup			= at91_pullup, +	.start			= at91_start, +	.stop			= at91_stop,  	/*  	 * VBUS-powered devices may also also want to support bigger @@ -1627,7 +1634,7 @@ static void at91_vbus_timer(unsigned long data)  		schedule_work(&udc->vbus_timer_work);  } -int usb_gadget_probe_driver(struct usb_gadget_driver *driver, +static int at91_start(struct usb_gadget_driver *driver,  		int (*bind)(struct usb_gadget *))  {  	struct at91_udc	*udc = &controller; @@ -1671,9 +1678,8 @@ int usb_gadget_probe_driver(struct usb_gadget_driver *driver,  	DBG("bound to %s\n", driver->driver.name);  	return 0;  } -EXPORT_SYMBOL(usb_gadget_probe_driver); -int usb_gadget_unregister_driver (struct usb_gadget_driver *driver) +static int at91_stop(struct usb_gadget_driver *driver)  {  	struct at91_udc *udc = &controller;  	unsigned long	flags; @@ -1695,7 +1701,6 @@ int usb_gadget_unregister_driver (struct usb_gadget_driver *driver)  	DBG("unbound from %s\n", driver->driver.name);  	return 0;  } -EXPORT_SYMBOL (usb_gadget_unregister_driver);  /*-------------------------------------------------------------------------*/ @@ -1853,13 +1858,18 @@ static int __init at91udc_probe(struct platform_device *pdev)  		DBG("no VBUS detection, assuming always-on\n");  		udc->vbus = 1;  	} +	retval = usb_add_gadget_udc(dev, &udc->gadget); +	if (retval) +		goto fail4;  	dev_set_drvdata(dev, udc);  	device_init_wakeup(dev, 1);  	create_debug_file(udc);  	INFO("%s version %s\n", driver_name, DRIVER_VERSION);  	return 0; - +fail4: +	if (udc->board.vbus_pin > 0 && !udc->board.vbus_polled) +		free_irq(udc->board.vbus_pin, udc);  fail3:  	if (udc->board.vbus_pin > 0)  		gpio_free(udc->board.vbus_pin); @@ -1886,6 +1896,7 @@ static int __exit at91udc_remove(struct platform_device *pdev)  	DBG("remove\n"); +	usb_del_gadget_udc(&udc->gadget);  	if (udc->driver)  		return -EBUSY; diff --git a/drivers/usb/gadget/atmel_usba_udc.c b/drivers/usb/gadget/atmel_usba_udc.c index db1a659702ba..5b1665eb1bef 100644 --- a/drivers/usb/gadget/atmel_usba_udc.c +++ b/drivers/usb/gadget/atmel_usba_udc.c @@ -272,7 +272,7 @@ static void usba_init_debugfs(struct usba_udc *udc)  	regs_resource = platform_get_resource(udc->pdev, IORESOURCE_MEM,  				CTRL_IOMEM_ID); -	regs->d_inode->i_size = regs_resource->end - regs_resource->start + 1; +	regs->d_inode->i_size = resource_size(regs_resource);  	udc->debugfs_regs = regs;  	usba_ep_init_debugfs(udc, to_usba_ep(udc->gadget.ep0)); @@ -1007,10 +1007,16 @@ usba_udc_set_selfpowered(struct usb_gadget *gadget, int is_selfpowered)  	return 0;  } +static int atmel_usba_start(struct usb_gadget_driver *driver, +		int (*bind)(struct usb_gadget *)); +static int atmel_usba_stop(struct usb_gadget_driver *driver); +  static const struct usb_gadget_ops usba_udc_ops = {  	.get_frame		= usba_udc_get_frame,  	.wakeup			= usba_udc_wakeup,  	.set_selfpowered	= usba_udc_set_selfpowered, +	.start			= atmel_usba_start, +	.stop			= atmel_usba_stop,  };  static struct usb_endpoint_descriptor usba_ep0_desc = { @@ -1789,7 +1795,7 @@ out:  	return IRQ_HANDLED;  } -int usb_gadget_probe_driver(struct usb_gadget_driver *driver, +static int atmel_usba_start(struct usb_gadget_driver *driver,  		int (*bind)(struct usb_gadget *))  {  	struct usba_udc *udc = &the_udc; @@ -1842,9 +1848,8 @@ err_driver_bind:  	udc->gadget.dev.driver = NULL;  	return ret;  } -EXPORT_SYMBOL(usb_gadget_probe_driver); -int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) +static int atmel_usba_stop(struct usb_gadget_driver *driver)  {  	struct usba_udc *udc = &the_udc;  	unsigned long flags; @@ -1880,7 +1885,6 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)  	return 0;  } -EXPORT_SYMBOL(usb_gadget_unregister_driver);  static int __init usba_udc_probe(struct platform_device *pdev)  { @@ -2021,12 +2025,24 @@ 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; +  	usba_init_debugfs(udc);  	for (i = 1; i < pdata->num_ep; i++)  		usba_ep_init_debugfs(udc, &usba_ep[i]);  	return 0; +err_add_udc: +	if (gpio_is_valid(pdata->vbus_pin)) { +		free_irq(gpio_to_irq(udc->vbus_pin), udc); +		gpio_free(udc->vbus_pin); +	} + +	device_unregister(&udc->gadget.dev); +  err_device_add:  	free_irq(irq, udc);  err_request_irq: @@ -2053,6 +2069,8 @@ static int __exit usba_udc_remove(struct platform_device *pdev)  	udc = platform_get_drvdata(pdev); +	usb_del_gadget_udc(&udc->gadget); +  	for (i = 1; i < pdata->num_ep; i++)  		usba_ep_cleanup_debugfs(&usba_ep[i]);  	usba_cleanup_debugfs(udc); diff --git a/drivers/usb/gadget/audio.c b/drivers/usb/gadget/audio.c index 93b999e49ef3..9d89ae4765a9 100644 --- a/drivers/usb/gadget/audio.c +++ b/drivers/usb/gadget/audio.c @@ -165,6 +165,7 @@ static struct usb_composite_driver audio_driver = {  	.name		= "g_audio",  	.dev		= &device_desc,  	.strings	= audio_strings, +	.max_speed	= USB_SPEED_HIGH,  	.unbind		= __exit_p(audio_unbind),  }; diff --git a/drivers/usb/gadget/cdc2.c b/drivers/usb/gadget/cdc2.c index 2720ab07ef1a..b1c1afbb8750 100644 --- a/drivers/usb/gadget/cdc2.c +++ b/drivers/usb/gadget/cdc2.c @@ -244,6 +244,7 @@ static struct usb_composite_driver cdc_driver = {  	.name		= "g_cdc",  	.dev		= &device_desc,  	.strings	= dev_strings, +	.max_speed	= USB_SPEED_HIGH,  	.unbind		= __exit_p(cdc_unbind),  }; diff --git a/drivers/usb/gadget/ci13xxx_msm.c b/drivers/usb/gadget/ci13xxx_msm.c index 139ac9419597..470981ad6f77 100644 --- a/drivers/usb/gadget/ci13xxx_msm.c +++ b/drivers/usb/gadget/ci13xxx_msm.c @@ -126,6 +126,7 @@ static struct platform_driver ci13xxx_msm_driver = {  	.probe = ci13xxx_msm_probe,  	.driver = { .name = "msm_hsusb", },  }; +MODULE_ALIAS("platform:msm_hsusb");  static int __init ci13xxx_msm_init(void)  { diff --git a/drivers/usb/gadget/ci13xxx_udc.c b/drivers/usb/gadget/ci13xxx_udc.c index baaf87ed7685..1265a8502ea0 100644 --- a/drivers/usb/gadget/ci13xxx_udc.c +++ b/drivers/usb/gadget/ci13xxx_udc.c @@ -857,7 +857,7 @@ static void dbg_print(u8 addr, const char *name, int status, const char *extra)  	stamp = stamp * 1000000 + tval.tv_usec;  	scnprintf(dbg_data.buf[dbg_data.idx], DBG_DATA_MSG, -		  "%04X\t» %02X %-7.7s %4i «\t%s\n", +		  "%04X\t? %02X %-7.7s %4i ?\t%s\n",  		  stamp, addr, name, status, extra);  	dbg_inc(&dbg_data.idx); @@ -865,7 +865,7 @@ static void dbg_print(u8 addr, const char *name, int status, const char *extra)  	write_unlock_irqrestore(&dbg_data.lck, flags);  	if (dbg_data.tty != 0) -		pr_notice("%04X\t» %02X %-7.7s %4i «\t%s\n", +		pr_notice("%04X\t? %02X %-7.7s %4i ?\t%s\n",  			  stamp, addr, name, status, extra);  } @@ -1025,15 +1025,15 @@ static ssize_t show_inters(struct device *dev, struct device_attribute *attr,  	n += scnprintf(buf + n, PAGE_SIZE - n, "*test = %d\n",  		       isr_statistics.test); -	n += scnprintf(buf + n, PAGE_SIZE - n, "» ui  = %d\n", +	n += scnprintf(buf + n, PAGE_SIZE - n, "? ui  = %d\n",  		       isr_statistics.ui); -	n += scnprintf(buf + n, PAGE_SIZE - n, "» uei = %d\n", +	n += scnprintf(buf + n, PAGE_SIZE - n, "? uei = %d\n",  		       isr_statistics.uei); -	n += scnprintf(buf + n, PAGE_SIZE - n, "» pci = %d\n", +	n += scnprintf(buf + n, PAGE_SIZE - n, "? pci = %d\n",  		       isr_statistics.pci); -	n += scnprintf(buf + n, PAGE_SIZE - n, "» uri = %d\n", +	n += scnprintf(buf + n, PAGE_SIZE - n, "? uri = %d\n",  		       isr_statistics.uri); -	n += scnprintf(buf + n, PAGE_SIZE - n, "» sli = %d\n", +	n += scnprintf(buf + n, PAGE_SIZE - n, "? sli = %d\n",  		       isr_statistics.sli);  	n += scnprintf(buf + n, PAGE_SIZE - n, "*none = %d\n",  		       isr_statistics.none); @@ -1214,12 +1214,13 @@ static DEVICE_ATTR(qheads, S_IRUSR, show_qheads, NULL);   *   * Check "device.h" for details   */ +#define DUMP_ENTRIES	512  static ssize_t show_registers(struct device *dev,  			      struct device_attribute *attr, char *buf)  {  	struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev);  	unsigned long flags; -	u32 dump[512]; +	u32 *dump;  	unsigned i, k, n = 0;  	dbg_trace("[%s] %p\n", __func__, buf); @@ -1228,8 +1229,14 @@ static ssize_t show_registers(struct device *dev,  		return 0;  	} +	dump = kmalloc(sizeof(u32) * DUMP_ENTRIES, GFP_KERNEL); +	if (!dump) { +		dev_err(dev, "%s: out of memory\n", __func__); +		return 0; +	} +  	spin_lock_irqsave(udc->lock, flags); -	k = hw_register_read(dump, sizeof(dump)/sizeof(u32)); +	k = hw_register_read(dump, DUMP_ENTRIES);  	spin_unlock_irqrestore(udc->lock, flags);  	for (i = 0; i < k; i++) { @@ -1237,6 +1244,7 @@ static ssize_t show_registers(struct device *dev,  			       "reg[0x%04X] = 0x%08X\n",  			       i * (unsigned)sizeof(u32), dump[i]);  	} +	kfree(dump);  	return n;  } @@ -2515,6 +2523,9 @@ static int ci13xxx_vbus_draw(struct usb_gadget *_gadget, unsigned mA)  	return -ENOTSUPP;  } +static int ci13xxx_start(struct usb_gadget_driver *driver, +		int (*bind)(struct usb_gadget *)); +static int ci13xxx_stop(struct usb_gadget_driver *driver);  /**   * Device operations part of the API to the USB controller hardware,   * which don't involve endpoints (or i/o) @@ -2524,17 +2535,19 @@ static const struct usb_gadget_ops usb_gadget_ops = {  	.vbus_session	= ci13xxx_vbus_session,  	.wakeup		= ci13xxx_wakeup,  	.vbus_draw	= ci13xxx_vbus_draw, +	.start		= ci13xxx_start, +	.stop		= ci13xxx_stop,  };  /** - * usb_gadget_probe_driver: register a gadget driver + * ci13xxx_start: register a gadget driver   * @driver: the driver being registered   * @bind: the driver's bind callback   * - * Check usb_gadget_probe_driver() at <linux/usb/gadget.h> for details. + * Check ci13xxx_start() at <linux/usb/gadget.h> for details.   * Interrupts are enabled here.   */ -int usb_gadget_probe_driver(struct usb_gadget_driver *driver, +static int ci13xxx_start(struct usb_gadget_driver *driver,  		int (*bind)(struct usb_gadget *))  {  	struct ci13xxx *udc = _udc; @@ -2615,10 +2628,13 @@ int usb_gadget_probe_driver(struct usb_gadget_driver *driver,  	if (retval)  		goto done;  	spin_unlock_irqrestore(udc->lock, flags); -	retval = usb_ep_enable(&udc->ep0out.ep, &ctrl_endpt_out_desc); +	udc->ep0out.ep.desc = &ctrl_endpt_out_desc; +	retval = usb_ep_enable(&udc->ep0out.ep);  	if (retval)  		return retval; -	retval = usb_ep_enable(&udc->ep0in.ep, &ctrl_endpt_in_desc); + +	udc->ep0in.ep.desc = &ctrl_endpt_in_desc; +	retval = usb_ep_enable(&udc->ep0in.ep);  	if (retval)  		return retval;  	spin_lock_irqsave(udc->lock, flags); @@ -2657,14 +2673,13 @@ int usb_gadget_probe_driver(struct usb_gadget_driver *driver,  	spin_unlock_irqrestore(udc->lock, flags);  	return retval;  } -EXPORT_SYMBOL(usb_gadget_probe_driver);  /** - * usb_gadget_unregister_driver: unregister a gadget driver + * ci13xxx_stop: unregister a gadget driver   *   * Check usb_gadget_unregister_driver() at "usb_gadget.h" for details   */ -int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) +static int ci13xxx_stop(struct usb_gadget_driver *driver)  {  	struct ci13xxx *udc = _udc;  	unsigned long i, flags; @@ -2726,7 +2741,6 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)  	return 0;  } -EXPORT_SYMBOL(usb_gadget_unregister_driver);  /******************************************************************************   * BUS block @@ -2901,12 +2915,23 @@ static int udc_probe(struct ci13xxx_udc_driver *driver, struct device *dev,  		if (retval)  			goto remove_dbg;  	} + +	retval = usb_add_gadget_udc(dev, &udc->gadget); +	if (retval) +		goto remove_trans; +  	pm_runtime_no_callbacks(&udc->gadget.dev);  	pm_runtime_enable(&udc->gadget.dev);  	_udc = udc;  	return retval; +remove_trans: +	if (udc->transceiver) { +		otg_set_peripheral(udc->transceiver, &udc->gadget); +		otg_put_transceiver(udc->transceiver); +	} +  	err("error = %i", retval);  remove_dbg:  #ifdef CONFIG_USB_GADGET_DEBUG_FILES @@ -2936,6 +2961,7 @@ static void udc_remove(void)  		err("EINVAL");  		return;  	} +	usb_del_gadget_udc(&udc->gadget);  	if (udc->transceiver) {  		otg_set_peripheral(udc->transceiver, &udc->gadget); diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c index 5cbb1a41c223..5ef87794fd32 100644 --- a/drivers/usb/gadget/composite.c +++ b/drivers/usb/gadget/composite.c @@ -27,7 +27,7 @@  #include <linux/utsname.h>  #include <linux/usb/composite.h> - +#include <asm/unaligned.h>  /*   * The code in this file is utility code, used to build a gadget driver @@ -74,6 +74,130 @@ MODULE_PARM_DESC(iSerialNumber, "SerialNumber string");  static char composite_manufacturer[50];  /*-------------------------------------------------------------------------*/ +/** + * next_ep_desc() - advance to the next EP descriptor + * @t: currect pointer within descriptor array + * + * Return: next EP descriptor or NULL + * + * Iterate over @t until either EP descriptor found or + * NULL (that indicates end of list) encountered + */ +static struct usb_descriptor_header** +next_ep_desc(struct usb_descriptor_header **t) +{ +	for (; *t; t++) { +		if ((*t)->bDescriptorType == USB_DT_ENDPOINT) +			return t; +	} +	return NULL; +} + +/* + * for_each_ep_desc()- iterate over endpoint descriptors in the + *		descriptors list + * @start:	pointer within descriptor array. + * @ep_desc:	endpoint descriptor to use as the loop cursor + */ +#define for_each_ep_desc(start, ep_desc) \ +	for (ep_desc = next_ep_desc(start); \ +	      ep_desc; ep_desc = next_ep_desc(ep_desc+1)) + +/** + * config_ep_by_speed() - configures the given endpoint + * according to gadget speed. + * @g: pointer to the gadget + * @f: usb function + * @_ep: the endpoint to configure + * + * Return: error code, 0 on success + * + * This function chooses the right descriptors for a given + * endpoint according to gadget speed and saves it in the + * endpoint desc field. If the endpoint already has a descriptor + * assigned to it - overwrites it with currently corresponding + * descriptor. The endpoint maxpacket field is updated according + * to the chosen descriptor. + * Note: the supplied function should hold all the descriptors + * for supported speeds + */ +int config_ep_by_speed(struct usb_gadget *g, +			struct usb_function *f, +			struct usb_ep *_ep) +{ +	struct usb_endpoint_descriptor *chosen_desc = NULL; +	struct usb_descriptor_header **speed_desc = NULL; + +	struct usb_ss_ep_comp_descriptor *comp_desc = NULL; +	int want_comp_desc = 0; + +	struct usb_descriptor_header **d_spd; /* cursor for speed desc */ + +	if (!g || !f || !_ep) +		return -EIO; + +	/* select desired speed */ +	switch (g->speed) { +	case USB_SPEED_SUPER: +		if (gadget_is_superspeed(g)) { +			speed_desc = f->ss_descriptors; +			want_comp_desc = 1; +			break; +		} +		/* else: Fall trough */ +	case USB_SPEED_HIGH: +		if (gadget_is_dualspeed(g)) { +			speed_desc = f->hs_descriptors; +			break; +		} +		/* else: fall through */ +	default: +		speed_desc = f->descriptors; +	} +	/* find descriptors */ +	for_each_ep_desc(speed_desc, d_spd) { +		chosen_desc = (struct usb_endpoint_descriptor *)*d_spd; +		if (chosen_desc->bEndpointAddress == _ep->address) +			goto ep_found; +	} +	return -EIO; + +ep_found: +	/* commit results */ +	_ep->maxpacket = le16_to_cpu(chosen_desc->wMaxPacketSize); +	_ep->desc = chosen_desc; +	_ep->comp_desc = NULL; +	_ep->maxburst = 0; +	_ep->mult = 0; +	if (!want_comp_desc) +		return 0; + +	/* +	 * Companion descriptor should follow EP descriptor +	 * USB 3.0 spec, #9.6.7 +	 */ +	comp_desc = (struct usb_ss_ep_comp_descriptor *)*(++d_spd); +	if (!comp_desc || +	    (comp_desc->bDescriptorType != USB_DT_SS_ENDPOINT_COMP)) +		return -EIO; +	_ep->comp_desc = comp_desc; +	if (g->speed == USB_SPEED_SUPER) { +		switch (usb_endpoint_type(_ep->desc)) { +		case USB_ENDPOINT_XFER_BULK: +		case USB_ENDPOINT_XFER_INT: +			_ep->maxburst = comp_desc->bMaxBurst; +			break; +		case USB_ENDPOINT_XFER_ISOC: +			/* mult: bits 1:0 of bmAttributes */ +			_ep->mult = comp_desc->bmAttributes & 0x3; +			break; +		default: +			/* Do nothing for control endpoints */ +			break; +		} +	} +	return 0; +}  /**   * usb_add_function() - add a function to a configuration @@ -123,6 +247,8 @@ int usb_add_function(struct usb_configuration *config,  		config->fullspeed = true;  	if (!config->highspeed && function->hs_descriptors)  		config->highspeed = true; +	if (!config->superspeed && function->ss_descriptors) +		config->superspeed = true;  done:  	if (value) @@ -266,10 +392,17 @@ static int config_buf(struct usb_configuration *config,  	list_for_each_entry(f, &config->functions, list) {  		struct usb_descriptor_header **descriptors; -		if (speed == USB_SPEED_HIGH) +		switch (speed) { +		case USB_SPEED_SUPER: +			descriptors = f->ss_descriptors; +			break; +		case USB_SPEED_HIGH:  			descriptors = f->hs_descriptors; -		else +			break; +		default:  			descriptors = f->descriptors; +		} +  		if (!descriptors)  			continue;  		status = usb_descriptor_fillbuf(next, len, @@ -292,9 +425,10 @@ static int config_desc(struct usb_composite_dev *cdev, unsigned w_value)  	u8				type = w_value >> 8;  	enum usb_device_speed		speed = USB_SPEED_UNKNOWN; -	if (gadget_is_dualspeed(gadget)) { -		int			hs = 0; - +	if (gadget->speed == USB_SPEED_SUPER) +		speed = gadget->speed; +	else if (gadget_is_dualspeed(gadget)) { +		int	hs = 0;  		if (gadget->speed == USB_SPEED_HIGH)  			hs = 1;  		if (type == USB_DT_OTHER_SPEED_CONFIG) @@ -308,13 +442,20 @@ static int config_desc(struct usb_composite_dev *cdev, unsigned w_value)  	w_value &= 0xff;  	list_for_each_entry(c, &cdev->configs, list) {  		/* ignore configs that won't work at this speed */ -		if (speed == USB_SPEED_HIGH) { +		switch (speed) { +		case USB_SPEED_SUPER: +			if (!c->superspeed) +				continue; +			break; +		case USB_SPEED_HIGH:  			if (!c->highspeed)  				continue; -		} else { +			break; +		default:  			if (!c->fullspeed)  				continue;  		} +  		if (w_value == 0)  			return config_buf(c, speed, cdev->req->buf, type);  		w_value--; @@ -328,16 +469,22 @@ static int count_configs(struct usb_composite_dev *cdev, unsigned type)  	struct usb_configuration	*c;  	unsigned			count = 0;  	int				hs = 0; +	int				ss = 0;  	if (gadget_is_dualspeed(gadget)) {  		if (gadget->speed == USB_SPEED_HIGH)  			hs = 1; +		if (gadget->speed == USB_SPEED_SUPER) +			ss = 1;  		if (type == USB_DT_DEVICE_QUALIFIER)  			hs = !hs;  	}  	list_for_each_entry(c, &cdev->configs, list) {  		/* ignore configs that won't work at this speed */ -		if (hs) { +		if (ss) { +			if (!c->superspeed) +				continue; +		} else if (hs) {  			if (!c->highspeed)  				continue;  		} else { @@ -349,6 +496,71 @@ static int count_configs(struct usb_composite_dev *cdev, unsigned type)  	return count;  } +/** + * bos_desc() - prepares the BOS descriptor. + * @cdev: pointer to usb_composite device to generate the bos + *	descriptor for + * + * This function generates the BOS (Binary Device Object) + * descriptor and its device capabilities descriptors. The BOS + * descriptor should be supported by a SuperSpeed device. + */ +static int bos_desc(struct usb_composite_dev *cdev) +{ +	struct usb_ext_cap_descriptor	*usb_ext; +	struct usb_ss_cap_descriptor	*ss_cap; +	struct usb_dcd_config_params	dcd_config_params; +	struct usb_bos_descriptor	*bos = cdev->req->buf; + +	bos->bLength = USB_DT_BOS_SIZE; +	bos->bDescriptorType = USB_DT_BOS; + +	bos->wTotalLength = cpu_to_le16(USB_DT_BOS_SIZE); +	bos->bNumDeviceCaps = 0; + +	/* +	 * A SuperSpeed device shall include the USB2.0 extension descriptor +	 * and shall support LPM when operating in USB2.0 HS mode. +	 */ +	usb_ext = cdev->req->buf + le16_to_cpu(bos->wTotalLength); +	bos->bNumDeviceCaps++; +	le16_add_cpu(&bos->wTotalLength, USB_DT_USB_EXT_CAP_SIZE); +	usb_ext->bLength = USB_DT_USB_EXT_CAP_SIZE; +	usb_ext->bDescriptorType = USB_DT_DEVICE_CAPABILITY; +	usb_ext->bDevCapabilityType = USB_CAP_TYPE_EXT; +	usb_ext->bmAttributes = cpu_to_le32(USB_LPM_SUPPORT); + +	/* +	 * The Superspeed USB Capability descriptor shall be implemented by all +	 * SuperSpeed devices. +	 */ +	ss_cap = cdev->req->buf + le16_to_cpu(bos->wTotalLength); +	bos->bNumDeviceCaps++; +	le16_add_cpu(&bos->wTotalLength, USB_DT_USB_SS_CAP_SIZE); +	ss_cap->bLength = USB_DT_USB_SS_CAP_SIZE; +	ss_cap->bDescriptorType = USB_DT_DEVICE_CAPABILITY; +	ss_cap->bDevCapabilityType = USB_SS_CAP_TYPE; +	ss_cap->bmAttributes = 0; /* LTM is not supported yet */ +	ss_cap->wSpeedSupported = cpu_to_le16(USB_LOW_SPEED_OPERATION | +				USB_FULL_SPEED_OPERATION | +				USB_HIGH_SPEED_OPERATION | +				USB_5GBPS_OPERATION); +	ss_cap->bFunctionalitySupport = USB_LOW_SPEED_OPERATION; + +	/* Get Controller configuration */ +	if (cdev->gadget->ops->get_config_params) +		cdev->gadget->ops->get_config_params(&dcd_config_params); +	else { +		dcd_config_params.bU1devExitLat = USB_DEFULT_U1_DEV_EXIT_LAT; +		dcd_config_params.bU2DevExitLat = +			cpu_to_le16(USB_DEFULT_U2_DEV_EXIT_LAT); +	} +	ss_cap->bU1devExitLat = dcd_config_params.bU1devExitLat; +	ss_cap->bU2DevExitLat = dcd_config_params.bU2DevExitLat; + +	return le16_to_cpu(bos->wTotalLength); +} +  static void device_qual(struct usb_composite_dev *cdev)  {  	struct usb_qualifier_descriptor	*qual = cdev->req->buf; @@ -361,7 +573,7 @@ static void device_qual(struct usb_composite_dev *cdev)  	qual->bDeviceSubClass = cdev->desc.bDeviceSubClass;  	qual->bDeviceProtocol = cdev->desc.bDeviceProtocol;  	/* ASSUME same EP0 fifo size at both speeds */ -	qual->bMaxPacketSize0 = cdev->desc.bMaxPacketSize0; +	qual->bMaxPacketSize0 = cdev->gadget->ep0->maxpacket;  	qual->bNumConfigurations = count_configs(cdev, USB_DT_DEVICE_QUALIFIER);  	qual->bRESERVED = 0;  } @@ -392,28 +604,46 @@ static int set_config(struct usb_composite_dev *cdev,  	unsigned		power = gadget_is_otg(gadget) ? 8 : 100;  	int			tmp; -	if (cdev->config) -		reset_config(cdev); -  	if (number) {  		list_for_each_entry(c, &cdev->configs, list) {  			if (c->bConfigurationValue == number) { +				/* +				 * We disable the FDs of the previous +				 * configuration only if the new configuration +				 * is a valid one +				 */ +				if (cdev->config) +					reset_config(cdev);  				result = 0;  				break;  			}  		}  		if (result < 0)  			goto done; -	} else +	} else { /* Zero configuration value - need to reset the config */ +		if (cdev->config) +			reset_config(cdev);  		result = 0; +	}  	INFO(cdev, "%s speed config #%d: %s\n",  		({ char *speed;  		switch (gadget->speed) { -		case USB_SPEED_LOW:	speed = "low"; break; -		case USB_SPEED_FULL:	speed = "full"; break; -		case USB_SPEED_HIGH:	speed = "high"; break; -		default:		speed = "?"; break; +		case USB_SPEED_LOW: +			speed = "low"; +			break; +		case USB_SPEED_FULL: +			speed = "full"; +			break; +		case USB_SPEED_HIGH: +			speed = "high"; +			break; +		case USB_SPEED_SUPER: +			speed = "super"; +			break; +		default: +			speed = "?"; +			break;  		} ; speed; }), number, c ? c->label : "unconfigured");  	if (!c) @@ -435,10 +665,16 @@ static int set_config(struct usb_composite_dev *cdev,  		 * function's setup callback instead of the current  		 * configuration's setup callback.  		 */ -		if (gadget->speed == USB_SPEED_HIGH) +		switch (gadget->speed) { +		case USB_SPEED_SUPER: +			descriptors = f->ss_descriptors; +			break; +		case USB_SPEED_HIGH:  			descriptors = f->hs_descriptors; -		else +			break; +		default:  			descriptors = f->descriptors; +		}  		for (; *descriptors; ++descriptors) {  			struct usb_endpoint_descriptor *ep; @@ -531,8 +767,9 @@ int usb_add_config(struct usb_composite_dev *cdev,  	} else {  		unsigned	i; -		DBG(cdev, "cfg %d/%p speeds:%s%s\n", +		DBG(cdev, "cfg %d/%p speeds:%s%s%s\n",  			config->bConfigurationValue, config, +			config->superspeed ? " super" : "",  			config->highspeed ? " high" : "",  			config->fullspeed  				? (gadget_is_dualspeed(cdev->gadget) @@ -811,6 +1048,7 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)  	struct usb_composite_dev	*cdev = get_gadget_data(gadget);  	struct usb_request		*req = cdev->req;  	int				value = -EOPNOTSUPP; +	int				status = 0;  	u16				w_index = le16_to_cpu(ctrl->wIndex);  	u8				intf = w_index & 0xFF;  	u16				w_value = le16_to_cpu(ctrl->wValue); @@ -838,18 +1076,29 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)  		case USB_DT_DEVICE:  			cdev->desc.bNumConfigurations =  				count_configs(cdev, USB_DT_DEVICE); +			cdev->desc.bMaxPacketSize0 = +				cdev->gadget->ep0->maxpacket; +			if (gadget_is_superspeed(gadget)) { +				if (gadget->speed >= USB_SPEED_SUPER) +					cdev->desc.bcdUSB = cpu_to_le16(0x0300); +				else +					cdev->desc.bcdUSB = cpu_to_le16(0x0210); +			} +  			value = min(w_length, (u16) sizeof cdev->desc);  			memcpy(req->buf, &cdev->desc, value);  			break;  		case USB_DT_DEVICE_QUALIFIER: -			if (!gadget_is_dualspeed(gadget)) +			if (!gadget_is_dualspeed(gadget) || +			    gadget->speed >= USB_SPEED_SUPER)  				break;  			device_qual(cdev);  			value = min_t(int, w_length,  				sizeof(struct usb_qualifier_descriptor));  			break;  		case USB_DT_OTHER_SPEED_CONFIG: -			if (!gadget_is_dualspeed(gadget)) +			if (!gadget_is_dualspeed(gadget) || +			    gadget->speed >= USB_SPEED_SUPER)  				break;  			/* FALLTHROUGH */  		case USB_DT_CONFIG: @@ -863,6 +1112,12 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)  			if (value >= 0)  				value = min(w_length, (u16) value);  			break; +		case USB_DT_BOS: +			if (gadget_is_superspeed(gadget)) { +				value = bos_desc(cdev); +				value = min(w_length, (u16) value); +			} +			break;  		}  		break; @@ -930,6 +1185,61 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)  		*((u8 *)req->buf) = value;  		value = min(w_length, (u16) 1);  		break; + +	/* +	 * USB 3.0 additions: +	 * Function driver should handle get_status request. If such cb +	 * wasn't supplied we respond with default value = 0 +	 * Note: function driver should supply such cb only for the first +	 * interface of the function +	 */ +	case USB_REQ_GET_STATUS: +		if (!gadget_is_superspeed(gadget)) +			goto unknown; +		if (ctrl->bRequestType != (USB_DIR_IN | USB_RECIP_INTERFACE)) +			goto unknown; +		value = 2;	/* This is the length of the get_status reply */ +		put_unaligned_le16(0, req->buf); +		if (!cdev->config || intf >= MAX_CONFIG_INTERFACES) +			break; +		f = cdev->config->interface[intf]; +		if (!f) +			break; +		status = f->get_status ? f->get_status(f) : 0; +		if (status < 0) +			break; +		put_unaligned_le16(status & 0x0000ffff, req->buf); +		break; +	/* +	 * Function drivers should handle SetFeature/ClearFeature +	 * (FUNCTION_SUSPEND) request. function_suspend cb should be supplied +	 * only for the first interface of the function +	 */ +	case USB_REQ_CLEAR_FEATURE: +	case USB_REQ_SET_FEATURE: +		if (!gadget_is_superspeed(gadget)) +			goto unknown; +		if (ctrl->bRequestType != (USB_DIR_OUT | USB_RECIP_INTERFACE)) +			goto unknown; +		switch (w_value) { +		case USB_INTRF_FUNC_SUSPEND: +			if (!cdev->config || intf >= MAX_CONFIG_INTERFACES) +				break; +			f = cdev->config->interface[intf]; +			if (!f) +				break; +			value = 0; +			if (f->func_suspend) +				value = f->func_suspend(f, w_index >> 8); +			if (value < 0) { +				ERROR(cdev, +				      "func_suspend() returned error %d\n", +				      value); +				value = 0; +			} +			break; +		} +		break;  	default:  unknown:  		VDBG(cdev, @@ -1140,7 +1450,6 @@ static int composite_bind(struct usb_gadget *gadget)  		goto fail;  	cdev->desc = *composite->dev; -	cdev->desc.bMaxPacketSize0 = gadget->ep0->maxpacket;  	/* standardized runtime overrides for device ID data */  	if (idVendor) @@ -1247,7 +1556,11 @@ composite_resume(struct usb_gadget *gadget)  /*-------------------------------------------------------------------------*/  static struct usb_gadget_driver composite_driver = { +#ifdef CONFIG_USB_GADGET_SUPERSPEED +	.speed		= USB_SPEED_SUPER, +#else  	.speed		= USB_SPEED_HIGH, +#endif  	.unbind		= composite_unbind, @@ -1293,6 +1606,8 @@ int usb_composite_probe(struct usb_composite_driver *driver,  		driver->iProduct = driver->name;  	composite_driver.function =  (char *) driver->name;  	composite_driver.driver.name = driver->name; +	composite_driver.speed = min((u8)composite_driver.speed, +				     (u8)driver->max_speed);  	composite = driver;  	composite_gadget_bind = bind; diff --git a/drivers/usb/gadget/config.c b/drivers/usb/gadget/config.c index 09084fd646ab..b2c001334876 100644 --- a/drivers/usb/gadget/config.c +++ b/drivers/usb/gadget/config.c @@ -165,28 +165,3 @@ usb_copy_descriptors(struct usb_descriptor_header **src)  	return ret;  } -/** - * usb_find_endpoint - find a copy of an endpoint descriptor - * @src: original vector of descriptors - * @copy: copy of @src - * @match: endpoint descriptor found in @src - * - * This returns the copy of the @match descriptor made for @copy.  Its - * intended use is to help remembering the endpoint descriptor to use - * when enabling a given endpoint. - */ -struct usb_endpoint_descriptor * -usb_find_endpoint( -	struct usb_descriptor_header **src, -	struct usb_descriptor_header **copy, -	struct usb_endpoint_descriptor *match -) -{ -	while (*src) { -		if (*src == (void *) match) -			return (void *)*copy; -		src++; -		copy++; -	} -	return NULL; -} diff --git a/drivers/usb/gadget/dbgp.c b/drivers/usb/gadget/dbgp.c index dbe92ee88477..8beefdd36787 100644 --- a/drivers/usb/gadget/dbgp.c +++ b/drivers/usb/gadget/dbgp.c @@ -173,7 +173,9 @@ fail_1:  static int __enable_ep(struct usb_ep *ep, struct usb_endpoint_descriptor *desc)  { -	int err = usb_ep_enable(ep, desc); +	int err; +	ep->desc = desc; +	err = usb_ep_enable(ep);  	ep->driver_data = dbgp.gadget;  	return err;  } @@ -268,8 +270,8 @@ static int __init dbgp_configure_endpoints(struct usb_gadget *gadget)  	dbgp.serial->in = dbgp.i_ep;  	dbgp.serial->out = dbgp.o_ep; -	dbgp.serial->in_desc = &i_desc; -	dbgp.serial->out_desc = &o_desc; +	dbgp.serial->in->desc = &i_desc; +	dbgp.serial->out->desc = &o_desc;  	if (gserial_setup(gadget, 1) < 0) {  		stp = 3; @@ -312,7 +314,6 @@ static int __init dbgp_bind(struct usb_gadget *gadget)  	dbgp.req->length = DBGP_REQ_EP0_LEN;  	gadget->ep0->driver_data = gadget; -	device_desc.bMaxPacketSize0 = gadget->ep0->maxpacket;  #ifdef CONFIG_USB_G_DBGP_SERIAL  	dbgp.serial = kzalloc(sizeof(struct gserial), GFP_KERNEL); @@ -363,6 +364,7 @@ static int dbgp_setup(struct usb_gadget *gadget,  			dev_dbg(&dbgp.gadget->dev, "setup: desc device\n");  			len = sizeof device_desc;  			data = &device_desc; +			device_desc.bMaxPacketSize0 = gadget->ep0->maxpacket;  			break;  		case USB_DT_DEBUG:  			dev_dbg(&dbgp.gadget->dev, "setup: desc debug\n"); diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c index 61ff927928ab..e755a9d267fc 100644 --- a/drivers/usb/gadget/dummy_hcd.c +++ b/drivers/usb/gadget/dummy_hcd.c @@ -70,6 +70,19 @@ MODULE_DESCRIPTION (DRIVER_DESC);  MODULE_AUTHOR ("David Brownell");  MODULE_LICENSE ("GPL"); +struct dummy_hcd_module_parameters { +	bool is_super_speed; +	bool is_high_speed; +}; + +static struct dummy_hcd_module_parameters mod_data = { +	.is_super_speed = false, +	.is_high_speed = true, +}; +module_param_named(is_super_speed, mod_data.is_super_speed, bool, S_IRUGO); +MODULE_PARM_DESC(is_super_speed, "true to simulate SuperSpeed connection"); +module_param_named(is_high_speed, mod_data.is_high_speed, bool, S_IRUGO); +MODULE_PARM_DESC(is_high_speed, "true to simulate HighSpeed connection");  /*-------------------------------------------------------------------------*/  /* gadget side driver data structres */ @@ -152,6 +165,22 @@ enum dummy_rh_state {  	DUMMY_RH_RUNNING  }; +struct dummy_hcd { +	struct dummy			*dum; +	enum dummy_rh_state		rh_state; +	struct timer_list		timer; +	u32				port_status; +	u32				old_status; +	unsigned long			re_timeout; + +	struct usb_device		*udev; +	struct list_head		urbp_list; + +	unsigned			active:1; +	unsigned			old_active:1; +	unsigned			resuming:1; +}; +  struct dummy {  	spinlock_t			lock; @@ -167,36 +196,27 @@ struct dummy {  	u16				devstatus;  	unsigned			udc_suspended:1;  	unsigned			pullup:1; -	unsigned			active:1; -	unsigned			old_active:1;  	/*  	 * MASTER/HOST side support  	 */ -	enum dummy_rh_state		rh_state; -	struct timer_list		timer; -	u32				port_status; -	u32				old_status; -	unsigned			resuming:1; -	unsigned long			re_timeout; - -	struct usb_device		*udev; -	struct list_head		urbp_list; +	struct dummy_hcd		*hs_hcd; +	struct dummy_hcd		*ss_hcd;  }; -static inline struct dummy *hcd_to_dummy (struct usb_hcd *hcd) +static inline struct dummy_hcd *hcd_to_dummy_hcd(struct usb_hcd *hcd)  { -	return (struct dummy *) (hcd->hcd_priv); +	return (struct dummy_hcd *) (hcd->hcd_priv);  } -static inline struct usb_hcd *dummy_to_hcd (struct dummy *dum) +static inline struct usb_hcd *dummy_hcd_to_hcd(struct dummy_hcd *dum)  {  	return container_of((void *) dum, struct usb_hcd, hcd_priv);  } -static inline struct device *dummy_dev (struct dummy *dum) +static inline struct device *dummy_dev(struct dummy_hcd *dum)  { -	return dummy_to_hcd(dum)->self.controller; +	return dummy_hcd_to_hcd(dum)->self.controller;  }  static inline struct device *udc_dev (struct dummy *dum) @@ -209,9 +229,13 @@ static inline struct dummy *ep_to_dummy (struct dummy_ep *ep)  	return container_of (ep->gadget, struct dummy, gadget);  } -static inline struct dummy *gadget_to_dummy (struct usb_gadget *gadget) +static inline struct dummy_hcd *gadget_to_dummy_hcd(struct usb_gadget *gadget)  { -	return container_of (gadget, struct dummy, gadget); +	struct dummy *dum = container_of(gadget, struct dummy, gadget); +	if (dum->gadget.speed == USB_SPEED_SUPER) +		return dum->ss_hcd; +	else +		return dum->hs_hcd;  }  static inline struct dummy *gadget_dev_to_dummy (struct device *dev) @@ -219,7 +243,7 @@ static inline struct dummy *gadget_dev_to_dummy (struct device *dev)  	return container_of (dev, struct dummy, gadget.dev);  } -static struct dummy			*the_controller; +static struct dummy			the_controller;  /*-------------------------------------------------------------------------*/ @@ -259,61 +283,122 @@ stop_activity (struct dummy *dum)  	/* driver now does any non-usb quiescing necessary */  } -/* caller must hold lock */ -static void -set_link_state (struct dummy *dum) -{ -	dum->active = 0; -	if ((dum->port_status & USB_PORT_STAT_POWER) == 0) -		dum->port_status = 0; - -	/* UDC suspend must cause a disconnect */ -	else if (!dum->pullup || dum->udc_suspended) { -		dum->port_status &= ~(USB_PORT_STAT_CONNECTION | -					USB_PORT_STAT_ENABLE | -					USB_PORT_STAT_LOW_SPEED | -					USB_PORT_STAT_HIGH_SPEED | -					USB_PORT_STAT_SUSPEND); -		if ((dum->old_status & USB_PORT_STAT_CONNECTION) != 0) -			dum->port_status |= (USB_PORT_STAT_C_CONNECTION << 16); +/** + * set_link_state_by_speed() - Sets the current state of the link according to + *	the hcd speed + * @dum_hcd: pointer to the dummy_hcd structure to update the link state for + * + * This function updates the port_status according to the link state and the + * speed of the hcd. + */ +static void set_link_state_by_speed(struct dummy_hcd *dum_hcd) +{ +	struct dummy *dum = dum_hcd->dum; + +	if (dummy_hcd_to_hcd(dum_hcd)->speed == HCD_USB3) { +		if ((dum_hcd->port_status & USB_SS_PORT_STAT_POWER) == 0) { +			dum_hcd->port_status = 0; +		} else if (!dum->pullup || dum->udc_suspended) { +			/* UDC suspend must cause a disconnect */ +			dum_hcd->port_status &= ~(USB_PORT_STAT_CONNECTION | +						USB_PORT_STAT_ENABLE); +			if ((dum_hcd->old_status & +			     USB_PORT_STAT_CONNECTION) != 0) +				dum_hcd->port_status |= +					(USB_PORT_STAT_C_CONNECTION << 16); +		} else { +			/* device is connected and not suspended */ +			dum_hcd->port_status |= (USB_PORT_STAT_CONNECTION | +						 USB_PORT_STAT_SPEED_5GBPS) ; +			if ((dum_hcd->old_status & +			     USB_PORT_STAT_CONNECTION) == 0) +				dum_hcd->port_status |= +					(USB_PORT_STAT_C_CONNECTION << 16); +			if ((dum_hcd->port_status & +			     USB_PORT_STAT_ENABLE) == 1 && +				(dum_hcd->port_status & +				 USB_SS_PORT_LS_U0) == 1 && +				dum_hcd->rh_state != DUMMY_RH_SUSPENDED) +				dum_hcd->active = 1; +		}  	} else { -		dum->port_status |= USB_PORT_STAT_CONNECTION; -		if ((dum->old_status & USB_PORT_STAT_CONNECTION) == 0) -			dum->port_status |= (USB_PORT_STAT_C_CONNECTION << 16); -		if ((dum->port_status & USB_PORT_STAT_ENABLE) == 0) -			dum->port_status &= ~USB_PORT_STAT_SUSPEND; -		else if ((dum->port_status & USB_PORT_STAT_SUSPEND) == 0 && -				dum->rh_state != DUMMY_RH_SUSPENDED) -			dum->active = 1; +		if ((dum_hcd->port_status & USB_PORT_STAT_POWER) == 0) { +			dum_hcd->port_status = 0; +		} else if (!dum->pullup || dum->udc_suspended) { +			/* UDC suspend must cause a disconnect */ +			dum_hcd->port_status &= ~(USB_PORT_STAT_CONNECTION | +						USB_PORT_STAT_ENABLE | +						USB_PORT_STAT_LOW_SPEED | +						USB_PORT_STAT_HIGH_SPEED | +						USB_PORT_STAT_SUSPEND); +			if ((dum_hcd->old_status & +			     USB_PORT_STAT_CONNECTION) != 0) +				dum_hcd->port_status |= +					(USB_PORT_STAT_C_CONNECTION << 16); +		} else { +			dum_hcd->port_status |= USB_PORT_STAT_CONNECTION; +			if ((dum_hcd->old_status & +			     USB_PORT_STAT_CONNECTION) == 0) +				dum_hcd->port_status |= +					(USB_PORT_STAT_C_CONNECTION << 16); +			if ((dum_hcd->port_status & USB_PORT_STAT_ENABLE) == 0) +				dum_hcd->port_status &= ~USB_PORT_STAT_SUSPEND; +			else if ((dum_hcd->port_status & +				  USB_PORT_STAT_SUSPEND) == 0 && +					dum_hcd->rh_state != DUMMY_RH_SUSPENDED) +				dum_hcd->active = 1; +		}  	} +} + +/* caller must hold lock */ +static void set_link_state(struct dummy_hcd *dum_hcd) +{ +	struct dummy *dum = dum_hcd->dum; -	if ((dum->port_status & USB_PORT_STAT_ENABLE) == 0 || dum->active) -		dum->resuming = 0; +	dum_hcd->active = 0; +	if (dum->pullup) +		if ((dummy_hcd_to_hcd(dum_hcd)->speed == HCD_USB3 && +		     dum->gadget.speed != USB_SPEED_SUPER) || +		    (dummy_hcd_to_hcd(dum_hcd)->speed != HCD_USB3 && +		     dum->gadget.speed == USB_SPEED_SUPER)) +			return; -	if ((dum->port_status & USB_PORT_STAT_CONNECTION) == 0 || -			(dum->port_status & USB_PORT_STAT_RESET) != 0) { -		if ((dum->old_status & USB_PORT_STAT_CONNECTION) != 0 && -				(dum->old_status & USB_PORT_STAT_RESET) == 0 && -				dum->driver) { -			stop_activity (dum); -			spin_unlock (&dum->lock); -			dum->driver->disconnect (&dum->gadget); -			spin_lock (&dum->lock); +	set_link_state_by_speed(dum_hcd); + +	if ((dum_hcd->port_status & USB_PORT_STAT_ENABLE) == 0 || +	     dum_hcd->active) +		dum_hcd->resuming = 0; + +	/* if !connected or reset */ +	if ((dum_hcd->port_status & USB_PORT_STAT_CONNECTION) == 0 || +			(dum_hcd->port_status & USB_PORT_STAT_RESET) != 0) { +		/* +		 * We're connected and not reset (reset occurred now), +		 * and driver attached - disconnect! +		 */ +		if ((dum_hcd->old_status & USB_PORT_STAT_CONNECTION) != 0 && +		    (dum_hcd->old_status & USB_PORT_STAT_RESET) == 0 && +		    dum->driver) { +			stop_activity(dum); +			spin_unlock(&dum->lock); +			dum->driver->disconnect(&dum->gadget); +			spin_lock(&dum->lock);  		} -	} else if (dum->active != dum->old_active) { -		if (dum->old_active && dum->driver->suspend) { -			spin_unlock (&dum->lock); -			dum->driver->suspend (&dum->gadget); -			spin_lock (&dum->lock); -		} else if (!dum->old_active && dum->driver->resume) { -			spin_unlock (&dum->lock); -			dum->driver->resume (&dum->gadget); -			spin_lock (&dum->lock); +	} else if (dum_hcd->active != dum_hcd->old_active) { +		if (dum_hcd->old_active && dum->driver->suspend) { +			spin_unlock(&dum->lock); +			dum->driver->suspend(&dum->gadget); +			spin_lock(&dum->lock); +		} else if (!dum_hcd->old_active &&  dum->driver->resume) { +			spin_unlock(&dum->lock); +			dum->driver->resume(&dum->gadget); +			spin_lock(&dum->lock);  		}  	} -	dum->old_status = dum->port_status; -	dum->old_active = dum->active; +	dum_hcd->old_status = dum_hcd->port_status; +	dum_hcd->old_active = dum_hcd->active;  }  /*-------------------------------------------------------------------------*/ @@ -332,6 +417,7 @@ static int  dummy_enable (struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)  {  	struct dummy		*dum; +	struct dummy_hcd	*dum_hcd;  	struct dummy_ep		*ep;  	unsigned		max;  	int			retval; @@ -341,9 +427,19 @@ dummy_enable (struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)  			|| desc->bDescriptorType != USB_DT_ENDPOINT)  		return -EINVAL;  	dum = ep_to_dummy (ep); -	if (!dum->driver || !is_enabled (dum)) +	if (!dum->driver) +		return -ESHUTDOWN; + +	dum_hcd = gadget_to_dummy_hcd(&dum->gadget); +	if (!is_enabled(dum_hcd))  		return -ESHUTDOWN; -	max = le16_to_cpu(desc->wMaxPacketSize) & 0x3ff; + +	/* +	 * For HS/FS devices only bits 0..10 of the wMaxPacketSize represent the +	 * maximum packet size. +	 * For SS devices the wMaxPacketSize is limited by 1024. +	 */ +	max = le16_to_cpu(desc->wMaxPacketSize) & 0x7ff;  	/* drivers must not request bad settings, since lower levels  	 * (hardware or its drivers) may not check.  some endpoints @@ -361,6 +457,10 @@ dummy_enable (struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)  			goto done;  		}  		switch (dum->gadget.speed) { +		case USB_SPEED_SUPER: +			if (max == 1024) +				break; +			goto done;  		case USB_SPEED_HIGH:  			if (max == 512)  				break; @@ -379,6 +479,7 @@ dummy_enable (struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)  			goto done;  		/* real hardware might not handle all packet sizes */  		switch (dum->gadget.speed) { +		case USB_SPEED_SUPER:  		case USB_SPEED_HIGH:  			if (max <= 1024)  				break; @@ -399,6 +500,7 @@ dummy_enable (struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)  			goto done;  		/* real hardware might not handle all packet sizes */  		switch (dum->gadget.speed) { +		case USB_SPEED_SUPER:  		case USB_SPEED_HIGH:  			if (max <= 1024)  				break; @@ -425,10 +527,18 @@ dummy_enable (struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)  		(desc->bEndpointAddress & USB_DIR_IN) ? "in" : "out",  		({ char *val;  		 switch (desc->bmAttributes & 0x03) { -		 case USB_ENDPOINT_XFER_BULK: val = "bulk"; break; -		 case USB_ENDPOINT_XFER_ISOC: val = "iso"; break; -		 case USB_ENDPOINT_XFER_INT: val = "intr"; break; -		 default: val = "ctrl"; break; +		 case USB_ENDPOINT_XFER_BULK: +			 val = "bulk"; +			 break; +		 case USB_ENDPOINT_XFER_ISOC: +			 val = "iso"; +			 break; +		 case USB_ENDPOINT_XFER_INT: +			 val = "intr"; +			 break; +		 default: +			 val = "ctrl"; +			 break;  		 }; val; }),  		max); @@ -507,6 +617,7 @@ dummy_queue (struct usb_ep *_ep, struct usb_request *_req,  	struct dummy_ep		*ep;  	struct dummy_request	*req;  	struct dummy		*dum; +	struct dummy_hcd	*dum_hcd;  	unsigned long		flags;  	req = usb_request_to_dummy_request (_req); @@ -518,7 +629,8 @@ dummy_queue (struct usb_ep *_ep, struct usb_request *_req,  		return -EINVAL;  	dum = ep_to_dummy (ep); -	if (!dum->driver || !is_enabled (dum)) +	dum_hcd = gadget_to_dummy_hcd(&dum->gadget); +	if (!dum->driver || !is_enabled(dum_hcd))  		return -ESHUTDOWN;  #if 0 @@ -662,24 +774,24 @@ static int dummy_g_get_frame (struct usb_gadget *_gadget)  static int dummy_wakeup (struct usb_gadget *_gadget)  { -	struct dummy	*dum; +	struct dummy_hcd *dum_hcd; -	dum = gadget_to_dummy (_gadget); -	if (!(dum->devstatus &	( (1 << USB_DEVICE_B_HNP_ENABLE) +	dum_hcd = gadget_to_dummy_hcd(_gadget); +	if (!(dum_hcd->dum->devstatus & ((1 << USB_DEVICE_B_HNP_ENABLE)  				| (1 << USB_DEVICE_REMOTE_WAKEUP))))  		return -EINVAL; -	if ((dum->port_status & USB_PORT_STAT_CONNECTION) == 0) +	if ((dum_hcd->port_status & USB_PORT_STAT_CONNECTION) == 0)  		return -ENOLINK; -	if ((dum->port_status & USB_PORT_STAT_SUSPEND) == 0 && -			 dum->rh_state != DUMMY_RH_SUSPENDED) +	if ((dum_hcd->port_status & USB_PORT_STAT_SUSPEND) == 0 && +			 dum_hcd->rh_state != DUMMY_RH_SUSPENDED)  		return -EIO;  	/* FIXME: What if the root hub is suspended but the port isn't? */  	/* hub notices our request, issues downstream resume, etc */ -	dum->resuming = 1; -	dum->re_timeout = jiffies + msecs_to_jiffies(20); -	mod_timer (&dummy_to_hcd (dum)->rh_timer, dum->re_timeout); +	dum_hcd->resuming = 1; +	dum_hcd->re_timeout = jiffies + msecs_to_jiffies(20); +	mod_timer(&dummy_hcd_to_hcd(dum_hcd)->rh_timer, dum_hcd->re_timeout);  	return 0;  } @@ -687,7 +799,7 @@ static int dummy_set_selfpowered (struct usb_gadget *_gadget, int value)  {  	struct dummy	*dum; -	dum = gadget_to_dummy (_gadget); +	dum = (gadget_to_dummy_hcd(_gadget))->dum;  	if (value)  		dum->devstatus |= (1 << USB_DEVICE_SELF_POWERED);  	else @@ -695,26 +807,68 @@ static int dummy_set_selfpowered (struct usb_gadget *_gadget, int value)  	return 0;  } +static void dummy_udc_udpate_ep0(struct dummy *dum) +{ +	u32 i; + +	if (dum->gadget.speed == USB_SPEED_SUPER) { +		for (i = 0; i < DUMMY_ENDPOINTS; i++) +			dum->ep[i].ep.max_streams = 0x10; +		dum->ep[0].ep.maxpacket = 9; +	} else { +		for (i = 0; i < DUMMY_ENDPOINTS; i++) +			dum->ep[i].ep.max_streams = 0; +		dum->ep[0].ep.maxpacket = 64; +	} +} +  static int dummy_pullup (struct usb_gadget *_gadget, int value)  { +	struct dummy_hcd *dum_hcd;  	struct dummy	*dum;  	unsigned long	flags; -	dum = gadget_to_dummy (_gadget); +	dum = gadget_dev_to_dummy(&_gadget->dev); + +	if (value && dum->driver) { +		if (mod_data.is_super_speed) +			dum->gadget.speed = dum->driver->speed; +		else if (mod_data.is_high_speed) +			dum->gadget.speed = min_t(u8, USB_SPEED_HIGH, +					dum->driver->speed); +		else +			dum->gadget.speed = USB_SPEED_FULL; +		dummy_udc_udpate_ep0(dum); + +		if (dum->gadget.speed < dum->driver->speed) +			dev_dbg(udc_dev(dum), "This device can perform faster" +					" if you connect it to a %s port...\n", +					(dum->driver->speed == USB_SPEED_SUPER ? +					 "SuperSpeed" : "HighSpeed")); +	} +	dum_hcd = gadget_to_dummy_hcd(_gadget); +  	spin_lock_irqsave (&dum->lock, flags);  	dum->pullup = (value != 0); -	set_link_state (dum); +	set_link_state(dum_hcd);  	spin_unlock_irqrestore (&dum->lock, flags); -	usb_hcd_poll_rh_status (dummy_to_hcd (dum)); +	usb_hcd_poll_rh_status(dummy_hcd_to_hcd(dum_hcd));  	return 0;  } +static int dummy_udc_start(struct usb_gadget *g, +		struct usb_gadget_driver *driver); +static int dummy_udc_stop(struct usb_gadget *g, +		struct usb_gadget_driver *driver); +  static const struct usb_gadget_ops dummy_ops = {  	.get_frame	= dummy_g_get_frame,  	.wakeup		= dummy_wakeup,  	.set_selfpowered = dummy_set_selfpowered,  	.pullup		= dummy_pullup, +	.udc_start	= dummy_udc_start, +	.udc_stop	= dummy_udc_stop,  };  /*-------------------------------------------------------------------------*/ @@ -747,18 +901,13 @@ static DEVICE_ATTR (function, S_IRUGO, show_function, NULL);   * for each driver that registers:  just add to a big root hub.   */ -int -usb_gadget_probe_driver(struct usb_gadget_driver *driver, -		int (*bind)(struct usb_gadget *)) +static int dummy_udc_start(struct usb_gadget *g, +		struct usb_gadget_driver *driver)  { -	struct dummy	*dum = the_controller; -	int		retval, i; +	struct dummy_hcd	*dum_hcd = gadget_to_dummy_hcd(g); +	struct dummy		*dum = dum_hcd->dum; -	if (!dum) -		return -EINVAL; -	if (dum->driver) -		return -EBUSY; -	if (!bind || !driver->setup || driver->speed == USB_SPEED_UNKNOWN) +	if (driver->speed == USB_SPEED_UNKNOWN)  		return -EINVAL;  	/* @@ -768,121 +917,77 @@ usb_gadget_probe_driver(struct usb_gadget_driver *driver,  	dum->devstatus = 0; -	INIT_LIST_HEAD (&dum->gadget.ep_list); -	for (i = 0; i < DUMMY_ENDPOINTS; i++) { -		struct dummy_ep	*ep = &dum->ep [i]; - -		if (!ep_name [i]) -			break; -		ep->ep.name = ep_name [i]; -		ep->ep.ops = &dummy_ep_ops; -		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; -		ep->last_io = jiffies; -		ep->gadget = &dum->gadget; -		ep->desc = NULL; -		INIT_LIST_HEAD (&ep->queue); -	} - -	dum->gadget.ep0 = &dum->ep [0].ep; -	dum->ep [0].ep.maxpacket = 64; -	list_del_init (&dum->ep [0].ep.ep_list); -	INIT_LIST_HEAD(&dum->fifo_req.queue); - -	driver->driver.bus = NULL;  	dum->driver = driver; -	dum->gadget.dev.driver = &driver->driver;  	dev_dbg (udc_dev(dum), "binding gadget driver '%s'\n",  			driver->driver.name); -	retval = bind(&dum->gadget); -	if (retval) { -		dum->driver = NULL; -		dum->gadget.dev.driver = NULL; -		return retval; -	} - -	/* khubd will enumerate this in a while */ -	spin_lock_irq (&dum->lock); -	dum->pullup = 1; -	set_link_state (dum); -	spin_unlock_irq (&dum->lock); - -	usb_hcd_poll_rh_status (dummy_to_hcd (dum));  	return 0;  } -EXPORT_SYMBOL(usb_gadget_probe_driver); -int -usb_gadget_unregister_driver (struct usb_gadget_driver *driver) +static int dummy_udc_stop(struct usb_gadget *g, +		struct usb_gadget_driver *driver)  { -	struct dummy	*dum = the_controller; -	unsigned long	flags; - -	if (!dum) -		return -ENODEV; -	if (!driver || driver != dum->driver || !driver->unbind) -		return -EINVAL; +	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); -	spin_lock_irqsave (&dum->lock, flags); -	dum->pullup = 0; -	set_link_state (dum); -	spin_unlock_irqrestore (&dum->lock, flags); - -	driver->unbind (&dum->gadget); -	dum->gadget.dev.driver = NULL;  	dum->driver = NULL; -	spin_lock_irqsave (&dum->lock, flags); -	dum->pullup = 0; -	set_link_state (dum); -	spin_unlock_irqrestore (&dum->lock, flags); - -	usb_hcd_poll_rh_status (dummy_to_hcd (dum)); +	dummy_pullup(&dum->gadget, 0);  	return 0;  } -EXPORT_SYMBOL (usb_gadget_unregister_driver);  #undef is_enabled -/* just declare this in any driver that really need it */ -extern int net2280_set_fifo_mode (struct usb_gadget *gadget, int mode); - -int net2280_set_fifo_mode (struct usb_gadget *gadget, int mode) -{ -	return -ENOSYS; -} -EXPORT_SYMBOL (net2280_set_fifo_mode); - -  /* The gadget structure is stored inside the hcd structure and will be   * released along with it. */  static void  dummy_gadget_release (struct device *dev)  { -	struct dummy	*dum = gadget_dev_to_dummy (dev); +	return; +} + +static void init_dummy_udc_hw(struct dummy *dum) +{ +	int i; + +	INIT_LIST_HEAD(&dum->gadget.ep_list); +	for (i = 0; i < DUMMY_ENDPOINTS; i++) { +		struct dummy_ep	*ep = &dum->ep[i]; + +		if (!ep_name[i]) +			break; +		ep->ep.name = ep_name[i]; +		ep->ep.ops = &dummy_ep_ops; +		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; +		ep->last_io = jiffies; +		ep->gadget = &dum->gadget; +		ep->desc = NULL; +		INIT_LIST_HEAD(&ep->queue); +	} + +	dum->gadget.ep0 = &dum->ep[0].ep; +	list_del_init(&dum->ep[0].ep.ep_list); +	INIT_LIST_HEAD(&dum->fifo_req.queue); -	usb_put_hcd (dummy_to_hcd (dum)); +#ifdef CONFIG_USB_OTG +	dum->gadget.is_otg = 1; +#endif  }  static int dummy_udc_probe (struct platform_device *pdev)  { -	struct dummy	*dum = the_controller; +	struct dummy	*dum = &the_controller;  	int		rc; -	usb_get_hcd(dummy_to_hcd(dum)); -  	dum->gadget.name = gadget_name;  	dum->gadget.ops = &dummy_ops;  	dum->gadget.is_dualspeed = 1; -	/* maybe claim OTG support, though we won't complete HNP */ -	dum->gadget.is_otg = (dummy_to_hcd(dum)->self.otg_port != 0); -  	dev_set_name(&dum->gadget.dev, "gadget");  	dum->gadget.dev.parent = &pdev->dev;  	dum->gadget.dev.release = dummy_gadget_release; @@ -892,11 +997,22 @@ static int dummy_udc_probe (struct platform_device *pdev)  		return rc;  	} +	init_dummy_udc_hw(dum); + +	rc = usb_add_gadget_udc(&pdev->dev, &dum->gadget); +	if (rc < 0) +		goto err_udc; +  	rc = device_create_file (&dum->gadget.dev, &dev_attr_function);  	if (rc < 0) -		device_unregister (&dum->gadget.dev); -	else -		platform_set_drvdata(pdev, dum); +		goto err_dev; +	platform_set_drvdata(pdev, dum); +	return rc; + +err_dev: +	usb_del_gadget_udc(&dum->gadget); +err_udc: +	device_unregister(&dum->gadget.dev);  	return rc;  } @@ -904,37 +1020,41 @@ static int dummy_udc_remove (struct platform_device *pdev)  {  	struct dummy	*dum = platform_get_drvdata (pdev); +	usb_del_gadget_udc(&dum->gadget);  	platform_set_drvdata (pdev, NULL);  	device_remove_file (&dum->gadget.dev, &dev_attr_function);  	device_unregister (&dum->gadget.dev);  	return 0;  } -static int dummy_udc_suspend (struct platform_device *pdev, pm_message_t state) +static void dummy_udc_pm(struct dummy *dum, struct dummy_hcd *dum_hcd, +		int suspend)  { -	struct dummy	*dum = platform_get_drvdata(pdev); +	spin_lock_irq(&dum->lock); +	dum->udc_suspended = suspend; +	set_link_state(dum_hcd); +	spin_unlock_irq(&dum->lock); +} -	dev_dbg (&pdev->dev, "%s\n", __func__); -	spin_lock_irq (&dum->lock); -	dum->udc_suspended = 1; -	set_link_state (dum); -	spin_unlock_irq (&dum->lock); +static int dummy_udc_suspend(struct platform_device *pdev, pm_message_t state) +{ +	struct dummy		*dum = platform_get_drvdata(pdev); +	struct dummy_hcd	*dum_hcd = gadget_to_dummy_hcd(&dum->gadget); -	usb_hcd_poll_rh_status (dummy_to_hcd (dum)); +	dev_dbg(&pdev->dev, "%s\n", __func__); +	dummy_udc_pm(dum, dum_hcd, 1); +	usb_hcd_poll_rh_status(dummy_hcd_to_hcd(dum_hcd));  	return 0;  } -static int dummy_udc_resume (struct platform_device *pdev) +static int dummy_udc_resume(struct platform_device *pdev)  { -	struct dummy	*dum = platform_get_drvdata(pdev); +	struct dummy		*dum = platform_get_drvdata(pdev); +	struct dummy_hcd	*dum_hcd = gadget_to_dummy_hcd(&dum->gadget); -	dev_dbg (&pdev->dev, "%s\n", __func__); -	spin_lock_irq (&dum->lock); -	dum->udc_suspended = 0; -	set_link_state (dum); -	spin_unlock_irq (&dum->lock); - -	usb_hcd_poll_rh_status (dummy_to_hcd (dum)); +	dev_dbg(&pdev->dev, "%s\n", __func__); +	dummy_udc_pm(dum, dum_hcd, 0); +	usb_hcd_poll_rh_status(dummy_hcd_to_hcd(dum_hcd));  	return 0;  } @@ -968,7 +1088,7 @@ static int dummy_urb_enqueue (  	struct urb			*urb,  	gfp_t				mem_flags  ) { -	struct dummy	*dum; +	struct dummy_hcd *dum_hcd;  	struct urbp	*urbp;  	unsigned long	flags;  	int		rc; @@ -981,51 +1101,51 @@ static int dummy_urb_enqueue (  		return -ENOMEM;  	urbp->urb = urb; -	dum = hcd_to_dummy (hcd); -	spin_lock_irqsave (&dum->lock, flags); +	dum_hcd = hcd_to_dummy_hcd(hcd); +	spin_lock_irqsave(&dum_hcd->dum->lock, flags);  	rc = usb_hcd_link_urb_to_ep(hcd, urb);  	if (rc) {  		kfree(urbp);  		goto done;  	} -	if (!dum->udev) { -		dum->udev = urb->dev; -		usb_get_dev (dum->udev); -	} else if (unlikely (dum->udev != urb->dev)) -		dev_err (dummy_dev(dum), "usb_device address has changed!\n"); +	if (!dum_hcd->udev) { +		dum_hcd->udev = urb->dev; +		usb_get_dev(dum_hcd->udev); +	} else if (unlikely(dum_hcd->udev != urb->dev)) +		dev_err(dummy_dev(dum_hcd), "usb_device address has changed!\n"); -	list_add_tail (&urbp->urbp_list, &dum->urbp_list); +	list_add_tail(&urbp->urbp_list, &dum_hcd->urbp_list);  	urb->hcpriv = urbp;  	if (usb_pipetype (urb->pipe) == PIPE_CONTROL)  		urb->error_count = 1;		/* mark as a new urb */  	/* kick the scheduler, it'll do the rest */ -	if (!timer_pending (&dum->timer)) -		mod_timer (&dum->timer, jiffies + 1); +	if (!timer_pending(&dum_hcd->timer)) +		mod_timer(&dum_hcd->timer, jiffies + 1);   done: -	spin_unlock_irqrestore(&dum->lock, flags); +	spin_unlock_irqrestore(&dum_hcd->dum->lock, flags);  	return rc;  }  static int dummy_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)  { -	struct dummy	*dum; +	struct dummy_hcd *dum_hcd;  	unsigned long	flags;  	int		rc;  	/* giveback happens automatically in timer callback,  	 * so make sure the callback happens */ -	dum = hcd_to_dummy (hcd); -	spin_lock_irqsave (&dum->lock, flags); +	dum_hcd = hcd_to_dummy_hcd(hcd); +	spin_lock_irqsave(&dum_hcd->dum->lock, flags);  	rc = usb_hcd_check_unlink_urb(hcd, urb, status); -	if (!rc && dum->rh_state != DUMMY_RH_RUNNING && -			!list_empty(&dum->urbp_list)) -		mod_timer (&dum->timer, jiffies); +	if (!rc && dum_hcd->rh_state != DUMMY_RH_RUNNING && +			!list_empty(&dum_hcd->urbp_list)) +		mod_timer(&dum_hcd->timer, jiffies); -	spin_unlock_irqrestore (&dum->lock, flags); +	spin_unlock_irqrestore(&dum_hcd->dum->lock, flags);  	return rc;  } @@ -1162,10 +1282,25 @@ static int periodic_bytes (struct dummy *dum, struct dummy_ep *ep)  		tmp *= 8 /* applies to entire frame */;  		limit += limit * tmp;  	} +	if (dum->gadget.speed == USB_SPEED_SUPER) { +		switch (ep->desc->bmAttributes & 0x03) { +		case USB_ENDPOINT_XFER_ISOC: +			/* Sec. 4.4.8.2 USB3.0 Spec */ +			limit = 3 * 16 * 1024 * 8; +			break; +		case USB_ENDPOINT_XFER_INT: +			/* Sec. 4.4.7.2 USB3.0 Spec */ +			limit = 3 * 1024 * 8; +			break; +		case USB_ENDPOINT_XFER_BULK: +		default: +			break; +		} +	}  	return limit;  } -#define is_active(dum)	((dum->port_status & \ +#define is_active(dum_hcd)	((dum_hcd->port_status & \  		(USB_PORT_STAT_CONNECTION | USB_PORT_STAT_ENABLE | \  			USB_PORT_STAT_SUSPEND)) \  		== (USB_PORT_STAT_CONNECTION | USB_PORT_STAT_ENABLE)) @@ -1174,7 +1309,8 @@ static struct dummy_ep *find_endpoint (struct dummy *dum, u8 address)  {  	int		i; -	if (!is_active (dum)) +	if (!is_active((dum->gadget.speed == USB_SPEED_SUPER ? +			dum->ss_hcd : dum->hs_hcd)))  		return NULL;  	if ((address & ~USB_DIR_IN) == 0)  		return &dum->ep [0]; @@ -1211,11 +1347,12 @@ static struct dummy_ep *find_endpoint (struct dummy *dum, u8 address)   *	  1 - if the request wasn't handles   *	  error code on error   */ -static int handle_control_request(struct dummy *dum, struct urb *urb, +static int handle_control_request(struct dummy_hcd *dum_hcd, struct urb *urb,  				  struct usb_ctrlrequest *setup,  				  int *status)  {  	struct dummy_ep		*ep2; +	struct dummy		*dum = dum_hcd->dum;  	int			ret_val = 1;  	unsigned	w_index;  	unsigned	w_value; @@ -1247,6 +1384,27 @@ static int handle_control_request(struct dummy *dum, struct urb *urb,  			case USB_DEVICE_A_ALT_HNP_SUPPORT:  				dum->gadget.a_alt_hnp_support = 1;  				break; +			case USB_DEVICE_U1_ENABLE: +				if (dummy_hcd_to_hcd(dum_hcd)->speed == +				    HCD_USB3) +					w_value = USB_DEV_STAT_U1_ENABLED; +				else +					ret_val = -EOPNOTSUPP; +				break; +			case USB_DEVICE_U2_ENABLE: +				if (dummy_hcd_to_hcd(dum_hcd)->speed == +				    HCD_USB3) +					w_value = USB_DEV_STAT_U2_ENABLED; +				else +					ret_val = -EOPNOTSUPP; +				break; +			case USB_DEVICE_LTM_ENABLE: +				if (dummy_hcd_to_hcd(dum_hcd)->speed == +				    HCD_USB3) +					w_value = USB_DEV_STAT_LTM_ENABLED; +				else +					ret_val = -EOPNOTSUPP; +				break;  			default:  				ret_val = -EOPNOTSUPP;  			} @@ -1273,6 +1431,27 @@ static int handle_control_request(struct dummy *dum, struct urb *urb,  			case USB_DEVICE_REMOTE_WAKEUP:  				w_value = USB_DEVICE_REMOTE_WAKEUP;  				break; +			case USB_DEVICE_U1_ENABLE: +				if (dummy_hcd_to_hcd(dum_hcd)->speed == +				    HCD_USB3) +					w_value = USB_DEV_STAT_U1_ENABLED; +				else +					ret_val = -EOPNOTSUPP; +				break; +			case USB_DEVICE_U2_ENABLE: +				if (dummy_hcd_to_hcd(dum_hcd)->speed == +				    HCD_USB3) +					w_value = USB_DEV_STAT_U2_ENABLED; +				else +					ret_val = -EOPNOTSUPP; +				break; +			case USB_DEVICE_LTM_ENABLE: +				if (dummy_hcd_to_hcd(dum_hcd)->speed == +				    HCD_USB3) +					w_value = USB_DEV_STAT_LTM_ENABLED; +				else +					ret_val = -EOPNOTSUPP; +				break;  			default:  				ret_val = -EOPNOTSUPP;  				break; @@ -1334,9 +1513,10 @@ static int handle_control_request(struct dummy *dum, struct urb *urb,  /* drive both sides of the transfers; looks like irq handlers to   * both drivers except the callbacks aren't in_irq().   */ -static void dummy_timer (unsigned long _dum) +static void dummy_timer(unsigned long _dum_hcd)  { -	struct dummy		*dum = (struct dummy *) _dum; +	struct dummy_hcd	*dum_hcd = (struct dummy_hcd *) _dum_hcd; +	struct dummy		*dum = dum_hcd->dum;  	struct urbp		*urbp, *tmp;  	unsigned long		flags;  	int			limit, total; @@ -1353,8 +1533,12 @@ static void dummy_timer (unsigned long _dum)  	case USB_SPEED_HIGH:  		total = 512/*bytes*/ * 13/*packets*/ * 8/*uframes*/;  		break; +	case USB_SPEED_SUPER: +		/* Bus speed is 500000 bytes/ms, so use a little less */ +		total = 490000; +		break;  	default: -		dev_err (dummy_dev(dum), "bogus device speed\n"); +		dev_err(dummy_dev(dum_hcd), "bogus device speed\n");  		return;  	} @@ -1363,8 +1547,8 @@ static void dummy_timer (unsigned long _dum)  	/* look at each urb queued by the host side driver */  	spin_lock_irqsave (&dum->lock, flags); -	if (!dum->udev) { -		dev_err (dummy_dev(dum), +	if (!dum_hcd->udev) { +		dev_err(dummy_dev(dum_hcd),  				"timer fired with no URBs pending?\n");  		spin_unlock_irqrestore (&dum->lock, flags);  		return; @@ -1377,7 +1561,7 @@ static void dummy_timer (unsigned long _dum)  	}  restart: -	list_for_each_entry_safe (urbp, tmp, &dum->urbp_list, urbp_list) { +	list_for_each_entry_safe(urbp, tmp, &dum_hcd->urbp_list, urbp_list) {  		struct urb		*urb;  		struct dummy_request	*req;  		u8			address; @@ -1388,7 +1572,7 @@ restart:  		urb = urbp->urb;  		if (urb->unlinked)  			goto return_urb; -		else if (dum->rh_state != DUMMY_RH_RUNNING) +		else if (dum_hcd->rh_state != DUMMY_RH_RUNNING)  			continue;  		type = usb_pipetype (urb->pipe); @@ -1406,7 +1590,7 @@ restart:  		ep = find_endpoint(dum, address);  		if (!ep) {  			/* set_configuration() disagreement */ -			dev_dbg (dummy_dev(dum), +			dev_dbg(dummy_dev(dum_hcd),  				"no ep configured for urb %p\n",  				urb);  			status = -EPROTO; @@ -1422,7 +1606,7 @@ restart:  		}  		if (ep->halted && !ep->setup_stage) {  			/* NOTE: must not be iso! */ -			dev_dbg (dummy_dev(dum), "ep %s halted, urb %p\n", +			dev_dbg(dummy_dev(dum_hcd), "ep %s halted, urb %p\n",  					ep->ep.name, urb);  			status = -EPIPE;  			goto return_urb; @@ -1457,7 +1641,7 @@ restart:  			ep->setup_stage = 0;  			ep->halted = 0; -			value = handle_control_request(dum, urb, &setup, +			value = handle_control_request(dum_hcd, urb, &setup,  						       &status);  			/* gadget driver handles all other requests.  block @@ -1527,20 +1711,20 @@ return_urb:  		if (ep)  			ep->already_seen = ep->setup_stage = 0; -		usb_hcd_unlink_urb_from_ep(dummy_to_hcd(dum), urb); +		usb_hcd_unlink_urb_from_ep(dummy_hcd_to_hcd(dum_hcd), urb);  		spin_unlock (&dum->lock); -		usb_hcd_giveback_urb(dummy_to_hcd(dum), urb, status); +		usb_hcd_giveback_urb(dummy_hcd_to_hcd(dum_hcd), urb, status);  		spin_lock (&dum->lock);  		goto restart;  	} -	if (list_empty (&dum->urbp_list)) { -		usb_put_dev (dum->udev); -		dum->udev = NULL; -	} else if (dum->rh_state == DUMMY_RH_RUNNING) { +	if (list_empty(&dum_hcd->urbp_list)) { +		usb_put_dev(dum_hcd->udev); +		dum_hcd->udev = NULL; +	} else if (dum_hcd->rh_state == DUMMY_RH_RUNNING) {  		/* want a 1 msec delay here */ -		mod_timer (&dum->timer, jiffies + msecs_to_jiffies(1)); +		mod_timer(&dum_hcd->timer, jiffies + msecs_to_jiffies(1));  	}  	spin_unlock_irqrestore (&dum->lock, flags); @@ -1557,36 +1741,48 @@ return_urb:  static int dummy_hub_status (struct usb_hcd *hcd, char *buf)  { -	struct dummy		*dum; +	struct dummy_hcd	*dum_hcd;  	unsigned long		flags;  	int			retval = 0; -	dum = hcd_to_dummy (hcd); +	dum_hcd = hcd_to_dummy_hcd(hcd); -	spin_lock_irqsave (&dum->lock, flags); +	spin_lock_irqsave(&dum_hcd->dum->lock, flags);  	if (!HCD_HW_ACCESSIBLE(hcd))  		goto done; -	if (dum->resuming && time_after_eq (jiffies, dum->re_timeout)) { -		dum->port_status |= (USB_PORT_STAT_C_SUSPEND << 16); -		dum->port_status &= ~USB_PORT_STAT_SUSPEND; -		set_link_state (dum); +	if (dum_hcd->resuming && time_after_eq(jiffies, dum_hcd->re_timeout)) { +		dum_hcd->port_status |= (USB_PORT_STAT_C_SUSPEND << 16); +		dum_hcd->port_status &= ~USB_PORT_STAT_SUSPEND; +		set_link_state(dum_hcd);  	} -	if ((dum->port_status & PORT_C_MASK) != 0) { +	if ((dum_hcd->port_status & PORT_C_MASK) != 0) {  		*buf = (1 << 1); -		dev_dbg (dummy_dev(dum), "port status 0x%08x has changes\n", -				dum->port_status); +		dev_dbg(dummy_dev(dum_hcd), "port status 0x%08x has changes\n", +				dum_hcd->port_status);  		retval = 1; -		if (dum->rh_state == DUMMY_RH_SUSPENDED) +		if (dum_hcd->rh_state == DUMMY_RH_SUSPENDED)  			usb_hcd_resume_root_hub (hcd);  	}  done: -	spin_unlock_irqrestore (&dum->lock, flags); +	spin_unlock_irqrestore(&dum_hcd->dum->lock, flags);  	return retval;  }  static inline void +ss_hub_descriptor(struct usb_hub_descriptor *desc) +{ +	memset(desc, 0, sizeof *desc); +	desc->bDescriptorType = 0x2a; +	desc->bDescLength = 12; +	desc->wHubCharacteristics = cpu_to_le16(0x0001); +	desc->bNbrPorts = 1; +	desc->u.ss.bHubHdrDecLat = 0x04; /* Worst case: 0.4 micro sec*/ +	desc->u.ss.DeviceRemovable = 0xffff; +} + +static inline void  hub_descriptor (struct usb_hub_descriptor *desc)  {  	memset (desc, 0, sizeof *desc); @@ -1606,39 +1802,64 @@ static int dummy_hub_control (  	char		*buf,  	u16		wLength  ) { -	struct dummy	*dum; +	struct dummy_hcd *dum_hcd;  	int		retval = 0;  	unsigned long	flags;  	if (!HCD_HW_ACCESSIBLE(hcd))  		return -ETIMEDOUT; -	dum = hcd_to_dummy (hcd); -	spin_lock_irqsave (&dum->lock, flags); +	dum_hcd = hcd_to_dummy_hcd(hcd); + +	spin_lock_irqsave(&dum_hcd->dum->lock, flags);  	switch (typeReq) {  	case ClearHubFeature:  		break;  	case ClearPortFeature:  		switch (wValue) {  		case USB_PORT_FEAT_SUSPEND: -			if (dum->port_status & USB_PORT_STAT_SUSPEND) { +			if (hcd->speed == HCD_USB3) { +				dev_dbg(dummy_dev(dum_hcd), +					 "USB_PORT_FEAT_SUSPEND req not " +					 "supported for USB 3.0 roothub\n"); +				goto error; +			} +			if (dum_hcd->port_status & USB_PORT_STAT_SUSPEND) {  				/* 20msec resume signaling */ -				dum->resuming = 1; -				dum->re_timeout = jiffies + +				dum_hcd->resuming = 1; +				dum_hcd->re_timeout = jiffies +  						msecs_to_jiffies(20);  			}  			break;  		case USB_PORT_FEAT_POWER: -			if (dum->port_status & USB_PORT_STAT_POWER) -				dev_dbg (dummy_dev(dum), "power-off\n"); +			if (hcd->speed == HCD_USB3) { +				if (dum_hcd->port_status & USB_PORT_STAT_POWER) +					dev_dbg(dummy_dev(dum_hcd), +						"power-off\n"); +			} else +				if (dum_hcd->port_status & +							USB_SS_PORT_STAT_POWER) +					dev_dbg(dummy_dev(dum_hcd), +						"power-off\n");  			/* FALLS THROUGH */  		default: -			dum->port_status &= ~(1 << wValue); -			set_link_state (dum); +			dum_hcd->port_status &= ~(1 << wValue); +			set_link_state(dum_hcd);  		}  		break;  	case GetHubDescriptor: -		hub_descriptor ((struct usb_hub_descriptor *) buf); +		if (hcd->speed == HCD_USB3 && +				(wLength < USB_DT_SS_HUB_SIZE || +				 wValue != (USB_DT_SS_HUB << 8))) { +			dev_dbg(dummy_dev(dum_hcd), +				"Wrong hub descriptor type for " +				"USB 3.0 roothub.\n"); +			goto error; +		} +		if (hcd->speed == HCD_USB3) +			ss_hub_descriptor((struct usb_hub_descriptor *) buf); +		else +			hub_descriptor((struct usb_hub_descriptor *) buf);  		break;  	case GetHubStatus:  		*(__le32 *) buf = cpu_to_le32 (0); @@ -1650,127 +1871,210 @@ static int dummy_hub_control (  		/* whoever resets or resumes must GetPortStatus to  		 * complete it!!  		 */ -		if (dum->resuming && -				time_after_eq (jiffies, dum->re_timeout)) { -			dum->port_status |= (USB_PORT_STAT_C_SUSPEND << 16); -			dum->port_status &= ~USB_PORT_STAT_SUSPEND; +		if (dum_hcd->resuming && +				time_after_eq(jiffies, dum_hcd->re_timeout)) { +			dum_hcd->port_status |= (USB_PORT_STAT_C_SUSPEND << 16); +			dum_hcd->port_status &= ~USB_PORT_STAT_SUSPEND;  		} -		if ((dum->port_status & USB_PORT_STAT_RESET) != 0 && -				time_after_eq (jiffies, dum->re_timeout)) { -			dum->port_status |= (USB_PORT_STAT_C_RESET << 16); -			dum->port_status &= ~USB_PORT_STAT_RESET; -			if (dum->pullup) { -				dum->port_status |= USB_PORT_STAT_ENABLE; -				/* give it the best speed we agree on */ -				dum->gadget.speed = dum->driver->speed; -				dum->gadget.ep0->maxpacket = 64; -				switch (dum->gadget.speed) { -				case USB_SPEED_HIGH: -					dum->port_status |= -						USB_PORT_STAT_HIGH_SPEED; -					break; -				case USB_SPEED_LOW: -					dum->gadget.ep0->maxpacket = 8; -					dum->port_status |= -						USB_PORT_STAT_LOW_SPEED; -					break; -				default: -					dum->gadget.speed = USB_SPEED_FULL; -					break; +		if ((dum_hcd->port_status & USB_PORT_STAT_RESET) != 0 && +				time_after_eq(jiffies, dum_hcd->re_timeout)) { +			dum_hcd->port_status |= (USB_PORT_STAT_C_RESET << 16); +			dum_hcd->port_status &= ~USB_PORT_STAT_RESET; +			if (dum_hcd->dum->pullup) { +				dum_hcd->port_status |= USB_PORT_STAT_ENABLE; + +				if (hcd->speed < HCD_USB3) { +					switch (dum_hcd->dum->gadget.speed) { +					case USB_SPEED_HIGH: +						dum_hcd->port_status |= +						      USB_PORT_STAT_HIGH_SPEED; +						break; +					case USB_SPEED_LOW: +						dum_hcd->dum->gadget.ep0-> +							maxpacket = 8; +						dum_hcd->port_status |= +							USB_PORT_STAT_LOW_SPEED; +						break; +					default: +						dum_hcd->dum->gadget.speed = +							USB_SPEED_FULL; +						break; +					}  				}  			}  		} -		set_link_state (dum); -		((__le16 *) buf)[0] = cpu_to_le16 (dum->port_status); -		((__le16 *) buf)[1] = cpu_to_le16 (dum->port_status >> 16); +		set_link_state(dum_hcd); +		((__le16 *) buf)[0] = cpu_to_le16 (dum_hcd->port_status); +		((__le16 *) buf)[1] = cpu_to_le16 (dum_hcd->port_status >> 16);  		break;  	case SetHubFeature:  		retval = -EPIPE;  		break;  	case SetPortFeature:  		switch (wValue) { +		case USB_PORT_FEAT_LINK_STATE: +			if (hcd->speed != HCD_USB3) { +				dev_dbg(dummy_dev(dum_hcd), +					 "USB_PORT_FEAT_LINK_STATE req not " +					 "supported for USB 2.0 roothub\n"); +				goto error; +			} +			/* +			 * Since this is dummy we don't have an actual link so +			 * there is nothing to do for the SET_LINK_STATE cmd +			 */ +			break; +		case USB_PORT_FEAT_U1_TIMEOUT: +		case USB_PORT_FEAT_U2_TIMEOUT: +			/* TODO: add suspend/resume support! */ +			if (hcd->speed != HCD_USB3) { +				dev_dbg(dummy_dev(dum_hcd), +					 "USB_PORT_FEAT_U1/2_TIMEOUT req not " +					 "supported for USB 2.0 roothub\n"); +				goto error; +			} +			break;  		case USB_PORT_FEAT_SUSPEND: -			if (dum->active) { -				dum->port_status |= USB_PORT_STAT_SUSPEND; +			/* Applicable only for USB2.0 hub */ +			if (hcd->speed == HCD_USB3) { +				dev_dbg(dummy_dev(dum_hcd), +					 "USB_PORT_FEAT_SUSPEND req not " +					 "supported for USB 3.0 roothub\n"); +				goto error; +			} +			if (dum_hcd->active) { +				dum_hcd->port_status |= USB_PORT_STAT_SUSPEND;  				/* HNP would happen here; for now we  				 * assume b_bus_req is always true.  				 */ -				set_link_state (dum); +				set_link_state(dum_hcd);  				if (((1 << USB_DEVICE_B_HNP_ENABLE) -						& dum->devstatus) != 0) -					dev_dbg (dummy_dev(dum), +						& dum_hcd->dum->devstatus) != 0) +					dev_dbg(dummy_dev(dum_hcd),  							"no HNP yet!\n");  			}  			break;  		case USB_PORT_FEAT_POWER: -			dum->port_status |= USB_PORT_STAT_POWER; -			set_link_state (dum); +			if (hcd->speed == HCD_USB3) +				dum_hcd->port_status |= USB_SS_PORT_STAT_POWER; +			else +				dum_hcd->port_status |= USB_PORT_STAT_POWER; +			set_link_state(dum_hcd);  			break; +		case USB_PORT_FEAT_BH_PORT_RESET: +			/* Applicable only for USB3.0 hub */ +			if (hcd->speed != HCD_USB3) { +				dev_dbg(dummy_dev(dum_hcd), +					 "USB_PORT_FEAT_BH_PORT_RESET req not " +					 "supported for USB 2.0 roothub\n"); +				goto error; +			} +			/* FALLS THROUGH */  		case USB_PORT_FEAT_RESET:  			/* if it's already enabled, disable */ -			dum->port_status &= ~(USB_PORT_STAT_ENABLE +			if (hcd->speed == HCD_USB3) { +				dum_hcd->port_status = 0; +				dum_hcd->port_status = +					(USB_SS_PORT_STAT_POWER | +					 USB_PORT_STAT_CONNECTION | +					 USB_PORT_STAT_RESET); +			} else +				dum_hcd->port_status &= ~(USB_PORT_STAT_ENABLE  					| USB_PORT_STAT_LOW_SPEED  					| USB_PORT_STAT_HIGH_SPEED); -			dum->devstatus = 0; -			/* 50msec reset signaling */ -			dum->re_timeout = jiffies + msecs_to_jiffies(50); +			/* +			 * We want to reset device status. All but the +			 * Self powered feature +			 */ +			dum_hcd->dum->devstatus &= +				(1 << USB_DEVICE_SELF_POWERED); +			/* +			 * FIXME USB3.0: what is the correct reset signaling +			 * interval? Is it still 50msec as for HS? +			 */ +			dum_hcd->re_timeout = jiffies + msecs_to_jiffies(50);  			/* FALLS THROUGH */  		default: -			if ((dum->port_status & USB_PORT_STAT_POWER) != 0) { -				dum->port_status |= (1 << wValue); -				set_link_state (dum); -			} +			if (hcd->speed == HCD_USB3) { +				if ((dum_hcd->port_status & +				     USB_SS_PORT_STAT_POWER) != 0) { +					dum_hcd->port_status |= (1 << wValue); +					set_link_state(dum_hcd); +				} +			} else +				if ((dum_hcd->port_status & +				     USB_PORT_STAT_POWER) != 0) { +					dum_hcd->port_status |= (1 << wValue); +					set_link_state(dum_hcd); +				} +		} +		break; +	case GetPortErrorCount: +		if (hcd->speed != HCD_USB3) { +			dev_dbg(dummy_dev(dum_hcd), +				 "GetPortErrorCount req not " +				 "supported for USB 2.0 roothub\n"); +			goto error; +		} +		/* We'll always return 0 since this is a dummy hub */ +		*(__le32 *) buf = cpu_to_le32(0); +		break; +	case SetHubDepth: +		if (hcd->speed != HCD_USB3) { +			dev_dbg(dummy_dev(dum_hcd), +				 "SetHubDepth req not supported for " +				 "USB 2.0 roothub\n"); +			goto error;  		}  		break; -  	default: -		dev_dbg (dummy_dev(dum), +		dev_dbg(dummy_dev(dum_hcd),  			"hub control req%04x v%04x i%04x l%d\n",  			typeReq, wValue, wIndex, wLength); - +error:  		/* "protocol stall" on error */  		retval = -EPIPE;  	} -	spin_unlock_irqrestore (&dum->lock, flags); +	spin_unlock_irqrestore(&dum_hcd->dum->lock, flags); -	if ((dum->port_status & PORT_C_MASK) != 0) +	if ((dum_hcd->port_status & PORT_C_MASK) != 0)  		usb_hcd_poll_rh_status (hcd);  	return retval;  }  static int dummy_bus_suspend (struct usb_hcd *hcd)  { -	struct dummy *dum = hcd_to_dummy (hcd); +	struct dummy_hcd *dum_hcd = hcd_to_dummy_hcd(hcd);  	dev_dbg (&hcd->self.root_hub->dev, "%s\n", __func__); -	spin_lock_irq (&dum->lock); -	dum->rh_state = DUMMY_RH_SUSPENDED; -	set_link_state (dum); +	spin_lock_irq(&dum_hcd->dum->lock); +	dum_hcd->rh_state = DUMMY_RH_SUSPENDED; +	set_link_state(dum_hcd);  	hcd->state = HC_STATE_SUSPENDED; -	spin_unlock_irq (&dum->lock); +	spin_unlock_irq(&dum_hcd->dum->lock);  	return 0;  }  static int dummy_bus_resume (struct usb_hcd *hcd)  { -	struct dummy *dum = hcd_to_dummy (hcd); +	struct dummy_hcd *dum_hcd = hcd_to_dummy_hcd(hcd);  	int rc = 0;  	dev_dbg (&hcd->self.root_hub->dev, "%s\n", __func__); -	spin_lock_irq (&dum->lock); +	spin_lock_irq(&dum_hcd->dum->lock);  	if (!HCD_HW_ACCESSIBLE(hcd)) {  		rc = -ESHUTDOWN;  	} else { -		dum->rh_state = DUMMY_RH_RUNNING; -		set_link_state (dum); -		if (!list_empty(&dum->urbp_list)) -			mod_timer (&dum->timer, jiffies); +		dum_hcd->rh_state = DUMMY_RH_RUNNING; +		set_link_state(dum_hcd); +		if (!list_empty(&dum_hcd->urbp_list)) +			mod_timer(&dum_hcd->timer, jiffies);  		hcd->state = HC_STATE_RUNNING;  	} -	spin_unlock_irq (&dum->lock); +	spin_unlock_irq(&dum_hcd->dum->lock);  	return rc;  } @@ -1786,18 +2090,37 @@ show_urb (char *buf, size_t size, struct urb *urb)  		urb,  		({ char *s;  		 switch (urb->dev->speed) { -		 case USB_SPEED_LOW:	s = "ls"; break; -		 case USB_SPEED_FULL:	s = "fs"; break; -		 case USB_SPEED_HIGH:	s = "hs"; break; -		 default:		s = "?"; break; +		 case USB_SPEED_LOW: +			s = "ls"; +			break; +		 case USB_SPEED_FULL: +			s = "fs"; +			break; +		 case USB_SPEED_HIGH: +			s = "hs"; +			break; +		 case USB_SPEED_SUPER: +			s = "ss"; +			break; +		 default: +			s = "?"; +			break;  		 }; s; }),  		ep, ep ? (usb_pipein (urb->pipe) ? "in" : "out") : "",  		({ char *s; \  		 switch (usb_pipetype (urb->pipe)) { \ -		 case PIPE_CONTROL:	s = ""; break; \ -		 case PIPE_BULK:	s = "-bulk"; break; \ -		 case PIPE_INTERRUPT:	s = "-int"; break; \ -		 default: 		s = "-iso"; break; \ +		 case PIPE_CONTROL: \ +			s = ""; \ +			break; \ +		 case PIPE_BULK: \ +			s = "-bulk"; \ +			break; \ +		 case PIPE_INTERRUPT: \ +			s = "-int"; \ +			break; \ +		 default: \ +			s = "-iso"; \ +			break; \  		}; s;}),  		urb->actual_length, urb->transfer_buffer_length);  } @@ -1806,43 +2129,63 @@ static ssize_t  show_urbs (struct device *dev, struct device_attribute *attr, char *buf)  {  	struct usb_hcd		*hcd = dev_get_drvdata (dev); -	struct dummy		*dum = hcd_to_dummy (hcd); +	struct dummy_hcd	*dum_hcd = hcd_to_dummy_hcd(hcd);  	struct urbp		*urbp;  	size_t			size = 0;  	unsigned long		flags; -	spin_lock_irqsave (&dum->lock, flags); -	list_for_each_entry (urbp, &dum->urbp_list, urbp_list) { +	spin_lock_irqsave(&dum_hcd->dum->lock, flags); +	list_for_each_entry(urbp, &dum_hcd->urbp_list, urbp_list) {  		size_t		temp;  		temp = show_urb (buf, PAGE_SIZE - size, urbp->urb);  		buf += temp;  		size += temp;  	} -	spin_unlock_irqrestore (&dum->lock, flags); +	spin_unlock_irqrestore(&dum_hcd->dum->lock, flags);  	return size;  }  static DEVICE_ATTR (urbs, S_IRUGO, show_urbs, NULL); -static int dummy_start (struct usb_hcd *hcd) +static int dummy_start_ss(struct dummy_hcd *dum_hcd)  { -	struct dummy		*dum; +	init_timer(&dum_hcd->timer); +	dum_hcd->timer.function = dummy_timer; +	dum_hcd->timer.data = (unsigned long)dum_hcd; +	dum_hcd->rh_state = DUMMY_RH_RUNNING; +	INIT_LIST_HEAD(&dum_hcd->urbp_list); +	dummy_hcd_to_hcd(dum_hcd)->power_budget = POWER_BUDGET; +	dummy_hcd_to_hcd(dum_hcd)->state = HC_STATE_RUNNING; +	dummy_hcd_to_hcd(dum_hcd)->uses_new_polling = 1; +#ifdef CONFIG_USB_OTG +	dummy_hcd_to_hcd(dum_hcd)->self.otg_port = 1; +#endif +	return 0; + +	/* FIXME 'urbs' should be a per-device thing, maybe in usbcore */ +	return device_create_file(dummy_dev(dum_hcd), &dev_attr_urbs); +} -	dum = hcd_to_dummy (hcd); +static int dummy_start(struct usb_hcd *hcd) +{ +	struct dummy_hcd	*dum_hcd = hcd_to_dummy_hcd(hcd);  	/*  	 * MASTER side init ... we emulate a root hub that'll only ever  	 * talk to one device (the slave side).  Also appears in sysfs,  	 * just like more familiar pci-based HCDs.  	 */ -	spin_lock_init (&dum->lock); -	init_timer (&dum->timer); -	dum->timer.function = dummy_timer; -	dum->timer.data = (unsigned long) dum; -	dum->rh_state = DUMMY_RH_RUNNING; +	if (!usb_hcd_is_primary_hcd(hcd)) +		return dummy_start_ss(dum_hcd); -	INIT_LIST_HEAD (&dum->urbp_list); +	spin_lock_init(&dum_hcd->dum->lock); +	init_timer(&dum_hcd->timer); +	dum_hcd->timer.function = dummy_timer; +	dum_hcd->timer.data = (unsigned long)dum_hcd; +	dum_hcd->rh_state = DUMMY_RH_RUNNING; + +	INIT_LIST_HEAD(&dum_hcd->urbp_list);  	hcd->power_budget = POWER_BUDGET;  	hcd->state = HC_STATE_RUNNING; @@ -1853,18 +2196,17 @@ static int dummy_start (struct usb_hcd *hcd)  #endif  	/* FIXME 'urbs' should be a per-device thing, maybe in usbcore */ -	return device_create_file (dummy_dev(dum), &dev_attr_urbs); +	return device_create_file(dummy_dev(dum_hcd), &dev_attr_urbs);  }  static void dummy_stop (struct usb_hcd *hcd)  {  	struct dummy		*dum; -	dum = hcd_to_dummy (hcd); - -	device_remove_file (dummy_dev(dum), &dev_attr_urbs); -	usb_gadget_unregister_driver (dum->driver); -	dev_info (dummy_dev(dum), "stopped\n"); +	dum = (hcd_to_dummy_hcd(hcd))->dum; +	device_remove_file(dummy_dev(hcd_to_dummy_hcd(hcd)), &dev_attr_urbs); +	usb_gadget_unregister_driver(dum->driver); +	dev_info(dummy_dev(hcd_to_dummy_hcd(hcd)), "stopped\n");  }  /*-------------------------------------------------------------------------*/ @@ -1874,13 +2216,59 @@ static int dummy_h_get_frame (struct usb_hcd *hcd)  	return dummy_g_get_frame (NULL);  } -static const struct hc_driver dummy_hcd = { +static int dummy_setup(struct usb_hcd *hcd) +{ +	if (usb_hcd_is_primary_hcd(hcd)) { +		the_controller.hs_hcd = hcd_to_dummy_hcd(hcd); +		the_controller.hs_hcd->dum = &the_controller; +		/* +		 * Mark the first roothub as being USB 2.0. +		 * The USB 3.0 roothub will be registered later by +		 * dummy_hcd_probe() +		 */ +		hcd->speed = HCD_USB2; +		hcd->self.root_hub->speed = USB_SPEED_HIGH; +	} else { +		the_controller.ss_hcd = hcd_to_dummy_hcd(hcd); +		the_controller.ss_hcd->dum = &the_controller; +		hcd->speed = HCD_USB3; +		hcd->self.root_hub->speed = USB_SPEED_SUPER; +	} +	return 0; +} + +/* Change a group of bulk endpoints to support multiple stream IDs */ +int dummy_alloc_streams(struct usb_hcd *hcd, struct usb_device *udev, +	struct usb_host_endpoint **eps, unsigned int num_eps, +	unsigned int num_streams, gfp_t mem_flags) +{ +	if (hcd->speed != HCD_USB3) +		dev_dbg(dummy_dev(hcd_to_dummy_hcd(hcd)), +			"%s() - ERROR! Not supported for USB2.0 roothub\n", +			__func__); +	return 0; +} + +/* Reverts a group of bulk endpoints back to not using stream IDs. */ +int dummy_free_streams(struct usb_hcd *hcd, struct usb_device *udev, +	struct usb_host_endpoint **eps, unsigned int num_eps, +	gfp_t mem_flags) +{ +	if (hcd->speed != HCD_USB3) +		dev_dbg(dummy_dev(hcd_to_dummy_hcd(hcd)), +			"%s() - ERROR! Not supported for USB2.0 roothub\n", +			__func__); +	return 0; +} + +static struct hc_driver dummy_hcd = {  	.description =		(char *) driver_name,  	.product_desc =		"Dummy host controller", -	.hcd_priv_size =	sizeof(struct dummy), +	.hcd_priv_size =	sizeof(struct dummy_hcd), -	.flags =		HCD_USB2, +	.flags =		HCD_USB3 | HCD_SHARED, +	.reset =		dummy_setup,  	.start =		dummy_start,  	.stop =			dummy_stop, @@ -1893,50 +2281,85 @@ static const struct hc_driver dummy_hcd = {  	.hub_control = 		dummy_hub_control,  	.bus_suspend =		dummy_bus_suspend,  	.bus_resume =		dummy_bus_resume, + +	.alloc_streams =	dummy_alloc_streams, +	.free_streams =		dummy_free_streams,  };  static int dummy_hcd_probe(struct platform_device *pdev)  { -	struct usb_hcd		*hcd; +	struct usb_hcd		*hs_hcd; +	struct usb_hcd		*ss_hcd;  	int			retval;  	dev_info(&pdev->dev, "%s, driver " DRIVER_VERSION "\n", driver_desc); -	hcd = usb_create_hcd(&dummy_hcd, &pdev->dev, dev_name(&pdev->dev)); -	if (!hcd) +	if (!mod_data.is_super_speed) +		dummy_hcd.flags = HCD_USB2; +	hs_hcd = usb_create_hcd(&dummy_hcd, &pdev->dev, dev_name(&pdev->dev)); +	if (!hs_hcd)  		return -ENOMEM; -	the_controller = hcd_to_dummy (hcd); +	hs_hcd->has_tt = 1; -	retval = usb_add_hcd(hcd, 0, 0); +	retval = usb_add_hcd(hs_hcd, 0, 0);  	if (retval != 0) { -		usb_put_hcd (hcd); -		the_controller = NULL; +		usb_put_hcd(hs_hcd); +		return retval; +	} + +	if (mod_data.is_super_speed) { +		ss_hcd = usb_create_shared_hcd(&dummy_hcd, &pdev->dev, +					dev_name(&pdev->dev), hs_hcd); +		if (!ss_hcd) { +			retval = -ENOMEM; +			goto dealloc_usb2_hcd; +		} + +		retval = usb_add_hcd(ss_hcd, 0, 0); +		if (retval) +			goto put_usb3_hcd;  	} +	return 0; + +put_usb3_hcd: +	usb_put_hcd(ss_hcd); +dealloc_usb2_hcd: +	usb_put_hcd(hs_hcd); +	the_controller.hs_hcd = the_controller.ss_hcd = NULL;  	return retval;  } -static int dummy_hcd_remove (struct platform_device *pdev) +static int dummy_hcd_remove(struct platform_device *pdev)  { -	struct usb_hcd		*hcd; +	struct dummy		*dum; + +	dum = (hcd_to_dummy_hcd(platform_get_drvdata(pdev)))->dum; + +	if (dum->ss_hcd) { +		usb_remove_hcd(dummy_hcd_to_hcd(dum->ss_hcd)); +		usb_put_hcd(dummy_hcd_to_hcd(dum->ss_hcd)); +	} + +	usb_remove_hcd(dummy_hcd_to_hcd(dum->hs_hcd)); +	usb_put_hcd(dummy_hcd_to_hcd(dum->hs_hcd)); + +	the_controller.hs_hcd = NULL; +	the_controller.ss_hcd = NULL; -	hcd = platform_get_drvdata (pdev); -	usb_remove_hcd (hcd); -	usb_put_hcd (hcd); -	the_controller = NULL;  	return 0;  }  static int dummy_hcd_suspend (struct platform_device *pdev, pm_message_t state)  {  	struct usb_hcd		*hcd; -	struct dummy		*dum; +	struct dummy_hcd	*dum_hcd;  	int			rc = 0;  	dev_dbg (&pdev->dev, "%s\n", __func__);  	hcd = platform_get_drvdata (pdev); -	dum = hcd_to_dummy (hcd); -	if (dum->rh_state == DUMMY_RH_RUNNING) { +	dum_hcd = hcd_to_dummy_hcd(hcd); +	if (dum_hcd->rh_state == DUMMY_RH_RUNNING) {  		dev_warn(&pdev->dev, "Root hub isn't suspended!\n");  		rc = -EBUSY;  	} else @@ -1979,6 +2402,9 @@ static int __init init (void)  	if (usb_disabled ())  		return -ENODEV; +	if (!mod_data.is_high_speed && mod_data.is_super_speed) +		return -EINVAL; +  	the_hcd_pdev = platform_device_alloc(driver_name, -1);  	if (!the_hcd_pdev)  		return retval; @@ -1996,7 +2422,8 @@ static int __init init (void)  	retval = platform_device_add(the_hcd_pdev);  	if (retval < 0)  		goto err_add_hcd; -	if (!the_controller) { +	if (!the_controller.hs_hcd || +	    (!the_controller.ss_hcd && mod_data.is_super_speed)) {  		/*  		 * The hcd was added successfully but its probe function failed  		 * for some reason. diff --git a/drivers/usb/gadget/epautoconf.c b/drivers/usb/gadget/epautoconf.c index 9b7360ff5aa7..7a7e6b7e1fd6 100644 --- a/drivers/usb/gadget/epautoconf.c +++ b/drivers/usb/gadget/epautoconf.c @@ -63,13 +63,16 @@ static int  ep_matches (  	struct usb_gadget		*gadget,  	struct usb_ep			*ep, -	struct usb_endpoint_descriptor	*desc +	struct usb_endpoint_descriptor	*desc, +	struct usb_ss_ep_comp_descriptor *ep_comp  )  {  	u8		type;  	const char	*tmp;  	u16		max; +	int		num_req_streams = 0; +  	/* endpoint already claimed? */  	if (NULL != ep->driver_data)  		return 0; @@ -129,6 +132,22 @@ ep_matches (  	}  	/* +	 * Get the number of required streams from the EP companion +	 * descriptor and see if the EP matches it +	 */ +	if (usb_endpoint_xfer_bulk(desc)) { +		if (ep_comp) { +			num_req_streams = ep_comp->bmAttributes & 0x1f; +			if (num_req_streams > ep->max_streams) +				return 0; +			/* Update the ep_comp descriptor if needed */ +			if (num_req_streams != ep->max_streams) +				ep_comp->bmAttributes = ep->max_streams; +		} + +	} + +	/*  	 * If the protocol driver hasn't yet decided on wMaxPacketSize  	 * and wants to know the maximum possible, provide the info.  	 */ @@ -142,13 +161,13 @@ ep_matches (  	max = 0x7ff & le16_to_cpu(desc->wMaxPacketSize);  	switch (type) {  	case USB_ENDPOINT_XFER_INT: -		/* INT:  limit 64 bytes full speed, 1024 high speed */ +		/* INT:  limit 64 bytes full speed, 1024 high/super speed */  		if (!gadget->is_dualspeed && max > 64)  			return 0;  		/* FALLTHROUGH */  	case USB_ENDPOINT_XFER_ISOC: -		/* ISO:  limit 1023 bytes full speed, 1024 high speed */ +		/* ISO:  limit 1023 bytes full speed, 1024 high/super speed */  		if (ep->maxpacket < max)  			return 0;  		if (!gadget->is_dualspeed && max > 1023) @@ -183,7 +202,7 @@ ep_matches (  	}  	/* report (variable) full speed bulk maxpacket */ -	if (USB_ENDPOINT_XFER_BULK == type) { +	if ((USB_ENDPOINT_XFER_BULK == type) && !ep_comp) {  		int size = ep->maxpacket;  		/* min() doesn't work on bitfields with gcc-3.5 */ @@ -191,6 +210,7 @@ ep_matches (  			size = 64;  		desc->wMaxPacketSize = cpu_to_le16(size);  	} +	ep->address = desc->bEndpointAddress;  	return 1;  } @@ -207,38 +227,53 @@ find_ep (struct usb_gadget *gadget, const char *name)  }  /** - * usb_ep_autoconfig - choose an endpoint matching the descriptor + * usb_ep_autoconfig_ss() - choose an endpoint matching the ep + * descriptor and ep companion descriptor   * @gadget: The device to which the endpoint must belong.   * @desc: Endpoint descriptor, with endpoint direction and transfer mode - *	initialized.  For periodic transfers, the maximum packet - *	size must also be initialized.  This is modified on success. + *    initialized.  For periodic transfers, the maximum packet + *    size must also be initialized.  This is modified on + *    success. + * @ep_comp: Endpoint companion descriptor, with the required + *    number of streams. Will be modified when the chosen EP + *    supports a different number of streams.   * - * By choosing an endpoint to use with the specified descriptor, this - * routine simplifies writing gadget drivers that work with multiple - * USB device controllers.  The endpoint would be passed later to - * usb_ep_enable(), along with some descriptor. + * This routine replaces the usb_ep_autoconfig when needed + * superspeed enhancments. If such enhancemnets are required, + * the FD should call usb_ep_autoconfig_ss directly and provide + * the additional ep_comp parameter. + * + * By choosing an endpoint to use with the specified descriptor, + * this routine simplifies writing gadget drivers that work with + * multiple USB device controllers.  The endpoint would be + * passed later to usb_ep_enable(), along with some descriptor.   *   * That second descriptor won't always be the same as the first one.   * For example, isochronous endpoints can be autoconfigured for high   * bandwidth, and then used in several lower bandwidth altsettings.   * Also, high and full speed descriptors will be different.   * - * Be sure to examine and test the results of autoconfiguration on your - * hardware.  This code may not make the best choices about how to use the - * USB controller, and it can't know all the restrictions that may apply. - * Some combinations of driver and hardware won't be able to autoconfigure. + * Be sure to examine and test the results of autoconfiguration + * on your hardware.  This code may not make the best choices + * about how to use the USB controller, and it can't know all + * the restrictions that may apply. Some combinations of driver + * and hardware won't be able to autoconfigure.   *   * On success, this returns an un-claimed usb_ep, and modifies the endpoint   * descriptor bEndpointAddress.  For bulk endpoints, the wMaxPacket value - * is initialized as if the endpoint were used at full speed.  To prevent - * the endpoint from being returned by a later autoconfig call, claim it - * by assigning ep->driver_data to some non-null value. + * is initialized as if the endpoint were used at full speed and + * the bmAttribute field in the ep companion descriptor is + * updated with the assigned number of streams if it is + * different from the original value. To prevent the endpoint + * from being returned by a later autoconfig call, claim it by + * assigning ep->driver_data to some non-null value.   *   * On failure, this returns a null endpoint descriptor.   */ -struct usb_ep *usb_ep_autoconfig ( +struct usb_ep *usb_ep_autoconfig_ss(  	struct usb_gadget		*gadget, -	struct usb_endpoint_descriptor	*desc +	struct usb_endpoint_descriptor	*desc, +	struct usb_ss_ep_comp_descriptor *ep_comp  )  {  	struct usb_ep	*ep; @@ -252,23 +287,24 @@ struct usb_ep *usb_ep_autoconfig (  	if (gadget_is_net2280 (gadget) && type == USB_ENDPOINT_XFER_INT) {  		/* ep-e, ep-f are PIO with only 64 byte fifos */  		ep = find_ep (gadget, "ep-e"); -		if (ep && ep_matches (gadget, ep, desc)) +		if (ep && ep_matches(gadget, ep, desc, ep_comp))  			return ep;  		ep = find_ep (gadget, "ep-f"); -		if (ep && ep_matches (gadget, ep, desc)) +		if (ep && ep_matches(gadget, ep, desc, ep_comp))  			return ep;  	} else if (gadget_is_goku (gadget)) {  		if (USB_ENDPOINT_XFER_INT == type) {  			/* single buffering is enough */ -			ep = find_ep (gadget, "ep3-bulk"); -			if (ep && ep_matches (gadget, ep, desc)) +			ep = find_ep(gadget, "ep3-bulk"); +			if (ep && ep_matches(gadget, ep, desc, ep_comp))  				return ep;  		} else if (USB_ENDPOINT_XFER_BULK == type  				&& (USB_DIR_IN & desc->bEndpointAddress)) {  			/* DMA may be available */ -			ep = find_ep (gadget, "ep2-bulk"); -			if (ep && ep_matches (gadget, ep, desc)) +			ep = find_ep(gadget, "ep2-bulk"); +			if (ep && ep_matches(gadget, ep, desc, +					      ep_comp))  				return ep;  		} @@ -287,14 +323,14 @@ struct usb_ep *usb_ep_autoconfig (  				ep = find_ep(gadget, "ep2out");  		} else  			ep = NULL; -		if (ep && ep_matches (gadget, ep, desc)) +		if (ep && ep_matches(gadget, ep, desc, ep_comp))  			return ep;  #endif  	}  	/* Second, look at endpoints until an unclaimed one looks usable */  	list_for_each_entry (ep, &gadget->ep_list, ep_list) { -		if (ep_matches (gadget, ep, desc)) +		if (ep_matches(gadget, ep, desc, ep_comp))  			return ep;  	} @@ -303,6 +339,46 @@ struct usb_ep *usb_ep_autoconfig (  }  /** + * usb_ep_autoconfig() - choose an endpoint matching the + * descriptor + * @gadget: The device to which the endpoint must belong. + * @desc: Endpoint descriptor, with endpoint direction and transfer mode + *	initialized.  For periodic transfers, the maximum packet + *	size must also be initialized.  This is modified on success. + * + * By choosing an endpoint to use with the specified descriptor, this + * routine simplifies writing gadget drivers that work with multiple + * USB device controllers.  The endpoint would be passed later to + * usb_ep_enable(), along with some descriptor. + * + * That second descriptor won't always be the same as the first one. + * For example, isochronous endpoints can be autoconfigured for high + * bandwidth, and then used in several lower bandwidth altsettings. + * Also, high and full speed descriptors will be different. + * + * Be sure to examine and test the results of autoconfiguration on your + * hardware.  This code may not make the best choices about how to use the + * USB controller, and it can't know all the restrictions that may apply. + * Some combinations of driver and hardware won't be able to autoconfigure. + * + * On success, this returns an un-claimed usb_ep, and modifies the endpoint + * descriptor bEndpointAddress.  For bulk endpoints, the wMaxPacket value + * is initialized as if the endpoint were used at full speed.  To prevent + * the endpoint from being returned by a later autoconfig call, claim it + * by assigning ep->driver_data to some non-null value. + * + * On failure, this returns a null endpoint descriptor. + */ +struct usb_ep *usb_ep_autoconfig( +	struct usb_gadget		*gadget, +	struct usb_endpoint_descriptor	*desc +) +{ +	return usb_ep_autoconfig_ss(gadget, desc, NULL); +} + + +/**   * usb_ep_autoconfig_reset - reset endpoint autoconfig state   * @gadget: device for which autoconfig state will be reset   * diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c index 1690c9d68256..aafc84f33e26 100644 --- a/drivers/usb/gadget/ether.c +++ b/drivers/usb/gadget/ether.c @@ -401,6 +401,7 @@ static struct usb_composite_driver eth_driver = {  	.name		= "g_ether",  	.dev		= &device_desc,  	.strings	= dev_strings, +	.max_speed	= USB_SPEED_SUPER,  	.unbind		= __exit_p(eth_unbind),  }; diff --git a/drivers/usb/gadget/f_acm.c b/drivers/usb/gadget/f_acm.c index bd6226cbae86..3f8849339ade 100644 --- a/drivers/usb/gadget/f_acm.c +++ b/drivers/usb/gadget/f_acm.c @@ -39,12 +39,6 @@   * descriptors (roughly equivalent to CDC Unions) may sometimes help.   */ -struct acm_ep_descs { -	struct usb_endpoint_descriptor	*in; -	struct usb_endpoint_descriptor	*out; -	struct usb_endpoint_descriptor	*notify; -}; -  struct f_acm {  	struct gserial			port;  	u8				ctrl_id, data_id; @@ -58,11 +52,7 @@ struct f_acm {  	 */  	spinlock_t			lock; -	struct acm_ep_descs		fs; -	struct acm_ep_descs		hs; -  	struct usb_ep			*notify; -	struct usb_endpoint_descriptor	*notify_desc;  	struct usb_request		*notify_req;  	struct usb_cdc_line_coding	port_line_coding;	/* 8-N-1 etc */ @@ -405,23 +395,27 @@ static int acm_set_alt(struct usb_function *f, unsigned intf, unsigned alt)  			usb_ep_disable(acm->notify);  		} else {  			VDBG(cdev, "init acm ctrl interface %d\n", intf); -			acm->notify_desc = ep_choose(cdev->gadget, -					acm->hs.notify, -					acm->fs.notify); +			if (config_ep_by_speed(cdev->gadget, f, acm->notify)) +				return -EINVAL;  		} -		usb_ep_enable(acm->notify, acm->notify_desc); +		usb_ep_enable(acm->notify);  		acm->notify->driver_data = acm;  	} else if (intf == acm->data_id) {  		if (acm->port.in->driver_data) {  			DBG(cdev, "reset acm ttyGS%d\n", acm->port_num);  			gserial_disconnect(&acm->port); -		} else { +		} +		if (!acm->port.in->desc || !acm->port.out->desc) {  			DBG(cdev, "activate acm ttyGS%d\n", acm->port_num); -			acm->port.in_desc = ep_choose(cdev->gadget, -					acm->hs.in, acm->fs.in); -			acm->port.out_desc = ep_choose(cdev->gadget, -					acm->hs.out, acm->fs.out); +			if (config_ep_by_speed(cdev->gadget, f, +					       acm->port.in) || +			    config_ep_by_speed(cdev->gadget, f, +					       acm->port.out)) { +				acm->port.in->desc = NULL; +				acm->port.out->desc = NULL; +				return -EINVAL; +			}  		}  		gserial_connect(&acm->port, acm->port_num); @@ -629,18 +623,11 @@ acm_bind(struct usb_configuration *c, struct usb_function *f)  	acm->notify_req->complete = acm_cdc_notify_complete;  	acm->notify_req->context = acm; -	/* copy descriptors, and track endpoint copies */ +	/* copy descriptors */  	f->descriptors = usb_copy_descriptors(acm_fs_function);  	if (!f->descriptors)  		goto fail; -	acm->fs.in = usb_find_endpoint(acm_fs_function, -			f->descriptors, &acm_fs_in_desc); -	acm->fs.out = usb_find_endpoint(acm_fs_function, -			f->descriptors, &acm_fs_out_desc); -	acm->fs.notify = usb_find_endpoint(acm_fs_function, -			f->descriptors, &acm_fs_notify_desc); -  	/* support all relevant hardware speeds... we expect that when  	 * hardware is dual speed, all bulk-capable endpoints work at  	 * both speeds @@ -653,15 +640,8 @@ acm_bind(struct usb_configuration *c, struct usb_function *f)  		acm_hs_notify_desc.bEndpointAddress =  				acm_fs_notify_desc.bEndpointAddress; -		/* copy descriptors, and track endpoint copies */ +		/* copy descriptors */  		f->hs_descriptors = usb_copy_descriptors(acm_hs_function); - -		acm->hs.in = usb_find_endpoint(acm_hs_function, -				f->hs_descriptors, &acm_hs_in_desc); -		acm->hs.out = usb_find_endpoint(acm_hs_function, -				f->hs_descriptors, &acm_hs_out_desc); -		acm->hs.notify = usb_find_endpoint(acm_hs_function, -				f->hs_descriptors, &acm_hs_notify_desc);  	}  	DBG(cdev, "acm ttyGS%d: %s speed IN/%s OUT/%s NOTIFY/%s\n", diff --git a/drivers/usb/gadget/f_audio.c b/drivers/usb/gadget/f_audio.c index 8ee330a2ab58..a9a4eade7e80 100644 --- a/drivers/usb/gadget/f_audio.c +++ b/drivers/usb/gadget/f_audio.c @@ -12,7 +12,7 @@  #include <linux/slab.h>  #include <linux/kernel.h>  #include <linux/device.h> -#include <asm/atomic.h> +#include <linux/atomic.h>  #include "u_audio.h" @@ -279,7 +279,6 @@ struct f_audio {  	/* endpoints handle full and/or high speeds */  	struct usb_ep			*out_ep; -	struct usb_endpoint_descriptor	*out_desc;  	spinlock_t			lock;  	struct f_audio_buf *copy_buf; @@ -575,7 +574,7 @@ static int f_audio_set_alt(struct usb_function *f, unsigned intf, unsigned alt)  	if (intf == 1) {  		if (alt == 1) { -			usb_ep_enable(out_ep, audio->out_desc); +			usb_ep_enable(out_ep);  			out_ep->driver_data = audio;  			audio->copy_buf = f_audio_buffer_alloc(audio_buf_size);  			if (IS_ERR(audio->copy_buf)) @@ -677,6 +676,7 @@ f_audio_bind(struct usb_configuration *c, struct usb_function *f)  	if (!ep)  		goto fail;  	audio->out_ep = ep; +	audio->out_ep->desc = &as_out_ep_desc;  	ep->driver_data = cdev;	/* claim */  	status = -ENOMEM; @@ -776,7 +776,6 @@ int __init audio_bind_config(struct usb_configuration *c)  	audio->card.func.set_alt = f_audio_set_alt;  	audio->card.func.setup = f_audio_setup;  	audio->card.func.disable = f_audio_disable; -	audio->out_desc = &as_out_ep_desc;  	control_selector_init(audio); diff --git a/drivers/usb/gadget/f_ecm.c b/drivers/usb/gadget/f_ecm.c index 544257a89ed2..3691a0cb9465 100644 --- a/drivers/usb/gadget/f_ecm.c +++ b/drivers/usb/gadget/f_ecm.c @@ -46,11 +46,6 @@   * and also means that a get_alt() method is required.   */ -struct ecm_ep_descs { -	struct usb_endpoint_descriptor	*in; -	struct usb_endpoint_descriptor	*out; -	struct usb_endpoint_descriptor	*notify; -};  enum ecm_notify_state {  	ECM_NOTIFY_NONE,		/* don't notify */ @@ -64,11 +59,7 @@ struct f_ecm {  	char				ethaddr[14]; -	struct ecm_ep_descs		fs; -	struct ecm_ep_descs		hs; -  	struct usb_ep			*notify; -	struct usb_endpoint_descriptor	*notify_desc;  	struct usb_request		*notify_req;  	u8				notify_state;  	bool				is_open; @@ -86,10 +77,12 @@ static inline struct f_ecm *func_to_ecm(struct usb_function *f)  /* peak (theoretical) bulk transfer rate in bits-per-second */  static inline unsigned ecm_bitrate(struct usb_gadget *g)  { -	if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH) +	if (gadget_is_superspeed(g) && g->speed == USB_SPEED_SUPER) +		return 13 * 1024 * 8 * 1000 * 8; +	else if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH)  		return 13 * 512 * 8 * 1000 * 8;  	else -		return 19 *  64 * 1 * 1000 * 8; +		return 19 * 64 * 1 * 1000 * 8;  }  /*-------------------------------------------------------------------------*/ @@ -219,8 +212,10 @@ static struct usb_descriptor_header *ecm_fs_function[] = {  	(struct usb_descriptor_header *) &ecm_header_desc,  	(struct usb_descriptor_header *) &ecm_union_desc,  	(struct usb_descriptor_header *) &ecm_desc, +  	/* NOTE: status endpoint might need to be removed */  	(struct usb_descriptor_header *) &fs_ecm_notify_desc, +  	/* data interface, altsettings 0 and 1 */  	(struct usb_descriptor_header *) &ecm_data_nop_intf,  	(struct usb_descriptor_header *) &ecm_data_intf, @@ -240,6 +235,7 @@ static struct usb_endpoint_descriptor hs_ecm_notify_desc = {  	.wMaxPacketSize =	cpu_to_le16(ECM_STATUS_BYTECOUNT),  	.bInterval =		LOG2_STATUS_INTERVAL_MSEC + 4,  }; +  static struct usb_endpoint_descriptor hs_ecm_in_desc = {  	.bLength =		USB_DT_ENDPOINT_SIZE,  	.bDescriptorType =	USB_DT_ENDPOINT, @@ -264,8 +260,10 @@ static struct usb_descriptor_header *ecm_hs_function[] = {  	(struct usb_descriptor_header *) &ecm_header_desc,  	(struct usb_descriptor_header *) &ecm_union_desc,  	(struct usb_descriptor_header *) &ecm_desc, +  	/* NOTE: status endpoint might need to be removed */  	(struct usb_descriptor_header *) &hs_ecm_notify_desc, +  	/* data interface, altsettings 0 and 1 */  	(struct usb_descriptor_header *) &ecm_data_nop_intf,  	(struct usb_descriptor_header *) &ecm_data_intf, @@ -274,6 +272,76 @@ static struct usb_descriptor_header *ecm_hs_function[] = {  	NULL,  }; +/* super speed support: */ + +static struct usb_endpoint_descriptor ss_ecm_notify_desc = { +	.bLength =		USB_DT_ENDPOINT_SIZE, +	.bDescriptorType =	USB_DT_ENDPOINT, + +	.bEndpointAddress =	USB_DIR_IN, +	.bmAttributes =		USB_ENDPOINT_XFER_INT, +	.wMaxPacketSize =	cpu_to_le16(ECM_STATUS_BYTECOUNT), +	.bInterval =		LOG2_STATUS_INTERVAL_MSEC + 4, +}; + +static struct usb_ss_ep_comp_descriptor ss_ecm_intr_comp_desc = { +	.bLength =		sizeof ss_ecm_intr_comp_desc, +	.bDescriptorType =	USB_DT_SS_ENDPOINT_COMP, + +	/* the following 3 values can be tweaked if necessary */ +	/* .bMaxBurst =		0, */ +	/* .bmAttributes =	0, */ +	.wBytesPerInterval =	cpu_to_le16(ECM_STATUS_BYTECOUNT), +}; + +static struct usb_endpoint_descriptor ss_ecm_in_desc = { +	.bLength =		USB_DT_ENDPOINT_SIZE, +	.bDescriptorType =	USB_DT_ENDPOINT, + +	.bEndpointAddress =	USB_DIR_IN, +	.bmAttributes =		USB_ENDPOINT_XFER_BULK, +	.wMaxPacketSize =	cpu_to_le16(1024), +}; + +static struct usb_endpoint_descriptor ss_ecm_out_desc = { +	.bLength =		USB_DT_ENDPOINT_SIZE, +	.bDescriptorType =	USB_DT_ENDPOINT, + +	.bEndpointAddress =	USB_DIR_OUT, +	.bmAttributes =		USB_ENDPOINT_XFER_BULK, +	.wMaxPacketSize =	cpu_to_le16(1024), +}; + +static struct usb_ss_ep_comp_descriptor ss_ecm_bulk_comp_desc = { +	.bLength =		sizeof ss_ecm_bulk_comp_desc, +	.bDescriptorType =	USB_DT_SS_ENDPOINT_COMP, + +	/* the following 2 values can be tweaked if necessary */ +	/* .bMaxBurst =		0, */ +	/* .bmAttributes =	0, */ +}; + +static struct usb_descriptor_header *ecm_ss_function[] = { +	/* CDC ECM control descriptors */ +	(struct usb_descriptor_header *) &ecm_control_intf, +	(struct usb_descriptor_header *) &ecm_header_desc, +	(struct usb_descriptor_header *) &ecm_union_desc, +	(struct usb_descriptor_header *) &ecm_desc, + +	/* NOTE: status endpoint might need to be removed */ +	(struct usb_descriptor_header *) &ss_ecm_notify_desc, +	(struct usb_descriptor_header *) &ss_ecm_intr_comp_desc, + +	/* data interface, altsettings 0 and 1 */ +	(struct usb_descriptor_header *) &ecm_data_nop_intf, +	(struct usb_descriptor_header *) &ecm_data_intf, +	(struct usb_descriptor_header *) &ss_ecm_in_desc, +	(struct usb_descriptor_header *) &ss_ecm_bulk_comp_desc, +	(struct usb_descriptor_header *) &ss_ecm_out_desc, +	(struct usb_descriptor_header *) &ss_ecm_bulk_comp_desc, +	NULL, +}; +  /* string descriptors: */  static struct usb_string ecm_string_defs[] = { @@ -464,13 +532,13 @@ static int ecm_set_alt(struct usb_function *f, unsigned intf, unsigned alt)  		if (ecm->notify->driver_data) {  			VDBG(cdev, "reset ecm control %d\n", intf);  			usb_ep_disable(ecm->notify); -		} else { +		} +		if (!(ecm->notify->desc)) {  			VDBG(cdev, "init ecm ctrl %d\n", intf); -			ecm->notify_desc = ep_choose(cdev->gadget, -					ecm->hs.notify, -					ecm->fs.notify); +			if (config_ep_by_speed(cdev->gadget, f, ecm->notify)) +				goto fail;  		} -		usb_ep_enable(ecm->notify, ecm->notify_desc); +		usb_ep_enable(ecm->notify);  		ecm->notify->driver_data = ecm;  	/* Data interface has two altsettings, 0 and 1 */ @@ -483,12 +551,17 @@ static int ecm_set_alt(struct usb_function *f, unsigned intf, unsigned alt)  			gether_disconnect(&ecm->port);  		} -		if (!ecm->port.in) { +		if (!ecm->port.in_ep->desc || +		    !ecm->port.out_ep->desc) {  			DBG(cdev, "init ecm\n"); -			ecm->port.in = ep_choose(cdev->gadget, -					ecm->hs.in, ecm->fs.in); -			ecm->port.out = ep_choose(cdev->gadget, -					ecm->hs.out, ecm->fs.out); +			if (config_ep_by_speed(cdev->gadget, f, +					       ecm->port.in_ep) || +			    config_ep_by_speed(cdev->gadget, f, +					       ecm->port.out_ep)) { +				ecm->port.in_ep->desc = NULL; +				ecm->port.out_ep->desc = NULL; +				goto fail; +			}  		}  		/* CDC Ethernet only sends data in non-default altsettings. @@ -549,7 +622,7 @@ static void ecm_disable(struct usb_function *f)  	if (ecm->notify->driver_data) {  		usb_ep_disable(ecm->notify);  		ecm->notify->driver_data = NULL; -		ecm->notify_desc = NULL; +		ecm->notify->desc = NULL;  	}  } @@ -665,13 +738,6 @@ ecm_bind(struct usb_configuration *c, struct usb_function *f)  	if (!f->descriptors)  		goto fail; -	ecm->fs.in = usb_find_endpoint(ecm_fs_function, -			f->descriptors, &fs_ecm_in_desc); -	ecm->fs.out = usb_find_endpoint(ecm_fs_function, -			f->descriptors, &fs_ecm_out_desc); -	ecm->fs.notify = usb_find_endpoint(ecm_fs_function, -			f->descriptors, &fs_ecm_notify_desc); -  	/* support all relevant hardware speeds... we expect that when  	 * hardware is dual speed, all bulk-capable endpoints work at  	 * both speeds @@ -688,13 +754,20 @@ ecm_bind(struct usb_configuration *c, struct usb_function *f)  		f->hs_descriptors = usb_copy_descriptors(ecm_hs_function);  		if (!f->hs_descriptors)  			goto fail; +	} -		ecm->hs.in = usb_find_endpoint(ecm_hs_function, -				f->hs_descriptors, &hs_ecm_in_desc); -		ecm->hs.out = usb_find_endpoint(ecm_hs_function, -				f->hs_descriptors, &hs_ecm_out_desc); -		ecm->hs.notify = usb_find_endpoint(ecm_hs_function, -				f->hs_descriptors, &hs_ecm_notify_desc); +	if (gadget_is_superspeed(c->cdev->gadget)) { +		ss_ecm_in_desc.bEndpointAddress = +				fs_ecm_in_desc.bEndpointAddress; +		ss_ecm_out_desc.bEndpointAddress = +				fs_ecm_out_desc.bEndpointAddress; +		ss_ecm_notify_desc.bEndpointAddress = +				fs_ecm_notify_desc.bEndpointAddress; + +		/* copy descriptors, and track endpoint copies */ +		f->ss_descriptors = usb_copy_descriptors(ecm_ss_function); +		if (!f->ss_descriptors) +			goto fail;  	}  	/* NOTE:  all that is done without knowing or caring about @@ -706,6 +779,7 @@ ecm_bind(struct usb_configuration *c, struct usb_function *f)  	ecm->port.close = ecm_close;  	DBG(cdev, "CDC Ethernet: %s speed IN/%s OUT/%s NOTIFY/%s\n", +			gadget_is_superspeed(c->cdev->gadget) ? "super" :  			gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full",  			ecm->port.in_ep->name, ecm->port.out_ep->name,  			ecm->notify->name); @@ -714,6 +788,8 @@ ecm_bind(struct usb_configuration *c, struct usb_function *f)  fail:  	if (f->descriptors)  		usb_free_descriptors(f->descriptors); +	if (f->hs_descriptors) +		usb_free_descriptors(f->hs_descriptors);  	if (ecm->notify_req) {  		kfree(ecm->notify_req->buf); @@ -723,9 +799,9 @@ fail:  	/* we might as well release our claims on endpoints */  	if (ecm->notify)  		ecm->notify->driver_data = NULL; -	if (ecm->port.out) +	if (ecm->port.out_ep->desc)  		ecm->port.out_ep->driver_data = NULL; -	if (ecm->port.in) +	if (ecm->port.in_ep->desc)  		ecm->port.in_ep->driver_data = NULL;  	ERROR(cdev, "%s: can't bind, err %d\n", f->name, status); @@ -740,6 +816,8 @@ ecm_unbind(struct usb_configuration *c, struct usb_function *f)  	DBG(c->cdev, "ecm unbind\n"); +	if (gadget_is_superspeed(c->cdev->gadget)) +		usb_free_descriptors(f->ss_descriptors);  	if (gadget_is_dualspeed(c->cdev->gadget))  		usb_free_descriptors(f->hs_descriptors);  	usb_free_descriptors(f->descriptors); diff --git a/drivers/usb/gadget/f_eem.c b/drivers/usb/gadget/f_eem.c index b3c304290150..046c6d0e6960 100644 --- a/drivers/usb/gadget/f_eem.c +++ b/drivers/usb/gadget/f_eem.c @@ -35,17 +35,9 @@   * Ethernet link.   */ -struct eem_ep_descs { -	struct usb_endpoint_descriptor	*in; -	struct usb_endpoint_descriptor	*out; -}; -  struct f_eem {  	struct gether			port;  	u8				ctrl_id; - -	struct eem_ep_descs		fs; -	struct eem_ep_descs		hs;  };  static inline struct f_eem *func_to_eem(struct usb_function *f) @@ -123,6 +115,45 @@ static struct usb_descriptor_header *eem_hs_function[] __initdata = {  	NULL,  }; +/* super speed support: */ + +static struct usb_endpoint_descriptor eem_ss_in_desc __initdata = { +	.bLength =		USB_DT_ENDPOINT_SIZE, +	.bDescriptorType =	USB_DT_ENDPOINT, + +	.bEndpointAddress =	USB_DIR_IN, +	.bmAttributes =		USB_ENDPOINT_XFER_BULK, +	.wMaxPacketSize =	cpu_to_le16(1024), +}; + +static struct usb_endpoint_descriptor eem_ss_out_desc __initdata = { +	.bLength =		USB_DT_ENDPOINT_SIZE, +	.bDescriptorType =	USB_DT_ENDPOINT, + +	.bEndpointAddress =	USB_DIR_OUT, +	.bmAttributes =		USB_ENDPOINT_XFER_BULK, +	.wMaxPacketSize =	cpu_to_le16(1024), +}; + +static struct usb_ss_ep_comp_descriptor eem_ss_bulk_comp_desc __initdata = { +	.bLength =		sizeof eem_ss_bulk_comp_desc, +	.bDescriptorType =	USB_DT_SS_ENDPOINT_COMP, + +	/* the following 2 values can be tweaked if necessary */ +	/* .bMaxBurst =		0, */ +	/* .bmAttributes =	0, */ +}; + +static struct usb_descriptor_header *eem_ss_function[] __initdata = { +	/* CDC EEM control descriptors */ +	(struct usb_descriptor_header *) &eem_intf, +	(struct usb_descriptor_header *) &eem_ss_in_desc, +	(struct usb_descriptor_header *) &eem_ss_bulk_comp_desc, +	(struct usb_descriptor_header *) &eem_ss_out_desc, +	(struct usb_descriptor_header *) &eem_ss_bulk_comp_desc, +	NULL, +}; +  /* string descriptors: */  static struct usb_string eem_string_defs[] = { @@ -176,12 +207,16 @@ static int eem_set_alt(struct usb_function *f, unsigned intf, unsigned alt)  			gether_disconnect(&eem->port);  		} -		if (!eem->port.in) { +		if (!eem->port.in_ep->desc || !eem->port.out_ep->desc) {  			DBG(cdev, "init eem\n"); -			eem->port.in = ep_choose(cdev->gadget, -					eem->hs.in, eem->fs.in); -			eem->port.out = ep_choose(cdev->gadget, -					eem->hs.out, eem->fs.out); +			if (config_ep_by_speed(cdev->gadget, f, +					       eem->port.in_ep) || +			    config_ep_by_speed(cdev->gadget, f, +					       eem->port.out_ep)) { +				eem->port.in_ep->desc = NULL; +				eem->port.out_ep->desc = NULL; +				goto fail; +			}  		}  		/* zlps should not occur because zero-length EEM packets @@ -253,11 +288,6 @@ eem_bind(struct usb_configuration *c, struct usb_function *f)  	if (!f->descriptors)  		goto fail; -	eem->fs.in = usb_find_endpoint(eem_fs_function, -			f->descriptors, &eem_fs_in_desc); -	eem->fs.out = usb_find_endpoint(eem_fs_function, -			f->descriptors, &eem_fs_out_desc); -  	/* support all relevant hardware speeds... we expect that when  	 * hardware is dual speed, all bulk-capable endpoints work at  	 * both speeds @@ -272,14 +302,22 @@ eem_bind(struct usb_configuration *c, struct usb_function *f)  		f->hs_descriptors = usb_copy_descriptors(eem_hs_function);  		if (!f->hs_descriptors)  			goto fail; +	} + +	if (gadget_is_superspeed(c->cdev->gadget)) { +		eem_ss_in_desc.bEndpointAddress = +				eem_fs_in_desc.bEndpointAddress; +		eem_ss_out_desc.bEndpointAddress = +				eem_fs_out_desc.bEndpointAddress; -		eem->hs.in = usb_find_endpoint(eem_hs_function, -				f->hs_descriptors, &eem_hs_in_desc); -		eem->hs.out = usb_find_endpoint(eem_hs_function, -				f->hs_descriptors, &eem_hs_out_desc); +		/* copy descriptors, and track endpoint copies */ +		f->ss_descriptors = usb_copy_descriptors(eem_ss_function); +		if (!f->ss_descriptors) +			goto fail;  	}  	DBG(cdev, "CDC Ethernet (EEM): %s speed IN/%s OUT/%s\n", +			gadget_is_superspeed(c->cdev->gadget) ? "super" :  			gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full",  			eem->port.in_ep->name, eem->port.out_ep->name);  	return 0; @@ -287,11 +325,13 @@ eem_bind(struct usb_configuration *c, struct usb_function *f)  fail:  	if (f->descriptors)  		usb_free_descriptors(f->descriptors); +	if (f->hs_descriptors) +		usb_free_descriptors(f->hs_descriptors);  	/* we might as well release our claims on endpoints */ -	if (eem->port.out) +	if (eem->port.out_ep->desc)  		eem->port.out_ep->driver_data = NULL; -	if (eem->port.in) +	if (eem->port.in_ep->desc)  		eem->port.in_ep->driver_data = NULL;  	ERROR(cdev, "%s: can't bind, err %d\n", f->name, status); @@ -306,6 +346,8 @@ eem_unbind(struct usb_configuration *c, struct usb_function *f)  	DBG(c->cdev, "eem unbind\n"); +	if (gadget_is_superspeed(c->cdev->gadget)) +		usb_free_descriptors(f->ss_descriptors);  	if (gadget_is_dualspeed(c->cdev->gadget))  		usb_free_descriptors(f->hs_descriptors);  	usb_free_descriptors(f->descriptors); diff --git a/drivers/usb/gadget/f_fs.c b/drivers/usb/gadget/f_fs.c index 19fffccc370d..c161a9aaeb7e 100644 --- a/drivers/usb/gadget/f_fs.c +++ b/drivers/usb/gadget/f_fs.c @@ -1544,7 +1544,8 @@ static int ffs_func_eps_enable(struct ffs_function *func)  		ds = ep->descs[ep->descs[1] ? 1 : 0];  		ep->ep->driver_data = ep; -		ret = usb_ep_enable(ep->ep, ds); +		ep->ep->desc = ds; +		ret = usb_ep_enable(ep->ep);  		if (likely(!ret)) {  			epfile->ep = ep;  			epfile->in = usb_endpoint_dir_in(ds); diff --git a/drivers/usb/gadget/f_hid.c b/drivers/usb/gadget/f_hid.c index 598e7e2ab80c..403a48bcf560 100644 --- a/drivers/usb/gadget/f_hid.c +++ b/drivers/usb/gadget/f_hid.c @@ -59,8 +59,6 @@ struct f_hidg {  	struct cdev			cdev;  	struct usb_function		func;  	struct usb_ep			*in_ep; -	struct usb_endpoint_descriptor	*fs_in_ep_desc; -	struct usb_endpoint_descriptor	*hs_in_ep_desc;  };  static inline struct f_hidg *func_to_hidg(struct usb_function *f) @@ -416,7 +414,6 @@ static int hidg_set_alt(struct usb_function *f, unsigned intf, unsigned alt)  {  	struct usb_composite_dev		*cdev = f->config->cdev;  	struct f_hidg				*hidg = func_to_hidg(f); -	const struct usb_endpoint_descriptor	*ep_desc;  	int status = 0;  	VDBG(cdev, "hidg_set_alt intf:%d alt:%d\n", intf, alt); @@ -426,9 +423,13 @@ static int hidg_set_alt(struct usb_function *f, unsigned intf, unsigned alt)  		if (hidg->in_ep->driver_data != NULL)  			usb_ep_disable(hidg->in_ep); -		ep_desc = ep_choose(f->config->cdev->gadget, -				hidg->hs_in_ep_desc, hidg->fs_in_ep_desc); -		status = usb_ep_enable(hidg->in_ep, ep_desc); +		status = config_ep_by_speed(f->config->cdev->gadget, f, +					    hidg->in_ep); +		if (status) { +			ERROR(cdev, "config_ep_by_speed FAILED!\n"); +			goto fail; +		} +		status = usb_ep_enable(hidg->in_ep);  		if (status < 0) {  			ERROR(cdev, "Enable endpoint FAILED!\n");  			goto fail; @@ -498,21 +499,12 @@ static int __init hidg_bind(struct usb_configuration *c, struct usb_function *f)  	if (!f->descriptors)  		goto fail; -	hidg->fs_in_ep_desc = usb_find_endpoint(hidg_fs_descriptors, -						f->descriptors, -						&hidg_fs_in_ep_desc); -  	if (gadget_is_dualspeed(c->cdev->gadget)) {  		hidg_hs_in_ep_desc.bEndpointAddress =  			hidg_fs_in_ep_desc.bEndpointAddress;  		f->hs_descriptors = usb_copy_descriptors(hidg_hs_descriptors);  		if (!f->hs_descriptors)  			goto fail; -		hidg->hs_in_ep_desc = usb_find_endpoint(hidg_hs_descriptors, -							f->hs_descriptors, -							&hidg_hs_in_ep_desc); -	} else { -		hidg->hs_in_ep_desc = NULL;  	}  	mutex_init(&hidg->lock); diff --git a/drivers/usb/gadget/f_loopback.c b/drivers/usb/gadget/f_loopback.c index b37960f9e753..ca660d40b11a 100644 --- a/drivers/usb/gadget/f_loopback.c +++ b/drivers/usb/gadget/f_loopback.c @@ -118,6 +118,49 @@ static struct usb_descriptor_header *hs_loopback_descs[] = {  	NULL,  }; +/* super speed support: */ + +static struct usb_endpoint_descriptor ss_loop_source_desc = { +	.bLength =		USB_DT_ENDPOINT_SIZE, +	.bDescriptorType =	USB_DT_ENDPOINT, + +	.bmAttributes =		USB_ENDPOINT_XFER_BULK, +	.wMaxPacketSize =	cpu_to_le16(1024), +}; + +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, +	.bmAttributes =		0, +	.wBytesPerInterval =	0, +}; + +static struct usb_endpoint_descriptor ss_loop_sink_desc = { +	.bLength =		USB_DT_ENDPOINT_SIZE, +	.bDescriptorType =	USB_DT_ENDPOINT, + +	.bmAttributes =		USB_ENDPOINT_XFER_BULK, +	.wMaxPacketSize =	cpu_to_le16(1024), +}; + +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, +	.bmAttributes =		0, +	.wBytesPerInterval =	0, +}; + +static struct usb_descriptor_header *ss_loopback_descs[] = { +	(struct usb_descriptor_header *) &loopback_intf, +	(struct usb_descriptor_header *) &ss_loop_source_desc, +	(struct usb_descriptor_header *) &ss_loop_source_comp_desc, +	(struct usb_descriptor_header *) &ss_loop_sink_desc, +	(struct usb_descriptor_header *) &ss_loop_sink_comp_desc, +	NULL, +}; +  /* function-specific strings: */  static struct usb_string strings_loopback[] = { @@ -175,8 +218,18 @@ autoconf_fail:  		f->hs_descriptors = hs_loopback_descs;  	} +	/* support super speed hardware */ +	if (gadget_is_superspeed(c->cdev->gadget)) { +		ss_loop_source_desc.bEndpointAddress = +				fs_loop_source_desc.bEndpointAddress; +		ss_loop_sink_desc.bEndpointAddress = +				fs_loop_sink_desc.bEndpointAddress; +		f->ss_descriptors = ss_loopback_descs; +	} +  	DBG(cdev, "%s speed %s: IN/%s, OUT/%s\n", -			gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full", +	    (gadget_is_superspeed(c->cdev->gadget) ? "super" : +	     (gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full")),  			f->name, loop->in_ep->name, loop->out_ep->name);  	return 0;  } @@ -250,26 +303,27 @@ static int  enable_loopback(struct usb_composite_dev *cdev, struct f_loopback *loop)  {  	int					result = 0; -	const struct usb_endpoint_descriptor	*src, *sink;  	struct usb_ep				*ep;  	struct usb_request			*req;  	unsigned				i; -	src = ep_choose(cdev->gadget, -			&hs_loop_source_desc, &fs_loop_source_desc); -	sink = ep_choose(cdev->gadget, -			&hs_loop_sink_desc, &fs_loop_sink_desc); -  	/* one endpoint writes data back IN to the host */  	ep = loop->in_ep; -	result = usb_ep_enable(ep, src); +	result = config_ep_by_speed(cdev->gadget, &(loop->function), ep); +	if (result) +		return result; +	result = usb_ep_enable(ep);  	if (result < 0)  		return result;  	ep->driver_data = loop;  	/* one endpoint just reads OUT packets */  	ep = loop->out_ep; -	result = usb_ep_enable(ep, sink); +	result = config_ep_by_speed(cdev->gadget, &(loop->function), ep); +	if (result) +		goto fail0; + +	result = usb_ep_enable(ep);  	if (result < 0) {  fail0:  		ep = loop->in_ep; diff --git a/drivers/usb/gadget/f_mass_storage.c b/drivers/usb/gadget/f_mass_storage.c index efb58f9f5aa9..5b9339582007 100644 --- a/drivers/usb/gadget/f_mass_storage.c +++ b/drivers/usb/gadget/f_mass_storage.c @@ -2324,18 +2324,6 @@ static int get_next_command(struct fsg_common *common)  /*-------------------------------------------------------------------------*/ -static int enable_endpoint(struct fsg_common *common, struct usb_ep *ep, -		const struct usb_endpoint_descriptor *d) -{ -	int	rc; - -	ep->driver_data = common; -	rc = usb_ep_enable(ep, d); -	if (rc) -		ERROR(common, "can't enable %s, result %d\n", ep->name, rc); -	return rc; -} -  static int alloc_request(struct fsg_common *common, struct usb_ep *ep,  		struct usb_request **preq)  { @@ -2349,7 +2337,6 @@ static int alloc_request(struct fsg_common *common, struct usb_ep *ep,  /* Reset interface setting and re-init endpoint state (toggle etc). */  static int do_set_interface(struct fsg_common *common, struct fsg_dev *new_fsg)  { -	const struct usb_endpoint_descriptor *d;  	struct fsg_dev *fsg;  	int i, rc = 0; @@ -2396,20 +2383,26 @@ reset:  	fsg = common->fsg;  	/* Enable the endpoints */ -	d = fsg_ep_desc(common->gadget, -			&fsg_fs_bulk_in_desc, &fsg_hs_bulk_in_desc); -	rc = enable_endpoint(common, fsg->bulk_in, d); +	rc = config_ep_by_speed(common->gadget, &(fsg->function), fsg->bulk_in); +	if (rc) +		goto reset; +	rc = usb_ep_enable(fsg->bulk_in);  	if (rc)  		goto reset; +	fsg->bulk_in->driver_data = common;  	fsg->bulk_in_enabled = 1; -	d = fsg_ep_desc(common->gadget, -			&fsg_fs_bulk_out_desc, &fsg_hs_bulk_out_desc); -	rc = enable_endpoint(common, fsg->bulk_out, d); +	rc = config_ep_by_speed(common->gadget, &(fsg->function), +				fsg->bulk_out); +	if (rc) +		goto reset; +	rc = usb_ep_enable(fsg->bulk_out);  	if (rc)  		goto reset; +	fsg->bulk_out->driver_data = common;  	fsg->bulk_out_enabled = 1; -	common->bulk_out_maxpacket = le16_to_cpu(d->wMaxPacketSize); +	common->bulk_out_maxpacket = +		le16_to_cpu(fsg->bulk_out->desc->wMaxPacketSize);  	clear_bit(IGNORE_BULK_OUT, &fsg->atomic_bitflags);  	/* Allocate the requests */ diff --git a/drivers/usb/gadget/f_ncm.c b/drivers/usb/gadget/f_ncm.c index 86902a60bcdb..ae69ed7e6b99 100644 --- a/drivers/usb/gadget/f_ncm.c +++ b/drivers/usb/gadget/f_ncm.c @@ -48,12 +48,6 @@  #define NCM_NDP_HDR_CRC		0x01000000  #define NCM_NDP_HDR_NOCRC	0x00000000 -struct ncm_ep_descs { -	struct usb_endpoint_descriptor	*in; -	struct usb_endpoint_descriptor	*out; -	struct usb_endpoint_descriptor	*notify; -}; -  enum ncm_notify_state {  	NCM_NOTIFY_NONE,		/* don't notify */  	NCM_NOTIFY_CONNECT,		/* issue CONNECT next */ @@ -66,11 +60,7 @@ struct f_ncm {  	char				ethaddr[14]; -	struct ncm_ep_descs		fs; -	struct ncm_ep_descs		hs; -  	struct usb_ep			*notify; -	struct usb_endpoint_descriptor	*notify_desc;  	struct usb_request		*notify_req;  	u8				notify_state;  	bool				is_open; @@ -802,13 +792,14 @@ static int ncm_set_alt(struct usb_function *f, unsigned intf, unsigned alt)  		if (ncm->notify->driver_data) {  			DBG(cdev, "reset ncm control %d\n", intf);  			usb_ep_disable(ncm->notify); -		} else { +		} + +		if (!(ncm->notify->desc)) {  			DBG(cdev, "init ncm ctrl %d\n", intf); -			ncm->notify_desc = ep_choose(cdev->gadget, -					ncm->hs.notify, -					ncm->fs.notify); +			if (config_ep_by_speed(cdev->gadget, f, ncm->notify)) +				goto fail;  		} -		usb_ep_enable(ncm->notify, ncm->notify_desc); +		usb_ep_enable(ncm->notify);  		ncm->notify->driver_data = ncm;  	/* Data interface has two altsettings, 0 and 1 */ @@ -829,14 +820,17 @@ static int ncm_set_alt(struct usb_function *f, unsigned intf, unsigned alt)  		if (alt == 1) {  			struct net_device	*net; -			if (!ncm->port.in) { +			if (!ncm->port.in_ep->desc || +			    !ncm->port.out_ep->desc) {  				DBG(cdev, "init ncm\n"); -				ncm->port.in = ep_choose(cdev->gadget, -							 ncm->hs.in, -							 ncm->fs.in); -				ncm->port.out = ep_choose(cdev->gadget, -							  ncm->hs.out, -							  ncm->fs.out); +				if (config_ep_by_speed(cdev->gadget, f, +						       ncm->port.in_ep) || +				    config_ep_by_speed(cdev->gadget, f, +						       ncm->port.out_ep)) { +					ncm->port.in_ep->desc = NULL; +					ncm->port.out_ep->desc = NULL; +					goto fail; +				}  			}  			/* TODO */ @@ -1111,7 +1105,7 @@ static void ncm_disable(struct usb_function *f)  	if (ncm->notify->driver_data) {  		usb_ep_disable(ncm->notify);  		ncm->notify->driver_data = NULL; -		ncm->notify_desc = NULL; +		ncm->notify->desc = NULL;  	}  } @@ -1228,13 +1222,6 @@ ncm_bind(struct usb_configuration *c, struct usb_function *f)  	if (!f->descriptors)  		goto fail; -	ncm->fs.in = usb_find_endpoint(ncm_fs_function, -			f->descriptors, &fs_ncm_in_desc); -	ncm->fs.out = usb_find_endpoint(ncm_fs_function, -			f->descriptors, &fs_ncm_out_desc); -	ncm->fs.notify = usb_find_endpoint(ncm_fs_function, -			f->descriptors, &fs_ncm_notify_desc); -  	/*  	 * support all relevant hardware speeds... we expect that when  	 * hardware is dual speed, all bulk-capable endpoints work at @@ -1252,13 +1239,6 @@ ncm_bind(struct usb_configuration *c, struct usb_function *f)  		f->hs_descriptors = usb_copy_descriptors(ncm_hs_function);  		if (!f->hs_descriptors)  			goto fail; - -		ncm->hs.in = usb_find_endpoint(ncm_hs_function, -				f->hs_descriptors, &hs_ncm_in_desc); -		ncm->hs.out = usb_find_endpoint(ncm_hs_function, -				f->hs_descriptors, &hs_ncm_out_desc); -		ncm->hs.notify = usb_find_endpoint(ncm_hs_function, -				f->hs_descriptors, &hs_ncm_notify_desc);  	}  	/* @@ -1288,9 +1268,9 @@ fail:  	/* we might as well release our claims on endpoints */  	if (ncm->notify)  		ncm->notify->driver_data = NULL; -	if (ncm->port.out) +	if (ncm->port.out_ep->desc)  		ncm->port.out_ep->driver_data = NULL; -	if (ncm->port.in) +	if (ncm->port.in_ep->desc)  		ncm->port.in_ep->driver_data = NULL;  	ERROR(cdev, "%s: can't bind, err %d\n", f->name, status); diff --git a/drivers/usb/gadget/f_obex.c b/drivers/usb/gadget/f_obex.c index 8f8c64371475..394502abeb96 100644 --- a/drivers/usb/gadget/f_obex.c +++ b/drivers/usb/gadget/f_obex.c @@ -39,20 +39,12 @@   * ready to handle the commands.   */ -struct obex_ep_descs { -	struct usb_endpoint_descriptor	*obex_in; -	struct usb_endpoint_descriptor	*obex_out; -}; -  struct f_obex {  	struct gserial			port;  	u8				ctrl_id;  	u8				data_id;  	u8				port_num;  	u8				can_activate; - -	struct obex_ep_descs		fs; -	struct obex_ep_descs		hs;  };  static inline struct f_obex *func_to_obex(struct usb_function *f) @@ -227,12 +219,16 @@ static int obex_set_alt(struct usb_function *f, unsigned intf, unsigned alt)  			gserial_disconnect(&obex->port);  		} -		if (!obex->port.in_desc) { +		if (!obex->port.in->desc || !obex->port.out->desc) {  			DBG(cdev, "init obex ttyGS%d\n", obex->port_num); -			obex->port.in_desc = ep_choose(cdev->gadget, -					obex->hs.obex_in, obex->fs.obex_in); -			obex->port.out_desc = ep_choose(cdev->gadget, -					obex->hs.obex_out, obex->fs.obex_out); +			if (config_ep_by_speed(cdev->gadget, f, +					       obex->port.in) || +			    config_ep_by_speed(cdev->gadget, f, +					       obex->port.out)) { +				obex->port.out->desc = NULL; +				obex->port.in->desc = NULL; +				goto fail; +			}  		}  		if (alt == 1) { @@ -346,11 +342,6 @@ obex_bind(struct usb_configuration *c, struct usb_function *f)  	/* copy descriptors, and track endpoint copies */  	f->descriptors = usb_copy_descriptors(fs_function); -	obex->fs.obex_in = usb_find_endpoint(fs_function, -			f->descriptors, &obex_fs_ep_in_desc); -	obex->fs.obex_out = usb_find_endpoint(fs_function, -			f->descriptors, &obex_fs_ep_out_desc); -  	/* support all relevant hardware speeds... we expect that when  	 * hardware is dual speed, all bulk-capable endpoints work at  	 * both speeds @@ -364,11 +355,6 @@ obex_bind(struct usb_configuration *c, struct usb_function *f)  		/* copy descriptors, and track endpoint copies */  		f->hs_descriptors = usb_copy_descriptors(hs_function); - -		obex->hs.obex_in = usb_find_endpoint(hs_function, -				f->hs_descriptors, &obex_hs_ep_in_desc); -		obex->hs.obex_out = usb_find_endpoint(hs_function, -				f->hs_descriptors, &obex_hs_ep_out_desc);  	}  	/* Avoid letting this gadget enumerate until the userspace diff --git a/drivers/usb/gadget/f_phonet.c b/drivers/usb/gadget/f_phonet.c index 5e1495097ec3..8f8d3f6cd89e 100644 --- a/drivers/usb/gadget/f_phonet.c +++ b/drivers/usb/gadget/f_phonet.c @@ -20,6 +20,7 @@   * 02110-1301 USA   */ +#include <linux/mm.h>  #include <linux/slab.h>  #include <linux/kernel.h>  #include <linux/device.h> @@ -427,17 +428,16 @@ static int pn_set_alt(struct usb_function *f, unsigned intf, unsigned alt)  		spin_lock(&port->lock);  		__pn_reset(f);  		if (alt == 1) { -			struct usb_endpoint_descriptor *out, *in;  			int i; -			out = ep_choose(gadget, -					&pn_hs_sink_desc, -					&pn_fs_sink_desc); -			in = ep_choose(gadget, -					&pn_hs_source_desc, -					&pn_fs_source_desc); -			usb_ep_enable(fp->out_ep, out); -			usb_ep_enable(fp->in_ep, in); +			if (config_ep_by_speed(gadget, f, fp->in_ep) || +			    config_ep_by_speed(gadget, f, fp->out_ep)) { +				fp->in_ep->desc = NULL; +				fp->out_ep->desc = NULL; +				return -EINVAL; +			} +			usb_ep_enable(fp->out_ep); +			usb_ep_enable(fp->in_ep);  			port->usb = fp;  			fp->out_ep->driver_data = fp; diff --git a/drivers/usb/gadget/f_rndis.c b/drivers/usb/gadget/f_rndis.c index fa12ec8364ef..3ea4666be3d0 100644 --- a/drivers/usb/gadget/f_rndis.c +++ b/drivers/usb/gadget/f_rndis.c @@ -29,7 +29,7 @@  #include <linux/device.h>  #include <linux/etherdevice.h> -#include <asm/atomic.h> +#include <linux/atomic.h>  #include "u_ether.h"  #include "rndis.h" @@ -76,23 +76,13 @@   *   - MS-Windows drivers sometimes emit undocumented requests.   */ -struct rndis_ep_descs { -	struct usb_endpoint_descriptor	*in; -	struct usb_endpoint_descriptor	*out; -	struct usb_endpoint_descriptor	*notify; -}; -  struct f_rndis {  	struct gether			port;  	u8				ctrl_id, data_id;  	u8				ethaddr[ETH_ALEN];  	int				config; -	struct rndis_ep_descs		fs; -	struct rndis_ep_descs		hs; -  	struct usb_ep			*notify; -	struct usb_endpoint_descriptor	*notify_desc;  	struct usb_request		*notify_req;  	atomic_t			notify_count;  }; @@ -105,10 +95,12 @@ static inline struct f_rndis *func_to_rndis(struct usb_function *f)  /* peak (theoretical) bulk transfer rate in bits-per-second */  static unsigned int bitrate(struct usb_gadget *g)  { -	if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH) +	if (gadget_is_superspeed(g) && g->speed == USB_SPEED_SUPER) +		return 13 * 1024 * 8 * 1000 * 8; +	else if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH)  		return 13 * 512 * 8 * 1000 * 8;  	else -		return 19 *  64 * 1 * 1000 * 8; +		return 19 * 64 * 1 * 1000 * 8;  }  /*-------------------------------------------------------------------------*/ @@ -226,6 +218,7 @@ static struct usb_endpoint_descriptor fs_out_desc = {  static struct usb_descriptor_header *eth_fs_function[] = {  	(struct usb_descriptor_header *) &rndis_iad_descriptor, +  	/* control interface matches ACM, not Ethernet */  	(struct usb_descriptor_header *) &rndis_control_intf,  	(struct usb_descriptor_header *) &header_desc, @@ -233,6 +226,7 @@ static struct usb_descriptor_header *eth_fs_function[] = {  	(struct usb_descriptor_header *) &rndis_acm_descriptor,  	(struct usb_descriptor_header *) &rndis_union_desc,  	(struct usb_descriptor_header *) &fs_notify_desc, +  	/* data interface has no altsetting */  	(struct usb_descriptor_header *) &rndis_data_intf,  	(struct usb_descriptor_header *) &fs_in_desc, @@ -251,6 +245,7 @@ static struct usb_endpoint_descriptor hs_notify_desc = {  	.wMaxPacketSize =	cpu_to_le16(STATUS_BYTECOUNT),  	.bInterval =		LOG2_STATUS_INTERVAL_MSEC + 4,  }; +  static struct usb_endpoint_descriptor hs_in_desc = {  	.bLength =		USB_DT_ENDPOINT_SIZE,  	.bDescriptorType =	USB_DT_ENDPOINT, @@ -271,6 +266,7 @@ static struct usb_endpoint_descriptor hs_out_desc = {  static struct usb_descriptor_header *eth_hs_function[] = {  	(struct usb_descriptor_header *) &rndis_iad_descriptor, +  	/* control interface matches ACM, not Ethernet */  	(struct usb_descriptor_header *) &rndis_control_intf,  	(struct usb_descriptor_header *) &header_desc, @@ -278,6 +274,7 @@ static struct usb_descriptor_header *eth_hs_function[] = {  	(struct usb_descriptor_header *) &rndis_acm_descriptor,  	(struct usb_descriptor_header *) &rndis_union_desc,  	(struct usb_descriptor_header *) &hs_notify_desc, +  	/* data interface has no altsetting */  	(struct usb_descriptor_header *) &rndis_data_intf,  	(struct usb_descriptor_header *) &hs_in_desc, @@ -285,6 +282,76 @@ static struct usb_descriptor_header *eth_hs_function[] = {  	NULL,  }; +/* super speed support: */ + +static struct usb_endpoint_descriptor ss_notify_desc = { +	.bLength =		USB_DT_ENDPOINT_SIZE, +	.bDescriptorType =	USB_DT_ENDPOINT, + +	.bEndpointAddress =	USB_DIR_IN, +	.bmAttributes =		USB_ENDPOINT_XFER_INT, +	.wMaxPacketSize =	cpu_to_le16(STATUS_BYTECOUNT), +	.bInterval =		LOG2_STATUS_INTERVAL_MSEC + 4, +}; + +static struct usb_ss_ep_comp_descriptor ss_intr_comp_desc = { +	.bLength =		sizeof ss_intr_comp_desc, +	.bDescriptorType =	USB_DT_SS_ENDPOINT_COMP, + +	/* the following 3 values can be tweaked if necessary */ +	/* .bMaxBurst =		0, */ +	/* .bmAttributes =	0, */ +	.wBytesPerInterval =	cpu_to_le16(STATUS_BYTECOUNT), +}; + +static struct usb_endpoint_descriptor ss_in_desc = { +	.bLength =		USB_DT_ENDPOINT_SIZE, +	.bDescriptorType =	USB_DT_ENDPOINT, + +	.bEndpointAddress =	USB_DIR_IN, +	.bmAttributes =		USB_ENDPOINT_XFER_BULK, +	.wMaxPacketSize =	cpu_to_le16(1024), +}; + +static struct usb_endpoint_descriptor ss_out_desc = { +	.bLength =		USB_DT_ENDPOINT_SIZE, +	.bDescriptorType =	USB_DT_ENDPOINT, + +	.bEndpointAddress =	USB_DIR_OUT, +	.bmAttributes =		USB_ENDPOINT_XFER_BULK, +	.wMaxPacketSize =	cpu_to_le16(1024), +}; + +static struct usb_ss_ep_comp_descriptor ss_bulk_comp_desc = { +	.bLength =		sizeof ss_bulk_comp_desc, +	.bDescriptorType =	USB_DT_SS_ENDPOINT_COMP, + +	/* the following 2 values can be tweaked if necessary */ +	/* .bMaxBurst =		0, */ +	/* .bmAttributes =	0, */ +}; + +static struct usb_descriptor_header *eth_ss_function[] = { +	(struct usb_descriptor_header *) &rndis_iad_descriptor, + +	/* control interface matches ACM, not Ethernet */ +	(struct usb_descriptor_header *) &rndis_control_intf, +	(struct usb_descriptor_header *) &header_desc, +	(struct usb_descriptor_header *) &call_mgmt_descriptor, +	(struct usb_descriptor_header *) &rndis_acm_descriptor, +	(struct usb_descriptor_header *) &rndis_union_desc, +	(struct usb_descriptor_header *) &ss_notify_desc, +	(struct usb_descriptor_header *) &ss_intr_comp_desc, + +	/* data interface has no altsetting */ +	(struct usb_descriptor_header *) &rndis_data_intf, +	(struct usb_descriptor_header *) &ss_in_desc, +	(struct usb_descriptor_header *) &ss_bulk_comp_desc, +	(struct usb_descriptor_header *) &ss_out_desc, +	(struct usb_descriptor_header *) &ss_bulk_comp_desc, +	NULL, +}; +  /* string descriptors: */  static struct usb_string rndis_string_defs[] = { @@ -484,13 +551,13 @@ static int rndis_set_alt(struct usb_function *f, unsigned intf, unsigned alt)  		if (rndis->notify->driver_data) {  			VDBG(cdev, "reset rndis control %d\n", intf);  			usb_ep_disable(rndis->notify); -		} else { +		} +		if (!rndis->notify->desc) {  			VDBG(cdev, "init rndis ctrl %d\n", intf); -			rndis->notify_desc = ep_choose(cdev->gadget, -					rndis->hs.notify, -					rndis->fs.notify); +			if (config_ep_by_speed(cdev->gadget, f, rndis->notify)) +				goto fail;  		} -		usb_ep_enable(rndis->notify, rndis->notify_desc); +		usb_ep_enable(rndis->notify);  		rndis->notify->driver_data = rndis;  	} else if (intf == rndis->data_id) { @@ -501,12 +568,16 @@ static int rndis_set_alt(struct usb_function *f, unsigned intf, unsigned alt)  			gether_disconnect(&rndis->port);  		} -		if (!rndis->port.in) { +		if (!rndis->port.in_ep->desc || !rndis->port.out_ep->desc) {  			DBG(cdev, "init rndis\n"); -			rndis->port.in = ep_choose(cdev->gadget, -					rndis->hs.in, rndis->fs.in); -			rndis->port.out = ep_choose(cdev->gadget, -					rndis->hs.out, rndis->fs.out); +			if (config_ep_by_speed(cdev->gadget, f, +					       rndis->port.in_ep) || +			    config_ep_by_speed(cdev->gadget, f, +					       rndis->port.out_ep)) { +				rndis->port.in_ep->desc = NULL; +				rndis->port.out_ep->desc = NULL; +				goto fail; +			}  		}  		/* Avoid ZLPs; they can be troublesome. */ @@ -662,13 +733,6 @@ rndis_bind(struct usb_configuration *c, struct usb_function *f)  	if (!f->descriptors)  		goto fail; -	rndis->fs.in = usb_find_endpoint(eth_fs_function, -			f->descriptors, &fs_in_desc); -	rndis->fs.out = usb_find_endpoint(eth_fs_function, -			f->descriptors, &fs_out_desc); -	rndis->fs.notify = usb_find_endpoint(eth_fs_function, -			f->descriptors, &fs_notify_desc); -  	/* support all relevant hardware speeds... we expect that when  	 * hardware is dual speed, all bulk-capable endpoints work at  	 * both speeds @@ -683,16 +747,22 @@ rndis_bind(struct usb_configuration *c, struct usb_function *f)  		/* copy descriptors, and track endpoint copies */  		f->hs_descriptors = usb_copy_descriptors(eth_hs_function); -  		if (!f->hs_descriptors)  			goto fail; +	} -		rndis->hs.in = usb_find_endpoint(eth_hs_function, -				f->hs_descriptors, &hs_in_desc); -		rndis->hs.out = usb_find_endpoint(eth_hs_function, -				f->hs_descriptors, &hs_out_desc); -		rndis->hs.notify = usb_find_endpoint(eth_hs_function, -				f->hs_descriptors, &hs_notify_desc); +	if (gadget_is_superspeed(c->cdev->gadget)) { +		ss_in_desc.bEndpointAddress = +				fs_in_desc.bEndpointAddress; +		ss_out_desc.bEndpointAddress = +				fs_out_desc.bEndpointAddress; +		ss_notify_desc.bEndpointAddress = +				fs_notify_desc.bEndpointAddress; + +		/* copy descriptors, and track endpoint copies */ +		f->ss_descriptors = usb_copy_descriptors(eth_ss_function); +		if (!f->ss_descriptors) +			goto fail;  	}  	rndis->port.open = rndis_open; @@ -719,12 +789,15 @@ rndis_bind(struct usb_configuration *c, struct usb_function *f)  	 */  	DBG(cdev, "RNDIS: %s speed IN/%s OUT/%s NOTIFY/%s\n", +			gadget_is_superspeed(c->cdev->gadget) ? "super" :  			gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full",  			rndis->port.in_ep->name, rndis->port.out_ep->name,  			rndis->notify->name);  	return 0;  fail: +	if (gadget_is_superspeed(c->cdev->gadget) && f->ss_descriptors) +		usb_free_descriptors(f->ss_descriptors);  	if (gadget_is_dualspeed(c->cdev->gadget) && f->hs_descriptors)  		usb_free_descriptors(f->hs_descriptors);  	if (f->descriptors) @@ -738,9 +811,9 @@ fail:  	/* we might as well release our claims on endpoints */  	if (rndis->notify)  		rndis->notify->driver_data = NULL; -	if (rndis->port.out) +	if (rndis->port.out_ep->desc)  		rndis->port.out_ep->driver_data = NULL; -	if (rndis->port.in) +	if (rndis->port.in_ep->desc)  		rndis->port.in_ep->driver_data = NULL;  	ERROR(cdev, "%s: can't bind, err %d\n", f->name, status); @@ -756,6 +829,8 @@ rndis_unbind(struct usb_configuration *c, struct usb_function *f)  	rndis_deregister(rndis->config);  	rndis_exit(); +	if (gadget_is_superspeed(c->cdev->gadget)) +		usb_free_descriptors(f->ss_descriptors);  	if (gadget_is_dualspeed(c->cdev->gadget))  		usb_free_descriptors(f->hs_descriptors);  	usb_free_descriptors(f->descriptors); diff --git a/drivers/usb/gadget/f_serial.c b/drivers/usb/gadget/f_serial.c index 490b00b01a7d..91fdf790ed20 100644 --- a/drivers/usb/gadget/f_serial.c +++ b/drivers/usb/gadget/f_serial.c @@ -27,18 +27,10 @@   * if you can arrange appropriate host side drivers.   */ -struct gser_descs { -	struct usb_endpoint_descriptor	*in; -	struct usb_endpoint_descriptor	*out; -}; -  struct f_gser {  	struct gserial			port;  	u8				data_id;  	u8				port_num; - -	struct gser_descs		fs; -	struct gser_descs		hs;  };  static inline struct f_gser *func_to_gser(struct usb_function *f) @@ -136,12 +128,15 @@ static int gser_set_alt(struct usb_function *f, unsigned intf, unsigned alt)  	if (gser->port.in->driver_data) {  		DBG(cdev, "reset generic ttyGS%d\n", gser->port_num);  		gserial_disconnect(&gser->port); -	} else { +	} +	if (!gser->port.in->desc || !gser->port.out->desc) {  		DBG(cdev, "activate generic ttyGS%d\n", gser->port_num); -		gser->port.in_desc = ep_choose(cdev->gadget, -				gser->hs.in, gser->fs.in); -		gser->port.out_desc = ep_choose(cdev->gadget, -				gser->hs.out, gser->fs.out); +		if (!config_ep_by_speed(cdev->gadget, f, gser->port.in) || +		    !config_ep_by_speed(cdev->gadget, f, gser->port.out)) { +			gser->port.in->desc = NULL; +			gser->port.out->desc = NULL; +			return -EINVAL; +		}  	}  	gserial_connect(&gser->port, gser->port_num);  	return 0; @@ -193,12 +188,6 @@ gser_bind(struct usb_configuration *c, struct usb_function *f)  	/* copy descriptors, and track endpoint copies */  	f->descriptors = usb_copy_descriptors(gser_fs_function); -	gser->fs.in = usb_find_endpoint(gser_fs_function, -			f->descriptors, &gser_fs_in_desc); -	gser->fs.out = usb_find_endpoint(gser_fs_function, -			f->descriptors, &gser_fs_out_desc); - -  	/* support all relevant hardware speeds... we expect that when  	 * hardware is dual speed, all bulk-capable endpoints work at  	 * both speeds @@ -211,11 +200,6 @@ gser_bind(struct usb_configuration *c, struct usb_function *f)  		/* copy descriptors, and track endpoint copies */  		f->hs_descriptors = usb_copy_descriptors(gser_hs_function); - -		gser->hs.in = usb_find_endpoint(gser_hs_function, -				f->hs_descriptors, &gser_hs_in_desc); -		gser->hs.out = usb_find_endpoint(gser_hs_function, -				f->hs_descriptors, &gser_hs_out_desc);  	}  	DBG(cdev, "generic ttyGS%d: %s speed IN/%s OUT/%s\n", diff --git a/drivers/usb/gadget/f_sourcesink.c b/drivers/usb/gadget/f_sourcesink.c index e403a534dd55..e18b4f520951 100644 --- a/drivers/usb/gadget/f_sourcesink.c +++ b/drivers/usb/gadget/f_sourcesink.c @@ -131,6 +131,49 @@ static struct usb_descriptor_header *hs_source_sink_descs[] = {  	NULL,  }; +/* super speed support: */ + +static struct usb_endpoint_descriptor ss_source_desc = { +	.bLength =		USB_DT_ENDPOINT_SIZE, +	.bDescriptorType =	USB_DT_ENDPOINT, + +	.bmAttributes =		USB_ENDPOINT_XFER_BULK, +	.wMaxPacketSize =	cpu_to_le16(1024), +}; + +struct usb_ss_ep_comp_descriptor ss_source_comp_desc = { +	.bLength =		USB_DT_SS_EP_COMP_SIZE, +	.bDescriptorType =	USB_DT_SS_ENDPOINT_COMP, +	.bMaxBurst =		0, +	.bmAttributes =		0, +	.wBytesPerInterval =	0, +}; + +static struct usb_endpoint_descriptor ss_sink_desc = { +	.bLength =		USB_DT_ENDPOINT_SIZE, +	.bDescriptorType =	USB_DT_ENDPOINT, + +	.bmAttributes =		USB_ENDPOINT_XFER_BULK, +	.wMaxPacketSize =	cpu_to_le16(1024), +}; + +struct usb_ss_ep_comp_descriptor ss_sink_comp_desc = { +	.bLength =		USB_DT_SS_EP_COMP_SIZE, +	.bDescriptorType =	USB_DT_SS_ENDPOINT_COMP, +	.bMaxBurst =		0, +	.bmAttributes =		0, +	.wBytesPerInterval =	0, +}; + +static struct usb_descriptor_header *ss_source_sink_descs[] = { +	(struct usb_descriptor_header *) &source_sink_intf, +	(struct usb_descriptor_header *) &ss_source_desc, +	(struct usb_descriptor_header *) &ss_source_comp_desc, +	(struct usb_descriptor_header *) &ss_sink_desc, +	(struct usb_descriptor_header *) &ss_sink_comp_desc, +	NULL, +}; +  /* function-specific strings: */  static struct usb_string strings_sourcesink[] = { @@ -187,8 +230,18 @@ autoconf_fail:  		f->hs_descriptors = hs_source_sink_descs;  	} +	/* support super speed hardware */ +	if (gadget_is_superspeed(c->cdev->gadget)) { +		ss_source_desc.bEndpointAddress = +				fs_source_desc.bEndpointAddress; +		ss_sink_desc.bEndpointAddress = +				fs_sink_desc.bEndpointAddress; +		f->ss_descriptors = ss_source_sink_descs; +	} +  	DBG(cdev, "%s speed %s: IN/%s, OUT/%s\n", -			gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full", +	    (gadget_is_superspeed(c->cdev->gadget) ? "super" : +	     (gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full")),  			f->name, ss->in_ep->name, ss->out_ep->name);  	return 0;  } @@ -343,15 +396,14 @@ static int  enable_source_sink(struct usb_composite_dev *cdev, struct f_sourcesink *ss)  {  	int					result = 0; -	const struct usb_endpoint_descriptor	*src, *sink;  	struct usb_ep				*ep; -	src = ep_choose(cdev->gadget, &hs_source_desc, &fs_source_desc); -	sink = ep_choose(cdev->gadget, &hs_sink_desc, &fs_sink_desc); -  	/* one endpoint writes (sources) zeroes IN (to the host) */  	ep = ss->in_ep; -	result = usb_ep_enable(ep, src); +	result = config_ep_by_speed(cdev->gadget, &(ss->function), ep); +	if (result) +		return result; +	result = usb_ep_enable(ep);  	if (result < 0)  		return result;  	ep->driver_data = ss; @@ -367,7 +419,10 @@ fail:  	/* one endpoint reads (sinks) anything OUT (from the host) */  	ep = ss->out_ep; -	result = usb_ep_enable(ep, sink); +	result = config_ep_by_speed(cdev->gadget, &(ss->function), ep); +	if (result) +		goto fail; +	result = usb_ep_enable(ep);  	if (result < 0)  		goto fail;  	ep->driver_data = ss; @@ -435,6 +490,8 @@ static int sourcesink_setup(struct usb_configuration *c,  	u16			w_value = le16_to_cpu(ctrl->wValue);  	u16			w_length = le16_to_cpu(ctrl->wLength); +	req->length = USB_BUFSIZ; +  	/* composite driver infrastructure handles everything except  	 * the two control test requests.  	 */ diff --git a/drivers/usb/gadget/f_subset.c b/drivers/usb/gadget/f_subset.c index 8675ca415329..3dc53754ab60 100644 --- a/drivers/usb/gadget/f_subset.c +++ b/drivers/usb/gadget/f_subset.c @@ -57,18 +57,10 @@   * caring about specific product and vendor IDs.   */ -struct geth_descs { -	struct usb_endpoint_descriptor	*in; -	struct usb_endpoint_descriptor	*out; -}; -  struct f_gether {  	struct gether			port;  	char				ethaddr[14]; - -	struct geth_descs		fs; -	struct geth_descs		hs;  };  static inline struct f_gether *func_to_geth(struct usb_function *f) @@ -209,6 +201,46 @@ static struct usb_descriptor_header *hs_eth_function[] __initdata = {  	NULL,  }; +/* super speed support: */ + +static struct usb_endpoint_descriptor ss_subset_in_desc __initdata = { +	.bLength =		USB_DT_ENDPOINT_SIZE, +	.bDescriptorType =	USB_DT_ENDPOINT, + +	.bmAttributes =		USB_ENDPOINT_XFER_BULK, +	.wMaxPacketSize =	cpu_to_le16(1024), +}; + +static struct usb_endpoint_descriptor ss_subset_out_desc __initdata = { +	.bLength =		USB_DT_ENDPOINT_SIZE, +	.bDescriptorType =	USB_DT_ENDPOINT, + +	.bmAttributes =		USB_ENDPOINT_XFER_BULK, +	.wMaxPacketSize =	cpu_to_le16(1024), +}; + +static struct usb_ss_ep_comp_descriptor ss_subset_bulk_comp_desc __initdata = { +	.bLength =		sizeof ss_subset_bulk_comp_desc, +	.bDescriptorType =	USB_DT_SS_ENDPOINT_COMP, + +	/* the following 2 values can be tweaked if necessary */ +	/* .bMaxBurst =		0, */ +	/* .bmAttributes =	0, */ +}; + +static struct usb_descriptor_header *ss_eth_function[] __initdata = { +	(struct usb_descriptor_header *) &subset_data_intf, +	(struct usb_descriptor_header *) &mdlm_header_desc, +	(struct usb_descriptor_header *) &mdlm_desc, +	(struct usb_descriptor_header *) &mdlm_detail_desc, +	(struct usb_descriptor_header *) ðer_desc, +	(struct usb_descriptor_header *) &ss_subset_in_desc, +	(struct usb_descriptor_header *) &ss_subset_bulk_comp_desc, +	(struct usb_descriptor_header *) &ss_subset_out_desc, +	(struct usb_descriptor_header *) &ss_subset_bulk_comp_desc, +	NULL, +}; +  /* string descriptors: */  static struct usb_string geth_string_defs[] = { @@ -243,10 +275,12 @@ static int geth_set_alt(struct usb_function *f, unsigned intf, unsigned alt)  	}  	DBG(cdev, "init + activate cdc subset\n"); -	geth->port.in = ep_choose(cdev->gadget, -			geth->hs.in, geth->fs.in); -	geth->port.out = ep_choose(cdev->gadget, -			geth->hs.out, geth->fs.out); +	if (config_ep_by_speed(cdev->gadget, f, geth->port.in_ep) || +	    config_ep_by_speed(cdev->gadget, f, geth->port.out_ep)) { +		geth->port.in_ep->desc = NULL; +		geth->port.out_ep->desc = NULL; +		return -EINVAL; +	}  	net = gether_connect(&geth->port);  	return IS_ERR(net) ? PTR_ERR(net) : 0; @@ -296,12 +330,8 @@ geth_bind(struct usb_configuration *c, struct usb_function *f)  	/* copy descriptors, and track endpoint copies */  	f->descriptors = usb_copy_descriptors(fs_eth_function); - -	geth->fs.in = usb_find_endpoint(fs_eth_function, -			f->descriptors, &fs_subset_in_desc); -	geth->fs.out = usb_find_endpoint(fs_eth_function, -			f->descriptors, &fs_subset_out_desc); - +	if (!f->descriptors) +		goto fail;  	/* support all relevant hardware speeds... we expect that when  	 * hardware is dual speed, all bulk-capable endpoints work at @@ -315,11 +345,20 @@ geth_bind(struct usb_configuration *c, struct usb_function *f)  		/* copy descriptors, and track endpoint copies */  		f->hs_descriptors = usb_copy_descriptors(hs_eth_function); +		if (!f->hs_descriptors) +			goto fail; +	} -		geth->hs.in = usb_find_endpoint(hs_eth_function, -				f->hs_descriptors, &hs_subset_in_desc); -		geth->hs.out = usb_find_endpoint(hs_eth_function, -				f->hs_descriptors, &hs_subset_out_desc); +	if (gadget_is_superspeed(c->cdev->gadget)) { +		ss_subset_in_desc.bEndpointAddress = +				fs_subset_in_desc.bEndpointAddress; +		ss_subset_out_desc.bEndpointAddress = +				fs_subset_out_desc.bEndpointAddress; + +		/* copy descriptors, and track endpoint copies */ +		f->ss_descriptors = usb_copy_descriptors(ss_eth_function); +		if (!f->ss_descriptors) +			goto fail;  	}  	/* NOTE:  all that is done without knowing or caring about @@ -328,15 +367,21 @@ geth_bind(struct usb_configuration *c, struct usb_function *f)  	 */  	DBG(cdev, "CDC Subset: %s speed IN/%s OUT/%s\n", +			gadget_is_superspeed(c->cdev->gadget) ? "super" :  			gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full",  			geth->port.in_ep->name, geth->port.out_ep->name);  	return 0;  fail: +	if (f->descriptors) +		usb_free_descriptors(f->descriptors); +	if (f->hs_descriptors) +		usb_free_descriptors(f->hs_descriptors); +  	/* we might as well release our claims on endpoints */ -	if (geth->port.out) +	if (geth->port.out_ep->desc)  		geth->port.out_ep->driver_data = NULL; -	if (geth->port.in) +	if (geth->port.in_ep->desc)  		geth->port.in_ep->driver_data = NULL;  	ERROR(cdev, "%s: can't bind, err %d\n", f->name, status); @@ -347,6 +392,8 @@ fail:  static void  geth_unbind(struct usb_configuration *c, struct usb_function *f)  { +	if (gadget_is_superspeed(c->cdev->gadget)) +		usb_free_descriptors(f->ss_descriptors);  	if (gadget_is_dualspeed(c->cdev->gadget))  		usb_free_descriptors(f->hs_descriptors);  	usb_free_descriptors(f->descriptors); diff --git a/drivers/usb/gadget/f_uvc.c b/drivers/usb/gadget/f_uvc.c index be446b7e7eaa..7a8b9aa4aea5 100644 --- a/drivers/usb/gadget/f_uvc.c +++ b/drivers/usb/gadget/f_uvc.c @@ -262,8 +262,10 @@ uvc_function_set_alt(struct usb_function *f, unsigned interface, unsigned alt)  		if (uvc->state != UVC_STATE_CONNECTED)  			return 0; -		if (uvc->video.ep) -			usb_ep_enable(uvc->video.ep, &uvc_streaming_ep); +		if (uvc->video.ep) { +			uvc->video.ep->desc = &uvc_streaming_ep; +			usb_ep_enable(uvc->video.ep); +		}  		memset(&v4l2_event, 0, sizeof(v4l2_event));  		v4l2_event.type = UVC_EVENT_STREAMON; @@ -649,7 +651,7 @@ uvc_bind_config(struct usb_configuration *c,  	if (ret)  		kfree(uvc); -	return 0; +	return ret;  error:  	kfree(uvc); diff --git a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c index 0360f56221ea..639e14a2fd15 100644 --- a/drivers/usb/gadget/file_storage.c +++ b/drivers/usb/gadget/file_storage.c @@ -929,6 +929,7 @@ static int standard_setup_req(struct fsg_dev *fsg,  		case USB_DT_DEVICE:  			VDBG(fsg, "get device descriptor\n"); +			device_desc.bMaxPacketSize0 = fsg->ep0->maxpacket;  			value = sizeof device_desc;  			memcpy(req->buf, &device_desc, value);  			break; @@ -936,6 +937,11 @@ static int standard_setup_req(struct fsg_dev *fsg,  			VDBG(fsg, "get device qualifier\n");  			if (!gadget_is_dualspeed(fsg->gadget))  				break; +			/* +			 * Assume ep0 uses the same maxpacket value for both +			 * speeds +			 */ +			dev_qualifier.bMaxPacketSize0 = fsg->ep0->maxpacket;  			value = sizeof dev_qualifier;  			memcpy(req->buf, &dev_qualifier, value);  			break; @@ -2713,7 +2719,8 @@ static int enable_endpoint(struct fsg_dev *fsg, struct usb_ep *ep,  	int	rc;  	ep->driver_data = fsg; -	rc = usb_ep_enable(ep, d); +	ep->desc = d; +	rc = usb_ep_enable(ep);  	if (rc)  		ERROR(fsg, "can't enable %s, result %d\n", ep->name, rc);  	return rc; @@ -3416,7 +3423,6 @@ static int __init fsg_bind(struct usb_gadget *gadget)  	}  	/* Fix up the descriptors */ -	device_desc.bMaxPacketSize0 = fsg->ep0->maxpacket;  	device_desc.idVendor = cpu_to_le16(mod_data.vendor);  	device_desc.idProduct = cpu_to_le16(mod_data.product);  	device_desc.bcdDevice = cpu_to_le16(mod_data.release); @@ -3430,9 +3436,6 @@ static int __init fsg_bind(struct usb_gadget *gadget)  	if (gadget_is_dualspeed(gadget)) {  		fsg_hs_function[i + FSG_HS_FUNCTION_PRE_EP_ENTRIES] = NULL; -		/* Assume ep0 uses the same maxpacket value for both speeds */ -		dev_qualifier.bMaxPacketSize0 = fsg->ep0->maxpacket; -  		/* Assume endpoint addresses are the same for both speeds */  		fsg_hs_bulk_in_desc.bEndpointAddress =  			fsg_fs_bulk_in_desc.bEndpointAddress; @@ -3486,6 +3489,8 @@ static int __init fsg_bind(struct usb_gadget *gadget)  	}  	INFO(fsg, DRIVER_DESC ", version: " DRIVER_VERSION "\n"); +	INFO(fsg, "NOTE: This driver is deprecated.  " +			"Consider using g_mass_storage instead.\n");  	INFO(fsg, "Number of LUNs=%d\n", fsg->nluns);  	pathbuf = kmalloc(PATH_MAX, GFP_KERNEL); diff --git a/drivers/usb/gadget/fsl_qe_udc.c b/drivers/usb/gadget/fsl_qe_udc.c index 3a68e09309f7..3bf872e1ad39 100644 --- a/drivers/usb/gadget/fsl_qe_udc.c +++ b/drivers/usb/gadget/fsl_qe_udc.c @@ -1927,6 +1927,10 @@ static int qe_pullup(struct usb_gadget *gadget, int is_on)  	return -ENOTSUPP;  } +static int fsl_qe_start(struct usb_gadget_driver *driver, +		int (*bind)(struct usb_gadget *)); +static int fsl_qe_stop(struct usb_gadget_driver *driver); +  /* defined in usb_gadget.h */  static struct usb_gadget_ops qe_gadget_ops = {  	.get_frame = qe_get_frame, @@ -1935,6 +1939,8 @@ static struct usb_gadget_ops qe_gadget_ops = {  	.vbus_session = qe_vbus_session,  	.vbus_draw = qe_vbus_draw,  	.pullup = qe_pullup, +	.start = fsl_qe_start, +	.stop = fsl_qe_stop,  };  /*------------------------------------------------------------------------- @@ -2320,7 +2326,7 @@ static irqreturn_t qe_udc_irq(int irq, void *_udc)  /*-------------------------------------------------------------------------  	Gadget driver probe and unregister.   --------------------------------------------------------------------------*/ -int usb_gadget_probe_driver(struct usb_gadget_driver *driver, +static int fsl_qe_start(struct usb_gadget_driver *driver,  		int (*bind)(struct usb_gadget *))  {  	int retval; @@ -2369,9 +2375,8 @@ int usb_gadget_probe_driver(struct usb_gadget_driver *driver,  		udc_controller->gadget.name, driver->driver.name);  	return 0;  } -EXPORT_SYMBOL(usb_gadget_probe_driver); -int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) +static int fsl_qe_stop(struct usb_gadget_driver *driver)  {  	struct qe_ep *loop_ep;  	unsigned long flags; @@ -2411,7 +2416,6 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)  			driver->driver.name);  	return 0;  } -EXPORT_SYMBOL(usb_gadget_unregister_driver);  /* udc structure's alloc and setup, include ep-param alloc */  static struct qe_udc __devinit *qe_udc_config(struct platform_device *ofdev) @@ -2662,11 +2666,17 @@ static int __devinit qe_udc_probe(struct platform_device *ofdev)  	if (ret)  		goto err6; +	ret = usb_add_gadget_udc(&ofdev->dev, &udc_controller->gadget); +	if (ret) +		goto err7; +  	dev_info(udc_controller->dev,  			"%s USB controller initialized as device\n",  			(udc_controller->soc_type == PORT_QE) ? "QE" : "CPM");  	return 0; +err7: +	device_unregister(&udc_controller->gadget.dev);  err6:  	free_irq(udc_controller->usb_irq, udc_controller);  err5: @@ -2721,6 +2731,8 @@ static int __devexit qe_udc_remove(struct platform_device *ofdev)  	if (!udc_controller)  		return -ENODEV; +	usb_del_gadget_udc(&udc_controller->gadget); +  	udc_controller->done = &done;  	tasklet_disable(&udc_controller->rx_tasklet); diff --git a/drivers/usb/gadget/fsl_udc_core.c b/drivers/usb/gadget/fsl_udc_core.c index 2cd9a60c7f3a..de24a4233c25 100644 --- a/drivers/usb/gadget/fsl_udc_core.c +++ b/drivers/usb/gadget/fsl_udc_core.c @@ -46,7 +46,6 @@  #include <asm/system.h>  #include <asm/unaligned.h>  #include <asm/dma.h> -#include <asm/cacheflush.h>  #include "fsl_usb2_udc.h" @@ -118,6 +117,17 @@ static void (*_fsl_writel)(u32 v, unsigned __iomem *p);  #define fsl_readl(p)		(*_fsl_readl)((p))  #define fsl_writel(v, p)	(*_fsl_writel)((v), (p)) +static inline void fsl_set_accessors(struct fsl_usb2_platform_data *pdata) +{ +	if (pdata->big_endian_mmio) { +		_fsl_readl = _fsl_readl_be; +		_fsl_writel = _fsl_writel_be; +	} else { +		_fsl_readl = _fsl_readl_le; +		_fsl_writel = _fsl_writel_le; +	} +} +  static inline u32 cpu_to_hc32(const u32 x)  {  	return udc_controller->pdata->big_endian_desc @@ -132,6 +142,8 @@ static inline u32 hc32_to_cpu(const u32 x)  		: le32_to_cpu((__force __le32)x);  }  #else /* !CONFIG_PPC32 */ +static inline void fsl_set_accessors(struct fsl_usb2_platform_data *pdata) {} +  #define fsl_readl(addr)		readl(addr)  #define fsl_writel(val32, addr) writel(val32, addr)  #define cpu_to_hc32(x)		cpu_to_le32(x) @@ -1232,6 +1244,9 @@ static int fsl_pullup(struct usb_gadget *gadget, int is_on)  	return 0;  } +static int fsl_start(struct usb_gadget_driver *driver, +		int (*bind)(struct usb_gadget *)); +static int fsl_stop(struct usb_gadget_driver *driver);  /* defined in gadget.h */  static struct usb_gadget_ops fsl_gadget_ops = {  	.get_frame = fsl_get_frame, @@ -1240,6 +1255,8 @@ static struct usb_gadget_ops fsl_gadget_ops = {  	.vbus_session = fsl_vbus_session,  	.vbus_draw = fsl_vbus_draw,  	.pullup = fsl_pullup, +	.start = fsl_start, +	.stop = fsl_stop,  };  /* Set protocol stall on ep0, protocol stall will automatically be cleared @@ -1277,6 +1294,11 @@ static int ep0_prime_status(struct fsl_udc *udc, int direction)  	req->req.complete = NULL;  	req->dtd_count = 0; +	req->req.dma = dma_map_single(ep->udc->gadget.dev.parent, +			req->req.buf, req->req.length, +			ep_is_in(ep) ? DMA_TO_DEVICE : DMA_FROM_DEVICE); +	req->mapped = 1; +  	if (fsl_req_to_dtd(req) == 0)  		fsl_queue_td(ep, req);  	else @@ -1348,9 +1370,6 @@ static void ch9getstatus(struct fsl_udc *udc, u8 request_type, u16 value,  	/* Fill in the reqest structure */  	*((u16 *) req->req.buf) = cpu_to_le16(tmp); -	/* flush cache for the req buffer */ -	flush_dcache_range((u32)req->req.buf, (u32)req->req.buf + 8); -  	req->ep = ep;  	req->req.length = 2;  	req->req.status = -EINPROGRESS; @@ -1358,6 +1377,11 @@ static void ch9getstatus(struct fsl_udc *udc, u8 request_type, u16 value,  	req->req.complete = NULL;  	req->dtd_count = 0; +	req->req.dma = dma_map_single(ep->udc->gadget.dev.parent, +				req->req.buf, req->req.length, +				ep_is_in(ep) ? DMA_TO_DEVICE : DMA_FROM_DEVICE); +	req->mapped = 1; +  	/* prime the data phase */  	if ((fsl_req_to_dtd(req) == 0))  		fsl_queue_td(ep, req); @@ -1908,7 +1932,7 @@ static irqreturn_t fsl_udc_irq(int irq, void *_udc)   * Hook to gadget drivers   * Called by initialization code of gadget drivers  *----------------------------------------------------------------*/ -int usb_gadget_probe_driver(struct usb_gadget_driver *driver, +static int fsl_start(struct usb_gadget_driver *driver,  		int (*bind)(struct usb_gadget *))  {  	int retval = -ENODEV; @@ -1976,10 +2000,9 @@ out:  		       retval);  	return retval;  } -EXPORT_SYMBOL(usb_gadget_probe_driver);  /* Disconnect from gadget driver */ -int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) +static int fsl_stop(struct usb_gadget_driver *driver)  {  	struct fsl_ep *loop_ep;  	unsigned long flags; @@ -2022,7 +2045,6 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)  	       driver->driver.name);  	return 0;  } -EXPORT_SYMBOL(usb_gadget_unregister_driver);  /*-------------------------------------------------------------------------  		PROC File System Support @@ -2354,7 +2376,6 @@ static int __init struct_udc_setup(struct fsl_udc *udc,  			struct fsl_req, req);  	/* allocate a small amount of memory to get valid address */  	udc->status_req->req.buf = kmalloc(8, GFP_KERNEL); -	udc->status_req->req.dma = virt_to_phys(udc->status_req->req.buf);  	udc->resume_state = USB_STATE_NOTATTACHED;  	udc->usb_state = USB_STATE_POWERED; @@ -2445,7 +2466,7 @@ static int __init fsl_udc_probe(struct platform_device *pdev)  	}  	if (pdata->operating_mode == FSL_USB2_DR_DEVICE) { -		if (!request_mem_region(res->start, res->end - res->start + 1, +		if (!request_mem_region(res->start, resource_size(res),  					driver_name)) {  			ERR("request mem region for %s failed\n", pdev->name);  			ret = -EBUSY; @@ -2470,13 +2491,7 @@ static int __init fsl_udc_probe(struct platform_device *pdev)  	}  	/* Set accessors only after pdata->init() ! */ -	if (pdata->big_endian_mmio) { -		_fsl_readl = _fsl_readl_be; -		_fsl_writel = _fsl_writel_be; -	} else { -		_fsl_readl = _fsl_readl_le; -		_fsl_writel = _fsl_writel_le; -	} +	fsl_set_accessors(pdata);  #ifndef CONFIG_ARCH_MXC  	if (pdata->have_sysif_regs) @@ -2578,9 +2593,16 @@ static int __init fsl_udc_probe(struct platform_device *pdev)  		ret = -ENOMEM;  		goto err_unregister;  	} + +	ret = usb_add_gadget_udc(&pdev->dev, &udc_controller->gadget); +	if (ret) +		goto err_del_udc; +  	create_proc_file();  	return 0; +err_del_udc: +	dma_pool_destroy(udc_controller->td_pool);  err_unregister:  	device_unregister(&udc_controller->gadget.dev);  err_free_irq: @@ -2593,7 +2615,7 @@ err_iounmap_noclk:  	iounmap(dr_regs);  err_release_mem_region:  	if (pdata->operating_mode == FSL_USB2_DR_DEVICE) -		release_mem_region(res->start, res->end - res->start + 1); +		release_mem_region(res->start, resource_size(res));  err_kfree:  	kfree(udc_controller);  	udc_controller = NULL; @@ -2612,6 +2634,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;  	fsl_udc_clk_release(); @@ -2628,7 +2652,7 @@ static int __exit fsl_udc_remove(struct platform_device *pdev)  	free_irq(udc_controller->irq, udc_controller);  	iounmap(dr_regs);  	if (pdata->operating_mode == FSL_USB2_DR_DEVICE) -		release_mem_region(res->start, res->end - res->start + 1); +		release_mem_region(res->start, resource_size(res));  	device_unregister(&udc_controller->gadget.dev);  	/* free udc --wait for the release() finished */ diff --git a/drivers/usb/gadget/fusb300_udc.c b/drivers/usb/gadget/fusb300_udc.c index 763d462454b9..24a924330c81 100644 --- a/drivers/usb/gadget/fusb300_udc.c +++ b/drivers/usb/gadget/fusb300_udc.c @@ -767,56 +767,6 @@ static void fusb300_rdfifo(struct fusb300_ep *ep,  	} while (!reg);  } -/* write data to fifo */ -static void fusb300_wrfifo(struct fusb300_ep *ep, -			   struct fusb300_request *req) -{ -	int i = 0; -	u8 *tmp; -	u32 data, reg; -	struct fusb300 *fusb300 = ep->fusb300; - -	tmp = req->req.buf; -	req->req.actual = req->req.length; - -	for (i = (req->req.length >> 2); i > 0; i--) { -		data = *tmp | *(tmp + 1) << 8 | -			*(tmp + 2) << 16 | *(tmp + 3) << 24; - -		iowrite32(data, fusb300->reg + -			FUSB300_OFFSET_EPPORT(ep->epnum)); -		tmp += 4; -	} - -	switch (req->req.length % 4) { -	case 1: -		data = *tmp; -		iowrite32(data, fusb300->reg + -			FUSB300_OFFSET_EPPORT(ep->epnum)); -		break; -	case 2: -		data = *tmp | *(tmp + 1) << 8; -		iowrite32(data, fusb300->reg + -			FUSB300_OFFSET_EPPORT(ep->epnum)); -		break; -	case 3: -		data = *tmp | *(tmp + 1) << 8 | *(tmp + 2) << 16; -		iowrite32(data, fusb300->reg + -			FUSB300_OFFSET_EPPORT(ep->epnum)); -		break; -	default: -		break; -	} - -	do { -		reg = ioread32(fusb300->reg + FUSB300_OFFSET_IGR1); -		reg &= FUSB300_IGR1_SYNF0_EMPTY_INT; -		if (i) -			printk(KERN_INFO"sync fifo is not empty!\n"); -		i++; -	} while (!reg); -} -  static u8 fusb300_get_epnstall(struct fusb300 *fusb300, u8 ep)  {  	u8 value; @@ -980,11 +930,6 @@ static void set_address(struct fusb300 *fusb300, struct usb_ctrlrequest *ctrl)  		} \  	} while (0) -static void fusb300_ep0_complete(struct usb_ep *ep, -				struct usb_request *req) -{ -} -  static int setup_packet(struct fusb300 *fusb300, struct usb_ctrlrequest *ctrl)  {  	u8 *p = (u8 *)ctrl; @@ -1029,17 +974,6 @@ static int setup_packet(struct fusb300 *fusb300, struct usb_ctrlrequest *ctrl)  	return ret;  } -static void fusb300_set_ep_bycnt(struct fusb300_ep *ep, u32 bycnt) -{ -	struct fusb300 *fusb300 = ep->fusb300; -	u32 reg = ioread32(fusb300->reg + FUSB300_OFFSET_EPFFR(ep->epnum)); - -	reg &= ~FUSB300_FFR_BYCNT; -	reg |= bycnt & FUSB300_FFR_BYCNT; - -	iowrite32(reg, fusb300->reg + FUSB300_OFFSET_EPFFR(ep->epnum)); -} -  static void done(struct fusb300_ep *ep, struct fusb300_request *req,  		 int status)  { @@ -1063,8 +997,8 @@ static void done(struct fusb300_ep *ep, struct fusb300_request *req,  		fusb300_set_cxdone(ep->fusb300);  } -void fusb300_fill_idma_prdtbl(struct fusb300_ep *ep, -			struct fusb300_request *req) +static void fusb300_fill_idma_prdtbl(struct fusb300_ep *ep, dma_addr_t d, +		u32 len)  {  	u32 value;  	u32 reg; @@ -1076,10 +1010,9 @@ void fusb300_fill_idma_prdtbl(struct fusb300_ep *ep,  		reg &= FUSB300_EPPRD0_H;  	} while (reg); -	iowrite32((u32) req->req.buf, ep->fusb300->reg + -		FUSB300_OFFSET_EPPRD_W1(ep->epnum)); +	iowrite32(d, ep->fusb300->reg + FUSB300_OFFSET_EPPRD_W1(ep->epnum)); -	value = FUSB300_EPPRD0_BTC(req->req.length) | FUSB300_EPPRD0_H | +	value = FUSB300_EPPRD0_BTC(len) | FUSB300_EPPRD0_H |  		FUSB300_EPPRD0_F | FUSB300_EPPRD0_L | FUSB300_EPPRD0_I;  	iowrite32(value, ep->fusb300->reg + FUSB300_OFFSET_EPPRD_W0(ep->epnum)); @@ -1116,13 +1049,12 @@ static void  fusb300_set_idma(struct fusb300_ep *ep,  			struct fusb300_request *req)  {  	dma_addr_t d; -	u8 *tmp = NULL;  	d = dma_map_single(NULL, req->req.buf, req->req.length, DMA_TO_DEVICE);  	if (dma_mapping_error(NULL, d)) { -		kfree(req->req.buf);  		printk(KERN_DEBUG "dma_mapping_error\n"); +		return;  	}  	dma_sync_single_for_device(NULL, d, req->req.length, DMA_TO_DEVICE); @@ -1130,17 +1062,11 @@ static void  fusb300_set_idma(struct fusb300_ep *ep,  	fusb300_enable_bit(ep->fusb300, FUSB300_OFFSET_IGER0,  		FUSB300_IGER0_EEPn_PRD_INT(ep->epnum)); -	tmp = req->req.buf; -	req->req.buf = (u8 *)d; - -	fusb300_fill_idma_prdtbl(ep, req); +	fusb300_fill_idma_prdtbl(ep, d, req->req.length);  	/* check idma is done */  	fusb300_wait_idma_finished(ep); -	req->req.buf = tmp; - -	if (d) -		dma_unmap_single(NULL, d, req->req.length, DMA_TO_DEVICE); +	dma_unmap_single(NULL, d, req->req.length, DMA_TO_DEVICE);  }  static void in_ep_fifo_handler(struct fusb300_ep *ep) @@ -1148,14 +1074,8 @@ static void in_ep_fifo_handler(struct fusb300_ep *ep)  	struct fusb300_request *req = list_entry(ep->queue.next,  					struct fusb300_request, queue); -	if (req->req.length) { -#if 0 -		fusb300_set_ep_bycnt(ep, req->req.length); -		fusb300_wrfifo(ep, req); -#else +	if (req->req.length)  		fusb300_set_idma(ep, req); -#endif -	}  	done(ep, req, 0);  } @@ -1500,7 +1420,7 @@ static void init_controller(struct fusb300 *fusb300)  /*------------------------------------------------------------------------*/  static struct fusb300 *the_controller; -int usb_gadget_probe_driver(struct usb_gadget_driver *driver, +static int fusb300_udc_start(struct usb_gadget_driver *driver,  		int (*bind)(struct usb_gadget *))  {  	struct fusb300 *fusb300 = the_controller; @@ -1544,9 +1464,8 @@ error:  	return retval;  } -EXPORT_SYMBOL(usb_gadget_probe_driver); -int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) +static int fusb300_udc_stop(struct usb_gadget_driver *driver)  {  	struct fusb300 *fusb300 = the_controller; @@ -1562,7 +1481,6 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)  	return 0;  } -EXPORT_SYMBOL(usb_gadget_unregister_driver);  /*--------------------------------------------------------------------------*/  static int fusb300_udc_pullup(struct usb_gadget *_gadget, int is_active) @@ -1572,12 +1490,15 @@ static int fusb300_udc_pullup(struct usb_gadget *_gadget, int is_active)  static struct usb_gadget_ops fusb300_gadget_ops = {  	.pullup		= fusb300_udc_pullup, +	.start		= fusb300_udc_start, +	.stop		= fusb300_udc_stop,  };  static int __exit fusb300_remove(struct platform_device *pdev)  {  	struct fusb300 *fusb300 = dev_get_drvdata(&pdev->dev); +	usb_del_gadget_udc(&fusb300->gadget);  	iounmap(fusb300->reg);  	free_irq(platform_get_irq(pdev, 0), fusb300); @@ -1702,9 +1623,15 @@ static int __init fusb300_probe(struct platform_device *pdev)  		goto clean_up3;  	init_controller(fusb300); +	ret = usb_add_gadget_udc(&pdev->dev, &fusb300->gadget); +	if (ret) +		goto err_add_udc; +  	dev_info(&pdev->dev, "version %s\n", DRIVER_VERSION);  	return 0; +err_add_udc: +	fusb300_free_request(&fusb300->ep[0]->ep, fusb300->ep0_req);  clean_up3:  	free_irq(ires->start, fusb300); diff --git a/drivers/usb/gadget/g_ffs.c b/drivers/usb/gadget/g_ffs.c index ebf6970a10bf..704c2800ac00 100644 --- a/drivers/usb/gadget/g_ffs.c +++ b/drivers/usb/gadget/g_ffs.c @@ -162,6 +162,7 @@ static struct usb_composite_driver gfs_driver = {  	.name		= DRIVER_NAME,  	.dev		= &gfs_dev_desc,  	.strings	= gfs_dev_strings, +	.max_speed	= USB_SPEED_HIGH,  	.unbind		= gfs_unbind,  	.iProduct	= DRIVER_DESC,  }; diff --git a/drivers/usb/gadget/gadget_chips.h b/drivers/usb/gadget/gadget_chips.h index bcdac7c73e89..f3a83cd0ef50 100644 --- a/drivers/usb/gadget/gadget_chips.h +++ b/drivers/usb/gadget/gadget_chips.h @@ -15,150 +15,40 @@  #ifndef __GADGET_CHIPS_H  #define __GADGET_CHIPS_H -#ifdef CONFIG_USB_GADGET_NET2280 -#define	gadget_is_net2280(g)	!strcmp("net2280", (g)->name) -#else -#define	gadget_is_net2280(g)	0 -#endif - -#ifdef CONFIG_USB_GADGET_AMD5536UDC -#define	gadget_is_amd5536udc(g)	!strcmp("amd5536udc", (g)->name) -#else -#define	gadget_is_amd5536udc(g)	0 -#endif - -#ifdef CONFIG_USB_GADGET_DUMMY_HCD -#define	gadget_is_dummy(g)	!strcmp("dummy_udc", (g)->name) -#else -#define	gadget_is_dummy(g)	0 -#endif - -#ifdef CONFIG_USB_GADGET_PXA25X -#define	gadget_is_pxa(g)	!strcmp("pxa25x_udc", (g)->name) -#else -#define	gadget_is_pxa(g)	0 -#endif - -#ifdef CONFIG_USB_GADGET_GOKU -#define	gadget_is_goku(g)	!strcmp("goku_udc", (g)->name) -#else -#define	gadget_is_goku(g)	0 -#endif - -#ifdef CONFIG_USB_GADGET_OMAP -#define	gadget_is_omap(g)	!strcmp("omap_udc", (g)->name) -#else -#define	gadget_is_omap(g)	0 -#endif - -/* various unstable versions available */ -#ifdef CONFIG_USB_GADGET_PXA27X -#define	gadget_is_pxa27x(g)	!strcmp("pxa27x_udc", (g)->name) -#else -#define	gadget_is_pxa27x(g)	0 -#endif - -#ifdef CONFIG_USB_GADGET_ATMEL_USBA -#define gadget_is_atmel_usba(g)	!strcmp("atmel_usba_udc", (g)->name) -#else -#define gadget_is_atmel_usba(g)	0 -#endif - -#ifdef CONFIG_USB_GADGET_S3C2410 -#define gadget_is_s3c2410(g)    !strcmp("s3c2410_udc", (g)->name) -#else -#define gadget_is_s3c2410(g)    0 -#endif - -#ifdef CONFIG_USB_GADGET_AT91 -#define gadget_is_at91(g)	!strcmp("at91_udc", (g)->name) -#else -#define gadget_is_at91(g)	0 -#endif - -#ifdef CONFIG_USB_GADGET_IMX -#define gadget_is_imx(g)	!strcmp("imx_udc", (g)->name) -#else -#define gadget_is_imx(g)	0 -#endif - -#ifdef CONFIG_USB_GADGET_FSL_USB2 -#define gadget_is_fsl_usb2(g)	!strcmp("fsl-usb2-udc", (g)->name) -#else -#define gadget_is_fsl_usb2(g)	0 -#endif - -/* Mentor high speed "dual role" controller, in peripheral role */ -#ifdef CONFIG_USB_GADGET_MUSB_HDRC -#define gadget_is_musbhdrc(g)	!strcmp("musb-hdrc", (g)->name) -#else -#define gadget_is_musbhdrc(g)	0 -#endif - -#ifdef CONFIG_USB_GADGET_LANGWELL -#define gadget_is_langwell(g)	(!strcmp("langwell_udc", (g)->name)) -#else -#define gadget_is_langwell(g)	0 -#endif - -#ifdef CONFIG_USB_GADGET_M66592 -#define	gadget_is_m66592(g)	!strcmp("m66592_udc", (g)->name) -#else -#define	gadget_is_m66592(g)	0 -#endif - -/* Freescale CPM/QE UDC SUPPORT */ -#ifdef CONFIG_USB_GADGET_FSL_QE -#define gadget_is_fsl_qe(g)	!strcmp("fsl_qe_udc", (g)->name) -#else -#define gadget_is_fsl_qe(g)	0 -#endif - -#ifdef CONFIG_USB_GADGET_CI13XXX_PCI -#define gadget_is_ci13xxx_pci(g)	(!strcmp("ci13xxx_pci", (g)->name)) -#else -#define gadget_is_ci13xxx_pci(g)	0 -#endif - -// CONFIG_USB_GADGET_SX2 -// CONFIG_USB_GADGET_AU1X00 -// ... - -#ifdef CONFIG_USB_GADGET_R8A66597 -#define	gadget_is_r8a66597(g)	!strcmp("r8a66597_udc", (g)->name) -#else -#define	gadget_is_r8a66597(g)	0 -#endif - -#ifdef CONFIG_USB_S3C_HSOTG -#define gadget_is_s3c_hsotg(g)    (!strcmp("s3c-hsotg", (g)->name)) -#else -#define gadget_is_s3c_hsotg(g)    0 -#endif - -#ifdef CONFIG_USB_S3C_HSUDC -#define gadget_is_s3c_hsudc(g) (!strcmp("s3c-hsudc", (g)->name)) -#else -#define gadget_is_s3c_hsudc(g) 0 -#endif - -#ifdef CONFIG_USB_GADGET_EG20T -#define	gadget_is_pch(g)	(!strcmp("pch_udc", (g)->name)) -#else -#define	gadget_is_pch(g)	0 -#endif - -#ifdef CONFIG_USB_GADGET_CI13XXX_MSM +/* + * NOTICE: the entries below are alphabetical and should be kept + * that way. + * + * Always be sure to add new entries to the correct position or + * accept the bashing later. + * + * If you have forgotten the alphabetical order let VIM/EMACS + * do that for you. + */ +#define gadget_is_amd5536udc(g)		(!strcmp("amd5536udc", (g)->name)) +#define gadget_is_at91(g)		(!strcmp("at91_udc", (g)->name)) +#define gadget_is_atmel_usba(g)		(!strcmp("atmel_usba_udc", (g)->name))  #define gadget_is_ci13xxx_msm(g)	(!strcmp("ci13xxx_msm", (g)->name)) -#else -#define gadget_is_ci13xxx_msm(g)	0 -#endif - -#ifdef CONFIG_USB_GADGET_RENESAS_USBHS -#define	gadget_is_renesas_usbhs(g) (!strcmp("renesas_usbhs_udc", (g)->name)) -#else -#define	gadget_is_renesas_usbhs(g) 0 -#endif +#define gadget_is_ci13xxx_pci(g)	(!strcmp("ci13xxx_pci", (g)->name)) +#define gadget_is_dummy(g)		(!strcmp("dummy_udc", (g)->name)) +#define gadget_is_fsl_qe(g)		(!strcmp("fsl_qe_udc", (g)->name)) +#define gadget_is_fsl_usb2(g)		(!strcmp("fsl-usb2-udc", (g)->name)) +#define gadget_is_goku(g)		(!strcmp("goku_udc", (g)->name)) +#define gadget_is_imx(g)		(!strcmp("imx_udc", (g)->name)) +#define gadget_is_langwell(g)		(!strcmp("langwell_udc", (g)->name)) +#define gadget_is_m66592(g)		(!strcmp("m66592_udc", (g)->name)) +#define gadget_is_musbhdrc(g)		(!strcmp("musb-hdrc", (g)->name)) +#define gadget_is_net2272(g)		(!strcmp("net2272", (g)->name)) +#define gadget_is_net2280(g)		(!strcmp("net2280", (g)->name)) +#define gadget_is_omap(g)		(!strcmp("omap_udc", (g)->name)) +#define gadget_is_pch(g)		(!strcmp("pch_udc", (g)->name)) +#define gadget_is_pxa(g)		(!strcmp("pxa25x_udc", (g)->name)) +#define gadget_is_pxa27x(g)		(!strcmp("pxa27x_udc", (g)->name)) +#define gadget_is_r8a66597(g)		(!strcmp("r8a66597_udc", (g)->name)) +#define gadget_is_renesas_usbhs(g)	(!strcmp("renesas_usbhs_udc", (g)->name)) +#define gadget_is_s3c2410(g)		(!strcmp("s3c2410_udc", (g)->name)) +#define gadget_is_s3c_hsotg(g)		(!strcmp("s3c-hsotg", (g)->name)) +#define gadget_is_s3c_hsudc(g)		(!strcmp("s3c-hsudc", (g)->name))  /**   * usb_gadget_controller_number - support bcdDevice id convention @@ -223,6 +113,8 @@ static inline int usb_gadget_controller_number(struct usb_gadget *gadget)  		return 0x29;  	else if (gadget_is_s3c_hsudc(gadget))  		return 0x30; +	else if (gadget_is_net2272(gadget)) +		return 0x31;  	return -ENOENT;  } diff --git a/drivers/usb/gadget/gmidi.c b/drivers/usb/gadget/gmidi.c index 47b86b99d449..8b9220e128a7 100644 --- a/drivers/usb/gadget/gmidi.c +++ b/drivers/usb/gadget/gmidi.c @@ -537,14 +537,16 @@ static int set_gmidi_config(struct gmidi_device *dev, gfp_t gfp_flags)  	struct usb_ep *ep;  	unsigned i; -	err = usb_ep_enable(dev->in_ep, &bulk_in_desc); +	dev->in_ep->desc = &bulk_in_desc; +	err = usb_ep_enable(dev->in_ep);  	if (err) {  		ERROR(dev, "can't start %s: %d\n", dev->in_ep->name, err);  		goto fail;  	}  	dev->in_ep->driver_data = dev; -	err = usb_ep_enable(dev->out_ep, &bulk_out_desc); +	dev->out_ep->desc = &bulk_out_desc; +	err = usb_ep_enable(dev->out_ep);  	if (err) {  		ERROR(dev, "can't start %s: %d\n", dev->out_ep->name, err);  		goto fail; @@ -693,6 +695,7 @@ static int gmidi_setup(struct usb_gadget *gadget,  		switch (w_value >> 8) {  		case USB_DT_DEVICE: +			device_desc.bMaxPacketSize0 = gadget->ep0->maxpacket;  			value = min(w_length, (u16) sizeof(device_desc));  			memcpy(req->buf, &device_desc, value);  			break; @@ -1247,8 +1250,6 @@ autoconf_fail:  	dev->req->complete = gmidi_setup_complete; -	device_desc.bMaxPacketSize0 = gadget->ep0->maxpacket; -  	gadget->ep0->driver_data = dev;  	INFO(dev, "%s, version: " DRIVER_VERSION "\n", longname); diff --git a/drivers/usb/gadget/goku_udc.c b/drivers/usb/gadget/goku_udc.c index bf6e11c758d5..7f87805cddc4 100644 --- a/drivers/usb/gadget/goku_udc.c +++ b/drivers/usb/gadget/goku_udc.c @@ -996,8 +996,14 @@ static int goku_get_frame(struct usb_gadget *_gadget)  	return -EOPNOTSUPP;  } +static int goku_start(struct usb_gadget_driver *driver, +		int (*bind)(struct usb_gadget *)); +static int goku_stop(struct usb_gadget_driver *driver); +  static const struct usb_gadget_ops goku_ops = {  	.get_frame	= goku_get_frame, +	.start		= goku_start, +	.stop		= goku_stop,  	// no remote wakeup  	// not selfpowered  }; @@ -1344,7 +1350,7 @@ static struct goku_udc	*the_controller;   * disconnect is reported.  then a host may connect again, or   * the driver might get unbound.   */ -int usb_gadget_probe_driver(struct usb_gadget_driver *driver, +static int goku_start(struct usb_gadget_driver *driver,  		int (*bind)(struct usb_gadget *))  {  	struct goku_udc	*dev = the_controller; @@ -1382,7 +1388,6 @@ int usb_gadget_probe_driver(struct usb_gadget_driver *driver,  	DBG(dev, "registered gadget driver '%s'\n", driver->driver.name);  	return 0;  } -EXPORT_SYMBOL(usb_gadget_probe_driver);  static void  stop_activity(struct goku_udc *dev, struct usb_gadget_driver *driver) @@ -1408,7 +1413,7 @@ stop_activity(struct goku_udc *dev, struct usb_gadget_driver *driver)  		udc_enable(dev);  } -int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) +static int goku_stop(struct usb_gadget_driver *driver)  {  	struct goku_udc	*dev = the_controller;  	unsigned long	flags; @@ -1429,8 +1434,6 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)  	DBG(dev, "unregistered driver '%s'\n", driver->driver.name);  	return 0;  } -EXPORT_SYMBOL(usb_gadget_unregister_driver); -  /*-------------------------------------------------------------------------*/ @@ -1730,6 +1733,8 @@ static void goku_remove(struct pci_dev *pdev)  	DBG(dev, "%s\n", __func__); +	usb_del_gadget_udc(&dev->gadget); +  	BUG_ON(dev->driver);  #ifdef CONFIG_USB_GADGET_DEBUG_FILES @@ -1854,6 +1859,10 @@ static int goku_probe(struct pci_dev *pdev, const struct pci_device_id *id)  		goto err;  	}  	dev->registered = 1; +	retval = usb_add_gadget_udc(&pdev->dev, &dev->gadget); +	if (retval) +		goto err; +  	return 0;  err: diff --git a/drivers/usb/gadget/hid.c b/drivers/usb/gadget/hid.c index 2523e54097bd..9fb575034a0e 100644 --- a/drivers/usb/gadget/hid.c +++ b/drivers/usb/gadget/hid.c @@ -255,6 +255,7 @@ static struct usb_composite_driver hidg_driver = {  	.name		= "g_hid",  	.dev		= &device_desc,  	.strings	= dev_strings, +	.max_speed	= USB_SPEED_HIGH,  	.unbind		= __exit_p(hid_unbind),  }; diff --git a/drivers/usb/gadget/imx_udc.c b/drivers/usb/gadget/imx_udc.c index ade40066decf..692fd9b2248b 100644 --- a/drivers/usb/gadget/imx_udc.c +++ b/drivers/usb/gadget/imx_udc.c @@ -1237,9 +1237,14 @@ irq_handler_t intr_handler(int i)   *******************************************************************************   */ +static int imx_udc_start(struct usb_gadget_driver *driver, +		int (*bind)(struct usb_gadget *)); +static int imx_udc_stop(struct usb_gadget_driver *driver);  static const struct usb_gadget_ops imx_udc_ops = {  	.get_frame	 = imx_udc_get_frame,  	.wakeup		 = imx_udc_wakeup, +	.start		= imx_udc_start, +	.stop		= imx_udc_stop,  };  static struct imx_udc_struct controller = { @@ -1324,7 +1329,7 @@ static struct imx_udc_struct controller = {   * USB gadget driver functions   *******************************************************************************   */ -int usb_gadget_probe_driver(struct usb_gadget_driver *driver, +static int imx_udc_start(struct usb_gadget_driver *driver,  		int (*bind)(struct usb_gadget *))  {  	struct imx_udc_struct *imx_usb = &controller; @@ -1368,9 +1373,8 @@ fail:  	imx_usb->gadget.dev.driver = NULL;  	return retval;  } -EXPORT_SYMBOL(usb_gadget_probe_driver); -int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) +static int imx_udc_stop(struct usb_gadget_driver *driver)  {  	struct imx_udc_struct *imx_usb = &controller; @@ -1394,7 +1398,6 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)  	return 0;  } -EXPORT_SYMBOL(usb_gadget_unregister_driver);  /*******************************************************************************   * Module functions @@ -1504,8 +1507,14 @@ static int __init imx_udc_probe(struct platform_device *pdev)  	imx_usb->timer.function = handle_config;  	imx_usb->timer.data = (unsigned long)imx_usb; -	return 0; +	ret = usb_add_gadget_udc(&pdev->dev, &imx_usb->gadget); +	if (ret) +		goto fail4; +	return 0; +fail4: +	for (i = 0; i < IMX_USB_NB_EP + 1; i++) +		free_irq(imx_usb->usbd_int[i], imx_usb);  fail3:  	clk_put(clk);  	clk_disable(clk); @@ -1525,6 +1534,7 @@ static int __exit imx_udc_remove(struct platform_device *pdev)  	struct imxusb_platform_data *pdata = pdev->dev.platform_data;  	int i; +	usb_del_gadget_udc(&imx_usb->gadget);  	imx_udc_disable(imx_usb);  	del_timer(&imx_usb->timer); diff --git a/drivers/usb/gadget/inode.c b/drivers/usb/gadget/inode.c index a01383f71f38..1b240990448f 100644 --- a/drivers/usb/gadget/inode.c +++ b/drivers/usb/gadget/inode.c @@ -431,8 +431,10 @@ ep_write (struct file *fd, const char __user *buf, size_t len, loff_t *ptr)  	/* halt any endpoint by doing a "wrong direction" i/o call */  	if (!usb_endpoint_dir_in(&data->desc)) { -		if (usb_endpoint_xfer_isoc(&data->desc)) +		if (usb_endpoint_xfer_isoc(&data->desc)) { +			mutex_unlock(&data->lock);  			return -EINVAL; +		}  		DBG (data->dev, "%s halt\n", data->name);  		spin_lock_irq (&data->dev->lock);  		if (likely (data->ep != NULL)) @@ -830,14 +832,16 @@ ep_config (struct file *fd, const char __user *buf, size_t len, loff_t *ptr)  	switch (data->dev->gadget->speed) {  	case USB_SPEED_LOW:  	case USB_SPEED_FULL: -		value = usb_ep_enable (ep, &data->desc); +		ep->desc = &data->desc; +		value = usb_ep_enable(ep);  		if (value == 0)  			data->state = STATE_EP_ENABLED;  		break;  #ifdef	CONFIG_USB_GADGET_DUALSPEED  	case USB_SPEED_HIGH:  		/* fails if caller didn't provide that descriptor... */ -		value = usb_ep_enable (ep, &data->hs_desc); +		ep->desc = &data->hs_desc; +		value = usb_ep_enable(ep);  		if (value == 0)  			data->state = STATE_EP_ENABLED;  		break; @@ -1343,7 +1347,7 @@ static void make_qualifier (struct dev_data *dev)  	qual.bDeviceProtocol = desc->bDeviceProtocol;  	/* assumes ep0 uses the same value for both speeds ... */ -	qual.bMaxPacketSize0 = desc->bMaxPacketSize0; +	qual.bMaxPacketSize0 = dev->gadget->ep0->maxpacket;  	qual.bNumConfigurations = 1;  	qual.bRESERVED = 0; @@ -1400,7 +1404,6 @@ gadgetfs_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)  		}  		dev->state = STATE_DEV_CONNECTED; -		dev->dev->bMaxPacketSize0 = gadget->ep0->maxpacket;  		INFO (dev, "connected\n");  		event = next_event (dev, GADGETFS_CONNECT); @@ -1428,6 +1431,7 @@ gadgetfs_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)  		case USB_DT_DEVICE:  			value = min (w_length, (u16) sizeof *dev->dev); +			dev->dev->bMaxPacketSize0 = dev->gadget->ep0->maxpacket;  			req->buf = dev->dev;  			break;  #ifdef	CONFIG_USB_GADGET_DUALSPEED @@ -1708,7 +1712,6 @@ gadgetfs_bind (struct usb_gadget *gadget)  	set_gadget_data (gadget, dev);  	dev->gadget = gadget;  	gadget->ep0->driver_data = dev; -	dev->dev->bMaxPacketSize0 = gadget->ep0->maxpacket;  	/* preallocate control response and buffer */  	dev->req = usb_ep_alloc_request (gadget->ep0, GFP_KERNEL); diff --git a/drivers/usb/gadget/langwell_udc.c b/drivers/usb/gadget/langwell_udc.c index 9cee88a43a73..a06e2c27b435 100644 --- a/drivers/usb/gadget/langwell_udc.c +++ b/drivers/usb/gadget/langwell_udc.c @@ -593,8 +593,8 @@ static int queue_dtd(struct langwell_ep *ep, struct langwell_request *req)  		/* ep0 */  		dev_vdbg(&dev->pdev->dev, "%s-%s\n", ep->name, DIR_STRING(ep)); -	dev_vdbg(&dev->pdev->dev, "ep_dqh[%d] addr: 0x%08x\n", -			i, (u32)&(dev->ep_dqh[i])); +	dev_vdbg(&dev->pdev->dev, "ep_dqh[%d] addr: 0x%p\n", +			i, &(dev->ep_dqh[i]));  	bit_mask = is_in(ep) ?  		(1 << (ep->ep_num + 16)) : (1 << (ep->ep_num)); @@ -1321,7 +1321,9 @@ static int langwell_pullup(struct usb_gadget *_gadget, int is_on)  	return 0;  } - +static int langwell_start(struct usb_gadget_driver *driver, +		int (*bind)(struct usb_gadget *)); +static int langwell_stop(struct usb_gadget_driver *driver);  /* device controller usb_gadget_ops structure */  static const struct usb_gadget_ops langwell_ops = { @@ -1342,6 +1344,9 @@ static const struct usb_gadget_ops langwell_ops = {  	/* D+ pullup, software-controlled connect/disconnect to USB host */  	.pullup		= langwell_pullup, + +	.start		= langwell_start, +	.stop		= langwell_stop,  }; @@ -1852,7 +1857,7 @@ static DEVICE_ATTR(remote_wakeup, S_IWUSR, NULL, store_remote_wakeup);   * the driver might get unbound.   */ -int usb_gadget_probe_driver(struct usb_gadget_driver *driver, +static int langwell_start(struct usb_gadget_driver *driver,  		int (*bind)(struct usb_gadget *))  {  	struct langwell_udc	*dev = the_controller; @@ -1914,11 +1919,9 @@ err_unbind:  	dev_dbg(&dev->pdev->dev, "<--- %s()\n", __func__);  	return retval;  } -EXPORT_SYMBOL(usb_gadget_probe_driver); -  /* unregister gadget driver */ -int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) +static int langwell_stop(struct usb_gadget_driver *driver)  {  	struct langwell_udc	*dev = the_controller;  	unsigned long		flags; @@ -1965,8 +1968,6 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)  	dev_dbg(&dev->pdev->dev, "<--- %s()\n", __func__);  	return 0;  } -EXPORT_SYMBOL(usb_gadget_unregister_driver); -  /*-------------------------------------------------------------------------*/ @@ -3270,7 +3271,7 @@ static int langwell_udc_probe(struct pci_dev *pdev,  	/* allocate device dQH memory */  	size = dev->ep_max * sizeof(struct langwell_dqh); -	dev_vdbg(&dev->pdev->dev, "orig size = %d\n", size); +	dev_vdbg(&dev->pdev->dev, "orig size = %zd\n", size);  	if (size < DQH_ALIGNMENT)  		size = DQH_ALIGNMENT;  	else if ((size % DQH_ALIGNMENT) != 0) { @@ -3285,7 +3286,7 @@ static int langwell_udc_probe(struct pci_dev *pdev,  		goto error;  	}  	dev->ep_dqh_size = size; -	dev_vdbg(&dev->pdev->dev, "ep_dqh_size = %d\n", dev->ep_dqh_size); +	dev_vdbg(&dev->pdev->dev, "ep_dqh_size = %zd\n", dev->ep_dqh_size);  	/* initialize ep0 status request structure */  	dev->status_req = kzalloc(sizeof(struct langwell_request), GFP_KERNEL); @@ -3373,6 +3374,10 @@ static int langwell_udc_probe(struct pci_dev *pdev,  	if (retval)  		goto error; +	retval = usb_add_gadget_udc(&pdev->dev, &dev->gadget); +	if (retval) +		goto error; +  	retval = device_create_file(&pdev->dev, &dev_attr_langwell_udc);  	if (retval)  		goto error; @@ -3403,6 +3408,7 @@ static int langwell_udc_suspend(struct pci_dev *pdev, pm_message_t state)  	dev_dbg(&dev->pdev->dev, "---> %s()\n", __func__); +	usb_del_gadget_udc(&dev->gadget);  	/* disable interrupt and set controller to stop state */  	langwell_udc_stop(dev); @@ -3464,7 +3470,7 @@ static int langwell_udc_resume(struct pci_dev *pdev)  	/* allocate device dQH memory */  	size = dev->ep_max * sizeof(struct langwell_dqh); -	dev_vdbg(&dev->pdev->dev, "orig size = %d\n", size); +	dev_vdbg(&dev->pdev->dev, "orig size = %zd\n", size);  	if (size < DQH_ALIGNMENT)  		size = DQH_ALIGNMENT;  	else if ((size % DQH_ALIGNMENT) != 0) { @@ -3478,7 +3484,7 @@ static int langwell_udc_resume(struct pci_dev *pdev)  		return -ENOMEM;  	}  	dev->ep_dqh_size = size; -	dev_vdbg(&dev->pdev->dev, "ep_dqh_size = %d\n", dev->ep_dqh_size); +	dev_vdbg(&dev->pdev->dev, "ep_dqh_size = %zd\n", dev->ep_dqh_size);  	/* create dTD dma_pool resource */  	dev->dtd_pool = dma_pool_create("langwell_dtd", diff --git a/drivers/usb/gadget/m66592-udc.c b/drivers/usb/gadget/m66592-udc.c index 084aa080a2d5..491f825ed5c9 100644 --- a/drivers/usb/gadget/m66592-udc.c +++ b/drivers/usb/gadget/m66592-udc.c @@ -3,7 +3,7 @@   *   * Copyright (C) 2006-2007 Renesas Solutions Corp.   * - * Author : Yoshihiro Shimoda <shimoda.yoshihiro@renesas.com> + * Author : Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>   *   * 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 @@ -691,6 +691,7 @@ static void init_controller(struct m66592 *m66592)  static void disable_controller(struct m66592 *m66592)  { +	m66592_bclr(m66592, M66592_UTST, M66592_TESTMODE);  	if (!m66592->pdata->on_chip) {  		m66592_bclr(m66592, M66592_SCKE, M66592_SYSCFG);  		udelay(1); @@ -780,7 +781,7 @@ static void irq_ep0_write(struct m66592_ep *ep, struct m66592_request *req)  	/* write fifo */  	if (req->req.buf) {  		if (size > 0) -			m66592_write_fifo(m66592, ep->fifoaddr, buf, size); +			m66592_write_fifo(m66592, ep, buf, size);  		if ((size == 0) || ((size % ep->ep.maxpacket) != 0))  			m66592_bset(m66592, M66592_BVAL, ep->fifoctr);  	} @@ -826,7 +827,7 @@ static void irq_packet_write(struct m66592_ep *ep, struct m66592_request *req)  	/* write fifo */  	if (req->req.buf) { -		m66592_write_fifo(m66592, ep->fifoaddr, buf, size); +		m66592_write_fifo(m66592, ep, buf, size);  		if ((size == 0)  				|| ((size % ep->ep.maxpacket) != 0)  				|| ((bufsize != ep->ep.maxpacket) @@ -1048,10 +1049,30 @@ static void clear_feature(struct m66592 *m66592, struct usb_ctrlrequest *ctrl)  static void set_feature(struct m66592 *m66592, struct usb_ctrlrequest *ctrl)  { +	u16 tmp; +	int timeout = 3000;  	switch (ctrl->bRequestType & USB_RECIP_MASK) {  	case USB_RECIP_DEVICE: -		control_end(m66592, 1); +		switch (le16_to_cpu(ctrl->wValue)) { +		case USB_DEVICE_TEST_MODE: +			control_end(m66592, 1); +			/* Wait for the completion of status stage */ +			do { +				tmp = m66592_read(m66592, M66592_INTSTS0) & +								M66592_CTSQ; +				udelay(1); +			} while (tmp != M66592_CS_IDST || timeout-- > 0); + +			if (tmp == M66592_CS_IDST) +				m66592_bset(m66592, +					    le16_to_cpu(ctrl->wIndex >> 8), +					    M66592_TESTMODE); +			break; +		default: +			pipe_stall(m66592, 0); +			break; +		}  		break;  	case USB_RECIP_INTERFACE:  		control_end(m66592, 1); @@ -1454,7 +1475,7 @@ static struct usb_ep_ops m66592_ep_ops = {  /*-------------------------------------------------------------------------*/  static struct m66592 *the_controller; -int usb_gadget_probe_driver(struct usb_gadget_driver *driver, +static int m66592_start(struct usb_gadget_driver *driver,  		int (*bind)(struct usb_gadget *))  {  	struct m66592 *m66592 = the_controller; @@ -1506,9 +1527,8 @@ error:  	return retval;  } -EXPORT_SYMBOL(usb_gadget_probe_driver); -int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) +static int m66592_stop(struct usb_gadget_driver *driver)  {  	struct m66592 *m66592 = the_controller;  	unsigned long flags; @@ -1533,7 +1553,6 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)  	m66592->driver = NULL;  	return 0;  } -EXPORT_SYMBOL(usb_gadget_unregister_driver);  /*-------------------------------------------------------------------------*/  static int m66592_get_frame(struct usb_gadget *_gadget) @@ -1542,14 +1561,34 @@ static int m66592_get_frame(struct usb_gadget *_gadget)  	return m66592_read(m66592, M66592_FRMNUM) & 0x03FF;  } +static int m66592_pullup(struct usb_gadget *gadget, int is_on) +{ +	struct m66592 *m66592 = gadget_to_m66592(gadget); +	unsigned long flags; + +	spin_lock_irqsave(&m66592->lock, flags); +	if (is_on) +		m66592_bset(m66592, M66592_DPRPU, M66592_SYSCFG); +	else +		m66592_bclr(m66592, M66592_DPRPU, M66592_SYSCFG); +	spin_unlock_irqrestore(&m66592->lock, flags); + +	return 0; +} +  static struct usb_gadget_ops m66592_gadget_ops = {  	.get_frame		= m66592_get_frame, +	.start			= m66592_start, +	.stop			= m66592_stop, +	.pullup			= m66592_pullup,  };  static int __exit m66592_remove(struct platform_device *pdev)  {  	struct m66592		*m66592 = dev_get_drvdata(&pdev->dev); +	usb_del_gadget_udc(&m66592->gadget); +  	del_timer_sync(&m66592->timer);  	iounmap(m66592->reg);  	free_irq(platform_get_irq(pdev, 0), m66592); @@ -1691,9 +1730,16 @@ static int __init m66592_probe(struct platform_device *pdev)  	init_controller(m66592); +	ret = usb_add_gadget_udc(&pdev->dev, &m66592->gadget); +	if (ret) +		goto err_add_udc; +  	dev_info(&pdev->dev, "version %s\n", DRIVER_VERSION);  	return 0; +err_add_udc: +	m66592_free_request(&m66592->ep[0].ep, m66592->ep0_req); +  clean_up3:  #ifdef CONFIG_HAVE_CLK  	if (m66592->pdata->on_chip) { diff --git a/drivers/usb/gadget/m66592-udc.h b/drivers/usb/gadget/m66592-udc.h index c3caf1ac73ce..7b93d579af37 100644 --- a/drivers/usb/gadget/m66592-udc.h +++ b/drivers/usb/gadget/m66592-udc.h @@ -3,7 +3,7 @@   *   * Copyright (C) 2006-2007 Renesas Solutions Corp.   * - * Author : Yoshihiro Shimoda <shimoda.yoshihiro@renesas.com> + * Author : Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>   *   * 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 @@ -561,11 +561,26 @@ static inline void m66592_write(struct m66592 *m66592, u16 val,  	iowrite16(val, m66592->reg + offset);  } +static inline void m66592_mdfy(struct m66592 *m66592, u16 val, u16 pat, +		unsigned long offset) +{ +	u16 tmp; +	tmp = m66592_read(m66592, offset); +	tmp = tmp & (~pat); +	tmp = tmp | val; +	m66592_write(m66592, tmp, offset); +} + +#define m66592_bclr(m66592, val, offset)	\ +			m66592_mdfy(m66592, 0, val, offset) +#define m66592_bset(m66592, val, offset)	\ +			m66592_mdfy(m66592, val, 0, offset) +  static inline void m66592_write_fifo(struct m66592 *m66592, -		unsigned long offset, +		struct m66592_ep *ep,  		void *buf, unsigned long len)  { -	void __iomem *fifoaddr = m66592->reg + offset; +	void __iomem *fifoaddr = m66592->reg + ep->fifoaddr;  	if (m66592->pdata->on_chip) {  		unsigned long count; @@ -591,26 +606,15 @@ static inline void m66592_write_fifo(struct m66592 *m66592,  		iowrite16_rep(fifoaddr, buf, len);  		if (odd) {  			unsigned char *p = buf + len*2; +			if (m66592->pdata->wr0_shorted_to_wr1) +				m66592_bclr(m66592, M66592_MBW_16, ep->fifosel);  			iowrite8(*p, fifoaddr); +			if (m66592->pdata->wr0_shorted_to_wr1) +				m66592_bset(m66592, M66592_MBW_16, ep->fifosel);  		}  	}  } -static inline void m66592_mdfy(struct m66592 *m66592, u16 val, u16 pat, -		unsigned long offset) -{ -	u16 tmp; -	tmp = m66592_read(m66592, offset); -	tmp = tmp & (~pat); -	tmp = tmp | val; -	m66592_write(m66592, tmp, offset); -} - -#define m66592_bclr(m66592, val, offset)	\ -			m66592_mdfy(m66592, 0, val, offset) -#define m66592_bset(m66592, val, offset)	\ -			m66592_mdfy(m66592, val, 0, offset) -  #endif	/* ifndef __M66592_UDC_H__ */ diff --git a/drivers/usb/gadget/mass_storage.c b/drivers/usb/gadget/mass_storage.c index 01822422c3e8..d3eb27427c58 100644 --- a/drivers/usb/gadget/mass_storage.c +++ b/drivers/usb/gadget/mass_storage.c @@ -169,6 +169,7 @@ static struct usb_composite_driver msg_driver = {  	.name		= "g_mass_storage",  	.dev		= &msg_device_desc,  	.iProduct	= DRIVER_DESC, +	.max_speed	= USB_SPEED_HIGH,  	.needs_serial	= 1,  }; diff --git a/drivers/usb/gadget/multi.c b/drivers/usb/gadget/multi.c index d9feced348e3..8c7b74717d85 100644 --- a/drivers/usb/gadget/multi.c +++ b/drivers/usb/gadget/multi.c @@ -351,6 +351,7 @@ static struct usb_composite_driver multi_driver = {  	.name		= "g_multi",  	.dev		= &device_desc,  	.strings	= dev_strings, +	.max_speed	= USB_SPEED_HIGH,  	.unbind		= __exit_p(multi_unbind),  	.iProduct	= DRIVER_DESC,  	.needs_serial	= 1, diff --git a/drivers/usb/gadget/mv_udc_core.c b/drivers/usb/gadget/mv_udc_core.c index b62b2640deb0..ce1ac2bcb314 100644 --- a/drivers/usb/gadget/mv_udc_core.c +++ b/drivers/usb/gadget/mv_udc_core.c @@ -1128,6 +1128,9 @@ static int mv_udc_pullup(struct usb_gadget *gadget, int is_on)  	return 0;  } +static int mv_udc_start(struct usb_gadget_driver *driver, +		int (*bind)(struct usb_gadget *)); +static int mv_udc_stop(struct usb_gadget_driver *driver);  /* device controller usb_gadget_ops structure */  static const struct usb_gadget_ops mv_ops = { @@ -1139,6 +1142,8 @@ static const struct usb_gadget_ops mv_ops = {  	/* D+ pullup, software-controlled connect/disconnect to USB host */  	.pullup		= mv_udc_pullup, +	.start		= mv_udc_start, +	.stop		= mv_udc_stop,  };  static void mv_udc_testmode(struct mv_udc *udc, u16 index, bool enter) @@ -1230,7 +1235,7 @@ static void stop_activity(struct mv_udc *udc, struct usb_gadget_driver *driver)  	}  } -int usb_gadget_probe_driver(struct usb_gadget_driver *driver, +static int mv_udc_start(struct usb_gadget_driver *driver,  		int (*bind)(struct usb_gadget *))  {  	struct mv_udc *udc = the_controller; @@ -1270,9 +1275,8 @@ int usb_gadget_probe_driver(struct usb_gadget_driver *driver,  	return 0;  } -EXPORT_SYMBOL(usb_gadget_probe_driver); -int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) +static int mv_udc_stop(struct usb_gadget_driver *driver)  {  	struct mv_udc *udc = the_controller;  	unsigned long flags; @@ -1296,7 +1300,6 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)  	return 0;  } -EXPORT_SYMBOL(usb_gadget_unregister_driver);  static int  udc_prime_status(struct mv_udc *udc, u8 direction, u16 status, bool empty) @@ -1880,9 +1883,10 @@ static void gadget_release(struct device *_dev)  static int mv_udc_remove(struct platform_device *dev)  {  	struct mv_udc *udc = the_controller; -  	DECLARE_COMPLETION(done); +	usb_del_gadget_udc(&udc->gadget); +  	udc->done = &done;  	/* free memory allocated in probe */ @@ -2074,16 +2078,17 @@ int mv_udc_probe(struct platform_device *dev)  	the_controller = udc; -	goto out; +	retval = usb_add_gadget_udc(&dev->dev, &udc->gadget); +	if (!retval) +		return retval;  error:  	if (udc)  		mv_udc_remove(udc->dev); -out:  	return retval;  }  #ifdef CONFIG_PM -static int mv_udc_suspend(struct platform_device *_dev, pm_message_t state) +static int mv_udc_suspend(struct device *_dev)  {  	struct mv_udc *udc = the_controller; @@ -2092,7 +2097,7 @@ static int mv_udc_suspend(struct platform_device *_dev, pm_message_t state)  	return 0;  } -static int mv_udc_resume(struct platform_device *_dev) +static int mv_udc_resume(struct device *_dev)  {  	struct mv_udc *udc = the_controller;  	int retval; @@ -2100,7 +2105,7 @@ static int mv_udc_resume(struct platform_device *_dev)  	retval = mv_udc_phy_init(udc->phy_regs);  	if (retval) {  		dev_err(_dev, "phy initialization error %d\n", retval); -		goto error; +		return retval;  	}  	udc_reset(udc);  	ep0_reset(udc); @@ -2122,11 +2127,11 @@ static struct platform_driver udc_driver = {  		.owner	= THIS_MODULE,  		.name	= "pxa-u2o",  #ifdef CONFIG_PM -		.pm	= mv_udc_pm_ops, +		.pm	= &mv_udc_pm_ops,  #endif  	},  }; - +MODULE_ALIAS("platform:pxa-u2o");  MODULE_DESCRIPTION(DRIVER_DESC);  MODULE_AUTHOR("Chao Xie <chao.xie@marvell.com>"); diff --git a/drivers/usb/gadget/ncm.c b/drivers/usb/gadget/ncm.c index 99c179ad729d..62ee5087dcac 100644 --- a/drivers/usb/gadget/ncm.c +++ b/drivers/usb/gadget/ncm.c @@ -228,6 +228,7 @@ static struct usb_composite_driver ncm_driver = {  	.name		= "g_ncm",  	.dev		= &device_desc,  	.strings	= dev_strings, +	.max_speed	= USB_SPEED_HIGH,  	.unbind		= __exit_p(gncm_unbind),  }; diff --git a/drivers/usb/gadget/net2272.c b/drivers/usb/gadget/net2272.c new file mode 100644 index 000000000000..7c7b0e120d88 --- /dev/null +++ b/drivers/usb/gadget/net2272.c @@ -0,0 +1,2752 @@ +/* + * Driver for PLX NET2272 USB device controller + * + * Copyright (C) 2005-2006 PLX Technology, Inc. + * Copyright (C) 2006-2011 Analog Devices, Inc. + * + * 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA + */ + +#include <linux/delay.h> +#include <linux/device.h> +#include <linux/errno.h> +#include <linux/gpio.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/ioport.h> +#include <linux/irq.h> +#include <linux/kernel.h> +#include <linux/list.h> +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/pci.h> +#include <linux/platform_device.h> +#include <linux/sched.h> +#include <linux/slab.h> +#include <linux/timer.h> +#include <linux/usb.h> +#include <linux/usb/ch9.h> +#include <linux/usb/gadget.h> + +#include <asm/byteorder.h> +#include <asm/system.h> +#include <asm/unaligned.h> + +#include "net2272.h" + +#define DRIVER_DESC "PLX NET2272 USB Peripheral Controller" + +static const char driver_name[] = "net2272"; +static const char driver_vers[] = "2006 October 17/mainline"; +static const char driver_desc[] = DRIVER_DESC; + +static const char ep0name[] = "ep0"; +static const char * const ep_name[] = { +	ep0name, +	"ep-a", "ep-b", "ep-c", +}; + +#define DMA_ADDR_INVALID	(~(dma_addr_t)0) +#ifdef CONFIG_USB_GADGET_NET2272_DMA +/* + * use_dma: the NET2272 can use an external DMA controller. + * Note that since there is no generic DMA api, some functions, + * notably request_dma, start_dma, and cancel_dma will need to be + * modified for your platform's particular dma controller. + * + * If use_dma is disabled, pio will be used instead. + */ +static int use_dma = 0; +module_param(use_dma, bool, 0644); + +/* + * dma_ep: selects the endpoint for use with dma (1=ep-a, 2=ep-b) + * The NET2272 can only use dma for a single endpoint at a time. + * At some point this could be modified to allow either endpoint + * to take control of dma as it becomes available. + * + * Note that DMA should not be used on OUT endpoints unless it can + * be guaranteed that no short packets will arrive on an IN endpoint + * while the DMA operation is pending.  Otherwise the OUT DMA will + * terminate prematurely (See NET2272 Errata 630-0213-0101) + */ +static ushort dma_ep = 1; +module_param(dma_ep, ushort, 0644); + +/* + * dma_mode: net2272 dma mode setting (see LOCCTL1 definiton): + *	mode 0 == Slow DREQ mode + *	mode 1 == Fast DREQ mode + *	mode 2 == Burst mode + */ +static ushort dma_mode = 2; +module_param(dma_mode, ushort, 0644); +#else +#define use_dma 0 +#define dma_ep 1 +#define dma_mode 2 +#endif + +/* + * fifo_mode: net2272 buffer configuration: + *      mode 0 == ep-{a,b,c} 512db each + *      mode 1 == ep-a 1k, ep-{b,c} 512db + *      mode 2 == ep-a 1k, ep-b 1k, ep-c 512db + *      mode 3 == ep-a 1k, ep-b disabled, ep-c 512db + */ +static ushort fifo_mode = 0; +module_param(fifo_mode, ushort, 0644); + +/* + * enable_suspend: When enabled, the driver will respond to + * USB suspend requests by powering down the NET2272.  Otherwise, + * USB suspend requests will be ignored.  This is acceptible for + * self-powered devices.  For bus powered devices set this to 1. + */ +static ushort enable_suspend = 0; +module_param(enable_suspend, ushort, 0644); + +static void assert_out_naking(struct net2272_ep *ep, const char *where) +{ +	u8 tmp; + +#ifndef DEBUG +	return; +#endif + +	tmp = net2272_ep_read(ep, EP_STAT0); +	if ((tmp & (1 << NAK_OUT_PACKETS)) == 0) { +		dev_dbg(ep->dev->dev, "%s %s %02x !NAK\n", +			ep->ep.name, where, tmp); +		net2272_ep_write(ep, EP_RSPSET, 1 << ALT_NAK_OUT_PACKETS); +	} +} +#define ASSERT_OUT_NAKING(ep) assert_out_naking(ep, __func__) + +static void stop_out_naking(struct net2272_ep *ep) +{ +	u8 tmp = net2272_ep_read(ep, EP_STAT0); + +	if ((tmp & (1 << NAK_OUT_PACKETS)) != 0) +		net2272_ep_write(ep, EP_RSPCLR, 1 << ALT_NAK_OUT_PACKETS); +} + +#define PIPEDIR(bAddress) (usb_pipein(bAddress) ? "in" : "out") + +static char *type_string(u8 bmAttributes) +{ +	switch ((bmAttributes) & USB_ENDPOINT_XFERTYPE_MASK) { +	case USB_ENDPOINT_XFER_BULK: return "bulk"; +	case USB_ENDPOINT_XFER_ISOC: return "iso"; +	case USB_ENDPOINT_XFER_INT:  return "intr"; +	default:                     return "control"; +	} +} + +static char *buf_state_string(unsigned state) +{ +	switch (state) { +	case BUFF_FREE:  return "free"; +	case BUFF_VALID: return "valid"; +	case BUFF_LCL:   return "local"; +	case BUFF_USB:   return "usb"; +	default:         return "unknown"; +	} +} + +static char *dma_mode_string(void) +{ +	if (!use_dma) +		return "PIO"; +	switch (dma_mode) { +	case 0:  return "SLOW DREQ"; +	case 1:  return "FAST DREQ"; +	case 2:  return "BURST"; +	default: return "invalid"; +	} +} + +static void net2272_dequeue_all(struct net2272_ep *); +static int net2272_kick_dma(struct net2272_ep *, struct net2272_request *); +static int net2272_fifo_status(struct usb_ep *); + +static struct usb_ep_ops net2272_ep_ops; + +/*---------------------------------------------------------------------------*/ + +static int +net2272_enable(struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc) +{ +	struct net2272 *dev; +	struct net2272_ep *ep; +	u32 max; +	u8 tmp; +	unsigned long flags; + +	ep = container_of(_ep, struct net2272_ep, ep); +	if (!_ep || !desc || ep->desc || _ep->name == ep0name +			|| desc->bDescriptorType != USB_DT_ENDPOINT) +		return -EINVAL; +	dev = ep->dev; +	if (!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN) +		return -ESHUTDOWN; + +	max = le16_to_cpu(desc->wMaxPacketSize) & 0x1fff; + +	spin_lock_irqsave(&dev->lock, flags); +	_ep->maxpacket = max & 0x7fff; +	ep->desc = desc; + +	/* net2272_ep_reset() has already been called */ +	ep->stopped = 0; +	ep->wedged = 0; + +	/* set speed-dependent max packet */ +	net2272_ep_write(ep, EP_MAXPKT0, max & 0xff); +	net2272_ep_write(ep, EP_MAXPKT1, (max & 0xff00) >> 8); + +	/* set type, direction, address; reset fifo counters */ +	net2272_ep_write(ep, EP_STAT1, 1 << BUFFER_FLUSH); +	tmp = usb_endpoint_type(desc); +	if (usb_endpoint_xfer_bulk(desc)) { +		/* catch some particularly blatant driver bugs */ +		if ((dev->gadget.speed == USB_SPEED_HIGH && max != 512) || +		    (dev->gadget.speed == USB_SPEED_FULL && max > 64)) { +			spin_unlock_irqrestore(&dev->lock, flags); +			return -ERANGE; +		} +	} +	ep->is_iso = usb_endpoint_xfer_isoc(desc) ? 1 : 0; +	tmp <<= ENDPOINT_TYPE; +	tmp |= ((desc->bEndpointAddress & 0x0f) << ENDPOINT_NUMBER); +	tmp |= usb_endpoint_dir_in(desc) << ENDPOINT_DIRECTION; +	tmp |= (1 << ENDPOINT_ENABLE); + +	/* for OUT transfers, block the rx fifo until a read is posted */ +	ep->is_in = usb_endpoint_dir_in(desc); +	if (!ep->is_in) +		net2272_ep_write(ep, EP_RSPSET, 1 << ALT_NAK_OUT_PACKETS); + +	net2272_ep_write(ep, EP_CFG, tmp); + +	/* enable irqs */ +	tmp = (1 << ep->num) | net2272_read(dev, IRQENB0); +	net2272_write(dev, IRQENB0, tmp); + +	tmp = (1 << DATA_PACKET_RECEIVED_INTERRUPT_ENABLE) +		| (1 << DATA_PACKET_TRANSMITTED_INTERRUPT_ENABLE) +		| net2272_ep_read(ep, EP_IRQENB); +	net2272_ep_write(ep, EP_IRQENB, tmp); + +	tmp = desc->bEndpointAddress; +	dev_dbg(dev->dev, "enabled %s (ep%d%s-%s) max %04x cfg %02x\n", +		_ep->name, tmp & 0x0f, PIPEDIR(tmp), +		type_string(desc->bmAttributes), max, +		net2272_ep_read(ep, EP_CFG)); + +	spin_unlock_irqrestore(&dev->lock, flags); +	return 0; +} + +static void net2272_ep_reset(struct net2272_ep *ep) +{ +	u8 tmp; + +	ep->desc = NULL; +	INIT_LIST_HEAD(&ep->queue); + +	ep->ep.maxpacket = ~0; +	ep->ep.ops = &net2272_ep_ops; + +	/* disable irqs, endpoint */ +	net2272_ep_write(ep, EP_IRQENB, 0); + +	/* init to our chosen defaults, notably so that we NAK OUT +	 * packets until the driver queues a read. +	 */ +	tmp = (1 << NAK_OUT_PACKETS_MODE) | (1 << ALT_NAK_OUT_PACKETS); +	net2272_ep_write(ep, EP_RSPSET, tmp); + +	tmp = (1 << INTERRUPT_MODE) | (1 << HIDE_STATUS_PHASE); +	if (ep->num != 0) +		tmp |= (1 << ENDPOINT_TOGGLE) | (1 << ENDPOINT_HALT); + +	net2272_ep_write(ep, EP_RSPCLR, tmp); + +	/* scrub most status bits, and flush any fifo state */ +	net2272_ep_write(ep, EP_STAT0, +			  (1 << DATA_IN_TOKEN_INTERRUPT) +			| (1 << DATA_OUT_TOKEN_INTERRUPT) +			| (1 << DATA_PACKET_TRANSMITTED_INTERRUPT) +			| (1 << DATA_PACKET_RECEIVED_INTERRUPT) +			| (1 << SHORT_PACKET_TRANSFERRED_INTERRUPT)); + +	net2272_ep_write(ep, EP_STAT1, +			    (1 << TIMEOUT) +			  | (1 << USB_OUT_ACK_SENT) +			  | (1 << USB_OUT_NAK_SENT) +			  | (1 << USB_IN_ACK_RCVD) +			  | (1 << USB_IN_NAK_SENT) +			  | (1 << USB_STALL_SENT) +			  | (1 << LOCAL_OUT_ZLP) +			  | (1 << BUFFER_FLUSH)); + +	/* fifo size is handled seperately */ +} + +static int net2272_disable(struct usb_ep *_ep) +{ +	struct net2272_ep *ep; +	unsigned long flags; + +	ep = container_of(_ep, struct net2272_ep, ep); +	if (!_ep || !ep->desc || _ep->name == ep0name) +		return -EINVAL; + +	spin_lock_irqsave(&ep->dev->lock, flags); +	net2272_dequeue_all(ep); +	net2272_ep_reset(ep); + +	dev_vdbg(ep->dev->dev, "disabled %s\n", _ep->name); + +	spin_unlock_irqrestore(&ep->dev->lock, flags); +	return 0; +} + +/*---------------------------------------------------------------------------*/ + +static struct usb_request * +net2272_alloc_request(struct usb_ep *_ep, gfp_t gfp_flags) +{ +	struct net2272_ep *ep; +	struct net2272_request *req; + +	if (!_ep) +		return NULL; +	ep = container_of(_ep, struct net2272_ep, ep); + +	req = kzalloc(sizeof(*req), gfp_flags); +	if (!req) +		return NULL; + +	req->req.dma = DMA_ADDR_INVALID; +	INIT_LIST_HEAD(&req->queue); + +	return &req->req; +} + +static void +net2272_free_request(struct usb_ep *_ep, struct usb_request *_req) +{ +	struct net2272_ep *ep; +	struct net2272_request *req; + +	ep = container_of(_ep, struct net2272_ep, ep); +	if (!_ep || !_req) +		return; + +	req = container_of(_req, struct net2272_request, req); +	WARN_ON(!list_empty(&req->queue)); +	kfree(req); +} + +static void +net2272_done(struct net2272_ep *ep, struct net2272_request *req, int status) +{ +	struct net2272 *dev; +	unsigned stopped = ep->stopped; + +	if (ep->num == 0) { +		if (ep->dev->protocol_stall) { +			ep->stopped = 1; +			set_halt(ep); +		} +		allow_status(ep); +	} + +	list_del_init(&req->queue); + +	if (req->req.status == -EINPROGRESS) +		req->req.status = status; +	else +		status = req->req.status; + +	dev = ep->dev; +	if (use_dma && req->mapped) { +		dma_unmap_single(dev->dev, req->req.dma, req->req.length, +			ep->is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE); +		req->req.dma = DMA_ADDR_INVALID; +		req->mapped = 0; +	} + +	if (status && status != -ESHUTDOWN) +		dev_vdbg(dev->dev, "complete %s req %p stat %d len %u/%u buf %p\n", +			ep->ep.name, &req->req, status, +			req->req.actual, req->req.length, req->req.buf); + +	/* don't modify queue heads during completion callback */ +	ep->stopped = 1; +	spin_unlock(&dev->lock); +	req->req.complete(&ep->ep, &req->req); +	spin_lock(&dev->lock); +	ep->stopped = stopped; +} + +static int +net2272_write_packet(struct net2272_ep *ep, u8 *buf, +	struct net2272_request *req, unsigned max) +{ +	u16 __iomem *ep_data = net2272_reg_addr(ep->dev, EP_DATA); +	u16 *bufp; +	unsigned length, count; +	u8 tmp; + +	length = min(req->req.length - req->req.actual, max); +	req->req.actual += length; + +	dev_vdbg(ep->dev->dev, "write packet %s req %p max %u len %u avail %u\n", +		ep->ep.name, req, max, length, +		(net2272_ep_read(ep, EP_AVAIL1) << 8) | net2272_ep_read(ep, EP_AVAIL0)); + +	count = length; +	bufp = (u16 *)buf; + +	while (likely(count >= 2)) { +		/* no byte-swap required; chip endian set during init */ +		writew(*bufp++, ep_data); +		count -= 2; +	} +	buf = (u8 *)bufp; + +	/* write final byte by placing the NET2272 into 8-bit mode */ +	if (unlikely(count)) { +		tmp = net2272_read(ep->dev, LOCCTL); +		net2272_write(ep->dev, LOCCTL, tmp & ~(1 << DATA_WIDTH)); +		writeb(*buf, ep_data); +		net2272_write(ep->dev, LOCCTL, tmp); +	} +	return length; +} + +/* returns: 0: still running, 1: completed, negative: errno */ +static int +net2272_write_fifo(struct net2272_ep *ep, struct net2272_request *req) +{ +	u8 *buf; +	unsigned count, max; +	int status; + +	dev_vdbg(ep->dev->dev, "write_fifo %s actual %d len %d\n", +		ep->ep.name, req->req.actual, req->req.length); + +	/* +	 * Keep loading the endpoint until the final packet is loaded, +	 * or the endpoint buffer is full. +	 */ + top: +	/* +	 * Clear interrupt status +	 *  - Packet Transmitted interrupt will become set again when the +	 *    host successfully takes another packet +	 */ +	net2272_ep_write(ep, EP_STAT0, (1 << DATA_PACKET_TRANSMITTED_INTERRUPT)); +	while (!(net2272_ep_read(ep, EP_STAT0) & (1 << BUFFER_FULL))) { +		buf = req->req.buf + req->req.actual; +		prefetch(buf); + +		/* force pagesel */ +		net2272_ep_read(ep, EP_STAT0); + +		max = (net2272_ep_read(ep, EP_AVAIL1) << 8) | +			(net2272_ep_read(ep, EP_AVAIL0)); + +		if (max < ep->ep.maxpacket) +			max = (net2272_ep_read(ep, EP_AVAIL1) << 8) +				| (net2272_ep_read(ep, EP_AVAIL0)); + +		count = net2272_write_packet(ep, buf, req, max); +		/* see if we are done */ +		if (req->req.length == req->req.actual) { +			/* validate short or zlp packet */ +			if (count < ep->ep.maxpacket) +				set_fifo_bytecount(ep, 0); +			net2272_done(ep, req, 0); + +			if (!list_empty(&ep->queue)) { +				req = list_entry(ep->queue.next, +						struct net2272_request, +						queue); +				status = net2272_kick_dma(ep, req); + +				if (status < 0) +					if ((net2272_ep_read(ep, EP_STAT0) +							& (1 << BUFFER_EMPTY))) +						goto top; +			} +			return 1; +		} +		net2272_ep_write(ep, EP_STAT0, (1 << DATA_PACKET_TRANSMITTED_INTERRUPT)); +	} +	return 0; +} + +static void +net2272_out_flush(struct net2272_ep *ep) +{ +	ASSERT_OUT_NAKING(ep); + +	net2272_ep_write(ep, EP_STAT0, (1 << DATA_OUT_TOKEN_INTERRUPT) +			| (1 << DATA_PACKET_RECEIVED_INTERRUPT)); +	net2272_ep_write(ep, EP_STAT1, 1 << BUFFER_FLUSH); +} + +static int +net2272_read_packet(struct net2272_ep *ep, u8 *buf, +	struct net2272_request *req, unsigned avail) +{ +	u16 __iomem *ep_data = net2272_reg_addr(ep->dev, EP_DATA); +	unsigned is_short; +	u16 *bufp; + +	req->req.actual += avail; + +	dev_vdbg(ep->dev->dev, "read packet %s req %p len %u avail %u\n", +		ep->ep.name, req, avail, +		(net2272_ep_read(ep, EP_AVAIL1) << 8) | net2272_ep_read(ep, EP_AVAIL0)); + +	is_short = (avail < ep->ep.maxpacket); + +	if (unlikely(avail == 0)) { +		/* remove any zlp from the buffer */ +		(void)readw(ep_data); +		return is_short; +	} + +	/* Ensure we get the final byte */ +	if (unlikely(avail % 2)) +		avail++; +	bufp = (u16 *)buf; + +	do { +		*bufp++ = readw(ep_data); +		avail -= 2; +	} while (avail); + +	/* +	 * To avoid false endpoint available race condition must read +	 * ep stat0 twice in the case of a short transfer +	 */ +	if (net2272_ep_read(ep, EP_STAT0) & (1 << SHORT_PACKET_TRANSFERRED_INTERRUPT)) +		net2272_ep_read(ep, EP_STAT0); + +	return is_short; +} + +static int +net2272_read_fifo(struct net2272_ep *ep, struct net2272_request *req) +{ +	u8 *buf; +	unsigned is_short; +	int count; +	int tmp; +	int cleanup = 0; +	int status = -1; + +	dev_vdbg(ep->dev->dev, "read_fifo %s actual %d len %d\n", +		ep->ep.name, req->req.actual, req->req.length); + + top: +	do { +		buf = req->req.buf + req->req.actual; +		prefetchw(buf); + +		count = (net2272_ep_read(ep, EP_AVAIL1) << 8) +			| net2272_ep_read(ep, EP_AVAIL0); + +		net2272_ep_write(ep, EP_STAT0, +			(1 << SHORT_PACKET_TRANSFERRED_INTERRUPT) | +			(1 << DATA_PACKET_RECEIVED_INTERRUPT)); + +		tmp = req->req.length - req->req.actual; + +		if (count > tmp) { +			if ((tmp % ep->ep.maxpacket) != 0) { +				dev_err(ep->dev->dev, +					"%s out fifo %d bytes, expected %d\n", +					ep->ep.name, count, tmp); +				cleanup = 1; +			} +			count = (tmp > 0) ? tmp : 0; +		} + +		is_short = net2272_read_packet(ep, buf, req, count); + +		/* completion */ +		if (unlikely(cleanup || is_short || +				((req->req.actual == req->req.length) +				 && !req->req.zero))) { + +			if (cleanup) { +				net2272_out_flush(ep); +				net2272_done(ep, req, -EOVERFLOW); +			} else +				net2272_done(ep, req, 0); + +			/* re-initialize endpoint transfer registers +			 * otherwise they may result in erroneous pre-validation +			 * for subsequent control reads +			 */ +			if (unlikely(ep->num == 0)) { +				net2272_ep_write(ep, EP_TRANSFER2, 0); +				net2272_ep_write(ep, EP_TRANSFER1, 0); +				net2272_ep_write(ep, EP_TRANSFER0, 0); +			} + +			if (!list_empty(&ep->queue)) { +				req = list_entry(ep->queue.next, +					struct net2272_request, queue); +				status = net2272_kick_dma(ep, req); +				if ((status < 0) && +				    !(net2272_ep_read(ep, EP_STAT0) & (1 << BUFFER_EMPTY))) +					goto top; +			} +			return 1; +		} +	} while (!(net2272_ep_read(ep, EP_STAT0) & (1 << BUFFER_EMPTY))); + +	return 0; +} + +static void +net2272_pio_advance(struct net2272_ep *ep) +{ +	struct net2272_request *req; + +	if (unlikely(list_empty(&ep->queue))) +		return; + +	req = list_entry(ep->queue.next, struct net2272_request, queue); +	(ep->is_in ? net2272_write_fifo : net2272_read_fifo)(ep, req); +} + +/* returns 0 on success, else negative errno */ +static int +net2272_request_dma(struct net2272 *dev, unsigned ep, u32 buf, +	unsigned len, unsigned dir) +{ +	dev_vdbg(dev->dev, "request_dma ep %d buf %08x len %d dir %d\n", +		ep, buf, len, dir); + +	/* The NET2272 only supports a single dma channel */ +	if (dev->dma_busy) +		return -EBUSY; +	/* +	 * EP_TRANSFER (used to determine the number of bytes received +	 * in an OUT transfer) is 24 bits wide; don't ask for more than that. +	 */ +	if ((dir == 1) && (len > 0x1000000)) +		return -EINVAL; + +	dev->dma_busy = 1; + +	/* initialize platform's dma */ +#ifdef CONFIG_PCI +	/* NET2272 addr, buffer addr, length, etc. */ +	switch (dev->dev_id) { +	case PCI_DEVICE_ID_RDK1: +		/* Setup PLX 9054 DMA mode */ +		writel((1 << LOCAL_BUS_WIDTH) | +			(1 << TA_READY_INPUT_ENABLE) | +			(0 << LOCAL_BURST_ENABLE) | +			(1 << DONE_INTERRUPT_ENABLE) | +			(1 << LOCAL_ADDRESSING_MODE) | +			(1 << DEMAND_MODE) | +			(1 << DMA_EOT_ENABLE) | +			(1 << FAST_SLOW_TERMINATE_MODE_SELECT) | +			(1 << DMA_CHANNEL_INTERRUPT_SELECT), +			dev->rdk1.plx9054_base_addr + DMAMODE0); + +		writel(0x100000, dev->rdk1.plx9054_base_addr + DMALADR0); +		writel(buf, dev->rdk1.plx9054_base_addr + DMAPADR0); +		writel(len, dev->rdk1.plx9054_base_addr + DMASIZ0); +		writel((dir << DIRECTION_OF_TRANSFER) | +			(1 << INTERRUPT_AFTER_TERMINAL_COUNT), +			dev->rdk1.plx9054_base_addr + DMADPR0); +		writel((1 << LOCAL_DMA_CHANNEL_0_INTERRUPT_ENABLE) | +			readl(dev->rdk1.plx9054_base_addr + INTCSR), +			dev->rdk1.plx9054_base_addr + INTCSR); + +		break; +	} +#endif + +	net2272_write(dev, DMAREQ, +		(0 << DMA_BUFFER_VALID) | +		(1 << DMA_REQUEST_ENABLE) | +		(1 << DMA_CONTROL_DACK) | +		(dev->dma_eot_polarity << EOT_POLARITY) | +		(dev->dma_dack_polarity << DACK_POLARITY) | +		(dev->dma_dreq_polarity << DREQ_POLARITY) | +		((ep >> 1) << DMA_ENDPOINT_SELECT)); + +	(void) net2272_read(dev, SCRATCH); + +	return 0; +} + +static void +net2272_start_dma(struct net2272 *dev) +{ +	/* start platform's dma controller */ +#ifdef CONFIG_PCI +	switch (dev->dev_id) { +	case PCI_DEVICE_ID_RDK1: +		writeb((1 << CHANNEL_ENABLE) | (1 << CHANNEL_START), +			dev->rdk1.plx9054_base_addr + DMACSR0); +		break; +	} +#endif +} + +/* returns 0 on success, else negative errno */ +static int +net2272_kick_dma(struct net2272_ep *ep, struct net2272_request *req) +{ +	unsigned size; +	u8 tmp; + +	if (!use_dma || (ep->num < 1) || (ep->num > 2) || !ep->dma) +		return -EINVAL; + +	/* don't use dma for odd-length transfers +	 * otherwise, we'd need to deal with the last byte with pio +	 */ +	if (req->req.length & 1) +		return -EINVAL; + +	dev_vdbg(ep->dev->dev, "kick_dma %s req %p dma %08llx\n", +		ep->ep.name, req, (unsigned long long) req->req.dma); + +	net2272_ep_write(ep, EP_RSPSET, 1 << ALT_NAK_OUT_PACKETS); + +	/* The NET2272 can only use DMA on one endpoint at a time */ +	if (ep->dev->dma_busy) +		return -EBUSY; + +	/* Make sure we only DMA an even number of bytes (we'll use +	 * pio to complete the transfer) +	 */ +	size = req->req.length; +	size &= ~1; + +	/* device-to-host transfer */ +	if (ep->is_in) { +		/* initialize platform's dma controller */ +		if (net2272_request_dma(ep->dev, ep->num, req->req.dma, size, 0)) +			/* unable to obtain DMA channel; return error and use pio mode */ +			return -EBUSY; +		req->req.actual += size; + +	/* host-to-device transfer */ +	} else { +		tmp = net2272_ep_read(ep, EP_STAT0); + +		/* initialize platform's dma controller */ +		if (net2272_request_dma(ep->dev, ep->num, req->req.dma, size, 1)) +			/* unable to obtain DMA channel; return error and use pio mode */ +			return -EBUSY; + +		if (!(tmp & (1 << BUFFER_EMPTY))) +			ep->not_empty = 1; +		else +			ep->not_empty = 0; + + +		/* allow the endpoint's buffer to fill */ +		net2272_ep_write(ep, EP_RSPCLR, 1 << ALT_NAK_OUT_PACKETS); + +		/* this transfer completed and data's already in the fifo +		 * return error so pio gets used. +		 */ +		if (tmp & (1 << SHORT_PACKET_TRANSFERRED_INTERRUPT)) { + +			/* deassert dreq */ +			net2272_write(ep->dev, DMAREQ, +				(0 << DMA_BUFFER_VALID) | +				(0 << DMA_REQUEST_ENABLE) | +				(1 << DMA_CONTROL_DACK) | +				(ep->dev->dma_eot_polarity << EOT_POLARITY) | +				(ep->dev->dma_dack_polarity << DACK_POLARITY) | +				(ep->dev->dma_dreq_polarity << DREQ_POLARITY) | +				((ep->num >> 1) << DMA_ENDPOINT_SELECT)); + +			return -EBUSY; +		} +	} + +	/* Don't use per-packet interrupts: use dma interrupts only */ +	net2272_ep_write(ep, EP_IRQENB, 0); + +	net2272_start_dma(ep->dev); + +	return 0; +} + +static void net2272_cancel_dma(struct net2272 *dev) +{ +#ifdef CONFIG_PCI +	switch (dev->dev_id) { +	case PCI_DEVICE_ID_RDK1: +		writeb(0, dev->rdk1.plx9054_base_addr + DMACSR0); +		writeb(1 << CHANNEL_ABORT, dev->rdk1.plx9054_base_addr + DMACSR0); +		while (!(readb(dev->rdk1.plx9054_base_addr + DMACSR0) & +		         (1 << CHANNEL_DONE))) +			continue;	/* wait for dma to stabalize */ + +		/* dma abort generates an interrupt */ +		writeb(1 << CHANNEL_CLEAR_INTERRUPT, +			dev->rdk1.plx9054_base_addr + DMACSR0); +		break; +	} +#endif + +	dev->dma_busy = 0; +} + +/*---------------------------------------------------------------------------*/ + +static int +net2272_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags) +{ +	struct net2272_request *req; +	struct net2272_ep *ep; +	struct net2272 *dev; +	unsigned long flags; +	int status = -1; +	u8 s; + +	req = container_of(_req, struct net2272_request, req); +	if (!_req || !_req->complete || !_req->buf +			|| !list_empty(&req->queue)) +		return -EINVAL; +	ep = container_of(_ep, struct net2272_ep, ep); +	if (!_ep || (!ep->desc && ep->num != 0)) +		return -EINVAL; +	dev = ep->dev; +	if (!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN) +		return -ESHUTDOWN; + +	/* set up dma mapping in case the caller didn't */ +	if (use_dma && ep->dma && _req->dma == DMA_ADDR_INVALID) { +		_req->dma = dma_map_single(dev->dev, _req->buf, _req->length, +			ep->is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE); +		req->mapped = 1; +	} + +	dev_vdbg(dev->dev, "%s queue req %p, len %d buf %p dma %08llx %s\n", +		_ep->name, _req, _req->length, _req->buf, +		(unsigned long long) _req->dma, _req->zero ? "zero" : "!zero"); + +	spin_lock_irqsave(&dev->lock, flags); + +	_req->status = -EINPROGRESS; +	_req->actual = 0; + +	/* kickstart this i/o queue? */ +	if (list_empty(&ep->queue) && !ep->stopped) { +		/* maybe there's no control data, just status ack */ +		if (ep->num == 0 && _req->length == 0) { +			net2272_done(ep, req, 0); +			dev_vdbg(dev->dev, "%s status ack\n", ep->ep.name); +			goto done; +		} + +		/* Return zlp, don't let it block subsequent packets */ +		s = net2272_ep_read(ep, EP_STAT0); +		if (s & (1 << BUFFER_EMPTY)) { +			/* Buffer is empty check for a blocking zlp, handle it */ +			if ((s & (1 << NAK_OUT_PACKETS)) && +			    net2272_ep_read(ep, EP_STAT1) & (1 << LOCAL_OUT_ZLP)) { +				dev_dbg(dev->dev, "WARNING: returning ZLP short packet termination!\n"); +				/* +				 * Request is going to terminate with a short packet ... +				 * hope the client is ready for it! +				 */ +				status = net2272_read_fifo(ep, req); +				/* clear short packet naking */ +				net2272_ep_write(ep, EP_STAT0, (1 << NAK_OUT_PACKETS)); +				goto done; +			} +		} + +		/* try dma first */ +		status = net2272_kick_dma(ep, req); + +		if (status < 0) { +			/* dma failed (most likely in use by another endpoint) +			 * fallback to pio +			 */ +			status = 0; + +			if (ep->is_in) +				status = net2272_write_fifo(ep, req); +			else { +				s = net2272_ep_read(ep, EP_STAT0); +				if ((s & (1 << BUFFER_EMPTY)) == 0) +					status = net2272_read_fifo(ep, req); +			} + +			if (unlikely(status != 0)) { +				if (status > 0) +					status = 0; +				req = NULL; +			} +		} +	} +	if (likely(req != 0)) +		list_add_tail(&req->queue, &ep->queue); + +	if (likely(!list_empty(&ep->queue))) +		net2272_ep_write(ep, EP_RSPCLR, 1 << ALT_NAK_OUT_PACKETS); + done: +	spin_unlock_irqrestore(&dev->lock, flags); + +	return 0; +} + +/* dequeue ALL requests */ +static void +net2272_dequeue_all(struct net2272_ep *ep) +{ +	struct net2272_request *req; + +	/* called with spinlock held */ +	ep->stopped = 1; + +	while (!list_empty(&ep->queue)) { +		req = list_entry(ep->queue.next, +				struct net2272_request, +				queue); +		net2272_done(ep, req, -ESHUTDOWN); +	} +} + +/* dequeue JUST ONE request */ +static int +net2272_dequeue(struct usb_ep *_ep, struct usb_request *_req) +{ +	struct net2272_ep *ep; +	struct net2272_request *req; +	unsigned long flags; +	int stopped; + +	ep = container_of(_ep, struct net2272_ep, ep); +	if (!_ep || (!ep->desc && ep->num != 0) || !_req) +		return -EINVAL; + +	spin_lock_irqsave(&ep->dev->lock, flags); +	stopped = ep->stopped; +	ep->stopped = 1; + +	/* make sure it's still queued on this endpoint */ +	list_for_each_entry(req, &ep->queue, queue) { +		if (&req->req == _req) +			break; +	} +	if (&req->req != _req) { +		spin_unlock_irqrestore(&ep->dev->lock, flags); +		return -EINVAL; +	} + +	/* queue head may be partially complete */ +	if (ep->queue.next == &req->queue) { +		dev_dbg(ep->dev->dev, "unlink (%s) pio\n", _ep->name); +		net2272_done(ep, req, -ECONNRESET); +	} +	req = NULL; +	ep->stopped = stopped; + +	spin_unlock_irqrestore(&ep->dev->lock, flags); +	return 0; +} + +/*---------------------------------------------------------------------------*/ + +static int +net2272_set_halt_and_wedge(struct usb_ep *_ep, int value, int wedged) +{ +	struct net2272_ep *ep; +	unsigned long flags; +	int ret = 0; + +	ep = container_of(_ep, struct net2272_ep, ep); +	if (!_ep || (!ep->desc && ep->num != 0)) +		return -EINVAL; +	if (!ep->dev->driver || ep->dev->gadget.speed == USB_SPEED_UNKNOWN) +		return -ESHUTDOWN; +	if (ep->desc /* not ep0 */ && usb_endpoint_xfer_isoc(ep->desc)) +		return -EINVAL; + +	spin_lock_irqsave(&ep->dev->lock, flags); +	if (!list_empty(&ep->queue)) +		ret = -EAGAIN; +	else if (ep->is_in && value && net2272_fifo_status(_ep) != 0) +		ret = -EAGAIN; +	else { +		dev_vdbg(ep->dev->dev, "%s %s %s\n", _ep->name, +			value ? "set" : "clear", +			wedged ? "wedge" : "halt"); +		/* set/clear */ +		if (value) { +			if (ep->num == 0) +				ep->dev->protocol_stall = 1; +			else +				set_halt(ep); +			if (wedged) +				ep->wedged = 1; +		} else { +			clear_halt(ep); +			ep->wedged = 0; +		} +	} +	spin_unlock_irqrestore(&ep->dev->lock, flags); + +	return ret; +} + +static int +net2272_set_halt(struct usb_ep *_ep, int value) +{ +	return net2272_set_halt_and_wedge(_ep, value, 0); +} + +static int +net2272_set_wedge(struct usb_ep *_ep) +{ +	if (!_ep || _ep->name == ep0name) +		return -EINVAL; +	return net2272_set_halt_and_wedge(_ep, 1, 1); +} + +static int +net2272_fifo_status(struct usb_ep *_ep) +{ +	struct net2272_ep *ep; +	u16 avail; + +	ep = container_of(_ep, struct net2272_ep, ep); +	if (!_ep || (!ep->desc && ep->num != 0)) +		return -ENODEV; +	if (!ep->dev->driver || ep->dev->gadget.speed == USB_SPEED_UNKNOWN) +		return -ESHUTDOWN; + +	avail = net2272_ep_read(ep, EP_AVAIL1) << 8; +	avail |= net2272_ep_read(ep, EP_AVAIL0); +	if (avail > ep->fifo_size) +		return -EOVERFLOW; +	if (ep->is_in) +		avail = ep->fifo_size - avail; +	return avail; +} + +static void +net2272_fifo_flush(struct usb_ep *_ep) +{ +	struct net2272_ep *ep; + +	ep = container_of(_ep, struct net2272_ep, ep); +	if (!_ep || (!ep->desc && ep->num != 0)) +		return; +	if (!ep->dev->driver || ep->dev->gadget.speed == USB_SPEED_UNKNOWN) +		return; + +	net2272_ep_write(ep, EP_STAT1, 1 << BUFFER_FLUSH); +} + +static struct usb_ep_ops net2272_ep_ops = { +	.enable        = net2272_enable, +	.disable       = net2272_disable, + +	.alloc_request = net2272_alloc_request, +	.free_request  = net2272_free_request, + +	.queue         = net2272_queue, +	.dequeue       = net2272_dequeue, + +	.set_halt      = net2272_set_halt, +	.set_wedge     = net2272_set_wedge, +	.fifo_status   = net2272_fifo_status, +	.fifo_flush    = net2272_fifo_flush, +}; + +/*---------------------------------------------------------------------------*/ + +static int +net2272_get_frame(struct usb_gadget *_gadget) +{ +	struct net2272 *dev; +	unsigned long flags; +	u16 ret; + +	if (!_gadget) +		return -ENODEV; +	dev = container_of(_gadget, struct net2272, gadget); +	spin_lock_irqsave(&dev->lock, flags); + +	ret = net2272_read(dev, FRAME1) << 8; +	ret |= net2272_read(dev, FRAME0); + +	spin_unlock_irqrestore(&dev->lock, flags); +	return ret; +} + +static int +net2272_wakeup(struct usb_gadget *_gadget) +{ +	struct net2272 *dev; +	u8 tmp; +	unsigned long flags; + +	if (!_gadget) +		return 0; +	dev = container_of(_gadget, struct net2272, gadget); + +	spin_lock_irqsave(&dev->lock, flags); +	tmp = net2272_read(dev, USBCTL0); +	if (tmp & (1 << IO_WAKEUP_ENABLE)) +		net2272_write(dev, USBCTL1, (1 << GENERATE_RESUME)); + +	spin_unlock_irqrestore(&dev->lock, flags); + +	return 0; +} + +static int +net2272_set_selfpowered(struct usb_gadget *_gadget, int value) +{ +	struct net2272 *dev; + +	if (!_gadget) +		return -ENODEV; +	dev = container_of(_gadget, struct net2272, gadget); + +	dev->is_selfpowered = value; + +	return 0; +} + +static int +net2272_pullup(struct usb_gadget *_gadget, int is_on) +{ +	struct net2272 *dev; +	u8 tmp; +	unsigned long flags; + +	if (!_gadget) +		return -ENODEV; +	dev = container_of(_gadget, struct net2272, gadget); + +	spin_lock_irqsave(&dev->lock, flags); +	tmp = net2272_read(dev, USBCTL0); +	dev->softconnect = (is_on != 0); +	if (is_on) +		tmp |= (1 << USB_DETECT_ENABLE); +	else +		tmp &= ~(1 << USB_DETECT_ENABLE); +	net2272_write(dev, USBCTL0, tmp); +	spin_unlock_irqrestore(&dev->lock, flags); + +	return 0; +} + +static int net2272_start(struct usb_gadget_driver *driver, +		int (*bind)(struct usb_gadget *)); +static int net2272_stop(struct usb_gadget_driver *driver); + +static const struct usb_gadget_ops net2272_ops = { +	.get_frame       = net2272_get_frame, +	.wakeup          = net2272_wakeup, +	.set_selfpowered = net2272_set_selfpowered, +	.pullup			= net2272_pullup, +	.start			= net2272_start, +	.stop			= net2272_stop, +}; + +/*---------------------------------------------------------------------------*/ + +static ssize_t +net2272_show_registers(struct device *_dev, struct device_attribute *attr, char *buf) +{ +	struct net2272 *dev; +	char *next; +	unsigned size, t; +	unsigned long flags; +	u8 t1, t2; +	int i; +	const char *s; + +	dev = dev_get_drvdata(_dev); +	next = buf; +	size = PAGE_SIZE; +	spin_lock_irqsave(&dev->lock, flags); + +	if (dev->driver) +		s = dev->driver->driver.name; +	else +		s = "(none)"; + +	/* Main Control Registers */ +	t = scnprintf(next, size, "%s version %s," +		"chiprev %02x, locctl %02x\n" +		"irqenb0 %02x irqenb1 %02x " +		"irqstat0 %02x irqstat1 %02x\n", +		driver_name, driver_vers, dev->chiprev, +		net2272_read(dev, LOCCTL), +		net2272_read(dev, IRQENB0), +		net2272_read(dev, IRQENB1), +		net2272_read(dev, IRQSTAT0), +		net2272_read(dev, IRQSTAT1)); +	size -= t; +	next += t; + +	/* DMA */ +	t1 = net2272_read(dev, DMAREQ); +	t = scnprintf(next, size, "\ndmareq %02x: %s %s%s%s%s\n", +		t1, ep_name[(t1 & 0x01) + 1], +		t1 & (1 << DMA_CONTROL_DACK) ? "dack " : "", +		t1 & (1 << DMA_REQUEST_ENABLE) ? "reqenb " : "", +		t1 & (1 << DMA_REQUEST) ? "req " : "", +		t1 & (1 << DMA_BUFFER_VALID) ? "valid " : ""); +	size -= t; +	next += t; + +	/* USB Control Registers */ +	t1 = net2272_read(dev, USBCTL1); +	if (t1 & (1 << VBUS_PIN)) { +		if (t1 & (1 << USB_HIGH_SPEED)) +			s = "high speed"; +		else if (dev->gadget.speed == USB_SPEED_UNKNOWN) +			s = "powered"; +		else +			s = "full speed"; +	} else +		s = "not attached"; +	t = scnprintf(next, size, +		"usbctl0 %02x usbctl1 %02x addr 0x%02x (%s)\n", +		net2272_read(dev, USBCTL0), t1, +		net2272_read(dev, OURADDR), s); +	size -= t; +	next += t; + +	/* Endpoint Registers */ +	for (i = 0; i < 4; ++i) { +		struct net2272_ep *ep; + +		ep = &dev->ep[i]; +		if (i && !ep->desc) +			continue; + +		t1 = net2272_ep_read(ep, EP_CFG); +		t2 = net2272_ep_read(ep, EP_RSPSET); +		t = scnprintf(next, size, +			"\n%s\tcfg %02x rsp (%02x) %s%s%s%s%s%s%s%s" +			"irqenb %02x\n", +			ep->ep.name, t1, t2, +			(t2 & (1 << ALT_NAK_OUT_PACKETS)) ? "NAK " : "", +			(t2 & (1 << HIDE_STATUS_PHASE)) ? "hide " : "", +			(t2 & (1 << AUTOVALIDATE)) ? "auto " : "", +			(t2 & (1 << INTERRUPT_MODE)) ? "interrupt " : "", +			(t2 & (1 << CONTROL_STATUS_PHASE_HANDSHAKE)) ? "status " : "", +			(t2 & (1 << NAK_OUT_PACKETS_MODE)) ? "NAKmode " : "", +			(t2 & (1 << ENDPOINT_TOGGLE)) ? "DATA1 " : "DATA0 ", +			(t2 & (1 << ENDPOINT_HALT)) ? "HALT " : "", +			net2272_ep_read(ep, EP_IRQENB)); +		size -= t; +		next += t; + +		t = scnprintf(next, size, +			"\tstat0 %02x stat1 %02x avail %04x " +			"(ep%d%s-%s)%s\n", +			net2272_ep_read(ep, EP_STAT0), +			net2272_ep_read(ep, EP_STAT1), +			(net2272_ep_read(ep, EP_AVAIL1) << 8) | net2272_ep_read(ep, EP_AVAIL0), +			t1 & 0x0f, +			ep->is_in ? "in" : "out", +			type_string(t1 >> 5), +			ep->stopped ? "*" : ""); +		size -= t; +		next += t; + +		t = scnprintf(next, size, +			"\tep_transfer %06x\n", +			((net2272_ep_read(ep, EP_TRANSFER2) & 0xff) << 16) | +			((net2272_ep_read(ep, EP_TRANSFER1) & 0xff) << 8) | +			((net2272_ep_read(ep, EP_TRANSFER0) & 0xff))); +		size -= t; +		next += t; + +		t1 = net2272_ep_read(ep, EP_BUFF_STATES) & 0x03; +		t2 = (net2272_ep_read(ep, EP_BUFF_STATES) >> 2) & 0x03; +		t = scnprintf(next, size, +			"\tbuf-a %s buf-b %s\n", +			buf_state_string(t1), +			buf_state_string(t2)); +		size -= t; +		next += t; +	} + +	spin_unlock_irqrestore(&dev->lock, flags); + +	return PAGE_SIZE - size; +} +static DEVICE_ATTR(registers, S_IRUGO, net2272_show_registers, NULL); + +/*---------------------------------------------------------------------------*/ + +static void +net2272_set_fifo_mode(struct net2272 *dev, int mode) +{ +	u8 tmp; + +	tmp = net2272_read(dev, LOCCTL) & 0x3f; +	tmp |= (mode << 6); +	net2272_write(dev, LOCCTL, tmp); + +	INIT_LIST_HEAD(&dev->gadget.ep_list); + +	/* always ep-a, ep-c ... maybe not ep-b */ +	list_add_tail(&dev->ep[1].ep.ep_list, &dev->gadget.ep_list); + +	switch (mode) { +	case 0: +		list_add_tail(&dev->ep[2].ep.ep_list, &dev->gadget.ep_list); +		dev->ep[1].fifo_size = dev->ep[2].fifo_size = 512; +		break; +	case 1: +		list_add_tail(&dev->ep[2].ep.ep_list, &dev->gadget.ep_list); +		dev->ep[1].fifo_size = 1024; +		dev->ep[2].fifo_size = 512; +		break; +	case 2: +		list_add_tail(&dev->ep[2].ep.ep_list, &dev->gadget.ep_list); +		dev->ep[1].fifo_size = dev->ep[2].fifo_size = 1024; +		break; +	case 3: +		dev->ep[1].fifo_size = 1024; +		break; +	} + +	/* ep-c is always 2 512 byte buffers */ +	list_add_tail(&dev->ep[3].ep.ep_list, &dev->gadget.ep_list); +	dev->ep[3].fifo_size = 512; +} + +/*---------------------------------------------------------------------------*/ + +static struct net2272 *the_controller; + +static void +net2272_usb_reset(struct net2272 *dev) +{ +	dev->gadget.speed = USB_SPEED_UNKNOWN; + +	net2272_cancel_dma(dev); + +	net2272_write(dev, IRQENB0, 0); +	net2272_write(dev, IRQENB1, 0); + +	/* clear irq state */ +	net2272_write(dev, IRQSTAT0, 0xff); +	net2272_write(dev, IRQSTAT1, ~(1 << SUSPEND_REQUEST_INTERRUPT)); + +	net2272_write(dev, DMAREQ, +		(0 << DMA_BUFFER_VALID) | +		(0 << DMA_REQUEST_ENABLE) | +		(1 << DMA_CONTROL_DACK) | +		(dev->dma_eot_polarity << EOT_POLARITY) | +		(dev->dma_dack_polarity << DACK_POLARITY) | +		(dev->dma_dreq_polarity << DREQ_POLARITY) | +		((dma_ep >> 1) << DMA_ENDPOINT_SELECT)); + +	net2272_cancel_dma(dev); +	net2272_set_fifo_mode(dev, (fifo_mode <= 3) ? fifo_mode : 0); + +	/* Set the NET2272 ep fifo data width to 16-bit mode and for correct byte swapping +	 * note that the higher level gadget drivers are expected to convert data to little endian. +	 * Enable byte swap for your local bus/cpu if needed by setting BYTE_SWAP in LOCCTL here +	 */ +	net2272_write(dev, LOCCTL, net2272_read(dev, LOCCTL) | (1 << DATA_WIDTH)); +	net2272_write(dev, LOCCTL1, (dma_mode << DMA_MODE)); +} + +static void +net2272_usb_reinit(struct net2272 *dev) +{ +	int i; + +	/* basic endpoint init */ +	for (i = 0; i < 4; ++i) { +		struct net2272_ep *ep = &dev->ep[i]; + +		ep->ep.name = ep_name[i]; +		ep->dev = dev; +		ep->num = i; +		ep->not_empty = 0; + +		if (use_dma && ep->num == dma_ep) +			ep->dma = 1; + +		if (i > 0 && i <= 3) +			ep->fifo_size = 512; +		else +			ep->fifo_size = 64; +		net2272_ep_reset(ep); +	} +	dev->ep[0].ep.maxpacket = 64; + +	dev->gadget.ep0 = &dev->ep[0].ep; +	dev->ep[0].stopped = 0; +	INIT_LIST_HEAD(&dev->gadget.ep0->ep_list); +} + +static void +net2272_ep0_start(struct net2272 *dev) +{ +	struct net2272_ep *ep0 = &dev->ep[0]; + +	net2272_ep_write(ep0, EP_RSPSET, +		(1 << NAK_OUT_PACKETS_MODE) | +		(1 << ALT_NAK_OUT_PACKETS)); +	net2272_ep_write(ep0, EP_RSPCLR, +		(1 << HIDE_STATUS_PHASE) | +		(1 << CONTROL_STATUS_PHASE_HANDSHAKE)); +	net2272_write(dev, USBCTL0, +		(dev->softconnect << USB_DETECT_ENABLE) | +		(1 << USB_ROOT_PORT_WAKEUP_ENABLE) | +		(1 << IO_WAKEUP_ENABLE)); +	net2272_write(dev, IRQENB0, +		(1 << SETUP_PACKET_INTERRUPT_ENABLE) | +		(1 << ENDPOINT_0_INTERRUPT_ENABLE) | +		(1 << DMA_DONE_INTERRUPT_ENABLE)); +	net2272_write(dev, IRQENB1, +		(1 << VBUS_INTERRUPT_ENABLE) | +		(1 << ROOT_PORT_RESET_INTERRUPT_ENABLE) | +		(1 << SUSPEND_REQUEST_CHANGE_INTERRUPT_ENABLE)); +} + +/* when a driver is successfully registered, it will receive + * control requests including set_configuration(), which enables + * non-control requests.  then usb traffic follows until a + * disconnect is reported.  then a host may connect again, or + * the driver might get unbound. + */ +static int net2272_start(struct usb_gadget_driver *driver, +	int (*bind)(struct usb_gadget *)) +{ +	struct net2272 *dev = the_controller; +	int ret; +	unsigned i; + +	if (!driver || !bind || !driver->unbind || !driver->setup || +	    driver->speed != USB_SPEED_HIGH) +		return -EINVAL; +	if (!dev) +		return -ENODEV; +	if (dev->driver) +		return -EBUSY; + +	for (i = 0; i < 4; ++i) +		dev->ep[i].irqs = 0; +	/* hook up the driver ... */ +	dev->softconnect = 1; +	driver->driver.bus = NULL; +	dev->driver = driver; +	dev->gadget.dev.driver = &driver->driver; +	ret = bind(&dev->gadget); +	if (ret) { +		dev_dbg(dev->dev, "bind to driver %s --> %d\n", +			driver->driver.name, ret); +		dev->driver = NULL; +		dev->gadget.dev.driver = NULL; +		return ret; +	} + +	/* ... then enable host detection and ep0; and we're ready +	 * for set_configuration as well as eventual disconnect. +	 */ +	net2272_ep0_start(dev); + +	dev_dbg(dev->dev, "%s ready\n", driver->driver.name); + +	return 0; +} + +static void +stop_activity(struct net2272 *dev, struct usb_gadget_driver *driver) +{ +	int i; + +	/* don't disconnect if it's not connected */ +	if (dev->gadget.speed == USB_SPEED_UNKNOWN) +		driver = NULL; + +	/* stop hardware; prevent new request submissions; +	 * and kill any outstanding requests. +	 */ +	net2272_usb_reset(dev); +	for (i = 0; i < 4; ++i) +		net2272_dequeue_all(&dev->ep[i]); + +	/* report disconnect; the driver is already quiesced */ +	if (driver) { +		spin_unlock(&dev->lock); +		driver->disconnect(&dev->gadget); +		spin_lock(&dev->lock); + +	} +	net2272_usb_reinit(dev); +} + +static int net2272_stop(struct usb_gadget_driver *driver) +{ +	struct net2272 *dev = the_controller; +	unsigned long flags; + +	if (!dev) +		return -ENODEV; +	if (!driver || driver != dev->driver) +		return -EINVAL; + +	spin_lock_irqsave(&dev->lock, flags); +	stop_activity(dev, driver); +	spin_unlock_irqrestore(&dev->lock, flags); + +	net2272_pullup(&dev->gadget, 0); + +	driver->unbind(&dev->gadget); +	dev->gadget.dev.driver = NULL; +	dev->driver = NULL; + +	dev_dbg(dev->dev, "unregistered driver '%s'\n", driver->driver.name); +	return 0; +} + +/*---------------------------------------------------------------------------*/ +/* handle ep-a/ep-b dma completions */ +static void +net2272_handle_dma(struct net2272_ep *ep) +{ +	struct net2272_request *req; +	unsigned len; +	int status; + +	if (!list_empty(&ep->queue)) +		req = list_entry(ep->queue.next, +				struct net2272_request, queue); +	else +		req = NULL; + +	dev_vdbg(ep->dev->dev, "handle_dma %s req %p\n", ep->ep.name, req); + +	/* Ensure DREQ is de-asserted */ +	net2272_write(ep->dev, DMAREQ, +		(0 << DMA_BUFFER_VALID) +	      | (0 << DMA_REQUEST_ENABLE) +	      | (1 << DMA_CONTROL_DACK) +	      | (ep->dev->dma_eot_polarity << EOT_POLARITY) +	      | (ep->dev->dma_dack_polarity << DACK_POLARITY) +	      | (ep->dev->dma_dreq_polarity << DREQ_POLARITY) +	      | ((ep->dma >> 1) << DMA_ENDPOINT_SELECT)); + +	ep->dev->dma_busy = 0; + +	net2272_ep_write(ep, EP_IRQENB, +		  (1 << DATA_PACKET_RECEIVED_INTERRUPT_ENABLE) +		| (1 << DATA_PACKET_TRANSMITTED_INTERRUPT_ENABLE) +		| net2272_ep_read(ep, EP_IRQENB)); + +	/* device-to-host transfer completed */ +	if (ep->is_in) { +		/* validate a short packet or zlp if necessary */ +		if ((req->req.length % ep->ep.maxpacket != 0) || +				req->req.zero) +			set_fifo_bytecount(ep, 0); + +		net2272_done(ep, req, 0); +		if (!list_empty(&ep->queue)) { +			req = list_entry(ep->queue.next, +					struct net2272_request, queue); +			status = net2272_kick_dma(ep, req); +			if (status < 0) +				net2272_pio_advance(ep); +		} + +	/* host-to-device transfer completed */ +	} else { +		/* terminated with a short packet? */ +		if (net2272_read(ep->dev, IRQSTAT0) & +				(1 << DMA_DONE_INTERRUPT)) { +			/* abort system dma */ +			net2272_cancel_dma(ep->dev); +		} + +		/* EP_TRANSFER will contain the number of bytes +		 * actually received. +		 * NOTE: There is no overflow detection on EP_TRANSFER: +		 * We can't deal with transfers larger than 2^24 bytes! +		 */ +		len = (net2272_ep_read(ep, EP_TRANSFER2) << 16) +			| (net2272_ep_read(ep, EP_TRANSFER1) << 8) +			| (net2272_ep_read(ep, EP_TRANSFER0)); + +		if (ep->not_empty) +			len += 4; + +		req->req.actual += len; + +		/* get any remaining data */ +		net2272_pio_advance(ep); +	} +} + +/*---------------------------------------------------------------------------*/ + +static void +net2272_handle_ep(struct net2272_ep *ep) +{ +	struct net2272_request *req; +	u8 stat0, stat1; + +	if (!list_empty(&ep->queue)) +		req = list_entry(ep->queue.next, +			struct net2272_request, queue); +	else +		req = NULL; + +	/* ack all, and handle what we care about */ +	stat0 = net2272_ep_read(ep, EP_STAT0); +	stat1 = net2272_ep_read(ep, EP_STAT1); +	ep->irqs++; + +	dev_vdbg(ep->dev->dev, "%s ack ep_stat0 %02x, ep_stat1 %02x, req %p\n", +		ep->ep.name, stat0, stat1, req ? &req->req : 0); + +	net2272_ep_write(ep, EP_STAT0, stat0 & +		~((1 << NAK_OUT_PACKETS) +		| (1 << SHORT_PACKET_TRANSFERRED_INTERRUPT))); +	net2272_ep_write(ep, EP_STAT1, stat1); + +	/* data packet(s) received (in the fifo, OUT) +	 * direction must be validated, otherwise control read status phase +	 * could be interpreted as a valid packet +	 */ +	if (!ep->is_in && (stat0 & (1 << DATA_PACKET_RECEIVED_INTERRUPT))) +		net2272_pio_advance(ep); +	/* data packet(s) transmitted (IN) */ +	else if (stat0 & (1 << DATA_PACKET_TRANSMITTED_INTERRUPT)) +		net2272_pio_advance(ep); +} + +static struct net2272_ep * +net2272_get_ep_by_addr(struct net2272 *dev, u16 wIndex) +{ +	struct net2272_ep *ep; + +	if ((wIndex & USB_ENDPOINT_NUMBER_MASK) == 0) +		return &dev->ep[0]; + +	list_for_each_entry(ep, &dev->gadget.ep_list, ep.ep_list) { +		u8 bEndpointAddress; + +		if (!ep->desc) +			continue; +		bEndpointAddress = ep->desc->bEndpointAddress; +		if ((wIndex ^ bEndpointAddress) & USB_DIR_IN) +			continue; +		if ((wIndex & 0x0f) == (bEndpointAddress & 0x0f)) +			return ep; +	} +	return NULL; +} + +/* + * USB Test Packet: + * JKJKJKJK * 9 + * JJKKJJKK * 8 + * JJJJKKKK * 8 + * JJJJJJJKKKKKKK * 8 + * JJJJJJJK * 8 + * {JKKKKKKK * 10}, JK + */ +static const u8 net2272_test_packet[] = { +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +	0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, +	0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, +	0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, +	0x7F, 0xBF, 0xDF, 0xEF, 0xF7, 0xFB, 0xFD, +	0xFC, 0x7E, 0xBF, 0xDF, 0xEF, 0xF7, 0xFD, 0x7E +}; + +static void +net2272_set_test_mode(struct net2272 *dev, int mode) +{ +	int i; + +	/* Disable all net2272 interrupts: +	 * Nothing but a power cycle should stop the test. +	 */ +	net2272_write(dev, IRQENB0, 0x00); +	net2272_write(dev, IRQENB1, 0x00); + +	/* Force tranceiver to high-speed */ +	net2272_write(dev, XCVRDIAG, 1 << FORCE_HIGH_SPEED); + +	net2272_write(dev, PAGESEL, 0); +	net2272_write(dev, EP_STAT0, 1 << DATA_PACKET_TRANSMITTED_INTERRUPT); +	net2272_write(dev, EP_RSPCLR, +			  (1 << CONTROL_STATUS_PHASE_HANDSHAKE) +			| (1 << HIDE_STATUS_PHASE)); +	net2272_write(dev, EP_CFG, 1 << ENDPOINT_DIRECTION); +	net2272_write(dev, EP_STAT1, 1 << BUFFER_FLUSH); + +	/* wait for status phase to complete */ +	while (!(net2272_read(dev, EP_STAT0) & +				(1 << DATA_PACKET_TRANSMITTED_INTERRUPT))) +		; + +	/* Enable test mode */ +	net2272_write(dev, USBTEST, mode); + +	/* load test packet */ +	if (mode == TEST_PACKET) { +		/* switch to 8 bit mode */ +		net2272_write(dev, LOCCTL, net2272_read(dev, LOCCTL) & +				~(1 << DATA_WIDTH)); + +		for (i = 0; i < sizeof(net2272_test_packet); ++i) +			net2272_write(dev, EP_DATA, net2272_test_packet[i]); + +		/* Validate test packet */ +		net2272_write(dev, EP_TRANSFER0, 0); +	} +} + +static void +net2272_handle_stat0_irqs(struct net2272 *dev, u8 stat) +{ +	struct net2272_ep *ep; +	u8 num, scratch; + +	/* starting a control request? */ +	if (unlikely(stat & (1 << SETUP_PACKET_INTERRUPT))) { +		union { +			u8 raw[8]; +			struct usb_ctrlrequest	r; +		} u; +		int tmp = 0; +		struct net2272_request *req; + +		if (dev->gadget.speed == USB_SPEED_UNKNOWN) { +			if (net2272_read(dev, USBCTL1) & (1 << USB_HIGH_SPEED)) +				dev->gadget.speed = USB_SPEED_HIGH; +			else +				dev->gadget.speed = USB_SPEED_FULL; +			dev_dbg(dev->dev, "%s speed\n", +				(dev->gadget.speed == USB_SPEED_HIGH) ? "high" : "full"); +		} + +		ep = &dev->ep[0]; +		ep->irqs++; + +		/* make sure any leftover interrupt state is cleared */ +		stat &= ~(1 << ENDPOINT_0_INTERRUPT); +		while (!list_empty(&ep->queue)) { +			req = list_entry(ep->queue.next, +				struct net2272_request, queue); +			net2272_done(ep, req, +				(req->req.actual == req->req.length) ? 0 : -EPROTO); +		} +		ep->stopped = 0; +		dev->protocol_stall = 0; +		net2272_ep_write(ep, EP_STAT0, +			    (1 << DATA_IN_TOKEN_INTERRUPT) +			  | (1 << DATA_OUT_TOKEN_INTERRUPT) +			  | (1 << DATA_PACKET_TRANSMITTED_INTERRUPT) +			  | (1 << DATA_PACKET_RECEIVED_INTERRUPT) +			  | (1 << SHORT_PACKET_TRANSFERRED_INTERRUPT)); +		net2272_ep_write(ep, EP_STAT1, +			    (1 << TIMEOUT) +			  | (1 << USB_OUT_ACK_SENT) +			  | (1 << USB_OUT_NAK_SENT) +			  | (1 << USB_IN_ACK_RCVD) +			  | (1 << USB_IN_NAK_SENT) +			  | (1 << USB_STALL_SENT) +			  | (1 << LOCAL_OUT_ZLP)); + +		/* +		 * Ensure Control Read pre-validation setting is beyond maximum size +		 *  - Control Writes can leave non-zero values in EP_TRANSFER. If +		 *    an EP0 transfer following the Control Write is a Control Read, +		 *    the NET2272 sees the non-zero EP_TRANSFER as an unexpected +		 *    pre-validation count. +		 *  - Setting EP_TRANSFER beyond the maximum EP0 transfer size ensures +		 *    the pre-validation count cannot cause an unexpected validatation +		 */ +		net2272_write(dev, PAGESEL, 0); +		net2272_write(dev, EP_TRANSFER2, 0xff); +		net2272_write(dev, EP_TRANSFER1, 0xff); +		net2272_write(dev, EP_TRANSFER0, 0xff); + +		u.raw[0] = net2272_read(dev, SETUP0); +		u.raw[1] = net2272_read(dev, SETUP1); +		u.raw[2] = net2272_read(dev, SETUP2); +		u.raw[3] = net2272_read(dev, SETUP3); +		u.raw[4] = net2272_read(dev, SETUP4); +		u.raw[5] = net2272_read(dev, SETUP5); +		u.raw[6] = net2272_read(dev, SETUP6); +		u.raw[7] = net2272_read(dev, SETUP7); +		/* +		 * If you have a big endian cpu make sure le16_to_cpus +		 * performs the proper byte swapping here... +		 */ +		le16_to_cpus(&u.r.wValue); +		le16_to_cpus(&u.r.wIndex); +		le16_to_cpus(&u.r.wLength); + +		/* ack the irq */ +		net2272_write(dev, IRQSTAT0, 1 << SETUP_PACKET_INTERRUPT); +		stat ^= (1 << SETUP_PACKET_INTERRUPT); + +		/* watch control traffic at the token level, and force +		 * synchronization before letting the status phase happen. +		 */ +		ep->is_in = (u.r.bRequestType & USB_DIR_IN) != 0; +		if (ep->is_in) { +			scratch = (1 << DATA_PACKET_TRANSMITTED_INTERRUPT_ENABLE) +				| (1 << DATA_OUT_TOKEN_INTERRUPT_ENABLE) +				| (1 << DATA_IN_TOKEN_INTERRUPT_ENABLE); +			stop_out_naking(ep); +		} else +			scratch = (1 << DATA_PACKET_RECEIVED_INTERRUPT_ENABLE) +				| (1 << DATA_OUT_TOKEN_INTERRUPT_ENABLE) +				| (1 << DATA_IN_TOKEN_INTERRUPT_ENABLE); +		net2272_ep_write(ep, EP_IRQENB, scratch); + +		if ((u.r.bRequestType & USB_TYPE_MASK) != USB_TYPE_STANDARD) +			goto delegate; +		switch (u.r.bRequest) { +		case USB_REQ_GET_STATUS: { +			struct net2272_ep *e; +			u16 status = 0; + +			switch (u.r.bRequestType & USB_RECIP_MASK) { +			case USB_RECIP_ENDPOINT: +				e = net2272_get_ep_by_addr(dev, u.r.wIndex); +				if (!e || u.r.wLength > 2) +					goto do_stall; +				if (net2272_ep_read(e, EP_RSPSET) & (1 << ENDPOINT_HALT)) +					status = __constant_cpu_to_le16(1); +				else +					status = __constant_cpu_to_le16(0); + +				/* don't bother with a request object! */ +				net2272_ep_write(&dev->ep[0], EP_IRQENB, 0); +				writew(status, net2272_reg_addr(dev, EP_DATA)); +				set_fifo_bytecount(&dev->ep[0], 0); +				allow_status(ep); +				dev_vdbg(dev->dev, "%s stat %02x\n", +					ep->ep.name, status); +				goto next_endpoints; +			case USB_RECIP_DEVICE: +				if (u.r.wLength > 2) +					goto do_stall; +				if (dev->is_selfpowered) +					status = (1 << USB_DEVICE_SELF_POWERED); + +				/* don't bother with a request object! */ +				net2272_ep_write(&dev->ep[0], EP_IRQENB, 0); +				writew(status, net2272_reg_addr(dev, EP_DATA)); +				set_fifo_bytecount(&dev->ep[0], 0); +				allow_status(ep); +				dev_vdbg(dev->dev, "device stat %02x\n", status); +				goto next_endpoints; +			case USB_RECIP_INTERFACE: +				if (u.r.wLength > 2) +					goto do_stall; + +				/* don't bother with a request object! */ +				net2272_ep_write(&dev->ep[0], EP_IRQENB, 0); +				writew(status, net2272_reg_addr(dev, EP_DATA)); +				set_fifo_bytecount(&dev->ep[0], 0); +				allow_status(ep); +				dev_vdbg(dev->dev, "interface status %02x\n", status); +				goto next_endpoints; +			} + +			break; +		} +		case USB_REQ_CLEAR_FEATURE: { +			struct net2272_ep *e; + +			if (u.r.bRequestType != USB_RECIP_ENDPOINT) +				goto delegate; +			if (u.r.wValue != USB_ENDPOINT_HALT || +			    u.r.wLength != 0) +				goto do_stall; +			e = net2272_get_ep_by_addr(dev, u.r.wIndex); +			if (!e) +				goto do_stall; +			if (e->wedged) { +				dev_vdbg(dev->dev, "%s wedged, halt not cleared\n", +					ep->ep.name); +			} else { +				dev_vdbg(dev->dev, "%s clear halt\n", ep->ep.name); +				clear_halt(e); +			} +			allow_status(ep); +			goto next_endpoints; +		} +		case USB_REQ_SET_FEATURE: { +			struct net2272_ep *e; + +			if (u.r.bRequestType == USB_RECIP_DEVICE) { +				if (u.r.wIndex != NORMAL_OPERATION) +					net2272_set_test_mode(dev, (u.r.wIndex >> 8)); +				allow_status(ep); +				dev_vdbg(dev->dev, "test mode: %d\n", u.r.wIndex); +				goto next_endpoints; +			} else if (u.r.bRequestType != USB_RECIP_ENDPOINT) +				goto delegate; +			if (u.r.wValue != USB_ENDPOINT_HALT || +			    u.r.wLength != 0) +				goto do_stall; +			e = net2272_get_ep_by_addr(dev, u.r.wIndex); +			if (!e) +				goto do_stall; +			set_halt(e); +			allow_status(ep); +			dev_vdbg(dev->dev, "%s set halt\n", ep->ep.name); +			goto next_endpoints; +		} +		case USB_REQ_SET_ADDRESS: { +			net2272_write(dev, OURADDR, u.r.wValue & 0xff); +			allow_status(ep); +			break; +		} +		default: + delegate: +			dev_vdbg(dev->dev, "setup %02x.%02x v%04x i%04x " +				"ep_cfg %08x\n", +				u.r.bRequestType, u.r.bRequest, +				u.r.wValue, u.r.wIndex, +				net2272_ep_read(ep, EP_CFG)); +			spin_unlock(&dev->lock); +			tmp = dev->driver->setup(&dev->gadget, &u.r); +			spin_lock(&dev->lock); +		} + +		/* stall ep0 on error */ +		if (tmp < 0) { + do_stall: +			dev_vdbg(dev->dev, "req %02x.%02x protocol STALL; stat %d\n", +				u.r.bRequestType, u.r.bRequest, tmp); +			dev->protocol_stall = 1; +		} +	/* endpoint dma irq? */ +	} else if (stat & (1 << DMA_DONE_INTERRUPT)) { +		net2272_cancel_dma(dev); +		net2272_write(dev, IRQSTAT0, 1 << DMA_DONE_INTERRUPT); +		stat &= ~(1 << DMA_DONE_INTERRUPT); +		num = (net2272_read(dev, DMAREQ) & (1 << DMA_ENDPOINT_SELECT)) +			? 2 : 1; + +		ep = &dev->ep[num]; +		net2272_handle_dma(ep); +	} + + next_endpoints: +	/* endpoint data irq? */ +	scratch = stat & 0x0f; +	stat &= ~0x0f; +	for (num = 0; scratch; num++) { +		u8 t; + +		/* does this endpoint's FIFO and queue need tending? */ +		t = 1 << num; +		if ((scratch & t) == 0) +			continue; +		scratch ^= t; + +		ep = &dev->ep[num]; +		net2272_handle_ep(ep); +	} + +	/* some interrupts we can just ignore */ +	stat &= ~(1 << SOF_INTERRUPT); + +	if (stat) +		dev_dbg(dev->dev, "unhandled irqstat0 %02x\n", stat); +} + +static void +net2272_handle_stat1_irqs(struct net2272 *dev, u8 stat) +{ +	u8 tmp, mask; + +	/* after disconnect there's nothing else to do! */ +	tmp = (1 << VBUS_INTERRUPT) | (1 << ROOT_PORT_RESET_INTERRUPT); +	mask = (1 << USB_HIGH_SPEED) | (1 << USB_FULL_SPEED); + +	if (stat & tmp) { +		net2272_write(dev, IRQSTAT1, tmp); +		if ((((stat & (1 << ROOT_PORT_RESET_INTERRUPT)) && +				((net2272_read(dev, USBCTL1) & mask) == 0)) +			|| ((net2272_read(dev, USBCTL1) & (1 << VBUS_PIN)) +				== 0)) +				&& (dev->gadget.speed != USB_SPEED_UNKNOWN)) { +			dev_dbg(dev->dev, "disconnect %s\n", +				dev->driver->driver.name); +			stop_activity(dev, dev->driver); +			net2272_ep0_start(dev); +			return; +		} +		stat &= ~tmp; + +		if (!stat) +			return; +	} + +	tmp = (1 << SUSPEND_REQUEST_CHANGE_INTERRUPT); +	if (stat & tmp) { +		net2272_write(dev, IRQSTAT1, tmp); +		if (stat & (1 << SUSPEND_REQUEST_INTERRUPT)) { +			if (dev->driver->suspend) +				dev->driver->suspend(&dev->gadget); +			if (!enable_suspend) { +				stat &= ~(1 << SUSPEND_REQUEST_INTERRUPT); +				dev_dbg(dev->dev, "Suspend disabled, ignoring\n"); +			} +		} else { +			if (dev->driver->resume) +				dev->driver->resume(&dev->gadget); +		} +		stat &= ~tmp; +	} + +	/* clear any other status/irqs */ +	if (stat) +		net2272_write(dev, IRQSTAT1, stat); + +	/* some status we can just ignore */ +	stat &= ~((1 << CONTROL_STATUS_INTERRUPT) +			| (1 << SUSPEND_REQUEST_INTERRUPT) +			| (1 << RESUME_INTERRUPT)); +	if (!stat) +		return; +	else +		dev_dbg(dev->dev, "unhandled irqstat1 %02x\n", stat); +} + +static irqreturn_t net2272_irq(int irq, void *_dev) +{ +	struct net2272 *dev = _dev; +#if defined(PLX_PCI_RDK) || defined(PLX_PCI_RDK2) +	u32 intcsr; +#endif +#if defined(PLX_PCI_RDK) +	u8 dmareq; +#endif +	spin_lock(&dev->lock); +#if defined(PLX_PCI_RDK) +	intcsr = readl(dev->rdk1.plx9054_base_addr + INTCSR); + +	if ((intcsr & LOCAL_INTERRUPT_TEST) == LOCAL_INTERRUPT_TEST) { +		writel(intcsr & ~(1 << PCI_INTERRUPT_ENABLE), +				dev->rdk1.plx9054_base_addr + INTCSR); +		net2272_handle_stat1_irqs(dev, net2272_read(dev, IRQSTAT1)); +		net2272_handle_stat0_irqs(dev, net2272_read(dev, IRQSTAT0)); +		intcsr = readl(dev->rdk1.plx9054_base_addr + INTCSR); +		writel(intcsr | (1 << PCI_INTERRUPT_ENABLE), +			dev->rdk1.plx9054_base_addr + INTCSR); +	} +	if ((intcsr & DMA_CHANNEL_0_TEST) == DMA_CHANNEL_0_TEST) { +		writeb((1 << CHANNEL_CLEAR_INTERRUPT | (0 << CHANNEL_ENABLE)), +				dev->rdk1.plx9054_base_addr + DMACSR0); + +		dmareq = net2272_read(dev, DMAREQ); +		if (dmareq & 0x01) +			net2272_handle_dma(&dev->ep[2]); +		else +			net2272_handle_dma(&dev->ep[1]); +	} +#endif +#if defined(PLX_PCI_RDK2) +	/* see if PCI int for us by checking irqstat */ +	intcsr = readl(dev->rdk2.fpga_base_addr + RDK2_IRQSTAT); +	if (!intcsr & (1 << NET2272_PCI_IRQ)) +		return IRQ_NONE; +	/* check dma interrupts */ +#endif +	/* Platform/devcice interrupt handler */ +#if !defined(PLX_PCI_RDK) +	net2272_handle_stat1_irqs(dev, net2272_read(dev, IRQSTAT1)); +	net2272_handle_stat0_irqs(dev, net2272_read(dev, IRQSTAT0)); +#endif +	spin_unlock(&dev->lock); + +	return IRQ_HANDLED; +} + +static int net2272_present(struct net2272 *dev) +{ +	/* +	 * Quick test to see if CPU can communicate properly with the NET2272. +	 * Verifies connection using writes and reads to write/read and +	 * read-only registers. +	 * +	 * This routine is strongly recommended especially during early bring-up +	 * of new hardware, however for designs that do not apply Power On System +	 * Tests (POST) it may discarded (or perhaps minimized). +	 */ +	unsigned int ii; +	u8 val, refval; + +	/* Verify NET2272 write/read SCRATCH register can write and read */ +	refval = net2272_read(dev, SCRATCH); +	for (ii = 0; ii < 0x100; ii += 7) { +		net2272_write(dev, SCRATCH, ii); +		val = net2272_read(dev, SCRATCH); +		if (val != ii) { +			dev_dbg(dev->dev, +				"%s: write/read SCRATCH register test failed: " +				"wrote:0x%2.2x, read:0x%2.2x\n", +				__func__, ii, val); +			return -EINVAL; +		} +	} +	/* To be nice, we write the original SCRATCH value back: */ +	net2272_write(dev, SCRATCH, refval); + +	/* Verify NET2272 CHIPREV register is read-only: */ +	refval = net2272_read(dev, CHIPREV_2272); +	for (ii = 0; ii < 0x100; ii += 7) { +		net2272_write(dev, CHIPREV_2272, ii); +		val = net2272_read(dev, CHIPREV_2272); +		if (val != refval) { +			dev_dbg(dev->dev, +				"%s: write/read CHIPREV register test failed: " +				"wrote 0x%2.2x, read:0x%2.2x expected:0x%2.2x\n", +				__func__, ii, val, refval); +			return -EINVAL; +		} +	} + +	/* +	 * Verify NET2272's "NET2270 legacy revision" register +	 *  - NET2272 has two revision registers. The NET2270 legacy revision +	 *    register should read the same value, regardless of the NET2272 +	 *    silicon revision.  The legacy register applies to NET2270 +	 *    firmware being applied to the NET2272. +	 */ +	val = net2272_read(dev, CHIPREV_LEGACY); +	if (val != NET2270_LEGACY_REV) { +		/* +		 * Unexpected legacy revision value +		 * - Perhaps the chip is a NET2270? +		 */ +		dev_dbg(dev->dev, +			"%s: WARNING: UNEXPECTED NET2272 LEGACY REGISTER VALUE:\n" +			" - CHIPREV_LEGACY: expected 0x%2.2x, got:0x%2.2x. (Not NET2272?)\n", +			__func__, NET2270_LEGACY_REV, val); +		return -EINVAL; +	} + +	/* +	 * Verify NET2272 silicon revision +	 *  - This revision register is appropriate for the silicon version +	 *    of the NET2272 +	 */ +	val = net2272_read(dev, CHIPREV_2272); +	switch (val) { +	case CHIPREV_NET2272_R1: +		/* +		 * NET2272 Rev 1 has DMA related errata: +		 *  - Newer silicon (Rev 1A or better) required +		 */ +		dev_dbg(dev->dev, +			"%s: Rev 1 detected: newer silicon recommended for DMA support\n", +			__func__); +		break; +	case CHIPREV_NET2272_R1A: +		break; +	default: +		/* NET2272 silicon version *may* not work with this firmware */ +		dev_dbg(dev->dev, +			"%s: unexpected silicon revision register value: " +			" CHIPREV_2272: 0x%2.2x\n", +			__func__, val); +		/* +		 * Return Success, even though the chip rev is not an expected value +		 *  - Older, pre-built firmware can attempt to operate on newer silicon +		 *  - Often, new silicon is perfectly compatible +		 */ +	} + +	/* Success: NET2272 checks out OK */ +	return 0; +} + +static void +net2272_gadget_release(struct device *_dev) +{ +	struct net2272 *dev = dev_get_drvdata(_dev); +	kfree(dev); +} + +/*---------------------------------------------------------------------------*/ + +static void __devexit +net2272_remove(struct net2272 *dev) +{ +	usb_del_gadget_udc(&dev->gadget); + +	/* start with the driver above us */ +	if (dev->driver) { +		/* should have been done already by driver model core */ +		dev_warn(dev->dev, "pci remove, driver '%s' is still registered\n", +			dev->driver->driver.name); +		usb_gadget_unregister_driver(dev->driver); +	} + +	free_irq(dev->irq, dev); +	iounmap(dev->base_addr); + +	device_unregister(&dev->gadget.dev); +	device_remove_file(dev->dev, &dev_attr_registers); + +	dev_info(dev->dev, "unbind\n"); +	the_controller = NULL; +} + +static struct net2272 * __devinit +net2272_probe_init(struct device *dev, unsigned int irq) +{ +	struct net2272 *ret; + +	if (the_controller) { +		dev_warn(dev, "ignoring\n"); +		return ERR_PTR(-EBUSY); +	} + +	if (!irq) { +		dev_dbg(dev, "No IRQ!\n"); +		return ERR_PTR(-ENODEV); +	} + +	/* alloc, and start init */ +	ret = kzalloc(sizeof(*ret), GFP_KERNEL); +	if (!ret) +		return ERR_PTR(-ENOMEM); + +	spin_lock_init(&ret->lock); +	ret->irq = irq; +	ret->dev = dev; +	ret->gadget.ops = &net2272_ops; +	ret->gadget.is_dualspeed = 1; + +	/* the "gadget" abstracts/virtualizes the controller */ +	dev_set_name(&ret->gadget.dev, "gadget"); +	ret->gadget.dev.parent = dev; +	ret->gadget.dev.dma_mask = dev->dma_mask; +	ret->gadget.dev.release = net2272_gadget_release; +	ret->gadget.name = driver_name; + +	return ret; +} + +static int __devinit +net2272_probe_fin(struct net2272 *dev, unsigned int irqflags) +{ +	int ret; + +	/* See if there... */ +	if (net2272_present(dev)) { +		dev_warn(dev->dev, "2272 not found!\n"); +		ret = -ENODEV; +		goto err; +	} + +	net2272_usb_reset(dev); +	net2272_usb_reinit(dev); + +	ret = request_irq(dev->irq, net2272_irq, irqflags, driver_name, dev); +	if (ret) { +		dev_err(dev->dev, "request interrupt %i failed\n", dev->irq); +		goto err; +	} + +	dev->chiprev = net2272_read(dev, CHIPREV_2272); + +	/* done */ +	dev_info(dev->dev, "%s\n", driver_desc); +	dev_info(dev->dev, "irq %i, mem %p, chip rev %04x, dma %s\n", +		dev->irq, dev->base_addr, dev->chiprev, +		dma_mode_string()); +	dev_info(dev->dev, "version: %s\n", driver_vers); + +	the_controller = dev; + +	ret = device_register(&dev->gadget.dev); +	if (ret) +		goto err_irq; +	ret = device_create_file(dev->dev, &dev_attr_registers); +	if (ret) +		goto err_dev_reg; + +	ret = usb_add_gadget_udc(dev->dev, &dev->gadget); +	if (ret) +		goto err_add_udc; + +	return 0; + +err_add_udc: +	device_remove_file(dev->dev, &dev_attr_registers); + err_dev_reg: +	device_unregister(&dev->gadget.dev); + err_irq: +	free_irq(dev->irq, dev); + err: +	return ret; +} + +#ifdef CONFIG_PCI + +/* + * wrap this driver around the specified device, but + * don't respond over USB until a gadget driver binds to us + */ + +static int __devinit +net2272_rdk1_probe(struct pci_dev *pdev, struct net2272 *dev) +{ +	unsigned long resource, len, tmp; +	void __iomem *mem_mapped_addr[4]; +	int ret, i; + +	/* +	 * BAR 0 holds PLX 9054 config registers +	 * BAR 1 is i/o memory; unused here +	 * BAR 2 holds EPLD config registers +	 * BAR 3 holds NET2272 registers +	 */ + +	/* Find and map all address spaces */ +	for (i = 0; i < 4; ++i) { +		if (i == 1) +			continue;	/* BAR1 unused */ + +		resource = pci_resource_start(pdev, i); +		len = pci_resource_len(pdev, i); + +		if (!request_mem_region(resource, len, driver_name)) { +			dev_dbg(dev->dev, "controller already in use\n"); +			ret = -EBUSY; +			goto err; +		} + +		mem_mapped_addr[i] = ioremap_nocache(resource, len); +		if (mem_mapped_addr[i] == NULL) { +			release_mem_region(resource, len); +			dev_dbg(dev->dev, "can't map memory\n"); +			ret = -EFAULT; +			goto err; +		} +	} + +	dev->rdk1.plx9054_base_addr = mem_mapped_addr[0]; +	dev->rdk1.epld_base_addr = mem_mapped_addr[2]; +	dev->base_addr = mem_mapped_addr[3]; + +	/* Set PLX 9054 bus width (16 bits) */ +	tmp = readl(dev->rdk1.plx9054_base_addr + LBRD1); +	writel((tmp & ~(3 << MEMORY_SPACE_LOCAL_BUS_WIDTH)) | W16_BIT, +			dev->rdk1.plx9054_base_addr + LBRD1); + +	/* Enable PLX 9054 Interrupts */ +	writel(readl(dev->rdk1.plx9054_base_addr + INTCSR) | +			(1 << PCI_INTERRUPT_ENABLE) | +			(1 << LOCAL_INTERRUPT_INPUT_ENABLE), +			dev->rdk1.plx9054_base_addr + INTCSR); + +	writeb((1 << CHANNEL_CLEAR_INTERRUPT | (0 << CHANNEL_ENABLE)), +			dev->rdk1.plx9054_base_addr + DMACSR0); + +	/* reset */ +	writeb((1 << EPLD_DMA_ENABLE) | +		(1 << DMA_CTL_DACK) | +		(1 << DMA_TIMEOUT_ENABLE) | +		(1 << USER) | +		(0 << MPX_MODE) | +		(1 << BUSWIDTH) | +		(1 << NET2272_RESET), +		dev->base_addr + EPLD_IO_CONTROL_REGISTER); + +	mb(); +	writeb(readb(dev->base_addr + EPLD_IO_CONTROL_REGISTER) & +		~(1 << NET2272_RESET), +		dev->base_addr + EPLD_IO_CONTROL_REGISTER); +	udelay(200); + +	return 0; + + err: +	while (--i >= 0) { +		iounmap(mem_mapped_addr[i]); +		release_mem_region(pci_resource_start(pdev, i), +			pci_resource_len(pdev, i)); +	} + +	return ret; +} + +static int __devinit +net2272_rdk2_probe(struct pci_dev *pdev, struct net2272 *dev) +{ +	unsigned long resource, len; +	void __iomem *mem_mapped_addr[2]; +	int ret, i; + +	/* +	 * BAR 0 holds FGPA config registers +	 * BAR 1 holds NET2272 registers +	 */ + +	/* Find and map all address spaces, bar2-3 unused in rdk 2 */ +	for (i = 0; i < 2; ++i) { +		resource = pci_resource_start(pdev, i); +		len = pci_resource_len(pdev, i); + +		if (!request_mem_region(resource, len, driver_name)) { +			dev_dbg(dev->dev, "controller already in use\n"); +			ret = -EBUSY; +			goto err; +		} + +		mem_mapped_addr[i] = ioremap_nocache(resource, len); +		if (mem_mapped_addr[i] == NULL) { +			release_mem_region(resource, len); +			dev_dbg(dev->dev, "can't map memory\n"); +			ret = -EFAULT; +			goto err; +		} +	} + +	dev->rdk2.fpga_base_addr = mem_mapped_addr[0]; +	dev->base_addr = mem_mapped_addr[1]; + +	mb(); +	/* Set 2272 bus width (16 bits) and reset */ +	writel((1 << CHIP_RESET), dev->rdk2.fpga_base_addr + RDK2_LOCCTLRDK); +	udelay(200); +	writel((1 << BUS_WIDTH), dev->rdk2.fpga_base_addr + RDK2_LOCCTLRDK); +	/* Print fpga version number */ +	dev_info(dev->dev, "RDK2 FPGA version %08x\n", +		readl(dev->rdk2.fpga_base_addr + RDK2_FPGAREV)); +	/* Enable FPGA Interrupts */ +	writel((1 << NET2272_PCI_IRQ), dev->rdk2.fpga_base_addr + RDK2_IRQENB); + +	return 0; + + err: +	while (--i >= 0) { +		iounmap(mem_mapped_addr[i]); +		release_mem_region(pci_resource_start(pdev, i), +			pci_resource_len(pdev, i)); +	} + +	return ret; +} + +static int __devinit +net2272_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) +{ +	struct net2272 *dev; +	int ret; + +	dev = net2272_probe_init(&pdev->dev, pdev->irq); +	if (IS_ERR(dev)) +		return PTR_ERR(dev); +	dev->dev_id = pdev->device; + +	if (pci_enable_device(pdev) < 0) { +		ret = -ENODEV; +		goto err_free; +	} + +	pci_set_master(pdev); + +	switch (pdev->device) { +	case PCI_DEVICE_ID_RDK1: ret = net2272_rdk1_probe(pdev, dev); break; +	case PCI_DEVICE_ID_RDK2: ret = net2272_rdk2_probe(pdev, dev); break; +	default: BUG(); +	} +	if (ret) +		goto err_pci; + +	ret = net2272_probe_fin(dev, 0); +	if (ret) +		goto err_pci; + +	pci_set_drvdata(pdev, dev); + +	return 0; + + err_pci: +	pci_disable_device(pdev); + err_free: +	kfree(dev); + +	return ret; +} + +static void __devexit +net2272_rdk1_remove(struct pci_dev *pdev, struct net2272 *dev) +{ +	int i; + +	/* disable PLX 9054 interrupts */ +	writel(readl(dev->rdk1.plx9054_base_addr + INTCSR) & +		~(1 << PCI_INTERRUPT_ENABLE), +		dev->rdk1.plx9054_base_addr + INTCSR); + +	/* clean up resources allocated during probe() */ +	iounmap(dev->rdk1.plx9054_base_addr); +	iounmap(dev->rdk1.epld_base_addr); + +	for (i = 0; i < 4; ++i) { +		if (i == 1) +			continue;	/* BAR1 unused */ +		release_mem_region(pci_resource_start(pdev, i), +			pci_resource_len(pdev, i)); +	} +} + +static void __devexit +net2272_rdk2_remove(struct pci_dev *pdev, struct net2272 *dev) +{ +	int i; + +	/* disable fpga interrupts +	writel(readl(dev->rdk1.plx9054_base_addr + INTCSR) & +			~(1 << PCI_INTERRUPT_ENABLE), +			dev->rdk1.plx9054_base_addr + INTCSR); +	*/ + +	/* clean up resources allocated during probe() */ +	iounmap(dev->rdk2.fpga_base_addr); + +	for (i = 0; i < 2; ++i) +		release_mem_region(pci_resource_start(pdev, i), +			pci_resource_len(pdev, i)); +} + +static void __devexit +net2272_pci_remove(struct pci_dev *pdev) +{ +	struct net2272 *dev = pci_get_drvdata(pdev); + +	net2272_remove(dev); + +	switch (pdev->device) { +	case PCI_DEVICE_ID_RDK1: net2272_rdk1_remove(pdev, dev); break; +	case PCI_DEVICE_ID_RDK2: net2272_rdk2_remove(pdev, dev); break; +	default: BUG(); +	} + +	pci_disable_device(pdev); + +	kfree(dev); +} + +/* Table of matching PCI IDs */ +static struct pci_device_id __devinitdata pci_ids[] = { +	{	/* RDK 1 card */ +		.class       = ((PCI_CLASS_BRIDGE_OTHER << 8) | 0xfe), +		.class_mask  = 0, +		.vendor      = PCI_VENDOR_ID_PLX, +		.device      = PCI_DEVICE_ID_RDK1, +		.subvendor   = PCI_ANY_ID, +		.subdevice   = PCI_ANY_ID, +	}, +	{	/* RDK 2 card */ +		.class       = ((PCI_CLASS_BRIDGE_OTHER << 8) | 0xfe), +		.class_mask  = 0, +		.vendor      = PCI_VENDOR_ID_PLX, +		.device      = PCI_DEVICE_ID_RDK2, +		.subvendor   = PCI_ANY_ID, +		.subdevice   = PCI_ANY_ID, +	}, +	{ } +}; +MODULE_DEVICE_TABLE(pci, pci_ids); + +static struct pci_driver net2272_pci_driver = { +	.name     = driver_name, +	.id_table = pci_ids, + +	.probe    = net2272_pci_probe, +	.remove   = __devexit_p(net2272_pci_remove), +}; + +static int net2272_pci_register(void) +{ +	return pci_register_driver(&net2272_pci_driver); +} + +static void net2272_pci_unregister(void) +{ +	pci_unregister_driver(&net2272_pci_driver); +} + +#else +static inline int net2272_pci_register(void) { return 0; } +static inline void net2272_pci_unregister(void) { } +#endif + +/*---------------------------------------------------------------------------*/ + +static int __devinit +net2272_plat_probe(struct platform_device *pdev) +{ +	struct net2272 *dev; +	int ret; +	unsigned int irqflags; +	resource_size_t base, len; +	struct resource *iomem, *iomem_bus, *irq_res; + +	irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); +	iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0); +	iomem_bus = platform_get_resource(pdev, IORESOURCE_BUS, 0); +	if (!irq_res || !iomem) { +		dev_err(&pdev->dev, "must provide irq/base addr"); +		return -EINVAL; +	} + +	dev = net2272_probe_init(&pdev->dev, irq_res->start); +	if (IS_ERR(dev)) +		return PTR_ERR(dev); + +	irqflags = 0; +	if (irq_res->flags & IORESOURCE_IRQ_HIGHEDGE) +		irqflags |= IRQF_TRIGGER_RISING; +	if (irq_res->flags & IORESOURCE_IRQ_LOWEDGE) +		irqflags |= IRQF_TRIGGER_FALLING; +	if (irq_res->flags & IORESOURCE_IRQ_HIGHLEVEL) +		irqflags |= IRQF_TRIGGER_HIGH; +	if (irq_res->flags & IORESOURCE_IRQ_LOWLEVEL) +		irqflags |= IRQF_TRIGGER_LOW; + +	base = iomem->start; +	len = resource_size(iomem); +	if (iomem_bus) +		dev->base_shift = iomem_bus->start; + +	if (!request_mem_region(base, len, driver_name)) { +		dev_dbg(dev->dev, "get request memory region!\n"); +		ret = -EBUSY; +		goto err; +	} +	dev->base_addr = ioremap_nocache(base, len); +	if (!dev->base_addr) { +		dev_dbg(dev->dev, "can't map memory\n"); +		ret = -EFAULT; +		goto err_req; +	} + +	ret = net2272_probe_fin(dev, IRQF_TRIGGER_LOW); +	if (ret) +		goto err_io; + +	platform_set_drvdata(pdev, dev); +	dev_info(&pdev->dev, "running in 16-bit, %sbyte swap local bus mode\n", +		(net2272_read(dev, LOCCTL) & (1 << BYTE_SWAP)) ? "" : "no "); + +	the_controller = dev; + +	return 0; + + err_io: +	iounmap(dev->base_addr); + err_req: +	release_mem_region(base, len); + err: +	return ret; +} + +static int __devexit +net2272_plat_remove(struct platform_device *pdev) +{ +	struct net2272 *dev = platform_get_drvdata(pdev); + +	net2272_remove(dev); + +	release_mem_region(pdev->resource[0].start, +		resource_size(&pdev->resource[0])); + +	kfree(dev); + +	return 0; +} + +static struct platform_driver net2272_plat_driver = { +	.probe   = net2272_plat_probe, +	.remove  = __devexit_p(net2272_plat_remove), +	.driver  = { +		.name  = driver_name, +		.owner = THIS_MODULE, +	}, +	/* FIXME .suspend, .resume */ +}; +MODULE_ALIAS("platform:net2272"); + +static int __init net2272_init(void) +{ +	int ret; + +	ret = net2272_pci_register(); +	if (ret) +		return ret; +	ret = platform_driver_register(&net2272_plat_driver); +	if (ret) +		goto err_pci; +	return ret; + +err_pci: +	net2272_pci_unregister(); +	return ret; +} +module_init(net2272_init); + +static void __exit net2272_cleanup(void) +{ +	net2272_pci_unregister(); +	platform_driver_unregister(&net2272_plat_driver); +} +module_exit(net2272_cleanup); + +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_AUTHOR("PLX Technology, Inc."); +MODULE_LICENSE("GPL"); diff --git a/drivers/usb/gadget/net2272.h b/drivers/usb/gadget/net2272.h new file mode 100644 index 000000000000..e59505789359 --- /dev/null +++ b/drivers/usb/gadget/net2272.h @@ -0,0 +1,601 @@ +/* + * PLX NET2272 high/full speed USB device controller + * + * Copyright (C) 2005-2006 PLX Technology, Inc. + * Copyright (C) 2006-2011 Analog Devices, Inc. + * + * 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA + */ + +#ifndef __NET2272_H__ +#define __NET2272_H__ + +/* Main Registers */ +#define REGADDRPTR			0x00 +#define REGDATA				0x01 +#define IRQSTAT0			0x02 +#define 	ENDPOINT_0_INTERRUPT			0 +#define 	ENDPOINT_A_INTERRUPT			1 +#define 	ENDPOINT_B_INTERRUPT			2 +#define 	ENDPOINT_C_INTERRUPT			3 +#define 	VIRTUALIZED_ENDPOINT_INTERRUPT		4 +#define 	SETUP_PACKET_INTERRUPT			5 +#define 	DMA_DONE_INTERRUPT			6 +#define 	SOF_INTERRUPT				7 +#define IRQSTAT1			0x03 +#define 	CONTROL_STATUS_INTERRUPT		1 +#define 	VBUS_INTERRUPT				2 +#define 	SUSPEND_REQUEST_INTERRUPT		3 +#define 	SUSPEND_REQUEST_CHANGE_INTERRUPT	4 +#define 	RESUME_INTERRUPT			5 +#define 	ROOT_PORT_RESET_INTERRUPT		6 +#define 	RESET_STATUS				7 +#define PAGESEL				0x04 +#define DMAREQ				0x1c +#define 	DMA_ENDPOINT_SELECT			0 +#define 	DREQ_POLARITY				1 +#define 	DACK_POLARITY				2 +#define 	EOT_POLARITY				3 +#define 	DMA_CONTROL_DACK			4 +#define 	DMA_REQUEST_ENABLE			5 +#define 	DMA_REQUEST				6 +#define 	DMA_BUFFER_VALID			7 +#define SCRATCH				0x1d +#define IRQENB0				0x20 +#define 	ENDPOINT_0_INTERRUPT_ENABLE		0 +#define 	ENDPOINT_A_INTERRUPT_ENABLE		1 +#define 	ENDPOINT_B_INTERRUPT_ENABLE		2 +#define 	ENDPOINT_C_INTERRUPT_ENABLE		3 +#define 	VIRTUALIZED_ENDPOINT_INTERRUPT_ENABLE	4 +#define 	SETUP_PACKET_INTERRUPT_ENABLE		5 +#define 	DMA_DONE_INTERRUPT_ENABLE		6 +#define 	SOF_INTERRUPT_ENABLE			7 +#define IRQENB1				0x21 +#define 	VBUS_INTERRUPT_ENABLE			2 +#define 	SUSPEND_REQUEST_INTERRUPT_ENABLE	3 +#define 	SUSPEND_REQUEST_CHANGE_INTERRUPT_ENABLE	4 +#define 	RESUME_INTERRUPT_ENABLE			5 +#define 	ROOT_PORT_RESET_INTERRUPT_ENABLE	6 +#define LOCCTL				0x22 +#define 	DATA_WIDTH				0 +#define 	LOCAL_CLOCK_OUTPUT			1 +#define 		LOCAL_CLOCK_OUTPUT_OFF			0 +#define 		LOCAL_CLOCK_OUTPUT_3_75MHZ		1 +#define 		LOCAL_CLOCK_OUTPUT_7_5MHZ		2 +#define 		LOCAL_CLOCK_OUTPUT_15MHZ		3 +#define 		LOCAL_CLOCK_OUTPUT_30MHZ		4 +#define 		LOCAL_CLOCK_OUTPUT_60MHZ		5 +#define 	DMA_SPLIT_BUS_MODE			4 +#define 	BYTE_SWAP				5 +#define 	BUFFER_CONFIGURATION			6 +#define 		BUFFER_CONFIGURATION_EPA512_EPB512	0 +#define 		BUFFER_CONFIGURATION_EPA1024_EPB512	1 +#define 		BUFFER_CONFIGURATION_EPA1024_EPB1024	2 +#define 		BUFFER_CONFIGURATION_EPA1024DB		3 +#define CHIPREV_LEGACY			0x23 +#define 		NET2270_LEGACY_REV			0x40 +#define LOCCTL1				0x24 +#define 	DMA_MODE				0 +#define 		SLOW_DREQ				0 +#define 		FAST_DREQ				1 +#define 		BURST_MODE				2 +#define 	DMA_DACK_ENABLE				2 +#define CHIPREV_2272			0x25 +#define 		CHIPREV_NET2272_R1			0x10 +#define 		CHIPREV_NET2272_R1A			0x11 +/* USB Registers */ +#define USBCTL0				0x18 +#define 	IO_WAKEUP_ENABLE			1 +#define 	USB_DETECT_ENABLE			3 +#define 	USB_ROOT_PORT_WAKEUP_ENABLE		5 +#define USBCTL1				0x19 +#define 	VBUS_PIN				0 +#define 		USB_FULL_SPEED				1 +#define 		USB_HIGH_SPEED				2 +#define 	GENERATE_RESUME				3 +#define 	VIRTUAL_ENDPOINT_ENABLE			4 +#define FRAME0				0x1a +#define FRAME1				0x1b +#define OURADDR				0x30 +#define 	FORCE_IMMEDIATE				7 +#define USBDIAG				0x31 +#define 	FORCE_TRANSMIT_CRC_ERROR		0 +#define 	PREVENT_TRANSMIT_BIT_STUFF		1 +#define 	FORCE_RECEIVE_ERROR			2 +#define 	FAST_TIMES				4 +#define USBTEST				0x32 +#define 	TEST_MODE_SELECT			0 +#define 		NORMAL_OPERATION			0 +#define 		TEST_J					1 +#define 		TEST_K					2 +#define 		TEST_SE0_NAK				3 +#define 		TEST_PACKET				4 +#define 		TEST_FORCE_ENABLE			5 +#define XCVRDIAG			0x33 +#define 	FORCE_FULL_SPEED			2 +#define 	FORCE_HIGH_SPEED			3 +#define 	OPMODE					4 +#define 		NORMAL_OPERATION			0 +#define 		NON_DRIVING				1 +#define 		DISABLE_BITSTUFF_AND_NRZI_ENCODE	2 +#define 	LINESTATE				6 +#define 		SE0_STATE				0 +#define 		J_STATE					1 +#define 		K_STATE					2 +#define 		SE1_STATE				3 +#define VIRTOUT0			0x34 +#define VIRTOUT1			0x35 +#define VIRTIN0				0x36 +#define VIRTIN1				0x37 +#define SETUP0				0x40 +#define SETUP1				0x41 +#define SETUP2				0x42 +#define SETUP3				0x43 +#define SETUP4				0x44 +#define SETUP5				0x45 +#define SETUP6				0x46 +#define SETUP7				0x47 +/* Endpoint Registers (Paged via PAGESEL) */ +#define EP_DATA				0x05 +#define EP_STAT0			0x06 +#define 	DATA_IN_TOKEN_INTERRUPT			0 +#define 	DATA_OUT_TOKEN_INTERRUPT		1 +#define 	DATA_PACKET_TRANSMITTED_INTERRUPT	2 +#define 	DATA_PACKET_RECEIVED_INTERRUPT		3 +#define 	SHORT_PACKET_TRANSFERRED_INTERRUPT	4 +#define 	NAK_OUT_PACKETS				5 +#define 	BUFFER_EMPTY				6 +#define 	BUFFER_FULL				7 +#define EP_STAT1			0x07 +#define 	TIMEOUT					0 +#define 	USB_OUT_ACK_SENT			1 +#define 	USB_OUT_NAK_SENT			2 +#define 	USB_IN_ACK_RCVD				3 +#define 	USB_IN_NAK_SENT				4 +#define 	USB_STALL_SENT				5 +#define 	LOCAL_OUT_ZLP				6 +#define 	BUFFER_FLUSH				7 +#define EP_TRANSFER0			0x08 +#define EP_TRANSFER1			0x09 +#define EP_TRANSFER2			0x0a +#define EP_IRQENB			0x0b +#define 	DATA_IN_TOKEN_INTERRUPT_ENABLE		0 +#define 	DATA_OUT_TOKEN_INTERRUPT_ENABLE		1 +#define 	DATA_PACKET_TRANSMITTED_INTERRUPT_ENABLE	2 +#define 	DATA_PACKET_RECEIVED_INTERRUPT_ENABLE	3 +#define 	SHORT_PACKET_TRANSFERRED_INTERRUPT_ENABLE	4 +#define EP_AVAIL0			0x0c +#define EP_AVAIL1			0x0d +#define EP_RSPCLR			0x0e +#define EP_RSPSET			0x0f +#define 	ENDPOINT_HALT				0 +#define 	ENDPOINT_TOGGLE				1 +#define 	NAK_OUT_PACKETS_MODE			2 +#define 	CONTROL_STATUS_PHASE_HANDSHAKE		3 +#define 	INTERRUPT_MODE				4 +#define 	AUTOVALIDATE				5 +#define 	HIDE_STATUS_PHASE			6 +#define 	ALT_NAK_OUT_PACKETS			7 +#define EP_MAXPKT0			0x28 +#define EP_MAXPKT1			0x29 +#define 	ADDITIONAL_TRANSACTION_OPPORTUNITIES	3 +#define 		NONE_ADDITIONAL_TRANSACTION		0 +#define 		ONE_ADDITIONAL_TRANSACTION		1 +#define 		TWO_ADDITIONAL_TRANSACTION		2 +#define EP_CFG				0x2a +#define 	ENDPOINT_NUMBER				0 +#define 	ENDPOINT_DIRECTION			4 +#define 	ENDPOINT_TYPE				5 +#define 	ENDPOINT_ENABLE				7 +#define EP_HBW				0x2b +#define 	HIGH_BANDWIDTH_OUT_TRANSACTION_PID	0 +#define 		DATA0_PID				0 +#define 		DATA1_PID				1 +#define 		DATA2_PID				2 +#define 		MDATA_PID				3 +#define EP_BUFF_STATES			0x2c +#define 	BUFFER_A_STATE				0 +#define 	BUFFER_B_STATE				2 +#define 		BUFF_FREE				0 +#define 		BUFF_VALID				1 +#define 		BUFF_LCL				2 +#define 		BUFF_USB				3 + +/*---------------------------------------------------------------------------*/ + +#define PCI_DEVICE_ID_RDK1	0x9054 + +/* PCI-RDK EPLD Registers */ +#define RDK_EPLD_IO_REGISTER1		0x00000000 +#define 	RDK_EPLD_USB_RESET				0 +#define 	RDK_EPLD_USB_POWERDOWN				1 +#define 	RDK_EPLD_USB_WAKEUP				2 +#define 	RDK_EPLD_USB_EOT				3 +#define 	RDK_EPLD_DPPULL					4 +#define RDK_EPLD_IO_REGISTER2		0x00000004 +#define 	RDK_EPLD_BUSWIDTH				0 +#define 	RDK_EPLD_USER					2 +#define 	RDK_EPLD_RESET_INTERRUPT_ENABLE			3 +#define 	RDK_EPLD_DMA_TIMEOUT_ENABLE			4 +#define RDK_EPLD_STATUS_REGISTER	0x00000008 +#define 	RDK_EPLD_USB_LRESET				0 +#define RDK_EPLD_REVISION_REGISTER	0x0000000c + +/* PCI-RDK PLX 9054 Registers */ +#define INTCSR				0x68 +#define 	PCI_INTERRUPT_ENABLE				8 +#define 	LOCAL_INTERRUPT_INPUT_ENABLE			11 +#define 	LOCAL_INPUT_INTERRUPT_ACTIVE			15 +#define 	LOCAL_DMA_CHANNEL_0_INTERRUPT_ENABLE		18 +#define 	LOCAL_DMA_CHANNEL_1_INTERRUPT_ENABLE		19 +#define 	DMA_CHANNEL_0_INTERRUPT_ACTIVE			21 +#define 	DMA_CHANNEL_1_INTERRUPT_ACTIVE			22 +#define CNTRL				0x6C +#define 	RELOAD_CONFIGURATION_REGISTERS			29 +#define 	PCI_ADAPTER_SOFTWARE_RESET			30 +#define DMAMODE0			0x80 +#define 	LOCAL_BUS_WIDTH					0 +#define 	INTERNAL_WAIT_STATES				2 +#define 	TA_READY_INPUT_ENABLE				6 +#define 	LOCAL_BURST_ENABLE				8 +#define 	SCATTER_GATHER_MODE				9 +#define 	DONE_INTERRUPT_ENABLE				10 +#define 	LOCAL_ADDRESSING_MODE				11 +#define 	DEMAND_MODE					12 +#define 	DMA_EOT_ENABLE					14 +#define 	FAST_SLOW_TERMINATE_MODE_SELECT			15 +#define 	DMA_CHANNEL_INTERRUPT_SELECT			17 +#define DMAPADR0			0x84 +#define DMALADR0			0x88 +#define DMASIZ0				0x8c +#define DMADPR0				0x90 +#define 	DESCRIPTOR_LOCATION				0 +#define 	END_OF_CHAIN					1 +#define 	INTERRUPT_AFTER_TERMINAL_COUNT			2 +#define 	DIRECTION_OF_TRANSFER				3 +#define DMACSR0				0xa8 +#define 	CHANNEL_ENABLE					0 +#define 	CHANNEL_START					1 +#define 	CHANNEL_ABORT					2 +#define 	CHANNEL_CLEAR_INTERRUPT				3 +#define 	CHANNEL_DONE					4 +#define DMATHR				0xb0 +#define LBRD1				0xf8 +#define 	MEMORY_SPACE_LOCAL_BUS_WIDTH			0 +#define 	W8_BIT						0 +#define 	W16_BIT						1 + +/* Special OR'ing of INTCSR bits */ +#define LOCAL_INTERRUPT_TEST \ +	((1 << LOCAL_INPUT_INTERRUPT_ACTIVE) | \ +	 (1 << LOCAL_INTERRUPT_INPUT_ENABLE)) + +#define DMA_CHANNEL_0_TEST \ +	((1 << DMA_CHANNEL_0_INTERRUPT_ACTIVE) | \ +	 (1 << LOCAL_DMA_CHANNEL_0_INTERRUPT_ENABLE)) + +#define DMA_CHANNEL_1_TEST \ +	((1 << DMA_CHANNEL_1_INTERRUPT_ACTIVE) | \ +	 (1 << LOCAL_DMA_CHANNEL_1_INTERRUPT_ENABLE)) + +/* EPLD Registers */ +#define RDK_EPLD_IO_REGISTER1			0x00000000 +#define 	RDK_EPLD_USB_RESET			0 +#define 	RDK_EPLD_USB_POWERDOWN			1 +#define 	RDK_EPLD_USB_WAKEUP			2 +#define 	RDK_EPLD_USB_EOT			3 +#define 	RDK_EPLD_DPPULL				4 +#define RDK_EPLD_IO_REGISTER2			0x00000004 +#define 	RDK_EPLD_BUSWIDTH			0 +#define 	RDK_EPLD_USER				2 +#define 	RDK_EPLD_RESET_INTERRUPT_ENABLE		3 +#define 	RDK_EPLD_DMA_TIMEOUT_ENABLE		4 +#define RDK_EPLD_STATUS_REGISTER		0x00000008 +#define RDK_EPLD_USB_LRESET				0 +#define RDK_EPLD_REVISION_REGISTER		0x0000000c + +#define EPLD_IO_CONTROL_REGISTER		0x400 +#define 	NET2272_RESET				0 +#define 	BUSWIDTH				1 +#define 	MPX_MODE				3 +#define 	USER					4 +#define 	DMA_TIMEOUT_ENABLE			5 +#define 	DMA_CTL_DACK				6 +#define 	EPLD_DMA_ENABLE				7 +#define EPLD_DMA_CONTROL_REGISTER		0x800 +#define 	SPLIT_DMA_MODE				0 +#define 	SPLIT_DMA_DIRECTION			1 +#define 	SPLIT_DMA_ENABLE			2 +#define 	SPLIT_DMA_INTERRUPT_ENABLE		3 +#define 	SPLIT_DMA_INTERRUPT			4 +#define 	EPLD_DMA_MODE				5 +#define 	EPLD_DMA_CONTROLLER_ENABLE		7 +#define SPLIT_DMA_ADDRESS_LOW			0xc00 +#define SPLIT_DMA_ADDRESS_HIGH			0x1000 +#define SPLIT_DMA_BYTE_COUNT_LOW		0x1400 +#define SPLIT_DMA_BYTE_COUNT_HIGH		0x1800 +#define EPLD_REVISION_REGISTER			0x1c00 +#define SPLIT_DMA_RAM				0x4000 +#define DMA_RAM_SIZE				0x1000 + +/*---------------------------------------------------------------------------*/ + +#define PCI_DEVICE_ID_RDK2	0x3272 + +/* PCI-RDK version 2 registers */ + +/* Main Control Registers */ + +#define RDK2_IRQENB			0x00 +#define RDK2_IRQSTAT			0x04 +#define 	PB7				23 +#define 	PB6				22 +#define 	PB5				21 +#define 	PB4				20 +#define 	PB3				19 +#define 	PB2				18 +#define 	PB1				17 +#define 	PB0				16 +#define 	GP3				23 +#define 	GP2				23 +#define 	GP1				23 +#define 	GP0				23 +#define 	DMA_RETRY_ABORT			6 +#define 	DMA_PAUSE_DONE			5 +#define 	DMA_ABORT_DONE			4 +#define 	DMA_OUT_FIFO_TRANSFER_DONE	3 +#define 	DMA_LOCAL_DONE			2 +#define 	DMA_PCI_DONE			1 +#define 	NET2272_PCI_IRQ			0 + +#define RDK2_LOCCTLRDK			0x08 +#define 	CHIP_RESET			3 +#define 	SPLIT_DMA			2 +#define 	MULTIPLEX_MODE			1 +#define 	BUS_WIDTH			0 + +#define RDK2_GPIOCTL			0x10 +#define 	GP3_OUT_ENABLE					7 +#define 	GP2_OUT_ENABLE					6 +#define 	GP1_OUT_ENABLE					5 +#define 	GP0_OUT_ENABLE					4 +#define 	GP3_DATA					3 +#define 	GP2_DATA					2 +#define 	GP1_DATA					1 +#define 	GP0_DATA					0 + +#define RDK2_LEDSW			0x14 +#define 	LED3				27 +#define 	LED2				26 +#define 	LED1				25 +#define 	LED0				24 +#define 	PBUTTON				16 +#define 	DIPSW				0 + +#define RDK2_DIAG			0x18 +#define 	RDK2_FAST_TIMES				2 +#define 	FORCE_PCI_SERR				1 +#define 	FORCE_PCI_INT				0 +#define RDK2_FPGAREV			0x1C + +/* Dma Control registers */ +#define RDK2_DMACTL			0x80 +#define 	ADDR_HOLD				24 +#define 	RETRY_COUNT				16	/* 23:16 */ +#define 	FIFO_THRESHOLD				11	/* 15:11 */ +#define 	MEM_WRITE_INVALIDATE			10 +#define 	READ_MULTIPLE				9 +#define 	READ_LINE				8 +#define 	RDK2_DMA_MODE				6	/* 7:6 */ +#define 	CONTROL_DACK				5 +#define 	EOT_ENABLE				4 +#define 	EOT_POLARITY				3 +#define 	DACK_POLARITY				2 +#define 	DREQ_POLARITY				1 +#define 	DMA_ENABLE				0 + +#define RDK2_DMASTAT			0x84 +#define 	GATHER_COUNT				12	/* 14:12 */ +#define 	FIFO_COUNT				6	/* 11:6 */ +#define 	FIFO_FLUSH				5 +#define 	FIFO_TRANSFER				4 +#define 	PAUSE_DONE				3 +#define 	ABORT_DONE				2 +#define 	DMA_ABORT				1 +#define 	DMA_START				0 + +#define RDK2_DMAPCICOUNT		0x88 +#define 	DMA_DIRECTION				31 +#define 	DMA_PCI_BYTE_COUNT			0	/* 0:23 */ + +#define RDK2_DMALOCCOUNT		0x8C	/* 0:23 dma local byte count */ + +#define RDK2_DMAADDR			0x90	/* 2:31 PCI bus starting address */ + +/*---------------------------------------------------------------------------*/ + +#define REG_INDEXED_THRESHOLD	(1 << 5) + +/* DRIVER DATA STRUCTURES and UTILITIES */ +struct net2272_ep { +	struct usb_ep ep; +	struct net2272 *dev; +	unsigned long irqs; + +	/* analogous to a host-side qh */ +	struct list_head queue; +	const struct usb_endpoint_descriptor *desc; +	unsigned num:8, +	         fifo_size:12, +	         stopped:1, +	         wedged:1, +	         is_in:1, +	         is_iso:1, +	         dma:1, +	         not_empty:1; +}; + +struct net2272 { +	/* each device provides one gadget, several endpoints */ +	struct usb_gadget gadget; +	struct device *dev; +	unsigned short dev_id; + +	spinlock_t lock; +	struct net2272_ep ep[4]; +	struct usb_gadget_driver *driver; +	unsigned protocol_stall:1, +	         softconnect:1, +	         is_selfpowered:1, +	         wakeup:1, +	         dma_eot_polarity:1, +	         dma_dack_polarity:1, +	         dma_dreq_polarity:1, +	         dma_busy:1; +	u16 chiprev; +	u8 pagesel; + +	unsigned int irq; +	unsigned short fifo_mode; + +	unsigned int base_shift; +	u16 __iomem *base_addr; +	union { +#ifdef CONFIG_PCI +		struct { +			void __iomem *plx9054_base_addr; +			void __iomem *epld_base_addr; +		} rdk1; +		struct { +			/* Bar0, Bar1 is base_addr both mem-mapped */ +			void __iomem *fpga_base_addr; +		} rdk2; +#endif +	}; +}; + +static void __iomem * +net2272_reg_addr(struct net2272 *dev, unsigned int reg) +{ +	return dev->base_addr + (reg << dev->base_shift); +} + +static void +net2272_write(struct net2272 *dev, unsigned int reg, u8 value) +{ +	if (reg >= REG_INDEXED_THRESHOLD) { +		/* +		 * Indexed register; use REGADDRPTR/REGDATA +		 *  - Save and restore REGADDRPTR. This prevents REGADDRPTR from +		 *    changes between other code sections, but it is time consuming. +		 *  - Performance tips: either do not save and restore REGADDRPTR (if it +		 *    is safe) or do save/restore operations only in critical sections. +		u8 tmp = readb(dev->base_addr + REGADDRPTR); +		 */ +		writeb((u8)reg, net2272_reg_addr(dev, REGADDRPTR)); +		writeb(value, net2272_reg_addr(dev, REGDATA)); +		/* writeb(tmp, net2272_reg_addr(dev, REGADDRPTR)); */ +	} else +		writeb(value, net2272_reg_addr(dev, reg)); +} + +static u8 +net2272_read(struct net2272 *dev, unsigned int reg) +{ +	u8 ret; + +	if (reg >= REG_INDEXED_THRESHOLD) { +		/* +		 * Indexed register; use REGADDRPTR/REGDATA +		 *  - Save and restore REGADDRPTR. This prevents REGADDRPTR from +		 *    changes between other code sections, but it is time consuming. +		 *  - Performance tips: either do not save and restore REGADDRPTR (if it +		 *    is safe) or do save/restore operations only in critical sections. +		u8 tmp = readb(dev->base_addr + REGADDRPTR); +		 */ +		writeb((u8)reg, net2272_reg_addr(dev, REGADDRPTR)); +		ret = readb(net2272_reg_addr(dev, REGDATA)); +		/* writeb(tmp, net2272_reg_addr(dev, REGADDRPTR)); */ +	} else +		ret = readb(net2272_reg_addr(dev, reg)); + +	return ret; +} + +static void +net2272_ep_write(struct net2272_ep *ep, unsigned int reg, u8 value) +{ +	struct net2272 *dev = ep->dev; + +	if (dev->pagesel != ep->num) { +		net2272_write(dev, PAGESEL, ep->num); +		dev->pagesel = ep->num; +	} +	net2272_write(dev, reg, value); +} + +static u8 +net2272_ep_read(struct net2272_ep *ep, unsigned int reg) +{ +	struct net2272 *dev = ep->dev; + +	if (dev->pagesel != ep->num) { +		net2272_write(dev, PAGESEL, ep->num); +		dev->pagesel = ep->num; +	} +	return net2272_read(dev, reg); +} + +static void allow_status(struct net2272_ep *ep) +{ +	/* ep0 only */ +	net2272_ep_write(ep, EP_RSPCLR, +		(1 << CONTROL_STATUS_PHASE_HANDSHAKE) | +		(1 << ALT_NAK_OUT_PACKETS) | +		(1 << NAK_OUT_PACKETS_MODE)); +	ep->stopped = 1; +} + +static void set_halt(struct net2272_ep *ep) +{ +	/* ep0 and bulk/intr endpoints */ +	net2272_ep_write(ep, EP_RSPCLR, 1 << CONTROL_STATUS_PHASE_HANDSHAKE); +	net2272_ep_write(ep, EP_RSPSET, 1 << ENDPOINT_HALT); +} + +static void clear_halt(struct net2272_ep *ep) +{ +	/* ep0 and bulk/intr endpoints */ +	net2272_ep_write(ep, EP_RSPCLR, +		(1 << ENDPOINT_HALT) | (1 << ENDPOINT_TOGGLE)); +} + +/* count (<= 4) bytes in the next fifo write will be valid */ +static void set_fifo_bytecount(struct net2272_ep *ep, unsigned count) +{ +	/* net2272_ep_write will truncate to u8 for us */ +	net2272_ep_write(ep, EP_TRANSFER2, count >> 16); +	net2272_ep_write(ep, EP_TRANSFER1, count >> 8); +	net2272_ep_write(ep, EP_TRANSFER0, count); +} + +struct net2272_request { +	struct usb_request req; +	struct list_head queue; +	unsigned mapped:1, +	         valid:1; +}; + +#endif diff --git a/drivers/usb/gadget/net2280.c b/drivers/usb/gadget/net2280.c index 24696f7fa6a9..3dd40b4e675c 100644 --- a/drivers/usb/gadget/net2280.c +++ b/drivers/usb/gadget/net2280.c @@ -63,6 +63,7 @@  #include <linux/device.h>  #include <linux/usb/ch9.h>  #include <linux/usb/gadget.h> +#include <linux/prefetch.h>  #include <asm/byteorder.h>  #include <asm/io.h> @@ -1409,11 +1410,17 @@ static int net2280_pullup(struct usb_gadget *_gadget, int is_on)  	return 0;  } +static int net2280_start(struct usb_gadget_driver *driver, +		int (*bind)(struct usb_gadget *)); +static int net2280_stop(struct usb_gadget_driver *driver); +  static const struct usb_gadget_ops net2280_ops = {  	.get_frame	= net2280_get_frame,  	.wakeup		= net2280_wakeup,  	.set_selfpowered = net2280_set_selfpowered,  	.pullup		= net2280_pullup, +	.start		= net2280_start, +	.stop		= net2280_stop,  };  /*-------------------------------------------------------------------------*/ @@ -1737,62 +1744,6 @@ static void set_fifo_mode (struct net2280 *dev, int mode)  	list_add_tail (&dev->ep [6].ep.ep_list, &dev->gadget.ep_list);  } -/* just declare this in any driver that really need it */ -extern int net2280_set_fifo_mode (struct usb_gadget *gadget, int mode); - -/** - * net2280_set_fifo_mode - change allocation of fifo buffers - * @gadget: access to the net2280 device that will be updated - * @mode: 0 for default, four 1kB buffers (ep-a through ep-d); - *	1 for two 2kB buffers (ep-a and ep-b only); - *	2 for one 2kB buffer (ep-a) and two 1kB ones (ep-b, ep-c). - * - * returns zero on success, else negative errno.  when this succeeds, - * the contents of gadget->ep_list may have changed. - * - * you may only call this function when endpoints a-d are all disabled. - * use it whenever extra hardware buffering can help performance, such - * as before enabling "high bandwidth" interrupt endpoints that use - * maxpacket bigger than 512 (when double buffering would otherwise - * be unavailable). - */ -int net2280_set_fifo_mode (struct usb_gadget *gadget, int mode) -{ -	int			i; -	struct net2280		*dev; -	int			status = 0; -	unsigned long		flags; - -	if (!gadget) -		return -ENODEV; -	dev = container_of (gadget, struct net2280, gadget); - -	spin_lock_irqsave (&dev->lock, flags); - -	for (i = 1; i <= 4; i++) -		if (dev->ep [i].desc) { -			status = -EINVAL; -			break; -		} -	if (mode < 0 || mode > 2) -		status = -EINVAL; -	if (status == 0) -		set_fifo_mode (dev, mode); -	spin_unlock_irqrestore (&dev->lock, flags); - -	if (status == 0) { -		if (mode == 1) -			DEBUG (dev, "fifo:  ep-a 2K, ep-b 2K\n"); -		else if (mode == 2) -			DEBUG (dev, "fifo:  ep-a 2K, ep-b 1K, ep-c 1K\n"); -		/* else all are 1K */ -	} -	return status; -} -EXPORT_SYMBOL (net2280_set_fifo_mode); - -/*-------------------------------------------------------------------------*/ -  /* keeping it simple:   * - one bus driver, initted first;   * - one function driver, initted second @@ -1929,7 +1880,7 @@ static void ep0_start (struct net2280 *dev)   * disconnect is reported.  then a host may connect again, or   * the driver might get unbound.   */ -int usb_gadget_probe_driver(struct usb_gadget_driver *driver, +static int net2280_start(struct usb_gadget_driver *driver,  		int (*bind)(struct usb_gadget *))  {  	struct net2280		*dev = the_controller; @@ -1993,7 +1944,6 @@ err_unbind:  	dev->driver = NULL;  	return retval;  } -EXPORT_SYMBOL(usb_gadget_probe_driver);  static void  stop_activity (struct net2280 *dev, struct usb_gadget_driver *driver) @@ -2021,7 +1971,7 @@ stop_activity (struct net2280 *dev, struct usb_gadget_driver *driver)  	usb_reinit (dev);  } -int usb_gadget_unregister_driver (struct usb_gadget_driver *driver) +static int net2280_stop(struct usb_gadget_driver *driver)  {  	struct net2280	*dev = the_controller;  	unsigned long	flags; @@ -2048,8 +1998,6 @@ int usb_gadget_unregister_driver (struct usb_gadget_driver *driver)  	DEBUG (dev, "unregistered driver '%s'\n", driver->driver.name);  	return 0;  } -EXPORT_SYMBOL (usb_gadget_unregister_driver); -  /*-------------------------------------------------------------------------*/ @@ -2731,6 +2679,8 @@ static void net2280_remove (struct pci_dev *pdev)  {  	struct net2280		*dev = pci_get_drvdata (pdev); +	usb_del_gadget_udc(&dev->gadget); +  	BUG_ON(dev->driver);  	/* then clean up the resources we allocated during probe() */ @@ -2915,6 +2865,9 @@ static int net2280_probe (struct pci_dev *pdev, const struct pci_device_id *id)  	retval = device_create_file (&pdev->dev, &dev_attr_registers);  	if (retval) goto done; +	retval = usb_add_gadget_udc(&pdev->dev, &dev->gadget); +	if (retval) +		goto done;  	return 0;  done: diff --git a/drivers/usb/gadget/nokia.c b/drivers/usb/gadget/nokia.c index 55ca63ad3506..c7fb7723c014 100644 --- a/drivers/usb/gadget/nokia.c +++ b/drivers/usb/gadget/nokia.c @@ -241,6 +241,7 @@ static struct usb_composite_driver nokia_driver = {  	.name		= "g_nokia",  	.dev		= &device_desc,  	.strings	= dev_strings, +	.max_speed	= USB_SPEED_HIGH,  	.unbind		= __exit_p(nokia_unbind),  }; diff --git a/drivers/usb/gadget/omap_udc.c b/drivers/usb/gadget/omap_udc.c index 82fd24935332..740c7daed279 100644 --- a/drivers/usb/gadget/omap_udc.c +++ b/drivers/usb/gadget/omap_udc.c @@ -1375,6 +1375,10 @@ static int omap_pullup(struct usb_gadget *gadget, int is_on)  	return 0;  } +static int omap_udc_start(struct usb_gadget_driver *driver, +		int (*bind)(struct usb_gadget *)); +static int omap_udc_stop(struct usb_gadget_driver *driver); +  static struct usb_gadget_ops omap_gadget_ops = {  	.get_frame		= omap_get_frame,  	.wakeup			= omap_wakeup, @@ -1382,6 +1386,8 @@ static struct usb_gadget_ops omap_gadget_ops = {  	.vbus_session		= omap_vbus_session,  	.vbus_draw		= omap_vbus_draw,  	.pullup			= omap_pullup, +	.start			= omap_udc_start, +	.stop			= omap_udc_stop,  };  /*-------------------------------------------------------------------------*/ @@ -2102,7 +2108,7 @@ static inline int machine_without_vbus_sense(void)  		);  } -int usb_gadget_probe_driver(struct usb_gadget_driver *driver, +static int omap_udc_start(struct usb_gadget_driver *driver,  		int (*bind)(struct usb_gadget *))  {  	int		status = -ENODEV; @@ -2186,9 +2192,8 @@ done:  		omap_udc_enable_clock(0);  	return status;  } -EXPORT_SYMBOL(usb_gadget_probe_driver); -int usb_gadget_unregister_driver (struct usb_gadget_driver *driver) +static int omap_udc_stop(struct usb_gadget_driver *driver)  {  	unsigned long	flags;  	int		status = -ENODEV; @@ -2222,8 +2227,6 @@ int usb_gadget_unregister_driver (struct usb_gadget_driver *driver)  	DBG("unregistered driver '%s'\n", driver->driver.name);  	return status;  } -EXPORT_SYMBOL(usb_gadget_unregister_driver); -  /*-------------------------------------------------------------------------*/ @@ -2991,9 +2994,16 @@ known:  	create_proc_file();  	status = device_add(&udc->gadget.dev); +	if (status) +		goto cleanup4; + +	status = usb_add_gadget_udc(&pdev->dev, &udc->gadget);  	if (!status)  		return status;  	/* If fail, fall through */ +cleanup4: +	remove_proc_file(); +  #ifdef	USE_ISO  cleanup3:  	free_irq(pdev->resource[2].start, udc); @@ -3029,6 +3039,8 @@ static int __exit omap_udc_remove(struct platform_device *pdev)  	if (!udc)  		return -ENODEV; + +	usb_del_gadget_udc(&udc->gadget);  	if (udc->driver)  		return -EBUSY; diff --git a/drivers/usb/gadget/pch_udc.c b/drivers/usb/gadget/pch_udc.c index 68dbcc3e4cc2..f96615ab6b77 100644 --- a/drivers/usb/gadget/pch_udc.c +++ b/drivers/usb/gadget/pch_udc.c @@ -1176,6 +1176,9 @@ static int pch_udc_pcd_vbus_draw(struct usb_gadget *gadget, unsigned int mA)  	return -EOPNOTSUPP;  } +static int pch_udc_start(struct usb_gadget_driver *driver, +	int (*bind)(struct usb_gadget *)); +static int pch_udc_stop(struct usb_gadget_driver *driver);  static const struct usb_gadget_ops pch_udc_ops = {  	.get_frame = pch_udc_pcd_get_frame,  	.wakeup = pch_udc_pcd_wakeup, @@ -1183,6 +1186,8 @@ static const struct usb_gadget_ops pch_udc_ops = {  	.pullup = pch_udc_pcd_pullup,  	.vbus_session = pch_udc_pcd_vbus_session,  	.vbus_draw = pch_udc_pcd_vbus_draw, +	.start	= pch_udc_start, +	.stop	= pch_udc_stop,  };  /** @@ -2690,7 +2695,7 @@ static int init_dma_pools(struct pch_udc_dev *dev)  	return 0;  } -int usb_gadget_probe_driver(struct usb_gadget_driver *driver, +static int pch_udc_start(struct usb_gadget_driver *driver,  	int (*bind)(struct usb_gadget *))  {  	struct pch_udc_dev	*dev = pch_udc; @@ -2733,9 +2738,8 @@ int usb_gadget_probe_driver(struct usb_gadget_driver *driver,  	dev->connected = 1;  	return 0;  } -EXPORT_SYMBOL(usb_gadget_probe_driver); -int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) +static int pch_udc_stop(struct usb_gadget_driver *driver)  {  	struct pch_udc_dev	*dev = pch_udc; @@ -2761,7 +2765,6 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)  	pch_udc_set_disconnect(dev);  	return 0;  } -EXPORT_SYMBOL(usb_gadget_unregister_driver);  static void pch_udc_shutdown(struct pci_dev *pdev)  { @@ -2778,6 +2781,8 @@ static void pch_udc_remove(struct pci_dev *pdev)  {  	struct pch_udc_dev	*dev = pci_get_drvdata(pdev); +	usb_del_gadget_udc(&dev->gadget); +  	/* gadget driver must not be registered */  	if (dev->driver)  		dev_err(&pdev->dev, @@ -2953,6 +2958,9 @@ static int pch_udc_probe(struct pci_dev *pdev,  	/* Put the device in disconnected state till a driver is bound */  	pch_udc_set_disconnect(dev); +	retval = usb_add_gadget_udc(&pdev->dev, &dev->gadget); +	if (retval) +		goto finished;  	return 0;  finished: diff --git a/drivers/usb/gadget/printer.c b/drivers/usb/gadget/printer.c index 271ef94668e7..a341dde6f9c3 100644 --- a/drivers/usb/gadget/printer.c +++ b/drivers/usb/gadget/printer.c @@ -89,8 +89,7 @@ struct printer_dev {  	u8			config;  	s8			interface;  	struct usb_ep		*in_ep, *out_ep; -	const struct usb_endpoint_descriptor -				*in, *out; +  	struct list_head	rx_reqs;	/* List of free RX structs */  	struct list_head	rx_reqs_active;	/* List of Active RX xfers */  	struct list_head	rx_buffers;	/* List of completed xfers */ @@ -795,12 +794,14 @@ printer_write(struct file *fd, const char __user *buf, size_t len, loff_t *ptr)  }  static int -printer_fsync(struct file *fd, int datasync) +printer_fsync(struct file *fd, loff_t start, loff_t end, int datasync)  {  	struct printer_dev	*dev = fd->private_data; +	struct inode *inode = fd->f_path.dentry->d_inode;  	unsigned long		flags;  	int			tx_list_empty; +	mutex_lock(&inode->i_mutex);  	spin_lock_irqsave(&dev->lock, flags);  	tx_list_empty = (likely(list_empty(&dev->tx_reqs)));  	spin_unlock_irqrestore(&dev->lock, flags); @@ -810,6 +811,7 @@ printer_fsync(struct file *fd, int datasync)  		wait_event_interruptible(dev->tx_flush_wait,  				(likely(list_empty(&dev->tx_reqs_active))));  	} +	mutex_unlock(&inode->i_mutex);  	return 0;  } @@ -895,19 +897,20 @@ set_printer_interface(struct printer_dev *dev)  {  	int			result = 0; -	dev->in = ep_desc(dev->gadget, &hs_ep_in_desc, &fs_ep_in_desc); +	dev->in_ep->desc = ep_desc(dev->gadget, &hs_ep_in_desc, &fs_ep_in_desc);  	dev->in_ep->driver_data = dev; -	dev->out = ep_desc(dev->gadget, &hs_ep_out_desc, &fs_ep_out_desc); +	dev->out_ep->desc = ep_desc(dev->gadget, &hs_ep_out_desc, +				    &fs_ep_out_desc);  	dev->out_ep->driver_data = dev; -	result = usb_ep_enable(dev->in_ep, dev->in); +	result = usb_ep_enable(dev->in_ep);  	if (result != 0) {  		DBG(dev, "enable %s --> %d\n", dev->in_ep->name, result);  		goto done;  	} -	result = usb_ep_enable(dev->out_ep, dev->out); +	result = usb_ep_enable(dev->out_ep);  	if (result != 0) {  		DBG(dev, "enable %s --> %d\n", dev->in_ep->name, result);  		goto done; @@ -918,8 +921,8 @@ done:  	if (result != 0) {  		(void) usb_ep_disable(dev->in_ep);  		(void) usb_ep_disable(dev->out_ep); -		dev->in = NULL; -		dev->out = NULL; +		dev->in_ep->desc = NULL; +		dev->out_ep->desc = NULL;  	}  	/* caller is responsible for cleanup on error */ @@ -933,12 +936,14 @@ static void printer_reset_interface(struct printer_dev *dev)  	DBG(dev, "%s\n", __func__); -	if (dev->in) +	if (dev->in_ep->desc)  		usb_ep_disable(dev->in_ep); -	if (dev->out) +	if (dev->out_ep->desc)  		usb_ep_disable(dev->out_ep); +	dev->in_ep->desc = NULL; +	dev->out_ep->desc = NULL;  	dev->interface = -1;  } @@ -1104,9 +1109,9 @@ static void printer_soft_reset(struct printer_dev *dev)  		list_add(&req->list, &dev->tx_reqs);  	} -	if (usb_ep_enable(dev->in_ep, dev->in)) +	if (usb_ep_enable(dev->in_ep))  		DBG(dev, "Failed to enable USB in_ep\n"); -	if (usb_ep_enable(dev->out_ep, dev->out)) +	if (usb_ep_enable(dev->out_ep))  		DBG(dev, "Failed to enable USB out_ep\n");  	wake_up_interruptible(&dev->rx_wait); @@ -1146,6 +1151,8 @@ printer_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)  			switch (wValue >> 8) {  			case USB_DT_DEVICE: +				device_desc.bMaxPacketSize0 = +					gadget->ep0->maxpacket;  				value = min(wLength, (u16) sizeof device_desc);  				memcpy(req->buf, &device_desc, value);  				break; @@ -1153,6 +1160,12 @@ printer_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)  			case USB_DT_DEVICE_QUALIFIER:  				if (!gadget->is_dualspeed)  					break; +				/* +				 * assumes ep0 uses the same value for both +				 * speeds +				 */ +				dev_qualifier.bMaxPacketSize0 = +					gadget->ep0->maxpacket;  				value = min(wLength,  						(u16) sizeof dev_qualifier);  				memcpy(req->buf, &dev_qualifier, value); @@ -1448,15 +1461,11 @@ autoconf_fail:  	out_ep->driver_data = out_ep;	/* claim */  #ifdef	CONFIG_USB_GADGET_DUALSPEED -	/* assumes ep0 uses the same value for both speeds ... */ -	dev_qualifier.bMaxPacketSize0 = device_desc.bMaxPacketSize0; - -	/* and that all endpoints are dual-speed */ +	/* assumes that all endpoints are dual-speed */  	hs_ep_in_desc.bEndpointAddress = fs_ep_in_desc.bEndpointAddress;  	hs_ep_out_desc.bEndpointAddress = fs_ep_out_desc.bEndpointAddress;  #endif	/* DUALSPEED */ -	device_desc.bMaxPacketSize0 = gadget->ep0->maxpacket;  	usb_gadget_set_selfpowered(gadget);  	if (gadget->is_otg) { diff --git a/drivers/usb/gadget/pxa25x_udc.c b/drivers/usb/gadget/pxa25x_udc.c index 365c02fc25fc..e4e59b4de25d 100644 --- a/drivers/usb/gadget/pxa25x_udc.c +++ b/drivers/usb/gadget/pxa25x_udc.c @@ -1011,12 +1011,18 @@ static int pxa25x_udc_vbus_draw(struct usb_gadget *_gadget, unsigned mA)  	return -EOPNOTSUPP;  } +static int pxa25x_start(struct usb_gadget_driver *driver, +		int (*bind)(struct usb_gadget *)); +static int pxa25x_stop(struct usb_gadget_driver *driver); +  static const struct usb_gadget_ops pxa25x_udc_ops = {  	.get_frame	= pxa25x_udc_get_frame,  	.wakeup		= pxa25x_udc_wakeup,  	.vbus_session	= pxa25x_udc_vbus_session,  	.pullup		= pxa25x_udc_pullup,  	.vbus_draw	= pxa25x_udc_vbus_draw, +	.start		= pxa25x_start, +	.stop		= pxa25x_stop,  };  /*-------------------------------------------------------------------------*/ @@ -1263,7 +1269,7 @@ static void udc_enable (struct pxa25x_udc *dev)   * disconnect is reported.  then a host may connect again, or   * the driver might get unbound.   */ -int usb_gadget_probe_driver(struct usb_gadget_driver *driver, +static int pxa25x_start(struct usb_gadget_driver *driver,  		int (*bind)(struct usb_gadget *))  {  	struct pxa25x_udc	*dev = the_controller; @@ -1322,7 +1328,6 @@ fail:  bind_fail:  	return retval;  } -EXPORT_SYMBOL(usb_gadget_probe_driver);  static void  stop_activity(struct pxa25x_udc *dev, struct usb_gadget_driver *driver) @@ -1351,7 +1356,7 @@ stop_activity(struct pxa25x_udc *dev, struct usb_gadget_driver *driver)  	udc_reinit(dev);  } -int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) +static int pxa25x_stop(struct usb_gadget_driver *driver)  {  	struct pxa25x_udc	*dev = the_controller; @@ -1379,8 +1384,6 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)  	dump_state(dev);  	return 0;  } -EXPORT_SYMBOL(usb_gadget_unregister_driver); -  /*-------------------------------------------------------------------------*/ @@ -2216,7 +2219,6 @@ static int __init pxa25x_udc_probe(struct platform_device *pdev)  		if (retval != 0) {  			pr_err("%s: can't get irq %i, err %d\n",  				driver_name, LUBBOCK_USB_DISC_IRQ, retval); -lubbock_fail0:  			goto err_irq_lub;  		}  		retval = request_irq(LUBBOCK_USB_IRQ, @@ -2226,20 +2228,23 @@ lubbock_fail0:  		if (retval != 0) {  			pr_err("%s: can't get irq %i, err %d\n",  				driver_name, LUBBOCK_USB_IRQ, retval); -			free_irq(LUBBOCK_USB_DISC_IRQ, dev);  			goto lubbock_fail0;  		}  	} else  #endif  	create_debug_files(dev); -	return 0; +	retval = usb_add_gadget_udc(&pdev->dev, &dev->gadget); +	if (!retval) +		return retval; +	remove_debug_files(dev);  #ifdef	CONFIG_ARCH_LUBBOCK +lubbock_fail0:  	free_irq(LUBBOCK_USB_DISC_IRQ, dev);   err_irq_lub: -#endif  	free_irq(irq, dev); +#endif   err_irq1:  	if (gpio_is_valid(dev->mach->gpio_pullup))  		gpio_free(dev->mach->gpio_pullup); @@ -2262,6 +2267,7 @@ static int __exit pxa25x_udc_remove(struct platform_device *pdev)  {  	struct pxa25x_udc *dev = platform_get_drvdata(pdev); +	usb_del_gadget_udc(&dev->gadget);  	if (dev->driver)  		return -EBUSY; diff --git a/drivers/usb/gadget/pxa27x_udc.c b/drivers/usb/gadget/pxa27x_udc.c index 57607696735c..85b68c75dc9d 100644 --- a/drivers/usb/gadget/pxa27x_udc.c +++ b/drivers/usb/gadget/pxa27x_udc.c @@ -1680,12 +1680,18 @@ static int pxa_udc_vbus_draw(struct usb_gadget *_gadget, unsigned mA)  	return -EOPNOTSUPP;  } +static int pxa27x_udc_start(struct usb_gadget_driver *driver, +		int (*bind)(struct usb_gadget *)); +static int pxa27x_udc_stop(struct usb_gadget_driver *driver); +  static const struct usb_gadget_ops pxa_udc_ops = {  	.get_frame	= pxa_udc_get_frame,  	.wakeup		= pxa_udc_wakeup,  	.pullup		= pxa_udc_pullup,  	.vbus_session	= pxa_udc_vbus_session,  	.vbus_draw	= pxa_udc_vbus_draw, +	.start		= pxa27x_udc_start, +	.stop		= pxa27x_udc_stop,  };  /** @@ -1791,7 +1797,7 @@ static void udc_enable(struct pxa_udc *udc)  }  /** - * usb_gadget_probe_driver - Register gadget driver + * pxa27x_start - Register gadget driver   * @driver: gadget driver   * @bind: bind function   * @@ -1805,7 +1811,7 @@ static void udc_enable(struct pxa_udc *udc)   *   * Returns 0 if no error, -EINVAL, -ENODEV, -EBUSY otherwise   */ -int usb_gadget_probe_driver(struct usb_gadget_driver *driver, +static int pxa27x_udc_start(struct usb_gadget_driver *driver,  		int (*bind)(struct usb_gadget *))  {  	struct pxa_udc *udc = the_controller; @@ -1860,8 +1866,6 @@ add_fail:  	udc->gadget.dev.driver = NULL;  	return retval;  } -EXPORT_SYMBOL(usb_gadget_probe_driver); -  /**   * stop_activity - Stops udc endpoints @@ -1888,12 +1892,12 @@ static void stop_activity(struct pxa_udc *udc, struct usb_gadget_driver *driver)  }  /** - * usb_gadget_unregister_driver - Unregister the gadget driver + * pxa27x_udc_stop - Unregister the gadget driver   * @driver: gadget driver   *   * Returns 0 if no error, -ENODEV, -EINVAL otherwise   */ -int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) +static int pxa27x_udc_stop(struct usb_gadget_driver *driver)  {  	struct pxa_udc *udc = the_controller; @@ -1917,7 +1921,6 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)  		return otg_set_peripheral(udc->transceiver, NULL);  	return 0;  } -EXPORT_SYMBOL(usb_gadget_unregister_driver);  /**   * handle_ep0_ctrl_req - handle control endpoint control request @@ -2516,9 +2519,14 @@ static int __init pxa_udc_probe(struct platform_device *pdev)  			driver_name, IRQ_USB, retval);  		goto err_irq;  	} +	retval = usb_add_gadget_udc(&pdev->dev, &udc->gadget); +	if (retval) +		goto err_add_udc;  	pxa_init_debugfs(udc);  	return 0; +err_add_udc: +	free_irq(udc->irq, udc);  err_irq:  	iounmap(udc->regs);  err_map: @@ -2537,6 +2545,7 @@ static int __exit pxa_udc_remove(struct platform_device *_dev)  	struct pxa_udc *udc = platform_get_drvdata(_dev);  	int gpio = udc->mach->gpio_pullup; +	usb_del_gadget_udc(&udc->gadget);  	usb_gadget_unregister_driver(udc->driver);  	free_irq(udc->irq, udc);  	pxa_cleanup_debugfs(udc); diff --git a/drivers/usb/gadget/pxa27x_udc.h b/drivers/usb/gadget/pxa27x_udc.h index cd16231d8c73..b01696eab068 100644 --- a/drivers/usb/gadget/pxa27x_udc.h +++ b/drivers/usb/gadget/pxa27x_udc.h @@ -88,9 +88,9 @@  #define UDCISR_INT_MASK	(UDCICR_FIFOERR | UDCICR_PKTCOMPL)  #define UDCOTGICR_IESF	(1 << 24)	/* OTG SET_FEATURE command recvd */ -#define UDCOTGICR_IEXR	(1 << 17)	/* Extra Transciever Interrupt +#define UDCOTGICR_IEXR	(1 << 17)	/* Extra Transceiver Interrupt  					   Rising Edge Interrupt Enable */ -#define UDCOTGICR_IEXF	(1 << 16)	/* Extra Transciever Interrupt +#define UDCOTGICR_IEXF	(1 << 16)	/* Extra Transceiver Interrupt  					   Falling Edge Interrupt Enable */  #define UDCOTGICR_IEVV40R (1 << 9)	/* OTG Vbus Valid 4.0V Rising Edge  					   Interrupt Enable */ diff --git a/drivers/usb/gadget/r8a66597-udc.c b/drivers/usb/gadget/r8a66597-udc.c index 6dcc1f68fa60..50991e5bd5e8 100644 --- a/drivers/usb/gadget/r8a66597-udc.c +++ b/drivers/usb/gadget/r8a66597-udc.c @@ -3,7 +3,7 @@   *   * Copyright (C) 2006-2009 Renesas Solutions Corp.   * - * Author : Yoshihiro Shimoda <shimoda.yoshihiro@renesas.com> + * Author : Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>   *   * 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 @@ -576,7 +576,11 @@ static void init_controller(struct r8a66597 *r8a66597)  	u16 endian = r8a66597->pdata->endian ? BIGEND : 0;  	if (r8a66597->pdata->on_chip) { -		r8a66597_bset(r8a66597, 0x04, SYSCFG1); +		if (r8a66597->pdata->buswait) +			r8a66597_write(r8a66597, r8a66597->pdata->buswait, +					SYSCFG1); +		else +			r8a66597_write(r8a66597, 0x0f, SYSCFG1);  		r8a66597_bset(r8a66597, HSE, SYSCFG0);  		r8a66597_bclr(r8a66597, USBE, SYSCFG0); @@ -618,6 +622,7 @@ static void disable_controller(struct r8a66597 *r8a66597)  {  	if (r8a66597->pdata->on_chip) {  		r8a66597_bset(r8a66597, SCKE, SYSCFG0); +		r8a66597_bclr(r8a66597, UTST, TESTMODE);  		/* disable interrupts */  		r8a66597_write(r8a66597, 0, INTENB0); @@ -635,6 +640,7 @@ static void disable_controller(struct r8a66597 *r8a66597)  		r8a66597_bclr(r8a66597, SCKE, SYSCFG0);  	} else { +		r8a66597_bclr(r8a66597, UTST, TESTMODE);  		r8a66597_bclr(r8a66597, SCKE, SYSCFG0);  		udelay(1);  		r8a66597_bclr(r8a66597, PLLC, SYSCFG0); @@ -999,10 +1005,29 @@ static void clear_feature(struct r8a66597 *r8a66597,  static void set_feature(struct r8a66597 *r8a66597, struct usb_ctrlrequest *ctrl)  { +	u16 tmp; +	int timeout = 3000;  	switch (ctrl->bRequestType & USB_RECIP_MASK) {  	case USB_RECIP_DEVICE: -		control_end(r8a66597, 1); +		switch (le16_to_cpu(ctrl->wValue)) { +		case USB_DEVICE_TEST_MODE: +			control_end(r8a66597, 1); +			/* Wait for the completion of status stage */ +			do { +				tmp = r8a66597_read(r8a66597, INTSTS0) & CTSQ; +				udelay(1); +			} while (tmp != CS_IDST || timeout-- > 0); + +			if (tmp == CS_IDST) +				r8a66597_bset(r8a66597, +					      le16_to_cpu(ctrl->wIndex >> 8), +					      TESTMODE); +			break; +		default: +			pipe_stall(r8a66597, 0); +			break; +		}  		break;  	case USB_RECIP_INTERFACE:  		control_end(r8a66597, 1); @@ -1410,7 +1435,7 @@ static struct usb_ep_ops r8a66597_ep_ops = {  /*-------------------------------------------------------------------------*/  static struct r8a66597 *the_controller; -int usb_gadget_probe_driver(struct usb_gadget_driver *driver, +static int r8a66597_start(struct usb_gadget_driver *driver,  		int (*bind)(struct usb_gadget *))  {  	struct r8a66597 *r8a66597 = the_controller; @@ -1444,6 +1469,7 @@ int usb_gadget_probe_driver(struct usb_gadget_driver *driver,  		goto error;  	} +	init_controller(r8a66597);  	r8a66597_bset(r8a66597, VBSE, INTENB0);  	if (r8a66597_read(r8a66597, INTSTS0) & VBSTS) {  		r8a66597_start_xclock(r8a66597); @@ -1462,9 +1488,8 @@ error:  	return retval;  } -EXPORT_SYMBOL(usb_gadget_probe_driver); -int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) +static int r8a66597_stop(struct usb_gadget_driver *driver)  {  	struct r8a66597 *r8a66597 = the_controller;  	unsigned long flags; @@ -1475,20 +1500,16 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)  	spin_lock_irqsave(&r8a66597->lock, flags);  	if (r8a66597->gadget.speed != USB_SPEED_UNKNOWN)  		r8a66597_usb_disconnect(r8a66597); -	spin_unlock_irqrestore(&r8a66597->lock, flags); -  	r8a66597_bclr(r8a66597, VBSE, INTENB0); +	disable_controller(r8a66597); +	spin_unlock_irqrestore(&r8a66597->lock, flags);  	driver->unbind(&r8a66597->gadget); -	init_controller(r8a66597); -	disable_controller(r8a66597); -  	device_del(&r8a66597->gadget.dev);  	r8a66597->driver = NULL;  	return 0;  } -EXPORT_SYMBOL(usb_gadget_unregister_driver);  /*-------------------------------------------------------------------------*/  static int r8a66597_get_frame(struct usb_gadget *_gadget) @@ -1497,14 +1518,33 @@ static int r8a66597_get_frame(struct usb_gadget *_gadget)  	return r8a66597_read(r8a66597, FRMNUM) & 0x03FF;  } +static int r8a66597_pullup(struct usb_gadget *gadget, int is_on) +{ +	struct r8a66597 *r8a66597 = gadget_to_r8a66597(gadget); +	unsigned long flags; + +	spin_lock_irqsave(&r8a66597->lock, flags); +	if (is_on) +		r8a66597_bset(r8a66597, DPRPU, SYSCFG0); +	else +		r8a66597_bclr(r8a66597, DPRPU, SYSCFG0); +	spin_unlock_irqrestore(&r8a66597->lock, flags); + +	return 0; +} +  static struct usb_gadget_ops r8a66597_gadget_ops = {  	.get_frame		= r8a66597_get_frame, +	.start			= r8a66597_start, +	.stop			= r8a66597_stop, +	.pullup			= r8a66597_pullup,  };  static int __exit r8a66597_remove(struct platform_device *pdev)  {  	struct r8a66597		*r8a66597 = dev_get_drvdata(&pdev->dev); +	usb_del_gadget_udc(&r8a66597->gadget);  	del_timer_sync(&r8a66597->timer);  	iounmap(r8a66597->reg);  	free_irq(platform_get_irq(pdev, 0), r8a66597); @@ -1645,11 +1685,15 @@ static int __init r8a66597_probe(struct platform_device *pdev)  		goto clean_up3;  	r8a66597->ep0_req->complete = nop_completion; -	init_controller(r8a66597); +	ret = usb_add_gadget_udc(&pdev->dev, &r8a66597->gadget); +	if (ret) +		goto err_add_udc;  	dev_info(&pdev->dev, "version %s\n", DRIVER_VERSION);  	return 0; +err_add_udc: +	r8a66597_free_request(&r8a66597->ep[0].ep, r8a66597->ep0_req);  clean_up3:  	free_irq(irq, r8a66597);  clean_up2: @@ -1679,6 +1723,7 @@ static struct platform_driver r8a66597_driver = {  		.name =	(char *) udc_name,  	},  }; +MODULE_ALIAS("platform:r8a66597_udc");  static int __init r8a66597_udc_init(void)  { diff --git a/drivers/usb/gadget/r8a66597-udc.h b/drivers/usb/gadget/r8a66597-udc.h index 5fc22e09a0f1..503f766c23a7 100644 --- a/drivers/usb/gadget/r8a66597-udc.h +++ b/drivers/usb/gadget/r8a66597-udc.h @@ -3,7 +3,7 @@   *   * Copyright (C) 2007-2009 Renesas Solutions Corp.   * - * Author : Yoshihiro Shimoda <shimoda.yoshihiro@renesas.com> + * Author : Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>   *   * 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 diff --git a/drivers/usb/gadget/s3c-hsotg.c b/drivers/usb/gadget/s3c-hsotg.c index acb9cc418df9..8bdee67ce09a 100644 --- a/drivers/usb/gadget/s3c-hsotg.c +++ b/drivers/usb/gadget/s3c-hsotg.c @@ -2574,7 +2574,7 @@ static int s3c_hsotg_corereset(struct s3c_hsotg *hsotg)  	return 0;  } -int usb_gadget_probe_driver(struct usb_gadget_driver *driver, +static int s3c_hsotg_start(struct usb_gadget_driver *driver,  		int (*bind)(struct usb_gadget *))  {  	struct s3c_hsotg *hsotg = our_hsotg; @@ -2680,9 +2680,9 @@ int usb_gadget_probe_driver(struct usb_gadget_driver *driver,  	writel(0, hsotg->regs + S3C_DAINTMSK); -	dev_info(hsotg->dev, "EP0: DIEPCTL0=0x%08x, DOEPCTL0=0x%08x\n", -		 readl(hsotg->regs + S3C_DIEPCTL0), -		 readl(hsotg->regs + S3C_DOEPCTL0)); +	dev_dbg(hsotg->dev, "EP0: DIEPCTL0=0x%08x, DOEPCTL0=0x%08x\n", +		readl(hsotg->regs + S3C_DIEPCTL0), +		readl(hsotg->regs + S3C_DOEPCTL0));  	/* enable in and out endpoint interrupts */  	s3c_hsotg_en_gsint(hsotg, S3C_GINTSTS_OEPInt | S3C_GINTSTS_IEPInt); @@ -2701,7 +2701,7 @@ int usb_gadget_probe_driver(struct usb_gadget_driver *driver,  	udelay(10);  /* see openiboot */  	__bic32(hsotg->regs + S3C_DCTL, S3C_DCTL_PWROnPrgDone); -	dev_info(hsotg->dev, "DCTL=0x%08x\n", readl(hsotg->regs + S3C_DCTL)); +	dev_dbg(hsotg->dev, "DCTL=0x%08x\n", readl(hsotg->regs + S3C_DCTL));  	/* S3C_DxEPCTL_USBActEp says RO in manual, but seems to be set by  	   writing to the EPCTL register.. */ @@ -2721,9 +2721,9 @@ int usb_gadget_probe_driver(struct usb_gadget_driver *driver,  	s3c_hsotg_enqueue_setup(hsotg); -	dev_info(hsotg->dev, "EP0: DIEPCTL0=0x%08x, DOEPCTL0=0x%08x\n", -		 readl(hsotg->regs + S3C_DIEPCTL0), -		 readl(hsotg->regs + S3C_DOEPCTL0)); +	dev_dbg(hsotg->dev, "EP0: DIEPCTL0=0x%08x, DOEPCTL0=0x%08x\n", +		readl(hsotg->regs + S3C_DIEPCTL0), +		readl(hsotg->regs + S3C_DOEPCTL0));  	/* clear global NAKs */  	writel(S3C_DCTL_CGOUTNak | S3C_DCTL_CGNPInNAK, @@ -2745,9 +2745,8 @@ err:  	hsotg->gadget.dev.driver = NULL;  	return ret;  } -EXPORT_SYMBOL(usb_gadget_probe_driver); -int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) +static int s3c_hsotg_stop(struct usb_gadget_driver *driver)  {  	struct s3c_hsotg *hsotg = our_hsotg;  	int ep; @@ -2775,7 +2774,6 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)  	return 0;  } -EXPORT_SYMBOL(usb_gadget_unregister_driver);  static int s3c_hsotg_gadget_getframe(struct usb_gadget *gadget)  { @@ -2784,6 +2782,8 @@ static int s3c_hsotg_gadget_getframe(struct usb_gadget *gadget)  static struct usb_gadget_ops s3c_hsotg_gadget_ops = {  	.get_frame	= s3c_hsotg_gadget_getframe, +	.start		= s3c_hsotg_start, +	.stop		= s3c_hsotg_stop,  };  /** @@ -2921,9 +2921,9 @@ static void s3c_hsotg_init(struct s3c_hsotg *hsotg)  	/* setup fifos */ -	dev_info(hsotg->dev, "GRXFSIZ=0x%08x, GNPTXFSIZ=0x%08x\n", -		 readl(hsotg->regs + S3C_GRXFSIZ), -		 readl(hsotg->regs + S3C_GNPTXFSIZ)); +	dev_dbg(hsotg->dev, "GRXFSIZ=0x%08x, GNPTXFSIZ=0x%08x\n", +		readl(hsotg->regs + S3C_GRXFSIZ), +		readl(hsotg->regs + S3C_GNPTXFSIZ));  	s3c_hsotg_init_fifo(hsotg); @@ -2945,6 +2945,7 @@ static void s3c_hsotg_init(struct s3c_hsotg *hsotg)  static void s3c_hsotg_dump(struct s3c_hsotg *hsotg)  { +#ifdef DEBUG  	struct device *dev = hsotg->dev;  	void __iomem *regs = hsotg->regs;  	u32 val; @@ -2987,6 +2988,7 @@ static void s3c_hsotg_dump(struct s3c_hsotg *hsotg)  	dev_info(dev, "DVBUSDIS=0x%08x, DVBUSPULSE=%08x\n",  		 readl(regs + S3C_DVBUSDIS), readl(regs + S3C_DVBUSPULSE)); +#endif  } @@ -3401,6 +3403,10 @@ static int __devinit s3c_hsotg_probe(struct platform_device *pdev)  	for (epnum = 0; epnum < S3C_HSOTG_EPS; epnum++)  		s3c_hsotg_initep(hsotg, &hsotg->eps[epnum], epnum); +	ret = usb_add_gadget_udc(&pdev->dev, &hsotg->gadget); +	if (ret) +		goto err_add_udc; +  	s3c_hsotg_create_debug(hsotg);  	s3c_hsotg_dump(hsotg); @@ -3408,6 +3414,11 @@ static int __devinit s3c_hsotg_probe(struct platform_device *pdev)  	our_hsotg = hsotg;  	return 0; +err_add_udc: +	s3c_hsotg_gate(pdev, false); +	clk_disable(hsotg->clk); +	clk_put(hsotg->clk); +  err_regs:  	iounmap(hsotg->regs); @@ -3425,6 +3436,8 @@ static int __devexit 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);  	usb_gadget_unregister_driver(hsotg->driver); diff --git a/drivers/usb/gadget/s3c-hsudc.c b/drivers/usb/gadget/s3c-hsudc.c index cfe3cf56d6bd..3fa717c5f4bc 100644 --- a/drivers/usb/gadget/s3c-hsudc.c +++ b/drivers/usb/gadget/s3c-hsudc.c @@ -26,6 +26,7 @@  #include <linux/clk.h>  #include <linux/usb/ch9.h>  #include <linux/usb/gadget.h> +#include <linux/prefetch.h>  #include <mach/regs-s3c2443-clock.h>  #include <plat/udc.h> @@ -1132,7 +1133,7 @@ static irqreturn_t s3c_hsudc_irq(int irq, void *_dev)  	return IRQ_HANDLED;  } -int usb_gadget_probe_driver(struct usb_gadget_driver *driver, +static int s3c_hsudc_start(struct usb_gadget_driver *driver,  		int (*bind)(struct usb_gadget *))  {  	struct s3c_hsudc *hsudc = the_controller; @@ -1180,9 +1181,8 @@ int usb_gadget_probe_driver(struct usb_gadget_driver *driver,  	return 0;  } -EXPORT_SYMBOL(usb_gadget_probe_driver); -int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) +static int s3c_hsudc_stop(struct usb_gadget_driver *driver)  {  	struct s3c_hsudc *hsudc = the_controller;  	unsigned long flags; @@ -1209,7 +1209,6 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)  			driver->driver.name);  	return 0;  } -EXPORT_SYMBOL(usb_gadget_unregister_driver);  static inline u32 s3c_hsudc_read_frameno(struct s3c_hsudc *hsudc)  { @@ -1223,6 +1222,8 @@ static int s3c_hsudc_gadget_getframe(struct usb_gadget *gadget)  static struct usb_gadget_ops s3c_hsudc_gadget_ops = {  	.get_frame	= s3c_hsudc_gadget_getframe, +	.start		= s3c_hsudc_start, +	.stop		= s3c_hsudc_stop,  };  static int s3c_hsudc_probe(struct platform_device *pdev) @@ -1301,7 +1302,8 @@ static int s3c_hsudc_probe(struct platform_device *pdev)  	hsudc->uclk = clk_get(&pdev->dev, "usb-device");  	if (IS_ERR(hsudc->uclk)) {  		dev_err(dev, "failed to find usb-device clock source\n"); -		return PTR_ERR(hsudc->uclk); +		ret = PTR_ERR(hsudc->uclk); +		goto err_clk;  	}  	clk_enable(hsudc->uclk); @@ -1309,8 +1311,17 @@ static int s3c_hsudc_probe(struct platform_device *pdev)  	disable_irq(hsudc->irq);  	local_irq_enable(); -	return 0; +	ret = usb_add_gadget_udc(&pdev->dev, &hsudc->gadget); +	if (ret) +		goto err_add_udc; + +	return 0; +err_add_udc: +	clk_disable(hsudc->uclk); +	clk_put(hsudc->uclk); +err_clk: +	free_irq(hsudc->irq, hsudc);  err_irq:  	iounmap(hsudc->regs); @@ -1330,6 +1341,7 @@ static struct platform_driver s3c_hsudc_driver = {  	},  	.probe		= s3c_hsudc_probe,  }; +MODULE_ALIAS("platform:s3c-hsudc");  static int __init s3c_hsudc_modinit(void)  { diff --git a/drivers/usb/gadget/s3c2410_udc.c b/drivers/usb/gadget/s3c2410_udc.c index 6d8b04061d5d..85c1b0d66293 100644 --- a/drivers/usb/gadget/s3c2410_udc.c +++ b/drivers/usb/gadget/s3c2410_udc.c @@ -36,6 +36,7 @@  #include <linux/platform_device.h>  #include <linux/clk.h>  #include <linux/gpio.h> +#include <linux/prefetch.h>  #include <linux/debugfs.h>  #include <linux/seq_file.h> @@ -1551,6 +1552,10 @@ static int s3c2410_vbus_draw(struct usb_gadget *_gadget, unsigned ma)  	return -ENOTSUPP;  } +static int s3c2410_udc_start(struct usb_gadget_driver *driver, +		int (*bind)(struct usb_gadget *)); +static int s3c2410_udc_stop(struct usb_gadget_driver *driver); +  static const struct usb_gadget_ops s3c2410_ops = {  	.get_frame		= s3c2410_udc_get_frame,  	.wakeup			= s3c2410_udc_wakeup, @@ -1558,6 +1563,8 @@ static const struct usb_gadget_ops s3c2410_ops = {  	.pullup			= s3c2410_udc_pullup,  	.vbus_session		= s3c2410_udc_vbus_session,  	.vbus_draw		= s3c2410_vbus_draw, +	.start			= s3c2410_udc_start, +	.stop			= s3c2410_udc_stop,  };  static void s3c2410_udc_command(enum s3c2410_udc_cmd_e cmd) @@ -1566,7 +1573,7 @@ static void s3c2410_udc_command(enum s3c2410_udc_cmd_e cmd)  		return;  	if (udc_info->udc_command) { -		udc_info->udc_command(S3C2410_UDC_P_DISABLE); +		udc_info->udc_command(cmd);  	} else if (gpio_is_valid(udc_info->pullup_pin)) {  		int value; @@ -1671,10 +1678,7 @@ static void s3c2410_udc_enable(struct s3c2410_udc *dev)  	s3c2410_udc_command(S3C2410_UDC_P_ENABLE);  } -/* - *	usb_gadget_probe_driver - */ -int usb_gadget_probe_driver(struct usb_gadget_driver *driver, +static int s3c2410_udc_start(struct usb_gadget_driver *driver,  		int (*bind)(struct usb_gadget *))  {  	struct s3c2410_udc *udc = the_controller; @@ -1729,12 +1733,8 @@ register_error:  	udc->gadget.dev.driver = NULL;  	return retval;  } -EXPORT_SYMBOL(usb_gadget_probe_driver); -/* - *	usb_gadget_unregister_driver - */ -int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) +static int s3c2410_udc_stop(struct usb_gadget_driver *driver)  {  	struct s3c2410_udc *udc = the_controller; @@ -1954,6 +1954,10 @@ static int s3c2410_udc_probe(struct platform_device *pdev)  			goto err_vbus_irq;  	} +	retval = usb_add_gadget_udc(&pdev->dev, &udc->gadget); +	if (retval) +		goto err_add_udc; +  	if (s3c2410_udc_debugfs_root) {  		udc->regs_info = debugfs_create_file("registers", S_IRUGO,  				s3c2410_udc_debugfs_root, @@ -1966,6 +1970,10 @@ static int s3c2410_udc_probe(struct platform_device *pdev)  	return 0; +err_add_udc: +	if (udc_info && !udc_info->udc_command && +			gpio_is_valid(udc_info->pullup_pin)) +		gpio_free(udc_info->pullup_pin);  err_vbus_irq:  	if (udc_info && udc_info->vbus_pin > 0)  		free_irq(gpio_to_irq(udc_info->vbus_pin), udc); @@ -1991,6 +1999,8 @@ static int s3c2410_udc_remove(struct platform_device *pdev)  	unsigned int irq;  	dev_dbg(&pdev->dev, "%s()\n", __func__); + +	usb_del_gadget_udc(&udc->gadget);  	if (udc->driver)  		return -EBUSY; @@ -2047,26 +2057,22 @@ static int s3c2410_udc_resume(struct platform_device *pdev)  #define s3c2410_udc_resume	NULL  #endif -static struct platform_driver udc_driver_2410 = { -	.driver		= { -		.name	= "s3c2410-usbgadget", -		.owner	= THIS_MODULE, -	}, -	.probe		= s3c2410_udc_probe, -	.remove		= s3c2410_udc_remove, -	.suspend	= s3c2410_udc_suspend, -	.resume		= s3c2410_udc_resume, +static const struct platform_device_id s3c_udc_ids[] = { +	{ "s3c2410-usbgadget", }, +	{ "s3c2440-usbgadget", },  }; +MODULE_DEVICE_TABLE(platform, s3c_udc_ids); -static struct platform_driver udc_driver_2440 = { +static struct platform_driver udc_driver_24x0 = {  	.driver		= { -		.name	= "s3c2440-usbgadget", +		.name	= "s3c24x0-usbgadget",  		.owner	= THIS_MODULE,  	},  	.probe		= s3c2410_udc_probe,  	.remove		= s3c2410_udc_remove,  	.suspend	= s3c2410_udc_suspend,  	.resume		= s3c2410_udc_resume, +	.id_table	= s3c_udc_ids,  };  static int __init udc_init(void) @@ -2082,11 +2088,7 @@ static int __init udc_init(void)  		s3c2410_udc_debugfs_root = NULL;  	} -	retval = platform_driver_register(&udc_driver_2410); -	if (retval) -		goto err; - -	retval = platform_driver_register(&udc_driver_2440); +	retval = platform_driver_register(&udc_driver_24x0);  	if (retval)  		goto err; @@ -2099,13 +2101,10 @@ err:  static void __exit udc_exit(void)  { -	platform_driver_unregister(&udc_driver_2410); -	platform_driver_unregister(&udc_driver_2440); +	platform_driver_unregister(&udc_driver_24x0);  	debugfs_remove(s3c2410_udc_debugfs_root);  } -EXPORT_SYMBOL(usb_gadget_unregister_driver); -  module_init(udc_init);  module_exit(udc_exit); @@ -2113,5 +2112,3 @@ MODULE_AUTHOR(DRIVER_AUTHOR);  MODULE_DESCRIPTION(DRIVER_DESC);  MODULE_VERSION(DRIVER_VERSION);  MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:s3c2410-usbgadget"); -MODULE_ALIAS("platform:s3c2440-usbgadget"); diff --git a/drivers/usb/gadget/serial.c b/drivers/usb/gadget/serial.c index 1ac57a973aa9..ed1b816e58d8 100644 --- a/drivers/usb/gadget/serial.c +++ b/drivers/usb/gadget/serial.c @@ -242,6 +242,7 @@ static struct usb_composite_driver gserial_driver = {  	.name		= "g_serial",  	.dev		= &device_desc,  	.strings	= dev_strings, +	.max_speed	= USB_SPEED_HIGH,  };  static int __init init(void) diff --git a/drivers/usb/gadget/storage_common.c b/drivers/usb/gadget/storage_common.c index 1fa4f705b0b4..d3dd227a2bfc 100644 --- a/drivers/usb/gadget/storage_common.c +++ b/drivers/usb/gadget/storage_common.c @@ -494,7 +494,7 @@ static struct usb_descriptor_header *fsg_hs_function[] = {  };  /* Maxpacket and other transfer characteristics vary by speed. */ -static struct usb_endpoint_descriptor * +static __maybe_unused struct usb_endpoint_descriptor *  fsg_ep_desc(struct usb_gadget *g, struct usb_endpoint_descriptor *fs,  		struct usb_endpoint_descriptor *hs)  { diff --git a/drivers/usb/gadget/u_ether.c b/drivers/usb/gadget/u_ether.c index 2ac1d2147325..dfed4c1d96c0 100644 --- a/drivers/usb/gadget/u_ether.c +++ b/drivers/usb/gadget/u_ether.c @@ -97,16 +97,17 @@ struct eth_dev {  static unsigned qmult = 5;  module_param(qmult, uint, S_IRUGO|S_IWUSR); -MODULE_PARM_DESC(qmult, "queue length multiplier at high speed"); +MODULE_PARM_DESC(qmult, "queue length multiplier at high/super speed");  #else	/* full speed (low speed doesn't do bulk) */  #define qmult		1  #endif -/* for dual-speed hardware, use deeper queues at highspeed */ +/* for dual-speed hardware, use deeper queues at high/super speed */  static inline int qlen(struct usb_gadget *gadget)  { -	if (gadget_is_dualspeed(gadget) && gadget->speed == USB_SPEED_HIGH) +	if (gadget_is_dualspeed(gadget) && (gadget->speed == USB_SPEED_HIGH || +					    gadget->speed == USB_SPEED_SUPER))  		return qmult * DEFAULT_QLEN;  	else  		return DEFAULT_QLEN; @@ -598,9 +599,10 @@ static netdev_tx_t eth_start_xmit(struct sk_buff *skb,  	req->length = length; -	/* throttle highspeed IRQ rate back slightly */ +	/* throttle high/super speed IRQ rate back slightly */  	if (gadget_is_dualspeed(dev->gadget)) -		req->no_interrupt = (dev->gadget->speed == USB_SPEED_HIGH) +		req->no_interrupt = (dev->gadget->speed == USB_SPEED_HIGH || +				     dev->gadget->speed == USB_SPEED_SUPER)  			? ((atomic_read(&dev->tx_qlen) % qmult) != 0)  			: 0; @@ -693,8 +695,8 @@ static int eth_stop(struct net_device *net)  		usb_ep_disable(link->out_ep);  		if (netif_carrier_ok(net)) {  			DBG(dev, "host still using in/out endpoints\n"); -			usb_ep_enable(link->in_ep, link->in); -			usb_ep_enable(link->out_ep, link->out); +			usb_ep_enable(link->in_ep); +			usb_ep_enable(link->out_ep);  		}  	}  	spin_unlock_irqrestore(&dev->lock, flags); @@ -871,7 +873,7 @@ struct net_device *gether_connect(struct gether *link)  		return ERR_PTR(-EINVAL);  	link->in_ep->driver_data = dev; -	result = usb_ep_enable(link->in_ep, link->in); +	result = usb_ep_enable(link->in_ep);  	if (result != 0) {  		DBG(dev, "enable %s --> %d\n",  			link->in_ep->name, result); @@ -879,7 +881,7 @@ struct net_device *gether_connect(struct gether *link)  	}  	link->out_ep->driver_data = dev; -	result = usb_ep_enable(link->out_ep, link->out); +	result = usb_ep_enable(link->out_ep);  	if (result != 0) {  		DBG(dev, "enable %s --> %d\n",  			link->out_ep->name, result); @@ -969,7 +971,7 @@ void gether_disconnect(struct gether *link)  	}  	spin_unlock(&dev->req_lock);  	link->in_ep->driver_data = NULL; -	link->in = NULL; +	link->in_ep->desc = NULL;  	usb_ep_disable(link->out_ep);  	spin_lock(&dev->req_lock); @@ -984,7 +986,7 @@ void gether_disconnect(struct gether *link)  	}  	spin_unlock(&dev->req_lock);  	link->out_ep->driver_data = NULL; -	link->out = NULL; +	link->out_ep->desc = NULL;  	/* finish forgetting about this USB link episode */  	dev->header_len = 0; diff --git a/drivers/usb/gadget/u_ether.h b/drivers/usb/gadget/u_ether.h index b56e1e7d423c..c966440ddd70 100644 --- a/drivers/usb/gadget/u_ether.h +++ b/drivers/usb/gadget/u_ether.h @@ -52,10 +52,6 @@ struct gether {  	struct usb_ep			*in_ep;  	struct usb_ep			*out_ep; -	/* descriptors match device speed at gether_connect() time */ -	struct usb_endpoint_descriptor	*in; -	struct usb_endpoint_descriptor	*out; -  	bool				is_zlp_ok;  	u16				cdc_filter; diff --git a/drivers/usb/gadget/u_serial.c b/drivers/usb/gadget/u_serial.c index 40f7716b31fc..a8aa46962d81 100644 --- a/drivers/usb/gadget/u_serial.c +++ b/drivers/usb/gadget/u_serial.c @@ -1247,12 +1247,12 @@ int gserial_connect(struct gserial *gser, u8 port_num)  	port = ports[port_num].port;  	/* activate the endpoints */ -	status = usb_ep_enable(gser->in, gser->in_desc); +	status = usb_ep_enable(gser->in);  	if (status < 0)  		return status;  	gser->in->driver_data = port; -	status = usb_ep_enable(gser->out, gser->out_desc); +	status = usb_ep_enable(gser->out);  	if (status < 0)  		goto fail_out;  	gser->out->driver_data = port; diff --git a/drivers/usb/gadget/u_serial.h b/drivers/usb/gadget/u_serial.h index 300f0ed9475d..9b0fe6450fbf 100644 --- a/drivers/usb/gadget/u_serial.h +++ b/drivers/usb/gadget/u_serial.h @@ -35,8 +35,6 @@ struct gserial {  	struct usb_ep			*in;  	struct usb_ep			*out; -	struct usb_endpoint_descriptor	*in_desc; -	struct usb_endpoint_descriptor	*out_desc;  	/* REVISIT avoid this CDC-ACM support harder ... */  	struct usb_cdc_line_coding port_line_coding;	/* 9600-8-N-1 etc */ diff --git a/drivers/usb/gadget/udc-core.c b/drivers/usb/gadget/udc-core.c new file mode 100644 index 000000000000..05ba47214361 --- /dev/null +++ b/drivers/usb/gadget/udc-core.c @@ -0,0 +1,484 @@ +/** + * udc.c - Core UDC Framework + * + * Copyright (C) 2010 Texas Instruments + * Author: Felipe Balbi <balbi@ti.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  of + * the License as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program.  If not, see <http://www.gnu.org/licenses/>. + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/device.h> +#include <linux/list.h> +#include <linux/err.h> + +#include <linux/usb/ch9.h> +#include <linux/usb/gadget.h> + +/** + * struct usb_udc - describes one usb device controller + * @driver - the gadget driver pointer. For use by the class code + * @dev - the child device to the actual controller + * @gadget - the gadget. For use by the class code + * @list - for use by the udc class driver + * + * This represents the internal data structure which is used by the UDC-class + * to hold information about udc driver and gadget together. + */ +struct usb_udc { +	struct usb_gadget_driver	*driver; +	struct usb_gadget		*gadget; +	struct device			dev; +	struct list_head		list; +}; + +static struct class *udc_class; +static LIST_HEAD(udc_list); +static DEFINE_MUTEX(udc_lock); + +/* ------------------------------------------------------------------------- */ + +/** + * usb_gadget_start - tells usb device controller to start up + * @gadget: The gadget we want to get started + * @driver: The driver we want to bind to @gadget + * @bind: The bind function for @driver + * + * This call is issued by the UDC Class driver when it's about + * to register a gadget driver to the device controller, before + * calling gadget driver's bind() method. + * + * It allows the controller to be powered off until strictly + * necessary to have it powered on. + * + * Returns zero on success, else negative errno. + */ +static inline int usb_gadget_start(struct usb_gadget *gadget, +		struct usb_gadget_driver *driver, +		int (*bind)(struct usb_gadget *)) +{ +	return gadget->ops->start(driver, bind); +} + +/** + * usb_gadget_udc_start - tells usb device controller to start up + * @gadget: The gadget we want to get started + * @driver: The driver we want to bind to @gadget + * + * This call is issued by the UDC Class driver when it's about + * to register a gadget driver to the device controller, before + * calling gadget driver's bind() method. + * + * It allows the controller to be powered off until strictly + * necessary to have it powered on. + * + * Returns zero on success, else negative errno. + */ +static inline int usb_gadget_udc_start(struct usb_gadget *gadget, +		struct usb_gadget_driver *driver) +{ +	return gadget->ops->udc_start(gadget, driver); +} + +/** + * usb_gadget_stop - tells usb device controller we don't need it anymore + * @gadget: The device we want to stop activity + * @driver: The driver to unbind from @gadget + * + * This call is issued by the UDC Class driver after calling + * gadget driver's unbind() method. + * + * The details are implementation specific, but it can go as + * far as powering off UDC completely and disable its data + * line pullups. + */ +static inline void usb_gadget_stop(struct usb_gadget *gadget, +		struct usb_gadget_driver *driver) +{ +	gadget->ops->stop(driver); +} + +/** + * usb_gadget_udc_stop - tells usb device controller we don't need it anymore + * @gadget: The device we want to stop activity + * @driver: The driver to unbind from @gadget + * + * This call is issued by the UDC Class driver after calling + * gadget driver's unbind() method. + * + * The details are implementation specific, but it can go as + * far as powering off UDC completely and disable its data + * line pullups. + */ +static inline void usb_gadget_udc_stop(struct usb_gadget *gadget, +		struct usb_gadget_driver *driver) +{ +	gadget->ops->udc_stop(gadget, driver); +} + +/** + * usb_udc_release - release the usb_udc struct + * @dev: the dev member within usb_udc + * + * This is called by driver's core in order to free memory once the last + * reference is released. + */ +static void usb_udc_release(struct device *dev) +{ +	struct usb_udc *udc; + +	udc = container_of(dev, struct usb_udc, dev); +	dev_dbg(dev, "releasing '%s'\n", dev_name(dev)); +	kfree(udc); +} + +static const struct attribute_group *usb_udc_attr_groups[]; +/** + * usb_add_gadget_udc - adds a new gadget to the udc class driver list + * @parent: the parent device to this udc. Usually the controller + * driver's device. + * @gadget: the gadget to be added to the list + * + * Returns zero on success, negative errno otherwise. + */ +int usb_add_gadget_udc(struct device *parent, struct usb_gadget *gadget) +{ +	struct usb_udc		*udc; +	int			ret = -ENOMEM; + +	udc = kzalloc(sizeof(*udc), GFP_KERNEL); +	if (!udc) +		goto err1; + +	device_initialize(&udc->dev); +	udc->dev.release = usb_udc_release; +	udc->dev.class = udc_class; +	udc->dev.groups = usb_udc_attr_groups; +	udc->dev.parent = parent; +	ret = dev_set_name(&udc->dev, "%s", kobject_name(&parent->kobj)); +	if (ret) +		goto err2; + +	udc->gadget = gadget; + +	mutex_lock(&udc_lock); +	list_add_tail(&udc->list, &udc_list); + +	ret = device_add(&udc->dev); +	if (ret) +		goto err3; + +	mutex_unlock(&udc_lock); + +	return 0; +err3: +	list_del(&udc->list); +	mutex_unlock(&udc_lock); + +err2: +	put_device(&udc->dev); + +err1: +	return ret; +} +EXPORT_SYMBOL_GPL(usb_add_gadget_udc); + +static int udc_is_newstyle(struct usb_udc *udc) +{ +	if (udc->gadget->ops->udc_start && udc->gadget->ops->udc_stop) +		return 1; +	return 0; +} + + +static void usb_gadget_remove_driver(struct usb_udc *udc) +{ +	dev_dbg(&udc->dev, "unregistering UDC driver [%s]\n", +			udc->gadget->name); + +	kobject_uevent(&udc->dev.kobj, KOBJ_CHANGE); + +	if (udc_is_newstyle(udc)) { +		usb_gadget_disconnect(udc->gadget); +		udc->driver->unbind(udc->gadget); +		usb_gadget_udc_stop(udc->gadget, udc->driver); + +	} else { +		usb_gadget_stop(udc->gadget, udc->driver); +	} + +	udc->driver = NULL; +	udc->dev.driver = NULL; +} + +/** + * usb_del_gadget_udc - deletes @udc from udc_list + * @gadget: the gadget to be removed. + * + * This, will call usb_gadget_unregister_driver() if + * the @udc is still busy. + */ +void usb_del_gadget_udc(struct usb_gadget *gadget) +{ +	struct usb_udc		*udc = NULL; + +	mutex_lock(&udc_lock); +	list_for_each_entry(udc, &udc_list, list) +		if (udc->gadget == gadget) +			goto found; + +	dev_err(gadget->dev.parent, "gadget not registered.\n"); +	mutex_unlock(&udc_lock); + +	return; + +found: +	dev_vdbg(gadget->dev.parent, "unregistering gadget\n"); + +	list_del(&udc->list); +	mutex_unlock(&udc_lock); + +	if (udc->driver) +		usb_gadget_remove_driver(udc); + +	kobject_uevent(&udc->dev.kobj, KOBJ_REMOVE); +	device_unregister(&udc->dev); +} +EXPORT_SYMBOL_GPL(usb_del_gadget_udc); + +/* ------------------------------------------------------------------------- */ + +int usb_gadget_probe_driver(struct usb_gadget_driver *driver, +		int (*bind)(struct usb_gadget *)) +{ +	struct usb_udc		*udc = NULL; +	int			ret; + +	if (!driver || !bind || !driver->setup) +		return -EINVAL; + +	mutex_lock(&udc_lock); +	list_for_each_entry(udc, &udc_list, list) { +		/* For now we take the first one */ +		if (!udc->driver) +			goto found; +	} + +	pr_debug("couldn't find an available UDC\n"); +	mutex_unlock(&udc_lock); +	return -ENODEV; + +found: +	dev_dbg(&udc->dev, "registering UDC driver [%s]\n", +			driver->function); + +	udc->driver = driver; +	udc->dev.driver = &driver->driver; + +	if (udc_is_newstyle(udc)) { +		ret = bind(udc->gadget); +		if (ret) +			goto err1; +		ret = usb_gadget_udc_start(udc->gadget, driver); +		if (ret) { +			driver->unbind(udc->gadget); +			goto err1; +		} +		usb_gadget_connect(udc->gadget); +	} else { + +		ret = usb_gadget_start(udc->gadget, driver, bind); +		if (ret) +			goto err1; + +	} + +	kobject_uevent(&udc->dev.kobj, KOBJ_CHANGE); +	mutex_unlock(&udc_lock); +	return 0; + +err1: +	dev_err(&udc->dev, "failed to start %s: %d\n", +			udc->driver->function, ret); +	udc->driver = NULL; +	udc->dev.driver = NULL; +	mutex_unlock(&udc_lock); +	return ret; +} +EXPORT_SYMBOL_GPL(usb_gadget_probe_driver); + +int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) +{ +	struct usb_udc		*udc = NULL; +	int			ret = -ENODEV; + +	if (!driver || !driver->unbind) +		return -EINVAL; + +	mutex_lock(&udc_lock); +	list_for_each_entry(udc, &udc_list, list) +		if (udc->driver == driver) { +			usb_gadget_remove_driver(udc); +			ret = 0; +			break; +		} + +	mutex_unlock(&udc_lock); +	return ret; +} +EXPORT_SYMBOL_GPL(usb_gadget_unregister_driver); + +/* ------------------------------------------------------------------------- */ + +static ssize_t usb_udc_srp_store(struct device *dev, +		struct device_attribute *attr, const char *buf, size_t n) +{ +	struct usb_udc		*udc = dev_get_drvdata(dev); + +	if (sysfs_streq(buf, "1")) +		usb_gadget_wakeup(udc->gadget); + +	return n; +} +static DEVICE_ATTR(srp, S_IWUSR, NULL, usb_udc_srp_store); + +static ssize_t usb_udc_softconn_store(struct device *dev, +		struct device_attribute *attr, const char *buf, size_t n) +{ +	struct usb_udc		*udc = dev_get_drvdata(dev); + +	if (sysfs_streq(buf, "connect")) { +		usb_gadget_connect(udc->gadget); +	} else if (sysfs_streq(buf, "disconnect")) { +		usb_gadget_disconnect(udc->gadget); +	} else { +		dev_err(dev, "unsupported command '%s'\n", buf); +		return -EINVAL; +	} + +	return n; +} +static DEVICE_ATTR(soft_connect, S_IWUSR, NULL, usb_udc_softconn_store); + +static ssize_t usb_udc_speed_show(struct device *dev, +		struct device_attribute *attr, char *buf) +{ +	struct usb_udc		*udc = container_of(dev, struct usb_udc, dev); +	struct usb_gadget	*gadget = udc->gadget; + +	switch (gadget->speed) { +	case USB_SPEED_LOW: +		return snprintf(buf, PAGE_SIZE, "low-speed\n"); +	case USB_SPEED_FULL: +		return snprintf(buf, PAGE_SIZE, "full-speed\n"); +	case USB_SPEED_HIGH: +		return snprintf(buf, PAGE_SIZE, "high-speed\n"); +	case USB_SPEED_WIRELESS: +		return snprintf(buf, PAGE_SIZE, "wireless\n"); +	case USB_SPEED_SUPER: +		return snprintf(buf, PAGE_SIZE, "super-speed\n"); +	case USB_SPEED_UNKNOWN:	/* FALLTHROUGH */ +	default: +		return snprintf(buf, PAGE_SIZE, "UNKNOWN\n"); +	} +} +static DEVICE_ATTR(speed, S_IRUSR, usb_udc_speed_show, NULL); + +#define USB_UDC_ATTR(name)					\ +ssize_t usb_udc_##name##_show(struct device *dev,		\ +		struct device_attribute *attr, char *buf)	\ +{								\ +	struct usb_udc		*udc = container_of(dev, struct usb_udc, dev); \ +	struct usb_gadget	*gadget = udc->gadget;		\ +								\ +	return snprintf(buf, PAGE_SIZE, "%d\n", gadget->name);	\ +}								\ +static DEVICE_ATTR(name, S_IRUSR, usb_udc_##name##_show, NULL) + +static USB_UDC_ATTR(is_dualspeed); +static USB_UDC_ATTR(is_otg); +static USB_UDC_ATTR(is_a_peripheral); +static USB_UDC_ATTR(b_hnp_enable); +static USB_UDC_ATTR(a_hnp_support); +static USB_UDC_ATTR(a_alt_hnp_support); + +static struct attribute *usb_udc_attrs[] = { +	&dev_attr_srp.attr, +	&dev_attr_soft_connect.attr, +	&dev_attr_speed.attr, + +	&dev_attr_is_dualspeed.attr, +	&dev_attr_is_otg.attr, +	&dev_attr_is_a_peripheral.attr, +	&dev_attr_b_hnp_enable.attr, +	&dev_attr_a_hnp_support.attr, +	&dev_attr_a_alt_hnp_support.attr, +	NULL, +}; + +static const struct attribute_group usb_udc_attr_group = { +	.attrs = usb_udc_attrs, +}; + +static const struct attribute_group *usb_udc_attr_groups[] = { +	&usb_udc_attr_group, +	NULL, +}; + +static int usb_udc_uevent(struct device *dev, struct kobj_uevent_env *env) +{ +	struct usb_udc		*udc = container_of(dev, struct usb_udc, dev); +	int			ret; + +	ret = add_uevent_var(env, "USB_UDC_NAME=%s", udc->gadget->name); +	if (ret) { +		dev_err(dev, "failed to add uevent USB_UDC_NAME\n"); +		return ret; +	} + +	if (udc->driver) { +		ret = add_uevent_var(env, "USB_UDC_DRIVER=%s", +				udc->driver->function); +		if (ret) { +			dev_err(dev, "failed to add uevent USB_UDC_DRIVER\n"); +			return ret; +		} +	} + +	return 0; +} + +static int __init usb_udc_init(void) +{ +	udc_class = class_create(THIS_MODULE, "udc"); +	if (IS_ERR(udc_class)) { +		pr_err("failed to create udc class --> %ld\n", +				PTR_ERR(udc_class)); +		return PTR_ERR(udc_class); +	} + +	udc_class->dev_uevent = usb_udc_uevent; +	return 0; +} +subsys_initcall(usb_udc_init); + +static void __exit usb_udc_exit(void) +{ +	class_destroy(udc_class); +} +module_exit(usb_udc_exit); + +MODULE_DESCRIPTION("UDC Framework"); +MODULE_AUTHOR("Felipe Balbi <balbi@ti.com>"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/usb/gadget/uvc_queue.c b/drivers/usb/gadget/uvc_queue.c index f7395ac5dc17..aa0ad34e0f1f 100644 --- a/drivers/usb/gadget/uvc_queue.c +++ b/drivers/usb/gadget/uvc_queue.c @@ -19,7 +19,7 @@  #include <linux/videodev2.h>  #include <linux/vmalloc.h>  #include <linux/wait.h> -#include <asm/atomic.h> +#include <linux/atomic.h>  #include "uvc.h" diff --git a/drivers/usb/gadget/uvc_v4l2.c b/drivers/usb/gadget/uvc_v4l2.c index 5e807f083bc8..52f8f9e513af 100644 --- a/drivers/usb/gadget/uvc_v4l2.c +++ b/drivers/usb/gadget/uvc_v4l2.c @@ -124,24 +124,12 @@ uvc_v4l2_open(struct file *file)  	struct video_device *vdev = video_devdata(file);  	struct uvc_device *uvc = video_get_drvdata(vdev);  	struct uvc_file_handle *handle; -	int ret;  	handle = kzalloc(sizeof(*handle), GFP_KERNEL);  	if (handle == NULL)  		return -ENOMEM; -	ret = v4l2_fh_init(&handle->vfh, vdev); -	if (ret < 0) -		goto error; - -	ret = v4l2_event_init(&handle->vfh); -	if (ret < 0) -		goto error; - -	ret = v4l2_event_alloc(&handle->vfh, 8); -	if (ret < 0) -		goto error; - +	v4l2_fh_init(&handle->vfh, vdev);  	v4l2_fh_add(&handle->vfh);  	handle->device = &uvc->video; @@ -149,10 +137,6 @@ uvc_v4l2_open(struct file *file)  	uvc_function_connect(uvc);  	return 0; - -error: -	v4l2_fh_exit(&handle->vfh); -	return ret;  }  static int @@ -314,7 +298,7 @@ uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)  		if (sub->type < UVC_EVENT_FIRST || sub->type > UVC_EVENT_LAST)  			return -EINVAL; -		return v4l2_event_subscribe(&handle->vfh, arg); +		return v4l2_event_subscribe(&handle->vfh, arg, 2);  	}  	case VIDIOC_UNSUBSCRIBE_EVENT: @@ -354,7 +338,7 @@ uvc_v4l2_poll(struct file *file, poll_table *wait)  	struct uvc_file_handle *handle = to_uvc_file_handle(file->private_data);  	unsigned int mask = 0; -	poll_wait(file, &handle->vfh.events->wait, wait); +	poll_wait(file, &handle->vfh.wait, wait);  	if (v4l2_event_pending(&handle->vfh))  		mask |= POLLPRI; diff --git a/drivers/usb/gadget/webcam.c b/drivers/usb/gadget/webcam.c index a5a0fdb808c7..df6882de50bf 100644 --- a/drivers/usb/gadget/webcam.c +++ b/drivers/usb/gadget/webcam.c @@ -373,6 +373,7 @@ static struct usb_composite_driver webcam_driver = {  	.name		= "g_webcam",  	.dev		= &webcam_device_descriptor,  	.strings	= webcam_device_strings, +	.max_speed	= USB_SPEED_HIGH,  	.unbind		= webcam_unbind,  }; diff --git a/drivers/usb/gadget/zero.c b/drivers/usb/gadget/zero.c index 6d16db9d9d2d..00e2fd2d4791 100644 --- a/drivers/usb/gadget/zero.c +++ b/drivers/usb/gadget/zero.c @@ -340,6 +340,7 @@ static struct usb_composite_driver zero_driver = {  	.name		= "zero",  	.dev		= &device_desc,  	.strings	= dev_strings, +	.max_speed	= USB_SPEED_SUPER,  	.unbind		= zero_unbind,  	.suspend	= zero_suspend,  	.resume		= zero_resume, | 
