diff options
237 files changed, 2461 insertions, 8561 deletions
diff --git a/Documentation/DocBook/gadget.tmpl b/Documentation/DocBook/gadget.tmpl index 6ef2f0073e5a..4017f147ba2f 100644 --- a/Documentation/DocBook/gadget.tmpl +++ b/Documentation/DocBook/gadget.tmpl @@ -671,7 +671,7 @@ than a kernel driver. <para>There's a USB Mass Storage class driver, which provides a different solution for interoperability with systems such as MS-Windows and MacOS. -That <emphasis>File-backed Storage</emphasis> driver uses a +That <emphasis>Mass Storage</emphasis> driver uses a file or block device as backing store for a drive, like the <filename>loop</filename> driver. The USB host uses the BBB, CB, or CBI versions of the mass diff --git a/Documentation/devicetree/bindings/usb/am33xx-usb.txt b/Documentation/devicetree/bindings/usb/am33xx-usb.txt index ca8fa56e9f03..a92250512a4e 100644 --- a/Documentation/devicetree/bindings/usb/am33xx-usb.txt +++ b/Documentation/devicetree/bindings/usb/am33xx-usb.txt @@ -3,12 +3,12 @@ AM33XX MUSB GLUE - ti,hwmods : must be "usb_otg_hs" - multipoint : Should be "1" indicating the musb controller supports multipoint. This is a MUSB configuration-specific setting. - - num_eps : Specifies the number of endpoints. This is also a + - num-eps : Specifies the number of endpoints. This is also a MUSB configuration-specific setting. Should be set to "16" - - ram_bits : Specifies the ram address size. Should be set to "12" - - port0_mode : Should be "3" to represent OTG. "1" signifies HOST and "2" + - ram-bits : Specifies the ram address size. Should be set to "12" + - port0-mode : Should be "3" to represent OTG. "1" signifies HOST and "2" represents PERIPHERAL. - - port1_mode : Should be "1" to represent HOST. "3" signifies OTG and "2" + - port1-mode : Should be "1" to represent HOST. "3" signifies OTG and "2" represents PERIPHERAL. - power : Should be "250". This signifies the controller can supply upto 500mA when operating in host mode. diff --git a/Documentation/usb/error-codes.txt b/Documentation/usb/error-codes.txt index b3f606b81a03..9c3eb845ebe5 100644 --- a/Documentation/usb/error-codes.txt +++ b/Documentation/usb/error-codes.txt @@ -21,6 +21,8 @@ Non-USB-specific: USB-specific: +-EBUSY The URB is already active. + -ENODEV specified USB-device or bus doesn't exist -ENOENT specified interface or endpoint does not exist or @@ -35,9 +37,8 @@ USB-specific: d) ISO: number_of_packets is < 0 e) various other cases --EAGAIN a) specified ISO start frame too early - b) (using ISO-ASAP) too much scheduled for the future - wait some time and try again. +-EXDEV ISO: URB_ISO_ASAP wasn't specified and all the frames + the URB would be scheduled in have already expired. -EFBIG Host controller driver can't schedule that many ISO frames. diff --git a/Documentation/usb/mass-storage.txt b/Documentation/usb/mass-storage.txt index e9b9334627bf..59063ad7a60d 100644 --- a/Documentation/usb/mass-storage.txt +++ b/Documentation/usb/mass-storage.txt @@ -20,9 +20,9 @@ This document describes how to use the gadget from user space, its relation to mass storage function (or MSF) and different gadgets - using it, and how it differs from File Storage Gadget (or FSG). It - will talk only briefly about how to use MSF within composite - gadgets. + using it, and how it differs from File Storage Gadget (or FSG) + (which is no longer included in Linux). It will talk only briefly + about how to use MSF within composite gadgets. * Module parameters @@ -198,16 +198,15 @@ The Mass Storage Function and thus the Mass Storage Gadget has been based on the File Storage Gadget. The difference between the two is that MSG is a composite gadget (ie. uses the composite framework) - while file storage gadget is a traditional gadget. From userspace + while file storage gadget was a traditional gadget. From userspace point of view this distinction does not really matter, but from kernel hacker's point of view, this means that (i) MSG does not duplicate code needed for handling basic USB protocol commands and (ii) MSF can be used in any other composite gadget. - Because of that, File Storage Gadget has been deprecated and - scheduled to be removed in Linux 3.8. All users need to transition - to the Mass Storage Gadget by that time. The two gadgets behave - mostly the same from the outside except: + Because of that, File Storage Gadget has been removed in Linux 3.8. + All users need to transition to the Mass Storage Gadget. The two + gadgets behave mostly the same from the outside except: 1. In FSG the “removable” and “cdrom” module parameters set the flag for all logical units whereas in MSG they accept a list of y/n diff --git a/arch/arm/configs/afeb9260_defconfig b/arch/arm/configs/afeb9260_defconfig index c285a9d777d9..a8dbc1e05253 100644 --- a/arch/arm/configs/afeb9260_defconfig +++ b/arch/arm/configs/afeb9260_defconfig @@ -79,7 +79,7 @@ CONFIG_USB_STORAGE=y CONFIG_USB_GADGET=y CONFIG_USB_ZERO=m CONFIG_USB_GADGETFS=m -CONFIG_USB_FILE_STORAGE=m +CONFIG_USB_MASS_STORAGE=m CONFIG_USB_G_SERIAL=m CONFIG_RTC_CLASS=y CONFIG_RTC_DEBUG=y diff --git a/arch/arm/configs/at91sam9260_defconfig b/arch/arm/configs/at91sam9260_defconfig index 505b3765f87e..0ea5d2c97fc4 100644 --- a/arch/arm/configs/at91sam9260_defconfig +++ b/arch/arm/configs/at91sam9260_defconfig @@ -75,7 +75,7 @@ CONFIG_USB_STORAGE_DEBUG=y CONFIG_USB_GADGET=y CONFIG_USB_ZERO=m CONFIG_USB_GADGETFS=m -CONFIG_USB_FILE_STORAGE=m +CONFIG_USB_MASS_STORAGE=m CONFIG_USB_G_SERIAL=m CONFIG_RTC_CLASS=y CONFIG_RTC_DRV_AT91SAM9=y diff --git a/arch/arm/configs/at91sam9261_defconfig b/arch/arm/configs/at91sam9261_defconfig index 1e8712ef062e..c87beb973b37 100644 --- a/arch/arm/configs/at91sam9261_defconfig +++ b/arch/arm/configs/at91sam9261_defconfig @@ -125,7 +125,7 @@ CONFIG_USB_GADGET=y CONFIG_USB_ZERO=m CONFIG_USB_ETH=m CONFIG_USB_GADGETFS=m -CONFIG_USB_FILE_STORAGE=m +CONFIG_USB_MASS_STORAGE=m CONFIG_USB_G_SERIAL=m CONFIG_MMC=y CONFIG_MMC_ATMELMCI=m diff --git a/arch/arm/configs/at91sam9263_defconfig b/arch/arm/configs/at91sam9263_defconfig index d2050cada82d..c5212f43eee6 100644 --- a/arch/arm/configs/at91sam9263_defconfig +++ b/arch/arm/configs/at91sam9263_defconfig @@ -133,7 +133,7 @@ CONFIG_USB_GADGET=y CONFIG_USB_ZERO=m CONFIG_USB_ETH=m CONFIG_USB_GADGETFS=m -CONFIG_USB_FILE_STORAGE=m +CONFIG_USB_MASS_STORAGE=m CONFIG_USB_G_SERIAL=m CONFIG_MMC=y CONFIG_SDIO_UART=m diff --git a/arch/arm/configs/at91sam9g20_defconfig b/arch/arm/configs/at91sam9g20_defconfig index e1b0e80b54a5..3b1881033ad8 100644 --- a/arch/arm/configs/at91sam9g20_defconfig +++ b/arch/arm/configs/at91sam9g20_defconfig @@ -96,7 +96,7 @@ CONFIG_USB_STORAGE=y CONFIG_USB_GADGET=y CONFIG_USB_ZERO=m CONFIG_USB_GADGETFS=m -CONFIG_USB_FILE_STORAGE=m +CONFIG_USB_MASS_STORAGE=m CONFIG_USB_G_SERIAL=m CONFIG_MMC=y CONFIG_MMC_ATMELMCI=m diff --git a/arch/arm/configs/corgi_defconfig b/arch/arm/configs/corgi_defconfig index 4b8a25d9e686..1fd1d1de3220 100644 --- a/arch/arm/configs/corgi_defconfig +++ b/arch/arm/configs/corgi_defconfig @@ -218,7 +218,7 @@ CONFIG_USB_GADGET=y CONFIG_USB_ZERO=m CONFIG_USB_ETH=m CONFIG_USB_GADGETFS=m -CONFIG_USB_FILE_STORAGE=m +CONFIG_USB_MASS_STORAGE=m CONFIG_USB_G_SERIAL=m CONFIG_MMC=y CONFIG_MMC_PXA=y diff --git a/arch/arm/configs/davinci_all_defconfig b/arch/arm/configs/davinci_all_defconfig index 67b5abb6f857..4ea7c95719d2 100644 --- a/arch/arm/configs/davinci_all_defconfig +++ b/arch/arm/configs/davinci_all_defconfig @@ -144,7 +144,7 @@ CONFIG_USB_GADGET_DEBUG_FS=y CONFIG_USB_ZERO=m CONFIG_USB_ETH=m CONFIG_USB_GADGETFS=m -CONFIG_USB_FILE_STORAGE=m +CONFIG_USB_MASS_STORAGE=m CONFIG_USB_G_SERIAL=m CONFIG_USB_G_PRINTER=m CONFIG_USB_CDC_COMPOSITE=m diff --git a/arch/arm/configs/h7202_defconfig b/arch/arm/configs/h7202_defconfig index 69405a762423..e16d3f372e2a 100644 --- a/arch/arm/configs/h7202_defconfig +++ b/arch/arm/configs/h7202_defconfig @@ -34,8 +34,7 @@ CONFIG_FB_MODE_HELPERS=y CONFIG_USB_GADGET=m CONFIG_USB_ZERO=m CONFIG_USB_GADGETFS=m -CONFIG_USB_FILE_STORAGE=m -CONFIG_USB_FILE_STORAGE_TEST=y +CONFIG_USB_MASS_STORAGE=m CONFIG_USB_G_SERIAL=m CONFIG_EXT2_FS=y CONFIG_TMPFS=y diff --git a/arch/arm/configs/magician_defconfig b/arch/arm/configs/magician_defconfig index a691ef4c6008..557dd291288b 100644 --- a/arch/arm/configs/magician_defconfig +++ b/arch/arm/configs/magician_defconfig @@ -136,7 +136,7 @@ CONFIG_USB_PXA27X=y CONFIG_USB_ETH=m # CONFIG_USB_ETH_RNDIS is not set CONFIG_USB_GADGETFS=m -CONFIG_USB_FILE_STORAGE=m +CONFIG_USB_MASS_STORAGE=m CONFIG_USB_G_SERIAL=m CONFIG_USB_CDC_COMPOSITE=m CONFIG_USB_GPIO_VBUS=y diff --git a/arch/arm/configs/mini2440_defconfig b/arch/arm/configs/mini2440_defconfig index 00630e6af45c..a07948a87caa 100644 --- a/arch/arm/configs/mini2440_defconfig +++ b/arch/arm/configs/mini2440_defconfig @@ -240,7 +240,7 @@ CONFIG_USB_GADGET_S3C2410=y CONFIG_USB_ZERO=m CONFIG_USB_ETH=m CONFIG_USB_GADGETFS=m -CONFIG_USB_FILE_STORAGE=m +CONFIG_USB_MASS_STORAGE=m CONFIG_USB_G_SERIAL=m CONFIG_USB_CDC_COMPOSITE=m CONFIG_MMC=y diff --git a/arch/arm/configs/omap1_defconfig b/arch/arm/configs/omap1_defconfig index dde2a1af7b39..42eab9a2a0fd 100644 --- a/arch/arm/configs/omap1_defconfig +++ b/arch/arm/configs/omap1_defconfig @@ -214,8 +214,7 @@ CONFIG_USB_TEST=y CONFIG_USB_GADGET=y CONFIG_USB_ETH=m # CONFIG_USB_ETH_RNDIS is not set -CONFIG_USB_FILE_STORAGE=m -CONFIG_USB_FILE_STORAGE_TEST=y +CONFIG_USB_MASS_STORAGE=m CONFIG_MMC=y CONFIG_MMC_SDHCI=y CONFIG_MMC_SDHCI_PLTFM=y diff --git a/arch/arm/configs/prima2_defconfig b/arch/arm/configs/prima2_defconfig index 807d4e2acb17..6a936c7c078a 100644 --- a/arch/arm/configs/prima2_defconfig +++ b/arch/arm/configs/prima2_defconfig @@ -37,7 +37,6 @@ CONFIG_SPI_SIRF=y CONFIG_SPI_SPIDEV=y # CONFIG_HWMON is not set CONFIG_USB_GADGET=y -CONFIG_USB_FILE_STORAGE=m CONFIG_USB_MASS_STORAGE=m CONFIG_MMC=y CONFIG_MMC_SDHCI=y diff --git a/arch/arm/configs/spitz_defconfig b/arch/arm/configs/spitz_defconfig index df77931a4326..2e0419d1b964 100644 --- a/arch/arm/configs/spitz_defconfig +++ b/arch/arm/configs/spitz_defconfig @@ -214,7 +214,7 @@ CONFIG_USB_GADGET_DUMMY_HCD=y CONFIG_USB_ZERO=m CONFIG_USB_ETH=m CONFIG_USB_GADGETFS=m -CONFIG_USB_FILE_STORAGE=m +CONFIG_USB_MASS_STORAGE=m CONFIG_USB_G_SERIAL=m CONFIG_MMC=y CONFIG_MMC_PXA=y diff --git a/arch/arm/configs/stamp9g20_defconfig b/arch/arm/configs/stamp9g20_defconfig index 52f1488591c7..b845f5519bcc 100644 --- a/arch/arm/configs/stamp9g20_defconfig +++ b/arch/arm/configs/stamp9g20_defconfig @@ -97,7 +97,7 @@ CONFIG_USB_STORAGE=y CONFIG_USB_GADGET=m CONFIG_USB_ZERO=m CONFIG_USB_ETH=m -CONFIG_USB_FILE_STORAGE=m +CONFIG_USB_MASS_STORAGE=m CONFIG_USB_G_SERIAL=m CONFIG_MMC=y CONFIG_MMC_ATMELMCI=y diff --git a/arch/arm/configs/viper_defconfig b/arch/arm/configs/viper_defconfig index 1d01ddd33122..d36e0d3c86ec 100644 --- a/arch/arm/configs/viper_defconfig +++ b/arch/arm/configs/viper_defconfig @@ -139,7 +139,7 @@ CONFIG_USB_SERIAL_MCT_U232=m CONFIG_USB_GADGET=m CONFIG_USB_ETH=m CONFIG_USB_GADGETFS=m -CONFIG_USB_FILE_STORAGE=m +CONFIG_USB_MASS_STORAGE=m CONFIG_USB_G_SERIAL=m CONFIG_USB_G_PRINTER=m CONFIG_RTC_CLASS=y diff --git a/arch/arm/configs/zeus_defconfig b/arch/arm/configs/zeus_defconfig index 547a3c1e59db..731d4f985310 100644 --- a/arch/arm/configs/zeus_defconfig +++ b/arch/arm/configs/zeus_defconfig @@ -143,7 +143,7 @@ CONFIG_USB_GADGET=m CONFIG_USB_PXA27X=y CONFIG_USB_ETH=m CONFIG_USB_GADGETFS=m -CONFIG_USB_FILE_STORAGE=m +CONFIG_USB_MASS_STORAGE=m CONFIG_USB_G_SERIAL=m CONFIG_USB_G_PRINTER=m CONFIG_MMC=y diff --git a/arch/arm/mach-cns3xxx/cns3420vb.c b/arch/arm/mach-cns3xxx/cns3420vb.c index 2c5fb4c7e509..ae305397003c 100644 --- a/arch/arm/mach-cns3xxx/cns3420vb.c +++ b/arch/arm/mach-cns3xxx/cns3420vb.c @@ -24,6 +24,8 @@ #include <linux/mtd/mtd.h> #include <linux/mtd/physmap.h> #include <linux/mtd/partitions.h> +#include <linux/usb/ehci_pdriver.h> +#include <linux/usb/ohci_pdriver.h> #include <asm/setup.h> #include <asm/mach-types.h> #include <asm/hardware/gic.h> @@ -32,6 +34,7 @@ #include <asm/mach/time.h> #include <mach/cns3xxx.h> #include <mach/irqs.h> +#include <mach/pm.h> #include "core.h" #include "devices.h" @@ -125,13 +128,52 @@ static struct resource cns3xxx_usb_ehci_resources[] = { static u64 cns3xxx_usb_ehci_dma_mask = DMA_BIT_MASK(32); +static int csn3xxx_usb_power_on(struct platform_device *pdev) +{ + /* + * EHCI and OHCI share the same clock and power, + * resetting twice would cause the 1st controller been reset. + * Therefore only do power up at the first up device, and + * power down at the last down device. + * + * Set USB AHB INCR length to 16 + */ + if (atomic_inc_return(&usb_pwr_ref) == 1) { + cns3xxx_pwr_power_up(1 << PM_PLL_HM_PD_CTRL_REG_OFFSET_PLL_USB); + cns3xxx_pwr_clk_en(1 << PM_CLK_GATE_REG_OFFSET_USB_HOST); + cns3xxx_pwr_soft_rst(1 << PM_SOFT_RST_REG_OFFST_USB_HOST); + __raw_writel((__raw_readl(MISC_CHIP_CONFIG_REG) | (0X2 << 24)), + MISC_CHIP_CONFIG_REG); + } + + return 0; +} + +static void csn3xxx_usb_power_off(struct platform_device *pdev) +{ + /* + * EHCI and OHCI share the same clock and power, + * resetting twice would cause the 1st controller been reset. + * Therefore only do power up at the first up device, and + * power down at the last down device. + */ + if (atomic_dec_return(&usb_pwr_ref) == 0) + cns3xxx_pwr_clk_dis(1 << PM_CLK_GATE_REG_OFFSET_USB_HOST); +} + +static struct usb_ehci_pdata cns3xxx_usb_ehci_pdata = { + .power_on = csn3xxx_usb_power_on, + .power_off = csn3xxx_usb_power_off, +}; + static struct platform_device cns3xxx_usb_ehci_device = { - .name = "cns3xxx-ehci", + .name = "ehci-platform", .num_resources = ARRAY_SIZE(cns3xxx_usb_ehci_resources), .resource = cns3xxx_usb_ehci_resources, .dev = { .dma_mask = &cns3xxx_usb_ehci_dma_mask, .coherent_dma_mask = DMA_BIT_MASK(32), + .platform_data = &cns3xxx_usb_ehci_pdata, }, }; @@ -149,13 +191,20 @@ static struct resource cns3xxx_usb_ohci_resources[] = { static u64 cns3xxx_usb_ohci_dma_mask = DMA_BIT_MASK(32); +static struct usb_ohci_pdata cns3xxx_usb_ohci_pdata = { + .num_ports = 1, + .power_on = csn3xxx_usb_power_on, + .power_off = csn3xxx_usb_power_off, +}; + static struct platform_device cns3xxx_usb_ohci_device = { - .name = "cns3xxx-ohci", + .name = "ohci-platform", .num_resources = ARRAY_SIZE(cns3xxx_usb_ohci_resources), .resource = cns3xxx_usb_ohci_resources, .dev = { .dma_mask = &cns3xxx_usb_ohci_dma_mask, .coherent_dma_mask = DMA_BIT_MASK(32), + .platform_data = &cns3xxx_usb_ohci_pdata, }, }; diff --git a/arch/avr32/configs/atngw100_defconfig b/arch/avr32/configs/atngw100_defconfig index a06bfccc2840..f4025db184ff 100644 --- a/arch/avr32/configs/atngw100_defconfig +++ b/arch/avr32/configs/atngw100_defconfig @@ -109,7 +109,7 @@ CONFIG_USB_GADGET_VBUS_DRAW=350 CONFIG_USB_ZERO=m CONFIG_USB_ETH=m CONFIG_USB_GADGETFS=m -CONFIG_USB_FILE_STORAGE=m +CONFIG_USB_MASS_STORAGE=m CONFIG_USB_G_SERIAL=m CONFIG_USB_CDC_COMPOSITE=m CONFIG_MMC=y diff --git a/arch/avr32/configs/atngw100_evklcd100_defconfig b/arch/avr32/configs/atngw100_evklcd100_defconfig index d8f1fe80d210..c76a49b9e9d0 100644 --- a/arch/avr32/configs/atngw100_evklcd100_defconfig +++ b/arch/avr32/configs/atngw100_evklcd100_defconfig @@ -125,7 +125,7 @@ CONFIG_USB_GADGET_VBUS_DRAW=350 CONFIG_USB_ZERO=m CONFIG_USB_ETH=m CONFIG_USB_GADGETFS=m -CONFIG_USB_FILE_STORAGE=m +CONFIG_USB_MASS_STORAGE=m CONFIG_USB_G_SERIAL=m CONFIG_USB_CDC_COMPOSITE=m CONFIG_MMC=y diff --git a/arch/avr32/configs/atngw100_evklcd101_defconfig b/arch/avr32/configs/atngw100_evklcd101_defconfig index d4c5b19ec950..2d8ab089a64e 100644 --- a/arch/avr32/configs/atngw100_evklcd101_defconfig +++ b/arch/avr32/configs/atngw100_evklcd101_defconfig @@ -124,7 +124,7 @@ CONFIG_USB_GADGET_VBUS_DRAW=350 CONFIG_USB_ZERO=m CONFIG_USB_ETH=m CONFIG_USB_GADGETFS=m -CONFIG_USB_FILE_STORAGE=m +CONFIG_USB_MASS_STORAGE=m CONFIG_USB_G_SERIAL=m CONFIG_USB_CDC_COMPOSITE=m CONFIG_MMC=y diff --git a/arch/avr32/configs/atngw100_mrmt_defconfig b/arch/avr32/configs/atngw100_mrmt_defconfig index 77ca4f905d2c..b189e0cab04b 100644 --- a/arch/avr32/configs/atngw100_mrmt_defconfig +++ b/arch/avr32/configs/atngw100_mrmt_defconfig @@ -99,7 +99,7 @@ CONFIG_SND_ATMEL_AC97C=m # CONFIG_SND_SPI is not set CONFIG_USB_GADGET=m CONFIG_USB_GADGET_DEBUG_FILES=y -CONFIG_USB_FILE_STORAGE=m +CONFIG_USB_MASS_STORAGE=m CONFIG_USB_G_SERIAL=m CONFIG_MMC=y CONFIG_MMC_ATMELMCI=y diff --git a/arch/avr32/configs/atngw100mkii_defconfig b/arch/avr32/configs/atngw100mkii_defconfig index 6e0dca4d3131..2e4de42a53c4 100644 --- a/arch/avr32/configs/atngw100mkii_defconfig +++ b/arch/avr32/configs/atngw100mkii_defconfig @@ -111,7 +111,7 @@ CONFIG_USB_GADGET_VBUS_DRAW=350 CONFIG_USB_ZERO=m CONFIG_USB_ETH=m CONFIG_USB_GADGETFS=m -CONFIG_USB_FILE_STORAGE=m +CONFIG_USB_MASS_STORAGE=m CONFIG_USB_G_SERIAL=m CONFIG_USB_CDC_COMPOSITE=m CONFIG_MMC=y diff --git a/arch/avr32/configs/atngw100mkii_evklcd100_defconfig b/arch/avr32/configs/atngw100mkii_evklcd100_defconfig index 7f2a344a5fa8..fad3cd22dfd3 100644 --- a/arch/avr32/configs/atngw100mkii_evklcd100_defconfig +++ b/arch/avr32/configs/atngw100mkii_evklcd100_defconfig @@ -128,7 +128,7 @@ CONFIG_USB_GADGET_VBUS_DRAW=350 CONFIG_USB_ZERO=m CONFIG_USB_ETH=m CONFIG_USB_GADGETFS=m -CONFIG_USB_FILE_STORAGE=m +CONFIG_USB_MASS_STORAGE=m CONFIG_USB_G_SERIAL=m CONFIG_USB_CDC_COMPOSITE=m CONFIG_MMC=y diff --git a/arch/avr32/configs/atngw100mkii_evklcd101_defconfig b/arch/avr32/configs/atngw100mkii_evklcd101_defconfig index 085eeba88f67..29986230aaa5 100644 --- a/arch/avr32/configs/atngw100mkii_evklcd101_defconfig +++ b/arch/avr32/configs/atngw100mkii_evklcd101_defconfig @@ -127,7 +127,7 @@ CONFIG_USB_GADGET_VBUS_DRAW=350 CONFIG_USB_ZERO=m CONFIG_USB_ETH=m CONFIG_USB_GADGETFS=m -CONFIG_USB_FILE_STORAGE=m +CONFIG_USB_MASS_STORAGE=m CONFIG_USB_G_SERIAL=m CONFIG_USB_CDC_COMPOSITE=m CONFIG_MMC=y diff --git a/arch/avr32/configs/atstk1002_defconfig b/arch/avr32/configs/atstk1002_defconfig index d1a887e64055..a582465e1cef 100644 --- a/arch/avr32/configs/atstk1002_defconfig +++ b/arch/avr32/configs/atstk1002_defconfig @@ -126,7 +126,7 @@ CONFIG_USB_GADGET=y CONFIG_USB_ZERO=m CONFIG_USB_ETH=m CONFIG_USB_GADGETFS=m -CONFIG_USB_FILE_STORAGE=m +CONFIG_USB_MASS_STORAGE=m CONFIG_USB_G_SERIAL=m CONFIG_USB_CDC_COMPOSITE=m CONFIG_MMC=y diff --git a/arch/avr32/configs/atstk1003_defconfig b/arch/avr32/configs/atstk1003_defconfig index 956f2819ad45..57a79df2ce5d 100644 --- a/arch/avr32/configs/atstk1003_defconfig +++ b/arch/avr32/configs/atstk1003_defconfig @@ -105,7 +105,7 @@ CONFIG_USB_GADGET=y CONFIG_USB_ZERO=m CONFIG_USB_ETH=m CONFIG_USB_GADGETFS=m -CONFIG_USB_FILE_STORAGE=m +CONFIG_USB_MASS_STORAGE=m CONFIG_USB_G_SERIAL=m CONFIG_USB_CDC_COMPOSITE=m CONFIG_MMC=y diff --git a/arch/avr32/configs/atstk1004_defconfig b/arch/avr32/configs/atstk1004_defconfig index 40c69f38c61a..1a49bd8c6340 100644 --- a/arch/avr32/configs/atstk1004_defconfig +++ b/arch/avr32/configs/atstk1004_defconfig @@ -104,7 +104,7 @@ CONFIG_USB_GADGET=y CONFIG_USB_ZERO=m CONFIG_USB_ETH=m CONFIG_USB_GADGETFS=m -CONFIG_USB_FILE_STORAGE=m +CONFIG_USB_MASS_STORAGE=m CONFIG_USB_G_SERIAL=m CONFIG_USB_CDC_COMPOSITE=m CONFIG_MMC=y diff --git a/arch/avr32/configs/atstk1006_defconfig b/arch/avr32/configs/atstk1006_defconfig index 511eb8af356d..206a1b67f763 100644 --- a/arch/avr32/configs/atstk1006_defconfig +++ b/arch/avr32/configs/atstk1006_defconfig @@ -129,7 +129,7 @@ CONFIG_USB_GADGET=y CONFIG_USB_ZERO=m CONFIG_USB_ETH=m CONFIG_USB_GADGETFS=m -CONFIG_USB_FILE_STORAGE=m +CONFIG_USB_MASS_STORAGE=m CONFIG_USB_G_SERIAL=m CONFIG_USB_CDC_COMPOSITE=m CONFIG_MMC=y diff --git a/arch/avr32/configs/favr-32_defconfig b/arch/avr32/configs/favr-32_defconfig index 19973b06170c..0421498d666b 100644 --- a/arch/avr32/configs/favr-32_defconfig +++ b/arch/avr32/configs/favr-32_defconfig @@ -117,7 +117,7 @@ CONFIG_USB_GADGET=y CONFIG_USB_ZERO=m CONFIG_USB_ETH=m CONFIG_USB_GADGETFS=m -CONFIG_USB_FILE_STORAGE=m +CONFIG_USB_MASS_STORAGE=m CONFIG_USB_G_SERIAL=m CONFIG_USB_CDC_COMPOSITE=m CONFIG_MMC=y diff --git a/arch/avr32/configs/hammerhead_defconfig b/arch/avr32/configs/hammerhead_defconfig index 6f45681196d1..82f24eb251bd 100644 --- a/arch/avr32/configs/hammerhead_defconfig +++ b/arch/avr32/configs/hammerhead_defconfig @@ -127,7 +127,7 @@ CONFIG_USB_GADGET=y CONFIG_USB_ZERO=m CONFIG_USB_ETH=m CONFIG_USB_GADGETFS=m -CONFIG_USB_FILE_STORAGE=m +CONFIG_USB_MASS_STORAGE=m CONFIG_USB_G_SERIAL=m CONFIG_MMC=m CONFIG_MMC_ATMELMCI=m diff --git a/arch/blackfin/configs/CM-BF527_defconfig b/arch/blackfin/configs/CM-BF527_defconfig index c280a50e7943..f59c80ee78e3 100644 --- a/arch/blackfin/configs/CM-BF527_defconfig +++ b/arch/blackfin/configs/CM-BF527_defconfig @@ -106,7 +106,7 @@ CONFIG_MUSB_PIO_ONLY=y CONFIG_USB_STORAGE=m CONFIG_USB_GADGET=m CONFIG_USB_ETH=m -CONFIG_USB_FILE_STORAGE=m +CONFIG_USB_MASS_STORAGE=m CONFIG_USB_G_SERIAL=m CONFIG_USB_G_PRINTER=m CONFIG_RTC_CLASS=y diff --git a/arch/blackfin/configs/CM-BF548_defconfig b/arch/blackfin/configs/CM-BF548_defconfig index 349922be01f3..e961483f1879 100644 --- a/arch/blackfin/configs/CM-BF548_defconfig +++ b/arch/blackfin/configs/CM-BF548_defconfig @@ -107,7 +107,7 @@ CONFIG_USB_ZERO=m CONFIG_USB_ETH=m # CONFIG_USB_ETH_RNDIS is not set CONFIG_USB_GADGETFS=m -CONFIG_USB_FILE_STORAGE=m +CONFIG_USB_MASS_STORAGE=m CONFIG_USB_G_SERIAL=m CONFIG_USB_G_PRINTER=m CONFIG_MMC=m diff --git a/arch/blackfin/configs/CM-BF561_defconfig b/arch/blackfin/configs/CM-BF561_defconfig index 0456deaa2d6f..24936b91a6ee 100644 --- a/arch/blackfin/configs/CM-BF561_defconfig +++ b/arch/blackfin/configs/CM-BF561_defconfig @@ -83,7 +83,7 @@ CONFIG_GPIOLIB=y CONFIG_GPIO_SYSFS=y CONFIG_USB_GADGET=m CONFIG_USB_ETH=m -CONFIG_USB_FILE_STORAGE=m +CONFIG_USB_MASS_STORAGE=m CONFIG_USB_G_SERIAL=m CONFIG_USB_G_PRINTER=m CONFIG_MMC=y diff --git a/arch/mips/alchemy/common/Makefile b/arch/mips/alchemy/common/Makefile index 407ebc00e661..cb83d8d21aef 100644 --- a/arch/mips/alchemy/common/Makefile +++ b/arch/mips/alchemy/common/Makefile @@ -6,7 +6,7 @@ # obj-y += prom.o time.o clocks.o platform.o power.o setup.o \ - sleeper.o dma.o dbdma.o vss.o irq.o + sleeper.o dma.o dbdma.o vss.o irq.o usb.o # optional gpiolib support ifeq ($(CONFIG_ALCHEMY_GPIO_INDIRECT),) diff --git a/arch/mips/alchemy/common/platform.c b/arch/mips/alchemy/common/platform.c index c0f3ce6dcb56..7af941d8e717 100644 --- a/arch/mips/alchemy/common/platform.c +++ b/arch/mips/alchemy/common/platform.c @@ -17,6 +17,8 @@ #include <linux/platform_device.h> #include <linux/serial_8250.h> #include <linux/slab.h> +#include <linux/usb/ehci_pdriver.h> +#include <linux/usb/ohci_pdriver.h> #include <asm/mach-au1x00/au1000.h> #include <asm/mach-au1x00/au1xxx_dbdma.h> @@ -122,6 +124,53 @@ static void __init alchemy_setup_uarts(int ctype) static u64 alchemy_ohci_dmamask = DMA_BIT_MASK(32); static u64 __maybe_unused alchemy_ehci_dmamask = DMA_BIT_MASK(32); +/* Power on callback for the ehci platform driver */ +static int alchemy_ehci_power_on(struct platform_device *pdev) +{ + return alchemy_usb_control(ALCHEMY_USB_EHCI0, 1); +} + +/* Power off/suspend callback for the ehci platform driver */ +static void alchemy_ehci_power_off(struct platform_device *pdev) +{ + alchemy_usb_control(ALCHEMY_USB_EHCI0, 0); +} + +static struct usb_ehci_pdata alchemy_ehci_pdata = { + .no_io_watchdog = 1, + .power_on = alchemy_ehci_power_on, + .power_off = alchemy_ehci_power_off, + .power_suspend = alchemy_ehci_power_off, +}; + +/* Power on callback for the ohci platform driver */ +static int alchemy_ohci_power_on(struct platform_device *pdev) +{ + int unit; + + unit = (pdev->id == 1) ? + ALCHEMY_USB_OHCI1 : ALCHEMY_USB_OHCI0; + + return alchemy_usb_control(unit, 1); +} + +/* Power off/suspend callback for the ohci platform driver */ +static void alchemy_ohci_power_off(struct platform_device *pdev) +{ + int unit; + + unit = (pdev->id == 1) ? + ALCHEMY_USB_OHCI1 : ALCHEMY_USB_OHCI0; + + alchemy_usb_control(unit, 0); +} + +static struct usb_ohci_pdata alchemy_ohci_pdata = { + .power_on = alchemy_ohci_power_on, + .power_off = alchemy_ohci_power_off, + .power_suspend = alchemy_ohci_power_off, +}; + static unsigned long alchemy_ohci_data[][2] __initdata = { [ALCHEMY_CPU_AU1000] = { AU1000_USB_OHCI_PHYS_ADDR, AU1000_USB_HOST_INT }, [ALCHEMY_CPU_AU1500] = { AU1000_USB_OHCI_PHYS_ADDR, AU1500_USB_HOST_INT }, @@ -169,9 +218,10 @@ static void __init alchemy_setup_usb(int ctype) res[1].start = alchemy_ohci_data[ctype][1]; res[1].end = res[1].start; res[1].flags = IORESOURCE_IRQ; - pdev->name = "au1xxx-ohci"; + pdev->name = "ohci-platform"; pdev->id = 0; pdev->dev.dma_mask = &alchemy_ohci_dmamask; + pdev->dev.platform_data = &alchemy_ohci_pdata; if (platform_device_register(pdev)) printk(KERN_INFO "Alchemy USB: cannot add OHCI0\n"); @@ -188,9 +238,10 @@ static void __init alchemy_setup_usb(int ctype) res[1].start = alchemy_ehci_data[ctype][1]; res[1].end = res[1].start; res[1].flags = IORESOURCE_IRQ; - pdev->name = "au1xxx-ehci"; + pdev->name = "ehci-platform"; pdev->id = 0; pdev->dev.dma_mask = &alchemy_ehci_dmamask; + pdev->dev.platform_data = &alchemy_ehci_pdata; if (platform_device_register(pdev)) printk(KERN_INFO "Alchemy USB: cannot add EHCI0\n"); @@ -207,9 +258,10 @@ static void __init alchemy_setup_usb(int ctype) res[1].start = AU1300_USB_INT; res[1].end = res[1].start; res[1].flags = IORESOURCE_IRQ; - pdev->name = "au1xxx-ohci"; + pdev->name = "ohci-platform"; pdev->id = 1; pdev->dev.dma_mask = &alchemy_ohci_dmamask; + pdev->dev.platform_data = &alchemy_ohci_pdata; if (platform_device_register(pdev)) printk(KERN_INFO "Alchemy USB: cannot add OHCI1\n"); diff --git a/drivers/usb/host/alchemy-common.c b/arch/mips/alchemy/common/usb.c index 936af8359fb2..936af8359fb2 100644 --- a/drivers/usb/host/alchemy-common.c +++ b/arch/mips/alchemy/common/usb.c diff --git a/arch/mips/ath79/dev-usb.c b/arch/mips/ath79/dev-usb.c index 072bb9be2304..bd2bc108e1b5 100644 --- a/arch/mips/ath79/dev-usb.c +++ b/arch/mips/ath79/dev-usb.c @@ -50,13 +50,11 @@ static u64 ath79_ehci_dmamask = DMA_BIT_MASK(32); static struct usb_ehci_pdata ath79_ehci_pdata_v1 = { .has_synopsys_hc_bug = 1, - .port_power_off = 1, }; static struct usb_ehci_pdata ath79_ehci_pdata_v2 = { .caps_offset = 0x100, .has_tt = 1, - .port_power_off = 1, }; static struct platform_device ath79_ehci_device = { diff --git a/arch/mips/configs/bcm47xx_defconfig b/arch/mips/configs/bcm47xx_defconfig index b6fde2bb51b6..4ca8e5c99225 100644 --- a/arch/mips/configs/bcm47xx_defconfig +++ b/arch/mips/configs/bcm47xx_defconfig @@ -473,7 +473,7 @@ CONFIG_USB_GADGET_NET2280=y CONFIG_USB_ZERO=m CONFIG_USB_ETH=m CONFIG_USB_GADGETFS=m -CONFIG_USB_FILE_STORAGE=m +CONFIG_USB_MASS_STORAGE=m CONFIG_USB_G_SERIAL=m CONFIG_USB_MIDI_GADGET=m CONFIG_LEDS_CLASS=y diff --git a/arch/mips/configs/db1000_defconfig b/arch/mips/configs/db1000_defconfig index 17a36c125172..face9d26e6d5 100644 --- a/arch/mips/configs/db1000_defconfig +++ b/arch/mips/configs/db1000_defconfig @@ -233,6 +233,7 @@ CONFIG_USB_EHCI_HCD=y CONFIG_USB_EHCI_ROOT_HUB_TT=y CONFIG_USB_EHCI_TT_NEWSCHED=y CONFIG_USB_OHCI_HCD=y +CONFIG_USB_OHCI_HCD_PLATFORM=y CONFIG_USB_UHCI_HCD=y CONFIG_USB_STORAGE=y CONFIG_NEW_LEDS=y diff --git a/arch/mips/configs/db1235_defconfig b/arch/mips/configs/db1235_defconfig index c48998ffd198..14752dde7540 100644 --- a/arch/mips/configs/db1235_defconfig +++ b/arch/mips/configs/db1235_defconfig @@ -346,8 +346,10 @@ CONFIG_USB=y CONFIG_USB_DYNAMIC_MINORS=y CONFIG_USB_SUSPEND=y CONFIG_USB_EHCI_HCD=y +CONFIG_USB_EHCI_HCD_PLATFORM=y CONFIG_USB_EHCI_ROOT_HUB_TT=y CONFIG_USB_OHCI_HCD=y +CONFIG_USB_OHCI_HCD_PLATFORM=y CONFIG_USB_STORAGE=y CONFIG_MMC=y CONFIG_MMC_CLKGATE=y diff --git a/arch/mips/configs/gpr_defconfig b/arch/mips/configs/gpr_defconfig index 48a40aefaf58..fb64589015fc 100644 --- a/arch/mips/configs/gpr_defconfig +++ b/arch/mips/configs/gpr_defconfig @@ -291,6 +291,7 @@ CONFIG_USB_MON=y CONFIG_USB_EHCI_HCD=y CONFIG_USB_EHCI_ROOT_HUB_TT=y CONFIG_USB_OHCI_HCD=y +CONFIG_USB_OHCI_HCD_PLATFORM=y CONFIG_USB_STORAGE=m CONFIG_USB_LIBUSUAL=y CONFIG_USB_SERIAL=y diff --git a/arch/mips/configs/ls1b_defconfig b/arch/mips/configs/ls1b_defconfig index 80cff8bea8e8..7eb75543ca1a 100644 --- a/arch/mips/configs/ls1b_defconfig +++ b/arch/mips/configs/ls1b_defconfig @@ -76,6 +76,7 @@ CONFIG_HID_GENERIC=m CONFIG_USB=y CONFIG_USB_ANNOUNCE_NEW_DEVICES=y CONFIG_USB_EHCI_HCD=y +CONFIG_USB_EHCI_HCD_PLATFORM=y # CONFIG_USB_EHCI_TT_NEWSCHED is not set CONFIG_USB_STORAGE=m CONFIG_USB_SERIAL=m diff --git a/arch/mips/configs/mtx1_defconfig b/arch/mips/configs/mtx1_defconfig index 46c61edcdf7b..9fa8f16068d8 100644 --- a/arch/mips/configs/mtx1_defconfig +++ b/arch/mips/configs/mtx1_defconfig @@ -581,6 +581,7 @@ CONFIG_USB_MON=m CONFIG_USB_EHCI_HCD=m CONFIG_USB_EHCI_ROOT_HUB_TT=y CONFIG_USB_OHCI_HCD=m +CONFIG_USB_OHCI_HCD_PLATFORM=y CONFIG_USB_UHCI_HCD=m CONFIG_USB_U132_HCD=m CONFIG_USB_SL811_HCD=m @@ -661,7 +662,7 @@ CONFIG_USB_GADGET_NET2280=y CONFIG_USB_ZERO=m CONFIG_USB_ETH=m CONFIG_USB_GADGETFS=m -CONFIG_USB_FILE_STORAGE=m +CONFIG_USB_MASS_STORAGE=m CONFIG_USB_G_SERIAL=m CONFIG_USB_MIDI_GADGET=m CONFIG_MMC=m diff --git a/arch/mips/loongson1/common/platform.c b/arch/mips/loongson1/common/platform.c index e92d59c4bd78..0412ad61e290 100644 --- a/arch/mips/loongson1/common/platform.c +++ b/arch/mips/loongson1/common/platform.c @@ -13,6 +13,7 @@ #include <linux/phy.h> #include <linux/serial_8250.h> #include <linux/stmmac.h> +#include <linux/usb/ehci_pdriver.h> #include <asm-generic/sizes.h> #include <loongson1.h> @@ -107,13 +108,17 @@ static struct resource ls1x_ehci_resources[] = { }, }; +static struct usb_ehci_pdata ls1x_ehci_pdata = { +}; + struct platform_device ls1x_ehci_device = { - .name = "ls1x-ehci", + .name = "ehci-platform", .id = -1, .num_resources = ARRAY_SIZE(ls1x_ehci_resources), .resource = ls1x_ehci_resources, .dev = { .dma_mask = &ls1x_ehci_dmamask, + .platform_data = &ls1x_ehci_pdata, }, }; diff --git a/arch/mips/netlogic/xlr/platform.c b/arch/mips/netlogic/xlr/platform.c index 71b44d82621d..507230eeb768 100644 --- a/arch/mips/netlogic/xlr/platform.c +++ b/arch/mips/netlogic/xlr/platform.c @@ -15,6 +15,8 @@ #include <linux/serial_8250.h> #include <linux/serial_reg.h> #include <linux/i2c.h> +#include <linux/usb/ehci_pdriver.h> +#include <linux/usb/ohci_pdriver.h> #include <asm/netlogic/haldefs.h> #include <asm/netlogic/xlr/iomap.h> @@ -123,12 +125,18 @@ static u64 xls_usb_dmamask = ~(u32)0; }, \ } +static struct usb_ehci_pdata xls_usb_ehci_pdata = { + .caps_offset = 0, +}; + +static struct usb_ohci_pdata xls_usb_ohci_pdata; + static struct platform_device xls_usb_ehci_device = - USB_PLATFORM_DEV("ehci-xls", 0, PIC_USB_IRQ); + USB_PLATFORM_DEV("ehci-platform", 0, PIC_USB_IRQ); static struct platform_device xls_usb_ohci_device_0 = - USB_PLATFORM_DEV("ohci-xls-0", 1, PIC_USB_IRQ); + USB_PLATFORM_DEV("ohci-platform", 1, PIC_USB_IRQ); static struct platform_device xls_usb_ohci_device_1 = - USB_PLATFORM_DEV("ohci-xls-1", 2, PIC_USB_IRQ); + USB_PLATFORM_DEV("ohci-platform", 2, PIC_USB_IRQ); static struct platform_device *xls_platform_devices[] = { &xls_usb_ehci_device, @@ -172,14 +180,17 @@ int xls_platform_usb_init(void) memres = CPHYSADDR((unsigned long)usb_mmio); xls_usb_ehci_device.resource[0].start = memres; xls_usb_ehci_device.resource[0].end = memres + 0x400 - 1; + xls_usb_ehci_device.dev.platform_data = &xls_usb_ehci_pdata; memres += 0x400; xls_usb_ohci_device_0.resource[0].start = memres; xls_usb_ohci_device_0.resource[0].end = memres + 0x400 - 1; + xls_usb_ohci_device_0.dev.platform_data = &xls_usb_ohci_pdata; memres += 0x400; xls_usb_ohci_device_1.resource[0].start = memres; xls_usb_ohci_device_1.resource[0].end = memres + 0x400 - 1; + xls_usb_ohci_device_1.dev.platform_data = &xls_usb_ohci_pdata; return platform_add_devices(xls_platform_devices, ARRAY_SIZE(xls_platform_devices)); diff --git a/arch/mips/pnx8550/common/platform.c b/arch/mips/pnx8550/common/platform.c index 5264cc09a27b..0a8faeaa7b70 100644 --- a/arch/mips/pnx8550/common/platform.c +++ b/arch/mips/pnx8550/common/platform.c @@ -20,6 +20,7 @@ #include <linux/serial.h> #include <linux/serial_pnx8xxx.h> #include <linux/platform_device.h> +#include <linux/usb/ohci_pdriver.h> #include <int.h> #include <usb.h> @@ -96,12 +97,40 @@ static u64 ohci_dmamask = DMA_BIT_MASK(32); static u64 uart_dmamask = DMA_BIT_MASK(32); +static int pnx8550_usb_ohci_power_on(struct platform_device *pdev) +{ + /* + * Set register CLK48CTL to enable and 48MHz + */ + outl(0x00000003, PCI_BASE | 0x0004770c); + + /* + * Set register CLK12CTL to enable and 48MHz + */ + outl(0x00000003, PCI_BASE | 0x00047710); + + udelay(100); + + return 0; +} + +static void pnx8550_usb_ohci_power_off(struct platform_device *pdev) +{ + udelay(10); +} + +static struct usb_ohci_pdata pnx8550_usb_ohci_pdata = { + .power_on = pnx8550_usb_ohci_power_on, + .power_off = pnx8550_usb_ohci_power_off, +}; + static struct platform_device pnx8550_usb_ohci_device = { - .name = "pnx8550-ohci", + .name = "ohci-platform", .id = -1, .dev = { .dma_mask = &ohci_dmamask, .coherent_dma_mask = DMA_BIT_MASK(32), + .platform_data = &pnx8550_usb_ohci_pdata, }, .num_resources = ARRAY_SIZE(pnx8550_usb_ohci_resources), .resource = pnx8550_usb_ohci_resources, diff --git a/arch/sh/configs/ecovec24_defconfig b/arch/sh/configs/ecovec24_defconfig index 911e30c9abfd..c6c2becdc8ab 100644 --- a/arch/sh/configs/ecovec24_defconfig +++ b/arch/sh/configs/ecovec24_defconfig @@ -112,7 +112,7 @@ CONFIG_USB_MON=y CONFIG_USB_R8A66597_HCD=y CONFIG_USB_STORAGE=y CONFIG_USB_GADGET=y -CONFIG_USB_FILE_STORAGE=m +CONFIG_USB_MASS_STORAGE=m CONFIG_MMC=y CONFIG_MMC_SPI=y CONFIG_MMC_SDHI=y diff --git a/arch/sh/configs/se7724_defconfig b/arch/sh/configs/se7724_defconfig index ed35093e3758..1faa788aecae 100644 --- a/arch/sh/configs/se7724_defconfig +++ b/arch/sh/configs/se7724_defconfig @@ -109,7 +109,7 @@ CONFIG_USB_STORAGE=y CONFIG_USB_GADGET=y CONFIG_USB_ETH=m CONFIG_USB_GADGETFS=m -CONFIG_USB_FILE_STORAGE=m +CONFIG_USB_MASS_STORAGE=m CONFIG_USB_G_SERIAL=m CONFIG_MMC=y CONFIG_MMC_SPI=y diff --git a/arch/sh/kernel/cpu/sh3/setup-sh7720.c b/arch/sh/kernel/cpu/sh3/setup-sh7720.c index 0c2f1b2c2e19..42d991f632b1 100644 --- a/arch/sh/kernel/cpu/sh3/setup-sh7720.c +++ b/arch/sh/kernel/cpu/sh3/setup-sh7720.c @@ -20,6 +20,7 @@ #include <linux/serial_sci.h> #include <linux/sh_timer.h> #include <linux/sh_intc.h> +#include <linux/usb/ohci_pdriver.h> #include <asm/rtc.h> #include <cpu/serial.h> @@ -103,12 +104,15 @@ static struct resource usb_ohci_resources[] = { static u64 usb_ohci_dma_mask = 0xffffffffUL; +static struct usb_ohci_pdata usb_ohci_pdata; + static struct platform_device usb_ohci_device = { - .name = "sh_ohci", + .name = "ohci-platform", .id = -1, .dev = { .dma_mask = &usb_ohci_dma_mask, .coherent_dma_mask = 0xffffffff, + .platform_data = &usb_ohci_pdata, }, .num_resources = ARRAY_SIZE(usb_ohci_resources), .resource = usb_ohci_resources, diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7757.c b/arch/sh/kernel/cpu/sh4a/setup-sh7757.c index 4a2f357f4df8..9079a0f9ea9b 100644 --- a/arch/sh/kernel/cpu/sh4a/setup-sh7757.c +++ b/arch/sh/kernel/cpu/sh4a/setup-sh7757.c @@ -19,6 +19,7 @@ #include <linux/sh_timer.h> #include <linux/sh_dma.h> #include <linux/sh_intc.h> +#include <linux/usb/ohci_pdriver.h> #include <cpu/dma-register.h> #include <cpu/sh7757.h> @@ -750,12 +751,15 @@ static struct resource usb_ohci_resources[] = { }, }; +static struct usb_ohci_pdata usb_ohci_pdata; + static struct platform_device usb_ohci_device = { - .name = "sh_ohci", + .name = "ohci-platform", .id = -1, .dev = { .dma_mask = &usb_ohci_device.dev.coherent_dma_mask, .coherent_dma_mask = DMA_BIT_MASK(32), + .platform_data = &usb_ohci_pdata, }, .num_resources = ARRAY_SIZE(usb_ohci_resources), .resource = usb_ohci_resources, diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7763.c b/arch/sh/kernel/cpu/sh4a/setup-sh7763.c index bd0a8fbe610f..1686acaaf45a 100644 --- a/arch/sh/kernel/cpu/sh4a/setup-sh7763.c +++ b/arch/sh/kernel/cpu/sh4a/setup-sh7763.c @@ -16,6 +16,7 @@ #include <linux/sh_intc.h> #include <linux/io.h> #include <linux/serial_sci.h> +#include <linux/usb/ohci_pdriver.h> static struct plat_sci_port scif0_platform_data = { .mapbase = 0xffe00000, @@ -106,12 +107,15 @@ static struct resource usb_ohci_resources[] = { static u64 usb_ohci_dma_mask = 0xffffffffUL; +static struct usb_ohci_pdata usb_ohci_pdata; + static struct platform_device usb_ohci_device = { - .name = "sh_ohci", + .name = "ohci-platform", .id = -1, .dev = { .dma_mask = &usb_ohci_dma_mask, .coherent_dma_mask = 0xffffffff, + .platform_data = &usb_ohci_pdata, }, .num_resources = ARRAY_SIZE(usb_ohci_resources), .resource = usb_ohci_resources, diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7786.c b/arch/sh/kernel/cpu/sh4a/setup-sh7786.c index 2e6952f87848..ab52d4d4484d 100644 --- a/arch/sh/kernel/cpu/sh4a/setup-sh7786.c +++ b/arch/sh/kernel/cpu/sh4a/setup-sh7786.c @@ -23,6 +23,7 @@ #include <linux/sh_timer.h> #include <linux/sh_dma.h> #include <linux/sh_intc.h> +#include <linux/usb/ohci_pdriver.h> #include <cpu/dma-register.h> #include <asm/mmzone.h> @@ -583,12 +584,15 @@ static struct resource usb_ohci_resources[] = { }, }; +static struct usb_ohci_pdata usb_ohci_pdata; + static struct platform_device usb_ohci_device = { - .name = "sh_ohci", + .name = "ohci-platform", .id = -1, .dev = { .dma_mask = &usb_ohci_device.dev.coherent_dma_mask, .coherent_dma_mask = DMA_BIT_MASK(32), + .platform_data = &usb_ohci_pdata, }, .num_resources = ARRAY_SIZE(usb_ohci_resources), .resource = usb_ohci_resources, diff --git a/drivers/usb/chipidea/Kconfig b/drivers/usb/chipidea/Kconfig index 1ea932a13685..608a2aeb400c 100644 --- a/drivers/usb/chipidea/Kconfig +++ b/drivers/usb/chipidea/Kconfig @@ -20,6 +20,7 @@ config USB_CHIPIDEA_UDC config USB_CHIPIDEA_HOST bool "ChipIdea host controller" depends on USB=y || USB=USB_CHIPIDEA + depends on USB_EHCI_HCD select USB_EHCI_ROOT_HUB_TT help Say Y here to enable host controller functionality of the diff --git a/drivers/usb/chipidea/debug.c b/drivers/usb/chipidea/debug.c index c6f50a257565..3bc244d2636a 100644 --- a/drivers/usb/chipidea/debug.c +++ b/drivers/usb/chipidea/debug.c @@ -160,9 +160,6 @@ static ssize_t show_device(struct device *dev, struct device_attribute *attr, gadget->speed); n += scnprintf(buf + n, PAGE_SIZE - n, "max_speed = %d\n", gadget->max_speed); - /* TODO: Scheduled for removal in 3.8. */ - n += scnprintf(buf + n, PAGE_SIZE - n, "is_dualspeed = %d\n", - gadget_is_dualspeed(gadget)); n += scnprintf(buf + n, PAGE_SIZE - n, "is_otg = %d\n", gadget->is_otg); n += scnprintf(buf + n, PAGE_SIZE - n, "is_a_peripheral = %d\n", diff --git a/drivers/usb/chipidea/host.c b/drivers/usb/chipidea/host.c index ebff9f4f56ec..caecad9213f5 100644 --- a/drivers/usb/chipidea/host.c +++ b/drivers/usb/chipidea/host.c @@ -20,77 +20,18 @@ */ #include <linux/kernel.h> +#include <linux/io.h> #include <linux/usb.h> #include <linux/usb/hcd.h> #include <linux/usb/chipidea.h> -#define CHIPIDEA_EHCI -#include "../host/ehci-hcd.c" +#include "../host/ehci.h" #include "ci.h" #include "bits.h" #include "host.h" -static int ci_ehci_setup(struct usb_hcd *hcd) -{ - struct ehci_hcd *ehci = hcd_to_ehci(hcd); - int ret; - - hcd->has_tt = 1; - - ret = ehci_setup(hcd); - if (ret) - return ret; - - ehci_port_power(ehci, 0); - - return ret; -} - -static const struct hc_driver ci_ehci_hc_driver = { - .description = "ehci_hcd", - .product_desc = "ChipIdea HDRC EHCI", - .hcd_priv_size = sizeof(struct ehci_hcd), - - /* - * generic hardware linkage - */ - .irq = ehci_irq, - .flags = HCD_MEMORY | HCD_USB2, - - /* - * basic lifecycle operations - */ - .reset = ci_ehci_setup, - .start = ehci_run, - .stop = ehci_stop, - .shutdown = ehci_shutdown, - - /* - * managing i/o requests and associated device resources - */ - .urb_enqueue = ehci_urb_enqueue, - .urb_dequeue = ehci_urb_dequeue, - .endpoint_disable = ehci_endpoint_disable, - .endpoint_reset = ehci_endpoint_reset, - - /* - * scheduling support - */ - .get_frame_number = ehci_get_frame, - - /* - * root hub support - */ - .hub_status_data = ehci_hub_status_data, - .hub_control = ehci_hub_control, - .bus_suspend = ehci_bus_suspend, - .bus_resume = ehci_bus_resume, - .relinquish_port = ehci_relinquish_port, - .port_handed_over = ehci_port_handed_over, - - .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete, -}; +static struct hc_driver __read_mostly ci_ehci_hc_driver; static irqreturn_t host_irq(struct ci13xxx *ci) { @@ -157,5 +98,7 @@ int ci_hdrc_host_init(struct ci13xxx *ci) rdrv->name = "host"; ci->roles[CI_ROLE_HOST] = rdrv; + ehci_init_driver(&ci_ehci_hc_driver, NULL); + return 0; } diff --git a/drivers/usb/core/devices.c b/drivers/usb/core/devices.c index f460de31acee..cbacea933b18 100644 --- a/drivers/usb/core/devices.c +++ b/drivers/usb/core/devices.c @@ -591,16 +591,14 @@ static ssize_t usb_device_dump(char __user **buffer, size_t *nbytes, /* Now look at all of this device's children. */ usb_hub_for_each_child(usbdev, chix, childdev) { - if (childdev) { - usb_lock_device(childdev); - ret = usb_device_dump(buffer, nbytes, skip_bytes, - file_offset, childdev, bus, - level + 1, chix - 1, ++cnt); - usb_unlock_device(childdev); - if (ret == -EFAULT) - return total_written; - total_written += ret; - } + usb_lock_device(childdev); + ret = usb_device_dump(buffer, nbytes, skip_bytes, + file_offset, childdev, bus, + level + 1, chix - 1, ++cnt); + usb_unlock_device(childdev); + if (ret == -EFAULT) + return total_written; + total_written += ret; } return total_written; } diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index 1e741bca0265..eaa14514e173 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -2039,8 +2039,9 @@ int hcd_bus_resume(struct usb_device *rhdev, pm_message_t msg) status = hcd->driver->bus_resume(hcd); clear_bit(HCD_FLAG_WAKEUP_PENDING, &hcd->flags); if (status == 0) { - /* TRSMRCY = 10 msec */ - msleep(10); + struct usb_device *udev; + int port1; + spin_lock_irq(&hcd_root_hub_lock); if (!HCD_DEAD(hcd)) { usb_set_device_state(rhdev, rhdev->actconfig @@ -2050,6 +2051,20 @@ int hcd_bus_resume(struct usb_device *rhdev, pm_message_t msg) hcd->state = HC_STATE_RUNNING; } spin_unlock_irq(&hcd_root_hub_lock); + + /* + * Check whether any of the enabled ports on the root hub are + * unsuspended. If they are then a TRSMRCY delay is needed + * (this is what the USB-2 spec calls a "global resume"). + * Otherwise we can skip the delay. + */ + usb_hub_for_each_child(rhdev, port1, udev) { + if (udev->state != USB_STATE_NOTATTACHED && + !udev->port_is_suspended) { + usleep_range(10000, 11000); /* TRSMRCY */ + break; + } + } } else { hcd->state = old_state; dev_dbg(&rhdev->dev, "bus %s fail, err %d\n", diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 1af04bdeaf0c..90accdefdc7d 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -39,6 +39,9 @@ #endif #endif +#define USB_VENDOR_GENESYS_LOGIC 0x05e3 +#define HUB_QUIRK_CHECK_PORT_AUTOSUSPEND 0x01 + struct usb_port { struct usb_device *child; struct device dev; @@ -86,6 +89,8 @@ struct usb_hub { unsigned quiescing:1; unsigned disconnected:1; + unsigned quirk_check_port_auto_suspend:1; + unsigned has_indicators:1; u8 indicator[USB_MAXCHILDREN]; struct delayed_work leds; @@ -736,7 +741,6 @@ static void hub_tt_work(struct work_struct *work) struct usb_hub *hub = container_of(work, struct usb_hub, tt.clear_work); unsigned long flags; - int limit = 100; spin_lock_irqsave (&hub->tt.lock, flags); while (!list_empty(&hub->tt.clear_list)) { @@ -746,9 +750,6 @@ static void hub_tt_work(struct work_struct *work) const struct hc_driver *drv; int status; - if (!hub->quiescing && --limit < 0) - break; - next = hub->tt.clear_list.next; clear = list_entry (next, struct usb_tt_clear, clear_list); list_del (&clear->clear_list); @@ -1612,6 +1613,41 @@ static int hub_probe(struct usb_interface *intf, const struct usb_device_id *id) desc = intf->cur_altsetting; hdev = interface_to_usbdev(intf); + /* + * Set default autosuspend delay as 0 to speedup bus suspend, + * based on the below considerations: + * + * - Unlike other drivers, the hub driver does not rely on the + * autosuspend delay to provide enough time to handle a wakeup + * event, and the submitted status URB is just to check future + * change on hub downstream ports, so it is safe to do it. + * + * - The patch might cause one or more auto supend/resume for + * below very rare devices when they are plugged into hub + * first time: + * + * devices having trouble initializing, and disconnect + * themselves from the bus and then reconnect a second + * or so later + * + * devices just for downloading firmware, and disconnects + * themselves after completing it + * + * For these quite rare devices, their drivers may change the + * autosuspend delay of their parent hub in the probe() to one + * appropriate value to avoid the subtle problem if someone + * does care it. + * + * - The patch may cause one or more auto suspend/resume on + * hub during running 'lsusb', but it is probably too + * infrequent to worry about. + * + * - Change autosuspend delay of hub can avoid unnecessary auto + * suspend timer for hub, also may decrease power consumption + * of USB bus. + */ + pm_runtime_set_autosuspend_delay(&hdev->dev, 0); + /* Hubs have proper suspend/resume support. */ usb_enable_autosuspend(hdev); @@ -1670,6 +1706,9 @@ descriptor_error: if (hdev->speed == USB_SPEED_HIGH) highspeed_hubs++; + if (id->driver_info & HUB_QUIRK_CHECK_PORT_AUTOSUSPEND) + hub->quirk_check_port_auto_suspend = 1; + if (hub_configure(hub, endpoint) >= 0) return 0; @@ -2012,7 +2051,7 @@ static void show_string(struct usb_device *udev, char *id, char *string) { if (!string) return; - dev_printk(KERN_INFO, &udev->dev, "%s: %s\n", id, string); + dev_info(&udev->dev, "%s: %s\n", id, string); } static void announce_device(struct usb_device *udev) @@ -2879,6 +2918,7 @@ int usb_port_suspend(struct usb_device *udev, pm_message_t msg) (PMSG_IS_AUTO(msg) ? "auto-" : ""), udev->do_remote_wakeup); usb_set_device_state(udev, USB_STATE_SUSPENDED); + udev->port_is_suspended = 1; msleep(10); } usb_mark_last_busy(hub->hdev); @@ -3043,6 +3083,7 @@ int usb_port_resume(struct usb_device *udev, pm_message_t msg) SuspendCleared: if (status == 0) { + udev->port_is_suspended = 0; if (hub_is_superspeed(hub->hdev)) { if (portchange & USB_PORT_STAT_C_LINK_STATE) clear_port_feature(hub->hdev, port1, @@ -3126,6 +3167,21 @@ int usb_port_resume(struct usb_device *udev, pm_message_t msg) #endif +static int check_ports_changed(struct usb_hub *hub) +{ + int port1; + + for (port1 = 1; port1 <= hub->hdev->maxchild; ++port1) { + u16 portstatus, portchange; + int status; + + status = hub_port_status(hub, port1, &portstatus, &portchange); + if (!status && portchange) + return 1; + } + return 0; +} + static int hub_suspend(struct usb_interface *intf, pm_message_t msg) { struct usb_hub *hub = usb_get_intfdata (intf); @@ -3144,6 +3200,16 @@ static int hub_suspend(struct usb_interface *intf, pm_message_t msg) return -EBUSY; } } + + if (hdev->do_remote_wakeup && hub->quirk_check_port_auto_suspend) { + /* check if there are changes pending on hub ports */ + if (check_ports_changed(hub)) { + if (PMSG_IS_AUTO(msg)) + return -EBUSY; + pm_wakeup_event(&hdev->dev, 2000); + } + } + if (hub_is_superspeed(hdev) && hdev->do_remote_wakeup) { /* Enable hub to send remote wakeup for all ports. */ for (port1 = 1; port1 <= hdev->maxchild; port1++) { @@ -4648,6 +4714,11 @@ static int hub_thread(void *__unused) } static const struct usb_device_id hub_id_table[] = { + { .match_flags = USB_DEVICE_ID_MATCH_VENDOR + | USB_DEVICE_ID_MATCH_INT_CLASS, + .idVendor = USB_VENDOR_GENESYS_LOGIC, + .bInterfaceClass = USB_CLASS_HUB, + .driver_info = HUB_QUIRK_CHECK_PORT_AUTOSUSPEND}, { .match_flags = USB_DEVICE_ID_MATCH_DEV_CLASS, .bDeviceClass = USB_CLASS_HUB}, { .match_flags = USB_DEVICE_ID_MATCH_INT_CLASS, diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c index 1ed5afd91e6d..a557658f3223 100644 --- a/drivers/usb/core/message.c +++ b/drivers/usb/core/message.c @@ -1806,29 +1806,8 @@ free_interfaces: goto free_interfaces; } - ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), - USB_REQ_SET_CONFIGURATION, 0, configuration, 0, - NULL, 0, USB_CTRL_SET_TIMEOUT); - if (ret < 0) { - /* All the old state is gone, so what else can we do? - * The device is probably useless now anyway. - */ - cp = NULL; - } - - dev->actconfig = cp; - if (!cp) { - usb_set_device_state(dev, USB_STATE_ADDRESS); - usb_hcd_alloc_bandwidth(dev, NULL, NULL, NULL); - /* Leave LPM disabled while the device is unconfigured. */ - mutex_unlock(hcd->bandwidth_mutex); - usb_autosuspend_device(dev); - goto free_interfaces; - } - mutex_unlock(hcd->bandwidth_mutex); - usb_set_device_state(dev, USB_STATE_CONFIGURED); - - /* Initialize the new interface structures and the + /* + * Initialize the new interface structures and the * hc/hcd/usbcore interface/endpoint state. */ for (i = 0; i < nintf; ++i) { @@ -1872,6 +1851,35 @@ free_interfaces: } kfree(new_interfaces); + ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), + USB_REQ_SET_CONFIGURATION, 0, configuration, 0, + NULL, 0, USB_CTRL_SET_TIMEOUT); + if (ret < 0 && cp) { + /* + * All the old state is gone, so what else can we do? + * The device is probably useless now anyway. + */ + usb_hcd_alloc_bandwidth(dev, NULL, NULL, NULL); + for (i = 0; i < nintf; ++i) { + usb_disable_interface(dev, cp->interface[i], true); + put_device(&cp->interface[i]->dev); + cp->interface[i] = NULL; + } + cp = NULL; + } + + dev->actconfig = cp; + mutex_unlock(hcd->bandwidth_mutex); + + if (!cp) { + usb_set_device_state(dev, USB_STATE_ADDRESS); + + /* Leave LPM disabled while the device is unconfigured. */ + usb_autosuspend_device(dev); + return ret; + } + usb_set_device_state(dev, USB_STATE_CONFIGURED); + if (cp->string == NULL && !(dev->quirks & USB_QUIRK_CONFIG_INTF_STRINGS)) cp->string = usb_cache_string(dev, cp->desc.iConfiguration); diff --git a/drivers/usb/core/urb.c b/drivers/usb/core/urb.c index 9d912bfdcffe..e0d9d948218c 100644 --- a/drivers/usb/core/urb.c +++ b/drivers/usb/core/urb.c @@ -214,9 +214,25 @@ EXPORT_SYMBOL_GPL(usb_unanchor_urb); * urb->interval is modified to reflect the actual transfer period used * (normally some power of two units). And for isochronous urbs, * urb->start_frame is modified to reflect when the URB's transfers were - * scheduled to start. Not all isochronous transfer scheduling policies - * will work, but most host controller drivers should easily handle ISO - * queues going from now until 10-200 msec into the future. + * scheduled to start. + * + * Not all isochronous transfer scheduling policies will work, but most + * host controller drivers should easily handle ISO queues going from now + * until 10-200 msec into the future. Drivers should try to keep at + * least one or two msec of data in the queue; many controllers require + * that new transfers start at least 1 msec in the future when they are + * added. If the driver is unable to keep up and the queue empties out, + * the behavior for new submissions is governed by the URB_ISO_ASAP flag. + * If the flag is set, or if the queue is idle, then the URB is always + * assigned to the first available (and not yet expired) slot in the + * endpoint's schedule. If the flag is not set and the queue is active + * then the URB is always assigned to the next slot in the schedule + * following the end of the endpoint's previous URB, even if that slot is + * in the past. When a packet is assigned in this way to a slot that has + * already expired, the packet is not transmitted and the corresponding + * usb_iso_packet_descriptor's status field will return -EXDEV. If this + * would happen to all the packets in the URB, submission fails with a + * -EXDEV error code. * * For control endpoints, the synchronous usb_control_msg() call is * often used (in non-interrupt context) instead of this call. @@ -305,8 +321,13 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags) struct usb_host_endpoint *ep; int is_out; - if (!urb || urb->hcpriv || !urb->complete) + if (!urb || !urb->complete) return -EINVAL; + if (urb->hcpriv) { + WARN_ONCE(1, "URB %p submitted while active\n", urb); + return -EBUSY; + } + dev = urb->dev; if ((!dev) || (dev->state < USB_STATE_UNAUTHENTICATED)) return -ENODEV; diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c index cd8fb44a3e16..7d3de09a82e4 100644 --- a/drivers/usb/core/usb.c +++ b/drivers/usb/core/usb.c @@ -370,14 +370,14 @@ struct usb_device *usb_alloc_dev(struct usb_device *parent, struct usb_bus *bus, unsigned port1) { struct usb_device *dev; - struct usb_hcd *usb_hcd = container_of(bus, struct usb_hcd, self); + struct usb_hcd *usb_hcd = bus_to_hcd(bus); unsigned root_hub = 0; dev = kzalloc(sizeof(*dev), GFP_KERNEL); if (!dev) return NULL; - if (!usb_get_hcd(bus_to_hcd(bus))) { + if (!usb_get_hcd(usb_hcd)) { kfree(dev); return NULL; } diff --git a/drivers/usb/dwc3/Makefile b/drivers/usb/dwc3/Makefile index d441fe4c180b..4502648b8171 100644 --- a/drivers/usb/dwc3/Makefile +++ b/drivers/usb/dwc3/Makefile @@ -27,19 +27,7 @@ endif ## obj-$(CONFIG_USB_DWC3) += dwc3-omap.o - -## -# REVISIT Samsung Exynos platform needs the clk API which isn't -# defined on all architectures. If we allow dwc3-exynos.c compile -# always we will fail the linking phase on those architectures -# which don't provide clk api implementation and that's unnaceptable. -# -# When Samsung's platform start supporting pm_runtime, this check -# for HAVE_CLK should be removed. -## -ifneq ($(CONFIG_HAVE_CLK),) - obj-$(CONFIG_USB_DWC3) += dwc3-exynos.o -endif +obj-$(CONFIG_USB_DWC3) += dwc3-exynos.o ifneq ($(CONFIG_PCI),) obj-$(CONFIG_USB_DWC3) += dwc3-pci.o diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index c14ebc975ba4..e71a62a652d0 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -66,45 +66,6 @@ MODULE_PARM_DESC(maximum_speed, "Maximum supported speed."); /* -------------------------------------------------------------------------- */ -#define DWC3_DEVS_POSSIBLE 32 - -static DECLARE_BITMAP(dwc3_devs, DWC3_DEVS_POSSIBLE); - -int dwc3_get_device_id(void) -{ - int id; - -again: - id = find_first_zero_bit(dwc3_devs, DWC3_DEVS_POSSIBLE); - if (id < DWC3_DEVS_POSSIBLE) { - int old; - - old = test_and_set_bit(id, dwc3_devs); - if (old) - goto again; - } else { - pr_err("dwc3: no space for new device\n"); - id = -ENOMEM; - } - - return id; -} -EXPORT_SYMBOL_GPL(dwc3_get_device_id); - -void dwc3_put_device_id(int id) -{ - int ret; - - if (id < 0) - return; - - ret = test_bit(id, dwc3_devs); - WARN(!ret, "dwc3: ID %d not in use\n", id); - smp_mb__before_clear_bit(); - clear_bit(id, dwc3_devs); -} -EXPORT_SYMBOL_GPL(dwc3_put_device_id); - void dwc3_set_mode(struct dwc3 *dwc, u32 mode) { u32 reg; @@ -169,7 +130,6 @@ static void dwc3_free_one_event_buffer(struct dwc3 *dwc, struct dwc3_event_buffer *evt) { dma_free_coherent(dwc->dev, evt->length, evt->buf, evt->dma); - kfree(evt); } /** @@ -185,7 +145,7 @@ dwc3_alloc_one_event_buffer(struct dwc3 *dwc, unsigned length) { struct dwc3_event_buffer *evt; - evt = kzalloc(sizeof(*evt), GFP_KERNEL); + evt = devm_kzalloc(dwc->dev, sizeof(*evt), GFP_KERNEL); if (!evt) return ERR_PTR(-ENOMEM); @@ -193,10 +153,8 @@ dwc3_alloc_one_event_buffer(struct dwc3 *dwc, unsigned length) evt->length = length; evt->buf = dma_alloc_coherent(dwc->dev, length, &evt->dma, GFP_KERNEL); - if (!evt->buf) { - kfree(evt); + if (!evt->buf) return ERR_PTR(-ENOMEM); - } return evt; } @@ -215,8 +173,6 @@ static void dwc3_free_event_buffers(struct dwc3 *dwc) if (evt) dwc3_free_one_event_buffer(dwc, evt); } - - kfree(dwc->ev_buffs); } /** @@ -235,7 +191,8 @@ static int __devinit dwc3_alloc_event_buffers(struct dwc3 *dwc, unsigned length) num = DWC3_NUM_INT(dwc->hwparams.hwparams1); dwc->num_event_buffers = num; - dwc->ev_buffs = kzalloc(sizeof(*dwc->ev_buffs) * num, GFP_KERNEL); + dwc->ev_buffs = devm_kzalloc(dwc->dev, sizeof(*dwc->ev_buffs) * num, + GFP_KERNEL); if (!dwc->ev_buffs) { dev_err(dwc->dev, "can't allocate event buffers array\n"); return -ENOMEM; @@ -383,24 +340,14 @@ static int __devinit dwc3_core_init(struct dwc3 *dwc) dwc3_writel(dwc->regs, DWC3_GCTL, reg); - ret = dwc3_alloc_event_buffers(dwc, DWC3_EVENT_BUFFERS_SIZE); - if (ret) { - dev_err(dwc->dev, "failed to allocate event buffers\n"); - ret = -ENOMEM; - goto err1; - } - ret = dwc3_event_buffers_setup(dwc); if (ret) { dev_err(dwc->dev, "failed to setup event buffers\n"); - goto err1; + goto err0; } return 0; -err1: - dwc3_free_event_buffers(dwc); - err0: return ret; } @@ -408,11 +355,9 @@ err0: static void dwc3_core_exit(struct dwc3 *dwc) { dwc3_event_buffers_cleanup(dwc); - dwc3_free_event_buffers(dwc); usb_phy_shutdown(dwc->usb2_phy); usb_phy_shutdown(dwc->usb3_phy); - } #define DWC3_ALIGN_MASK (16 - 1) @@ -515,10 +460,17 @@ static int __devinit dwc3_probe(struct platform_device *pdev) pm_runtime_get_sync(dev); pm_runtime_forbid(dev); + ret = dwc3_alloc_event_buffers(dwc, DWC3_EVENT_BUFFERS_SIZE); + if (ret) { + dev_err(dwc->dev, "failed to allocate event buffers\n"); + ret = -ENOMEM; + goto err0; + } + ret = dwc3_core_init(dwc); if (ret) { dev_err(dev, "failed to initialize core\n"); - return ret; + goto err0; } mode = DWC3_MODE(dwc->hwparams.hwparams0); @@ -590,6 +542,9 @@ err2: err1: dwc3_core_exit(dwc); +err0: + dwc3_free_event_buffers(dwc); + return ret; } diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index 243affc93431..499956344262 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -868,7 +868,4 @@ void dwc3_host_exit(struct dwc3 *dwc); int dwc3_gadget_init(struct dwc3 *dwc); void dwc3_gadget_exit(struct dwc3 *dwc); -extern int dwc3_get_device_id(void); -extern void dwc3_put_device_id(int id); - #endif /* __DRIVERS_USB_DWC3_CORE_H */ diff --git a/drivers/usb/dwc3/dwc3-exynos.c b/drivers/usb/dwc3/dwc3-exynos.c index ca6597853f90..dc35c5476f37 100644 --- a/drivers/usb/dwc3/dwc3-exynos.c +++ b/drivers/usb/dwc3/dwc3-exynos.c @@ -21,6 +21,7 @@ #include <linux/clk.h> #include <linux/usb/otg.h> #include <linux/usb/nop-usb-xceiv.h> +#include <linux/of.h> #include "core.h" @@ -87,14 +88,14 @@ err1: return ret; } +static u64 dwc3_exynos_dma_mask = DMA_BIT_MASK(32); + static int __devinit dwc3_exynos_probe(struct platform_device *pdev) { - struct dwc3_exynos_data *pdata = pdev->dev.platform_data; struct platform_device *dwc3; struct dwc3_exynos *exynos; struct clk *clk; - int devid; int ret = -ENOMEM; exynos = kzalloc(sizeof(*exynos), GFP_KERNEL); @@ -103,11 +104,15 @@ static int __devinit dwc3_exynos_probe(struct platform_device *pdev) goto err0; } - platform_set_drvdata(pdev, exynos); + /* + * Right now device-tree probed devices don't get dma_mask set. + * Since shared usb code relies on it, set it here for now. + * Once we move to full device tree support this will vanish off. + */ + if (!pdev->dev.dma_mask) + pdev->dev.dma_mask = &dwc3_exynos_dma_mask; - devid = dwc3_get_device_id(); - if (devid < 0) - goto err1; + platform_set_drvdata(pdev, exynos); ret = dwc3_exynos_register_phys(exynos); if (ret) { @@ -115,10 +120,10 @@ static int __devinit dwc3_exynos_probe(struct platform_device *pdev) goto err1; } - dwc3 = platform_device_alloc("dwc3", devid); + dwc3 = platform_device_alloc("dwc3", PLATFORM_DEVID_AUTO); if (!dwc3) { dev_err(&pdev->dev, "couldn't allocate dwc3 device\n"); - goto err2; + goto err1; } clk = clk_get(&pdev->dev, "usbdrd30"); @@ -139,14 +144,6 @@ static int __devinit dwc3_exynos_probe(struct platform_device *pdev) clk_enable(exynos->clk); - /* PHY initialization */ - if (!pdata) { - dev_dbg(&pdev->dev, "missing platform data\n"); - } else { - if (pdata->phy_init) - pdata->phy_init(pdev, pdata->phy_type); - } - ret = platform_device_add_resources(dwc3, pdev->resource, pdev->num_resources); if (ret) { @@ -163,15 +160,10 @@ static int __devinit dwc3_exynos_probe(struct platform_device *pdev) return 0; err4: - if (pdata && pdata->phy_exit) - pdata->phy_exit(pdev, pdata->phy_type); - clk_disable(clk); clk_put(clk); err3: platform_device_put(dwc3); -err2: - dwc3_put_device_id(devid); err1: kfree(exynos); err0: @@ -181,17 +173,11 @@ err0: static int __devexit dwc3_exynos_remove(struct platform_device *pdev) { struct dwc3_exynos *exynos = platform_get_drvdata(pdev); - struct dwc3_exynos_data *pdata = pdev->dev.platform_data; platform_device_unregister(exynos->dwc3); platform_device_unregister(exynos->usb2_phy); platform_device_unregister(exynos->usb3_phy); - dwc3_put_device_id(exynos->dwc3->id); - - if (pdata && pdata->phy_exit) - pdata->phy_exit(pdev, pdata->phy_type); - clk_disable(exynos->clk); clk_put(exynos->clk); @@ -200,11 +186,20 @@ static int __devexit dwc3_exynos_remove(struct platform_device *pdev) return 0; } +#ifdef CONFIG_OF +static const struct of_device_id exynos_dwc3_match[] = { + { .compatible = "samsung,exynos-dwc3" }, + {}, +}; +MODULE_DEVICE_TABLE(of, exynos_dwc3_match); +#endif + static struct platform_driver dwc3_exynos_driver = { .probe = dwc3_exynos_probe, .remove = __devexit_p(dwc3_exynos_remove), .driver = { .name = "exynos-dwc3", + .of_match_table = of_match_ptr(exynos_dwc3_match), }, }; diff --git a/drivers/usb/dwc3/dwc3-omap.c b/drivers/usb/dwc3/dwc3-omap.c index ee57a10d90d0..900d435f41d1 100644 --- a/drivers/usb/dwc3/dwc3-omap.c +++ b/drivers/usb/dwc3/dwc3-omap.c @@ -272,7 +272,6 @@ static int __devinit dwc3_omap_probe(struct platform_device *pdev) struct resource *res; struct device *dev = &pdev->dev; - int devid; int size; int ret = -ENOMEM; int irq; @@ -315,14 +314,10 @@ static int __devinit dwc3_omap_probe(struct platform_device *pdev) return ret; } - devid = dwc3_get_device_id(); - if (devid < 0) - return -ENODEV; - - dwc3 = platform_device_alloc("dwc3", devid); + dwc3 = platform_device_alloc("dwc3", PLATFORM_DEVID_AUTO); if (!dwc3) { dev_err(dev, "couldn't allocate dwc3 device\n"); - goto err1; + return -ENOMEM; } context = devm_kzalloc(dev, resource_size(res), GFP_KERNEL); @@ -423,10 +418,6 @@ static int __devinit dwc3_omap_probe(struct platform_device *pdev) err2: platform_device_put(dwc3); - -err1: - dwc3_put_device_id(devid); - return ret; } @@ -437,9 +428,6 @@ static int __devexit dwc3_omap_remove(struct platform_device *pdev) platform_device_unregister(omap->dwc3); platform_device_unregister(omap->usb2_phy); platform_device_unregister(omap->usb3_phy); - - dwc3_put_device_id(omap->dwc3->id); - return 0; } diff --git a/drivers/usb/dwc3/dwc3-pci.c b/drivers/usb/dwc3/dwc3-pci.c index 94f550e37f98..13962597f3fe 100644 --- a/drivers/usb/dwc3/dwc3-pci.c +++ b/drivers/usb/dwc3/dwc3-pci.c @@ -119,7 +119,6 @@ static int __devinit dwc3_pci_probe(struct pci_dev *pci, struct platform_device *dwc3; struct dwc3_pci *glue; int ret = -ENOMEM; - int devid; struct device *dev = &pci->dev; glue = devm_kzalloc(dev, sizeof(*glue), GFP_KERNEL); @@ -145,13 +144,7 @@ static int __devinit dwc3_pci_probe(struct pci_dev *pci, return ret; } - devid = dwc3_get_device_id(); - if (devid < 0) { - ret = -ENOMEM; - goto err1; - } - - dwc3 = platform_device_alloc("dwc3", devid); + dwc3 = platform_device_alloc("dwc3", PLATFORM_DEVID_AUTO); if (!dwc3) { dev_err(dev, "couldn't allocate dwc3 device\n"); ret = -ENOMEM; @@ -172,7 +165,7 @@ static int __devinit dwc3_pci_probe(struct pci_dev *pci, ret = platform_device_add_resources(dwc3, res, ARRAY_SIZE(res)); if (ret) { dev_err(dev, "couldn't add resources to dwc3 device\n"); - goto err2; + goto err1; } pci_set_drvdata(pci, glue); @@ -195,10 +188,6 @@ static int __devinit dwc3_pci_probe(struct pci_dev *pci, err3: pci_set_drvdata(pci, NULL); platform_device_put(dwc3); - -err2: - dwc3_put_device_id(devid); - err1: pci_disable_device(pci); @@ -211,7 +200,6 @@ static void __devexit dwc3_pci_remove(struct pci_dev *pci) platform_device_unregister(glue->usb2_phy); platform_device_unregister(glue->usb3_phy); - dwc3_put_device_id(glue->dwc3->id); platform_device_unregister(glue->dwc3); pci_set_drvdata(pci, NULL); pci_disable_device(pci); diff --git a/drivers/usb/early/ehci-dbgp.c b/drivers/usb/early/ehci-dbgp.c index e426ad626d74..5e29ddeb4d33 100644 --- a/drivers/usb/early/ehci-dbgp.c +++ b/drivers/usb/early/ehci-dbgp.c @@ -20,6 +20,7 @@ #include <linux/usb/ehci_def.h> #include <linux/delay.h> #include <linux/serial_core.h> +#include <linux/kconfig.h> #include <linux/kgdb.h> #include <linux/kthread.h> #include <asm/io.h> @@ -614,12 +615,6 @@ err: return -ENODEV; } -int dbgp_external_startup(struct usb_hcd *hcd) -{ - return xen_dbgp_external_startup(hcd) ?: _dbgp_external_startup(); -} -EXPORT_SYMBOL_GPL(dbgp_external_startup); - static int ehci_reset_port(int port) { u32 portsc; @@ -979,6 +974,7 @@ struct console early_dbgp_console = { .index = -1, }; +#if IS_ENABLED(CONFIG_USB) int dbgp_reset_prep(struct usb_hcd *hcd) { int ret = xen_dbgp_reset_prep(hcd); @@ -1007,6 +1003,13 @@ int dbgp_reset_prep(struct usb_hcd *hcd) } EXPORT_SYMBOL_GPL(dbgp_reset_prep); +int dbgp_external_startup(struct usb_hcd *hcd) +{ + return xen_dbgp_external_startup(hcd) ?: _dbgp_external_startup(); +} +EXPORT_SYMBOL_GPL(dbgp_external_startup); +#endif /* USB */ + #ifdef CONFIG_KGDB static char kgdbdbgp_buf[DBGP_MAX_PACKET]; diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index e0ff51b89529..14625fd2cecd 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -721,31 +721,6 @@ config USB_FUNCTIONFS_GENERIC Include a configuration with the Function Filesystem alone with no Ethernet interface. -config USB_FILE_STORAGE - tristate "File-backed Storage Gadget (DEPRECATED)" - depends on BLOCK - help - The File-backed Storage Gadget acts as a USB Mass Storage - disk drive. As its storage repository it can use a regular - file or a block device (in much the same way as the "loop" - device driver), specified as a module parameter. - - 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 - default n - help - Say "y" to generate the larger testing version of the - File-backed Storage Gadget, useful for probing the - behavior of USB Mass Storage hosts. Not needed for - normal operation. - config USB_MASS_STORAGE tristate "Mass Storage Gadget" depends on BLOCK @@ -756,8 +731,8 @@ config USB_MASS_STORAGE device (in much the same way as the "loop" device driver), specified as a module parameter or sysfs option. - This driver is an updated replacement for the deprecated - File-backed Storage Gadget (g_file_storage). + This driver is a replacement for now removed 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". diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile index 307be5fa824c..8b4acfd92aa3 100644 --- a/drivers/usb/gadget/Makefile +++ b/drivers/usb/gadget/Makefile @@ -44,7 +44,6 @@ g_ether-y := ether.o g_serial-y := serial.o g_midi-y := gmidi.o gadgetfs-y := inode.o -g_file_storage-y := file_storage.o g_mass_storage-y := mass_storage.o g_printer-y := printer.o g_cdc-y := cdc2.o @@ -62,7 +61,6 @@ obj-$(CONFIG_USB_AUDIO) += g_audio.o obj-$(CONFIG_USB_ETH) += g_ether.o obj-$(CONFIG_USB_GADGETFS) += gadgetfs.o obj-$(CONFIG_USB_FUNCTIONFS) += g_ffs.o -obj-$(CONFIG_USB_FILE_STORAGE) += g_file_storage.o obj-$(CONFIG_USB_MASS_STORAGE) += g_mass_storage.o obj-$(CONFIG_USB_G_SERIAL) += g_serial.o obj-$(CONFIG_USB_G_PRINTER) += g_printer.o diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c index 957f973dd96a..2a6bfe759c29 100644 --- a/drivers/usb/gadget/composite.c +++ b/drivers/usb/gadget/composite.c @@ -107,7 +107,7 @@ int config_ep_by_speed(struct usb_gadget *g, } /* else: fall through */ default: - speed_desc = f->descriptors; + speed_desc = f->fs_descriptors; } /* find descriptors */ for_each_ep_desc(speed_desc, d_spd) { @@ -200,7 +200,7 @@ int usb_add_function(struct usb_configuration *config, * as full speed ... it's the function drivers that will need * to avoid bulk and ISO transfers. */ - if (!config->fullspeed && function->descriptors) + if (!config->fullspeed && function->fs_descriptors) config->fullspeed = true; if (!config->highspeed && function->hs_descriptors) config->highspeed = true; @@ -363,7 +363,7 @@ static int config_buf(struct usb_configuration *config, descriptors = f->hs_descriptors; break; default: - descriptors = f->descriptors; + descriptors = f->fs_descriptors; } if (!descriptors) @@ -620,7 +620,7 @@ static int set_config(struct usb_composite_dev *cdev, descriptors = f->hs_descriptors; break; default: - descriptors = f->descriptors; + descriptors = f->fs_descriptors; } for (; *descriptors; ++descriptors) { diff --git a/drivers/usb/gadget/config.c b/drivers/usb/gadget/config.c index e3a98929d346..34e12fc52c23 100644 --- a/drivers/usb/gadget/config.c +++ b/drivers/usb/gadget/config.c @@ -19,7 +19,7 @@ #include <linux/usb/ch9.h> #include <linux/usb/gadget.h> - +#include <linux/usb/composite.h> /** * usb_descriptor_fillbuf - fill buffer with descriptors @@ -158,3 +158,40 @@ usb_copy_descriptors(struct usb_descriptor_header **src) return ret; } EXPORT_SYMBOL_GPL(usb_copy_descriptors); + +int usb_assign_descriptors(struct usb_function *f, + struct usb_descriptor_header **fs, + struct usb_descriptor_header **hs, + struct usb_descriptor_header **ss) +{ + struct usb_gadget *g = f->config->cdev->gadget; + + if (fs) { + f->fs_descriptors = usb_copy_descriptors(fs); + if (!f->fs_descriptors) + goto err; + } + if (hs && gadget_is_dualspeed(g)) { + f->hs_descriptors = usb_copy_descriptors(hs); + if (!f->hs_descriptors) + goto err; + } + if (ss && gadget_is_superspeed(g)) { + f->ss_descriptors = usb_copy_descriptors(ss); + if (!f->ss_descriptors) + goto err; + } + return 0; +err: + usb_free_all_descriptors(f); + return -ENOMEM; +} +EXPORT_SYMBOL_GPL(usb_assign_descriptors); + +void usb_free_all_descriptors(struct usb_function *f) +{ + usb_free_descriptors(f->fs_descriptors); + usb_free_descriptors(f->hs_descriptors); + usb_free_descriptors(f->ss_descriptors); +} +EXPORT_SYMBOL_GPL(usb_free_all_descriptors); diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c index 0f7541be28f3..95d584dbed13 100644 --- a/drivers/usb/gadget/dummy_hcd.c +++ b/drivers/usb/gadget/dummy_hcd.c @@ -63,16 +63,20 @@ MODULE_LICENSE("GPL"); struct dummy_hcd_module_parameters { bool is_super_speed; bool is_high_speed; + unsigned int num; }; static struct dummy_hcd_module_parameters mod_data = { .is_super_speed = false, .is_high_speed = true, + .num = 1, }; 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"); +module_param_named(num, mod_data.num, uint, S_IRUGO); +MODULE_PARM_DESC(num, "number of emulated controllers"); /*-------------------------------------------------------------------------*/ /* gadget side driver data structres */ @@ -238,8 +242,6 @@ static inline struct dummy *gadget_dev_to_dummy(struct device *dev) return container_of(dev, struct dummy, gadget.dev); } -static struct dummy the_controller; - /*-------------------------------------------------------------------------*/ /* SLAVE/GADGET SIDE UTILITY ROUTINES */ @@ -973,9 +975,10 @@ static void init_dummy_udc_hw(struct dummy *dum) static int dummy_udc_probe(struct platform_device *pdev) { - struct dummy *dum = &the_controller; + struct dummy *dum; int rc; + dum = *((void **)dev_get_platdata(&pdev->dev)); dum->gadget.name = gadget_name; dum->gadget.ops = &dummy_ops; dum->gadget.max_speed = USB_SPEED_SUPER; @@ -2398,10 +2401,13 @@ static int dummy_h_get_frame(struct usb_hcd *hcd) static int dummy_setup(struct usb_hcd *hcd) { + struct dummy *dum; + + dum = *((void **)dev_get_platdata(hcd->self.controller)); hcd->self.sg_tablesize = ~0; if (usb_hcd_is_primary_hcd(hcd)) { - the_controller.hs_hcd = hcd_to_dummy_hcd(hcd); - the_controller.hs_hcd->dum = &the_controller; + dum->hs_hcd = hcd_to_dummy_hcd(hcd); + dum->hs_hcd->dum = dum; /* * Mark the first roothub as being USB 2.0. * The USB 3.0 roothub will be registered later by @@ -2410,8 +2416,8 @@ static int dummy_setup(struct usb_hcd *hcd) 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; + dum->ss_hcd = hcd_to_dummy_hcd(hcd); + dum->ss_hcd->dum = dum; hcd->speed = HCD_USB3; hcd->self.root_hub->speed = USB_SPEED_SUPER; } @@ -2524,11 +2530,13 @@ static struct hc_driver dummy_hcd = { static int dummy_hcd_probe(struct platform_device *pdev) { + struct dummy *dum; struct usb_hcd *hs_hcd; struct usb_hcd *ss_hcd; int retval; dev_info(&pdev->dev, "%s, driver " DRIVER_VERSION "\n", driver_desc); + dum = *((void **)dev_get_platdata(&pdev->dev)); if (!mod_data.is_super_speed) dummy_hcd.flags = HCD_USB2; @@ -2561,7 +2569,7 @@ dealloc_usb2_hcd: usb_remove_hcd(hs_hcd); put_usb2_hcd: usb_put_hcd(hs_hcd); - the_controller.hs_hcd = the_controller.ss_hcd = NULL; + dum->hs_hcd = dum->ss_hcd = NULL; return retval; } @@ -2579,8 +2587,8 @@ static int dummy_hcd_remove(struct platform_device *pdev) 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; + dum->hs_hcd = NULL; + dum->ss_hcd = NULL; return 0; } @@ -2627,13 +2635,15 @@ static struct platform_driver dummy_hcd_driver = { }; /*-------------------------------------------------------------------------*/ - -static struct platform_device *the_udc_pdev; -static struct platform_device *the_hcd_pdev; +#define MAX_NUM_UDC 2 +static struct platform_device *the_udc_pdev[MAX_NUM_UDC]; +static struct platform_device *the_hcd_pdev[MAX_NUM_UDC]; static int __init init(void) { int retval = -ENOMEM; + int i; + struct dummy *dum[MAX_NUM_UDC]; if (usb_disabled()) return -ENODEV; @@ -2641,65 +2651,129 @@ static int __init init(void) 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; - the_udc_pdev = platform_device_alloc(gadget_name, -1); - if (!the_udc_pdev) - goto err_alloc_udc; + if (mod_data.num < 1 || mod_data.num > MAX_NUM_UDC) { + pr_err("Number of emulated UDC must be in range of 1…%d\n", + MAX_NUM_UDC); + return -EINVAL; + } + + for (i = 0; i < mod_data.num; i++) { + the_hcd_pdev[i] = platform_device_alloc(driver_name, i); + if (!the_hcd_pdev[i]) { + i--; + while (i >= 0) + platform_device_put(the_hcd_pdev[i--]); + return retval; + } + } + for (i = 0; i < mod_data.num; i++) { + the_udc_pdev[i] = platform_device_alloc(gadget_name, i); + if (!the_udc_pdev[i]) { + i--; + while (i >= 0) + platform_device_put(the_udc_pdev[i--]); + goto err_alloc_udc; + } + } + for (i = 0; i < mod_data.num; i++) { + dum[i] = kzalloc(sizeof(struct dummy), GFP_KERNEL); + if (!dum[i]) + goto err_add_pdata; + retval = platform_device_add_data(the_hcd_pdev[i], &dum[i], + sizeof(void *)); + if (retval) + goto err_add_pdata; + retval = platform_device_add_data(the_udc_pdev[i], &dum[i], + sizeof(void *)); + if (retval) + goto err_add_pdata; + } retval = platform_driver_register(&dummy_hcd_driver); if (retval < 0) - goto err_register_hcd_driver; + goto err_add_pdata; retval = platform_driver_register(&dummy_udc_driver); if (retval < 0) goto err_register_udc_driver; - retval = platform_device_add(the_hcd_pdev); - if (retval < 0) - goto err_add_hcd; - 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. - */ - retval = -EINVAL; - goto err_add_udc; + for (i = 0; i < mod_data.num; i++) { + retval = platform_device_add(the_hcd_pdev[i]); + if (retval < 0) { + i--; + while (i >= 0) + platform_device_del(the_hcd_pdev[i--]); + goto err_add_hcd; + } } - retval = platform_device_add(the_udc_pdev); - if (retval < 0) - goto err_add_udc; - if (!platform_get_drvdata(the_udc_pdev)) { - /* - * The udc was added successfully but its probe function failed - * for some reason. - */ - retval = -EINVAL; - goto err_probe_udc; + for (i = 0; i < mod_data.num; i++) { + if (!dum[i]->hs_hcd || + (!dum[i]->ss_hcd && mod_data.is_super_speed)) { + /* + * The hcd was added successfully but its probe + * function failed for some reason. + */ + retval = -EINVAL; + goto err_add_udc; + } + } + + for (i = 0; i < mod_data.num; i++) { + retval = platform_device_add(the_udc_pdev[i]); + if (retval < 0) { + i--; + while (i >= 0) + platform_device_del(the_udc_pdev[i]); + goto err_add_udc; + } + } + + for (i = 0; i < mod_data.num; i++) { + if (!platform_get_drvdata(the_udc_pdev[i])) { + /* + * The udc was added successfully but its probe + * function failed for some reason. + */ + retval = -EINVAL; + goto err_probe_udc; + } } return retval; err_probe_udc: - platform_device_del(the_udc_pdev); + for (i = 0; i < mod_data.num; i++) + platform_device_del(the_udc_pdev[i]); err_add_udc: - platform_device_del(the_hcd_pdev); + for (i = 0; i < mod_data.num; i++) + platform_device_del(the_hcd_pdev[i]); err_add_hcd: platform_driver_unregister(&dummy_udc_driver); err_register_udc_driver: platform_driver_unregister(&dummy_hcd_driver); -err_register_hcd_driver: - platform_device_put(the_udc_pdev); +err_add_pdata: + for (i = 0; i < mod_data.num; i++) + kfree(dum[i]); + for (i = 0; i < mod_data.num; i++) + platform_device_put(the_udc_pdev[i]); err_alloc_udc: - platform_device_put(the_hcd_pdev); + for (i = 0; i < mod_data.num; i++) + platform_device_put(the_hcd_pdev[i]); return retval; } module_init(init); static void __exit cleanup(void) { - platform_device_unregister(the_udc_pdev); - platform_device_unregister(the_hcd_pdev); + int i; + + for (i = 0; i < mod_data.num; i++) { + struct dummy *dum; + + dum = *((void **)dev_get_platdata(&the_udc_pdev[i]->dev)); + + platform_device_unregister(the_udc_pdev[i]); + platform_device_unregister(the_hcd_pdev[i]); + kfree(dum); + } platform_driver_unregister(&dummy_udc_driver); platform_driver_unregister(&dummy_hcd_driver); } diff --git a/drivers/usb/gadget/f_acm.c b/drivers/usb/gadget/f_acm.c index d672250a61fa..549174466c21 100644 --- a/drivers/usb/gadget/f_acm.c +++ b/drivers/usb/gadget/f_acm.c @@ -87,7 +87,7 @@ static inline struct f_acm *port_to_acm(struct gserial *p) /* notification endpoint uses smallish and infrequent fixed-size messages */ -#define GS_LOG2_NOTIFY_INTERVAL 5 /* 1 << 5 == 32 msec */ +#define GS_NOTIFY_INTERVAL_MS 32 #define GS_NOTIFY_MAXPACKET 10 /* notification + 2 bytes */ /* interface and class descriptors: */ @@ -167,7 +167,7 @@ static struct usb_endpoint_descriptor acm_fs_notify_desc = { .bEndpointAddress = USB_DIR_IN, .bmAttributes = USB_ENDPOINT_XFER_INT, .wMaxPacketSize = cpu_to_le16(GS_NOTIFY_MAXPACKET), - .bInterval = 1 << GS_LOG2_NOTIFY_INTERVAL, + .bInterval = GS_NOTIFY_INTERVAL_MS, }; static struct usb_endpoint_descriptor acm_fs_in_desc = { @@ -199,14 +199,13 @@ static struct usb_descriptor_header *acm_fs_function[] = { }; /* high speed support: */ - static struct usb_endpoint_descriptor acm_hs_notify_desc = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, .bEndpointAddress = USB_DIR_IN, .bmAttributes = USB_ENDPOINT_XFER_INT, .wMaxPacketSize = cpu_to_le16(GS_NOTIFY_MAXPACKET), - .bInterval = GS_LOG2_NOTIFY_INTERVAL+4, + .bInterval = USB_MS_TO_HS_INTERVAL(GS_NOTIFY_INTERVAL_MS), }; static struct usb_endpoint_descriptor acm_hs_in_desc = { @@ -659,37 +658,22 @@ 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 */ - f->descriptors = usb_copy_descriptors(acm_fs_function); - if (!f->descriptors) - goto fail; - /* support all relevant hardware speeds... we expect that when * hardware is dual speed, all bulk-capable endpoints work at * both speeds */ - if (gadget_is_dualspeed(c->cdev->gadget)) { - acm_hs_in_desc.bEndpointAddress = - acm_fs_in_desc.bEndpointAddress; - acm_hs_out_desc.bEndpointAddress = - acm_fs_out_desc.bEndpointAddress; - acm_hs_notify_desc.bEndpointAddress = - acm_fs_notify_desc.bEndpointAddress; - - /* copy descriptors */ - f->hs_descriptors = usb_copy_descriptors(acm_hs_function); - } - if (gadget_is_superspeed(c->cdev->gadget)) { - acm_ss_in_desc.bEndpointAddress = - acm_fs_in_desc.bEndpointAddress; - acm_ss_out_desc.bEndpointAddress = - acm_fs_out_desc.bEndpointAddress; - - /* copy descriptors, and track endpoint copies */ - f->ss_descriptors = usb_copy_descriptors(acm_ss_function); - if (!f->ss_descriptors) - goto fail; - } + acm_hs_in_desc.bEndpointAddress = acm_fs_in_desc.bEndpointAddress; + acm_hs_out_desc.bEndpointAddress = acm_fs_out_desc.bEndpointAddress; + acm_hs_notify_desc.bEndpointAddress = + acm_fs_notify_desc.bEndpointAddress; + + acm_ss_in_desc.bEndpointAddress = acm_fs_in_desc.bEndpointAddress; + acm_ss_out_desc.bEndpointAddress = acm_fs_out_desc.bEndpointAddress; + + status = usb_assign_descriptors(f, acm_fs_function, acm_hs_function, + acm_ss_function); + if (status) + goto fail; DBG(cdev, "acm ttyGS%d: %s speed IN/%s OUT/%s NOTIFY/%s\n", acm->port_num, @@ -721,11 +705,8 @@ acm_unbind(struct usb_configuration *c, struct usb_function *f) { struct f_acm *acm = func_to_acm(f); - if (gadget_is_dualspeed(c->cdev->gadget)) - usb_free_descriptors(f->hs_descriptors); - if (gadget_is_superspeed(c->cdev->gadget)) - usb_free_descriptors(f->ss_descriptors); - usb_free_descriptors(f->descriptors); + acm_string_defs[0].id = 0; + usb_free_all_descriptors(f); gs_free_req(acm->notify, acm->notify_req); kfree(acm); } @@ -762,27 +743,15 @@ int acm_bind_config(struct usb_configuration *c, u8 port_num) */ /* maybe allocate device-global string IDs, and patch descriptors */ - if (acm_string_defs[ACM_CTRL_IDX].id == 0) { - status = usb_string_id(c->cdev); + if (acm_string_defs[0].id == 0) { + status = usb_string_ids_tab(c->cdev, acm_string_defs); if (status < 0) return status; - acm_string_defs[ACM_CTRL_IDX].id = status; - - acm_control_interface_desc.iInterface = status; - - status = usb_string_id(c->cdev); - if (status < 0) - return status; - acm_string_defs[ACM_DATA_IDX].id = status; - - acm_data_interface_desc.iInterface = status; - - status = usb_string_id(c->cdev); - if (status < 0) - return status; - acm_string_defs[ACM_IAD_IDX].id = status; - - acm_iad_descriptor.iFunction = status; + acm_control_interface_desc.iInterface = + acm_string_defs[ACM_CTRL_IDX].id; + acm_data_interface_desc.iInterface = + acm_string_defs[ACM_DATA_IDX].id; + acm_iad_descriptor.iFunction = acm_string_defs[ACM_IAD_IDX].id; } /* allocate and initialize one new instance */ diff --git a/drivers/usb/gadget/f_ecm.c b/drivers/usb/gadget/f_ecm.c index 95bc94f8e570..83420a310fb7 100644 --- a/drivers/usb/gadget/f_ecm.c +++ b/drivers/usb/gadget/f_ecm.c @@ -91,7 +91,7 @@ static inline unsigned ecm_bitrate(struct usb_gadget *g) * encapsulated commands (vendor-specific, using control-OUT). */ -#define LOG2_STATUS_INTERVAL_MSEC 5 /* 1 << 5 == 32 msec */ +#define ECM_STATUS_INTERVAL_MS 32 #define ECM_STATUS_BYTECOUNT 16 /* 8 byte header + data */ @@ -192,7 +192,7 @@ static struct usb_endpoint_descriptor fs_ecm_notify_desc = { .bEndpointAddress = USB_DIR_IN, .bmAttributes = USB_ENDPOINT_XFER_INT, .wMaxPacketSize = cpu_to_le16(ECM_STATUS_BYTECOUNT), - .bInterval = 1 << LOG2_STATUS_INTERVAL_MSEC, + .bInterval = ECM_STATUS_INTERVAL_MS, }; static struct usb_endpoint_descriptor fs_ecm_in_desc = { @@ -239,7 +239,7 @@ static struct usb_endpoint_descriptor hs_ecm_notify_desc = { .bEndpointAddress = USB_DIR_IN, .bmAttributes = USB_ENDPOINT_XFER_INT, .wMaxPacketSize = cpu_to_le16(ECM_STATUS_BYTECOUNT), - .bInterval = LOG2_STATUS_INTERVAL_MSEC + 4, + .bInterval = USB_MS_TO_HS_INTERVAL(ECM_STATUS_INTERVAL_MS), }; static struct usb_endpoint_descriptor hs_ecm_in_desc = { @@ -288,7 +288,7 @@ static struct usb_endpoint_descriptor ss_ecm_notify_desc = { .bEndpointAddress = USB_DIR_IN, .bmAttributes = USB_ENDPOINT_XFER_INT, .wMaxPacketSize = cpu_to_le16(ECM_STATUS_BYTECOUNT), - .bInterval = LOG2_STATUS_INTERVAL_MSEC + 4, + .bInterval = USB_MS_TO_HS_INTERVAL(ECM_STATUS_INTERVAL_MS), }; static struct usb_ss_ep_comp_descriptor ss_ecm_intr_comp_desc = { @@ -330,6 +330,7 @@ static struct usb_ss_ep_comp_descriptor ss_ecm_bulk_comp_desc = { static struct usb_descriptor_header *ecm_ss_function[] = { /* CDC ECM control descriptors */ + (struct usb_descriptor_header *) &ecm_iad_descriptor, (struct usb_descriptor_header *) &ecm_control_intf, (struct usb_descriptor_header *) &ecm_header_desc, (struct usb_descriptor_header *) &ecm_union_desc, @@ -353,7 +354,7 @@ static struct usb_descriptor_header *ecm_ss_function[] = { static struct usb_string ecm_string_defs[] = { [0].s = "CDC Ethernet Control Model (ECM)", - [1].s = NULL /* DYNAMIC */, + [1].s = "", [2].s = "CDC Ethernet Data", [3].s = "CDC ECM", { } /* end of list */ @@ -742,42 +743,24 @@ ecm_bind(struct usb_configuration *c, struct usb_function *f) ecm->notify_req->context = ecm; ecm->notify_req->complete = ecm_notify_complete; - /* copy descriptors, and track endpoint copies */ - f->descriptors = usb_copy_descriptors(ecm_fs_function); - if (!f->descriptors) - goto fail; - /* support all relevant hardware speeds... we expect that when * hardware is dual speed, all bulk-capable endpoints work at * both speeds */ - if (gadget_is_dualspeed(c->cdev->gadget)) { - hs_ecm_in_desc.bEndpointAddress = - fs_ecm_in_desc.bEndpointAddress; - hs_ecm_out_desc.bEndpointAddress = - fs_ecm_out_desc.bEndpointAddress; - hs_ecm_notify_desc.bEndpointAddress = - fs_ecm_notify_desc.bEndpointAddress; - - /* copy descriptors, and track endpoint copies */ - f->hs_descriptors = usb_copy_descriptors(ecm_hs_function); - if (!f->hs_descriptors) - goto fail; - } - - 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; - } + hs_ecm_in_desc.bEndpointAddress = fs_ecm_in_desc.bEndpointAddress; + hs_ecm_out_desc.bEndpointAddress = fs_ecm_out_desc.bEndpointAddress; + hs_ecm_notify_desc.bEndpointAddress = + fs_ecm_notify_desc.bEndpointAddress; + + 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; + + status = usb_assign_descriptors(f, ecm_fs_function, ecm_hs_function, + ecm_ss_function); + if (status) + goto fail; /* NOTE: all that is done without knowing or caring about * the network link ... which is unavailable to this code @@ -795,11 +778,6 @@ ecm_bind(struct usb_configuration *c, struct usb_function *f) return 0; 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); usb_ep_free_request(ecm->notify, ecm->notify_req); @@ -808,9 +786,9 @@ fail: /* we might as well release our claims on endpoints */ if (ecm->notify) ecm->notify->driver_data = NULL; - if (ecm->port.out_ep->desc) + if (ecm->port.out_ep) ecm->port.out_ep->driver_data = NULL; - if (ecm->port.in_ep->desc) + if (ecm->port.in_ep) ecm->port.in_ep->driver_data = NULL; ERROR(cdev, "%s: can't bind, err %d\n", f->name, status); @@ -825,16 +803,11 @@ 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); + ecm_string_defs[0].id = 0; + usb_free_all_descriptors(f); kfree(ecm->notify_req->buf); usb_ep_free_request(ecm->notify, ecm->notify_req); - - ecm_string_defs[1].s = NULL; kfree(ecm); } @@ -859,36 +832,15 @@ ecm_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN]) if (!can_support_ecm(c->cdev->gadget) || !ethaddr) return -EINVAL; - /* maybe allocate device-global string IDs */ if (ecm_string_defs[0].id == 0) { - - /* control interface label */ - status = usb_string_id(c->cdev); - if (status < 0) - return status; - ecm_string_defs[0].id = status; - ecm_control_intf.iInterface = status; - - /* data interface label */ - status = usb_string_id(c->cdev); - if (status < 0) + status = usb_string_ids_tab(c->cdev, ecm_string_defs); + if (status) return status; - ecm_string_defs[2].id = status; - ecm_data_intf.iInterface = status; - /* MAC address */ - status = usb_string_id(c->cdev); - if (status < 0) - return status; - ecm_string_defs[1].id = status; - ecm_desc.iMACAddress = status; - - /* IAD label */ - status = usb_string_id(c->cdev); - if (status < 0) - return status; - ecm_string_defs[3].id = status; - ecm_iad_descriptor.iFunction = status; + ecm_control_intf.iInterface = ecm_string_defs[0].id; + ecm_data_intf.iInterface = ecm_string_defs[2].id; + ecm_desc.iMACAddress = ecm_string_defs[1].id; + ecm_iad_descriptor.iFunction = ecm_string_defs[3].id; } /* allocate and initialize one new instance */ @@ -913,9 +865,7 @@ ecm_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN]) ecm->port.func.disable = ecm_disable; status = usb_add_function(c, &ecm->port.func); - if (status) { - ecm_string_defs[1].s = NULL; + if (status) kfree(ecm); - } return status; } diff --git a/drivers/usb/gadget/f_eem.c b/drivers/usb/gadget/f_eem.c index 1a7b2dd7d408..cf0ebee85563 100644 --- a/drivers/usb/gadget/f_eem.c +++ b/drivers/usb/gadget/f_eem.c @@ -274,38 +274,20 @@ eem_bind(struct usb_configuration *c, struct usb_function *f) status = -ENOMEM; - /* copy descriptors, and track endpoint copies */ - f->descriptors = usb_copy_descriptors(eem_fs_function); - if (!f->descriptors) - goto fail; - /* support all relevant hardware speeds... we expect that when * hardware is dual speed, all bulk-capable endpoints work at * both speeds */ - if (gadget_is_dualspeed(c->cdev->gadget)) { - eem_hs_in_desc.bEndpointAddress = - eem_fs_in_desc.bEndpointAddress; - eem_hs_out_desc.bEndpointAddress = - eem_fs_out_desc.bEndpointAddress; - - /* copy descriptors, and track endpoint copies */ - f->hs_descriptors = usb_copy_descriptors(eem_hs_function); - if (!f->hs_descriptors) - goto fail; - } + eem_hs_in_desc.bEndpointAddress = eem_fs_in_desc.bEndpointAddress; + eem_hs_out_desc.bEndpointAddress = eem_fs_out_desc.bEndpointAddress; - 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_ss_in_desc.bEndpointAddress = eem_fs_in_desc.bEndpointAddress; + eem_ss_out_desc.bEndpointAddress = eem_fs_out_desc.bEndpointAddress; - /* copy descriptors, and track endpoint copies */ - f->ss_descriptors = usb_copy_descriptors(eem_ss_function); - if (!f->ss_descriptors) - goto fail; - } + status = usb_assign_descriptors(f, eem_fs_function, eem_hs_function, + eem_ss_function); + if (status) + goto fail; DBG(cdev, "CDC Ethernet (EEM): %s speed IN/%s OUT/%s\n", gadget_is_superspeed(c->cdev->gadget) ? "super" : @@ -314,15 +296,10 @@ eem_bind(struct usb_configuration *c, struct usb_function *f) 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 (eem->port.out_ep->desc) + usb_free_all_descriptors(f); + if (eem->port.out_ep) eem->port.out_ep->driver_data = NULL; - if (eem->port.in_ep->desc) + if (eem->port.in_ep) eem->port.in_ep->driver_data = NULL; ERROR(cdev, "%s: can't bind, err %d\n", f->name, status); @@ -337,11 +314,7 @@ 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); + usb_free_all_descriptors(f); kfree(eem); } diff --git a/drivers/usb/gadget/f_fs.c b/drivers/usb/gadget/f_fs.c index 64c4ec10d1fc..4a6961c517f2 100644 --- a/drivers/usb/gadget/f_fs.c +++ b/drivers/usb/gadget/f_fs.c @@ -2097,7 +2097,7 @@ static int __ffs_func_bind_do_descs(enum ffs_entity_type type, u8 *valuep, if (isHS) func->function.hs_descriptors[(long)valuep] = desc; else - func->function.descriptors[(long)valuep] = desc; + func->function.fs_descriptors[(long)valuep] = desc; if (!desc || desc->bDescriptorType != USB_DT_ENDPOINT) return 0; @@ -2249,7 +2249,7 @@ static int ffs_func_bind(struct usb_configuration *c, * numbers without worrying that it may be described later on. */ if (likely(full)) { - func->function.descriptors = data->fs_descs; + func->function.fs_descriptors = data->fs_descs; ret = ffs_do_descs(ffs->fs_descs_count, data->raw_descs, sizeof data->raw_descs, diff --git a/drivers/usb/gadget/f_hid.c b/drivers/usb/gadget/f_hid.c index 511e527178e2..6e69a8e8d22a 100644 --- a/drivers/usb/gadget/f_hid.c +++ b/drivers/usb/gadget/f_hid.c @@ -573,7 +573,6 @@ static int __init hidg_bind(struct usb_configuration *c, struct usb_function *f) goto fail; hidg_interface_desc.bInterfaceNumber = status; - /* allocate instance-specific endpoints */ status = -ENODEV; ep = usb_ep_autoconfig(c->cdev->gadget, &hidg_fs_in_ep_desc); @@ -609,20 +608,15 @@ static int __init hidg_bind(struct usb_configuration *c, struct usb_function *f) hidg_desc.desc[0].wDescriptorLength = cpu_to_le16(hidg->report_desc_length); - /* copy descriptors */ - f->descriptors = usb_copy_descriptors(hidg_fs_descriptors); - if (!f->descriptors) - goto fail; + hidg_hs_in_ep_desc.bEndpointAddress = + hidg_fs_in_ep_desc.bEndpointAddress; + hidg_hs_out_ep_desc.bEndpointAddress = + hidg_fs_out_ep_desc.bEndpointAddress; - if (gadget_is_dualspeed(c->cdev->gadget)) { - hidg_hs_in_ep_desc.bEndpointAddress = - hidg_fs_in_ep_desc.bEndpointAddress; - hidg_hs_out_ep_desc.bEndpointAddress = - hidg_fs_out_ep_desc.bEndpointAddress; - f->hs_descriptors = usb_copy_descriptors(hidg_hs_descriptors); - if (!f->hs_descriptors) - goto fail; - } + status = usb_assign_descriptors(f, hidg_fs_descriptors, + hidg_hs_descriptors, NULL); + if (status) + goto fail; mutex_init(&hidg->lock); spin_lock_init(&hidg->spinlock); @@ -649,9 +643,7 @@ fail: usb_ep_free_request(hidg->in_ep, hidg->req); } - usb_free_descriptors(f->hs_descriptors); - usb_free_descriptors(f->descriptors); - + usb_free_all_descriptors(f); return status; } @@ -668,9 +660,7 @@ static void hidg_unbind(struct usb_configuration *c, struct usb_function *f) kfree(hidg->req->buf); usb_ep_free_request(hidg->in_ep, hidg->req); - /* free descriptors copies */ - usb_free_descriptors(f->hs_descriptors); - usb_free_descriptors(f->descriptors); + usb_free_all_descriptors(f); kfree(hidg->report_desc); kfree(hidg); diff --git a/drivers/usb/gadget/f_loopback.c b/drivers/usb/gadget/f_loopback.c index 7275706caeb0..bb39cb2bb3a3 100644 --- a/drivers/usb/gadget/f_loopback.c +++ b/drivers/usb/gadget/f_loopback.c @@ -177,6 +177,7 @@ loopback_bind(struct usb_configuration *c, struct usb_function *f) struct usb_composite_dev *cdev = c->cdev; struct f_loopback *loop = func_to_loop(f); int id; + int ret; /* allocate interface ID(s) */ id = usb_interface_id(c, f); @@ -201,22 +202,19 @@ autoconf_fail: loop->out_ep->driver_data = cdev; /* claim */ /* support high speed hardware */ - if (gadget_is_dualspeed(c->cdev->gadget)) { - hs_loop_source_desc.bEndpointAddress = - fs_loop_source_desc.bEndpointAddress; - hs_loop_sink_desc.bEndpointAddress = - fs_loop_sink_desc.bEndpointAddress; - f->hs_descriptors = hs_loopback_descs; - } + hs_loop_source_desc.bEndpointAddress = + fs_loop_source_desc.bEndpointAddress; + hs_loop_sink_desc.bEndpointAddress = fs_loop_sink_desc.bEndpointAddress; /* 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; - } + ss_loop_source_desc.bEndpointAddress = + fs_loop_source_desc.bEndpointAddress; + ss_loop_sink_desc.bEndpointAddress = fs_loop_sink_desc.bEndpointAddress; + + ret = usb_assign_descriptors(f, fs_loopback_descs, hs_loopback_descs, + ss_loopback_descs); + if (ret) + return ret; DBG(cdev, "%s speed %s: IN/%s, OUT/%s\n", (gadget_is_superspeed(c->cdev->gadget) ? "super" : @@ -228,6 +226,7 @@ autoconf_fail: static void loopback_unbind(struct usb_configuration *c, struct usb_function *f) { + usb_free_all_descriptors(f); kfree(func_to_loop(f)); } @@ -379,7 +378,6 @@ static int __init loopback_bind_config(struct usb_configuration *c) return -ENOMEM; loop->function.name = "loopback"; - loop->function.descriptors = fs_loopback_descs; loop->function.bind = loopback_bind; loop->function.unbind = loopback_unbind; loop->function.set_alt = loopback_set_alt; diff --git a/drivers/usb/gadget/f_mass_storage.c b/drivers/usb/gadget/f_mass_storage.c index 3a7668bde3ef..5d027b3e1ef0 100644 --- a/drivers/usb/gadget/f_mass_storage.c +++ b/drivers/usb/gadget/f_mass_storage.c @@ -228,10 +228,6 @@ static const char fsg_string_interface[] = "Mass Storage"; -#define FSG_NO_DEVICE_STRINGS 1 -#define FSG_NO_OTG 1 -#define FSG_NO_INTR_EP 1 - #include "storage_common.c" @@ -2904,9 +2900,7 @@ static void fsg_unbind(struct usb_configuration *c, struct usb_function *f) } fsg_common_put(common); - usb_free_descriptors(fsg->function.descriptors); - usb_free_descriptors(fsg->function.hs_descriptors); - usb_free_descriptors(fsg->function.ss_descriptors); + usb_free_all_descriptors(&fsg->function); kfree(fsg); } @@ -2916,6 +2910,8 @@ static int fsg_bind(struct usb_configuration *c, struct usb_function *f) struct usb_gadget *gadget = c->cdev->gadget; int i; struct usb_ep *ep; + unsigned max_burst; + int ret; fsg->gadget = gadget; @@ -2939,45 +2935,27 @@ static int fsg_bind(struct usb_configuration *c, struct usb_function *f) ep->driver_data = fsg->common; /* claim the endpoint */ fsg->bulk_out = ep; - /* Copy descriptors */ - f->descriptors = usb_copy_descriptors(fsg_fs_function); - if (unlikely(!f->descriptors)) - return -ENOMEM; - - if (gadget_is_dualspeed(gadget)) { - /* Assume endpoint addresses are the same for both speeds */ - fsg_hs_bulk_in_desc.bEndpointAddress = - fsg_fs_bulk_in_desc.bEndpointAddress; - fsg_hs_bulk_out_desc.bEndpointAddress = - fsg_fs_bulk_out_desc.bEndpointAddress; - f->hs_descriptors = usb_copy_descriptors(fsg_hs_function); - if (unlikely(!f->hs_descriptors)) { - usb_free_descriptors(f->descriptors); - return -ENOMEM; - } - } - - if (gadget_is_superspeed(gadget)) { - unsigned max_burst; + /* Assume endpoint addresses are the same for both speeds */ + fsg_hs_bulk_in_desc.bEndpointAddress = + fsg_fs_bulk_in_desc.bEndpointAddress; + fsg_hs_bulk_out_desc.bEndpointAddress = + fsg_fs_bulk_out_desc.bEndpointAddress; - /* Calculate bMaxBurst, we know packet size is 1024 */ - max_burst = min_t(unsigned, FSG_BUFLEN / 1024, 15); + /* Calculate bMaxBurst, we know packet size is 1024 */ + max_burst = min_t(unsigned, FSG_BUFLEN / 1024, 15); - fsg_ss_bulk_in_desc.bEndpointAddress = - fsg_fs_bulk_in_desc.bEndpointAddress; - fsg_ss_bulk_in_comp_desc.bMaxBurst = max_burst; + fsg_ss_bulk_in_desc.bEndpointAddress = + fsg_fs_bulk_in_desc.bEndpointAddress; + fsg_ss_bulk_in_comp_desc.bMaxBurst = max_burst; - fsg_ss_bulk_out_desc.bEndpointAddress = - fsg_fs_bulk_out_desc.bEndpointAddress; - fsg_ss_bulk_out_comp_desc.bMaxBurst = max_burst; + fsg_ss_bulk_out_desc.bEndpointAddress = + fsg_fs_bulk_out_desc.bEndpointAddress; + fsg_ss_bulk_out_comp_desc.bMaxBurst = max_burst; - f->ss_descriptors = usb_copy_descriptors(fsg_ss_function); - if (unlikely(!f->ss_descriptors)) { - usb_free_descriptors(f->hs_descriptors); - usb_free_descriptors(f->descriptors); - return -ENOMEM; - } - } + ret = usb_assign_descriptors(f, fsg_fs_function, fsg_hs_function, + fsg_ss_function); + if (ret) + goto autoconf_fail; return 0; @@ -2986,7 +2964,6 @@ autoconf_fail: return -ENOTSUPP; } - /****************************** ADD FUNCTION ******************************/ static struct usb_gadget_strings *fsg_strings_array[] = { diff --git a/drivers/usb/gadget/f_midi.c b/drivers/usb/gadget/f_midi.c index 8ed1259fe80d..263e721c2694 100644 --- a/drivers/usb/gadget/f_midi.c +++ b/drivers/usb/gadget/f_midi.c @@ -414,7 +414,7 @@ static void f_midi_unbind(struct usb_configuration *c, struct usb_function *f) kfree(midi->id); midi->id = NULL; - usb_free_descriptors(f->descriptors); + usb_free_all_descriptors(f); kfree(midi); } @@ -881,19 +881,25 @@ f_midi_bind(struct usb_configuration *c, struct usb_function *f) * both speeds */ /* copy descriptors, and track endpoint copies */ + f->fs_descriptors = usb_copy_descriptors(midi_function); + if (!f->fs_descriptors) + goto fail_f_midi; + if (gadget_is_dualspeed(c->cdev->gadget)) { - c->highspeed = true; bulk_in_desc.wMaxPacketSize = cpu_to_le16(512); bulk_out_desc.wMaxPacketSize = cpu_to_le16(512); f->hs_descriptors = usb_copy_descriptors(midi_function); - } else { - f->descriptors = usb_copy_descriptors(midi_function); + if (!f->hs_descriptors) + goto fail_f_midi; } kfree(midi_function); return 0; +fail_f_midi: + kfree(midi_function); + usb_free_descriptors(f->hs_descriptors); fail: /* we might as well release our claims on endpoints */ if (midi->out_ep) diff --git a/drivers/usb/gadget/f_ncm.c b/drivers/usb/gadget/f_ncm.c index b651b529c67f..6c8362f937be 100644 --- a/drivers/usb/gadget/f_ncm.c +++ b/drivers/usb/gadget/f_ncm.c @@ -102,7 +102,7 @@ static inline unsigned ncm_bitrate(struct usb_gadget *g) USB_CDC_NCM_NTB32_SUPPORTED) static struct usb_cdc_ncm_ntb_parameters ntb_parameters = { - .wLength = sizeof ntb_parameters, + .wLength = cpu_to_le16(sizeof(ntb_parameters)), .bmNtbFormatsSupported = cpu_to_le16(FORMATS_SUPPORTED), .dwNtbInMaxSize = cpu_to_le32(NTB_DEFAULT_IN_SIZE), .wNdpInDivisor = cpu_to_le16(4), @@ -121,7 +121,7 @@ static struct usb_cdc_ncm_ntb_parameters ntb_parameters = { * waste less bandwidth. */ -#define LOG2_STATUS_INTERVAL_MSEC 5 /* 1 << 5 == 32 msec */ +#define NCM_STATUS_INTERVAL_MS 32 #define NCM_STATUS_BYTECOUNT 16 /* 8 byte header + data */ static struct usb_interface_assoc_descriptor ncm_iad_desc __initdata = { @@ -230,7 +230,7 @@ static struct usb_endpoint_descriptor fs_ncm_notify_desc __initdata = { .bEndpointAddress = USB_DIR_IN, .bmAttributes = USB_ENDPOINT_XFER_INT, .wMaxPacketSize = cpu_to_le16(NCM_STATUS_BYTECOUNT), - .bInterval = 1 << LOG2_STATUS_INTERVAL_MSEC, + .bInterval = NCM_STATUS_INTERVAL_MS, }; static struct usb_endpoint_descriptor fs_ncm_in_desc __initdata = { @@ -275,7 +275,7 @@ static struct usb_endpoint_descriptor hs_ncm_notify_desc __initdata = { .bEndpointAddress = USB_DIR_IN, .bmAttributes = USB_ENDPOINT_XFER_INT, .wMaxPacketSize = cpu_to_le16(NCM_STATUS_BYTECOUNT), - .bInterval = LOG2_STATUS_INTERVAL_MSEC + 4, + .bInterval = USB_MS_TO_HS_INTERVAL(NCM_STATUS_INTERVAL_MS), }; static struct usb_endpoint_descriptor hs_ncm_in_desc __initdata = { .bLength = USB_DT_ENDPOINT_SIZE, @@ -321,7 +321,7 @@ static struct usb_descriptor_header *ncm_hs_function[] __initdata = { static struct usb_string ncm_string_defs[] = { [STRING_CTRL_IDX].s = "CDC Network Control Model (NCM)", - [STRING_MAC_IDX].s = NULL /* DYNAMIC */, + [STRING_MAC_IDX].s = "", [STRING_DATA_IDX].s = "CDC Network Data", [STRING_IAD_IDX].s = "CDC NCM", { } /* end of list */ @@ -869,15 +869,19 @@ static struct sk_buff *ncm_wrap_ntb(struct gether *port, struct sk_buff *skb2; int ncb_len = 0; __le16 *tmp; - int div = ntb_parameters.wNdpInDivisor; - int rem = ntb_parameters.wNdpInPayloadRemainder; + int div; + int rem; int pad; - int ndp_align = ntb_parameters.wNdpInAlignment; + int ndp_align; int ndp_pad; unsigned max_size = ncm->port.fixed_in_len; struct ndp_parser_opts *opts = ncm->parser_opts; unsigned crc_len = ncm->is_crc ? sizeof(uint32_t) : 0; + div = le16_to_cpu(ntb_parameters.wNdpInDivisor); + rem = le16_to_cpu(ntb_parameters.wNdpInPayloadRemainder); + ndp_align = le16_to_cpu(ntb_parameters.wNdpInAlignment); + ncb_len += opts->nth_size; ndp_pad = ALIGN(ncb_len, ndp_align) - ncb_len; ncb_len += ndp_pad; @@ -1208,30 +1212,18 @@ ncm_bind(struct usb_configuration *c, struct usb_function *f) ncm->notify_req->context = ncm; ncm->notify_req->complete = ncm_notify_complete; - /* copy descriptors, and track endpoint copies */ - f->descriptors = usb_copy_descriptors(ncm_fs_function); - if (!f->descriptors) - goto fail; - /* * support all relevant hardware speeds... we expect that when * hardware is dual speed, all bulk-capable endpoints work at * both speeds */ - if (gadget_is_dualspeed(c->cdev->gadget)) { - hs_ncm_in_desc.bEndpointAddress = - fs_ncm_in_desc.bEndpointAddress; - hs_ncm_out_desc.bEndpointAddress = - fs_ncm_out_desc.bEndpointAddress; - hs_ncm_notify_desc.bEndpointAddress = - fs_ncm_notify_desc.bEndpointAddress; - - /* copy descriptors, and track endpoint copies */ - f->hs_descriptors = usb_copy_descriptors(ncm_hs_function); - if (!f->hs_descriptors) - goto fail; - } + hs_ncm_in_desc.bEndpointAddress = fs_ncm_in_desc.bEndpointAddress; + hs_ncm_out_desc.bEndpointAddress = fs_ncm_out_desc.bEndpointAddress; + hs_ncm_notify_desc.bEndpointAddress = + fs_ncm_notify_desc.bEndpointAddress; + status = usb_assign_descriptors(f, ncm_fs_function, ncm_hs_function, + NULL); /* * NOTE: all that is done without knowing or caring about * the network link ... which is unavailable to this code @@ -1248,9 +1240,7 @@ ncm_bind(struct usb_configuration *c, struct usb_function *f) return 0; fail: - if (f->descriptors) - usb_free_descriptors(f->descriptors); - + usb_free_all_descriptors(f); if (ncm->notify_req) { kfree(ncm->notify_req->buf); usb_ep_free_request(ncm->notify, ncm->notify_req); @@ -1259,9 +1249,9 @@ fail: /* we might as well release our claims on endpoints */ if (ncm->notify) ncm->notify->driver_data = NULL; - if (ncm->port.out_ep->desc) + if (ncm->port.out_ep) ncm->port.out_ep->driver_data = NULL; - if (ncm->port.in_ep->desc) + if (ncm->port.in_ep) ncm->port.in_ep->driver_data = NULL; ERROR(cdev, "%s: can't bind, err %d\n", f->name, status); @@ -1276,14 +1266,12 @@ ncm_unbind(struct usb_configuration *c, struct usb_function *f) DBG(c->cdev, "ncm unbind\n"); - if (gadget_is_dualspeed(c->cdev->gadget)) - usb_free_descriptors(f->hs_descriptors); - usb_free_descriptors(f->descriptors); + ncm_string_defs[0].id = 0; + usb_free_all_descriptors(f); kfree(ncm->notify_req->buf); usb_ep_free_request(ncm->notify, ncm->notify_req); - ncm_string_defs[1].s = NULL; kfree(ncm); } @@ -1307,37 +1295,19 @@ int __init ncm_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN]) if (!can_support_ecm(c->cdev->gadget) || !ethaddr) return -EINVAL; - /* maybe allocate device-global string IDs */ if (ncm_string_defs[0].id == 0) { - - /* control interface label */ - status = usb_string_id(c->cdev); + status = usb_string_ids_tab(c->cdev, ncm_string_defs); if (status < 0) return status; - ncm_string_defs[STRING_CTRL_IDX].id = status; - ncm_control_intf.iInterface = status; + ncm_control_intf.iInterface = + ncm_string_defs[STRING_CTRL_IDX].id; - /* data interface label */ - status = usb_string_id(c->cdev); - if (status < 0) - return status; - ncm_string_defs[STRING_DATA_IDX].id = status; + status = ncm_string_defs[STRING_DATA_IDX].id; ncm_data_nop_intf.iInterface = status; ncm_data_intf.iInterface = status; - /* MAC address */ - status = usb_string_id(c->cdev); - if (status < 0) - return status; - ncm_string_defs[STRING_MAC_IDX].id = status; - ecm_desc.iMACAddress = status; - - /* IAD */ - status = usb_string_id(c->cdev); - if (status < 0) - return status; - ncm_string_defs[STRING_IAD_IDX].id = status; - ncm_iad_desc.iFunction = status; + ecm_desc.iMACAddress = ncm_string_defs[STRING_MAC_IDX].id; + ncm_iad_desc.iFunction = ncm_string_defs[STRING_IAD_IDX].id; } /* allocate and initialize one new instance */ @@ -1347,7 +1317,7 @@ int __init ncm_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN]) /* export host's Ethernet address in CDC format */ snprintf(ncm->ethaddr, sizeof ncm->ethaddr, "%pm", ethaddr); - ncm_string_defs[1].s = ncm->ethaddr; + ncm_string_defs[STRING_MAC_IDX].s = ncm->ethaddr; spin_lock_init(&ncm->lock); ncm_reset_values(ncm); @@ -1367,9 +1337,7 @@ int __init ncm_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN]) ncm->port.unwrap = ncm_unwrap_ntb; status = usb_add_function(c, &ncm->port.func); - if (status) { - ncm_string_defs[1].s = NULL; + if (status) kfree(ncm); - } return status; } diff --git a/drivers/usb/gadget/f_obex.c b/drivers/usb/gadget/f_obex.c index 5f400f66aa9b..d8dd8782768c 100644 --- a/drivers/usb/gadget/f_obex.c +++ b/drivers/usb/gadget/f_obex.c @@ -331,23 +331,19 @@ obex_bind(struct usb_configuration *c, struct usb_function *f) obex->port.out = ep; ep->driver_data = cdev; /* claim */ - /* copy descriptors, and track endpoint copies */ - f->descriptors = usb_copy_descriptors(fs_function); - /* support all relevant hardware speeds... we expect that when * hardware is dual speed, all bulk-capable endpoints work at * both speeds */ - if (gadget_is_dualspeed(c->cdev->gadget)) { - obex_hs_ep_in_desc.bEndpointAddress = - obex_fs_ep_in_desc.bEndpointAddress; - obex_hs_ep_out_desc.bEndpointAddress = - obex_fs_ep_out_desc.bEndpointAddress; + obex_hs_ep_in_desc.bEndpointAddress = + obex_fs_ep_in_desc.bEndpointAddress; + obex_hs_ep_out_desc.bEndpointAddress = + obex_fs_ep_out_desc.bEndpointAddress; - /* copy descriptors, and track endpoint copies */ - f->hs_descriptors = usb_copy_descriptors(hs_function); - } + status = usb_assign_descriptors(f, fs_function, hs_function, NULL); + if (status) + goto fail; /* Avoid letting this gadget enumerate until the userspace * OBEX server is active. @@ -368,6 +364,7 @@ obex_bind(struct usb_configuration *c, struct usb_function *f) return 0; fail: + usb_free_all_descriptors(f); /* we might as well release our claims on endpoints */ if (obex->port.out) obex->port.out->driver_data = NULL; @@ -382,9 +379,8 @@ fail: static void obex_unbind(struct usb_configuration *c, struct usb_function *f) { - if (gadget_is_dualspeed(c->cdev->gadget)) - usb_free_descriptors(f->hs_descriptors); - usb_free_descriptors(f->descriptors); + obex_string_defs[OBEX_CTRL_IDX].id = 0; + usb_free_all_descriptors(f); kfree(func_to_obex(f)); } @@ -423,22 +419,16 @@ int __init obex_bind_config(struct usb_configuration *c, u8 port_num) if (!can_support_obex(c)) return -EINVAL; - /* maybe allocate device-global string IDs, and patch descriptors */ if (obex_string_defs[OBEX_CTRL_IDX].id == 0) { - status = usb_string_id(c->cdev); - if (status < 0) - return status; - obex_string_defs[OBEX_CTRL_IDX].id = status; - - obex_control_intf.iInterface = status; - - status = usb_string_id(c->cdev); + status = usb_string_ids_tab(c->cdev, obex_string_defs); if (status < 0) return status; - obex_string_defs[OBEX_DATA_IDX].id = status; + obex_control_intf.iInterface = + obex_string_defs[OBEX_CTRL_IDX].id; - obex_data_nop_intf.iInterface = - obex_data_intf.iInterface = status; + status = obex_string_defs[OBEX_DATA_IDX].id; + obex_data_nop_intf.iInterface = status; + obex_data_intf.iInterface = status; } /* allocate and initialize one new instance */ diff --git a/drivers/usb/gadget/f_phonet.c b/drivers/usb/gadget/f_phonet.c index 8ee9268fe253..b21ab558b6c0 100644 --- a/drivers/usb/gadget/f_phonet.c +++ b/drivers/usb/gadget/f_phonet.c @@ -515,14 +515,14 @@ int pn_bind(struct usb_configuration *c, struct usb_function *f) fp->in_ep = ep; ep->driver_data = fp; /* Claim */ - pn_hs_sink_desc.bEndpointAddress = - pn_fs_sink_desc.bEndpointAddress; - pn_hs_source_desc.bEndpointAddress = - pn_fs_source_desc.bEndpointAddress; + pn_hs_sink_desc.bEndpointAddress = pn_fs_sink_desc.bEndpointAddress; + pn_hs_source_desc.bEndpointAddress = pn_fs_source_desc.bEndpointAddress; /* Do not try to bind Phonet twice... */ - fp->function.descriptors = fs_pn_function; - fp->function.hs_descriptors = hs_pn_function; + status = usb_assign_descriptors(f, fs_pn_function, hs_pn_function, + NULL); + if (status) + goto err; /* Incoming USB requests */ status = -ENOMEM; @@ -531,7 +531,7 @@ int pn_bind(struct usb_configuration *c, struct usb_function *f) req = usb_ep_alloc_request(fp->out_ep, GFP_KERNEL); if (!req) - goto err; + goto err_req; req->complete = pn_rx_complete; fp->out_reqv[i] = req; @@ -540,14 +540,18 @@ int pn_bind(struct usb_configuration *c, struct usb_function *f) /* Outgoing USB requests */ fp->in_req = usb_ep_alloc_request(fp->in_ep, GFP_KERNEL); if (!fp->in_req) - goto err; + goto err_req; INFO(cdev, "USB CDC Phonet function\n"); INFO(cdev, "using %s, OUT %s, IN %s\n", cdev->gadget->name, fp->out_ep->name, fp->in_ep->name); return 0; +err_req: + for (i = 0; i < phonet_rxq_size && fp->out_reqv[i]; i++) + usb_ep_free_request(fp->out_ep, fp->out_reqv[i]); err: + usb_free_all_descriptors(f); if (fp->out_ep) fp->out_ep->driver_data = NULL; if (fp->in_ep) @@ -569,6 +573,7 @@ pn_unbind(struct usb_configuration *c, struct usb_function *f) if (fp->out_reqv[i]) usb_ep_free_request(fp->out_ep, fp->out_reqv[i]); + usb_free_all_descriptors(f); kfree(fp); } diff --git a/drivers/usb/gadget/f_rndis.c b/drivers/usb/gadget/f_rndis.c index b1681e45aca7..71beeb833558 100644 --- a/drivers/usb/gadget/f_rndis.c +++ b/drivers/usb/gadget/f_rndis.c @@ -101,7 +101,7 @@ static unsigned int bitrate(struct usb_gadget *g) /* */ -#define LOG2_STATUS_INTERVAL_MSEC 5 /* 1 << 5 == 32 msec */ +#define RNDIS_STATUS_INTERVAL_MS 32 #define STATUS_BYTECOUNT 8 /* 8 bytes data */ @@ -190,7 +190,7 @@ static struct usb_endpoint_descriptor fs_notify_desc = { .bEndpointAddress = USB_DIR_IN, .bmAttributes = USB_ENDPOINT_XFER_INT, .wMaxPacketSize = cpu_to_le16(STATUS_BYTECOUNT), - .bInterval = 1 << LOG2_STATUS_INTERVAL_MSEC, + .bInterval = RNDIS_STATUS_INTERVAL_MS, }; static struct usb_endpoint_descriptor fs_in_desc = { @@ -236,7 +236,7 @@ static struct usb_endpoint_descriptor hs_notify_desc = { .bEndpointAddress = USB_DIR_IN, .bmAttributes = USB_ENDPOINT_XFER_INT, .wMaxPacketSize = cpu_to_le16(STATUS_BYTECOUNT), - .bInterval = LOG2_STATUS_INTERVAL_MSEC + 4, + .bInterval = USB_MS_TO_HS_INTERVAL(RNDIS_STATUS_INTERVAL_MS) }; static struct usb_endpoint_descriptor hs_in_desc = { @@ -284,7 +284,7 @@ static struct usb_endpoint_descriptor ss_notify_desc = { .bEndpointAddress = USB_DIR_IN, .bmAttributes = USB_ENDPOINT_XFER_INT, .wMaxPacketSize = cpu_to_le16(STATUS_BYTECOUNT), - .bInterval = LOG2_STATUS_INTERVAL_MSEC + 4, + .bInterval = USB_MS_TO_HS_INTERVAL(RNDIS_STATUS_INTERVAL_MS) }; static struct usb_ss_ep_comp_descriptor ss_intr_comp_desc = { @@ -722,42 +722,22 @@ rndis_bind(struct usb_configuration *c, struct usb_function *f) rndis->notify_req->context = rndis; rndis->notify_req->complete = rndis_response_complete; - /* copy descriptors, and track endpoint copies */ - f->descriptors = usb_copy_descriptors(eth_fs_function); - if (!f->descriptors) - goto fail; - /* support all relevant hardware speeds... we expect that when * hardware is dual speed, all bulk-capable endpoints work at * both speeds */ - if (gadget_is_dualspeed(c->cdev->gadget)) { - hs_in_desc.bEndpointAddress = - fs_in_desc.bEndpointAddress; - hs_out_desc.bEndpointAddress = - fs_out_desc.bEndpointAddress; - hs_notify_desc.bEndpointAddress = - fs_notify_desc.bEndpointAddress; - - /* copy descriptors, and track endpoint copies */ - f->hs_descriptors = usb_copy_descriptors(eth_hs_function); - if (!f->hs_descriptors) - goto fail; - } + hs_in_desc.bEndpointAddress = fs_in_desc.bEndpointAddress; + hs_out_desc.bEndpointAddress = fs_out_desc.bEndpointAddress; + hs_notify_desc.bEndpointAddress = fs_notify_desc.bEndpointAddress; - 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; - } + ss_in_desc.bEndpointAddress = fs_in_desc.bEndpointAddress; + ss_out_desc.bEndpointAddress = fs_out_desc.bEndpointAddress; + ss_notify_desc.bEndpointAddress = fs_notify_desc.bEndpointAddress; + + status = usb_assign_descriptors(f, eth_fs_function, eth_hs_function, + eth_ss_function); + if (status) + goto fail; rndis->port.open = rndis_open; rndis->port.close = rndis_close; @@ -788,12 +768,7 @@ rndis_bind(struct usb_configuration *c, struct usb_function *f) 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) - usb_free_descriptors(f->descriptors); + usb_free_all_descriptors(f); if (rndis->notify_req) { kfree(rndis->notify_req->buf); @@ -803,9 +778,9 @@ fail: /* we might as well release our claims on endpoints */ if (rndis->notify) rndis->notify->driver_data = NULL; - if (rndis->port.out_ep->desc) + if (rndis->port.out_ep) rndis->port.out_ep->driver_data = NULL; - if (rndis->port.in_ep->desc) + if (rndis->port.in_ep) rndis->port.in_ep->driver_data = NULL; ERROR(cdev, "%s: can't bind, err %d\n", f->name, status); @@ -820,13 +795,9 @@ rndis_unbind(struct usb_configuration *c, struct usb_function *f) rndis_deregister(rndis->config); rndis_exit(); - rndis_string_defs[0].id = 0; - 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); + rndis_string_defs[0].id = 0; + usb_free_all_descriptors(f); kfree(rndis->notify_req->buf); usb_ep_free_request(rndis->notify, rndis->notify_req); @@ -851,34 +822,19 @@ rndis_bind_config_vendor(struct usb_configuration *c, u8 ethaddr[ETH_ALEN], if (!can_support_rndis(c) || !ethaddr) return -EINVAL; - /* maybe allocate device-global string IDs */ if (rndis_string_defs[0].id == 0) { - /* ... and setup RNDIS itself */ status = rndis_init(); if (status < 0) return status; - /* control interface label */ - status = usb_string_id(c->cdev); - if (status < 0) + status = usb_string_ids_tab(c->cdev, rndis_string_defs); + if (status) return status; - rndis_string_defs[0].id = status; - rndis_control_intf.iInterface = status; - /* data interface label */ - status = usb_string_id(c->cdev); - if (status < 0) - return status; - rndis_string_defs[1].id = status; - rndis_data_intf.iInterface = status; - - /* IAD iFunction label */ - status = usb_string_id(c->cdev); - if (status < 0) - return status; - rndis_string_defs[2].id = status; - rndis_iad_descriptor.iFunction = status; + rndis_control_intf.iInterface = rndis_string_defs[0].id; + rndis_data_intf.iInterface = rndis_string_defs[1].id; + rndis_iad_descriptor.iFunction = rndis_string_defs[2].id; } /* allocate and initialize one new instance */ diff --git a/drivers/usb/gadget/f_serial.c b/drivers/usb/gadget/f_serial.c index 07197d63d9b1..98fa7795df5f 100644 --- a/drivers/usb/gadget/f_serial.c +++ b/drivers/usb/gadget/f_serial.c @@ -213,34 +213,20 @@ gser_bind(struct usb_configuration *c, struct usb_function *f) gser->port.out = ep; ep->driver_data = cdev; /* claim */ - /* copy descriptors, and track endpoint copies */ - f->descriptors = usb_copy_descriptors(gser_fs_function); - /* support all relevant hardware speeds... we expect that when * hardware is dual speed, all bulk-capable endpoints work at * both speeds */ - if (gadget_is_dualspeed(c->cdev->gadget)) { - gser_hs_in_desc.bEndpointAddress = - gser_fs_in_desc.bEndpointAddress; - gser_hs_out_desc.bEndpointAddress = - gser_fs_out_desc.bEndpointAddress; - - /* copy descriptors, and track endpoint copies */ - f->hs_descriptors = usb_copy_descriptors(gser_hs_function); - } - if (gadget_is_superspeed(c->cdev->gadget)) { - gser_ss_in_desc.bEndpointAddress = - gser_fs_in_desc.bEndpointAddress; - gser_ss_out_desc.bEndpointAddress = - gser_fs_out_desc.bEndpointAddress; - - /* copy descriptors, and track endpoint copies */ - f->ss_descriptors = usb_copy_descriptors(gser_ss_function); - if (!f->ss_descriptors) - goto fail; - } + gser_hs_in_desc.bEndpointAddress = gser_fs_in_desc.bEndpointAddress; + gser_hs_out_desc.bEndpointAddress = gser_fs_out_desc.bEndpointAddress; + gser_ss_in_desc.bEndpointAddress = gser_fs_in_desc.bEndpointAddress; + gser_ss_out_desc.bEndpointAddress = gser_fs_out_desc.bEndpointAddress; + + status = usb_assign_descriptors(f, gser_fs_function, gser_hs_function, + gser_ss_function); + if (status) + goto fail; DBG(cdev, "generic ttyGS%d: %s speed IN/%s OUT/%s\n", gser->port_num, gadget_is_superspeed(c->cdev->gadget) ? "super" : @@ -263,11 +249,7 @@ fail: static void gser_unbind(struct usb_configuration *c, struct usb_function *f) { - if (gadget_is_dualspeed(c->cdev->gadget)) - usb_free_descriptors(f->hs_descriptors); - if (gadget_is_superspeed(c->cdev->gadget)) - usb_free_descriptors(f->ss_descriptors); - usb_free_descriptors(f->descriptors); + usb_free_all_descriptors(f); kfree(func_to_gser(f)); } diff --git a/drivers/usb/gadget/f_sourcesink.c b/drivers/usb/gadget/f_sourcesink.c index 3c126fde6e7e..102d49beb9df 100644 --- a/drivers/usb/gadget/f_sourcesink.c +++ b/drivers/usb/gadget/f_sourcesink.c @@ -319,6 +319,7 @@ sourcesink_bind(struct usb_configuration *c, struct usb_function *f) struct usb_composite_dev *cdev = c->cdev; struct f_sourcesink *ss = func_to_ss(f); int id; + int ret; /* allocate interface ID(s) */ id = usb_interface_id(c, f); @@ -387,64 +388,57 @@ no_iso: isoc_maxpacket = 1024; /* support high speed hardware */ - if (gadget_is_dualspeed(c->cdev->gadget)) { - hs_source_desc.bEndpointAddress = - fs_source_desc.bEndpointAddress; - hs_sink_desc.bEndpointAddress = - fs_sink_desc.bEndpointAddress; + hs_source_desc.bEndpointAddress = fs_source_desc.bEndpointAddress; + hs_sink_desc.bEndpointAddress = fs_sink_desc.bEndpointAddress; - /* - * Fill in the HS isoc descriptors from the module parameters. - * We assume that the user knows what they are doing and won't - * give parameters that their UDC doesn't support. - */ - hs_iso_source_desc.wMaxPacketSize = isoc_maxpacket; - hs_iso_source_desc.wMaxPacketSize |= isoc_mult << 11; - hs_iso_source_desc.bInterval = isoc_interval; - hs_iso_source_desc.bEndpointAddress = - fs_iso_source_desc.bEndpointAddress; - - hs_iso_sink_desc.wMaxPacketSize = isoc_maxpacket; - hs_iso_sink_desc.wMaxPacketSize |= isoc_mult << 11; - hs_iso_sink_desc.bInterval = isoc_interval; - hs_iso_sink_desc.bEndpointAddress = - fs_iso_sink_desc.bEndpointAddress; - - f->hs_descriptors = hs_source_sink_descs; - } + /* + * Fill in the HS isoc descriptors from the module parameters. + * We assume that the user knows what they are doing and won't + * give parameters that their UDC doesn't support. + */ + hs_iso_source_desc.wMaxPacketSize = isoc_maxpacket; + hs_iso_source_desc.wMaxPacketSize |= isoc_mult << 11; + hs_iso_source_desc.bInterval = isoc_interval; + hs_iso_source_desc.bEndpointAddress = + fs_iso_source_desc.bEndpointAddress; + + hs_iso_sink_desc.wMaxPacketSize = isoc_maxpacket; + hs_iso_sink_desc.wMaxPacketSize |= isoc_mult << 11; + hs_iso_sink_desc.bInterval = isoc_interval; + hs_iso_sink_desc.bEndpointAddress = fs_iso_sink_desc.bEndpointAddress; /* 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; + ss_source_desc.bEndpointAddress = + fs_source_desc.bEndpointAddress; + ss_sink_desc.bEndpointAddress = + fs_sink_desc.bEndpointAddress; - /* - * Fill in the SS isoc descriptors from the module parameters. - * We assume that the user knows what they are doing and won't - * give parameters that their UDC doesn't support. - */ - ss_iso_source_desc.wMaxPacketSize = isoc_maxpacket; - ss_iso_source_desc.bInterval = isoc_interval; - ss_iso_source_comp_desc.bmAttributes = isoc_mult; - ss_iso_source_comp_desc.bMaxBurst = isoc_maxburst; - ss_iso_source_comp_desc.wBytesPerInterval = - isoc_maxpacket * (isoc_mult + 1) * (isoc_maxburst + 1); - ss_iso_source_desc.bEndpointAddress = - fs_iso_source_desc.bEndpointAddress; - - ss_iso_sink_desc.wMaxPacketSize = isoc_maxpacket; - ss_iso_sink_desc.bInterval = isoc_interval; - ss_iso_sink_comp_desc.bmAttributes = isoc_mult; - ss_iso_sink_comp_desc.bMaxBurst = isoc_maxburst; - ss_iso_sink_comp_desc.wBytesPerInterval = - isoc_maxpacket * (isoc_mult + 1) * (isoc_maxburst + 1); - ss_iso_sink_desc.bEndpointAddress = - fs_iso_sink_desc.bEndpointAddress; - - f->ss_descriptors = ss_source_sink_descs; - } + /* + * Fill in the SS isoc descriptors from the module parameters. + * We assume that the user knows what they are doing and won't + * give parameters that their UDC doesn't support. + */ + ss_iso_source_desc.wMaxPacketSize = isoc_maxpacket; + ss_iso_source_desc.bInterval = isoc_interval; + ss_iso_source_comp_desc.bmAttributes = isoc_mult; + ss_iso_source_comp_desc.bMaxBurst = isoc_maxburst; + ss_iso_source_comp_desc.wBytesPerInterval = + isoc_maxpacket * (isoc_mult + 1) * (isoc_maxburst + 1); + ss_iso_source_desc.bEndpointAddress = + fs_iso_source_desc.bEndpointAddress; + + ss_iso_sink_desc.wMaxPacketSize = isoc_maxpacket; + ss_iso_sink_desc.bInterval = isoc_interval; + ss_iso_sink_comp_desc.bmAttributes = isoc_mult; + ss_iso_sink_comp_desc.bMaxBurst = isoc_maxburst; + ss_iso_sink_comp_desc.wBytesPerInterval = + isoc_maxpacket * (isoc_mult + 1) * (isoc_maxburst + 1); + ss_iso_sink_desc.bEndpointAddress = fs_iso_sink_desc.bEndpointAddress; + + ret = usb_assign_descriptors(f, fs_source_sink_descs, + hs_source_sink_descs, ss_source_sink_descs); + if (ret) + return ret; DBG(cdev, "%s speed %s: IN/%s, OUT/%s, ISO-IN/%s, ISO-OUT/%s\n", (gadget_is_superspeed(c->cdev->gadget) ? "super" : @@ -458,6 +452,7 @@ no_iso: static void sourcesink_unbind(struct usb_configuration *c, struct usb_function *f) { + usb_free_all_descriptors(f); kfree(func_to_ss(f)); } @@ -773,7 +768,6 @@ static int __init sourcesink_bind_config(struct usb_configuration *c) return -ENOMEM; ss->function.name = "source/sink"; - ss->function.descriptors = fs_source_sink_descs; ss->function.bind = sourcesink_bind; ss->function.unbind = sourcesink_unbind; ss->function.set_alt = sourcesink_set_alt; diff --git a/drivers/usb/gadget/f_subset.c b/drivers/usb/gadget/f_subset.c index 4060c0bd9785..f172bd152fbb 100644 --- a/drivers/usb/gadget/f_subset.c +++ b/drivers/usb/gadget/f_subset.c @@ -236,7 +236,7 @@ static struct usb_descriptor_header *ss_eth_function[] = { static struct usb_string geth_string_defs[] = { [0].s = "CDC Ethernet Subset/SAFE", - [1].s = NULL /* DYNAMIC */, + [1].s = "", { } /* end of list */ }; @@ -319,38 +319,22 @@ geth_bind(struct usb_configuration *c, struct usb_function *f) geth->port.out_ep = ep; ep->driver_data = cdev; /* claim */ - /* copy descriptors, and track endpoint copies */ - f->descriptors = usb_copy_descriptors(fs_eth_function); - if (!f->descriptors) - goto fail; - /* support all relevant hardware speeds... we expect that when * hardware is dual speed, all bulk-capable endpoints work at * both speeds */ - if (gadget_is_dualspeed(c->cdev->gadget)) { - hs_subset_in_desc.bEndpointAddress = - fs_subset_in_desc.bEndpointAddress; - hs_subset_out_desc.bEndpointAddress = - fs_subset_out_desc.bEndpointAddress; - - /* copy descriptors, and track endpoint copies */ - f->hs_descriptors = usb_copy_descriptors(hs_eth_function); - if (!f->hs_descriptors) - goto fail; - } + hs_subset_in_desc.bEndpointAddress = fs_subset_in_desc.bEndpointAddress; + hs_subset_out_desc.bEndpointAddress = + fs_subset_out_desc.bEndpointAddress; - 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; + 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; - } + status = usb_assign_descriptors(f, fs_eth_function, hs_eth_function, + ss_eth_function); + if (status) + goto fail; /* NOTE: all that is done without knowing or caring about * the network link ... which is unavailable to this code @@ -364,15 +348,11 @@ geth_bind(struct usb_configuration *c, struct usb_function *f) return 0; fail: - if (f->descriptors) - usb_free_descriptors(f->descriptors); - if (f->hs_descriptors) - usb_free_descriptors(f->hs_descriptors); - + usb_free_all_descriptors(f); /* we might as well release our claims on endpoints */ - if (geth->port.out_ep->desc) + if (geth->port.out_ep) geth->port.out_ep->driver_data = NULL; - if (geth->port.in_ep->desc) + if (geth->port.in_ep) geth->port.in_ep->driver_data = NULL; ERROR(cdev, "%s: can't bind, err %d\n", f->name, status); @@ -383,12 +363,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); - geth_string_defs[1].s = NULL; + geth_string_defs[0].id = 0; + usb_free_all_descriptors(f); kfree(func_to_geth(f)); } @@ -414,20 +390,11 @@ int geth_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN]) /* maybe allocate device-global string IDs */ if (geth_string_defs[0].id == 0) { - - /* interface label */ - status = usb_string_id(c->cdev); + status = usb_string_ids_tab(c->cdev, geth_string_defs); if (status < 0) return status; - geth_string_defs[0].id = status; - subset_data_intf.iInterface = status; - - /* MAC address */ - status = usb_string_id(c->cdev); - if (status < 0) - return status; - geth_string_defs[1].id = status; - ether_desc.iMACAddress = status; + subset_data_intf.iInterface = geth_string_defs[0].id; + ether_desc.iMACAddress = geth_string_defs[1].id; } /* allocate and initialize one new instance */ @@ -449,9 +416,7 @@ int geth_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN]) geth->port.func.disable = geth_disable; status = usb_add_function(c, &geth->port.func); - if (status) { - geth_string_defs[1].s = NULL; + if (status) kfree(geth); - } return status; } diff --git a/drivers/usb/gadget/f_uac1.c b/drivers/usb/gadget/f_uac1.c index 1a5dcd5565e3..f570e667a640 100644 --- a/drivers/usb/gadget/f_uac1.c +++ b/drivers/usb/gadget/f_uac1.c @@ -630,7 +630,7 @@ f_audio_bind(struct usb_configuration *c, struct usb_function *f) struct usb_composite_dev *cdev = c->cdev; struct f_audio *audio = func_to_audio(f); int status; - struct usb_ep *ep; + struct usb_ep *ep = NULL; f_audio_build_desc(audio); @@ -659,22 +659,14 @@ f_audio_bind(struct usb_configuration *c, struct usb_function *f) status = -ENOMEM; /* copy descriptors, and track endpoint copies */ - f->descriptors = usb_copy_descriptors(f_audio_desc); - - /* - * support all relevant hardware speeds... we expect that when - * hardware is dual speed, all bulk-capable endpoints work at - * both speeds - */ - if (gadget_is_dualspeed(c->cdev->gadget)) { - c->highspeed = true; - f->hs_descriptors = usb_copy_descriptors(f_audio_desc); - } - + status = usb_assign_descriptors(f, f_audio_desc, f_audio_desc, NULL); + if (status) + goto fail; return 0; fail: - + if (ep) + ep->driver_data = NULL; return status; } @@ -683,8 +675,7 @@ f_audio_unbind(struct usb_configuration *c, struct usb_function *f) { struct f_audio *audio = func_to_audio(f); - usb_free_descriptors(f->descriptors); - usb_free_descriptors(f->hs_descriptors); + usb_free_all_descriptors(f); kfree(audio); } diff --git a/drivers/usb/gadget/f_uac2.c b/drivers/usb/gadget/f_uac2.c index d3c6cffccb72..91396a1683eb 100644 --- a/drivers/usb/gadget/f_uac2.c +++ b/drivers/usb/gadget/f_uac2.c @@ -50,13 +50,6 @@ static int c_ssize = 2; module_param(c_ssize, uint, S_IRUGO); MODULE_PARM_DESC(c_ssize, "Capture Sample Size(bytes)"); -#define DMA_ADDR_INVALID (~(dma_addr_t)0) - -#define ALT_SET(x, a) do {(x) &= ~0xff; (x) |= (a); } while (0) -#define ALT_GET(x) ((x) & 0xff) -#define INTF_SET(x, i) do {(x) &= 0xff; (x) |= ((i) << 8); } while (0) -#define INTF_GET(x) ((x >> 8) & 0xff) - /* Keep everyone on toes */ #define USB_XFERS 2 @@ -144,8 +137,9 @@ static struct snd_pcm_hardware uac2_pcm_hardware = { }; struct audio_dev { - /* Currently active {Interface[15:8] | AltSettings[7:0]} */ - __u16 ac_alt, as_out_alt, as_in_alt; + u8 ac_intf, ac_alt; + u8 as_out_intf, as_out_alt; + u8 as_in_intf, as_in_alt; struct usb_ep *in_ep, *out_ep; struct usb_function func; @@ -526,32 +520,22 @@ enum { STR_AS_IN_ALT1, }; -static const char ifassoc[] = "Source/Sink"; -static const char ifctrl[] = "Topology Control"; static char clksrc_in[8]; static char clksrc_out[8]; -static const char usb_it[] = "USBH Out"; -static const char io_it[] = "USBD Out"; -static const char usb_ot[] = "USBH In"; -static const char io_ot[] = "USBD In"; -static const char out_alt0[] = "Playback Inactive"; -static const char out_alt1[] = "Playback Active"; -static const char in_alt0[] = "Capture Inactive"; -static const char in_alt1[] = "Capture Active"; static struct usb_string strings_fn[] = { - [STR_ASSOC].s = ifassoc, - [STR_IF_CTRL].s = ifctrl, + [STR_ASSOC].s = "Source/Sink", + [STR_IF_CTRL].s = "Topology Control", [STR_CLKSRC_IN].s = clksrc_in, [STR_CLKSRC_OUT].s = clksrc_out, - [STR_USB_IT].s = usb_it, - [STR_IO_IT].s = io_it, - [STR_USB_OT].s = usb_ot, - [STR_IO_OT].s = io_ot, - [STR_AS_OUT_ALT0].s = out_alt0, - [STR_AS_OUT_ALT1].s = out_alt1, - [STR_AS_IN_ALT0].s = in_alt0, - [STR_AS_IN_ALT1].s = in_alt1, + [STR_USB_IT].s = "USBH Out", + [STR_IO_IT].s = "USBD Out", + [STR_USB_OT].s = "USBH In", + [STR_IO_OT].s = "USBD In", + [STR_AS_OUT_ALT0].s = "Playback Inactive", + [STR_AS_OUT_ALT1].s = "Playback Active", + [STR_AS_IN_ALT0].s = "Capture Inactive", + [STR_AS_IN_ALT1].s = "Capture Active", { }, }; @@ -952,8 +936,8 @@ afunc_bind(struct usb_configuration *cfg, struct usb_function *fn) return ret; } std_ac_if_desc.bInterfaceNumber = ret; - ALT_SET(agdev->ac_alt, 0); - INTF_SET(agdev->ac_alt, ret); + agdev->ac_intf = ret; + agdev->ac_alt = 0; ret = usb_interface_id(cfg, fn); if (ret < 0) { @@ -963,8 +947,8 @@ afunc_bind(struct usb_configuration *cfg, struct usb_function *fn) } std_as_out_if0_desc.bInterfaceNumber = ret; std_as_out_if1_desc.bInterfaceNumber = ret; - ALT_SET(agdev->as_out_alt, 0); - INTF_SET(agdev->as_out_alt, ret); + agdev->as_out_intf = ret; + agdev->as_out_alt = 0; ret = usb_interface_id(cfg, fn); if (ret < 0) { @@ -974,19 +958,23 @@ afunc_bind(struct usb_configuration *cfg, struct usb_function *fn) } std_as_in_if0_desc.bInterfaceNumber = ret; std_as_in_if1_desc.bInterfaceNumber = ret; - ALT_SET(agdev->as_in_alt, 0); - INTF_SET(agdev->as_in_alt, ret); + agdev->as_in_intf = ret; + agdev->as_in_alt = 0; agdev->out_ep = usb_ep_autoconfig(gadget, &fs_epout_desc); - if (!agdev->out_ep) + if (!agdev->out_ep) { dev_err(&uac2->pdev.dev, "%s:%d Error!\n", __func__, __LINE__); + goto err; + } agdev->out_ep->driver_data = agdev; agdev->in_ep = usb_ep_autoconfig(gadget, &fs_epin_desc); - if (!agdev->in_ep) + if (!agdev->in_ep) { dev_err(&uac2->pdev.dev, "%s:%d Error!\n", __func__, __LINE__); + goto err; + } agdev->in_ep->driver_data = agdev; hs_epout_desc.bEndpointAddress = fs_epout_desc.bEndpointAddress; @@ -994,9 +982,9 @@ afunc_bind(struct usb_configuration *cfg, struct usb_function *fn) hs_epin_desc.bEndpointAddress = fs_epin_desc.bEndpointAddress; hs_epin_desc.wMaxPacketSize = fs_epin_desc.wMaxPacketSize; - fn->descriptors = usb_copy_descriptors(fs_audio_desc); - if (gadget_is_dualspeed(gadget)) - fn->hs_descriptors = usb_copy_descriptors(hs_audio_desc); + ret = usb_assign_descriptors(fn, fs_audio_desc, hs_audio_desc, NULL); + if (ret) + goto err; prm = &agdev->uac2.c_prm; prm->max_psize = hs_epout_desc.wMaxPacketSize; @@ -1005,6 +993,7 @@ afunc_bind(struct usb_configuration *cfg, struct usb_function *fn) prm->max_psize = 0; dev_err(&uac2->pdev.dev, "%s:%d Error!\n", __func__, __LINE__); + goto err; } prm = &agdev->uac2.p_prm; @@ -1014,17 +1003,28 @@ afunc_bind(struct usb_configuration *cfg, struct usb_function *fn) prm->max_psize = 0; dev_err(&uac2->pdev.dev, "%s:%d Error!\n", __func__, __LINE__); + goto err; } - return alsa_uac2_init(agdev); + ret = alsa_uac2_init(agdev); + if (ret) + goto err; + return 0; +err: + kfree(agdev->uac2.p_prm.rbuf); + kfree(agdev->uac2.c_prm.rbuf); + usb_free_all_descriptors(fn); + if (agdev->in_ep) + agdev->in_ep->driver_data = NULL; + if (agdev->out_ep) + agdev->out_ep->driver_data = NULL; + return -EINVAL; } static void afunc_unbind(struct usb_configuration *cfg, struct usb_function *fn) { struct audio_dev *agdev = func_to_agdev(fn); - struct usb_composite_dev *cdev = cfg->cdev; - struct usb_gadget *gadget = cdev->gadget; struct uac2_rtd_params *prm; alsa_uac2_exit(agdev); @@ -1034,10 +1034,7 @@ afunc_unbind(struct usb_configuration *cfg, struct usb_function *fn) prm = &agdev->uac2.c_prm; kfree(prm->rbuf); - - if (gadget_is_dualspeed(gadget)) - usb_free_descriptors(fn->hs_descriptors); - usb_free_descriptors(fn->descriptors); + usb_free_all_descriptors(fn); if (agdev->in_ep) agdev->in_ep->driver_data = NULL; @@ -1064,7 +1061,7 @@ afunc_set_alt(struct usb_function *fn, unsigned intf, unsigned alt) return -EINVAL; } - if (intf == INTF_GET(agdev->ac_alt)) { + if (intf == agdev->ac_intf) { /* Control I/f has only 1 AltSetting - 0 */ if (alt) { dev_err(&uac2->pdev.dev, @@ -1074,16 +1071,16 @@ afunc_set_alt(struct usb_function *fn, unsigned intf, unsigned alt) return 0; } - if (intf == INTF_GET(agdev->as_out_alt)) { + if (intf == agdev->as_out_intf) { ep = agdev->out_ep; prm = &uac2->c_prm; config_ep_by_speed(gadget, fn, ep); - ALT_SET(agdev->as_out_alt, alt); - } else if (intf == INTF_GET(agdev->as_in_alt)) { + agdev->as_out_alt = alt; + } else if (intf == agdev->as_in_intf) { ep = agdev->in_ep; prm = &uac2->p_prm; config_ep_by_speed(gadget, fn, ep); - ALT_SET(agdev->as_in_alt, alt); + agdev->as_in_alt = alt; } else { dev_err(&uac2->pdev.dev, "%s:%d Error!\n", __func__, __LINE__); @@ -1117,7 +1114,6 @@ afunc_set_alt(struct usb_function *fn, unsigned intf, unsigned alt) prm->ureq[i].pp = prm; req->zero = 0; - req->dma = DMA_ADDR_INVALID; req->context = &prm->ureq[i]; req->length = prm->max_psize; req->complete = agdev_iso_complete; @@ -1136,12 +1132,12 @@ afunc_get_alt(struct usb_function *fn, unsigned intf) struct audio_dev *agdev = func_to_agdev(fn); struct snd_uac2_chip *uac2 = &agdev->uac2; - if (intf == INTF_GET(agdev->ac_alt)) - return ALT_GET(agdev->ac_alt); - else if (intf == INTF_GET(agdev->as_out_alt)) - return ALT_GET(agdev->as_out_alt); - else if (intf == INTF_GET(agdev->as_in_alt)) - return ALT_GET(agdev->as_in_alt); + if (intf == agdev->ac_intf) + return agdev->ac_alt; + else if (intf == agdev->as_out_intf) + return agdev->as_out_alt; + else if (intf == agdev->as_in_intf) + return agdev->as_in_alt; else dev_err(&uac2->pdev.dev, "%s:%d Invalid Interface %d!\n", @@ -1157,10 +1153,10 @@ afunc_disable(struct usb_function *fn) struct snd_uac2_chip *uac2 = &agdev->uac2; free_ep(&uac2->p_prm, agdev->in_ep); - ALT_SET(agdev->as_in_alt, 0); + agdev->as_in_alt = 0; free_ep(&uac2->c_prm, agdev->out_ep); - ALT_SET(agdev->as_out_alt, 0); + agdev->as_out_alt = 0; } static int @@ -1267,7 +1263,7 @@ setup_rq_inf(struct usb_function *fn, const struct usb_ctrlrequest *cr) u16 w_index = le16_to_cpu(cr->wIndex); u8 intf = w_index & 0xff; - if (intf != INTF_GET(agdev->ac_alt)) { + if (intf != agdev->ac_intf) { dev_err(&uac2->pdev.dev, "%s:%d Error!\n", __func__, __LINE__); return -EOPNOTSUPP; @@ -1316,7 +1312,7 @@ afunc_setup(struct usb_function *fn, const struct usb_ctrlrequest *cr) static int audio_bind_config(struct usb_configuration *cfg) { - int id, res; + int res; agdev_g = kzalloc(sizeof *agdev_g, GFP_KERNEL); if (agdev_g == NULL) { @@ -1324,89 +1320,21 @@ static int audio_bind_config(struct usb_configuration *cfg) return -ENOMEM; } - id = usb_string_id(cfg->cdev); - if (id < 0) - return id; - - strings_fn[STR_ASSOC].id = id; - iad_desc.iFunction = id, - - id = usb_string_id(cfg->cdev); - if (id < 0) - return id; - - strings_fn[STR_IF_CTRL].id = id; - std_ac_if_desc.iInterface = id, - - id = usb_string_id(cfg->cdev); - if (id < 0) - return id; - - strings_fn[STR_CLKSRC_IN].id = id; - in_clk_src_desc.iClockSource = id, - - id = usb_string_id(cfg->cdev); - if (id < 0) - return id; - - strings_fn[STR_CLKSRC_OUT].id = id; - out_clk_src_desc.iClockSource = id, - - id = usb_string_id(cfg->cdev); - if (id < 0) - return id; - - strings_fn[STR_USB_IT].id = id; - usb_out_it_desc.iTerminal = id, - - id = usb_string_id(cfg->cdev); - if (id < 0) - return id; - - strings_fn[STR_IO_IT].id = id; - io_in_it_desc.iTerminal = id; - - id = usb_string_id(cfg->cdev); - if (id < 0) - return id; - - strings_fn[STR_USB_OT].id = id; - usb_in_ot_desc.iTerminal = id; - - id = usb_string_id(cfg->cdev); - if (id < 0) - return id; - - strings_fn[STR_IO_OT].id = id; - io_out_ot_desc.iTerminal = id; - - id = usb_string_id(cfg->cdev); - if (id < 0) - return id; - - strings_fn[STR_AS_OUT_ALT0].id = id; - std_as_out_if0_desc.iInterface = id; - - id = usb_string_id(cfg->cdev); - if (id < 0) - return id; - - strings_fn[STR_AS_OUT_ALT1].id = id; - std_as_out_if1_desc.iInterface = id; - - id = usb_string_id(cfg->cdev); - if (id < 0) - return id; - - strings_fn[STR_AS_IN_ALT0].id = id; - std_as_in_if0_desc.iInterface = id; - - id = usb_string_id(cfg->cdev); - if (id < 0) - return id; - - strings_fn[STR_AS_IN_ALT1].id = id; - std_as_in_if1_desc.iInterface = id; + res = usb_string_ids_tab(cfg->cdev, strings_fn); + if (res) + return res; + iad_desc.iFunction = strings_fn[STR_ASSOC].id; + std_ac_if_desc.iInterface = strings_fn[STR_IF_CTRL].id; + in_clk_src_desc.iClockSource = strings_fn[STR_CLKSRC_IN].id; + out_clk_src_desc.iClockSource = strings_fn[STR_CLKSRC_OUT].id; + usb_out_it_desc.iTerminal = strings_fn[STR_USB_IT].id; + io_in_it_desc.iTerminal = strings_fn[STR_IO_IT].id; + usb_in_ot_desc.iTerminal = strings_fn[STR_USB_OT].id; + io_out_ot_desc.iTerminal = strings_fn[STR_IO_OT].id; + std_as_out_if0_desc.iInterface = strings_fn[STR_AS_OUT_ALT0].id; + std_as_out_if1_desc.iInterface = strings_fn[STR_AS_OUT_ALT1].id; + std_as_in_if0_desc.iInterface = strings_fn[STR_AS_IN_ALT0].id; + std_as_in_if1_desc.iInterface = strings_fn[STR_AS_IN_ALT1].id; agdev_g->func.name = "uac2_func"; agdev_g->func.strings = fn_strings; diff --git a/drivers/usb/gadget/f_uvc.c b/drivers/usb/gadget/f_uvc.c index 2a8bf0655c60..5b629876941b 100644 --- a/drivers/usb/gadget/f_uvc.c +++ b/drivers/usb/gadget/f_uvc.c @@ -417,7 +417,6 @@ uvc_register_video(struct uvc_device *uvc) return -ENOMEM; video->parent = &cdev->gadget->dev; - video->minor = -1; video->fops = &uvc_v4l2_fops; video->release = video_device_release; strncpy(video->name, cdev->gadget->name, sizeof(video->name)); @@ -577,27 +576,15 @@ uvc_function_unbind(struct usb_configuration *c, struct usb_function *f) INFO(cdev, "uvc_function_unbind\n"); - if (uvc->vdev) { - if (uvc->vdev->minor == -1) - video_device_release(uvc->vdev); - else - video_unregister_device(uvc->vdev); - uvc->vdev = NULL; - } + video_unregister_device(uvc->vdev); + uvc->control_ep->driver_data = NULL; + uvc->video.ep->driver_data = NULL; - if (uvc->control_ep) - uvc->control_ep->driver_data = NULL; - if (uvc->video.ep) - uvc->video.ep->driver_data = NULL; - - if (uvc->control_req) { - usb_ep_free_request(cdev->gadget->ep0, uvc->control_req); - kfree(uvc->control_buf); - } + uvc_en_us_strings[UVC_STRING_ASSOCIATION_IDX].id = 0; + usb_ep_free_request(cdev->gadget->ep0, uvc->control_req); + kfree(uvc->control_buf); - kfree(f->descriptors); - kfree(f->hs_descriptors); - kfree(f->ss_descriptors); + usb_free_all_descriptors(f); kfree(uvc); } @@ -663,49 +650,40 @@ uvc_function_bind(struct usb_configuration *c, struct usb_function *f) /* sanity check the streaming endpoint module parameters */ if (streaming_maxpacket > 1024) streaming_maxpacket = 1024; + /* + * Fill in the HS descriptors from the module parameters for the Video + * Streaming endpoint. + * NOTE: We assume that the user knows what they are doing and won't + * give parameters that their UDC doesn't support. + */ + uvc_hs_streaming_ep.wMaxPacketSize = streaming_maxpacket; + uvc_hs_streaming_ep.wMaxPacketSize |= streaming_mult << 11; + uvc_hs_streaming_ep.bInterval = streaming_interval; + uvc_hs_streaming_ep.bEndpointAddress = + uvc_fs_streaming_ep.bEndpointAddress; - /* Copy descriptors for FS. */ - f->descriptors = uvc_copy_descriptors(uvc, USB_SPEED_FULL); - - /* support high speed hardware */ - if (gadget_is_dualspeed(cdev->gadget)) { - /* - * Fill in the HS descriptors from the module parameters for the - * Video Streaming endpoint. - * NOTE: We assume that the user knows what they are doing and - * won't give parameters that their UDC doesn't support. - */ - uvc_hs_streaming_ep.wMaxPacketSize = streaming_maxpacket; - uvc_hs_streaming_ep.wMaxPacketSize |= streaming_mult << 11; - uvc_hs_streaming_ep.bInterval = streaming_interval; - uvc_hs_streaming_ep.bEndpointAddress = - uvc_fs_streaming_ep.bEndpointAddress; - - /* Copy descriptors. */ - f->hs_descriptors = uvc_copy_descriptors(uvc, USB_SPEED_HIGH); - } + /* + * Fill in the SS descriptors from the module parameters for the Video + * Streaming endpoint. + * NOTE: We assume that the user knows what they are doing and won't + * give parameters that their UDC doesn't support. + */ + uvc_ss_streaming_ep.wMaxPacketSize = streaming_maxpacket; + uvc_ss_streaming_ep.bInterval = streaming_interval; + uvc_ss_streaming_comp.bmAttributes = streaming_mult; + uvc_ss_streaming_comp.bMaxBurst = streaming_maxburst; + uvc_ss_streaming_comp.wBytesPerInterval = + streaming_maxpacket * (streaming_mult + 1) * + (streaming_maxburst + 1); + uvc_ss_streaming_ep.bEndpointAddress = + uvc_fs_streaming_ep.bEndpointAddress; - /* support super speed hardware */ - if (gadget_is_superspeed(c->cdev->gadget)) { - /* - * Fill in the SS descriptors from the module parameters for the - * Video Streaming endpoint. - * NOTE: We assume that the user knows what they are doing and - * won't give parameters that their UDC doesn't support. - */ - uvc_ss_streaming_ep.wMaxPacketSize = streaming_maxpacket; - uvc_ss_streaming_ep.bInterval = streaming_interval; - uvc_ss_streaming_comp.bmAttributes = streaming_mult; - uvc_ss_streaming_comp.bMaxBurst = streaming_maxburst; - uvc_ss_streaming_comp.wBytesPerInterval = - streaming_maxpacket * (streaming_mult + 1) * - (streaming_maxburst + 1); - uvc_ss_streaming_ep.bEndpointAddress = - uvc_fs_streaming_ep.bEndpointAddress; - - /* Copy descriptors. */ + /* Copy descriptors */ + f->fs_descriptors = uvc_copy_descriptors(uvc, USB_SPEED_FULL); + if (gadget_is_dualspeed(cdev->gadget)) + f->hs_descriptors = uvc_copy_descriptors(uvc, USB_SPEED_HIGH); + if (gadget_is_superspeed(c->cdev->gadget)) f->ss_descriptors = uvc_copy_descriptors(uvc, USB_SPEED_SUPER); - } /* Preallocate control endpoint request. */ uvc->control_req = usb_ep_alloc_request(cdev->gadget->ep0, GFP_KERNEL); @@ -740,7 +718,20 @@ uvc_function_bind(struct usb_configuration *c, struct usb_function *f) return 0; error: - uvc_function_unbind(c, f); + if (uvc->vdev) + video_device_release(uvc->vdev); + + if (uvc->control_ep) + uvc->control_ep->driver_data = NULL; + if (uvc->video.ep) + uvc->video.ep->driver_data = NULL; + + if (uvc->control_req) { + usb_ep_free_request(cdev->gadget->ep0, uvc->control_req); + kfree(uvc->control_buf); + } + + usb_free_all_descriptors(f); return ret; } @@ -808,25 +799,16 @@ uvc_bind_config(struct usb_configuration *c, uvc->desc.hs_streaming = hs_streaming; uvc->desc.ss_streaming = ss_streaming; - /* maybe allocate device-global string IDs, and patch descriptors */ + /* Allocate string descriptor numbers. */ if (uvc_en_us_strings[UVC_STRING_ASSOCIATION_IDX].id == 0) { - /* Allocate string descriptor numbers. */ - ret = usb_string_id(c->cdev); - if (ret < 0) - goto error; - uvc_en_us_strings[UVC_STRING_ASSOCIATION_IDX].id = ret; - uvc_iad.iFunction = ret; - - ret = usb_string_id(c->cdev); - if (ret < 0) - goto error; - uvc_en_us_strings[UVC_STRING_CONTROL_IDX].id = ret; - uvc_control_intf.iInterface = ret; - - ret = usb_string_id(c->cdev); - if (ret < 0) + ret = usb_string_ids_tab(c->cdev, uvc_en_us_strings); + if (ret) goto error; - uvc_en_us_strings[UVC_STRING_STREAMING_IDX].id = ret; + uvc_iad.iFunction = + uvc_en_us_strings[UVC_STRING_ASSOCIATION_IDX].id; + uvc_control_intf.iInterface = + uvc_en_us_strings[UVC_STRING_CONTROL_IDX].id; + ret = uvc_en_us_strings[UVC_STRING_STREAMING_IDX].id; uvc_streaming_intf_alt0.iInterface = ret; uvc_streaming_intf_alt1.iInterface = ret; } diff --git a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c deleted file mode 100644 index 3f7d640b6758..000000000000 --- a/drivers/usb/gadget/file_storage.c +++ /dev/null @@ -1,3656 +0,0 @@ -/* - * file_storage.c -- File-backed USB Storage Gadget, for USB development - * - * Copyright (C) 2003-2008 Alan Stern - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions, and the following disclaimer, - * without modification. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The names of the above-listed copyright holders may not be used - * to endorse or promote products derived from this software without - * specific prior written permission. - * - * ALTERNATIVELY, this software may be distributed under the terms of the - * GNU General Public License ("GPL") as published by the Free Software - * Foundation, either version 2 of that License or (at your option) any - * later version. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - - -/* - * The File-backed Storage Gadget acts as a USB Mass Storage device, - * appearing to the host as a disk drive or as a CD-ROM drive. In addition - * to providing an example of a genuinely useful gadget driver for a USB - * device, it also illustrates a technique of double-buffering for increased - * throughput. Last but not least, it gives an easy way to probe the - * behavior of the Mass Storage drivers in a USB host. - * - * Backing storage is provided by a regular file or a block device, specified - * by the "file" module parameter. Access can be limited to read-only by - * setting the optional "ro" module parameter. (For CD-ROM emulation, - * access is always read-only.) The gadget will indicate that it has - * removable media if the optional "removable" module parameter is set. - * - * The gadget supports the Control-Bulk (CB), Control-Bulk-Interrupt (CBI), - * and Bulk-Only (also known as Bulk-Bulk-Bulk or BBB) transports, selected - * by the optional "transport" module parameter. It also supports the - * following protocols: RBC (0x01), ATAPI or SFF-8020i (0x02), QIC-157 (0c03), - * UFI (0x04), SFF-8070i (0x05), and transparent SCSI (0x06), selected by - * the optional "protocol" module parameter. In addition, the default - * Vendor ID, Product ID, release number and serial number can be overridden. - * - * There is support for multiple logical units (LUNs), each of which has - * its own backing file. The number of LUNs can be set using the optional - * "luns" module parameter (anywhere from 1 to 8), and the corresponding - * files are specified using comma-separated lists for "file" and "ro". - * The default number of LUNs is taken from the number of "file" elements; - * it is 1 if "file" is not given. If "removable" is not set then a backing - * file must be specified for each LUN. If it is set, then an unspecified - * or empty backing filename means the LUN's medium is not loaded. Ideally - * each LUN would be settable independently as a disk drive or a CD-ROM - * drive, but currently all LUNs have to be the same type. The CD-ROM - * emulation includes a single data track and no audio tracks; hence there - * need be only one backing file per LUN. - * - * Requirements are modest; only a bulk-in and a bulk-out endpoint are - * needed (an interrupt-out endpoint is also needed for CBI). The memory - * requirement amounts to two 16K buffers, size configurable by a parameter. - * Support is included for both full-speed and high-speed operation. - * - * Note that the driver is slightly non-portable in that it assumes a - * single memory/DMA buffer will be useable for bulk-in, bulk-out, and - * interrupt-in endpoints. With most device controllers this isn't an - * issue, but there may be some with hardware restrictions that prevent - * a buffer from being used by more than one endpoint. - * - * Module options: - * - * file=filename[,filename...] - * Required if "removable" is not set, names of - * the files or block devices used for - * backing storage - * serial=HHHH... Required serial number (string of hex chars) - * ro=b[,b...] Default false, booleans for read-only access - * removable Default false, boolean for removable media - * luns=N Default N = number of filenames, number of - * LUNs to support - * nofua=b[,b...] Default false, booleans for ignore FUA flag - * in SCSI WRITE(10,12) commands - * stall Default determined according to the type of - * USB device controller (usually true), - * boolean to permit the driver to halt - * bulk endpoints - * cdrom Default false, boolean for whether to emulate - * a CD-ROM drive - * transport=XXX Default BBB, transport name (CB, CBI, or BBB) - * protocol=YYY Default SCSI, protocol name (RBC, 8020 or - * ATAPI, QIC, UFI, 8070, or SCSI; - * also 1 - 6) - * vendor=0xVVVV Default 0x0525 (NetChip), USB Vendor ID - * product=0xPPPP Default 0xa4a5 (FSG), USB Product ID - * release=0xRRRR Override the USB release number (bcdDevice) - * buflen=N Default N=16384, buffer size used (will be - * rounded down to a multiple of - * PAGE_CACHE_SIZE) - * - * If CONFIG_USB_FILE_STORAGE_TEST is not set, only the "file", "serial", "ro", - * "removable", "luns", "nofua", "stall", and "cdrom" options are available; - * default values are used for everything else. - * - * The pathnames of the backing files and the ro settings are available in - * the attribute files "file", "nofua", and "ro" in the lun<n> subdirectory of - * the gadget's sysfs directory. If the "removable" option is set, writing to - * these files will simulate ejecting/loading the medium (writing an empty - * line means eject) and adjusting a write-enable tab. Changes to the ro - * setting are not allowed when the medium is loaded or if CD-ROM emulation - * is being used. - * - * This gadget driver is heavily based on "Gadget Zero" by David Brownell. - * The driver's SCSI command interface was based on the "Information - * technology - Small Computer System Interface - 2" document from - * X3T9.2 Project 375D, Revision 10L, 7-SEP-93, available at - * <http://www.t10.org/ftp/t10/drafts/s2/s2-r10l.pdf>. The single exception - * is opcode 0x23 (READ FORMAT CAPACITIES), which was based on the - * "Universal Serial Bus Mass Storage Class UFI Command Specification" - * document, Revision 1.0, December 14, 1998, available at - * <http://www.usb.org/developers/devclass_docs/usbmass-ufi10.pdf>. - */ - - -/* - * Driver Design - * - * The FSG driver is fairly straightforward. There is a main kernel - * thread that handles most of the work. Interrupt routines field - * callbacks from the controller driver: bulk- and interrupt-request - * completion notifications, endpoint-0 events, and disconnect events. - * Completion events are passed to the main thread by wakeup calls. Many - * ep0 requests are handled at interrupt time, but SetInterface, - * SetConfiguration, and device reset requests are forwarded to the - * thread in the form of "exceptions" using SIGUSR1 signals (since they - * should interrupt any ongoing file I/O operations). - * - * The thread's main routine implements the standard command/data/status - * parts of a SCSI interaction. It and its subroutines are full of tests - * for pending signals/exceptions -- all this polling is necessary since - * the kernel has no setjmp/longjmp equivalents. (Maybe this is an - * indication that the driver really wants to be running in userspace.) - * An important point is that so long as the thread is alive it keeps an - * open reference to the backing file. This will prevent unmounting - * the backing file's underlying filesystem and could cause problems - * during system shutdown, for example. To prevent such problems, the - * thread catches INT, TERM, and KILL signals and converts them into - * an EXIT exception. - * - * In normal operation the main thread is started during the gadget's - * fsg_bind() callback and stopped during fsg_unbind(). But it can also - * exit when it receives a signal, and there's no point leaving the - * gadget running when the thread is dead. So just before the thread - * exits, it deregisters the gadget driver. This makes things a little - * tricky: The driver is deregistered at two places, and the exiting - * thread can indirectly call fsg_unbind() which in turn can tell the - * thread to exit. The first problem is resolved through the use of the - * REGISTERED atomic bitflag; the driver will only be deregistered once. - * The second problem is resolved by having fsg_unbind() check - * fsg->state; it won't try to stop the thread if the state is already - * FSG_STATE_TERMINATED. - * - * To provide maximum throughput, the driver uses a circular pipeline of - * buffer heads (struct fsg_buffhd). In principle the pipeline can be - * arbitrarily long; in practice the benefits don't justify having more - * than 2 stages (i.e., double buffering). But it helps to think of the - * pipeline as being a long one. Each buffer head contains a bulk-in and - * a bulk-out request pointer (since the buffer can be used for both - * output and input -- directions always are given from the host's - * point of view) as well as a pointer to the buffer and various state - * variables. - * - * Use of the pipeline follows a simple protocol. There is a variable - * (fsg->next_buffhd_to_fill) that points to the next buffer head to use. - * At any time that buffer head may still be in use from an earlier - * request, so each buffer head has a state variable indicating whether - * it is EMPTY, FULL, or BUSY. Typical use involves waiting for the - * buffer head to be EMPTY, filling the buffer either by file I/O or by - * USB I/O (during which the buffer head is BUSY), and marking the buffer - * head FULL when the I/O is complete. Then the buffer will be emptied - * (again possibly by USB I/O, during which it is marked BUSY) and - * finally marked EMPTY again (possibly by a completion routine). - * - * A module parameter tells the driver to avoid stalling the bulk - * endpoints wherever the transport specification allows. This is - * necessary for some UDCs like the SuperH, which cannot reliably clear a - * halt on a bulk endpoint. However, under certain circumstances the - * Bulk-only specification requires a stall. In such cases the driver - * will halt the endpoint and set a flag indicating that it should clear - * the halt in software during the next device reset. Hopefully this - * will permit everything to work correctly. Furthermore, although the - * specification allows the bulk-out endpoint to halt when the host sends - * too much data, implementing this would cause an unavoidable race. - * The driver will always use the "no-stall" approach for OUT transfers. - * - * One subtle point concerns sending status-stage responses for ep0 - * requests. Some of these requests, such as device reset, can involve - * interrupting an ongoing file I/O operation, which might take an - * arbitrarily long time. During that delay the host might give up on - * the original ep0 request and issue a new one. When that happens the - * driver should not notify the host about completion of the original - * request, as the host will no longer be waiting for it. So the driver - * assigns to each ep0 request a unique tag, and it keeps track of the - * tag value of the request associated with a long-running exception - * (device-reset, interface-change, or configuration-change). When the - * exception handler is finished, the status-stage response is submitted - * only if the current ep0 request tag is equal to the exception request - * tag. Thus only the most recently received ep0 request will get a - * status-stage response. - * - * Warning: This driver source file is too long. It ought to be split up - * into a header file plus about 3 separate .c files, to handle the details - * of the Gadget, USB Mass Storage, and SCSI protocols. - */ - - -/* #define VERBOSE_DEBUG */ -/* #define DUMP_MSGS */ - - -#include <linux/blkdev.h> -#include <linux/completion.h> -#include <linux/dcache.h> -#include <linux/delay.h> -#include <linux/device.h> -#include <linux/fcntl.h> -#include <linux/file.h> -#include <linux/fs.h> -#include <linux/kref.h> -#include <linux/kthread.h> -#include <linux/limits.h> -#include <linux/module.h> -#include <linux/rwsem.h> -#include <linux/slab.h> -#include <linux/spinlock.h> -#include <linux/string.h> -#include <linux/freezer.h> -#include <linux/utsname.h> - -#include <linux/usb/composite.h> -#include <linux/usb/ch9.h> -#include <linux/usb/gadget.h> - -#include "gadget_chips.h" - -#define DRIVER_DESC "File-backed Storage Gadget" -#define DRIVER_NAME "g_file_storage" -#define DRIVER_VERSION "1 September 2010" - -static char fsg_string_manufacturer[64]; -static const char fsg_string_product[] = DRIVER_DESC; -static const char fsg_string_config[] = "Self-powered"; -static const char fsg_string_interface[] = "Mass Storage"; - - -#include "storage_common.c" - - -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_AUTHOR("Alan Stern"); -MODULE_LICENSE("Dual BSD/GPL"); - -/* - * This driver assumes self-powered hardware and has no way for users to - * trigger remote wakeup. It uses autoconfiguration to select endpoints - * and endpoint addresses. - */ - - -/*-------------------------------------------------------------------------*/ - - -/* Encapsulate the module parameter settings */ - -static struct { - char *file[FSG_MAX_LUNS]; - char *serial; - bool ro[FSG_MAX_LUNS]; - bool nofua[FSG_MAX_LUNS]; - unsigned int num_filenames; - unsigned int num_ros; - unsigned int num_nofuas; - unsigned int nluns; - - bool removable; - bool can_stall; - bool cdrom; - - char *transport_parm; - char *protocol_parm; - unsigned short vendor; - unsigned short product; - unsigned short release; - unsigned int buflen; - - int transport_type; - char *transport_name; - int protocol_type; - char *protocol_name; - -} mod_data = { // Default values - .transport_parm = "BBB", - .protocol_parm = "SCSI", - .removable = 0, - .can_stall = 1, - .cdrom = 0, - .vendor = FSG_VENDOR_ID, - .product = FSG_PRODUCT_ID, - .release = 0xffff, // Use controller chip type - .buflen = 16384, - }; - - -module_param_array_named(file, mod_data.file, charp, &mod_data.num_filenames, - S_IRUGO); -MODULE_PARM_DESC(file, "names of backing files or devices"); - -module_param_named(serial, mod_data.serial, charp, S_IRUGO); -MODULE_PARM_DESC(serial, "USB serial number"); - -module_param_array_named(ro, mod_data.ro, bool, &mod_data.num_ros, S_IRUGO); -MODULE_PARM_DESC(ro, "true to force read-only"); - -module_param_array_named(nofua, mod_data.nofua, bool, &mod_data.num_nofuas, - S_IRUGO); -MODULE_PARM_DESC(nofua, "true to ignore SCSI WRITE(10,12) FUA bit"); - -module_param_named(luns, mod_data.nluns, uint, S_IRUGO); -MODULE_PARM_DESC(luns, "number of LUNs"); - -module_param_named(removable, mod_data.removable, bool, S_IRUGO); -MODULE_PARM_DESC(removable, "true to simulate removable media"); - -module_param_named(stall, mod_data.can_stall, bool, S_IRUGO); -MODULE_PARM_DESC(stall, "false to prevent bulk stalls"); - -module_param_named(cdrom, mod_data.cdrom, bool, S_IRUGO); -MODULE_PARM_DESC(cdrom, "true to emulate cdrom instead of disk"); - -/* In the non-TEST version, only the module parameters listed above - * are available. */ -#ifdef CONFIG_USB_FILE_STORAGE_TEST - -module_param_named(transport, mod_data.transport_parm, charp, S_IRUGO); -MODULE_PARM_DESC(transport, "type of transport (BBB, CBI, or CB)"); - -module_param_named(protocol, mod_data.protocol_parm, charp, S_IRUGO); -MODULE_PARM_DESC(protocol, "type of protocol (RBC, 8020, QIC, UFI, " - "8070, or SCSI)"); - -module_param_named(vendor, mod_data.vendor, ushort, S_IRUGO); -MODULE_PARM_DESC(vendor, "USB Vendor ID"); - -module_param_named(product, mod_data.product, ushort, S_IRUGO); -MODULE_PARM_DESC(product, "USB Product ID"); - -module_param_named(release, mod_data.release, ushort, S_IRUGO); -MODULE_PARM_DESC(release, "USB release number"); - -module_param_named(buflen, mod_data.buflen, uint, S_IRUGO); -MODULE_PARM_DESC(buflen, "I/O buffer size"); - -#endif /* CONFIG_USB_FILE_STORAGE_TEST */ - - -/* - * These definitions will permit the compiler to avoid generating code for - * parts of the driver that aren't used in the non-TEST version. Even gcc - * can recognize when a test of a constant expression yields a dead code - * path. - */ - -#ifdef CONFIG_USB_FILE_STORAGE_TEST - -#define transport_is_bbb() (mod_data.transport_type == USB_PR_BULK) -#define transport_is_cbi() (mod_data.transport_type == USB_PR_CBI) -#define protocol_is_scsi() (mod_data.protocol_type == USB_SC_SCSI) - -#else - -#define transport_is_bbb() 1 -#define transport_is_cbi() 0 -#define protocol_is_scsi() 1 - -#endif /* CONFIG_USB_FILE_STORAGE_TEST */ - - -/*-------------------------------------------------------------------------*/ - - -struct fsg_dev { - /* lock protects: state, all the req_busy's, and cbbuf_cmnd */ - spinlock_t lock; - struct usb_gadget *gadget; - - /* filesem protects: backing files in use */ - struct rw_semaphore filesem; - - /* reference counting: wait until all LUNs are released */ - struct kref ref; - - struct usb_ep *ep0; // Handy copy of gadget->ep0 - struct usb_request *ep0req; // For control responses - unsigned int ep0_req_tag; - const char *ep0req_name; - - struct usb_request *intreq; // For interrupt responses - int intreq_busy; - struct fsg_buffhd *intr_buffhd; - - unsigned int bulk_out_maxpacket; - enum fsg_state state; // For exception handling - unsigned int exception_req_tag; - - u8 config, new_config; - - unsigned int running : 1; - unsigned int bulk_in_enabled : 1; - unsigned int bulk_out_enabled : 1; - unsigned int intr_in_enabled : 1; - unsigned int phase_error : 1; - unsigned int short_packet_received : 1; - unsigned int bad_lun_okay : 1; - - unsigned long atomic_bitflags; -#define REGISTERED 0 -#define IGNORE_BULK_OUT 1 -#define SUSPENDED 2 - - struct usb_ep *bulk_in; - struct usb_ep *bulk_out; - struct usb_ep *intr_in; - - struct fsg_buffhd *next_buffhd_to_fill; - struct fsg_buffhd *next_buffhd_to_drain; - - int thread_wakeup_needed; - struct completion thread_notifier; - struct task_struct *thread_task; - - int cmnd_size; - u8 cmnd[MAX_COMMAND_SIZE]; - enum data_direction data_dir; - u32 data_size; - u32 data_size_from_cmnd; - u32 tag; - unsigned int lun; - u32 residue; - u32 usb_amount_left; - - /* The CB protocol offers no way for a host to know when a command - * has completed. As a result the next command may arrive early, - * and we will still have to handle it. For that reason we need - * a buffer to store new commands when using CB (or CBI, which - * does not oblige a host to wait for command completion either). */ - int cbbuf_cmnd_size; - u8 cbbuf_cmnd[MAX_COMMAND_SIZE]; - - unsigned int nluns; - struct fsg_lun *luns; - struct fsg_lun *curlun; - /* Must be the last entry */ - struct fsg_buffhd buffhds[]; -}; - -typedef void (*fsg_routine_t)(struct fsg_dev *); - -static int exception_in_progress(struct fsg_dev *fsg) -{ - return (fsg->state > FSG_STATE_IDLE); -} - -/* Make bulk-out requests be divisible by the maxpacket size */ -static void set_bulk_out_req_length(struct fsg_dev *fsg, - struct fsg_buffhd *bh, unsigned int length) -{ - unsigned int rem; - - bh->bulk_out_intended_length = length; - rem = length % fsg->bulk_out_maxpacket; - if (rem > 0) - length += fsg->bulk_out_maxpacket - rem; - bh->outreq->length = length; -} - -static struct fsg_dev *the_fsg; -static struct usb_gadget_driver fsg_driver; - - -/*-------------------------------------------------------------------------*/ - -static int fsg_set_halt(struct fsg_dev *fsg, struct usb_ep *ep) -{ - const char *name; - - if (ep == fsg->bulk_in) - name = "bulk-in"; - else if (ep == fsg->bulk_out) - name = "bulk-out"; - else - name = ep->name; - DBG(fsg, "%s set halt\n", name); - return usb_ep_set_halt(ep); -} - - -/*-------------------------------------------------------------------------*/ - -/* - * DESCRIPTORS ... most are static, but strings and (full) configuration - * descriptors are built on demand. Also the (static) config and interface - * descriptors are adjusted during fsg_bind(). - */ - -/* There is only one configuration. */ -#define CONFIG_VALUE 1 - -static struct usb_device_descriptor -device_desc = { - .bLength = sizeof device_desc, - .bDescriptorType = USB_DT_DEVICE, - - .bcdUSB = cpu_to_le16(0x0200), - .bDeviceClass = USB_CLASS_PER_INTERFACE, - - /* The next three values can be overridden by module parameters */ - .idVendor = cpu_to_le16(FSG_VENDOR_ID), - .idProduct = cpu_to_le16(FSG_PRODUCT_ID), - .bcdDevice = cpu_to_le16(0xffff), - - .iManufacturer = FSG_STRING_MANUFACTURER, - .iProduct = FSG_STRING_PRODUCT, - .iSerialNumber = FSG_STRING_SERIAL, - .bNumConfigurations = 1, -}; - -static struct usb_config_descriptor -config_desc = { - .bLength = sizeof config_desc, - .bDescriptorType = USB_DT_CONFIG, - - /* wTotalLength computed by usb_gadget_config_buf() */ - .bNumInterfaces = 1, - .bConfigurationValue = CONFIG_VALUE, - .iConfiguration = FSG_STRING_CONFIG, - .bmAttributes = USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER, - .bMaxPower = CONFIG_USB_GADGET_VBUS_DRAW / 2, -}; - - -static struct usb_qualifier_descriptor -dev_qualifier = { - .bLength = sizeof dev_qualifier, - .bDescriptorType = USB_DT_DEVICE_QUALIFIER, - - .bcdUSB = cpu_to_le16(0x0200), - .bDeviceClass = USB_CLASS_PER_INTERFACE, - - .bNumConfigurations = 1, -}; - -static int populate_bos(struct fsg_dev *fsg, u8 *buf) -{ - memcpy(buf, &fsg_bos_desc, USB_DT_BOS_SIZE); - buf += USB_DT_BOS_SIZE; - - memcpy(buf, &fsg_ext_cap_desc, USB_DT_USB_EXT_CAP_SIZE); - buf += USB_DT_USB_EXT_CAP_SIZE; - - memcpy(buf, &fsg_ss_cap_desc, USB_DT_USB_SS_CAP_SIZE); - - return USB_DT_BOS_SIZE + USB_DT_USB_SS_CAP_SIZE - + USB_DT_USB_EXT_CAP_SIZE; -} - -/* - * Config descriptors must agree with the code that sets configurations - * and with code managing interfaces and their altsettings. They must - * also handle different speeds and other-speed requests. - */ -static int populate_config_buf(struct usb_gadget *gadget, - u8 *buf, u8 type, unsigned index) -{ - enum usb_device_speed speed = gadget->speed; - int len; - const struct usb_descriptor_header **function; - - if (index > 0) - return -EINVAL; - - if (gadget_is_dualspeed(gadget) && type == USB_DT_OTHER_SPEED_CONFIG) - speed = (USB_SPEED_FULL + USB_SPEED_HIGH) - speed; - function = gadget_is_dualspeed(gadget) && speed == USB_SPEED_HIGH - ? (const struct usb_descriptor_header **)fsg_hs_function - : (const struct usb_descriptor_header **)fsg_fs_function; - - /* for now, don't advertise srp-only devices */ - if (!gadget_is_otg(gadget)) - function++; - - len = usb_gadget_config_buf(&config_desc, buf, EP0_BUFSIZE, function); - ((struct usb_config_descriptor *) buf)->bDescriptorType = type; - return len; -} - - -/*-------------------------------------------------------------------------*/ - -/* These routines may be called in process context or in_irq */ - -/* Caller must hold fsg->lock */ -static void wakeup_thread(struct fsg_dev *fsg) -{ - /* Tell the main thread that something has happened */ - fsg->thread_wakeup_needed = 1; - if (fsg->thread_task) - wake_up_process(fsg->thread_task); -} - - -static void raise_exception(struct fsg_dev *fsg, enum fsg_state new_state) -{ - unsigned long flags; - - /* Do nothing if a higher-priority exception is already in progress. - * If a lower-or-equal priority exception is in progress, preempt it - * and notify the main thread by sending it a signal. */ - spin_lock_irqsave(&fsg->lock, flags); - if (fsg->state <= new_state) { - fsg->exception_req_tag = fsg->ep0_req_tag; - fsg->state = new_state; - if (fsg->thread_task) - send_sig_info(SIGUSR1, SEND_SIG_FORCED, - fsg->thread_task); - } - spin_unlock_irqrestore(&fsg->lock, flags); -} - - -/*-------------------------------------------------------------------------*/ - -/* The disconnect callback and ep0 routines. These always run in_irq, - * except that ep0_queue() is called in the main thread to acknowledge - * completion of various requests: set config, set interface, and - * Bulk-only device reset. */ - -static void fsg_disconnect(struct usb_gadget *gadget) -{ - struct fsg_dev *fsg = get_gadget_data(gadget); - - DBG(fsg, "disconnect or port reset\n"); - raise_exception(fsg, FSG_STATE_DISCONNECT); -} - - -static int ep0_queue(struct fsg_dev *fsg) -{ - int rc; - - rc = usb_ep_queue(fsg->ep0, fsg->ep0req, GFP_ATOMIC); - if (rc != 0 && rc != -ESHUTDOWN) { - - /* We can't do much more than wait for a reset */ - WARNING(fsg, "error in submission: %s --> %d\n", - fsg->ep0->name, rc); - } - return rc; -} - -static void ep0_complete(struct usb_ep *ep, struct usb_request *req) -{ - struct fsg_dev *fsg = ep->driver_data; - - if (req->actual > 0) - dump_msg(fsg, fsg->ep0req_name, req->buf, req->actual); - if (req->status || req->actual != req->length) - DBG(fsg, "%s --> %d, %u/%u\n", __func__, - req->status, req->actual, req->length); - if (req->status == -ECONNRESET) // Request was cancelled - usb_ep_fifo_flush(ep); - - if (req->status == 0 && req->context) - ((fsg_routine_t) (req->context))(fsg); -} - - -/*-------------------------------------------------------------------------*/ - -/* Bulk and interrupt endpoint completion handlers. - * These always run in_irq. */ - -static void bulk_in_complete(struct usb_ep *ep, struct usb_request *req) -{ - struct fsg_dev *fsg = ep->driver_data; - struct fsg_buffhd *bh = req->context; - - if (req->status || req->actual != req->length) - DBG(fsg, "%s --> %d, %u/%u\n", __func__, - req->status, req->actual, req->length); - if (req->status == -ECONNRESET) // Request was cancelled - usb_ep_fifo_flush(ep); - - /* Hold the lock while we update the request and buffer states */ - smp_wmb(); - spin_lock(&fsg->lock); - bh->inreq_busy = 0; - bh->state = BUF_STATE_EMPTY; - wakeup_thread(fsg); - spin_unlock(&fsg->lock); -} - -static void bulk_out_complete(struct usb_ep *ep, struct usb_request *req) -{ - struct fsg_dev *fsg = ep->driver_data; - struct fsg_buffhd *bh = req->context; - - dump_msg(fsg, "bulk-out", req->buf, req->actual); - if (req->status || req->actual != bh->bulk_out_intended_length) - DBG(fsg, "%s --> %d, %u/%u\n", __func__, - req->status, req->actual, - bh->bulk_out_intended_length); - if (req->status == -ECONNRESET) // Request was cancelled - usb_ep_fifo_flush(ep); - - /* Hold the lock while we update the request and buffer states */ - smp_wmb(); - spin_lock(&fsg->lock); - bh->outreq_busy = 0; - bh->state = BUF_STATE_FULL; - wakeup_thread(fsg); - spin_unlock(&fsg->lock); -} - - -#ifdef CONFIG_USB_FILE_STORAGE_TEST -static void intr_in_complete(struct usb_ep *ep, struct usb_request *req) -{ - struct fsg_dev *fsg = ep->driver_data; - struct fsg_buffhd *bh = req->context; - - if (req->status || req->actual != req->length) - DBG(fsg, "%s --> %d, %u/%u\n", __func__, - req->status, req->actual, req->length); - if (req->status == -ECONNRESET) // Request was cancelled - usb_ep_fifo_flush(ep); - - /* Hold the lock while we update the request and buffer states */ - smp_wmb(); - spin_lock(&fsg->lock); - fsg->intreq_busy = 0; - bh->state = BUF_STATE_EMPTY; - wakeup_thread(fsg); - spin_unlock(&fsg->lock); -} - -#else -static void intr_in_complete(struct usb_ep *ep, struct usb_request *req) -{} -#endif /* CONFIG_USB_FILE_STORAGE_TEST */ - - -/*-------------------------------------------------------------------------*/ - -/* Ep0 class-specific handlers. These always run in_irq. */ - -#ifdef CONFIG_USB_FILE_STORAGE_TEST -static void received_cbi_adsc(struct fsg_dev *fsg, struct fsg_buffhd *bh) -{ - struct usb_request *req = fsg->ep0req; - static u8 cbi_reset_cmnd[6] = { - SEND_DIAGNOSTIC, 4, 0xff, 0xff, 0xff, 0xff}; - - /* Error in command transfer? */ - if (req->status || req->length != req->actual || - req->actual < 6 || req->actual > MAX_COMMAND_SIZE) { - - /* Not all controllers allow a protocol stall after - * receiving control-out data, but we'll try anyway. */ - fsg_set_halt(fsg, fsg->ep0); - return; // Wait for reset - } - - /* Is it the special reset command? */ - if (req->actual >= sizeof cbi_reset_cmnd && - memcmp(req->buf, cbi_reset_cmnd, - sizeof cbi_reset_cmnd) == 0) { - - /* Raise an exception to stop the current operation - * and reinitialize our state. */ - DBG(fsg, "cbi reset request\n"); - raise_exception(fsg, FSG_STATE_RESET); - return; - } - - VDBG(fsg, "CB[I] accept device-specific command\n"); - spin_lock(&fsg->lock); - - /* Save the command for later */ - if (fsg->cbbuf_cmnd_size) - WARNING(fsg, "CB[I] overwriting previous command\n"); - fsg->cbbuf_cmnd_size = req->actual; - memcpy(fsg->cbbuf_cmnd, req->buf, fsg->cbbuf_cmnd_size); - - wakeup_thread(fsg); - spin_unlock(&fsg->lock); -} - -#else -static void received_cbi_adsc(struct fsg_dev *fsg, struct fsg_buffhd *bh) -{} -#endif /* CONFIG_USB_FILE_STORAGE_TEST */ - - -static int class_setup_req(struct fsg_dev *fsg, - const struct usb_ctrlrequest *ctrl) -{ - struct usb_request *req = fsg->ep0req; - int value = -EOPNOTSUPP; - u16 w_index = le16_to_cpu(ctrl->wIndex); - u16 w_value = le16_to_cpu(ctrl->wValue); - u16 w_length = le16_to_cpu(ctrl->wLength); - - if (!fsg->config) - return value; - - /* Handle Bulk-only class-specific requests */ - if (transport_is_bbb()) { - switch (ctrl->bRequest) { - - case US_BULK_RESET_REQUEST: - if (ctrl->bRequestType != (USB_DIR_OUT | - USB_TYPE_CLASS | USB_RECIP_INTERFACE)) - break; - if (w_index != 0 || w_value != 0 || w_length != 0) { - value = -EDOM; - break; - } - - /* Raise an exception to stop the current operation - * and reinitialize our state. */ - DBG(fsg, "bulk reset request\n"); - raise_exception(fsg, FSG_STATE_RESET); - value = DELAYED_STATUS; - break; - - case US_BULK_GET_MAX_LUN: - if (ctrl->bRequestType != (USB_DIR_IN | - USB_TYPE_CLASS | USB_RECIP_INTERFACE)) - break; - if (w_index != 0 || w_value != 0 || w_length != 1) { - value = -EDOM; - break; - } - VDBG(fsg, "get max LUN\n"); - *(u8 *) req->buf = fsg->nluns - 1; - value = 1; - break; - } - } - - /* Handle CBI class-specific requests */ - else { - switch (ctrl->bRequest) { - - case USB_CBI_ADSC_REQUEST: - if (ctrl->bRequestType != (USB_DIR_OUT | - USB_TYPE_CLASS | USB_RECIP_INTERFACE)) - break; - if (w_index != 0 || w_value != 0) { - value = -EDOM; - break; - } - if (w_length > MAX_COMMAND_SIZE) { - value = -EOVERFLOW; - break; - } - value = w_length; - fsg->ep0req->context = received_cbi_adsc; - break; - } - } - - if (value == -EOPNOTSUPP) - VDBG(fsg, - "unknown class-specific control req " - "%02x.%02x v%04x i%04x l%u\n", - ctrl->bRequestType, ctrl->bRequest, - le16_to_cpu(ctrl->wValue), w_index, w_length); - return value; -} - - -/*-------------------------------------------------------------------------*/ - -/* Ep0 standard request handlers. These always run in_irq. */ - -static int standard_setup_req(struct fsg_dev *fsg, - const struct usb_ctrlrequest *ctrl) -{ - struct usb_request *req = fsg->ep0req; - int value = -EOPNOTSUPP; - u16 w_index = le16_to_cpu(ctrl->wIndex); - u16 w_value = le16_to_cpu(ctrl->wValue); - - /* Usually this just stores reply data in the pre-allocated ep0 buffer, - * but config change events will also reconfigure hardware. */ - switch (ctrl->bRequest) { - - case USB_REQ_GET_DESCRIPTOR: - if (ctrl->bRequestType != (USB_DIR_IN | USB_TYPE_STANDARD | - USB_RECIP_DEVICE)) - break; - switch (w_value >> 8) { - - 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; - case USB_DT_DEVICE_QUALIFIER: - VDBG(fsg, "get device qualifier\n"); - if (!gadget_is_dualspeed(fsg->gadget) || - fsg->gadget->speed == USB_SPEED_SUPER) - 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; - - case USB_DT_OTHER_SPEED_CONFIG: - VDBG(fsg, "get other-speed config descriptor\n"); - if (!gadget_is_dualspeed(fsg->gadget) || - fsg->gadget->speed == USB_SPEED_SUPER) - break; - goto get_config; - case USB_DT_CONFIG: - VDBG(fsg, "get configuration descriptor\n"); -get_config: - value = populate_config_buf(fsg->gadget, - req->buf, - w_value >> 8, - w_value & 0xff); - break; - - case USB_DT_STRING: - VDBG(fsg, "get string descriptor\n"); - - /* wIndex == language code */ - value = usb_gadget_get_string(&fsg_stringtab, - w_value & 0xff, req->buf); - break; - - case USB_DT_BOS: - VDBG(fsg, "get bos descriptor\n"); - - if (gadget_is_superspeed(fsg->gadget)) - value = populate_bos(fsg, req->buf); - break; - } - - break; - - /* One config, two speeds */ - case USB_REQ_SET_CONFIGURATION: - if (ctrl->bRequestType != (USB_DIR_OUT | USB_TYPE_STANDARD | - USB_RECIP_DEVICE)) - break; - VDBG(fsg, "set configuration\n"); - if (w_value == CONFIG_VALUE || w_value == 0) { - fsg->new_config = w_value; - - /* Raise an exception to wipe out previous transaction - * state (queued bufs, etc) and set the new config. */ - raise_exception(fsg, FSG_STATE_CONFIG_CHANGE); - value = DELAYED_STATUS; - } - break; - case USB_REQ_GET_CONFIGURATION: - if (ctrl->bRequestType != (USB_DIR_IN | USB_TYPE_STANDARD | - USB_RECIP_DEVICE)) - break; - VDBG(fsg, "get configuration\n"); - *(u8 *) req->buf = fsg->config; - value = 1; - break; - - case USB_REQ_SET_INTERFACE: - if (ctrl->bRequestType != (USB_DIR_OUT| USB_TYPE_STANDARD | - USB_RECIP_INTERFACE)) - break; - if (fsg->config && w_index == 0) { - - /* Raise an exception to wipe out previous transaction - * state (queued bufs, etc) and install the new - * interface altsetting. */ - raise_exception(fsg, FSG_STATE_INTERFACE_CHANGE); - value = DELAYED_STATUS; - } - break; - case USB_REQ_GET_INTERFACE: - if (ctrl->bRequestType != (USB_DIR_IN | USB_TYPE_STANDARD | - USB_RECIP_INTERFACE)) - break; - if (!fsg->config) - break; - if (w_index != 0) { - value = -EDOM; - break; - } - VDBG(fsg, "get interface\n"); - *(u8 *) req->buf = 0; - value = 1; - break; - - default: - VDBG(fsg, - "unknown control req %02x.%02x v%04x i%04x l%u\n", - ctrl->bRequestType, ctrl->bRequest, - w_value, w_index, le16_to_cpu(ctrl->wLength)); - } - - return value; -} - - -static int fsg_setup(struct usb_gadget *gadget, - const struct usb_ctrlrequest *ctrl) -{ - struct fsg_dev *fsg = get_gadget_data(gadget); - int rc; - int w_length = le16_to_cpu(ctrl->wLength); - - ++fsg->ep0_req_tag; // Record arrival of a new request - fsg->ep0req->context = NULL; - fsg->ep0req->length = 0; - dump_msg(fsg, "ep0-setup", (u8 *) ctrl, sizeof(*ctrl)); - - if ((ctrl->bRequestType & USB_TYPE_MASK) == USB_TYPE_CLASS) - rc = class_setup_req(fsg, ctrl); - else - rc = standard_setup_req(fsg, ctrl); - - /* Respond with data/status or defer until later? */ - if (rc >= 0 && rc != DELAYED_STATUS) { - rc = min(rc, w_length); - fsg->ep0req->length = rc; - fsg->ep0req->zero = rc < w_length; - fsg->ep0req_name = (ctrl->bRequestType & USB_DIR_IN ? - "ep0-in" : "ep0-out"); - rc = ep0_queue(fsg); - } - - /* Device either stalls (rc < 0) or reports success */ - return rc; -} - - -/*-------------------------------------------------------------------------*/ - -/* All the following routines run in process context */ - - -/* Use this for bulk or interrupt transfers, not ep0 */ -static void start_transfer(struct fsg_dev *fsg, struct usb_ep *ep, - struct usb_request *req, int *pbusy, - enum fsg_buffer_state *state) -{ - int rc; - - if (ep == fsg->bulk_in) - dump_msg(fsg, "bulk-in", req->buf, req->length); - else if (ep == fsg->intr_in) - dump_msg(fsg, "intr-in", req->buf, req->length); - - spin_lock_irq(&fsg->lock); - *pbusy = 1; - *state = BUF_STATE_BUSY; - spin_unlock_irq(&fsg->lock); - rc = usb_ep_queue(ep, req, GFP_KERNEL); - if (rc != 0) { - *pbusy = 0; - *state = BUF_STATE_EMPTY; - - /* We can't do much more than wait for a reset */ - - /* Note: currently the net2280 driver fails zero-length - * submissions if DMA is enabled. */ - if (rc != -ESHUTDOWN && !(rc == -EOPNOTSUPP && - req->length == 0)) - WARNING(fsg, "error in submission: %s --> %d\n", - ep->name, rc); - } -} - - -static int sleep_thread(struct fsg_dev *fsg) -{ - int rc = 0; - - /* Wait until a signal arrives or we are woken up */ - for (;;) { - try_to_freeze(); - set_current_state(TASK_INTERRUPTIBLE); - if (signal_pending(current)) { - rc = -EINTR; - break; - } - if (fsg->thread_wakeup_needed) - break; - schedule(); - } - __set_current_state(TASK_RUNNING); - fsg->thread_wakeup_needed = 0; - return rc; -} - - -/*-------------------------------------------------------------------------*/ - -static int do_read(struct fsg_dev *fsg) -{ - struct fsg_lun *curlun = fsg->curlun; - u32 lba; - struct fsg_buffhd *bh; - int rc; - u32 amount_left; - loff_t file_offset, file_offset_tmp; - unsigned int amount; - ssize_t nread; - - /* Get the starting Logical Block Address and check that it's - * not too big */ - if (fsg->cmnd[0] == READ_6) - lba = get_unaligned_be24(&fsg->cmnd[1]); - else { - lba = get_unaligned_be32(&fsg->cmnd[2]); - - /* We allow DPO (Disable Page Out = don't save data in the - * cache) and FUA (Force Unit Access = don't read from the - * cache), but we don't implement them. */ - if ((fsg->cmnd[1] & ~0x18) != 0) { - curlun->sense_data = SS_INVALID_FIELD_IN_CDB; - return -EINVAL; - } - } - if (lba >= curlun->num_sectors) { - curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; - return -EINVAL; - } - file_offset = ((loff_t) lba) << curlun->blkbits; - - /* Carry out the file reads */ - amount_left = fsg->data_size_from_cmnd; - if (unlikely(amount_left == 0)) - return -EIO; // No default reply - - for (;;) { - - /* Figure out how much we need to read: - * Try to read the remaining amount. - * But don't read more than the buffer size. - * And don't try to read past the end of the file. - */ - amount = min((unsigned int) amount_left, mod_data.buflen); - amount = min((loff_t) amount, - curlun->file_length - file_offset); - - /* Wait for the next buffer to become available */ - bh = fsg->next_buffhd_to_fill; - while (bh->state != BUF_STATE_EMPTY) { - rc = sleep_thread(fsg); - if (rc) - return rc; - } - - /* If we were asked to read past the end of file, - * end with an empty buffer. */ - if (amount == 0) { - curlun->sense_data = - SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; - curlun->sense_data_info = file_offset >> curlun->blkbits; - curlun->info_valid = 1; - bh->inreq->length = 0; - bh->state = BUF_STATE_FULL; - break; - } - - /* Perform the read */ - file_offset_tmp = file_offset; - nread = vfs_read(curlun->filp, - (char __user *) bh->buf, - amount, &file_offset_tmp); - VLDBG(curlun, "file read %u @ %llu -> %d\n", amount, - (unsigned long long) file_offset, - (int) nread); - if (signal_pending(current)) - return -EINTR; - - if (nread < 0) { - LDBG(curlun, "error in file read: %d\n", - (int) nread); - nread = 0; - } else if (nread < amount) { - LDBG(curlun, "partial file read: %d/%u\n", - (int) nread, amount); - nread = round_down(nread, curlun->blksize); - } - file_offset += nread; - amount_left -= nread; - fsg->residue -= nread; - - /* Except at the end of the transfer, nread will be - * equal to the buffer size, which is divisible by the - * bulk-in maxpacket size. - */ - bh->inreq->length = nread; - bh->state = BUF_STATE_FULL; - - /* If an error occurred, report it and its position */ - if (nread < amount) { - curlun->sense_data = SS_UNRECOVERED_READ_ERROR; - curlun->sense_data_info = file_offset >> curlun->blkbits; - curlun->info_valid = 1; - break; - } - - if (amount_left == 0) - break; // No more left to read - - /* Send this buffer and go read some more */ - bh->inreq->zero = 0; - start_transfer(fsg, fsg->bulk_in, bh->inreq, - &bh->inreq_busy, &bh->state); - fsg->next_buffhd_to_fill = bh->next; - } - - return -EIO; // No default reply -} - - -/*-------------------------------------------------------------------------*/ - -static int do_write(struct fsg_dev *fsg) -{ - struct fsg_lun *curlun = fsg->curlun; - u32 lba; - struct fsg_buffhd *bh; - int get_some_more; - u32 amount_left_to_req, amount_left_to_write; - loff_t usb_offset, file_offset, file_offset_tmp; - unsigned int amount; - ssize_t nwritten; - int rc; - - if (curlun->ro) { - curlun->sense_data = SS_WRITE_PROTECTED; - return -EINVAL; - } - spin_lock(&curlun->filp->f_lock); - curlun->filp->f_flags &= ~O_SYNC; // Default is not to wait - spin_unlock(&curlun->filp->f_lock); - - /* Get the starting Logical Block Address and check that it's - * not too big */ - if (fsg->cmnd[0] == WRITE_6) - lba = get_unaligned_be24(&fsg->cmnd[1]); - else { - lba = get_unaligned_be32(&fsg->cmnd[2]); - - /* We allow DPO (Disable Page Out = don't save data in the - * cache) and FUA (Force Unit Access = write directly to the - * medium). We don't implement DPO; we implement FUA by - * performing synchronous output. */ - if ((fsg->cmnd[1] & ~0x18) != 0) { - curlun->sense_data = SS_INVALID_FIELD_IN_CDB; - return -EINVAL; - } - /* FUA */ - if (!curlun->nofua && (fsg->cmnd[1] & 0x08)) { - spin_lock(&curlun->filp->f_lock); - curlun->filp->f_flags |= O_DSYNC; - spin_unlock(&curlun->filp->f_lock); - } - } - if (lba >= curlun->num_sectors) { - curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; - return -EINVAL; - } - - /* Carry out the file writes */ - get_some_more = 1; - file_offset = usb_offset = ((loff_t) lba) << curlun->blkbits; - amount_left_to_req = amount_left_to_write = fsg->data_size_from_cmnd; - - while (amount_left_to_write > 0) { - - /* Queue a request for more data from the host */ - bh = fsg->next_buffhd_to_fill; - if (bh->state == BUF_STATE_EMPTY && get_some_more) { - - /* Figure out how much we want to get: - * Try to get the remaining amount, - * but not more than the buffer size. - */ - amount = min(amount_left_to_req, mod_data.buflen); - - /* Beyond the end of the backing file? */ - if (usb_offset >= curlun->file_length) { - get_some_more = 0; - curlun->sense_data = - SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; - curlun->sense_data_info = usb_offset >> curlun->blkbits; - curlun->info_valid = 1; - continue; - } - - /* Get the next buffer */ - usb_offset += amount; - fsg->usb_amount_left -= amount; - amount_left_to_req -= amount; - if (amount_left_to_req == 0) - get_some_more = 0; - - /* Except at the end of the transfer, amount will be - * equal to the buffer size, which is divisible by - * the bulk-out maxpacket size. - */ - set_bulk_out_req_length(fsg, bh, amount); - start_transfer(fsg, fsg->bulk_out, bh->outreq, - &bh->outreq_busy, &bh->state); - fsg->next_buffhd_to_fill = bh->next; - continue; - } - - /* Write the received data to the backing file */ - bh = fsg->next_buffhd_to_drain; - if (bh->state == BUF_STATE_EMPTY && !get_some_more) - break; // We stopped early - if (bh->state == BUF_STATE_FULL) { - smp_rmb(); - fsg->next_buffhd_to_drain = bh->next; - bh->state = BUF_STATE_EMPTY; - - /* Did something go wrong with the transfer? */ - if (bh->outreq->status != 0) { - curlun->sense_data = SS_COMMUNICATION_FAILURE; - curlun->sense_data_info = file_offset >> curlun->blkbits; - curlun->info_valid = 1; - break; - } - - amount = bh->outreq->actual; - if (curlun->file_length - file_offset < amount) { - LERROR(curlun, - "write %u @ %llu beyond end %llu\n", - amount, (unsigned long long) file_offset, - (unsigned long long) curlun->file_length); - amount = curlun->file_length - file_offset; - } - - /* Don't accept excess data. The spec doesn't say - * what to do in this case. We'll ignore the error. - */ - amount = min(amount, bh->bulk_out_intended_length); - - /* Don't write a partial block */ - amount = round_down(amount, curlun->blksize); - if (amount == 0) - goto empty_write; - - /* Perform the write */ - file_offset_tmp = file_offset; - nwritten = vfs_write(curlun->filp, - (char __user *) bh->buf, - amount, &file_offset_tmp); - VLDBG(curlun, "file write %u @ %llu -> %d\n", amount, - (unsigned long long) file_offset, - (int) nwritten); - if (signal_pending(current)) - return -EINTR; // Interrupted! - - if (nwritten < 0) { - LDBG(curlun, "error in file write: %d\n", - (int) nwritten); - nwritten = 0; - } else if (nwritten < amount) { - LDBG(curlun, "partial file write: %d/%u\n", - (int) nwritten, amount); - nwritten = round_down(nwritten, curlun->blksize); - } - file_offset += nwritten; - amount_left_to_write -= nwritten; - fsg->residue -= nwritten; - - /* If an error occurred, report it and its position */ - if (nwritten < amount) { - curlun->sense_data = SS_WRITE_ERROR; - curlun->sense_data_info = file_offset >> curlun->blkbits; - curlun->info_valid = 1; - break; - } - - empty_write: - /* Did the host decide to stop early? */ - if (bh->outreq->actual < bh->bulk_out_intended_length) { - fsg->short_packet_received = 1; - break; - } - continue; - } - - /* Wait for something to happen */ - rc = sleep_thread(fsg); - if (rc) - return rc; - } - - return -EIO; // No default reply -} - - -/*-------------------------------------------------------------------------*/ - -static int do_synchronize_cache(struct fsg_dev *fsg) -{ - struct fsg_lun *curlun = fsg->curlun; - int rc; - - /* We ignore the requested LBA and write out all file's - * dirty data buffers. */ - rc = fsg_lun_fsync_sub(curlun); - if (rc) - curlun->sense_data = SS_WRITE_ERROR; - return 0; -} - - -/*-------------------------------------------------------------------------*/ - -static void invalidate_sub(struct fsg_lun *curlun) -{ - struct file *filp = curlun->filp; - struct inode *inode = filp->f_path.dentry->d_inode; - unsigned long rc; - - rc = invalidate_mapping_pages(inode->i_mapping, 0, -1); - VLDBG(curlun, "invalidate_mapping_pages -> %ld\n", rc); -} - -static int do_verify(struct fsg_dev *fsg) -{ - struct fsg_lun *curlun = fsg->curlun; - u32 lba; - u32 verification_length; - struct fsg_buffhd *bh = fsg->next_buffhd_to_fill; - loff_t file_offset, file_offset_tmp; - u32 amount_left; - unsigned int amount; - ssize_t nread; - - /* Get the starting Logical Block Address and check that it's - * not too big */ - lba = get_unaligned_be32(&fsg->cmnd[2]); - if (lba >= curlun->num_sectors) { - curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; - return -EINVAL; - } - - /* We allow DPO (Disable Page Out = don't save data in the - * cache) but we don't implement it. */ - if ((fsg->cmnd[1] & ~0x10) != 0) { - curlun->sense_data = SS_INVALID_FIELD_IN_CDB; - return -EINVAL; - } - - verification_length = get_unaligned_be16(&fsg->cmnd[7]); - if (unlikely(verification_length == 0)) - return -EIO; // No default reply - - /* Prepare to carry out the file verify */ - amount_left = verification_length << curlun->blkbits; - file_offset = ((loff_t) lba) << curlun->blkbits; - - /* Write out all the dirty buffers before invalidating them */ - fsg_lun_fsync_sub(curlun); - if (signal_pending(current)) - return -EINTR; - - invalidate_sub(curlun); - if (signal_pending(current)) - return -EINTR; - - /* Just try to read the requested blocks */ - while (amount_left > 0) { - - /* Figure out how much we need to read: - * Try to read the remaining amount, but not more than - * the buffer size. - * And don't try to read past the end of the file. - */ - amount = min((unsigned int) amount_left, mod_data.buflen); - amount = min((loff_t) amount, - curlun->file_length - file_offset); - if (amount == 0) { - curlun->sense_data = - SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; - curlun->sense_data_info = file_offset >> curlun->blkbits; - curlun->info_valid = 1; - break; - } - - /* Perform the read */ - file_offset_tmp = file_offset; - nread = vfs_read(curlun->filp, - (char __user *) bh->buf, - amount, &file_offset_tmp); - VLDBG(curlun, "file read %u @ %llu -> %d\n", amount, - (unsigned long long) file_offset, - (int) nread); - if (signal_pending(current)) - return -EINTR; - - if (nread < 0) { - LDBG(curlun, "error in file verify: %d\n", - (int) nread); - nread = 0; - } else if (nread < amount) { - LDBG(curlun, "partial file verify: %d/%u\n", - (int) nread, amount); - nread = round_down(nread, curlun->blksize); - } - if (nread == 0) { - curlun->sense_data = SS_UNRECOVERED_READ_ERROR; - curlun->sense_data_info = file_offset >> curlun->blkbits; - curlun->info_valid = 1; - break; - } - file_offset += nread; - amount_left -= nread; - } - return 0; -} - - -/*-------------------------------------------------------------------------*/ - -static int do_inquiry(struct fsg_dev *fsg, struct fsg_buffhd *bh) -{ - u8 *buf = (u8 *) bh->buf; - - static char vendor_id[] = "Linux "; - static char product_disk_id[] = "File-Stor Gadget"; - static char product_cdrom_id[] = "File-CD Gadget "; - - if (!fsg->curlun) { // Unsupported LUNs are okay - fsg->bad_lun_okay = 1; - memset(buf, 0, 36); - buf[0] = 0x7f; // Unsupported, no device-type - buf[4] = 31; // Additional length - return 36; - } - - memset(buf, 0, 8); - buf[0] = (mod_data.cdrom ? TYPE_ROM : TYPE_DISK); - if (mod_data.removable) - buf[1] = 0x80; - buf[2] = 2; // ANSI SCSI level 2 - buf[3] = 2; // SCSI-2 INQUIRY data format - buf[4] = 31; // Additional length - // No special options - sprintf(buf + 8, "%-8s%-16s%04x", vendor_id, - (mod_data.cdrom ? product_cdrom_id : - product_disk_id), - mod_data.release); - return 36; -} - - -static int do_request_sense(struct fsg_dev *fsg, struct fsg_buffhd *bh) -{ - struct fsg_lun *curlun = fsg->curlun; - u8 *buf = (u8 *) bh->buf; - u32 sd, sdinfo; - int valid; - - /* - * From the SCSI-2 spec., section 7.9 (Unit attention condition): - * - * If a REQUEST SENSE command is received from an initiator - * with a pending unit attention condition (before the target - * generates the contingent allegiance condition), then the - * target shall either: - * a) report any pending sense data and preserve the unit - * attention condition on the logical unit, or, - * b) report the unit attention condition, may discard any - * pending sense data, and clear the unit attention - * condition on the logical unit for that initiator. - * - * FSG normally uses option a); enable this code to use option b). - */ -#if 0 - if (curlun && curlun->unit_attention_data != SS_NO_SENSE) { - curlun->sense_data = curlun->unit_attention_data; - curlun->unit_attention_data = SS_NO_SENSE; - } -#endif - - if (!curlun) { // Unsupported LUNs are okay - fsg->bad_lun_okay = 1; - sd = SS_LOGICAL_UNIT_NOT_SUPPORTED; - sdinfo = 0; - valid = 0; - } else { - sd = curlun->sense_data; - sdinfo = curlun->sense_data_info; - valid = curlun->info_valid << 7; - curlun->sense_data = SS_NO_SENSE; - curlun->sense_data_info = 0; - curlun->info_valid = 0; - } - - memset(buf, 0, 18); - buf[0] = valid | 0x70; // Valid, current error - buf[2] = SK(sd); - put_unaligned_be32(sdinfo, &buf[3]); /* Sense information */ - buf[7] = 18 - 8; // Additional sense length - buf[12] = ASC(sd); - buf[13] = ASCQ(sd); - return 18; -} - - -static int do_read_capacity(struct fsg_dev *fsg, struct fsg_buffhd *bh) -{ - struct fsg_lun *curlun = fsg->curlun; - u32 lba = get_unaligned_be32(&fsg->cmnd[2]); - int pmi = fsg->cmnd[8]; - u8 *buf = (u8 *) bh->buf; - - /* Check the PMI and LBA fields */ - if (pmi > 1 || (pmi == 0 && lba != 0)) { - curlun->sense_data = SS_INVALID_FIELD_IN_CDB; - return -EINVAL; - } - - put_unaligned_be32(curlun->num_sectors - 1, &buf[0]); - /* Max logical block */ - put_unaligned_be32(curlun->blksize, &buf[4]); /* Block length */ - return 8; -} - - -static int do_read_header(struct fsg_dev *fsg, struct fsg_buffhd *bh) -{ - struct fsg_lun *curlun = fsg->curlun; - int msf = fsg->cmnd[1] & 0x02; - u32 lba = get_unaligned_be32(&fsg->cmnd[2]); - u8 *buf = (u8 *) bh->buf; - - if ((fsg->cmnd[1] & ~0x02) != 0) { /* Mask away MSF */ - curlun->sense_data = SS_INVALID_FIELD_IN_CDB; - return -EINVAL; - } - if (lba >= curlun->num_sectors) { - curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; - return -EINVAL; - } - - memset(buf, 0, 8); - buf[0] = 0x01; /* 2048 bytes of user data, rest is EC */ - store_cdrom_address(&buf[4], msf, lba); - return 8; -} - - -static int do_read_toc(struct fsg_dev *fsg, struct fsg_buffhd *bh) -{ - struct fsg_lun *curlun = fsg->curlun; - int msf = fsg->cmnd[1] & 0x02; - int start_track = fsg->cmnd[6]; - u8 *buf = (u8 *) bh->buf; - - if ((fsg->cmnd[1] & ~0x02) != 0 || /* Mask away MSF */ - start_track > 1) { - curlun->sense_data = SS_INVALID_FIELD_IN_CDB; - return -EINVAL; - } - - memset(buf, 0, 20); - buf[1] = (20-2); /* TOC data length */ - buf[2] = 1; /* First track number */ - buf[3] = 1; /* Last track number */ - buf[5] = 0x16; /* Data track, copying allowed */ - buf[6] = 0x01; /* Only track is number 1 */ - store_cdrom_address(&buf[8], msf, 0); - - buf[13] = 0x16; /* Lead-out track is data */ - buf[14] = 0xAA; /* Lead-out track number */ - store_cdrom_address(&buf[16], msf, curlun->num_sectors); - return 20; -} - - -static int do_mode_sense(struct fsg_dev *fsg, struct fsg_buffhd *bh) -{ - struct fsg_lun *curlun = fsg->curlun; - int mscmnd = fsg->cmnd[0]; - u8 *buf = (u8 *) bh->buf; - u8 *buf0 = buf; - int pc, page_code; - int changeable_values, all_pages; - int valid_page = 0; - int len, limit; - - if ((fsg->cmnd[1] & ~0x08) != 0) { // Mask away DBD - curlun->sense_data = SS_INVALID_FIELD_IN_CDB; - return -EINVAL; - } - pc = fsg->cmnd[2] >> 6; - page_code = fsg->cmnd[2] & 0x3f; - if (pc == 3) { - curlun->sense_data = SS_SAVING_PARAMETERS_NOT_SUPPORTED; - return -EINVAL; - } - changeable_values = (pc == 1); - all_pages = (page_code == 0x3f); - - /* Write the mode parameter header. Fixed values are: default - * medium type, no cache control (DPOFUA), and no block descriptors. - * The only variable value is the WriteProtect bit. We will fill in - * the mode data length later. */ - memset(buf, 0, 8); - if (mscmnd == MODE_SENSE) { - buf[2] = (curlun->ro ? 0x80 : 0x00); // WP, DPOFUA - buf += 4; - limit = 255; - } else { // MODE_SENSE_10 - buf[3] = (curlun->ro ? 0x80 : 0x00); // WP, DPOFUA - buf += 8; - limit = 65535; // Should really be mod_data.buflen - } - - /* No block descriptors */ - - /* The mode pages, in numerical order. The only page we support - * is the Caching page. */ - if (page_code == 0x08 || all_pages) { - valid_page = 1; - buf[0] = 0x08; // Page code - buf[1] = 10; // Page length - memset(buf+2, 0, 10); // None of the fields are changeable - - if (!changeable_values) { - buf[2] = 0x04; // Write cache enable, - // Read cache not disabled - // No cache retention priorities - put_unaligned_be16(0xffff, &buf[4]); - /* Don't disable prefetch */ - /* Minimum prefetch = 0 */ - put_unaligned_be16(0xffff, &buf[8]); - /* Maximum prefetch */ - put_unaligned_be16(0xffff, &buf[10]); - /* Maximum prefetch ceiling */ - } - buf += 12; - } - - /* Check that a valid page was requested and the mode data length - * isn't too long. */ - len = buf - buf0; - if (!valid_page || len > limit) { - curlun->sense_data = SS_INVALID_FIELD_IN_CDB; - return -EINVAL; - } - - /* Store the mode data length */ - if (mscmnd == MODE_SENSE) - buf0[0] = len - 1; - else - put_unaligned_be16(len - 2, buf0); - return len; -} - - -static int do_start_stop(struct fsg_dev *fsg) -{ - struct fsg_lun *curlun = fsg->curlun; - int loej, start; - - if (!mod_data.removable) { - curlun->sense_data = SS_INVALID_COMMAND; - return -EINVAL; - } - - // int immed = fsg->cmnd[1] & 0x01; - loej = fsg->cmnd[4] & 0x02; - start = fsg->cmnd[4] & 0x01; - -#ifdef CONFIG_USB_FILE_STORAGE_TEST - if ((fsg->cmnd[1] & ~0x01) != 0 || // Mask away Immed - (fsg->cmnd[4] & ~0x03) != 0) { // Mask LoEj, Start - curlun->sense_data = SS_INVALID_FIELD_IN_CDB; - return -EINVAL; - } - - if (!start) { - - /* Are we allowed to unload the media? */ - if (curlun->prevent_medium_removal) { - LDBG(curlun, "unload attempt prevented\n"); - curlun->sense_data = SS_MEDIUM_REMOVAL_PREVENTED; - return -EINVAL; - } - if (loej) { // Simulate an unload/eject - up_read(&fsg->filesem); - down_write(&fsg->filesem); - fsg_lun_close(curlun); - up_write(&fsg->filesem); - down_read(&fsg->filesem); - } - } else { - - /* Our emulation doesn't support mounting; the medium is - * available for use as soon as it is loaded. */ - if (!fsg_lun_is_open(curlun)) { - curlun->sense_data = SS_MEDIUM_NOT_PRESENT; - return -EINVAL; - } - } -#endif - return 0; -} - - -static int do_prevent_allow(struct fsg_dev *fsg) -{ - struct fsg_lun *curlun = fsg->curlun; - int prevent; - - if (!mod_data.removable) { - curlun->sense_data = SS_INVALID_COMMAND; - return -EINVAL; - } - - prevent = fsg->cmnd[4] & 0x01; - if ((fsg->cmnd[4] & ~0x01) != 0) { // Mask away Prevent - curlun->sense_data = SS_INVALID_FIELD_IN_CDB; - return -EINVAL; - } - - if (curlun->prevent_medium_removal && !prevent) - fsg_lun_fsync_sub(curlun); - curlun->prevent_medium_removal = prevent; - return 0; -} - - -static int do_read_format_capacities(struct fsg_dev *fsg, - struct fsg_buffhd *bh) -{ - struct fsg_lun *curlun = fsg->curlun; - u8 *buf = (u8 *) bh->buf; - - buf[0] = buf[1] = buf[2] = 0; - buf[3] = 8; // Only the Current/Maximum Capacity Descriptor - buf += 4; - - put_unaligned_be32(curlun->num_sectors, &buf[0]); - /* Number of blocks */ - put_unaligned_be32(curlun->blksize, &buf[4]); /* Block length */ - buf[4] = 0x02; /* Current capacity */ - return 12; -} - - -static int do_mode_select(struct fsg_dev *fsg, struct fsg_buffhd *bh) -{ - struct fsg_lun *curlun = fsg->curlun; - - /* We don't support MODE SELECT */ - curlun->sense_data = SS_INVALID_COMMAND; - return -EINVAL; -} - - -/*-------------------------------------------------------------------------*/ - -static int halt_bulk_in_endpoint(struct fsg_dev *fsg) -{ - int rc; - - rc = fsg_set_halt(fsg, fsg->bulk_in); - if (rc == -EAGAIN) - VDBG(fsg, "delayed bulk-in endpoint halt\n"); - while (rc != 0) { - if (rc != -EAGAIN) { - WARNING(fsg, "usb_ep_set_halt -> %d\n", rc); - rc = 0; - break; - } - - /* Wait for a short time and then try again */ - if (msleep_interruptible(100) != 0) - return -EINTR; - rc = usb_ep_set_halt(fsg->bulk_in); - } - return rc; -} - -static int wedge_bulk_in_endpoint(struct fsg_dev *fsg) -{ - int rc; - - DBG(fsg, "bulk-in set wedge\n"); - rc = usb_ep_set_wedge(fsg->bulk_in); - if (rc == -EAGAIN) - VDBG(fsg, "delayed bulk-in endpoint wedge\n"); - while (rc != 0) { - if (rc != -EAGAIN) { - WARNING(fsg, "usb_ep_set_wedge -> %d\n", rc); - rc = 0; - break; - } - - /* Wait for a short time and then try again */ - if (msleep_interruptible(100) != 0) - return -EINTR; - rc = usb_ep_set_wedge(fsg->bulk_in); - } - return rc; -} - -static int throw_away_data(struct fsg_dev *fsg) -{ - struct fsg_buffhd *bh; - u32 amount; - int rc; - - while ((bh = fsg->next_buffhd_to_drain)->state != BUF_STATE_EMPTY || - fsg->usb_amount_left > 0) { - - /* Throw away the data in a filled buffer */ - if (bh->state == BUF_STATE_FULL) { - smp_rmb(); - bh->state = BUF_STATE_EMPTY; - fsg->next_buffhd_to_drain = bh->next; - - /* A short packet or an error ends everything */ - if (bh->outreq->actual < bh->bulk_out_intended_length || - bh->outreq->status != 0) { - raise_exception(fsg, FSG_STATE_ABORT_BULK_OUT); - return -EINTR; - } - continue; - } - - /* Try to submit another request if we need one */ - bh = fsg->next_buffhd_to_fill; - if (bh->state == BUF_STATE_EMPTY && fsg->usb_amount_left > 0) { - amount = min(fsg->usb_amount_left, - (u32) mod_data.buflen); - - /* Except at the end of the transfer, amount will be - * equal to the buffer size, which is divisible by - * the bulk-out maxpacket size. - */ - set_bulk_out_req_length(fsg, bh, amount); - start_transfer(fsg, fsg->bulk_out, bh->outreq, - &bh->outreq_busy, &bh->state); - fsg->next_buffhd_to_fill = bh->next; - fsg->usb_amount_left -= amount; - continue; - } - - /* Otherwise wait for something to happen */ - rc = sleep_thread(fsg); - if (rc) - return rc; - } - return 0; -} - - -static int finish_reply(struct fsg_dev *fsg) -{ - struct fsg_buffhd *bh = fsg->next_buffhd_to_fill; - int rc = 0; - - switch (fsg->data_dir) { - case DATA_DIR_NONE: - break; // Nothing to send - - /* If we don't know whether the host wants to read or write, - * this must be CB or CBI with an unknown command. We mustn't - * try to send or receive any data. So stall both bulk pipes - * if we can and wait for a reset. */ - case DATA_DIR_UNKNOWN: - if (mod_data.can_stall) { - fsg_set_halt(fsg, fsg->bulk_out); - rc = halt_bulk_in_endpoint(fsg); - } - break; - - /* All but the last buffer of data must have already been sent */ - case DATA_DIR_TO_HOST: - if (fsg->data_size == 0) - ; // Nothing to send - - /* If there's no residue, simply send the last buffer */ - else if (fsg->residue == 0) { - bh->inreq->zero = 0; - start_transfer(fsg, fsg->bulk_in, bh->inreq, - &bh->inreq_busy, &bh->state); - fsg->next_buffhd_to_fill = bh->next; - } - - /* There is a residue. For CB and CBI, simply mark the end - * of the data with a short packet. However, if we are - * allowed to stall, there was no data at all (residue == - * data_size), and the command failed (invalid LUN or - * sense data is set), then halt the bulk-in endpoint - * instead. */ - else if (!transport_is_bbb()) { - if (mod_data.can_stall && - fsg->residue == fsg->data_size && - (!fsg->curlun || fsg->curlun->sense_data != SS_NO_SENSE)) { - bh->state = BUF_STATE_EMPTY; - rc = halt_bulk_in_endpoint(fsg); - } else { - bh->inreq->zero = 1; - start_transfer(fsg, fsg->bulk_in, bh->inreq, - &bh->inreq_busy, &bh->state); - fsg->next_buffhd_to_fill = bh->next; - } - } - - /* - * For Bulk-only, mark the end of the data with a short - * packet. If we are allowed to stall, halt the bulk-in - * endpoint. (Note: This violates the Bulk-Only Transport - * specification, which requires us to pad the data if we - * don't halt the endpoint. Presumably nobody will mind.) - */ - else { - bh->inreq->zero = 1; - start_transfer(fsg, fsg->bulk_in, bh->inreq, - &bh->inreq_busy, &bh->state); - fsg->next_buffhd_to_fill = bh->next; - if (mod_data.can_stall) - rc = halt_bulk_in_endpoint(fsg); - } - break; - - /* We have processed all we want from the data the host has sent. - * There may still be outstanding bulk-out requests. */ - case DATA_DIR_FROM_HOST: - if (fsg->residue == 0) - ; // Nothing to receive - - /* Did the host stop sending unexpectedly early? */ - else if (fsg->short_packet_received) { - raise_exception(fsg, FSG_STATE_ABORT_BULK_OUT); - rc = -EINTR; - } - - /* We haven't processed all the incoming data. Even though - * we may be allowed to stall, doing so would cause a race. - * The controller may already have ACK'ed all the remaining - * bulk-out packets, in which case the host wouldn't see a - * STALL. Not realizing the endpoint was halted, it wouldn't - * clear the halt -- leading to problems later on. */ -#if 0 - else if (mod_data.can_stall) { - fsg_set_halt(fsg, fsg->bulk_out); - raise_exception(fsg, FSG_STATE_ABORT_BULK_OUT); - rc = -EINTR; - } -#endif - - /* We can't stall. Read in the excess data and throw it - * all away. */ - else - rc = throw_away_data(fsg); - break; - } - return rc; -} - - -static int send_status(struct fsg_dev *fsg) -{ - struct fsg_lun *curlun = fsg->curlun; - struct fsg_buffhd *bh; - int rc; - u8 status = US_BULK_STAT_OK; - u32 sd, sdinfo = 0; - - /* Wait for the next buffer to become available */ - bh = fsg->next_buffhd_to_fill; - while (bh->state != BUF_STATE_EMPTY) { - rc = sleep_thread(fsg); - if (rc) - return rc; - } - - if (curlun) { - sd = curlun->sense_data; - sdinfo = curlun->sense_data_info; - } else if (fsg->bad_lun_okay) - sd = SS_NO_SENSE; - else - sd = SS_LOGICAL_UNIT_NOT_SUPPORTED; - - if (fsg->phase_error) { - DBG(fsg, "sending phase-error status\n"); - status = US_BULK_STAT_PHASE; - sd = SS_INVALID_COMMAND; - } else if (sd != SS_NO_SENSE) { - DBG(fsg, "sending command-failure status\n"); - status = US_BULK_STAT_FAIL; - VDBG(fsg, " sense data: SK x%02x, ASC x%02x, ASCQ x%02x;" - " info x%x\n", - SK(sd), ASC(sd), ASCQ(sd), sdinfo); - } - - if (transport_is_bbb()) { - struct bulk_cs_wrap *csw = bh->buf; - - /* Store and send the Bulk-only CSW */ - csw->Signature = cpu_to_le32(US_BULK_CS_SIGN); - csw->Tag = fsg->tag; - csw->Residue = cpu_to_le32(fsg->residue); - csw->Status = status; - - bh->inreq->length = US_BULK_CS_WRAP_LEN; - bh->inreq->zero = 0; - start_transfer(fsg, fsg->bulk_in, bh->inreq, - &bh->inreq_busy, &bh->state); - - } else if (mod_data.transport_type == USB_PR_CB) { - - /* Control-Bulk transport has no status phase! */ - return 0; - - } else { // USB_PR_CBI - struct interrupt_data *buf = bh->buf; - - /* Store and send the Interrupt data. UFI sends the ASC - * and ASCQ bytes. Everything else sends a Type (which - * is always 0) and the status Value. */ - if (mod_data.protocol_type == USB_SC_UFI) { - buf->bType = ASC(sd); - buf->bValue = ASCQ(sd); - } else { - buf->bType = 0; - buf->bValue = status; - } - fsg->intreq->length = CBI_INTERRUPT_DATA_LEN; - - fsg->intr_buffhd = bh; // Point to the right buffhd - fsg->intreq->buf = bh->inreq->buf; - fsg->intreq->context = bh; - start_transfer(fsg, fsg->intr_in, fsg->intreq, - &fsg->intreq_busy, &bh->state); - } - - fsg->next_buffhd_to_fill = bh->next; - return 0; -} - - -/*-------------------------------------------------------------------------*/ - -/* Check whether the command is properly formed and whether its data size - * and direction agree with the values we already have. */ -static int check_command(struct fsg_dev *fsg, int cmnd_size, - enum data_direction data_dir, unsigned int mask, - int needs_medium, const char *name) -{ - int i; - int lun = fsg->cmnd[1] >> 5; - static const char dirletter[4] = {'u', 'o', 'i', 'n'}; - char hdlen[20]; - struct fsg_lun *curlun; - - /* Adjust the expected cmnd_size for protocol encapsulation padding. - * Transparent SCSI doesn't pad. */ - if (protocol_is_scsi()) - ; - - /* There's some disagreement as to whether RBC pads commands or not. - * We'll play it safe and accept either form. */ - else if (mod_data.protocol_type == USB_SC_RBC) { - if (fsg->cmnd_size == 12) - cmnd_size = 12; - - /* All the other protocols pad to 12 bytes */ - } else - cmnd_size = 12; - - hdlen[0] = 0; - if (fsg->data_dir != DATA_DIR_UNKNOWN) - sprintf(hdlen, ", H%c=%u", dirletter[(int) fsg->data_dir], - fsg->data_size); - VDBG(fsg, "SCSI command: %s; Dc=%d, D%c=%u; Hc=%d%s\n", - name, cmnd_size, dirletter[(int) data_dir], - fsg->data_size_from_cmnd, fsg->cmnd_size, hdlen); - - /* We can't reply at all until we know the correct data direction - * and size. */ - if (fsg->data_size_from_cmnd == 0) - data_dir = DATA_DIR_NONE; - if (fsg->data_dir == DATA_DIR_UNKNOWN) { // CB or CBI - fsg->data_dir = data_dir; - fsg->data_size = fsg->data_size_from_cmnd; - - } else { // Bulk-only - if (fsg->data_size < fsg->data_size_from_cmnd) { - - /* Host data size < Device data size is a phase error. - * Carry out the command, but only transfer as much - * as we are allowed. */ - fsg->data_size_from_cmnd = fsg->data_size; - fsg->phase_error = 1; - } - } - fsg->residue = fsg->usb_amount_left = fsg->data_size; - - /* Conflicting data directions is a phase error */ - if (fsg->data_dir != data_dir && fsg->data_size_from_cmnd > 0) { - fsg->phase_error = 1; - return -EINVAL; - } - - /* Verify the length of the command itself */ - if (cmnd_size != fsg->cmnd_size) { - - /* Special case workaround: There are plenty of buggy SCSI - * implementations. Many have issues with cbw->Length - * field passing a wrong command size. For those cases we - * always try to work around the problem by using the length - * sent by the host side provided it is at least as large - * as the correct command length. - * Examples of such cases would be MS-Windows, which issues - * REQUEST SENSE with cbw->Length == 12 where it should - * be 6, and xbox360 issuing INQUIRY, TEST UNIT READY and - * REQUEST SENSE with cbw->Length == 10 where it should - * be 6 as well. - */ - if (cmnd_size <= fsg->cmnd_size) { - DBG(fsg, "%s is buggy! Expected length %d " - "but we got %d\n", name, - cmnd_size, fsg->cmnd_size); - cmnd_size = fsg->cmnd_size; - } else { - fsg->phase_error = 1; - return -EINVAL; - } - } - - /* Check that the LUN values are consistent */ - if (transport_is_bbb()) { - if (fsg->lun != lun) - DBG(fsg, "using LUN %d from CBW, " - "not LUN %d from CDB\n", - fsg->lun, lun); - } - - /* Check the LUN */ - curlun = fsg->curlun; - if (curlun) { - if (fsg->cmnd[0] != REQUEST_SENSE) { - curlun->sense_data = SS_NO_SENSE; - curlun->sense_data_info = 0; - curlun->info_valid = 0; - } - } else { - fsg->bad_lun_okay = 0; - - /* INQUIRY and REQUEST SENSE commands are explicitly allowed - * to use unsupported LUNs; all others may not. */ - if (fsg->cmnd[0] != INQUIRY && - fsg->cmnd[0] != REQUEST_SENSE) { - DBG(fsg, "unsupported LUN %d\n", fsg->lun); - return -EINVAL; - } - } - - /* If a unit attention condition exists, only INQUIRY and - * REQUEST SENSE commands are allowed; anything else must fail. */ - if (curlun && curlun->unit_attention_data != SS_NO_SENSE && - fsg->cmnd[0] != INQUIRY && - fsg->cmnd[0] != REQUEST_SENSE) { - curlun->sense_data = curlun->unit_attention_data; - curlun->unit_attention_data = SS_NO_SENSE; - return -EINVAL; - } - - /* Check that only command bytes listed in the mask are non-zero */ - fsg->cmnd[1] &= 0x1f; // Mask away the LUN - for (i = 1; i < cmnd_size; ++i) { - if (fsg->cmnd[i] && !(mask & (1 << i))) { - if (curlun) - curlun->sense_data = SS_INVALID_FIELD_IN_CDB; - return -EINVAL; - } - } - - /* If the medium isn't mounted and the command needs to access - * it, return an error. */ - if (curlun && !fsg_lun_is_open(curlun) && needs_medium) { - curlun->sense_data = SS_MEDIUM_NOT_PRESENT; - return -EINVAL; - } - - return 0; -} - -/* wrapper of check_command for data size in blocks handling */ -static int check_command_size_in_blocks(struct fsg_dev *fsg, int cmnd_size, - enum data_direction data_dir, unsigned int mask, - int needs_medium, const char *name) -{ - if (fsg->curlun) - fsg->data_size_from_cmnd <<= fsg->curlun->blkbits; - return check_command(fsg, cmnd_size, data_dir, - mask, needs_medium, name); -} - -static int do_scsi_command(struct fsg_dev *fsg) -{ - struct fsg_buffhd *bh; - int rc; - int reply = -EINVAL; - int i; - static char unknown[16]; - - dump_cdb(fsg); - - /* Wait for the next buffer to become available for data or status */ - bh = fsg->next_buffhd_to_drain = fsg->next_buffhd_to_fill; - while (bh->state != BUF_STATE_EMPTY) { - rc = sleep_thread(fsg); - if (rc) - return rc; - } - fsg->phase_error = 0; - fsg->short_packet_received = 0; - - down_read(&fsg->filesem); // We're using the backing file - switch (fsg->cmnd[0]) { - - case INQUIRY: - fsg->data_size_from_cmnd = fsg->cmnd[4]; - if ((reply = check_command(fsg, 6, DATA_DIR_TO_HOST, - (1<<4), 0, - "INQUIRY")) == 0) - reply = do_inquiry(fsg, bh); - break; - - case MODE_SELECT: - fsg->data_size_from_cmnd = fsg->cmnd[4]; - if ((reply = check_command(fsg, 6, DATA_DIR_FROM_HOST, - (1<<1) | (1<<4), 0, - "MODE SELECT(6)")) == 0) - reply = do_mode_select(fsg, bh); - break; - - case MODE_SELECT_10: - fsg->data_size_from_cmnd = get_unaligned_be16(&fsg->cmnd[7]); - if ((reply = check_command(fsg, 10, DATA_DIR_FROM_HOST, - (1<<1) | (3<<7), 0, - "MODE SELECT(10)")) == 0) - reply = do_mode_select(fsg, bh); - break; - - case MODE_SENSE: - fsg->data_size_from_cmnd = fsg->cmnd[4]; - if ((reply = check_command(fsg, 6, DATA_DIR_TO_HOST, - (1<<1) | (1<<2) | (1<<4), 0, - "MODE SENSE(6)")) == 0) - reply = do_mode_sense(fsg, bh); - break; - - case MODE_SENSE_10: - fsg->data_size_from_cmnd = get_unaligned_be16(&fsg->cmnd[7]); - if ((reply = check_command(fsg, 10, DATA_DIR_TO_HOST, - (1<<1) | (1<<2) | (3<<7), 0, - "MODE SENSE(10)")) == 0) - reply = do_mode_sense(fsg, bh); - break; - - case ALLOW_MEDIUM_REMOVAL: - fsg->data_size_from_cmnd = 0; - if ((reply = check_command(fsg, 6, DATA_DIR_NONE, - (1<<4), 0, - "PREVENT-ALLOW MEDIUM REMOVAL")) == 0) - reply = do_prevent_allow(fsg); - break; - - case READ_6: - i = fsg->cmnd[4]; - fsg->data_size_from_cmnd = (i == 0) ? 256 : i; - if ((reply = check_command_size_in_blocks(fsg, 6, - DATA_DIR_TO_HOST, - (7<<1) | (1<<4), 1, - "READ(6)")) == 0) - reply = do_read(fsg); - break; - - case READ_10: - fsg->data_size_from_cmnd = get_unaligned_be16(&fsg->cmnd[7]); - if ((reply = check_command_size_in_blocks(fsg, 10, - DATA_DIR_TO_HOST, - (1<<1) | (0xf<<2) | (3<<7), 1, - "READ(10)")) == 0) - reply = do_read(fsg); - break; - - case READ_12: - fsg->data_size_from_cmnd = get_unaligned_be32(&fsg->cmnd[6]); - if ((reply = check_command_size_in_blocks(fsg, 12, - DATA_DIR_TO_HOST, - (1<<1) | (0xf<<2) | (0xf<<6), 1, - "READ(12)")) == 0) - reply = do_read(fsg); - break; - - case READ_CAPACITY: - fsg->data_size_from_cmnd = 8; - if ((reply = check_command(fsg, 10, DATA_DIR_TO_HOST, - (0xf<<2) | (1<<8), 1, - "READ CAPACITY")) == 0) - reply = do_read_capacity(fsg, bh); - break; - - case READ_HEADER: - if (!mod_data.cdrom) - goto unknown_cmnd; - fsg->data_size_from_cmnd = get_unaligned_be16(&fsg->cmnd[7]); - if ((reply = check_command(fsg, 10, DATA_DIR_TO_HOST, - (3<<7) | (0x1f<<1), 1, - "READ HEADER")) == 0) - reply = do_read_header(fsg, bh); - break; - - case READ_TOC: - if (!mod_data.cdrom) - goto unknown_cmnd; - fsg->data_size_from_cmnd = get_unaligned_be16(&fsg->cmnd[7]); - if ((reply = check_command(fsg, 10, DATA_DIR_TO_HOST, - (7<<6) | (1<<1), 1, - "READ TOC")) == 0) - reply = do_read_toc(fsg, bh); - break; - - case READ_FORMAT_CAPACITIES: - fsg->data_size_from_cmnd = get_unaligned_be16(&fsg->cmnd[7]); - if ((reply = check_command(fsg, 10, DATA_DIR_TO_HOST, - (3<<7), 1, - "READ FORMAT CAPACITIES")) == 0) - reply = do_read_format_capacities(fsg, bh); - break; - - case REQUEST_SENSE: - fsg->data_size_from_cmnd = fsg->cmnd[4]; - if ((reply = check_command(fsg, 6, DATA_DIR_TO_HOST, - (1<<4), 0, - "REQUEST SENSE")) == 0) - reply = do_request_sense(fsg, bh); - break; - - case START_STOP: - fsg->data_size_from_cmnd = 0; - if ((reply = check_command(fsg, 6, DATA_DIR_NONE, - (1<<1) | (1<<4), 0, - "START-STOP UNIT")) == 0) - reply = do_start_stop(fsg); - break; - - case SYNCHRONIZE_CACHE: - fsg->data_size_from_cmnd = 0; - if ((reply = check_command(fsg, 10, DATA_DIR_NONE, - (0xf<<2) | (3<<7), 1, - "SYNCHRONIZE CACHE")) == 0) - reply = do_synchronize_cache(fsg); - break; - - case TEST_UNIT_READY: - fsg->data_size_from_cmnd = 0; - reply = check_command(fsg, 6, DATA_DIR_NONE, - 0, 1, - "TEST UNIT READY"); - break; - - /* Although optional, this command is used by MS-Windows. We - * support a minimal version: BytChk must be 0. */ - case VERIFY: - fsg->data_size_from_cmnd = 0; - if ((reply = check_command(fsg, 10, DATA_DIR_NONE, - (1<<1) | (0xf<<2) | (3<<7), 1, - "VERIFY")) == 0) - reply = do_verify(fsg); - break; - - case WRITE_6: - i = fsg->cmnd[4]; - fsg->data_size_from_cmnd = (i == 0) ? 256 : i; - if ((reply = check_command_size_in_blocks(fsg, 6, - DATA_DIR_FROM_HOST, - (7<<1) | (1<<4), 1, - "WRITE(6)")) == 0) - reply = do_write(fsg); - break; - - case WRITE_10: - fsg->data_size_from_cmnd = get_unaligned_be16(&fsg->cmnd[7]); - if ((reply = check_command_size_in_blocks(fsg, 10, - DATA_DIR_FROM_HOST, - (1<<1) | (0xf<<2) | (3<<7), 1, - "WRITE(10)")) == 0) - reply = do_write(fsg); - break; - - case WRITE_12: - fsg->data_size_from_cmnd = get_unaligned_be32(&fsg->cmnd[6]); - if ((reply = check_command_size_in_blocks(fsg, 12, - DATA_DIR_FROM_HOST, - (1<<1) | (0xf<<2) | (0xf<<6), 1, - "WRITE(12)")) == 0) - reply = do_write(fsg); - break; - - /* Some mandatory commands that we recognize but don't implement. - * They don't mean much in this setting. It's left as an exercise - * for anyone interested to implement RESERVE and RELEASE in terms - * of Posix locks. */ - case FORMAT_UNIT: - case RELEASE: - case RESERVE: - case SEND_DIAGNOSTIC: - // Fall through - - default: - unknown_cmnd: - fsg->data_size_from_cmnd = 0; - sprintf(unknown, "Unknown x%02x", fsg->cmnd[0]); - if ((reply = check_command(fsg, fsg->cmnd_size, - DATA_DIR_UNKNOWN, ~0, 0, unknown)) == 0) { - fsg->curlun->sense_data = SS_INVALID_COMMAND; - reply = -EINVAL; - } - break; - } - up_read(&fsg->filesem); - - if (reply == -EINTR || signal_pending(current)) - return -EINTR; - - /* Set up the single reply buffer for finish_reply() */ - if (reply == -EINVAL) - reply = 0; // Error reply length - if (reply >= 0 && fsg->data_dir == DATA_DIR_TO_HOST) { - reply = min((u32) reply, fsg->data_size_from_cmnd); - bh->inreq->length = reply; - bh->state = BUF_STATE_FULL; - fsg->residue -= reply; - } // Otherwise it's already set - - return 0; -} - - -/*-------------------------------------------------------------------------*/ - -static int received_cbw(struct fsg_dev *fsg, struct fsg_buffhd *bh) -{ - struct usb_request *req = bh->outreq; - struct bulk_cb_wrap *cbw = req->buf; - - /* Was this a real packet? Should it be ignored? */ - if (req->status || test_bit(IGNORE_BULK_OUT, &fsg->atomic_bitflags)) - return -EINVAL; - - /* Is the CBW valid? */ - if (req->actual != US_BULK_CB_WRAP_LEN || - cbw->Signature != cpu_to_le32( - US_BULK_CB_SIGN)) { - DBG(fsg, "invalid CBW: len %u sig 0x%x\n", - req->actual, - le32_to_cpu(cbw->Signature)); - - /* The Bulk-only spec says we MUST stall the IN endpoint - * (6.6.1), so it's unavoidable. It also says we must - * retain this state until the next reset, but there's - * no way to tell the controller driver it should ignore - * Clear-Feature(HALT) requests. - * - * We aren't required to halt the OUT endpoint; instead - * we can simply accept and discard any data received - * until the next reset. */ - wedge_bulk_in_endpoint(fsg); - set_bit(IGNORE_BULK_OUT, &fsg->atomic_bitflags); - return -EINVAL; - } - - /* Is the CBW meaningful? */ - if (cbw->Lun >= FSG_MAX_LUNS || cbw->Flags & ~US_BULK_FLAG_IN || - cbw->Length <= 0 || cbw->Length > MAX_COMMAND_SIZE) { - DBG(fsg, "non-meaningful CBW: lun = %u, flags = 0x%x, " - "cmdlen %u\n", - cbw->Lun, cbw->Flags, cbw->Length); - - /* We can do anything we want here, so let's stall the - * bulk pipes if we are allowed to. */ - if (mod_data.can_stall) { - fsg_set_halt(fsg, fsg->bulk_out); - halt_bulk_in_endpoint(fsg); - } - return -EINVAL; - } - - /* Save the command for later */ - fsg->cmnd_size = cbw->Length; - memcpy(fsg->cmnd, cbw->CDB, fsg->cmnd_size); - if (cbw->Flags & US_BULK_FLAG_IN) - fsg->data_dir = DATA_DIR_TO_HOST; - else - fsg->data_dir = DATA_DIR_FROM_HOST; - fsg->data_size = le32_to_cpu(cbw->DataTransferLength); - if (fsg->data_size == 0) - fsg->data_dir = DATA_DIR_NONE; - fsg->lun = cbw->Lun; - fsg->tag = cbw->Tag; - return 0; -} - - -static int get_next_command(struct fsg_dev *fsg) -{ - struct fsg_buffhd *bh; - int rc = 0; - - if (transport_is_bbb()) { - - /* Wait for the next buffer to become available */ - bh = fsg->next_buffhd_to_fill; - while (bh->state != BUF_STATE_EMPTY) { - rc = sleep_thread(fsg); - if (rc) - return rc; - } - - /* Queue a request to read a Bulk-only CBW */ - set_bulk_out_req_length(fsg, bh, US_BULK_CB_WRAP_LEN); - start_transfer(fsg, fsg->bulk_out, bh->outreq, - &bh->outreq_busy, &bh->state); - - /* We will drain the buffer in software, which means we - * can reuse it for the next filling. No need to advance - * next_buffhd_to_fill. */ - - /* Wait for the CBW to arrive */ - while (bh->state != BUF_STATE_FULL) { - rc = sleep_thread(fsg); - if (rc) - return rc; - } - smp_rmb(); - rc = received_cbw(fsg, bh); - bh->state = BUF_STATE_EMPTY; - - } else { // USB_PR_CB or USB_PR_CBI - - /* Wait for the next command to arrive */ - while (fsg->cbbuf_cmnd_size == 0) { - rc = sleep_thread(fsg); - if (rc) - return rc; - } - - /* Is the previous status interrupt request still busy? - * The host is allowed to skip reading the status, - * so we must cancel it. */ - if (fsg->intreq_busy) - usb_ep_dequeue(fsg->intr_in, fsg->intreq); - - /* Copy the command and mark the buffer empty */ - fsg->data_dir = DATA_DIR_UNKNOWN; - spin_lock_irq(&fsg->lock); - fsg->cmnd_size = fsg->cbbuf_cmnd_size; - memcpy(fsg->cmnd, fsg->cbbuf_cmnd, fsg->cmnd_size); - fsg->cbbuf_cmnd_size = 0; - spin_unlock_irq(&fsg->lock); - - /* Use LUN from the command */ - fsg->lun = fsg->cmnd[1] >> 5; - } - - /* Update current lun */ - if (fsg->lun >= 0 && fsg->lun < fsg->nluns) - fsg->curlun = &fsg->luns[fsg->lun]; - else - fsg->curlun = NULL; - - return rc; -} - - -/*-------------------------------------------------------------------------*/ - -static int enable_endpoint(struct fsg_dev *fsg, struct usb_ep *ep, - const struct usb_endpoint_descriptor *d) -{ - int rc; - - ep->driver_data = fsg; - ep->desc = d; - rc = usb_ep_enable(ep); - if (rc) - ERROR(fsg, "can't enable %s, result %d\n", ep->name, rc); - return rc; -} - -static int alloc_request(struct fsg_dev *fsg, struct usb_ep *ep, - struct usb_request **preq) -{ - *preq = usb_ep_alloc_request(ep, GFP_ATOMIC); - if (*preq) - return 0; - ERROR(fsg, "can't allocate request for %s\n", ep->name); - return -ENOMEM; -} - -/* - * Reset interface setting and re-init endpoint state (toggle etc). - * Call with altsetting < 0 to disable the interface. The only other - * available altsetting is 0, which enables the interface. - */ -static int do_set_interface(struct fsg_dev *fsg, int altsetting) -{ - int rc = 0; - int i; - const struct usb_endpoint_descriptor *d; - - if (fsg->running) - DBG(fsg, "reset interface\n"); - -reset: - /* Deallocate the requests */ - for (i = 0; i < fsg_num_buffers; ++i) { - struct fsg_buffhd *bh = &fsg->buffhds[i]; - - if (bh->inreq) { - usb_ep_free_request(fsg->bulk_in, bh->inreq); - bh->inreq = NULL; - } - if (bh->outreq) { - usb_ep_free_request(fsg->bulk_out, bh->outreq); - bh->outreq = NULL; - } - } - if (fsg->intreq) { - usb_ep_free_request(fsg->intr_in, fsg->intreq); - fsg->intreq = NULL; - } - - /* Disable the endpoints */ - if (fsg->bulk_in_enabled) { - usb_ep_disable(fsg->bulk_in); - fsg->bulk_in_enabled = 0; - } - if (fsg->bulk_out_enabled) { - usb_ep_disable(fsg->bulk_out); - fsg->bulk_out_enabled = 0; - } - if (fsg->intr_in_enabled) { - usb_ep_disable(fsg->intr_in); - fsg->intr_in_enabled = 0; - } - - fsg->running = 0; - if (altsetting < 0 || rc != 0) - return rc; - - DBG(fsg, "set interface %d\n", altsetting); - - /* Enable the endpoints */ - d = fsg_ep_desc(fsg->gadget, - &fsg_fs_bulk_in_desc, &fsg_hs_bulk_in_desc, - &fsg_ss_bulk_in_desc); - if ((rc = enable_endpoint(fsg, fsg->bulk_in, d)) != 0) - goto reset; - fsg->bulk_in_enabled = 1; - - d = fsg_ep_desc(fsg->gadget, - &fsg_fs_bulk_out_desc, &fsg_hs_bulk_out_desc, - &fsg_ss_bulk_out_desc); - if ((rc = enable_endpoint(fsg, fsg->bulk_out, d)) != 0) - goto reset; - fsg->bulk_out_enabled = 1; - fsg->bulk_out_maxpacket = usb_endpoint_maxp(d); - clear_bit(IGNORE_BULK_OUT, &fsg->atomic_bitflags); - - if (transport_is_cbi()) { - d = fsg_ep_desc(fsg->gadget, - &fsg_fs_intr_in_desc, &fsg_hs_intr_in_desc, - &fsg_ss_intr_in_desc); - if ((rc = enable_endpoint(fsg, fsg->intr_in, d)) != 0) - goto reset; - fsg->intr_in_enabled = 1; - } - - /* Allocate the requests */ - for (i = 0; i < fsg_num_buffers; ++i) { - struct fsg_buffhd *bh = &fsg->buffhds[i]; - - if ((rc = alloc_request(fsg, fsg->bulk_in, &bh->inreq)) != 0) - goto reset; - if ((rc = alloc_request(fsg, fsg->bulk_out, &bh->outreq)) != 0) - goto reset; - bh->inreq->buf = bh->outreq->buf = bh->buf; - bh->inreq->context = bh->outreq->context = bh; - bh->inreq->complete = bulk_in_complete; - bh->outreq->complete = bulk_out_complete; - } - if (transport_is_cbi()) { - if ((rc = alloc_request(fsg, fsg->intr_in, &fsg->intreq)) != 0) - goto reset; - fsg->intreq->complete = intr_in_complete; - } - - fsg->running = 1; - for (i = 0; i < fsg->nluns; ++i) - fsg->luns[i].unit_attention_data = SS_RESET_OCCURRED; - return rc; -} - - -/* - * Change our operational configuration. This code must agree with the code - * that returns config descriptors, and with interface altsetting code. - * - * It's also responsible for power management interactions. Some - * configurations might not work with our current power sources. - * For now we just assume the gadget is always self-powered. - */ -static int do_set_config(struct fsg_dev *fsg, u8 new_config) -{ - int rc = 0; - - /* Disable the single interface */ - if (fsg->config != 0) { - DBG(fsg, "reset config\n"); - fsg->config = 0; - rc = do_set_interface(fsg, -1); - } - - /* Enable the interface */ - if (new_config != 0) { - fsg->config = new_config; - if ((rc = do_set_interface(fsg, 0)) != 0) - fsg->config = 0; // Reset on errors - else - INFO(fsg, "%s config #%d\n", - usb_speed_string(fsg->gadget->speed), - fsg->config); - } - return rc; -} - - -/*-------------------------------------------------------------------------*/ - -static void handle_exception(struct fsg_dev *fsg) -{ - siginfo_t info; - int sig; - int i; - int num_active; - struct fsg_buffhd *bh; - enum fsg_state old_state; - u8 new_config; - struct fsg_lun *curlun; - unsigned int exception_req_tag; - int rc; - - /* Clear the existing signals. Anything but SIGUSR1 is converted - * into a high-priority EXIT exception. */ - for (;;) { - sig = dequeue_signal_lock(current, ¤t->blocked, &info); - if (!sig) - break; - if (sig != SIGUSR1) { - if (fsg->state < FSG_STATE_EXIT) - DBG(fsg, "Main thread exiting on signal\n"); - raise_exception(fsg, FSG_STATE_EXIT); - } - } - - /* Cancel all the pending transfers */ - if (fsg->intreq_busy) - usb_ep_dequeue(fsg->intr_in, fsg->intreq); - for (i = 0; i < fsg_num_buffers; ++i) { - bh = &fsg->buffhds[i]; - if (bh->inreq_busy) - usb_ep_dequeue(fsg->bulk_in, bh->inreq); - if (bh->outreq_busy) - usb_ep_dequeue(fsg->bulk_out, bh->outreq); - } - - /* Wait until everything is idle */ - for (;;) { - num_active = fsg->intreq_busy; - for (i = 0; i < fsg_num_buffers; ++i) { - bh = &fsg->buffhds[i]; - num_active += bh->inreq_busy + bh->outreq_busy; - } - if (num_active == 0) - break; - if (sleep_thread(fsg)) - return; - } - - /* Clear out the controller's fifos */ - if (fsg->bulk_in_enabled) - usb_ep_fifo_flush(fsg->bulk_in); - if (fsg->bulk_out_enabled) - usb_ep_fifo_flush(fsg->bulk_out); - if (fsg->intr_in_enabled) - usb_ep_fifo_flush(fsg->intr_in); - - /* Reset the I/O buffer states and pointers, the SCSI - * state, and the exception. Then invoke the handler. */ - spin_lock_irq(&fsg->lock); - - for (i = 0; i < fsg_num_buffers; ++i) { - bh = &fsg->buffhds[i]; - bh->state = BUF_STATE_EMPTY; - } - fsg->next_buffhd_to_fill = fsg->next_buffhd_to_drain = - &fsg->buffhds[0]; - - exception_req_tag = fsg->exception_req_tag; - new_config = fsg->new_config; - old_state = fsg->state; - - if (old_state == FSG_STATE_ABORT_BULK_OUT) - fsg->state = FSG_STATE_STATUS_PHASE; - else { - for (i = 0; i < fsg->nluns; ++i) { - curlun = &fsg->luns[i]; - curlun->prevent_medium_removal = 0; - curlun->sense_data = curlun->unit_attention_data = - SS_NO_SENSE; - curlun->sense_data_info = 0; - curlun->info_valid = 0; - } - fsg->state = FSG_STATE_IDLE; - } - spin_unlock_irq(&fsg->lock); - - /* Carry out any extra actions required for the exception */ - switch (old_state) { - default: - break; - - case FSG_STATE_ABORT_BULK_OUT: - send_status(fsg); - spin_lock_irq(&fsg->lock); - if (fsg->state == FSG_STATE_STATUS_PHASE) - fsg->state = FSG_STATE_IDLE; - spin_unlock_irq(&fsg->lock); - break; - - case FSG_STATE_RESET: - /* In case we were forced against our will to halt a - * bulk endpoint, clear the halt now. (The SuperH UDC - * requires this.) */ - if (test_and_clear_bit(IGNORE_BULK_OUT, &fsg->atomic_bitflags)) - usb_ep_clear_halt(fsg->bulk_in); - - if (transport_is_bbb()) { - if (fsg->ep0_req_tag == exception_req_tag) - ep0_queue(fsg); // Complete the status stage - - } else if (transport_is_cbi()) - send_status(fsg); // Status by interrupt pipe - - /* Technically this should go here, but it would only be - * a waste of time. Ditto for the INTERFACE_CHANGE and - * CONFIG_CHANGE cases. */ - // for (i = 0; i < fsg->nluns; ++i) - // fsg->luns[i].unit_attention_data = SS_RESET_OCCURRED; - break; - - case FSG_STATE_INTERFACE_CHANGE: - rc = do_set_interface(fsg, 0); - if (fsg->ep0_req_tag != exception_req_tag) - break; - if (rc != 0) // STALL on errors - fsg_set_halt(fsg, fsg->ep0); - else // Complete the status stage - ep0_queue(fsg); - break; - - case FSG_STATE_CONFIG_CHANGE: - rc = do_set_config(fsg, new_config); - if (fsg->ep0_req_tag != exception_req_tag) - break; - if (rc != 0) // STALL on errors - fsg_set_halt(fsg, fsg->ep0); - else // Complete the status stage - ep0_queue(fsg); - break; - - case FSG_STATE_DISCONNECT: - for (i = 0; i < fsg->nluns; ++i) - fsg_lun_fsync_sub(fsg->luns + i); - do_set_config(fsg, 0); // Unconfigured state - break; - - case FSG_STATE_EXIT: - case FSG_STATE_TERMINATED: - do_set_config(fsg, 0); // Free resources - spin_lock_irq(&fsg->lock); - fsg->state = FSG_STATE_TERMINATED; // Stop the thread - spin_unlock_irq(&fsg->lock); - break; - } -} - - -/*-------------------------------------------------------------------------*/ - -static int fsg_main_thread(void *fsg_) -{ - struct fsg_dev *fsg = fsg_; - - /* Allow the thread to be killed by a signal, but set the signal mask - * to block everything but INT, TERM, KILL, and USR1. */ - allow_signal(SIGINT); - allow_signal(SIGTERM); - allow_signal(SIGKILL); - allow_signal(SIGUSR1); - - /* Allow the thread to be frozen */ - set_freezable(); - - /* Arrange for userspace references to be interpreted as kernel - * pointers. That way we can pass a kernel pointer to a routine - * that expects a __user pointer and it will work okay. */ - set_fs(get_ds()); - - /* The main loop */ - while (fsg->state != FSG_STATE_TERMINATED) { - if (exception_in_progress(fsg) || signal_pending(current)) { - handle_exception(fsg); - continue; - } - - if (!fsg->running) { - sleep_thread(fsg); - continue; - } - - if (get_next_command(fsg)) - continue; - - spin_lock_irq(&fsg->lock); - if (!exception_in_progress(fsg)) - fsg->state = FSG_STATE_DATA_PHASE; - spin_unlock_irq(&fsg->lock); - - if (do_scsi_command(fsg) || finish_reply(fsg)) - continue; - - spin_lock_irq(&fsg->lock); - if (!exception_in_progress(fsg)) - fsg->state = FSG_STATE_STATUS_PHASE; - spin_unlock_irq(&fsg->lock); - - if (send_status(fsg)) - continue; - - spin_lock_irq(&fsg->lock); - if (!exception_in_progress(fsg)) - fsg->state = FSG_STATE_IDLE; - spin_unlock_irq(&fsg->lock); - } - - spin_lock_irq(&fsg->lock); - fsg->thread_task = NULL; - spin_unlock_irq(&fsg->lock); - - /* If we are exiting because of a signal, unregister the - * gadget driver. */ - if (test_and_clear_bit(REGISTERED, &fsg->atomic_bitflags)) - usb_gadget_unregister_driver(&fsg_driver); - - /* Let the unbind and cleanup routines know the thread has exited */ - complete_and_exit(&fsg->thread_notifier, 0); -} - - -/*-------------------------------------------------------------------------*/ - - -/* The write permissions and store_xxx pointers are set in fsg_bind() */ -static DEVICE_ATTR(ro, 0444, fsg_show_ro, NULL); -static DEVICE_ATTR(nofua, 0644, fsg_show_nofua, NULL); -static DEVICE_ATTR(file, 0444, fsg_show_file, NULL); - - -/*-------------------------------------------------------------------------*/ - -static void fsg_release(struct kref *ref) -{ - struct fsg_dev *fsg = container_of(ref, struct fsg_dev, ref); - - kfree(fsg->luns); - kfree(fsg); -} - -static void lun_release(struct device *dev) -{ - struct rw_semaphore *filesem = dev_get_drvdata(dev); - struct fsg_dev *fsg = - container_of(filesem, struct fsg_dev, filesem); - - kref_put(&fsg->ref, fsg_release); -} - -static void /* __init_or_exit */ fsg_unbind(struct usb_gadget *gadget) -{ - struct fsg_dev *fsg = get_gadget_data(gadget); - int i; - struct fsg_lun *curlun; - struct usb_request *req = fsg->ep0req; - - DBG(fsg, "unbind\n"); - clear_bit(REGISTERED, &fsg->atomic_bitflags); - - /* If the thread isn't already dead, tell it to exit now */ - if (fsg->state != FSG_STATE_TERMINATED) { - raise_exception(fsg, FSG_STATE_EXIT); - wait_for_completion(&fsg->thread_notifier); - - /* The cleanup routine waits for this completion also */ - complete(&fsg->thread_notifier); - } - - /* Unregister the sysfs attribute files and the LUNs */ - for (i = 0; i < fsg->nluns; ++i) { - curlun = &fsg->luns[i]; - if (curlun->registered) { - device_remove_file(&curlun->dev, &dev_attr_nofua); - device_remove_file(&curlun->dev, &dev_attr_ro); - device_remove_file(&curlun->dev, &dev_attr_file); - fsg_lun_close(curlun); - device_unregister(&curlun->dev); - curlun->registered = 0; - } - } - - /* Free the data buffers */ - for (i = 0; i < fsg_num_buffers; ++i) - kfree(fsg->buffhds[i].buf); - - /* Free the request and buffer for endpoint 0 */ - if (req) { - kfree(req->buf); - usb_ep_free_request(fsg->ep0, req); - } - - set_gadget_data(gadget, NULL); -} - - -static int __init check_parameters(struct fsg_dev *fsg) -{ - int prot; - - /* Store the default values */ - mod_data.transport_type = USB_PR_BULK; - mod_data.transport_name = "Bulk-only"; - mod_data.protocol_type = USB_SC_SCSI; - mod_data.protocol_name = "Transparent SCSI"; - - /* Some peripheral controllers are known not to be able to - * halt bulk endpoints correctly. If one of them is present, - * disable stalls. - */ - if (gadget_is_at91(fsg->gadget)) - mod_data.can_stall = 0; - - if (mod_data.release == 0xffff) - mod_data.release = get_default_bcdDevice(); - - prot = simple_strtol(mod_data.protocol_parm, NULL, 0); - -#ifdef CONFIG_USB_FILE_STORAGE_TEST - if (strnicmp(mod_data.transport_parm, "BBB", 10) == 0) { - ; // Use default setting - } else if (strnicmp(mod_data.transport_parm, "CB", 10) == 0) { - mod_data.transport_type = USB_PR_CB; - mod_data.transport_name = "Control-Bulk"; - } else if (strnicmp(mod_data.transport_parm, "CBI", 10) == 0) { - mod_data.transport_type = USB_PR_CBI; - mod_data.transport_name = "Control-Bulk-Interrupt"; - } else { - ERROR(fsg, "invalid transport: %s\n", mod_data.transport_parm); - return -EINVAL; - } - - if (strnicmp(mod_data.protocol_parm, "SCSI", 10) == 0 || - prot == USB_SC_SCSI) { - ; // Use default setting - } else if (strnicmp(mod_data.protocol_parm, "RBC", 10) == 0 || - prot == USB_SC_RBC) { - mod_data.protocol_type = USB_SC_RBC; - mod_data.protocol_name = "RBC"; - } else if (strnicmp(mod_data.protocol_parm, "8020", 4) == 0 || - strnicmp(mod_data.protocol_parm, "ATAPI", 10) == 0 || - prot == USB_SC_8020) { - mod_data.protocol_type = USB_SC_8020; - mod_data.protocol_name = "8020i (ATAPI)"; - } else if (strnicmp(mod_data.protocol_parm, "QIC", 3) == 0 || - prot == USB_SC_QIC) { - mod_data.protocol_type = USB_SC_QIC; - mod_data.protocol_name = "QIC-157"; - } else if (strnicmp(mod_data.protocol_parm, "UFI", 10) == 0 || - prot == USB_SC_UFI) { - mod_data.protocol_type = USB_SC_UFI; - mod_data.protocol_name = "UFI"; - } else if (strnicmp(mod_data.protocol_parm, "8070", 4) == 0 || - prot == USB_SC_8070) { - mod_data.protocol_type = USB_SC_8070; - mod_data.protocol_name = "8070i"; - } else { - ERROR(fsg, "invalid protocol: %s\n", mod_data.protocol_parm); - return -EINVAL; - } - - mod_data.buflen &= PAGE_CACHE_MASK; - if (mod_data.buflen <= 0) { - ERROR(fsg, "invalid buflen\n"); - return -ETOOSMALL; - } - -#endif /* CONFIG_USB_FILE_STORAGE_TEST */ - - /* Serial string handling. - * On a real device, the serial string would be loaded - * from permanent storage. */ - if (mod_data.serial) { - const char *ch; - unsigned len = 0; - - /* Sanity check : - * The CB[I] specification limits the serial string to - * 12 uppercase hexadecimal characters. - * BBB need at least 12 uppercase hexadecimal characters, - * with a maximum of 126. */ - for (ch = mod_data.serial; *ch; ++ch) { - ++len; - if ((*ch < '0' || *ch > '9') && - (*ch < 'A' || *ch > 'F')) { /* not uppercase hex */ - WARNING(fsg, - "Invalid serial string character: %c\n", - *ch); - goto no_serial; - } - } - if (len > 126 || - (mod_data.transport_type == USB_PR_BULK && len < 12) || - (mod_data.transport_type != USB_PR_BULK && len > 12)) { - WARNING(fsg, "Invalid serial string length!\n"); - goto no_serial; - } - fsg_strings[FSG_STRING_SERIAL - 1].s = mod_data.serial; - } else { - WARNING(fsg, "No serial-number string provided!\n"); - no_serial: - device_desc.iSerialNumber = 0; - } - - return 0; -} - - -static int __init fsg_bind(struct usb_gadget *gadget, - struct usb_gadget_driver *driver) -{ - struct fsg_dev *fsg = the_fsg; - int rc; - int i; - struct fsg_lun *curlun; - struct usb_ep *ep; - struct usb_request *req; - char *pathbuf, *p; - - fsg->gadget = gadget; - set_gadget_data(gadget, fsg); - fsg->ep0 = gadget->ep0; - fsg->ep0->driver_data = fsg; - - if ((rc = check_parameters(fsg)) != 0) - goto out; - - if (mod_data.removable) { // Enable the store_xxx attributes - dev_attr_file.attr.mode = 0644; - dev_attr_file.store = fsg_store_file; - if (!mod_data.cdrom) { - dev_attr_ro.attr.mode = 0644; - dev_attr_ro.store = fsg_store_ro; - } - } - - /* Only for removable media? */ - dev_attr_nofua.attr.mode = 0644; - dev_attr_nofua.store = fsg_store_nofua; - - /* Find out how many LUNs there should be */ - i = mod_data.nluns; - if (i == 0) - i = max(mod_data.num_filenames, 1u); - if (i > FSG_MAX_LUNS) { - ERROR(fsg, "invalid number of LUNs: %d\n", i); - rc = -EINVAL; - goto out; - } - - /* Create the LUNs, open their backing files, and register the - * LUN devices in sysfs. */ - fsg->luns = kzalloc(i * sizeof(struct fsg_lun), GFP_KERNEL); - if (!fsg->luns) { - rc = -ENOMEM; - goto out; - } - fsg->nluns = i; - - for (i = 0; i < fsg->nluns; ++i) { - curlun = &fsg->luns[i]; - curlun->cdrom = !!mod_data.cdrom; - curlun->ro = mod_data.cdrom || mod_data.ro[i]; - curlun->initially_ro = curlun->ro; - curlun->removable = mod_data.removable; - curlun->nofua = mod_data.nofua[i]; - curlun->dev.release = lun_release; - curlun->dev.parent = &gadget->dev; - curlun->dev.driver = &fsg_driver.driver; - dev_set_drvdata(&curlun->dev, &fsg->filesem); - dev_set_name(&curlun->dev,"%s-lun%d", - dev_name(&gadget->dev), i); - - kref_get(&fsg->ref); - rc = device_register(&curlun->dev); - if (rc) { - INFO(fsg, "failed to register LUN%d: %d\n", i, rc); - put_device(&curlun->dev); - goto out; - } - curlun->registered = 1; - - rc = device_create_file(&curlun->dev, &dev_attr_ro); - if (rc) - goto out; - rc = device_create_file(&curlun->dev, &dev_attr_nofua); - if (rc) - goto out; - rc = device_create_file(&curlun->dev, &dev_attr_file); - if (rc) - goto out; - - if (mod_data.file[i] && *mod_data.file[i]) { - rc = fsg_lun_open(curlun, mod_data.file[i]); - if (rc) - goto out; - } else if (!mod_data.removable) { - ERROR(fsg, "no file given for LUN%d\n", i); - rc = -EINVAL; - goto out; - } - } - - /* Find all the endpoints we will use */ - usb_ep_autoconfig_reset(gadget); - ep = usb_ep_autoconfig(gadget, &fsg_fs_bulk_in_desc); - if (!ep) - goto autoconf_fail; - ep->driver_data = fsg; // claim the endpoint - fsg->bulk_in = ep; - - ep = usb_ep_autoconfig(gadget, &fsg_fs_bulk_out_desc); - if (!ep) - goto autoconf_fail; - ep->driver_data = fsg; // claim the endpoint - fsg->bulk_out = ep; - - if (transport_is_cbi()) { - ep = usb_ep_autoconfig(gadget, &fsg_fs_intr_in_desc); - if (!ep) - goto autoconf_fail; - ep->driver_data = fsg; // claim the endpoint - fsg->intr_in = ep; - } - - /* Fix up the descriptors */ - 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); - - i = (transport_is_cbi() ? 3 : 2); // Number of endpoints - fsg_intf_desc.bNumEndpoints = i; - fsg_intf_desc.bInterfaceSubClass = mod_data.protocol_type; - fsg_intf_desc.bInterfaceProtocol = mod_data.transport_type; - fsg_fs_function[i + FSG_FS_FUNCTION_PRE_EP_ENTRIES] = NULL; - - if (gadget_is_dualspeed(gadget)) { - fsg_hs_function[i + FSG_HS_FUNCTION_PRE_EP_ENTRIES] = NULL; - - /* Assume endpoint addresses are the same for both speeds */ - fsg_hs_bulk_in_desc.bEndpointAddress = - fsg_fs_bulk_in_desc.bEndpointAddress; - fsg_hs_bulk_out_desc.bEndpointAddress = - fsg_fs_bulk_out_desc.bEndpointAddress; - fsg_hs_intr_in_desc.bEndpointAddress = - fsg_fs_intr_in_desc.bEndpointAddress; - } - - if (gadget_is_superspeed(gadget)) { - unsigned max_burst; - - fsg_ss_function[i + FSG_SS_FUNCTION_PRE_EP_ENTRIES] = NULL; - - /* Calculate bMaxBurst, we know packet size is 1024 */ - max_burst = min_t(unsigned, mod_data.buflen / 1024, 15); - - /* Assume endpoint addresses are the same for both speeds */ - fsg_ss_bulk_in_desc.bEndpointAddress = - fsg_fs_bulk_in_desc.bEndpointAddress; - fsg_ss_bulk_in_comp_desc.bMaxBurst = max_burst; - - fsg_ss_bulk_out_desc.bEndpointAddress = - fsg_fs_bulk_out_desc.bEndpointAddress; - fsg_ss_bulk_out_comp_desc.bMaxBurst = max_burst; - } - - if (gadget_is_otg(gadget)) - fsg_otg_desc.bmAttributes |= USB_OTG_HNP; - - rc = -ENOMEM; - - /* Allocate the request and buffer for endpoint 0 */ - fsg->ep0req = req = usb_ep_alloc_request(fsg->ep0, GFP_KERNEL); - if (!req) - goto out; - req->buf = kmalloc(EP0_BUFSIZE, GFP_KERNEL); - if (!req->buf) - goto out; - req->complete = ep0_complete; - - /* Allocate the data buffers */ - for (i = 0; i < fsg_num_buffers; ++i) { - struct fsg_buffhd *bh = &fsg->buffhds[i]; - - /* Allocate for the bulk-in endpoint. We assume that - * the buffer will also work with the bulk-out (and - * interrupt-in) endpoint. */ - bh->buf = kmalloc(mod_data.buflen, GFP_KERNEL); - if (!bh->buf) - goto out; - bh->next = bh + 1; - } - fsg->buffhds[fsg_num_buffers - 1].next = &fsg->buffhds[0]; - - /* This should reflect the actual gadget power source */ - usb_gadget_set_selfpowered(gadget); - - snprintf(fsg_string_manufacturer, sizeof fsg_string_manufacturer, - "%s %s with %s", - init_utsname()->sysname, init_utsname()->release, - gadget->name); - - fsg->thread_task = kthread_create(fsg_main_thread, fsg, - "file-storage-gadget"); - if (IS_ERR(fsg->thread_task)) { - rc = PTR_ERR(fsg->thread_task); - goto out; - } - - 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); - for (i = 0; i < fsg->nluns; ++i) { - curlun = &fsg->luns[i]; - if (fsg_lun_is_open(curlun)) { - p = NULL; - if (pathbuf) { - p = d_path(&curlun->filp->f_path, - pathbuf, PATH_MAX); - if (IS_ERR(p)) - p = NULL; - } - LINFO(curlun, "ro=%d, nofua=%d, file: %s\n", - curlun->ro, curlun->nofua, (p ? p : "(error)")); - } - } - kfree(pathbuf); - - DBG(fsg, "transport=%s (x%02x)\n", - mod_data.transport_name, mod_data.transport_type); - DBG(fsg, "protocol=%s (x%02x)\n", - mod_data.protocol_name, mod_data.protocol_type); - DBG(fsg, "VendorID=x%04x, ProductID=x%04x, Release=x%04x\n", - mod_data.vendor, mod_data.product, mod_data.release); - DBG(fsg, "removable=%d, stall=%d, cdrom=%d, buflen=%u\n", - mod_data.removable, mod_data.can_stall, - mod_data.cdrom, mod_data.buflen); - DBG(fsg, "I/O thread pid: %d\n", task_pid_nr(fsg->thread_task)); - - set_bit(REGISTERED, &fsg->atomic_bitflags); - - /* Tell the thread to start working */ - wake_up_process(fsg->thread_task); - return 0; - -autoconf_fail: - ERROR(fsg, "unable to autoconfigure all endpoints\n"); - rc = -ENOTSUPP; - -out: - fsg->state = FSG_STATE_TERMINATED; // The thread is dead - fsg_unbind(gadget); - complete(&fsg->thread_notifier); - return rc; -} - - -/*-------------------------------------------------------------------------*/ - -static void fsg_suspend(struct usb_gadget *gadget) -{ - struct fsg_dev *fsg = get_gadget_data(gadget); - - DBG(fsg, "suspend\n"); - set_bit(SUSPENDED, &fsg->atomic_bitflags); -} - -static void fsg_resume(struct usb_gadget *gadget) -{ - struct fsg_dev *fsg = get_gadget_data(gadget); - - DBG(fsg, "resume\n"); - clear_bit(SUSPENDED, &fsg->atomic_bitflags); -} - - -/*-------------------------------------------------------------------------*/ - -static __refdata struct usb_gadget_driver fsg_driver = { - .max_speed = USB_SPEED_SUPER, - .function = (char *) fsg_string_product, - .bind = fsg_bind, - .unbind = fsg_unbind, - .disconnect = fsg_disconnect, - .setup = fsg_setup, - .suspend = fsg_suspend, - .resume = fsg_resume, - - .driver = { - .name = DRIVER_NAME, - .owner = THIS_MODULE, - // .release = ... - // .suspend = ... - // .resume = ... - }, -}; - - -static int __init fsg_alloc(void) -{ - struct fsg_dev *fsg; - - fsg = kzalloc(sizeof *fsg + - fsg_num_buffers * sizeof *(fsg->buffhds), GFP_KERNEL); - - if (!fsg) - return -ENOMEM; - spin_lock_init(&fsg->lock); - init_rwsem(&fsg->filesem); - kref_init(&fsg->ref); - init_completion(&fsg->thread_notifier); - - the_fsg = fsg; - return 0; -} - - -static int __init fsg_init(void) -{ - int rc; - struct fsg_dev *fsg; - - rc = fsg_num_buffers_validate(); - if (rc != 0) - return rc; - - if ((rc = fsg_alloc()) != 0) - return rc; - fsg = the_fsg; - rc = usb_gadget_probe_driver(&fsg_driver); - if (rc != 0) - kref_put(&fsg->ref, fsg_release); - return rc; -} -module_init(fsg_init); - - -static void __exit fsg_cleanup(void) -{ - struct fsg_dev *fsg = the_fsg; - - /* Unregister the driver iff the thread hasn't already done so */ - if (test_and_clear_bit(REGISTERED, &fsg->atomic_bitflags)) - usb_gadget_unregister_driver(&fsg_driver); - - /* Wait for the thread to finish up */ - wait_for_completion(&fsg->thread_notifier); - - kref_put(&fsg->ref, fsg_release); -} -module_exit(fsg_cleanup); diff --git a/drivers/usb/gadget/fsl_udc_core.c b/drivers/usb/gadget/fsl_udc_core.c index 6ae70cba0c4a..c19f7f13790b 100644 --- a/drivers/usb/gadget/fsl_udc_core.c +++ b/drivers/usb/gadget/fsl_udc_core.c @@ -2126,7 +2126,7 @@ static int fsl_proc_read(char *page, char **start, off_t off, int count, tmp_reg = fsl_readl(&dr_regs->usbintr); t = scnprintf(next, size, - "USB Intrrupt Enable Reg:\n" + "USB Interrupt Enable Reg:\n" "Sleep Enable: %d SOF Received Enable: %d " "Reset Enable: %d\n" "System Error Enable: %d " diff --git a/drivers/usb/gadget/inode.c b/drivers/usb/gadget/inode.c index 76494cabf4e4..8ac840f25ba9 100644 --- a/drivers/usb/gadget/inode.c +++ b/drivers/usb/gadget/inode.c @@ -76,7 +76,6 @@ MODULE_LICENSE ("GPL"); /*----------------------------------------------------------------------*/ #define GADGETFS_MAGIC 0xaee71ee7 -#define DMA_ADDR_INVALID (~(dma_addr_t)0) /* /dev/gadget/$CHIP represents ep0 and the whole device */ enum ep0_state { @@ -918,7 +917,6 @@ static void clean_req (struct usb_ep *ep, struct usb_request *req) if (req->buf != dev->rbuf) { kfree(req->buf); req->buf = dev->rbuf; - req->dma = DMA_ADDR_INVALID; } req->complete = epio_complete; dev->setup_out_ready = 0; @@ -1408,7 +1406,6 @@ gadgetfs_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) dev->setup_abort = 1; req->buf = dev->rbuf; - req->dma = DMA_ADDR_INVALID; req->context = NULL; value = -EOPNOTSUPP; switch (ctrl->bRequest) { diff --git a/drivers/usb/gadget/lpc32xx_udc.c b/drivers/usb/gadget/lpc32xx_udc.c index 21a9861dabf0..d1cf1f4db16a 100644 --- a/drivers/usb/gadget/lpc32xx_udc.c +++ b/drivers/usb/gadget/lpc32xx_udc.c @@ -2399,7 +2399,7 @@ static void udc_handle_ep0_setup(struct lpc32xx_udc *udc) if (i < 0) { /* setup processing failed, force stall */ - dev_err(udc->dev, + dev_dbg(udc->dev, "req %02x.%02x protocol STALL; stat %d\n", reqtype, req, i); udc->ep0state = WAIT_FOR_SETUP; diff --git a/drivers/usb/gadget/net2280.c b/drivers/usb/gadget/net2280.c index ac335af154ba..708c0b55dcc8 100644 --- a/drivers/usb/gadget/net2280.c +++ b/drivers/usb/gadget/net2280.c @@ -9,7 +9,7 @@ * CODE STATUS HIGHLIGHTS * * This driver should work well with most "gadget" drivers, including - * the File Storage, Serial, and Ethernet/RNDIS gadget drivers + * the Mass Storage, Serial, and Ethernet/RNDIS gadget drivers * as well as Gadget Zero and Gadgetfs. * * DMA is enabled by default. Drivers using transfer queues might use diff --git a/drivers/usb/gadget/printer.c b/drivers/usb/gadget/printer.c index e156e3f26727..35bcc83d1e04 100644 --- a/drivers/usb/gadget/printer.c +++ b/drivers/usb/gadget/printer.c @@ -983,8 +983,10 @@ static int __init printer_func_bind(struct usb_configuration *c, { struct printer_dev *dev = container_of(f, struct printer_dev, function); struct usb_composite_dev *cdev = c->cdev; - struct usb_ep *in_ep, *out_ep; + struct usb_ep *in_ep; + struct usb_ep *out_ep = NULL; int id; + int ret; id = usb_interface_id(c, f); if (id < 0) @@ -1010,6 +1012,11 @@ autoconf_fail: hs_ep_in_desc.bEndpointAddress = fs_ep_in_desc.bEndpointAddress; hs_ep_out_desc.bEndpointAddress = fs_ep_out_desc.bEndpointAddress; + ret = usb_assign_descriptors(f, fs_printer_function, + hs_printer_function, NULL); + if (ret) + return ret; + dev->in_ep = in_ep; dev->out_ep = out_ep; return 0; @@ -1018,6 +1025,7 @@ autoconf_fail: static void printer_func_unbind(struct usb_configuration *c, struct usb_function *f) { + usb_free_all_descriptors(f); } static int printer_func_set_alt(struct usb_function *f, @@ -1110,8 +1118,6 @@ static int __init printer_bind_config(struct usb_configuration *c) dev = &usb_printer_gadget; dev->function.name = shortname; - dev->function.descriptors = fs_printer_function; - dev->function.hs_descriptors = hs_printer_function; dev->function.bind = printer_func_bind; dev->function.setup = printer_func_setup; dev->function.unbind = printer_func_unbind; diff --git a/drivers/usb/gadget/pxa27x_udc.h b/drivers/usb/gadget/pxa27x_udc.h index a1d268c6f2cc..79d81a4b2344 100644 --- a/drivers/usb/gadget/pxa27x_udc.h +++ b/drivers/usb/gadget/pxa27x_udc.h @@ -418,7 +418,7 @@ struct udc_stats { * @irq: udc irq * @clk: udc clock * @usb_gadget: udc gadget structure - * @driver: bound gadget (zero, g_ether, g_file_storage, ...) + * @driver: bound gadget (zero, g_ether, g_mass_storage, ...) * @dev: device * @mach: machine info, used to activate specific GPIO * @transceiver: external transceiver to handle vbus sense and D+ pullup diff --git a/drivers/usb/gadget/storage_common.c b/drivers/usb/gadget/storage_common.c index 8d9bcd8207c8..0e3ae43454a2 100644 --- a/drivers/usb/gadget/storage_common.c +++ b/drivers/usb/gadget/storage_common.c @@ -11,30 +11,10 @@ * (at your option) any later version. */ - /* * This file requires the following identifiers used in USB strings to * be defined (each of type pointer to char): - * - fsg_string_manufacturer -- name of the manufacturer - * - fsg_string_product -- name of the product - * - fsg_string_config -- name of the configuration * - fsg_string_interface -- name of the interface - * The first four are only needed when FSG_DESCRIPTORS_DEVICE_STRINGS - * macro is defined prior to including this file. - */ - -/* - * When FSG_NO_INTR_EP is defined fsg_fs_intr_in_desc and - * fsg_hs_intr_in_desc objects as well as - * FSG_FS_FUNCTION_PRE_EP_ENTRIES and FSG_HS_FUNCTION_PRE_EP_ENTRIES - * macros are not defined. - * - * When FSG_NO_DEVICE_STRINGS is defined FSG_STRING_MANUFACTURER, - * FSG_STRING_PRODUCT, FSG_STRING_SERIAL and FSG_STRING_CONFIG are not - * defined (as well as corresponding entries in string tables are - * missing) and FSG_STRING_INTERFACE has value of zero. - * - * When FSG_NO_OTG is defined fsg_otg_desc won't be defined. */ /* @@ -78,34 +58,6 @@ #define LWARN(lun, fmt, args...) dev_warn(&(lun)->dev, fmt, ## args) #define LINFO(lun, fmt, args...) dev_info(&(lun)->dev, fmt, ## args) -/* - * Keep those macros in sync with those in - * include/linux/usb/composite.h or else GCC will complain. If they - * are identical (the same names of arguments, white spaces in the - * same places) GCC will allow redefinition otherwise (even if some - * white space is removed or added) warning will be issued. - * - * Those macros are needed here because File Storage Gadget does not - * include the composite.h header. For composite gadgets those macros - * are redundant since composite.h is included any way. - * - * One could check whether those macros are already defined (which - * would indicate composite.h had been included) or not (which would - * indicate we were in FSG) but this is not done because a warning is - * desired if definitions here differ from the ones in composite.h. - * - * We want the definitions to match and be the same in File Storage - * Gadget as well as Mass Storage Function (and so composite gadgets - * using MSF). If someone changes them in composite.h it will produce - * a warning in this file when building MSF. - */ -#define DBG(d, fmt, args...) dev_dbg(&(d)->gadget->dev , fmt , ## args) -#define VDBG(d, fmt, args...) dev_vdbg(&(d)->gadget->dev , fmt , ## args) -#define ERROR(d, fmt, args...) dev_err(&(d)->gadget->dev , fmt , ## args) -#define WARNING(d, fmt, args...) dev_warn(&(d)->gadget->dev , fmt , ## args) -#define INFO(d, fmt, args...) dev_info(&(d)->gadget->dev , fmt , ## args) - - #ifdef DUMP_MSGS @@ -203,9 +155,12 @@ struct fsg_lun { struct device dev; }; -#define fsg_lun_is_open(curlun) ((curlun)->filp != NULL) +static inline bool fsg_lun_is_open(struct fsg_lun *curlun) +{ + return curlun->filp != NULL; +} -static struct fsg_lun *fsg_lun_from_dev(struct device *dev) +static inline struct fsg_lun *fsg_lun_from_dev(struct device *dev) { return container_of(dev, struct fsg_lun, dev); } @@ -308,26 +263,10 @@ static inline u32 get_unaligned_be24(u8 *buf) enum { -#ifndef FSG_NO_DEVICE_STRINGS - FSG_STRING_MANUFACTURER = 1, - FSG_STRING_PRODUCT, - FSG_STRING_SERIAL, - FSG_STRING_CONFIG, -#endif FSG_STRING_INTERFACE }; -#ifndef FSG_NO_OTG -static struct usb_otg_descriptor -fsg_otg_desc = { - .bLength = sizeof fsg_otg_desc, - .bDescriptorType = USB_DT_OTG, - - .bmAttributes = USB_OTG_SRP, -}; -#endif - /* There is only one interface. */ static struct usb_interface_descriptor @@ -367,37 +306,10 @@ fsg_fs_bulk_out_desc = { /* wMaxPacketSize set by autoconfiguration */ }; -#ifndef FSG_NO_INTR_EP - -static struct usb_endpoint_descriptor -fsg_fs_intr_in_desc = { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - - .bEndpointAddress = USB_DIR_IN, - .bmAttributes = USB_ENDPOINT_XFER_INT, - .wMaxPacketSize = cpu_to_le16(2), - .bInterval = 32, /* frames -> 32 ms */ -}; - -#ifndef FSG_NO_OTG -# define FSG_FS_FUNCTION_PRE_EP_ENTRIES 2 -#else -# define FSG_FS_FUNCTION_PRE_EP_ENTRIES 1 -#endif - -#endif - static struct usb_descriptor_header *fsg_fs_function[] = { -#ifndef FSG_NO_OTG - (struct usb_descriptor_header *) &fsg_otg_desc, -#endif (struct usb_descriptor_header *) &fsg_intf_desc, (struct usb_descriptor_header *) &fsg_fs_bulk_in_desc, (struct usb_descriptor_header *) &fsg_fs_bulk_out_desc, -#ifndef FSG_NO_INTR_EP - (struct usb_descriptor_header *) &fsg_fs_intr_in_desc, -#endif NULL, }; @@ -431,37 +343,11 @@ fsg_hs_bulk_out_desc = { .bInterval = 1, /* NAK every 1 uframe */ }; -#ifndef FSG_NO_INTR_EP - -static struct usb_endpoint_descriptor -fsg_hs_intr_in_desc = { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - - /* bEndpointAddress copied from fs_intr_in_desc during fsg_bind() */ - .bmAttributes = USB_ENDPOINT_XFER_INT, - .wMaxPacketSize = cpu_to_le16(2), - .bInterval = 9, /* 2**(9-1) = 256 uframes -> 32 ms */ -}; - -#ifndef FSG_NO_OTG -# define FSG_HS_FUNCTION_PRE_EP_ENTRIES 2 -#else -# define FSG_HS_FUNCTION_PRE_EP_ENTRIES 1 -#endif - -#endif static struct usb_descriptor_header *fsg_hs_function[] = { -#ifndef FSG_NO_OTG - (struct usb_descriptor_header *) &fsg_otg_desc, -#endif (struct usb_descriptor_header *) &fsg_intf_desc, (struct usb_descriptor_header *) &fsg_hs_bulk_in_desc, (struct usb_descriptor_header *) &fsg_hs_bulk_out_desc, -#ifndef FSG_NO_INTR_EP - (struct usb_descriptor_header *) &fsg_hs_intr_in_desc, -#endif NULL, }; @@ -499,34 +385,6 @@ static struct usb_ss_ep_comp_descriptor fsg_ss_bulk_out_comp_desc = { /*.bMaxBurst = DYNAMIC, */ }; -#ifndef FSG_NO_INTR_EP - -static struct usb_endpoint_descriptor -fsg_ss_intr_in_desc = { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - - /* bEndpointAddress copied from fs_intr_in_desc during fsg_bind() */ - .bmAttributes = USB_ENDPOINT_XFER_INT, - .wMaxPacketSize = cpu_to_le16(2), - .bInterval = 9, /* 2**(9-1) = 256 uframes -> 32 ms */ -}; - -static struct usb_ss_ep_comp_descriptor fsg_ss_intr_in_comp_desc = { - .bLength = sizeof(fsg_ss_bulk_in_comp_desc), - .bDescriptorType = USB_DT_SS_ENDPOINT_COMP, - - .wBytesPerInterval = cpu_to_le16(2), -}; - -#ifndef FSG_NO_OTG -# define FSG_SS_FUNCTION_PRE_EP_ENTRIES 2 -#else -# define FSG_SS_FUNCTION_PRE_EP_ENTRIES 1 -#endif - -#endif - static __maybe_unused struct usb_ext_cap_descriptor fsg_ext_cap_desc = { .bLength = USB_DT_USB_EXT_CAP_SIZE, .bDescriptorType = USB_DT_DEVICE_CAPABILITY, @@ -563,18 +421,11 @@ static __maybe_unused struct usb_bos_descriptor fsg_bos_desc = { }; static struct usb_descriptor_header *fsg_ss_function[] = { -#ifndef FSG_NO_OTG - (struct usb_descriptor_header *) &fsg_otg_desc, -#endif (struct usb_descriptor_header *) &fsg_intf_desc, (struct usb_descriptor_header *) &fsg_ss_bulk_in_desc, (struct usb_descriptor_header *) &fsg_ss_bulk_in_comp_desc, (struct usb_descriptor_header *) &fsg_ss_bulk_out_desc, (struct usb_descriptor_header *) &fsg_ss_bulk_out_comp_desc, -#ifndef FSG_NO_INTR_EP - (struct usb_descriptor_header *) &fsg_ss_intr_in_desc, - (struct usb_descriptor_header *) &fsg_ss_intr_in_comp_desc, -#endif NULL, }; @@ -594,12 +445,6 @@ fsg_ep_desc(struct usb_gadget *g, struct usb_endpoint_descriptor *fs, /* Static strings, in UTF-8 (for simplicity we use only ASCII characters) */ static struct usb_string fsg_strings[] = { -#ifndef FSG_NO_DEVICE_STRINGS - {FSG_STRING_MANUFACTURER, fsg_string_manufacturer}, - {FSG_STRING_PRODUCT, fsg_string_product}, - {FSG_STRING_SERIAL, ""}, - {FSG_STRING_CONFIG, fsg_string_config}, -#endif {FSG_STRING_INTERFACE, fsg_string_interface}, {} }; diff --git a/drivers/usb/gadget/tcm_usb_gadget.c b/drivers/usb/gadget/tcm_usb_gadget.c index 97e68b38cfdf..4f7f76f00c74 100644 --- a/drivers/usb/gadget/tcm_usb_gadget.c +++ b/drivers/usb/gadget/tcm_usb_gadget.c @@ -1384,7 +1384,7 @@ static struct se_node_acl *usbg_alloc_fabric_acl(struct se_portal_group *se_tpg) nacl = kzalloc(sizeof(struct usbg_nacl), GFP_KERNEL); if (!nacl) { - printk(KERN_ERR "Unable to alocate struct usbg_nacl\n"); + printk(KERN_ERR "Unable to allocate struct usbg_nacl\n"); return NULL; } @@ -2139,6 +2139,7 @@ static struct usb_descriptor_header *uasp_fs_function_desc[] = { (struct usb_descriptor_header *) &uasp_status_pipe_desc, (struct usb_descriptor_header *) &uasp_fs_cmd_desc, (struct usb_descriptor_header *) &uasp_cmd_pipe_desc, + NULL, }; static struct usb_descriptor_header *uasp_hs_function_desc[] = { @@ -2239,6 +2240,7 @@ static int usbg_bind(struct usb_configuration *c, struct usb_function *f) struct usb_gadget *gadget = c->cdev->gadget; struct usb_ep *ep; int iface; + int ret; iface = usb_interface_id(c, f); if (iface < 0) @@ -2289,6 +2291,11 @@ static int usbg_bind(struct usb_configuration *c, struct usb_function *f) uasp_ss_status_desc.bEndpointAddress; uasp_fs_cmd_desc.bEndpointAddress = uasp_ss_cmd_desc.bEndpointAddress; + ret = usb_assign_descriptors(f, uasp_fs_function_desc, + uasp_hs_function_desc, uasp_ss_function_desc); + if (ret) + goto ep_fail; + return 0; ep_fail: pr_err("Can't claim all required eps\n"); @@ -2304,6 +2311,7 @@ static void usbg_unbind(struct usb_configuration *c, struct usb_function *f) { struct f_uas *fu = to_f_uas(f); + usb_free_all_descriptors(f); kfree(fu); } @@ -2384,9 +2392,6 @@ static int usbg_cfg_bind(struct usb_configuration *c) if (!fu) return -ENOMEM; fu->function.name = "Target Function"; - fu->function.descriptors = uasp_fs_function_desc; - fu->function.hs_descriptors = uasp_hs_function_desc; - fu->function.ss_descriptors = uasp_ss_function_desc; fu->function.bind = usbg_bind; fu->function.unbind = usbg_unbind; fu->function.set_alt = usbg_set_alt; diff --git a/drivers/usb/gadget/udc-core.c b/drivers/usb/gadget/udc-core.c index f3cd9690b101..4d90a800063c 100644 --- a/drivers/usb/gadget/udc-core.c +++ b/drivers/usb/gadget/udc-core.c @@ -439,16 +439,6 @@ static DEVICE_ATTR(name, S_IRUSR, usb_udc_##param##_show, NULL) static USB_UDC_SPEED_ATTR(current_speed, speed); static USB_UDC_SPEED_ATTR(maximum_speed, max_speed); -/* TODO: Scheduled for removal in 3.8. */ -static ssize_t usb_udc_is_dualspeed_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct usb_udc *udc = container_of(dev, struct usb_udc, dev); - return snprintf(buf, PAGE_SIZE, "%d\n", - gadget_is_dualspeed(udc->gadget)); -} -static DEVICE_ATTR(is_dualspeed, S_IRUSR, usb_udc_is_dualspeed_show, NULL); - #define USB_UDC_ATTR(name) \ ssize_t usb_udc_##name##_show(struct device *dev, \ struct device_attribute *attr, char *buf) \ @@ -472,7 +462,6 @@ static struct attribute *usb_udc_attrs[] = { &dev_attr_current_speed.attr, &dev_attr_maximum_speed.attr, - &dev_attr_is_dualspeed.attr, &dev_attr_is_otg.attr, &dev_attr_is_a_peripheral.attr, &dev_attr_b_hnp_enable.attr, diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig index 3f1431d37e1c..d6bb128ce21e 100644 --- a/drivers/usb/host/Kconfig +++ b/drivers/usb/host/Kconfig @@ -95,6 +95,11 @@ config USB_EHCI_TT_NEWSCHED If unsure, say Y. +config USB_EHCI_PCI + tristate + depends on USB_EHCI_HCD && PCI + default y + config USB_EHCI_HCD_PMC_MSP tristate "EHCI support for on-chip PMC MSP71xx USB controller" depends on USB_EHCI_HCD && MSP_HAS_USB @@ -215,9 +220,13 @@ config USB_W90X900_EHCI Enables support for the W90X900 USB controller config USB_CNS3XXX_EHCI - bool "Cavium CNS3XXX EHCI Module" + bool "Cavium CNS3XXX EHCI Module (DEPRECATED)" depends on USB_EHCI_HCD && ARCH_CNS3XXX + select USB_EHCI_HCD_PLATFORM ---help--- + This option is deprecated now and the driver was removed, use + USB_EHCI_HCD_PLATFORM instead. + Enable support for the CNS3XXX SOC's on-chip EHCI controller. It is needed for high-speed (480Mbit/sec) USB 2.0 device support. @@ -333,16 +342,6 @@ config USB_OHCI_ATH79 Enables support for the built-in OHCI controller present on the Atheros AR71XX/AR7240 SoCs. -config USB_OHCI_HCD_PPC_SOC - bool "OHCI support for on-chip PPC USB controller" - depends on USB_OHCI_HCD && (STB03xxx || PPC_MPC52xx) - default y - select USB_OHCI_BIG_ENDIAN_DESC - select USB_OHCI_BIG_ENDIAN_MMIO - ---help--- - Enables support for the USB controller on the MPC52xx or - STB03xxx processor chip. If unsure, say Y. - config USB_OHCI_HCD_PPC_OF_BE bool "OHCI support for OF platform bus (big endian)" depends on USB_OHCI_HCD && PPC_OF @@ -393,9 +392,13 @@ config USB_OHCI_HCD_SSB If unsure, say N. config USB_OHCI_SH - bool "OHCI support for SuperH USB controller" + bool "OHCI support for SuperH USB controller (DEPRECATED)" depends on USB_OHCI_HCD && SUPERH + select USB_OHCI_HCD_PLATFORM ---help--- + This option is deprecated now and the driver was removed, use + USB_OHCI_HCD_PLATFORM instead. + Enables support for the on-chip OHCI controller on the SuperH. If you use the PCI OHCI controller, this option is not necessary. @@ -406,9 +409,13 @@ config USB_OHCI_EXYNOS Enable support for the Samsung Exynos SOC's on-chip OHCI controller. config USB_CNS3XXX_OHCI - bool "Cavium CNS3XXX OHCI Module" + bool "Cavium CNS3XXX OHCI Module (DEPRECATED)" depends on USB_OHCI_HCD && ARCH_CNS3XXX + select USB_OHCI_HCD_PLATFORM ---help--- + This option is deprecated now and the driver was removed, use + USB_OHCI_HCD_PLATFORM instead. + Enable support for the CNS3XXX SOC's on-chip OHCI controller. It is needed for low-speed USB 1.0 device support. @@ -423,7 +430,7 @@ config USB_OHCI_HCD_PLATFORM If unsure, say N. config USB_EHCI_HCD_PLATFORM - bool "Generic EHCI driver for a platform device" + tristate "Generic EHCI driver for a platform device" depends on USB_EHCI_HCD default n ---help--- diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile index 9e0a89ced15c..1eb4c3006e9e 100644 --- a/drivers/usb/host/Makefile +++ b/drivers/usb/host/Makefile @@ -24,6 +24,9 @@ obj-$(CONFIG_USB_WHCI_HCD) += whci/ obj-$(CONFIG_PCI) += pci-quirks.o obj-$(CONFIG_USB_EHCI_HCD) += ehci-hcd.o +obj-$(CONFIG_USB_EHCI_PCI) += ehci-pci.o +obj-$(CONFIG_USB_EHCI_HCD_PLATFORM) += ehci-platform.o + obj-$(CONFIG_USB_OXU210HP_HCD) += oxu210hp-hcd.o obj-$(CONFIG_USB_ISP116X_HCD) += isp116x-hcd.o obj-$(CONFIG_USB_ISP1362_HCD) += isp1362-hcd.o @@ -40,6 +43,5 @@ obj-$(CONFIG_USB_HWA_HCD) += hwa-hc.o obj-$(CONFIG_USB_IMX21_HCD) += imx21-hcd.o obj-$(CONFIG_USB_FSL_MPH_DR_OF) += fsl-mph-dr-of.o obj-$(CONFIG_USB_OCTEON2_COMMON) += octeon2-common.o -obj-$(CONFIG_MIPS_ALCHEMY) += alchemy-common.o obj-$(CONFIG_USB_HCD_BCMA) += bcma-hcd.o obj-$(CONFIG_USB_HCD_SSB) += ssb-hcd.o diff --git a/drivers/usb/host/ehci-atmel.c b/drivers/usb/host/ehci-atmel.c index 411bb74152eb..d23321ec0e46 100644 --- a/drivers/usb/host/ehci-atmel.c +++ b/drivers/usb/host/ehci-atmel.c @@ -53,18 +53,11 @@ static void atmel_stop_ehci(struct platform_device *pdev) static int ehci_atmel_setup(struct usb_hcd *hcd) { struct ehci_hcd *ehci = hcd_to_ehci(hcd); - int retval; /* registers start at offset 0x0 */ ehci->caps = hcd->regs; - retval = ehci_setup(hcd); - if (retval) - return retval; - - ehci_port_power(ehci, 0); - - return retval; + return ehci_setup(hcd); } static const struct hc_driver ehci_atmel_hc_driver = { diff --git a/drivers/usb/host/ehci-au1xxx.c b/drivers/usb/host/ehci-au1xxx.c deleted file mode 100644 index 65c945eb4144..000000000000 --- a/drivers/usb/host/ehci-au1xxx.c +++ /dev/null @@ -1,184 +0,0 @@ -/* - * EHCI HCD (Host Controller Driver) for USB. - * - * Bus Glue for AMD Alchemy Au1xxx - * - * Based on "ohci-au1xxx.c" by Matt Porter <mporter@kernel.crashing.org> - * - * Modified for AMD Alchemy Au1200 EHC - * by K.Boge <karsten.boge@amd.com> - * - * This file is licenced under the GPL. - */ - -#include <linux/platform_device.h> -#include <asm/mach-au1x00/au1000.h> - - -extern int usb_disabled(void); - -static int au1xxx_ehci_setup(struct usb_hcd *hcd) -{ - struct ehci_hcd *ehci = hcd_to_ehci(hcd); - int ret; - - ehci->caps = hcd->regs; - ret = ehci_setup(hcd); - - ehci->need_io_watchdog = 0; - return ret; -} - -static const struct hc_driver ehci_au1xxx_hc_driver = { - .description = hcd_name, - .product_desc = "Au1xxx EHCI", - .hcd_priv_size = sizeof(struct ehci_hcd), - - /* - * generic hardware linkage - */ - .irq = ehci_irq, - .flags = HCD_MEMORY | HCD_USB2, - - /* - * basic lifecycle operations - * - * FIXME -- ehci_init() doesn't do enough here. - * See ehci-ppc-soc for a complete implementation. - */ - .reset = au1xxx_ehci_setup, - .start = ehci_run, - .stop = ehci_stop, - .shutdown = ehci_shutdown, - - /* - * managing i/o requests and associated device resources - */ - .urb_enqueue = ehci_urb_enqueue, - .urb_dequeue = ehci_urb_dequeue, - .endpoint_disable = ehci_endpoint_disable, - .endpoint_reset = ehci_endpoint_reset, - - /* - * scheduling support - */ - .get_frame_number = ehci_get_frame, - - /* - * root hub support - */ - .hub_status_data = ehci_hub_status_data, - .hub_control = ehci_hub_control, - .bus_suspend = ehci_bus_suspend, - .bus_resume = ehci_bus_resume, - .relinquish_port = ehci_relinquish_port, - .port_handed_over = ehci_port_handed_over, - - .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete, -}; - -static int ehci_hcd_au1xxx_drv_probe(struct platform_device *pdev) -{ - struct usb_hcd *hcd; - struct resource *res; - int ret; - - if (usb_disabled()) - return -ENODEV; - - if (pdev->resource[1].flags != IORESOURCE_IRQ) { - pr_debug("resource[1] is not IORESOURCE_IRQ"); - return -ENOMEM; - } - hcd = usb_create_hcd(&ehci_au1xxx_hc_driver, &pdev->dev, "Au1xxx"); - if (!hcd) - return -ENOMEM; - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - hcd->rsrc_start = res->start; - hcd->rsrc_len = resource_size(res); - - hcd->regs = devm_request_and_ioremap(&pdev->dev, res); - if (!hcd->regs) { - pr_debug("devm_request_and_ioremap failed"); - ret = -ENOMEM; - goto err1; - } - - if (alchemy_usb_control(ALCHEMY_USB_EHCI0, 1)) { - printk(KERN_INFO "%s: controller init failed!\n", pdev->name); - ret = -ENODEV; - goto err1; - } - - ret = usb_add_hcd(hcd, pdev->resource[1].start, - IRQF_SHARED); - if (ret == 0) { - platform_set_drvdata(pdev, hcd); - return ret; - } - - alchemy_usb_control(ALCHEMY_USB_EHCI0, 0); -err1: - usb_put_hcd(hcd); - return ret; -} - -static int ehci_hcd_au1xxx_drv_remove(struct platform_device *pdev) -{ - struct usb_hcd *hcd = platform_get_drvdata(pdev); - - usb_remove_hcd(hcd); - alchemy_usb_control(ALCHEMY_USB_EHCI0, 0); - usb_put_hcd(hcd); - platform_set_drvdata(pdev, NULL); - - return 0; -} - -#ifdef CONFIG_PM -static int ehci_hcd_au1xxx_drv_suspend(struct device *dev) -{ - struct usb_hcd *hcd = dev_get_drvdata(dev); - bool do_wakeup = device_may_wakeup(dev); - int rc; - - rc = ehci_suspend(hcd, do_wakeup); - alchemy_usb_control(ALCHEMY_USB_EHCI0, 0); - - return rc; -} - -static int ehci_hcd_au1xxx_drv_resume(struct device *dev) -{ - struct usb_hcd *hcd = dev_get_drvdata(dev); - - alchemy_usb_control(ALCHEMY_USB_EHCI0, 1); - ehci_resume(hcd, false); - - return 0; -} - -static const struct dev_pm_ops au1xxx_ehci_pmops = { - .suspend = ehci_hcd_au1xxx_drv_suspend, - .resume = ehci_hcd_au1xxx_drv_resume, -}; - -#define AU1XXX_EHCI_PMOPS &au1xxx_ehci_pmops - -#else -#define AU1XXX_EHCI_PMOPS NULL -#endif - -static struct platform_driver ehci_hcd_au1xxx_driver = { - .probe = ehci_hcd_au1xxx_drv_probe, - .remove = ehci_hcd_au1xxx_drv_remove, - .shutdown = usb_hcd_platform_shutdown, - .driver = { - .name = "au1xxx-ehci", - .owner = THIS_MODULE, - .pm = AU1XXX_EHCI_PMOPS, - } -}; - -MODULE_ALIAS("platform:au1xxx-ehci"); diff --git a/drivers/usb/host/ehci-cns3xxx.c b/drivers/usb/host/ehci-cns3xxx.c deleted file mode 100644 index d91708d2e729..000000000000 --- a/drivers/usb/host/ehci-cns3xxx.c +++ /dev/null @@ -1,155 +0,0 @@ -/* - * Copyright 2008 Cavium Networks - * - * This file is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License, Version 2, as - * published by the Free Software Foundation. - */ - -#include <linux/platform_device.h> -#include <linux/atomic.h> -#include <mach/cns3xxx.h> -#include <mach/pm.h> - -static int cns3xxx_ehci_init(struct usb_hcd *hcd) -{ - struct ehci_hcd *ehci = hcd_to_ehci(hcd); - int retval; - - /* - * EHCI and OHCI share the same clock and power, - * resetting twice would cause the 1st controller been reset. - * Therefore only do power up at the first up device, and - * power down at the last down device. - * - * Set USB AHB INCR length to 16 - */ - if (atomic_inc_return(&usb_pwr_ref) == 1) { - cns3xxx_pwr_power_up(1 << PM_PLL_HM_PD_CTRL_REG_OFFSET_PLL_USB); - cns3xxx_pwr_clk_en(1 << PM_CLK_GATE_REG_OFFSET_USB_HOST); - cns3xxx_pwr_soft_rst(1 << PM_SOFT_RST_REG_OFFST_USB_HOST); - __raw_writel((__raw_readl(MISC_CHIP_CONFIG_REG) | (0X2 << 24)), - MISC_CHIP_CONFIG_REG); - } - - ehci->caps = hcd->regs; - - hcd->has_tt = 0; - - retval = ehci_setup(hcd); - if (retval) - return retval; - - ehci_port_power(ehci, 0); - - return retval; -} - -static const struct hc_driver cns3xxx_ehci_hc_driver = { - .description = hcd_name, - .product_desc = "CNS3XXX EHCI Host Controller", - .hcd_priv_size = sizeof(struct ehci_hcd), - .irq = ehci_irq, - .flags = HCD_MEMORY | HCD_USB2, - .reset = cns3xxx_ehci_init, - .start = ehci_run, - .stop = ehci_stop, - .shutdown = ehci_shutdown, - .urb_enqueue = ehci_urb_enqueue, - .urb_dequeue = ehci_urb_dequeue, - .endpoint_disable = ehci_endpoint_disable, - .endpoint_reset = ehci_endpoint_reset, - .get_frame_number = ehci_get_frame, - .hub_status_data = ehci_hub_status_data, - .hub_control = ehci_hub_control, -#ifdef CONFIG_PM - .bus_suspend = ehci_bus_suspend, - .bus_resume = ehci_bus_resume, -#endif - .relinquish_port = ehci_relinquish_port, - .port_handed_over = ehci_port_handed_over, - - .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete, -}; - -static int cns3xxx_ehci_probe(struct platform_device *pdev) -{ - struct device *dev = &pdev->dev; - struct usb_hcd *hcd; - const struct hc_driver *driver = &cns3xxx_ehci_hc_driver; - struct resource *res; - int irq; - int retval; - - if (usb_disabled()) - return -ENODEV; - - res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); - if (!res) { - dev_err(dev, "Found HC with no IRQ.\n"); - return -ENODEV; - } - irq = res->start; - - hcd = usb_create_hcd(driver, &pdev->dev, dev_name(&pdev->dev)); - if (!hcd) - return -ENOMEM; - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - dev_err(dev, "Found HC with no register addr.\n"); - retval = -ENODEV; - goto err1; - } - - hcd->rsrc_start = res->start; - hcd->rsrc_len = resource_size(res); - - hcd->regs = devm_request_and_ioremap(&pdev->dev, res); - if (hcd->regs == NULL) { - dev_dbg(dev, "error mapping memory\n"); - retval = -EFAULT; - goto err1; - } - - retval = usb_add_hcd(hcd, irq, IRQF_SHARED); - if (retval == 0) - return retval; - -err1: - usb_put_hcd(hcd); - - return retval; -} - -static int cns3xxx_ehci_remove(struct platform_device *pdev) -{ - struct usb_hcd *hcd = platform_get_drvdata(pdev); - - usb_remove_hcd(hcd); - - /* - * EHCI and OHCI share the same clock and power, - * resetting twice would cause the 1st controller been reset. - * Therefore only do power up at the first up device, and - * power down at the last down device. - */ - if (atomic_dec_return(&usb_pwr_ref) == 0) - cns3xxx_pwr_clk_dis(1 << PM_CLK_GATE_REG_OFFSET_USB_HOST); - - usb_put_hcd(hcd); - - platform_set_drvdata(pdev, NULL); - - return 0; -} - -MODULE_ALIAS("platform:cns3xxx-ehci"); - -static struct platform_driver cns3xxx_ehci_driver = { - .probe = cns3xxx_ehci_probe, - .remove = cns3xxx_ehci_remove, - .driver = { - .name = "cns3xxx-ehci", - }, -}; diff --git a/drivers/usb/host/ehci-dbg.c b/drivers/usb/host/ehci-dbg.c index 1599806e3d47..70b496dc18a0 100644 --- a/drivers/usb/host/ehci-dbg.c +++ b/drivers/usb/host/ehci-dbg.c @@ -18,21 +18,6 @@ /* this file is part of ehci-hcd.c */ -#define ehci_dbg(ehci, fmt, args...) \ - dev_dbg (ehci_to_hcd(ehci)->self.controller , fmt , ## args ) -#define ehci_err(ehci, fmt, args...) \ - dev_err (ehci_to_hcd(ehci)->self.controller , fmt , ## args ) -#define ehci_info(ehci, fmt, args...) \ - dev_info (ehci_to_hcd(ehci)->self.controller , fmt , ## args ) -#define ehci_warn(ehci, fmt, args...) \ - dev_warn (ehci_to_hcd(ehci)->self.controller , fmt , ## args ) - -#ifdef VERBOSE_DEBUG -# define ehci_vdbg ehci_dbg -#else - static inline void ehci_vdbg(struct ehci_hcd *ehci, ...) {} -#endif - #ifdef DEBUG /* check the values in the HCSPARAMS register @@ -352,11 +337,6 @@ static int debug_async_open(struct inode *, struct file *); static int debug_periodic_open(struct inode *, struct file *); static int debug_registers_open(struct inode *, struct file *); static int debug_async_open(struct inode *, struct file *); -static ssize_t debug_lpm_read(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos); -static ssize_t debug_lpm_write(struct file *file, const char __user *buffer, - size_t count, loff_t *ppos); -static int debug_lpm_close(struct inode *inode, struct file *file); static ssize_t debug_output(struct file*, char __user*, size_t, loff_t*); static int debug_close(struct inode *, struct file *); @@ -382,14 +362,6 @@ static const struct file_operations debug_registers_fops = { .release = debug_close, .llseek = default_llseek, }; -static const struct file_operations debug_lpm_fops = { - .owner = THIS_MODULE, - .open = simple_open, - .read = debug_lpm_read, - .write = debug_lpm_write, - .release = debug_lpm_close, - .llseek = noop_llseek, -}; static struct dentry *ehci_debug_root; @@ -971,86 +943,6 @@ static int debug_registers_open(struct inode *inode, struct file *file) return file->private_data ? 0 : -ENOMEM; } -static int debug_lpm_close(struct inode *inode, struct file *file) -{ - return 0; -} - -static ssize_t debug_lpm_read(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos) -{ - /* TODO: show lpm stats */ - return 0; -} - -static ssize_t debug_lpm_write(struct file *file, const char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct usb_hcd *hcd; - struct ehci_hcd *ehci; - char buf[50]; - size_t len; - u32 temp; - unsigned long port; - u32 __iomem *portsc ; - u32 params; - - hcd = bus_to_hcd(file->private_data); - ehci = hcd_to_ehci(hcd); - - len = min(count, sizeof(buf) - 1); - if (copy_from_user(buf, user_buf, len)) - return -EFAULT; - buf[len] = '\0'; - if (len > 0 && buf[len - 1] == '\n') - buf[len - 1] = '\0'; - - if (strncmp(buf, "enable", 5) == 0) { - if (strict_strtoul(buf + 7, 10, &port)) - return -EINVAL; - params = ehci_readl(ehci, &ehci->caps->hcs_params); - if (port > HCS_N_PORTS(params)) { - ehci_dbg(ehci, "ERR: LPM on bad port %lu\n", port); - return -ENODEV; - } - portsc = &ehci->regs->port_status[port-1]; - temp = ehci_readl(ehci, portsc); - if (!(temp & PORT_DEV_ADDR)) { - ehci_dbg(ehci, "LPM: no device attached\n"); - return -ENODEV; - } - temp |= PORT_LPM; - ehci_writel(ehci, temp, portsc); - printk(KERN_INFO "force enable LPM for port %lu\n", port); - } else if (strncmp(buf, "hird=", 5) == 0) { - unsigned long hird; - if (strict_strtoul(buf + 5, 16, &hird)) - return -EINVAL; - printk(KERN_INFO "setting hird %s %lu\n", buf + 6, hird); - ehci->command = (ehci->command & ~CMD_HIRD) | (hird << 24); - ehci_writel(ehci, ehci->command, &ehci->regs->command); - } else if (strncmp(buf, "disable", 7) == 0) { - if (strict_strtoul(buf + 8, 10, &port)) - return -EINVAL; - params = ehci_readl(ehci, &ehci->caps->hcs_params); - if (port > HCS_N_PORTS(params)) { - ehci_dbg(ehci, "ERR: LPM off bad port %lu\n", port); - return -ENODEV; - } - portsc = &ehci->regs->port_status[port-1]; - temp = ehci_readl(ehci, portsc); - if (!(temp & PORT_DEV_ADDR)) { - ehci_dbg(ehci, "ERR: no device attached\n"); - return -ENODEV; - } - temp &= ~PORT_LPM; - ehci_writel(ehci, temp, portsc); - printk(KERN_INFO "disabled LPM for port %lu\n", port); - } else - return -EOPNOTSUPP; - return count; -} - static inline void create_debug_files (struct ehci_hcd *ehci) { struct usb_bus *bus = &ehci_to_hcd(ehci)->self; @@ -1071,10 +963,6 @@ static inline void create_debug_files (struct ehci_hcd *ehci) &debug_registers_fops)) goto file_error; - if (!debugfs_create_file("lpm", S_IRUGO|S_IWUSR, ehci->debug_dir, bus, - &debug_lpm_fops)) - goto file_error; - return; file_error: diff --git a/drivers/usb/host/ehci-fsl.c b/drivers/usb/host/ehci-fsl.c index 0d2f35ca93f1..fd9b5424b860 100644 --- a/drivers/usb/host/ehci-fsl.c +++ b/drivers/usb/host/ehci-fsl.c @@ -349,7 +349,6 @@ static int ehci_fsl_reinit(struct ehci_hcd *ehci) { if (ehci_fsl_usb_setup(ehci)) return -EINVAL; - ehci_port_power(ehci, 0); return 0; } diff --git a/drivers/usb/host/ehci-grlib.c b/drivers/usb/host/ehci-grlib.c index 3180cb3624d9..da4269550fba 100644 --- a/drivers/usb/host/ehci-grlib.c +++ b/drivers/usb/host/ehci-grlib.c @@ -34,22 +34,6 @@ #define GRUSBHC_HCIVERSION 0x0100 /* Known value of cap. reg. HCIVERSION */ -/* called during probe() after chip reset completes */ -static int ehci_grlib_setup(struct usb_hcd *hcd) -{ - struct ehci_hcd *ehci = hcd_to_ehci(hcd); - int retval; - - retval = ehci_setup(hcd); - if (retval) - return retval; - - ehci_port_power(ehci, 1); - - return retval; -} - - static const struct hc_driver ehci_grlib_hc_driver = { .description = hcd_name, .product_desc = "GRLIB GRUSBHC EHCI", @@ -64,7 +48,7 @@ static const struct hc_driver ehci_grlib_hc_driver = { /* * basic lifecycle operations */ - .reset = ehci_grlib_setup, + .reset = ehci_setup, .start = ehci_run, .stop = ehci_stop, .shutdown = ehci_shutdown, diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index 6bf6c42481e8..c97503bb0b0e 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -39,7 +39,6 @@ #include <linux/dma-mapping.h> #include <linux/debugfs.h> #include <linux/slab.h> -#include <linux/uaccess.h> #include <asm/byteorder.h> #include <asm/io.h> @@ -108,19 +107,39 @@ static bool ignore_oc = 0; module_param (ignore_oc, bool, S_IRUGO); MODULE_PARM_DESC (ignore_oc, "ignore bogus hardware overcurrent indications"); -/* for link power management(LPM) feature */ -static unsigned int hird; -module_param(hird, int, S_IRUGO); -MODULE_PARM_DESC(hird, "host initiated resume duration, +1 for each 75us"); - #define INTR_MASK (STS_IAA | STS_FATAL | STS_PCD | STS_ERR | STS_INT) /*-------------------------------------------------------------------------*/ #include "ehci.h" -#include "ehci-dbg.c" #include "pci-quirks.h" +/* + * The MosChip MCS9990 controller updates its microframe counter + * a little before the frame counter, and occasionally we will read + * the invalid intermediate value. Avoid problems by checking the + * microframe number (the low-order 3 bits); if they are 0 then + * re-read the register to get the correct value. + */ +static unsigned ehci_moschip_read_frame_index(struct ehci_hcd *ehci) +{ + unsigned uf; + + uf = ehci_readl(ehci, &ehci->regs->frame_index); + if (unlikely((uf & 7) == 0)) + uf = ehci_readl(ehci, &ehci->regs->frame_index); + return uf; +} + +static inline unsigned ehci_read_frame_index(struct ehci_hcd *ehci) +{ + if (ehci->frame_index_bug) + return ehci_moschip_read_frame_index(ehci); + return ehci_readl(ehci, &ehci->regs->frame_index); +} + +#include "ehci-dbg.c" + /*-------------------------------------------------------------------------*/ /* @@ -293,7 +312,6 @@ static void end_unlink_intr(struct ehci_hcd *ehci, struct ehci_qh *qh); #include "ehci-timer.c" #include "ehci-hub.c" -#include "ehci-lpm.c" #include "ehci-mem.c" #include "ehci-q.c" #include "ehci-sched.c" @@ -353,24 +371,6 @@ static void ehci_shutdown(struct usb_hcd *hcd) hrtimer_cancel(&ehci->hrtimer); } -static void ehci_port_power (struct ehci_hcd *ehci, int is_on) -{ - unsigned port; - - if (!HCS_PPC (ehci->hcs_params)) - return; - - ehci_dbg (ehci, "...power%s ports...\n", is_on ? "up" : "down"); - for (port = HCS_N_PORTS (ehci->hcs_params); port > 0; ) - (void) ehci_hub_control(ehci_to_hcd(ehci), - is_on ? SetPortFeature : ClearPortFeature, - USB_PORT_FEAT_POWER, - port--, NULL, 0); - /* Flush those writes */ - ehci_readl(ehci, &ehci->regs->command); - msleep(20); -} - /*-------------------------------------------------------------------------*/ /* @@ -503,7 +503,7 @@ static int ehci_init(struct usb_hcd *hcd) /* controllers may cache some of the periodic schedule ... */ if (HCC_ISOC_CACHE(hcc_params)) // full frame cache - ehci->i_thresh = 2 + 8; + ehci->i_thresh = 0; else // N microframes cached ehci->i_thresh = 2 + HCC_ISOC_THRES(hcc_params); @@ -555,17 +555,6 @@ static int ehci_init(struct usb_hcd *hcd) temp &= ~(3 << 2); temp |= (EHCI_TUNE_FLS << 2); } - if (HCC_LPM(hcc_params)) { - /* support link power management EHCI 1.1 addendum */ - ehci_dbg(ehci, "support lpm\n"); - ehci->has_lpm = 1; - if (hird > 0xf) { - ehci_dbg(ehci, "hird %d invalid, use default 0", - hird); - hird = 0; - } - temp |= hird << 24; - } ehci->command = temp; /* Accept arbitrarily long scatter-gather lists */ @@ -660,7 +649,7 @@ static int ehci_run (struct usb_hcd *hcd) return 0; } -static int ehci_setup(struct usb_hcd *hcd) +int ehci_setup(struct usb_hcd *hcd) { struct ehci_hcd *ehci = hcd_to_ehci(hcd); int retval; @@ -691,6 +680,7 @@ static int ehci_setup(struct usb_hcd *hcd) return 0; } +EXPORT_SYMBOL_GPL(ehci_setup); /*-------------------------------------------------------------------------*/ @@ -1096,7 +1086,7 @@ static int ehci_get_frame (struct usb_hcd *hcd) /* These routines handle the generic parts of controller suspend/resume */ -static int __maybe_unused ehci_suspend(struct usb_hcd *hcd, bool do_wakeup) +int ehci_suspend(struct usb_hcd *hcd, bool do_wakeup) { struct ehci_hcd *ehci = hcd_to_ehci(hcd); @@ -1119,9 +1109,10 @@ static int __maybe_unused ehci_suspend(struct usb_hcd *hcd, bool do_wakeup) return 0; } +EXPORT_SYMBOL_GPL(ehci_suspend); /* Returns 0 if power was preserved, 1 if power was lost */ -static int __maybe_unused ehci_resume(struct usb_hcd *hcd, bool hibernated) +int ehci_resume(struct usb_hcd *hcd, bool hibernated) { struct ehci_hcd *ehci = hcd_to_ehci(hcd); @@ -1177,33 +1168,83 @@ static int __maybe_unused ehci_resume(struct usb_hcd *hcd, bool hibernated) ehci->rh_state = EHCI_RH_SUSPENDED; spin_unlock_irq(&ehci->lock); - /* here we "know" root ports should always stay powered */ - ehci_port_power(ehci, 1); - return 1; } +EXPORT_SYMBOL_GPL(ehci_resume); #endif /*-------------------------------------------------------------------------*/ /* - * The EHCI in ChipIdea HDRC cannot be a separate module or device, - * because its registers (and irq) are shared between host/gadget/otg - * functions and in order to facilitate role switching we cannot - * give the ehci driver exclusive access to those. + * Generic structure: This gets copied for platform drivers so that + * individual entries can be overridden as needed. */ -#ifndef CHIPIDEA_EHCI + +static const struct hc_driver ehci_hc_driver = { + .description = hcd_name, + .product_desc = "EHCI Host Controller", + .hcd_priv_size = sizeof(struct ehci_hcd), + + /* + * generic hardware linkage + */ + .irq = ehci_irq, + .flags = HCD_MEMORY | HCD_USB2, + + /* + * basic lifecycle operations + */ + .reset = ehci_setup, + .start = ehci_run, + .stop = ehci_stop, + .shutdown = ehci_shutdown, + + /* + * managing i/o requests and associated device resources + */ + .urb_enqueue = ehci_urb_enqueue, + .urb_dequeue = ehci_urb_dequeue, + .endpoint_disable = ehci_endpoint_disable, + .endpoint_reset = ehci_endpoint_reset, + .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete, + + /* + * scheduling support + */ + .get_frame_number = ehci_get_frame, + + /* + * root hub support + */ + .hub_status_data = ehci_hub_status_data, + .hub_control = ehci_hub_control, + .bus_suspend = ehci_bus_suspend, + .bus_resume = ehci_bus_resume, + .relinquish_port = ehci_relinquish_port, + .port_handed_over = ehci_port_handed_over, +}; + +void ehci_init_driver(struct hc_driver *drv, + const struct ehci_driver_overrides *over) +{ + /* Copy the generic table to drv and then apply the overrides */ + *drv = ehci_hc_driver; + + if (over) { + drv->hcd_priv_size += over->extra_priv_size; + if (over->reset) + drv->reset = over->reset; + } +} +EXPORT_SYMBOL_GPL(ehci_init_driver); + +/*-------------------------------------------------------------------------*/ MODULE_DESCRIPTION(DRIVER_DESC); MODULE_AUTHOR (DRIVER_AUTHOR); MODULE_LICENSE ("GPL"); -#ifdef CONFIG_PCI -#include "ehci-pci.c" -#define PCI_DRIVER ehci_pci_driver -#endif - #ifdef CONFIG_USB_EHCI_FSL #include "ehci-fsl.c" #define PLATFORM_DRIVER ehci_fsl_driver @@ -1219,11 +1260,6 @@ MODULE_LICENSE ("GPL"); #define PLATFORM_DRIVER ehci_hcd_sh_driver #endif -#ifdef CONFIG_MIPS_ALCHEMY -#include "ehci-au1xxx.c" -#define PLATFORM_DRIVER ehci_hcd_au1xxx_driver -#endif - #ifdef CONFIG_USB_EHCI_HCD_OMAP #include "ehci-omap.c" #define PLATFORM_DRIVER ehci_hcd_omap_driver @@ -1249,11 +1285,6 @@ MODULE_LICENSE ("GPL"); #define PLATFORM_DRIVER ehci_orion_driver #endif -#ifdef CONFIG_ARCH_IXP4XX -#include "ehci-ixp4xx.c" -#define PLATFORM_DRIVER ixp4xx_ehci_driver -#endif - #ifdef CONFIG_USB_W90X900_EHCI #include "ehci-w90x900.c" #define PLATFORM_DRIVER ehci_hcd_w90x900_driver @@ -1269,11 +1300,6 @@ MODULE_LICENSE ("GPL"); #define PLATFORM_DRIVER ehci_octeon_driver #endif -#ifdef CONFIG_USB_CNS3XXX_EHCI -#include "ehci-cns3xxx.c" -#define PLATFORM_DRIVER cns3xxx_ehci_driver -#endif - #ifdef CONFIG_ARCH_VT8500 #include "ehci-vt8500.c" #define PLATFORM_DRIVER vt8500_ehci_driver @@ -1314,34 +1340,23 @@ MODULE_LICENSE ("GPL"); #define PLATFORM_DRIVER ehci_grlib_driver #endif -#ifdef CONFIG_CPU_XLR -#include "ehci-xls.c" -#define PLATFORM_DRIVER ehci_xls_driver -#endif - #ifdef CONFIG_USB_EHCI_MV #include "ehci-mv.c" #define PLATFORM_DRIVER ehci_mv_driver #endif -#ifdef CONFIG_MACH_LOONGSON1 -#include "ehci-ls1x.c" -#define PLATFORM_DRIVER ehci_ls1x_driver -#endif - #ifdef CONFIG_MIPS_SEAD3 #include "ehci-sead3.c" #define PLATFORM_DRIVER ehci_hcd_sead3_driver #endif -#ifdef CONFIG_USB_EHCI_HCD_PLATFORM -#include "ehci-platform.c" -#define PLATFORM_DRIVER ehci_platform_driver -#endif - -#if !defined(PCI_DRIVER) && !defined(PLATFORM_DRIVER) && \ - !defined(PS3_SYSTEM_BUS_DRIVER) && !defined(OF_PLATFORM_DRIVER) && \ - !defined(XILINX_OF_PLATFORM_DRIVER) +#if !IS_ENABLED(CONFIG_USB_EHCI_PCI) && \ + !IS_ENABLED(CONFIG_USB_EHCI_HCD_PLATFORM) && \ + !defined(CONFIG_USB_CHIPIDEA_HOST) && \ + !defined(PLATFORM_DRIVER) && \ + !defined(PS3_SYSTEM_BUS_DRIVER) && \ + !defined(OF_PLATFORM_DRIVER) && \ + !defined(XILINX_OF_PLATFORM_DRIVER) #error "missing bus glue for ehci-hcd" #endif @@ -1378,12 +1393,6 @@ static int __init ehci_hcd_init(void) goto clean0; #endif -#ifdef PCI_DRIVER - retval = pci_register_driver(&PCI_DRIVER); - if (retval < 0) - goto clean1; -#endif - #ifdef PS3_SYSTEM_BUS_DRIVER retval = ps3_ehci_driver_register(&PS3_SYSTEM_BUS_DRIVER); if (retval < 0) @@ -1415,10 +1424,6 @@ clean3: ps3_ehci_driver_unregister(&PS3_SYSTEM_BUS_DRIVER); clean2: #endif -#ifdef PCI_DRIVER - pci_unregister_driver(&PCI_DRIVER); -clean1: -#endif #ifdef PLATFORM_DRIVER platform_driver_unregister(&PLATFORM_DRIVER); clean0: @@ -1444,9 +1449,6 @@ static void __exit ehci_hcd_cleanup(void) #ifdef PLATFORM_DRIVER platform_driver_unregister(&PLATFORM_DRIVER); #endif -#ifdef PCI_DRIVER - pci_unregister_driver(&PCI_DRIVER); -#endif #ifdef PS3_SYSTEM_BUS_DRIVER ps3_ehci_driver_unregister(&PS3_SYSTEM_BUS_DRIVER); #endif @@ -1456,5 +1458,3 @@ static void __exit ehci_hcd_cleanup(void) clear_bit(USB_EHCI_LOADED, &usb_hcds_loaded); } module_exit(ehci_hcd_cleanup); - -#endif /* CHIPIDEA_EHCI */ diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c index 914ce9370e70..4ccb97c0678f 100644 --- a/drivers/usb/host/ehci-hub.c +++ b/drivers/usb/host/ehci-hub.c @@ -56,6 +56,19 @@ static void ehci_handover_companion_ports(struct ehci_hcd *ehci) if (!ehci->owned_ports) return; + /* Make sure the ports are powered */ + port = HCS_N_PORTS(ehci->hcs_params); + while (port--) { + if (test_bit(port, &ehci->owned_ports)) { + reg = &ehci->regs->port_status[port]; + status = ehci_readl(ehci, reg) & ~PORT_RWC_BITS; + if (!(status & PORT_POWER)) { + status |= PORT_POWER; + ehci_writel(ehci, status, reg); + } + } + } + /* Give the connections some time to appear */ msleep(20); @@ -384,11 +397,24 @@ static int ehci_bus_resume (struct usb_hcd *hcd) ehci_writel(ehci, ehci->command, &ehci->regs->command); ehci->rh_state = EHCI_RH_RUNNING; - /* Some controller/firmware combinations need a delay during which - * they set up the port statuses. See Bugzilla #8190. */ - spin_unlock_irq(&ehci->lock); - msleep(8); - spin_lock_irq(&ehci->lock); + /* + * According to Bugzilla #8190, the port status for some controllers + * will be wrong without a delay. At their wrong status, the port + * is enabled, but not suspended neither resumed. + */ + i = HCS_N_PORTS(ehci->hcs_params); + while (i--) { + temp = ehci_readl(ehci, &ehci->regs->port_status[i]); + if ((temp & PORT_PE) && + !(temp & (PORT_SUSPEND | PORT_RESUME))) { + ehci_dbg(ehci, "Port status(0x%x) is wrong\n", temp); + spin_unlock_irq(&ehci->lock); + msleep(8); + spin_lock_irq(&ehci->lock); + break; + } + } + if (ehci->shutdown) goto shutdown; @@ -764,11 +790,6 @@ static int ehci_hub_control ( status_reg); break; case USB_PORT_FEAT_C_CONNECTION: - if (ehci->has_lpm) { - /* clear PORTSC bits on disconnect */ - temp &= ~PORT_LPM; - temp &= ~PORT_DEV_ADDR; - } ehci_writel(ehci, temp | PORT_CSC, status_reg); break; case USB_PORT_FEAT_C_OVER_CURRENT: @@ -1088,8 +1109,7 @@ error_exit: return retval; } -static void __maybe_unused ehci_relinquish_port(struct usb_hcd *hcd, - int portnum) +static void ehci_relinquish_port(struct usb_hcd *hcd, int portnum) { struct ehci_hcd *ehci = hcd_to_ehci(hcd); @@ -1098,8 +1118,7 @@ static void __maybe_unused ehci_relinquish_port(struct usb_hcd *hcd, set_owner(ehci, --portnum, PORT_OWNER); } -static int __maybe_unused ehci_port_handed_over(struct usb_hcd *hcd, - int portnum) +static int ehci_port_handed_over(struct usb_hcd *hcd, int portnum) { struct ehci_hcd *ehci = hcd_to_ehci(hcd); u32 __iomem *reg; diff --git a/drivers/usb/host/ehci-ixp4xx.c b/drivers/usb/host/ehci-ixp4xx.c deleted file mode 100644 index f224c0a48bed..000000000000 --- a/drivers/usb/host/ehci-ixp4xx.c +++ /dev/null @@ -1,139 +0,0 @@ -/* - * IXP4XX EHCI Host Controller Driver - * - * Author: Vladimir Barinov <vbarinov@embeddedalley.com> - * - * Based on "ehci-fsl.c" by Randy Vinson <rvinson@mvista.com> - * - * 2007 (c) MontaVista Software, Inc. This file is licensed under - * the terms of the GNU General Public License version 2. This program - * is licensed "as is" without any warranty of any kind, whether express - * or implied. - */ - -#include <linux/platform_device.h> - -static int ixp4xx_ehci_init(struct usb_hcd *hcd) -{ - struct ehci_hcd *ehci = hcd_to_ehci(hcd); - int retval = 0; - - ehci->big_endian_desc = 1; - ehci->big_endian_mmio = 1; - - ehci->caps = hcd->regs + 0x100; - - hcd->has_tt = 1; - - retval = ehci_setup(hcd); - if (retval) - return retval; - - ehci_port_power(ehci, 0); - - return retval; -} - -static const struct hc_driver ixp4xx_ehci_hc_driver = { - .description = hcd_name, - .product_desc = "IXP4XX EHCI Host Controller", - .hcd_priv_size = sizeof(struct ehci_hcd), - .irq = ehci_irq, - .flags = HCD_MEMORY | HCD_USB2, - .reset = ixp4xx_ehci_init, - .start = ehci_run, - .stop = ehci_stop, - .shutdown = ehci_shutdown, - .urb_enqueue = ehci_urb_enqueue, - .urb_dequeue = ehci_urb_dequeue, - .endpoint_disable = ehci_endpoint_disable, - .endpoint_reset = ehci_endpoint_reset, - .get_frame_number = ehci_get_frame, - .hub_status_data = ehci_hub_status_data, - .hub_control = ehci_hub_control, -#if defined(CONFIG_PM) - .bus_suspend = ehci_bus_suspend, - .bus_resume = ehci_bus_resume, -#endif - .relinquish_port = ehci_relinquish_port, - .port_handed_over = ehci_port_handed_over, - - .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete, -}; - -static int ixp4xx_ehci_probe(struct platform_device *pdev) -{ - struct usb_hcd *hcd; - const struct hc_driver *driver = &ixp4xx_ehci_hc_driver; - struct resource *res; - int irq; - int retval; - - if (usb_disabled()) - return -ENODEV; - - res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); - if (!res) { - dev_err(&pdev->dev, - "Found HC with no IRQ. Check %s setup!\n", - dev_name(&pdev->dev)); - return -ENODEV; - } - irq = res->start; - - hcd = usb_create_hcd(driver, &pdev->dev, dev_name(&pdev->dev)); - if (!hcd) { - retval = -ENOMEM; - goto fail_create_hcd; - } - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - dev_err(&pdev->dev, - "Found HC with no register addr. Check %s setup!\n", - dev_name(&pdev->dev)); - retval = -ENODEV; - goto fail_request_resource; - } - hcd->rsrc_start = res->start; - hcd->rsrc_len = resource_size(res); - - hcd->regs = devm_request_and_ioremap(&pdev->dev, res); - if (hcd->regs == NULL) { - dev_dbg(&pdev->dev, "error mapping memory\n"); - retval = -EFAULT; - goto fail_request_resource; - } - - retval = usb_add_hcd(hcd, irq, IRQF_SHARED); - if (retval) - goto fail_request_resource; - - return retval; - -fail_request_resource: - usb_put_hcd(hcd); -fail_create_hcd: - dev_err(&pdev->dev, "init %s fail, %d\n", dev_name(&pdev->dev), retval); - return retval; -} - -static int ixp4xx_ehci_remove(struct platform_device *pdev) -{ - struct usb_hcd *hcd = platform_get_drvdata(pdev); - - usb_remove_hcd(hcd); - usb_put_hcd(hcd); - - return 0; -} - -MODULE_ALIAS("platform:ixp4xx-ehci"); - -static struct platform_driver ixp4xx_ehci_driver = { - .probe = ixp4xx_ehci_probe, - .remove = ixp4xx_ehci_remove, - .driver = { - .name = "ixp4xx-ehci", - }, -}; diff --git a/drivers/usb/host/ehci-lpm.c b/drivers/usb/host/ehci-lpm.c deleted file mode 100644 index 2111627a19de..000000000000 --- a/drivers/usb/host/ehci-lpm.c +++ /dev/null @@ -1,84 +0,0 @@ -/* ehci-lpm.c EHCI HCD LPM support code - * Copyright (c) 2008 - 2010, Intel Corporation. - * Author: Jacob Pan <jacob.jun.pan@intel.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -/* this file is part of ehci-hcd.c */ -static int __maybe_unused ehci_lpm_set_da(struct ehci_hcd *ehci, - int dev_addr, int port_num) -{ - u32 __iomem portsc; - - ehci_dbg(ehci, "set dev address %d for port %d\n", dev_addr, port_num); - if (port_num > HCS_N_PORTS(ehci->hcs_params)) { - ehci_dbg(ehci, "invalid port number %d\n", port_num); - return -ENODEV; - } - portsc = ehci_readl(ehci, &ehci->regs->port_status[port_num-1]); - portsc &= ~PORT_DEV_ADDR; - portsc |= dev_addr<<25; - ehci_writel(ehci, portsc, &ehci->regs->port_status[port_num-1]); - return 0; -} - -/* - * this function is used to check if the device support LPM - * if yes, mark the PORTSC register with PORT_LPM bit - */ -static int __maybe_unused ehci_lpm_check(struct ehci_hcd *ehci, int port) -{ - u32 __iomem *portsc ; - u32 val32; - int retval; - - portsc = &ehci->regs->port_status[port-1]; - val32 = ehci_readl(ehci, portsc); - if (!(val32 & PORT_DEV_ADDR)) { - ehci_dbg(ehci, "LPM: no device attached\n"); - return -ENODEV; - } - val32 |= PORT_LPM; - ehci_writel(ehci, val32, portsc); - msleep(5); - val32 |= PORT_SUSPEND; - ehci_dbg(ehci, "Sending LPM 0x%08x to port %d\n", val32, port); - ehci_writel(ehci, val32, portsc); - /* wait for ACK */ - msleep(10); - retval = handshake(ehci, &ehci->regs->port_status[port-1], PORT_SSTS, - PORTSC_SUSPEND_STS_ACK, 125); - dbg_port(ehci, "LPM", port, val32); - if (retval != -ETIMEDOUT) { - ehci_dbg(ehci, "LPM: device ACK for LPM\n"); - val32 |= PORT_LPM; - /* - * now device should be in L1 sleep, let's wake up the device - * so that we can complete enumeration. - */ - ehci_writel(ehci, val32, portsc); - msleep(10); - val32 |= PORT_RESUME; - ehci_writel(ehci, val32, portsc); - } else { - ehci_dbg(ehci, "LPM: device does not ACK, disable LPM %d\n", - retval); - val32 &= ~PORT_LPM; - retval = -ETIMEDOUT; - ehci_writel(ehci, val32, portsc); - } - - return retval; -} diff --git a/drivers/usb/host/ehci-ls1x.c b/drivers/usb/host/ehci-ls1x.c deleted file mode 100644 index ca759652626b..000000000000 --- a/drivers/usb/host/ehci-ls1x.c +++ /dev/null @@ -1,147 +0,0 @@ -/* - * Bus Glue for Loongson LS1X built-in EHCI controller. - * - * Copyright (c) 2012 Zhang, Keguang <keguang.zhang@gmail.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published - * by the Free Software Foundation. - */ - - -#include <linux/platform_device.h> - -static int ehci_ls1x_reset(struct usb_hcd *hcd) -{ - struct ehci_hcd *ehci = hcd_to_ehci(hcd); - int ret; - - ehci->caps = hcd->regs; - - ret = ehci_setup(hcd); - if (ret) - return ret; - - ehci_port_power(ehci, 0); - - return 0; -} - -static const struct hc_driver ehci_ls1x_hc_driver = { - .description = hcd_name, - .product_desc = "LOONGSON1 EHCI", - .hcd_priv_size = sizeof(struct ehci_hcd), - - /* - * generic hardware linkage - */ - .irq = ehci_irq, - .flags = HCD_MEMORY | HCD_USB2, - - /* - * basic lifecycle operations - */ - .reset = ehci_ls1x_reset, - .start = ehci_run, - .stop = ehci_stop, - .shutdown = ehci_shutdown, - - /* - * managing i/o requests and associated device resources - */ - .urb_enqueue = ehci_urb_enqueue, - .urb_dequeue = ehci_urb_dequeue, - .endpoint_disable = ehci_endpoint_disable, - .endpoint_reset = ehci_endpoint_reset, - - /* - * scheduling support - */ - .get_frame_number = ehci_get_frame, - - /* - * root hub support - */ - .hub_status_data = ehci_hub_status_data, - .hub_control = ehci_hub_control, - .relinquish_port = ehci_relinquish_port, - .port_handed_over = ehci_port_handed_over, - - .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete, -}; - -static int ehci_hcd_ls1x_probe(struct platform_device *pdev) -{ - struct usb_hcd *hcd; - struct resource *res; - int irq; - int ret; - - pr_debug("initializing loongson1 ehci USB Controller\n"); - - if (usb_disabled()) - return -ENODEV; - - res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); - if (!res) { - dev_err(&pdev->dev, - "Found HC with no IRQ. Check %s setup!\n", - dev_name(&pdev->dev)); - return -ENODEV; - } - irq = res->start; - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - dev_err(&pdev->dev, - "Found HC with no register addr. Check %s setup!\n", - dev_name(&pdev->dev)); - return -ENODEV; - } - - hcd = usb_create_hcd(&ehci_ls1x_hc_driver, &pdev->dev, - dev_name(&pdev->dev)); - if (!hcd) - return -ENOMEM; - hcd->rsrc_start = res->start; - hcd->rsrc_len = resource_size(res); - - hcd->regs = devm_request_and_ioremap(&pdev->dev, res); - if (hcd->regs == NULL) { - dev_dbg(&pdev->dev, "error mapping memory\n"); - ret = -EFAULT; - goto err_put_hcd; - } - - ret = usb_add_hcd(hcd, irq, IRQF_SHARED); - if (ret) - goto err_put_hcd; - - return ret; - -err_put_hcd: - usb_put_hcd(hcd); - return ret; -} - -static int ehci_hcd_ls1x_remove(struct platform_device *pdev) -{ - struct usb_hcd *hcd = platform_get_drvdata(pdev); - - usb_remove_hcd(hcd); - usb_put_hcd(hcd); - - return 0; -} - -static struct platform_driver ehci_ls1x_driver = { - .probe = ehci_hcd_ls1x_probe, - .remove = ehci_hcd_ls1x_remove, - .shutdown = usb_hcd_platform_shutdown, - .driver = { - .name = "ls1x-ehci", - .owner = THIS_MODULE, - }, -}; - -MODULE_ALIAS(PLATFORM_MODULE_PREFIX "ls1x-ehci"); diff --git a/drivers/usb/host/ehci-msm.c b/drivers/usb/host/ehci-msm.c index 4af4dc5b618c..7fa1ba4de789 100644 --- a/drivers/usb/host/ehci-msm.c +++ b/drivers/usb/host/ehci-msm.c @@ -53,7 +53,6 @@ static int ehci_msm_reset(struct usb_hcd *hcd) /* Disable streaming mode and select host mode */ writel(0x13, USB_USBMODE); - ehci_port_power(ehci, 1); return 0; } diff --git a/drivers/usb/host/ehci-mxc.c b/drivers/usb/host/ehci-mxc.c index 4a08fc0b27c9..a37224a4a49b 100644 --- a/drivers/usb/host/ehci-mxc.c +++ b/drivers/usb/host/ehci-mxc.c @@ -40,16 +40,10 @@ struct ehci_mxc_priv { static int ehci_mxc_setup(struct usb_hcd *hcd) { struct ehci_hcd *ehci = hcd_to_ehci(hcd); - int retval; hcd->has_tt = 1; - retval = ehci_setup(hcd); - if (retval) - return retval; - - ehci_port_power(ehci, 0); - return 0; + return ehci_setup(hcd); } static const struct hc_driver ehci_mxc_hc_driver = { diff --git a/drivers/usb/host/ehci-octeon.c b/drivers/usb/host/ehci-octeon.c index ba26957abf46..a89750fff4ff 100644 --- a/drivers/usb/host/ehci-octeon.c +++ b/drivers/usb/host/ehci-octeon.c @@ -159,9 +159,6 @@ static int ehci_octeon_drv_probe(struct platform_device *pdev) platform_set_drvdata(pdev, hcd); - /* root ports should always stay powered */ - ehci_port_power(ehci, 1); - return 0; err3: ehci_octeon_stop(); diff --git a/drivers/usb/host/ehci-omap.c b/drivers/usb/host/ehci-omap.c index d7fe287d0678..44e7d0f638e8 100644 --- a/drivers/usb/host/ehci-omap.c +++ b/drivers/usb/host/ehci-omap.c @@ -146,9 +146,6 @@ static int omap_ehci_init(struct usb_hcd *hcd) gpio_set_value_cansleep(pdata->reset_gpio_port[1], 1); } - /* root ports should always stay powered */ - ehci_port_power(ehci, 1); - return rc; } diff --git a/drivers/usb/host/ehci-orion.c b/drivers/usb/host/ehci-orion.c index 9c2717d66730..96da679becef 100644 --- a/drivers/usb/host/ehci-orion.c +++ b/drivers/usb/host/ehci-orion.c @@ -101,20 +101,6 @@ static void orion_usb_phy_v1_setup(struct usb_hcd *hcd) wrl(USB_MODE, 0x13); } -static int ehci_orion_setup(struct usb_hcd *hcd) -{ - struct ehci_hcd *ehci = hcd_to_ehci(hcd); - int retval; - - retval = ehci_setup(hcd); - if (retval) - return retval; - - ehci_port_power(ehci, 0); - - return retval; -} - static const struct hc_driver ehci_orion_hc_driver = { .description = hcd_name, .product_desc = "Marvell Orion EHCI", @@ -129,7 +115,7 @@ static const struct hc_driver ehci_orion_hc_driver = { /* * basic lifecycle operations */ - .reset = ehci_orion_setup, + .reset = ehci_setup, .start = ehci_run, .stop = ehci_stop, .shutdown = ehci_shutdown, diff --git a/drivers/usb/host/ehci-pci.c b/drivers/usb/host/ehci-pci.c index 2cb7d370c4ef..3fb76ca61848 100644 --- a/drivers/usb/host/ehci-pci.c +++ b/drivers/usb/host/ehci-pci.c @@ -18,9 +18,18 @@ * Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#ifndef CONFIG_PCI -#error "This file is PCI bus glue. CONFIG_PCI must be defined." -#endif +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/pci.h> +#include <linux/usb.h> +#include <linux/usb/hcd.h> + +#include "ehci.h" +#include "pci-quirks.h" + +#define DRIVER_DESC "EHCI PCI platform driver" + +static const char hcd_name[] = "ehci-pci"; /* defined here to avoid adding to pci_ids.h for single instance use */ #define PCI_DEVICE_ID_INTEL_CE4100_USB 0x2e70 @@ -103,7 +112,6 @@ static int ehci_pci_setup(struct usb_hcd *hcd) } break; case PCI_VENDOR_ID_INTEL: - ehci->fs_i_thresh = 1; if (pdev->device == PCI_DEVICE_ID_INTEL_CE4100_USB) hcd->has_tt = 1; break; @@ -203,11 +211,6 @@ static int ehci_pci_setup(struct usb_hcd *hcd) break; case PCI_VENDOR_ID_INTEL: ehci->need_io_watchdog = 0; - if (pdev->device == 0x0806 || pdev->device == 0x0811 - || pdev->device == 0x0829) { - ehci_info(ehci, "disable lpm for langwell/penwell\n"); - ehci->has_lpm = 0; - } break; case PCI_VENDOR_ID_NVIDIA: switch (pdev->device) { @@ -217,8 +220,7 @@ static int ehci_pci_setup(struct usb_hcd *hcd) * devices with PPCD enabled. */ case 0x0d9d: - ehci_info(ehci, "disable lpm/ppcd for nvidia mcp89"); - ehci->has_lpm = 0; + ehci_info(ehci, "disable ppcd for nvidia mcp89\n"); ehci->has_ppcd = 0; ehci->command &= ~CMD_PPCEE; break; @@ -304,7 +306,6 @@ static int ehci_pci_setup(struct usb_hcd *hcd) ehci_warn(ehci, "selective suspend/wakeup unavailable\n"); #endif - ehci_port_power(ehci, 1); retval = ehci_pci_reinit(ehci, pdev); done: return retval; @@ -323,11 +324,6 @@ done: * Also they depend on separate root hub suspend/resume. */ -static int ehci_pci_suspend(struct usb_hcd *hcd, bool do_wakeup) -{ - return ehci_suspend(hcd, do_wakeup); -} - static bool usb_is_intel_switchable_ehci(struct pci_dev *pdev) { return pdev->class == PCI_CLASS_SERIAL_USB_EHCI && @@ -378,76 +374,17 @@ static int ehci_pci_resume(struct usb_hcd *hcd, bool hibernated) (void) ehci_pci_reinit(ehci, pdev); return 0; } -#endif -static int ehci_update_device(struct usb_hcd *hcd, struct usb_device *udev) -{ - struct ehci_hcd *ehci = hcd_to_ehci(hcd); - int rc = 0; - - if (!udev->parent) /* udev is root hub itself, impossible */ - rc = -1; - /* we only support lpm device connected to root hub yet */ - if (ehci->has_lpm && !udev->parent->parent) { - rc = ehci_lpm_set_da(ehci, udev->devnum, udev->portnum); - if (!rc) - rc = ehci_lpm_check(ehci, udev->portnum); - } - return rc; -} +#else -static const struct hc_driver ehci_pci_hc_driver = { - .description = hcd_name, - .product_desc = "EHCI Host Controller", - .hcd_priv_size = sizeof(struct ehci_hcd), +#define ehci_suspend NULL +#define ehci_pci_resume NULL +#endif /* CONFIG_PM */ - /* - * generic hardware linkage - */ - .irq = ehci_irq, - .flags = HCD_MEMORY | HCD_USB2, +static struct hc_driver __read_mostly ehci_pci_hc_driver; - /* - * basic lifecycle operations - */ +static const struct ehci_driver_overrides pci_overrides __initdata = { .reset = ehci_pci_setup, - .start = ehci_run, -#ifdef CONFIG_PM - .pci_suspend = ehci_pci_suspend, - .pci_resume = ehci_pci_resume, -#endif - .stop = ehci_stop, - .shutdown = ehci_shutdown, - - /* - * managing i/o requests and associated device resources - */ - .urb_enqueue = ehci_urb_enqueue, - .urb_dequeue = ehci_urb_dequeue, - .endpoint_disable = ehci_endpoint_disable, - .endpoint_reset = ehci_endpoint_reset, - - /* - * scheduling support - */ - .get_frame_number = ehci_get_frame, - - /* - * root hub support - */ - .hub_status_data = ehci_hub_status_data, - .hub_control = ehci_hub_control, - .bus_suspend = ehci_bus_suspend, - .bus_resume = ehci_bus_resume, - .relinquish_port = ehci_relinquish_port, - .port_handed_over = ehci_port_handed_over, - - /* - * call back when device connected and addressed - */ - .update_device = ehci_update_device, - - .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete, }; /*-------------------------------------------------------------------------*/ @@ -480,3 +417,31 @@ static struct pci_driver ehci_pci_driver = { }, #endif }; + +static int __init ehci_pci_init(void) +{ + if (usb_disabled()) + return -ENODEV; + + pr_info("%s: " DRIVER_DESC "\n", hcd_name); + + ehci_init_driver(&ehci_pci_hc_driver, &pci_overrides); + + /* Entries for the PCI suspend/resume callbacks are special */ + ehci_pci_hc_driver.pci_suspend = ehci_suspend; + ehci_pci_hc_driver.pci_resume = ehci_pci_resume; + + return pci_register_driver(&ehci_pci_driver); +} +module_init(ehci_pci_init); + +static void __exit ehci_pci_cleanup(void) +{ + pci_unregister_driver(&ehci_pci_driver); +} +module_exit(ehci_pci_cleanup); + +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_AUTHOR("David Brownell"); +MODULE_AUTHOR("Alan Stern"); +MODULE_LICENSE("GPL"); diff --git a/drivers/usb/host/ehci-platform.c b/drivers/usb/host/ehci-platform.c index 764e0100b6f4..f14c542b142f 100644 --- a/drivers/usb/host/ehci-platform.c +++ b/drivers/usb/host/ehci-platform.c @@ -18,9 +18,21 @@ * * Licensed under the GNU/GPL. See COPYING for details. */ +#include <linux/kernel.h> +#include <linux/hrtimer.h> +#include <linux/io.h> +#include <linux/module.h> #include <linux/platform_device.h> +#include <linux/usb.h> +#include <linux/usb/hcd.h> #include <linux/usb/ehci_pdriver.h> +#include "ehci.h" + +#define DRIVER_DESC "EHCI generic platform driver" + +static const char hcd_name[] = "ehci-platform"; + static int ehci_platform_reset(struct usb_hcd *hcd) { struct platform_device *pdev = to_platform_device(hcd->self.controller); @@ -38,44 +50,15 @@ static int ehci_platform_reset(struct usb_hcd *hcd) if (retval) return retval; - if (pdata->port_power_on) - ehci_port_power(ehci, 1); - if (pdata->port_power_off) - ehci_port_power(ehci, 0); - + if (pdata->no_io_watchdog) + ehci->need_io_watchdog = 0; return 0; } -static const struct hc_driver ehci_platform_hc_driver = { - .description = hcd_name, - .product_desc = "Generic Platform EHCI Controller", - .hcd_priv_size = sizeof(struct ehci_hcd), - - .irq = ehci_irq, - .flags = HCD_MEMORY | HCD_USB2, - - .reset = ehci_platform_reset, - .start = ehci_run, - .stop = ehci_stop, - .shutdown = ehci_shutdown, - - .urb_enqueue = ehci_urb_enqueue, - .urb_dequeue = ehci_urb_dequeue, - .endpoint_disable = ehci_endpoint_disable, - .endpoint_reset = ehci_endpoint_reset, +static struct hc_driver __read_mostly ehci_platform_hc_driver; - .get_frame_number = ehci_get_frame, - - .hub_status_data = ehci_hub_status_data, - .hub_control = ehci_hub_control, -#if defined(CONFIG_PM) - .bus_suspend = ehci_bus_suspend, - .bus_resume = ehci_bus_resume, -#endif - .relinquish_port = ehci_relinquish_port, - .port_handed_over = ehci_port_handed_over, - - .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete, +static const struct ehci_driver_overrides platform_overrides __initdata = { + .reset = ehci_platform_reset, }; static int __devinit ehci_platform_probe(struct platform_device *dev) @@ -96,12 +79,12 @@ static int __devinit ehci_platform_probe(struct platform_device *dev) irq = platform_get_irq(dev, 0); if (irq < 0) { - pr_err("no irq provided"); + dev_err(&dev->dev, "no irq provided"); return irq; } res_mem = platform_get_resource(dev, IORESOURCE_MEM, 0); if (!res_mem) { - pr_err("no memory recourse provided"); + dev_err(&dev->dev, "no memory resource provided"); return -ENXIO; } @@ -121,29 +104,19 @@ static int __devinit ehci_platform_probe(struct platform_device *dev) hcd->rsrc_start = res_mem->start; hcd->rsrc_len = resource_size(res_mem); - if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) { - pr_err("controller already in use"); - err = -EBUSY; - goto err_put_hcd; - } - - hcd->regs = ioremap_nocache(hcd->rsrc_start, hcd->rsrc_len); + hcd->regs = devm_request_and_ioremap(&dev->dev, res_mem); if (!hcd->regs) { err = -ENOMEM; - goto err_release_region; + goto err_put_hcd; } err = usb_add_hcd(hcd, irq, IRQF_SHARED); if (err) - goto err_iounmap; + goto err_put_hcd; platform_set_drvdata(dev, hcd); return err; -err_iounmap: - iounmap(hcd->regs); -err_release_region: - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); err_put_hcd: usb_put_hcd(hcd); err_power: @@ -159,8 +132,6 @@ static int __devexit ehci_platform_remove(struct platform_device *dev) struct usb_ehci_pdata *pdata = dev->dev.platform_data; usb_remove_hcd(hcd); - iounmap(hcd->regs); - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); usb_put_hcd(hcd); platform_set_drvdata(dev, NULL); @@ -233,3 +204,26 @@ static struct platform_driver ehci_platform_driver = { .pm = &ehci_platform_pm_ops, } }; + +static int __init ehci_platform_init(void) +{ + if (usb_disabled()) + return -ENODEV; + + pr_info("%s: " DRIVER_DESC "\n", hcd_name); + + ehci_init_driver(&ehci_platform_hc_driver, &platform_overrides); + return platform_driver_register(&ehci_platform_driver); +} +module_init(ehci_platform_init); + +static void __exit ehci_platform_cleanup(void) +{ + platform_driver_unregister(&ehci_platform_driver); +} +module_exit(ehci_platform_cleanup); + +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_AUTHOR("Hauke Mehrtens"); +MODULE_AUTHOR("Alan Stern"); +MODULE_LICENSE("GPL"); diff --git a/drivers/usb/host/ehci-pmcmsp.c b/drivers/usb/host/ehci-pmcmsp.c index 087aee2a904f..363890ee41d2 100644 --- a/drivers/usb/host/ehci-pmcmsp.c +++ b/drivers/usb/host/ehci-pmcmsp.c @@ -90,7 +90,6 @@ static int ehci_msp_setup(struct usb_hcd *hcd) return retval; usb_hcd_tdi_set_mode(ehci); - ehci_port_power(ehci, 0); return retval; } diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c index 4b66374bdc8e..3d989028c836 100644 --- a/drivers/usb/host/ehci-q.c +++ b/drivers/usb/host/ehci-q.c @@ -264,15 +264,9 @@ ehci_urb_done(struct ehci_hcd *ehci, struct urb *urb, int status) __releases(ehci->lock) __acquires(ehci->lock) { - if (likely (urb->hcpriv != NULL)) { - struct ehci_qh *qh = (struct ehci_qh *) urb->hcpriv; - - /* S-mask in a QH means it's an interrupt urb */ - if ((qh->hw->hw_info2 & cpu_to_hc32(ehci, QH_SMASK)) != 0) { - - /* ... update hc-wide periodic stats (for usbfs) */ - ehci_to_hcd(ehci)->self.bandwidth_int_reqs--; - } + if (usb_pipetype(urb->pipe) == PIPE_INTERRUPT) { + /* ... update hc-wide periodic stats */ + ehci_to_hcd(ehci)->self.bandwidth_int_reqs--; } if (unlikely(urb->unlinked)) { diff --git a/drivers/usb/host/ehci-s5p.c b/drivers/usb/host/ehci-s5p.c index 85b74be202eb..abc178d21fe4 100644 --- a/drivers/usb/host/ehci-s5p.c +++ b/drivers/usb/host/ehci-s5p.c @@ -136,7 +136,7 @@ static int __devinit s5p_ehci_probe(struct platform_device *pdev) goto fail_clk; } - err = clk_enable(s5p_ehci->clk); + err = clk_prepare_enable(s5p_ehci->clk); if (err) goto fail_clk; @@ -183,7 +183,7 @@ static int __devinit s5p_ehci_probe(struct platform_device *pdev) return 0; fail_io: - clk_disable(s5p_ehci->clk); + clk_disable_unprepare(s5p_ehci->clk); fail_clk: usb_put_hcd(hcd); return err; @@ -200,7 +200,7 @@ static int __devexit s5p_ehci_remove(struct platform_device *pdev) if (pdata && pdata->phy_exit) pdata->phy_exit(pdev, S5P_USB_PHY_HOST); - clk_disable(s5p_ehci->clk); + clk_disable_unprepare(s5p_ehci->clk); usb_put_hcd(hcd); @@ -231,7 +231,7 @@ static int s5p_ehci_suspend(struct device *dev) if (pdata && pdata->phy_exit) pdata->phy_exit(pdev, S5P_USB_PHY_HOST); - clk_disable(s5p_ehci->clk); + clk_disable_unprepare(s5p_ehci->clk); return rc; } @@ -243,7 +243,7 @@ static int s5p_ehci_resume(struct device *dev) struct platform_device *pdev = to_platform_device(dev); struct s5p_ehci_platdata *pdata = pdev->dev.platform_data; - clk_enable(s5p_ehci->clk); + clk_prepare_enable(s5p_ehci->clk); if (pdata && pdata->phy_init) pdata->phy_init(pdev, S5P_USB_PHY_HOST); diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c index 7cf3da7babf0..69ebee73c0c1 100644 --- a/drivers/usb/host/ehci-sched.c +++ b/drivers/usb/host/ehci-sched.c @@ -36,29 +36,6 @@ static int ehci_get_frame (struct usb_hcd *hcd); -#ifdef CONFIG_PCI - -static unsigned ehci_read_frame_index(struct ehci_hcd *ehci) -{ - unsigned uf; - - /* - * The MosChip MCS9990 controller updates its microframe counter - * a little before the frame counter, and occasionally we will read - * the invalid intermediate value. Avoid problems by checking the - * microframe number (the low-order 3 bits); if they are 0 then - * re-read the register to get the correct value. - */ - uf = ehci_readl(ehci, &ehci->regs->frame_index); - if (unlikely(ehci->frame_index_bug && ((uf & 7) == 0))) - uf = ehci_readl(ehci, &ehci->regs->frame_index); - return uf; -} - -#endif - -/*-------------------------------------------------------------------------*/ - /* * periodic_next_shadow - return "next" pointer on shadow list * @periodic: host pointer to qh/itd/sitd @@ -1361,7 +1338,7 @@ sitd_slot_ok ( * given EHCI_TUNE_FLS and the slop). Or, write a smarter scheduler! */ -#define SCHEDULE_SLOP 80 /* microframes */ +#define SCHEDULING_DELAY 40 /* microframes */ static int iso_stream_schedule ( @@ -1370,7 +1347,7 @@ iso_stream_schedule ( struct ehci_iso_stream *stream ) { - u32 now, next, start, period, span; + u32 now, base, next, start, period, span; int status; unsigned mod = ehci->periodic_size << 3; struct ehci_iso_sched *sched = urb->hcpriv; @@ -1382,62 +1359,72 @@ iso_stream_schedule ( span <<= 3; } - if (span > mod - SCHEDULE_SLOP) { - ehci_dbg (ehci, "iso request %p too long\n", urb); - status = -EFBIG; - goto fail; - } - now = ehci_read_frame_index(ehci) & (mod - 1); /* Typical case: reuse current schedule, stream is still active. * Hopefully there are no gaps from the host falling behind - * (irq delays etc), but if there are we'll take the next - * slot in the schedule, implicitly assuming URB_ISO_ASAP. + * (irq delays etc). If there are, the behavior depends on + * whether URB_ISO_ASAP is set. */ if (likely (!list_empty (&stream->td_list))) { - u32 excess; - /* For high speed devices, allow scheduling within the - * isochronous scheduling threshold. For full speed devices - * and Intel PCI-based controllers, don't (work around for - * Intel ICH9 bug). - */ - if (!stream->highspeed && ehci->fs_i_thresh) - next = now + ehci->i_thresh; + /* Take the isochronous scheduling threshold into account */ + if (ehci->i_thresh) + next = now + ehci->i_thresh; /* uframe cache */ else - next = now; + next = (now + 2 + 7) & ~0x07; /* full frame cache */ - /* Fell behind (by up to twice the slop amount)? - * We decide based on the time of the last currently-scheduled - * slot, not the time of the next available slot. + /* + * Use ehci->last_iso_frame as the base. There can't be any + * TDs scheduled for earlier than that. */ - excess = (stream->next_uframe - period - next) & (mod - 1); - if (excess >= mod - 2 * SCHEDULE_SLOP) - start = next + excess - mod + period * - DIV_ROUND_UP(mod - excess, period); - else - start = next + excess + period; - if (start - now >= mod) { - ehci_dbg(ehci, "request %p would overflow (%d+%d >= %d)\n", - urb, start - now - period, period, - mod); - status = -EFBIG; + base = ehci->last_iso_frame << 3; + next = (next - base) & (mod - 1); + start = (stream->next_uframe - base) & (mod - 1); + + /* Is the schedule already full? */ + if (unlikely(start < period)) { + ehci_dbg(ehci, "iso sched full %p (%u-%u < %u mod %u)\n", + urb, stream->next_uframe, base, + period, mod); + status = -ENOSPC; goto fail; } + + /* Behind the scheduling threshold? */ + if (unlikely(start < next)) { + + /* USB_ISO_ASAP: Round up to the first available slot */ + if (urb->transfer_flags & URB_ISO_ASAP) + start += (next - start + period - 1) & -period; + + /* + * Not ASAP: Use the next slot in the stream. If + * the entire URB falls before the threshold, fail. + */ + else if (start + span - period < next) { + ehci_dbg(ehci, "iso urb late %p (%u+%u < %u)\n", + urb, start + base, + span - period, next + base); + status = -EXDEV; + goto fail; + } + } + + start += base; } /* need to schedule; when's the next (u)frame we could start? * this is bigger than ehci->i_thresh allows; scheduling itself - * isn't free, the slop should handle reasonably slow cpus. it + * isn't free, the delay should handle reasonably slow cpus. it * can also help high bandwidth if the dma and irq loads don't * jump until after the queue is primed. */ else { int done = 0; - start = SCHEDULE_SLOP + (now & ~0x07); - /* NOTE: assumes URB_ISO_ASAP, to limit complexity/bugs */ + base = now & ~0x07; + start = base + SCHEDULING_DELAY; /* find a uframe slot with enough bandwidth. * Early uframes are more precious because full-speed @@ -1464,19 +1451,16 @@ iso_stream_schedule ( /* no room in the schedule */ if (!done) { - ehci_dbg(ehci, "iso resched full %p (now %d max %d)\n", - urb, now, now + mod); + ehci_dbg(ehci, "iso sched full %p", urb); status = -ENOSPC; goto fail; } } /* Tried to schedule too far into the future? */ - if (unlikely(start - now + span - period - >= mod - 2 * SCHEDULE_SLOP)) { - ehci_dbg(ehci, "request %p would overflow (%d+%d >= %d)\n", - urb, start - now, span - period, - mod - 2 * SCHEDULE_SLOP); + if (unlikely(start - base + span - period >= mod)) { + ehci_dbg(ehci, "request %p would overflow (%u+%u >= %u)\n", + urb, start - base, span - period, mod); status = -EFBIG; goto fail; } @@ -1490,7 +1474,7 @@ iso_stream_schedule ( /* Make sure scan_isoc() sees these */ if (ehci->isoc_count == 0) - ehci->next_frame = now >> 3; + ehci->last_iso_frame = now >> 3; return 0; fail: @@ -1646,7 +1630,7 @@ static void itd_link_urb( /* don't need that schedule data any more */ iso_sched_free (stream, iso_sched); - urb->hcpriv = NULL; + urb->hcpriv = stream; ++ehci->isoc_count; enable_periodic(ehci); @@ -1708,7 +1692,7 @@ static bool itd_complete(struct ehci_hcd *ehci, struct ehci_itd *itd) urb->actual_length += desc->actual_length; } else { /* URB was too late */ - desc->status = -EXDEV; + urb->error_count++; } } @@ -2045,7 +2029,7 @@ static void sitd_link_urb( /* don't need that schedule data any more */ iso_sched_free (stream, sched); - urb->hcpriv = NULL; + urb->hcpriv = stream; ++ehci->isoc_count; enable_periodic(ehci); @@ -2081,7 +2065,7 @@ static bool sitd_complete(struct ehci_hcd *ehci, struct ehci_sitd *sitd) t = hc32_to_cpup(ehci, &sitd->hw_results); /* report transfer status */ - if (t & SITD_ERRS) { + if (unlikely(t & SITD_ERRS)) { urb->error_count++; if (t & SITD_STS_DBE) desc->status = usb_pipein (urb->pipe) @@ -2091,6 +2075,9 @@ static bool sitd_complete(struct ehci_hcd *ehci, struct ehci_sitd *sitd) desc->status = -EOVERFLOW; else /* XACT, MMF, etc */ desc->status = -EPROTO; + } else if (unlikely(t & SITD_STS_ACTIVE)) { + /* URB was too late */ + urb->error_count++; } else { desc->status = 0; desc->actual_length = desc->length - SITD_LENGTH(t); @@ -2220,16 +2207,16 @@ static void scan_isoc(struct ehci_hcd *ehci) now_frame = (uf >> 3) & fmask; live = true; } else { - now_frame = (ehci->next_frame - 1) & fmask; + now_frame = (ehci->last_iso_frame - 1) & fmask; live = false; } ehci->now_frame = now_frame; - frame = ehci->next_frame; for (;;) { union ehci_shadow q, *q_p; __hc32 type, *hw_p; + frame = ehci->last_iso_frame; restart: /* scan each element in frame's queue for completions */ q_p = &ehci->pshadow [frame]; @@ -2334,7 +2321,6 @@ restart: /* Stop when we have reached the current frame */ if (frame == now_frame) break; - frame = (frame + 1) & fmask; + ehci->last_iso_frame = (frame + 1) & fmask; } - ehci->next_frame = now_frame; } diff --git a/drivers/usb/host/ehci-sh.c b/drivers/usb/host/ehci-sh.c index 6081e1ed3ac9..0c90a24fa989 100644 --- a/drivers/usb/host/ehci-sh.c +++ b/drivers/usb/host/ehci-sh.c @@ -21,17 +21,10 @@ struct ehci_sh_priv { static int ehci_sh_reset(struct usb_hcd *hcd) { struct ehci_hcd *ehci = hcd_to_ehci(hcd); - int ret; ehci->caps = hcd->regs; - ret = ehci_setup(hcd); - if (unlikely(ret)) - return ret; - - ehci_port_power(ehci, 0); - - return ret; + return ehci_setup(hcd); } static const struct hc_driver ehci_sh_hc_driver = { diff --git a/drivers/usb/host/ehci-spear.c b/drivers/usb/host/ehci-spear.c index c718a065e154..719ca48a471a 100644 --- a/drivers/usb/host/ehci-spear.c +++ b/drivers/usb/host/ehci-spear.c @@ -37,18 +37,11 @@ static void spear_stop_ehci(struct spear_ehci *ehci) static int ehci_spear_setup(struct usb_hcd *hcd) { struct ehci_hcd *ehci = hcd_to_ehci(hcd); - int retval = 0; /* registers start at offset 0x0 */ ehci->caps = hcd->regs; - retval = ehci_setup(hcd); - if (retval) - return retval; - - ehci_port_power(ehci, 0); - - return retval; + return ehci_setup(hcd); } static const struct hc_driver ehci_spear_hc_driver = { diff --git a/drivers/usb/host/ehci-tegra.c b/drivers/usb/host/ehci-tegra.c index 6223d1757848..94ee3212094e 100644 --- a/drivers/usb/host/ehci-tegra.c +++ b/drivers/usb/host/ehci-tegra.c @@ -28,7 +28,10 @@ #include <linux/pm_runtime.h> #include <linux/usb/tegra_usb_phy.h> -#include <mach/iomap.h> + +#define TEGRA_USB_BASE 0xC5000000 +#define TEGRA_USB2_BASE 0xC5004000 +#define TEGRA_USB3_BASE 0xC5008000 #define TEGRA_USB_DMA_ALIGN 32 @@ -277,7 +280,6 @@ static void tegra_ehci_shutdown(struct usb_hcd *hcd) static int tegra_ehci_setup(struct usb_hcd *hcd) { struct ehci_hcd *ehci = hcd_to_ehci(hcd); - int retval; /* EHCI registers start at offset 0x100 */ ehci->caps = hcd->regs + 0x100; @@ -285,12 +287,7 @@ static int tegra_ehci_setup(struct usb_hcd *hcd) /* switch to host mode */ hcd->has_tt = 1; - retval = ehci_setup(hcd); - if (retval) - return retval; - - ehci_port_power(ehci, 1); - return retval; + return ehci_setup(hcd); } struct dma_aligned_buffer { diff --git a/drivers/usb/host/ehci-vt8500.c b/drivers/usb/host/ehci-vt8500.c index d3c9a3e397b9..11695d5b9d86 100644 --- a/drivers/usb/host/ehci-vt8500.c +++ b/drivers/usb/host/ehci-vt8500.c @@ -19,22 +19,6 @@ #include <linux/of.h> #include <linux/platform_device.h> -static int ehci_update_device(struct usb_hcd *hcd, struct usb_device *udev) -{ - struct ehci_hcd *ehci = hcd_to_ehci(hcd); - int rc = 0; - - if (!udev->parent) /* udev is root hub itself, impossible */ - rc = -1; - /* we only support lpm device connected to root hub yet */ - if (ehci->has_lpm && !udev->parent->parent) { - rc = ehci_lpm_set_da(ehci, udev->devnum, udev->portnum); - if (!rc) - rc = ehci_lpm_check(ehci, udev->portnum); - } - return rc; -} - static const struct hc_driver vt8500_ehci_hc_driver = { .description = hcd_name, .product_desc = "VT8500 EHCI", @@ -77,11 +61,6 @@ static const struct hc_driver vt8500_ehci_hc_driver = { .relinquish_port = ehci_relinquish_port, .port_handed_over = ehci_port_handed_over, - /* - * call back when device connected and addressed - */ - .update_device = ehci_update_device, - .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete, }; diff --git a/drivers/usb/host/ehci-w90x900.c b/drivers/usb/host/ehci-w90x900.c index ec598082c14b..fdd7c4873cf2 100644 --- a/drivers/usb/host/ehci-w90x900.c +++ b/drivers/usb/host/ehci-w90x900.c @@ -13,7 +13,7 @@ #include <linux/platform_device.h> -/*ebable phy0 and phy1 for w90p910*/ +/* enable phy0 and phy1 for w90p910 */ #define ENPHY (0x01<<8) #define PHY0_CTR (0xA4) #define PHY1_CTR (0xA8) diff --git a/drivers/usb/host/ehci-xls.c b/drivers/usb/host/ehci-xls.c deleted file mode 100644 index 8dc6a22d90b8..000000000000 --- a/drivers/usb/host/ehci-xls.c +++ /dev/null @@ -1,142 +0,0 @@ -/* - * EHCI HCD for Netlogic XLS processors. - * - * (C) Copyright 2011 Netlogic Microsystems Inc. - * - * Based on various ehci-*.c drivers - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file COPYING in the main directory of this archive for - * more details. - */ - -#include <linux/platform_device.h> - -static int ehci_xls_setup(struct usb_hcd *hcd) -{ - struct ehci_hcd *ehci = hcd_to_ehci(hcd); - - ehci->caps = hcd->regs; - - return ehci_setup(hcd); -} - -int ehci_xls_probe_internal(const struct hc_driver *driver, - struct platform_device *pdev) -{ - struct usb_hcd *hcd; - struct resource *res; - int retval, irq; - - /* Get our IRQ from an earlier registered Platform Resource */ - irq = platform_get_irq(pdev, 0); - if (irq < 0) { - dev_err(&pdev->dev, "Found HC with no IRQ. Check %s setup!\n", - dev_name(&pdev->dev)); - return -ENODEV; - } - - /* Get our Memory Handle */ - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - dev_err(&pdev->dev, "Error: MMIO Handle %s setup!\n", - dev_name(&pdev->dev)); - return -ENODEV; - } - hcd = usb_create_hcd(driver, &pdev->dev, dev_name(&pdev->dev)); - if (!hcd) { - retval = -ENOMEM; - goto err1; - } - - hcd->rsrc_start = res->start; - hcd->rsrc_len = resource_size(res); - - if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, - driver->description)) { - dev_dbg(&pdev->dev, "controller already in use\n"); - retval = -EBUSY; - goto err2; - } - hcd->regs = ioremap_nocache(hcd->rsrc_start, hcd->rsrc_len); - - if (hcd->regs == NULL) { - dev_dbg(&pdev->dev, "error mapping memory\n"); - retval = -EFAULT; - goto err3; - } - - retval = usb_add_hcd(hcd, irq, IRQF_SHARED); - if (retval != 0) - goto err4; - return retval; - -err4: - iounmap(hcd->regs); -err3: - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); -err2: - usb_put_hcd(hcd); -err1: - dev_err(&pdev->dev, "init %s fail, %d\n", dev_name(&pdev->dev), - retval); - return retval; -} - -static struct hc_driver ehci_xls_hc_driver = { - .description = hcd_name, - .product_desc = "XLS EHCI Host Controller", - .hcd_priv_size = sizeof(struct ehci_hcd), - .irq = ehci_irq, - .flags = HCD_USB2 | HCD_MEMORY, - .reset = ehci_xls_setup, - .start = ehci_run, - .stop = ehci_stop, - .shutdown = ehci_shutdown, - - .urb_enqueue = ehci_urb_enqueue, - .urb_dequeue = ehci_urb_dequeue, - .endpoint_disable = ehci_endpoint_disable, - .endpoint_reset = ehci_endpoint_reset, - - .get_frame_number = ehci_get_frame, - - .hub_status_data = ehci_hub_status_data, - .hub_control = ehci_hub_control, - .bus_suspend = ehci_bus_suspend, - .bus_resume = ehci_bus_resume, - .relinquish_port = ehci_relinquish_port, - .port_handed_over = ehci_port_handed_over, - - .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete, -}; - -static int ehci_xls_probe(struct platform_device *pdev) -{ - if (usb_disabled()) - return -ENODEV; - - return ehci_xls_probe_internal(&ehci_xls_hc_driver, pdev); -} - -static int ehci_xls_remove(struct platform_device *pdev) -{ - struct usb_hcd *hcd = platform_get_drvdata(pdev); - - usb_remove_hcd(hcd); - iounmap(hcd->regs); - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); - usb_put_hcd(hcd); - return 0; -} - -MODULE_ALIAS("ehci-xls"); - -static struct platform_driver ehci_xls_driver = { - .probe = ehci_xls_probe, - .remove = ehci_xls_remove, - .shutdown = usb_hcd_platform_shutdown, - .driver = { - .name = "ehci-xls", - }, -}; diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h index da07d98f7d1d..9dadc7118d68 100644 --- a/drivers/usb/host/ehci.h +++ b/drivers/usb/host/ehci.h @@ -143,7 +143,7 @@ struct ehci_hcd { /* one per controller */ struct ehci_qh *intr_unlink_last; unsigned intr_unlink_cycle; unsigned now_frame; /* frame from HC hardware */ - unsigned next_frame; /* scan periodic, start here */ + unsigned last_iso_frame; /* last frame scanned for iso */ unsigned intr_count; /* intr activity count */ unsigned isoc_count; /* isoc activity count */ unsigned periodic_count; /* periodic activity count */ @@ -193,7 +193,6 @@ struct ehci_hcd { /* one per controller */ unsigned has_amcc_usb23:1; unsigned need_io_watchdog:1; unsigned amd_pll_fix:1; - unsigned fs_i_thresh:1; /* Intel iso scheduling */ unsigned use_dummy_qh:1; /* AMD Frame List table quirk*/ unsigned has_synopsys_hc_bug:1; /* Synopsys HC */ unsigned frame_index_bug:1; /* MosChip (AKA NetMos) */ @@ -207,7 +206,6 @@ struct ehci_hcd { /* one per controller */ #define OHCI_HCCTRL_LEN 0x4 __hc32 *ohci_hcctrl_reg; unsigned has_hostpc:1; - unsigned has_lpm:1; /* support link power management */ unsigned has_ppcd:1; /* support per-port change bits */ u8 sbrn; /* packed release number */ @@ -762,26 +760,41 @@ static inline u32 hc32_to_cpup (const struct ehci_hcd *ehci, const __hc32 *x) /*-------------------------------------------------------------------------*/ -#ifdef CONFIG_PCI - -/* For working around the MosChip frame-index-register bug */ -static unsigned ehci_read_frame_index(struct ehci_hcd *ehci); - +#define ehci_dbg(ehci, fmt, args...) \ + dev_dbg(ehci_to_hcd(ehci)->self.controller , fmt , ## args) +#define ehci_err(ehci, fmt, args...) \ + dev_err(ehci_to_hcd(ehci)->self.controller , fmt , ## args) +#define ehci_info(ehci, fmt, args...) \ + dev_info(ehci_to_hcd(ehci)->self.controller , fmt , ## args) +#define ehci_warn(ehci, fmt, args...) \ + dev_warn(ehci_to_hcd(ehci)->self.controller , fmt , ## args) + +#ifdef VERBOSE_DEBUG +# define ehci_vdbg ehci_dbg #else - -static inline unsigned ehci_read_frame_index(struct ehci_hcd *ehci) -{ - return ehci_readl(ehci, &ehci->regs->frame_index); -} - + static inline void ehci_vdbg(struct ehci_hcd *ehci, ...) {} #endif -/*-------------------------------------------------------------------------*/ - #ifndef DEBUG #define STUB_DEBUG_FILES #endif /* DEBUG */ /*-------------------------------------------------------------------------*/ +/* Declarations of things exported for use by ehci platform drivers */ + +struct ehci_driver_overrides { + size_t extra_priv_size; + int (*reset)(struct usb_hcd *hcd); +}; + +extern void ehci_init_driver(struct hc_driver *drv, + const struct ehci_driver_overrides *over); +extern int ehci_setup(struct usb_hcd *hcd); + +#ifdef CONFIG_PM +extern int ehci_suspend(struct usb_hcd *hcd, bool do_wakeup); +extern int ehci_resume(struct usb_hcd *hcd, bool hibernated); +#endif /* CONFIG_PM */ + #endif /* __LINUX_EHCI_HCD_H */ diff --git a/drivers/usb/host/isp1760-if.c b/drivers/usb/host/isp1760-if.c index fff114fd5461..958379f9de79 100644 --- a/drivers/usb/host/isp1760-if.c +++ b/drivers/usb/host/isp1760-if.c @@ -43,7 +43,6 @@ static int of_isp1760_probe(struct platform_device *dev) struct device_node *dp = dev->dev.of_node; struct resource *res; struct resource memory; - struct of_irq oirq; int virq; resource_size_t res_len; int ret; @@ -69,14 +68,12 @@ static int of_isp1760_probe(struct platform_device *dev) goto free_data; } - if (of_irq_map_one(dp, 0, &oirq)) { + virq = irq_of_parse_and_map(dp, 0); + if (!virq) { ret = -ENODEV; goto release_reg; } - virq = irq_create_of_mapping(oirq.controller, oirq.specifier, - oirq.size); - if (of_device_is_compatible(dp, "nxp,usb-isp1761")) devflags |= ISP1760_FLAG_ISP1761; diff --git a/drivers/usb/host/ohci-at91.c b/drivers/usb/host/ohci-at91.c index 0bf72f943b00..908d84af1dd7 100644 --- a/drivers/usb/host/ohci-at91.c +++ b/drivers/usb/host/ohci-at91.c @@ -705,7 +705,7 @@ static int ohci_hcd_at91_drv_resume(struct platform_device *pdev) if (!clocked) at91_start_clock(); - ohci_finish_controller_resume(hcd); + ohci_resume(hcd, false); return 0; } #else diff --git a/drivers/usb/host/ohci-au1xxx.c b/drivers/usb/host/ohci-au1xxx.c deleted file mode 100644 index c611699b4aa6..000000000000 --- a/drivers/usb/host/ohci-au1xxx.c +++ /dev/null @@ -1,234 +0,0 @@ -/* - * OHCI HCD (Host Controller Driver) for USB. - * - * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at> - * (C) Copyright 2000-2002 David Brownell <dbrownell@users.sourceforge.net> - * (C) Copyright 2002 Hewlett-Packard Company - * - * Bus Glue for AMD Alchemy Au1xxx - * - * Written by Christopher Hoover <ch@hpl.hp.com> - * Based on fragments of previous driver by Russell King et al. - * - * Modified for LH7A404 from ohci-sa1111.c - * by Durgesh Pattamatta <pattamattad@sharpsec.com> - * Modified for AMD Alchemy Au1xxx - * by Matt Porter <mporter@kernel.crashing.org> - * - * This file is licenced under the GPL. - */ - -#include <linux/platform_device.h> -#include <linux/signal.h> - -#include <asm/mach-au1x00/au1000.h> - - -extern int usb_disabled(void); - -static int __devinit ohci_au1xxx_start(struct usb_hcd *hcd) -{ - struct ohci_hcd *ohci = hcd_to_ohci(hcd); - int ret; - - ohci_dbg(ohci, "ohci_au1xxx_start, ohci:%p", ohci); - - if ((ret = ohci_init(ohci)) < 0) - return ret; - - if ((ret = ohci_run(ohci)) < 0) { - dev_err(hcd->self.controller, "can't start %s", - hcd->self.bus_name); - ohci_stop(hcd); - return ret; - } - - return 0; -} - -static const struct hc_driver ohci_au1xxx_hc_driver = { - .description = hcd_name, - .product_desc = "Au1xxx OHCI", - .hcd_priv_size = sizeof(struct ohci_hcd), - - /* - * generic hardware linkage - */ - .irq = ohci_irq, - .flags = HCD_USB11 | HCD_MEMORY, - - /* - * basic lifecycle operations - */ - .start = ohci_au1xxx_start, - .stop = ohci_stop, - .shutdown = ohci_shutdown, - - /* - * managing i/o requests and associated device resources - */ - .urb_enqueue = ohci_urb_enqueue, - .urb_dequeue = ohci_urb_dequeue, - .endpoint_disable = ohci_endpoint_disable, - - /* - * scheduling support - */ - .get_frame_number = ohci_get_frame, - - /* - * root hub support - */ - .hub_status_data = ohci_hub_status_data, - .hub_control = ohci_hub_control, -#ifdef CONFIG_PM - .bus_suspend = ohci_bus_suspend, - .bus_resume = ohci_bus_resume, -#endif - .start_port_reset = ohci_start_port_reset, -}; - -static int ohci_hcd_au1xxx_drv_probe(struct platform_device *pdev) -{ - int ret, unit; - struct usb_hcd *hcd; - - if (usb_disabled()) - return -ENODEV; - - if (pdev->resource[1].flags != IORESOURCE_IRQ) { - pr_debug("resource[1] is not IORESOURCE_IRQ\n"); - return -ENOMEM; - } - - hcd = usb_create_hcd(&ohci_au1xxx_hc_driver, &pdev->dev, "au1xxx"); - if (!hcd) - return -ENOMEM; - - hcd->rsrc_start = pdev->resource[0].start; - hcd->rsrc_len = pdev->resource[0].end - pdev->resource[0].start + 1; - - if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) { - pr_debug("request_mem_region failed\n"); - ret = -EBUSY; - goto err1; - } - - hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len); - if (!hcd->regs) { - pr_debug("ioremap failed\n"); - ret = -ENOMEM; - goto err2; - } - - unit = (hcd->rsrc_start == AU1300_USB_OHCI1_PHYS_ADDR) ? - ALCHEMY_USB_OHCI1 : ALCHEMY_USB_OHCI0; - if (alchemy_usb_control(unit, 1)) { - printk(KERN_INFO "%s: controller init failed!\n", pdev->name); - ret = -ENODEV; - goto err3; - } - - ohci_hcd_init(hcd_to_ohci(hcd)); - - ret = usb_add_hcd(hcd, pdev->resource[1].start, - IRQF_SHARED); - if (ret == 0) { - platform_set_drvdata(pdev, hcd); - return ret; - } - - alchemy_usb_control(unit, 0); -err3: - iounmap(hcd->regs); -err2: - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); -err1: - usb_put_hcd(hcd); - return ret; -} - -static int ohci_hcd_au1xxx_drv_remove(struct platform_device *pdev) -{ - struct usb_hcd *hcd = platform_get_drvdata(pdev); - int unit; - - unit = (hcd->rsrc_start == AU1300_USB_OHCI1_PHYS_ADDR) ? - ALCHEMY_USB_OHCI1 : ALCHEMY_USB_OHCI0; - usb_remove_hcd(hcd); - alchemy_usb_control(unit, 0); - iounmap(hcd->regs); - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); - usb_put_hcd(hcd); - platform_set_drvdata(pdev, NULL); - - return 0; -} - -#ifdef CONFIG_PM -static int ohci_hcd_au1xxx_drv_suspend(struct device *dev) -{ - struct usb_hcd *hcd = dev_get_drvdata(dev); - struct ohci_hcd *ohci = hcd_to_ohci(hcd); - unsigned long flags; - int rc; - - rc = 0; - - /* Root hub was already suspended. Disable irq emission and - * mark HW unaccessible, bail out if RH has been resumed. Use - * the spinlock to properly synchronize with possible pending - * RH suspend or resume activity. - */ - spin_lock_irqsave(&ohci->lock, flags); - if (ohci->rh_state != OHCI_RH_SUSPENDED) { - rc = -EINVAL; - goto bail; - } - ohci_writel(ohci, OHCI_INTR_MIE, &ohci->regs->intrdisable); - (void)ohci_readl(ohci, &ohci->regs->intrdisable); - - clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); - - alchemy_usb_control(ALCHEMY_USB_OHCI0, 0); -bail: - spin_unlock_irqrestore(&ohci->lock, flags); - - return rc; -} - -static int ohci_hcd_au1xxx_drv_resume(struct device *dev) -{ - struct usb_hcd *hcd = dev_get_drvdata(dev); - - alchemy_usb_control(ALCHEMY_USB_OHCI0, 1); - - set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); - ohci_finish_controller_resume(hcd); - - return 0; -} - -static const struct dev_pm_ops au1xxx_ohci_pmops = { - .suspend = ohci_hcd_au1xxx_drv_suspend, - .resume = ohci_hcd_au1xxx_drv_resume, -}; - -#define AU1XXX_OHCI_PMOPS &au1xxx_ohci_pmops - -#else -#define AU1XXX_OHCI_PMOPS NULL -#endif - -static struct platform_driver ohci_hcd_au1xxx_driver = { - .probe = ohci_hcd_au1xxx_drv_probe, - .remove = ohci_hcd_au1xxx_drv_remove, - .shutdown = usb_hcd_platform_shutdown, - .driver = { - .name = "au1xxx-ohci", - .owner = THIS_MODULE, - .pm = AU1XXX_OHCI_PMOPS, - }, -}; - -MODULE_ALIAS("platform:au1xxx-ohci"); diff --git a/drivers/usb/host/ohci-cns3xxx.c b/drivers/usb/host/ohci-cns3xxx.c deleted file mode 100644 index 2c9f233047be..000000000000 --- a/drivers/usb/host/ohci-cns3xxx.c +++ /dev/null @@ -1,166 +0,0 @@ -/* - * Copyright 2008 Cavium Networks - * - * This file is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License, Version 2, as - * published by the Free Software Foundation. - */ - -#include <linux/platform_device.h> -#include <linux/atomic.h> -#include <mach/cns3xxx.h> -#include <mach/pm.h> - -static int __devinit -cns3xxx_ohci_start(struct usb_hcd *hcd) -{ - struct ohci_hcd *ohci = hcd_to_ohci(hcd); - int ret; - - /* - * EHCI and OHCI share the same clock and power, - * resetting twice would cause the 1st controller been reset. - * Therefore only do power up at the first up device, and - * power down at the last down device. - * - * Set USB AHB INCR length to 16 - */ - if (atomic_inc_return(&usb_pwr_ref) == 1) { - cns3xxx_pwr_power_up(1 << PM_PLL_HM_PD_CTRL_REG_OFFSET_PLL_USB); - cns3xxx_pwr_clk_en(1 << PM_CLK_GATE_REG_OFFSET_USB_HOST); - cns3xxx_pwr_soft_rst(1 << PM_SOFT_RST_REG_OFFST_USB_HOST); - __raw_writel((__raw_readl(MISC_CHIP_CONFIG_REG) | (0X2 << 24)), - MISC_CHIP_CONFIG_REG); - } - - ret = ohci_init(ohci); - if (ret < 0) - return ret; - - ohci->num_ports = 1; - - ret = ohci_run(ohci); - if (ret < 0) { - dev_err(hcd->self.controller, "can't start %s\n", - hcd->self.bus_name); - ohci_stop(hcd); - return ret; - } - return 0; -} - -static const struct hc_driver cns3xxx_ohci_hc_driver = { - .description = hcd_name, - .product_desc = "CNS3XXX OHCI Host controller", - .hcd_priv_size = sizeof(struct ohci_hcd), - .irq = ohci_irq, - .flags = HCD_USB11 | HCD_MEMORY, - .start = cns3xxx_ohci_start, - .stop = ohci_stop, - .shutdown = ohci_shutdown, - .urb_enqueue = ohci_urb_enqueue, - .urb_dequeue = ohci_urb_dequeue, - .endpoint_disable = ohci_endpoint_disable, - .get_frame_number = ohci_get_frame, - .hub_status_data = ohci_hub_status_data, - .hub_control = ohci_hub_control, -#ifdef CONFIG_PM - .bus_suspend = ohci_bus_suspend, - .bus_resume = ohci_bus_resume, -#endif - .start_port_reset = ohci_start_port_reset, -}; - -static int cns3xxx_ohci_probe(struct platform_device *pdev) -{ - struct device *dev = &pdev->dev; - struct usb_hcd *hcd; - const struct hc_driver *driver = &cns3xxx_ohci_hc_driver; - struct resource *res; - int irq; - int retval; - - if (usb_disabled()) - return -ENODEV; - - res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); - if (!res) { - dev_err(dev, "Found HC with no IRQ.\n"); - return -ENODEV; - } - irq = res->start; - - hcd = usb_create_hcd(driver, dev, dev_name(dev)); - if (!hcd) - return -ENOMEM; - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - dev_err(dev, "Found HC with no register addr.\n"); - retval = -ENODEV; - goto err1; - } - hcd->rsrc_start = res->start; - hcd->rsrc_len = resource_size(res); - - if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, - driver->description)) { - dev_dbg(dev, "controller already in use\n"); - retval = -EBUSY; - goto err1; - } - - hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len); - if (!hcd->regs) { - dev_dbg(dev, "error mapping memory\n"); - retval = -EFAULT; - goto err2; - } - - ohci_hcd_init(hcd_to_ohci(hcd)); - - retval = usb_add_hcd(hcd, irq, IRQF_SHARED); - if (retval == 0) - return retval; - - iounmap(hcd->regs); -err2: - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); -err1: - usb_put_hcd(hcd); - return retval; -} - -static int cns3xxx_ohci_remove(struct platform_device *pdev) -{ - struct usb_hcd *hcd = platform_get_drvdata(pdev); - - usb_remove_hcd(hcd); - iounmap(hcd->regs); - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); - - /* - * EHCI and OHCI share the same clock and power, - * resetting twice would cause the 1st controller been reset. - * Therefore only do power up at the first up device, and - * power down at the last down device. - */ - if (atomic_dec_return(&usb_pwr_ref) == 0) - cns3xxx_pwr_clk_dis(1 << PM_CLK_GATE_REG_OFFSET_USB_HOST); - - usb_put_hcd(hcd); - - platform_set_drvdata(pdev, NULL); - - return 0; -} - -MODULE_ALIAS("platform:cns3xxx-ohci"); - -static struct platform_driver ohci_hcd_cns3xxx_driver = { - .probe = cns3xxx_ohci_probe, - .remove = cns3xxx_ohci_remove, - .driver = { - .name = "cns3xxx-ohci", - }, -}; diff --git a/drivers/usb/host/ohci-ep93xx.c b/drivers/usb/host/ohci-ep93xx.c index dbfbd1dfd2e2..a982f04ed787 100644 --- a/drivers/usb/host/ohci-ep93xx.c +++ b/drivers/usb/host/ohci-ep93xx.c @@ -194,7 +194,7 @@ static int ohci_hcd_ep93xx_drv_resume(struct platform_device *pdev) ep93xx_start_hc(&pdev->dev); - ohci_finish_controller_resume(hcd); + ohci_resume(hcd, false); return 0; } #endif diff --git a/drivers/usb/host/ohci-exynos.c b/drivers/usb/host/ohci-exynos.c index 20a50081f922..6a30fc5bec93 100644 --- a/drivers/usb/host/ohci-exynos.c +++ b/drivers/usb/host/ohci-exynos.c @@ -23,6 +23,11 @@ struct exynos_ohci_hcd { struct clk *clk; }; +static int ohci_exynos_reset(struct usb_hcd *hcd) +{ + return ohci_init(hcd_to_ohci(hcd)); +} + static int ohci_exynos_start(struct usb_hcd *hcd) { struct ohci_hcd *ohci = hcd_to_ohci(hcd); @@ -30,10 +35,6 @@ static int ohci_exynos_start(struct usb_hcd *hcd) ohci_dbg(ohci, "ohci_exynos_start, ohci:%p", ohci); - ret = ohci_init(ohci); - if (ret < 0) - return ret; - ret = ohci_run(ohci); if (ret < 0) { dev_err(hcd->self.controller, "can't start %s\n", @@ -53,6 +54,7 @@ static const struct hc_driver exynos_ohci_hc_driver = { .irq = ohci_irq, .flags = HCD_MEMORY|HCD_USB11, + .reset = ohci_exynos_reset, .start = ohci_exynos_start, .stop = ohci_stop, .shutdown = ohci_shutdown, @@ -115,7 +117,7 @@ static int __devinit exynos_ohci_probe(struct platform_device *pdev) } exynos_ohci->hcd = hcd; - exynos_ohci->clk = clk_get(&pdev->dev, "usbhost"); + exynos_ohci->clk = devm_clk_get(&pdev->dev, "usbhost"); if (IS_ERR(exynos_ohci->clk)) { dev_err(&pdev->dev, "Failed to get usbhost clock\n"); @@ -123,9 +125,9 @@ static int __devinit exynos_ohci_probe(struct platform_device *pdev) goto fail_clk; } - err = clk_enable(exynos_ohci->clk); + err = clk_prepare_enable(exynos_ohci->clk); if (err) - goto fail_clken; + goto fail_clk; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) { @@ -167,9 +169,7 @@ static int __devinit exynos_ohci_probe(struct platform_device *pdev) return 0; fail_io: - clk_disable(exynos_ohci->clk); -fail_clken: - clk_put(exynos_ohci->clk); + clk_disable_unprepare(exynos_ohci->clk); fail_clk: usb_put_hcd(hcd); return err; @@ -186,8 +186,7 @@ static int __devexit exynos_ohci_remove(struct platform_device *pdev) if (pdata && pdata->phy_exit) pdata->phy_exit(pdev, S5P_USB_PHY_HOST); - clk_disable(exynos_ohci->clk); - clk_put(exynos_ohci->clk); + clk_disable_unprepare(exynos_ohci->clk); usb_put_hcd(hcd); @@ -232,7 +231,7 @@ static int exynos_ohci_suspend(struct device *dev) if (pdata && pdata->phy_exit) pdata->phy_exit(pdev, S5P_USB_PHY_HOST); - clk_disable(exynos_ohci->clk); + clk_disable_unprepare(exynos_ohci->clk); fail: spin_unlock_irqrestore(&ohci->lock, flags); @@ -247,15 +246,12 @@ static int exynos_ohci_resume(struct device *dev) struct platform_device *pdev = to_platform_device(dev); struct exynos4_ohci_platdata *pdata = pdev->dev.platform_data; - clk_enable(exynos_ohci->clk); + clk_prepare_enable(exynos_ohci->clk); if (pdata && pdata->phy_init) pdata->phy_init(pdev, S5P_USB_PHY_HOST); - /* Mark hardware accessible again as we are out of D3 state by now */ - set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); - - ohci_finish_controller_resume(hcd); + ohci_resume(hcd, false); return 0; } diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c index 4a1d64d92338..180a2b01db56 100644 --- a/drivers/usb/host/ohci-hcd.c +++ b/drivers/usb/host/ohci-hcd.c @@ -231,13 +231,41 @@ static int ohci_urb_enqueue ( frame &= ~(ed->interval - 1); frame |= ed->branch; urb->start_frame = frame; + } + } else if (ed->type == PIPE_ISOCHRONOUS) { + u16 next = ohci_frame_no(ohci) + 2; + u16 frame = ed->last_iso + ed->interval; + + /* Behind the scheduling threshold? */ + if (unlikely(tick_before(frame, next))) { - /* yes, only URB_ISO_ASAP is supported, and - * urb->start_frame is never used as input. + /* USB_ISO_ASAP: Round up to the first available slot */ + if (urb->transfer_flags & URB_ISO_ASAP) + frame += (next - frame + ed->interval - 1) & + -ed->interval; + + /* + * Not ASAP: Use the next slot in the stream. If + * the entire URB falls before the threshold, fail. */ + else if (tick_before(frame + ed->interval * + (urb->number_of_packets - 1), next)) { + retval = -EXDEV; + usb_hcd_unlink_urb_from_ep(hcd, urb); + goto fail; + } + + /* + * Some OHCI hardware doesn't handle late TDs + * correctly. After retiring them it proceeds to + * the next ED instead of the next TD. Therefore + * we have to omit the late TDs entirely. + */ + urb_priv->td_cnt = DIV_ROUND_UP(next - frame, + ed->interval); } - } else if (ed->type == PIPE_ISOCHRONOUS) - urb->start_frame = ed->last_iso + ed->interval; + urb->start_frame = frame; + } /* fill the TDs and link them to the ed; and * enable that part of the schedule, if needed @@ -983,6 +1011,79 @@ static int ohci_restart (struct ohci_hcd *ohci) #endif +#ifdef CONFIG_PM + +static int __maybe_unused ohci_suspend(struct usb_hcd *hcd, bool do_wakeup) +{ + struct ohci_hcd *ohci = hcd_to_ohci (hcd); + unsigned long flags; + + /* Disable irq emission and mark HW unaccessible. Use + * the spinlock to properly synchronize with possible pending + * RH suspend or resume activity. + */ + spin_lock_irqsave (&ohci->lock, flags); + ohci_writel(ohci, OHCI_INTR_MIE, &ohci->regs->intrdisable); + (void)ohci_readl(ohci, &ohci->regs->intrdisable); + + clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); + spin_unlock_irqrestore (&ohci->lock, flags); + + return 0; +} + + +static int __maybe_unused ohci_resume(struct usb_hcd *hcd, bool hibernated) +{ + struct ohci_hcd *ohci = hcd_to_ohci(hcd); + int port; + bool need_reinit = false; + + set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); + + /* Make sure resume from hibernation re-enumerates everything */ + if (hibernated) + ohci_usb_reset(ohci); + + /* See if the controller is already running or has been reset */ + ohci->hc_control = ohci_readl(ohci, &ohci->regs->control); + if (ohci->hc_control & (OHCI_CTRL_IR | OHCI_SCHED_ENABLES)) { + need_reinit = true; + } else { + switch (ohci->hc_control & OHCI_CTRL_HCFS) { + case OHCI_USB_OPER: + case OHCI_USB_RESET: + need_reinit = true; + } + } + + /* If needed, reinitialize and suspend the root hub */ + if (need_reinit) { + spin_lock_irq(&ohci->lock); + ohci_rh_resume(ohci); + ohci_rh_suspend(ohci, 0); + spin_unlock_irq(&ohci->lock); + } + + /* Normally just turn on port power and enable interrupts */ + else { + ohci_dbg(ohci, "powerup ports\n"); + for (port = 0; port < ohci->num_ports; port++) + ohci_writel(ohci, RH_PS_PPS, + &ohci->regs->roothub.portstatus[port]); + + ohci_writel(ohci, OHCI_INTR_MIE, &ohci->regs->intrenable); + ohci_readl(ohci, &ohci->regs->intrenable); + msleep(20); + } + + usb_hcd_resume_root_hub(hcd); + + return 0; +} + +#endif + /*-------------------------------------------------------------------------*/ MODULE_AUTHOR (DRIVER_AUTHOR); @@ -1029,21 +1130,6 @@ MODULE_LICENSE ("GPL"); #define PLATFORM_DRIVER ohci_hcd_ep93xx_driver #endif -#ifdef CONFIG_MIPS_ALCHEMY -#include "ohci-au1xxx.c" -#define PLATFORM_DRIVER ohci_hcd_au1xxx_driver -#endif - -#ifdef CONFIG_PNX8550 -#include "ohci-pnx8550.c" -#define PLATFORM_DRIVER ohci_hcd_pnx8550_driver -#endif - -#ifdef CONFIG_USB_OHCI_HCD_PPC_SOC -#include "ohci-ppc-soc.c" -#define PLATFORM_DRIVER ohci_hcd_ppc_soc_driver -#endif - #ifdef CONFIG_ARCH_AT91 #include "ohci-at91.c" #define PLATFORM_DRIVER ohci_hcd_at91_driver @@ -1059,11 +1145,6 @@ MODULE_LICENSE ("GPL"); #define PLATFORM_DRIVER ohci_hcd_da8xx_driver #endif -#ifdef CONFIG_USB_OHCI_SH -#include "ohci-sh.c" -#define PLATFORM_DRIVER ohci_hcd_sh_driver -#endif - #ifdef CONFIG_USB_OHCI_HCD_PPC_OF #include "ohci-ppc-of.c" @@ -1105,16 +1186,6 @@ MODULE_LICENSE ("GPL"); #define PLATFORM_DRIVER ohci_hcd_tilegx_driver #endif -#ifdef CONFIG_USB_CNS3XXX_OHCI -#include "ohci-cns3xxx.c" -#define PLATFORM_DRIVER ohci_hcd_cns3xxx_driver -#endif - -#ifdef CONFIG_CPU_XLR -#include "ohci-xls.c" -#define PLATFORM_DRIVER ohci_xls_driver -#endif - #ifdef CONFIG_USB_OHCI_HCD_PLATFORM #include "ohci-platform.c" #define PLATFORM_DRIVER ohci_platform_driver diff --git a/drivers/usb/host/ohci-hub.c b/drivers/usb/host/ohci-hub.c index 2f3619eefefa..db09dae7b557 100644 --- a/drivers/usb/host/ohci-hub.c +++ b/drivers/usb/host/ohci-hub.c @@ -316,48 +316,6 @@ static int ohci_bus_resume (struct usb_hcd *hcd) return rc; } -/* Carry out the final steps of resuming the controller device */ -static void __maybe_unused ohci_finish_controller_resume(struct usb_hcd *hcd) -{ - struct ohci_hcd *ohci = hcd_to_ohci(hcd); - int port; - bool need_reinit = false; - - /* See if the controller is already running or has been reset */ - ohci->hc_control = ohci_readl(ohci, &ohci->regs->control); - if (ohci->hc_control & (OHCI_CTRL_IR | OHCI_SCHED_ENABLES)) { - need_reinit = true; - } else { - switch (ohci->hc_control & OHCI_CTRL_HCFS) { - case OHCI_USB_OPER: - case OHCI_USB_RESET: - need_reinit = true; - } - } - - /* If needed, reinitialize and suspend the root hub */ - if (need_reinit) { - spin_lock_irq(&ohci->lock); - ohci_rh_resume(ohci); - ohci_rh_suspend(ohci, 0); - spin_unlock_irq(&ohci->lock); - } - - /* Normally just turn on port power and enable interrupts */ - else { - ohci_dbg(ohci, "powerup ports\n"); - for (port = 0; port < ohci->num_ports; port++) - ohci_writel(ohci, RH_PS_PPS, - &ohci->regs->roothub.portstatus[port]); - - ohci_writel(ohci, OHCI_INTR_MIE, &ohci->regs->intrenable); - ohci_readl(ohci, &ohci->regs->intrenable); - msleep(20); - } - - usb_hcd_resume_root_hub(hcd); -} - /* Carry out polling-, autostop-, and autoresume-related state changes */ static int ohci_root_hub_state_changes(struct ohci_hcd *ohci, int changed, int any_connected, int rhsc_status) diff --git a/drivers/usb/host/ohci-omap.c b/drivers/usb/host/ohci-omap.c index 4531d03503c3..733c77c36355 100644 --- a/drivers/usb/host/ohci-omap.c +++ b/drivers/usb/host/ohci-omap.c @@ -530,7 +530,7 @@ static int ohci_omap_resume(struct platform_device *dev) ohci->next_statechange = jiffies; omap_ohci_clock_power(1); - ohci_finish_controller_resume(hcd); + ohci_resume(hcd, false); return 0; } diff --git a/drivers/usb/host/ohci-pci.c b/drivers/usb/host/ohci-pci.c index 1843bb68ac7c..6afa7dc4e4c3 100644 --- a/drivers/usb/host/ohci-pci.c +++ b/drivers/usb/host/ohci-pci.c @@ -296,49 +296,6 @@ static int __devinit ohci_pci_start (struct usb_hcd *hcd) return ret; } -#ifdef CONFIG_PM - -static int ohci_pci_suspend(struct usb_hcd *hcd, bool do_wakeup) -{ - struct ohci_hcd *ohci = hcd_to_ohci (hcd); - unsigned long flags; - int rc = 0; - - /* Root hub was already suspended. Disable irq emission and - * mark HW unaccessible, bail out if RH has been resumed. Use - * the spinlock to properly synchronize with possible pending - * RH suspend or resume activity. - */ - spin_lock_irqsave (&ohci->lock, flags); - if (ohci->rh_state != OHCI_RH_SUSPENDED) { - rc = -EINVAL; - goto bail; - } - ohci_writel(ohci, OHCI_INTR_MIE, &ohci->regs->intrdisable); - (void)ohci_readl(ohci, &ohci->regs->intrdisable); - - clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); - bail: - spin_unlock_irqrestore (&ohci->lock, flags); - - return rc; -} - - -static int ohci_pci_resume(struct usb_hcd *hcd, bool hibernated) -{ - set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); - - /* Make sure resume from hibernation re-enumerates everything */ - if (hibernated) - ohci_usb_reset(hcd_to_ohci(hcd)); - - ohci_finish_controller_resume(hcd); - return 0; -} - -#endif /* CONFIG_PM */ - /*-------------------------------------------------------------------------*/ @@ -362,8 +319,8 @@ static const struct hc_driver ohci_pci_hc_driver = { .shutdown = ohci_shutdown, #ifdef CONFIG_PM - .pci_suspend = ohci_pci_suspend, - .pci_resume = ohci_pci_resume, + .pci_suspend = ohci_suspend, + .pci_resume = ohci_resume, #endif /* diff --git a/drivers/usb/host/ohci-platform.c b/drivers/usb/host/ohci-platform.c index e24ec9f79164..bda4e0bb8ab3 100644 --- a/drivers/usb/host/ohci-platform.c +++ b/drivers/usb/host/ohci-platform.c @@ -31,6 +31,10 @@ static int ohci_platform_reset(struct usb_hcd *hcd) ohci->flags |= OHCI_QUIRK_FRAME_NO; ohci_hcd_init(ohci); + + if (pdata->num_ports) + ohci->num_ports = pdata->num_ports; + err = ohci_init(ohci); return err; @@ -97,13 +101,13 @@ static int __devinit ohci_platform_probe(struct platform_device *dev) irq = platform_get_irq(dev, 0); if (irq < 0) { - pr_err("no irq provided"); + dev_err(&dev->dev, "no irq provided"); return irq; } res_mem = platform_get_resource(dev, IORESOURCE_MEM, 0); if (!res_mem) { - pr_err("no memory recourse provided"); + dev_err(&dev->dev, "no memory resource provided"); return -ENXIO; } @@ -123,29 +127,19 @@ static int __devinit ohci_platform_probe(struct platform_device *dev) hcd->rsrc_start = res_mem->start; hcd->rsrc_len = resource_size(res_mem); - if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) { - pr_err("controller already in use"); - err = -EBUSY; - goto err_put_hcd; - } - - hcd->regs = ioremap_nocache(hcd->rsrc_start, hcd->rsrc_len); + hcd->regs = devm_request_and_ioremap(&dev->dev, res_mem); if (!hcd->regs) { err = -ENOMEM; - goto err_release_region; + goto err_put_hcd; } err = usb_add_hcd(hcd, irq, IRQF_SHARED); if (err) - goto err_iounmap; + goto err_put_hcd; platform_set_drvdata(dev, hcd); return err; -err_iounmap: - iounmap(hcd->regs); -err_release_region: - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); err_put_hcd: usb_put_hcd(hcd); err_power: @@ -161,8 +155,6 @@ static int __devexit ohci_platform_remove(struct platform_device *dev) struct usb_ohci_pdata *pdata = dev->dev.platform_data; usb_remove_hcd(hcd); - iounmap(hcd->regs); - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); usb_put_hcd(hcd); platform_set_drvdata(dev, NULL); @@ -199,7 +191,7 @@ static int ohci_platform_resume(struct device *dev) return err; } - ohci_finish_controller_resume(hcd); + ohci_resume(hcd, false); return 0; } diff --git a/drivers/usb/host/ohci-pnx8550.c b/drivers/usb/host/ohci-pnx8550.c deleted file mode 100644 index 148d27d6a67c..000000000000 --- a/drivers/usb/host/ohci-pnx8550.c +++ /dev/null @@ -1,243 +0,0 @@ -/* - * OHCI HCD (Host Controller Driver) for USB. - * - * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at> - * (C) Copyright 2000-2002 David Brownell <dbrownell@users.sourceforge.net> - * (C) Copyright 2002 Hewlett-Packard Company - * (C) Copyright 2005 Embedded Alley Solutions, Inc. - * - * Bus Glue for PNX8550 - * - * Written by Christopher Hoover <ch@hpl.hp.com> - * Based on fragments of previous driver by Russell King et al. - * - * Modified for LH7A404 from ohci-sa1111.c - * by Durgesh Pattamatta <pattamattad@sharpsec.com> - * - * Modified for PNX8550 from ohci-sa1111.c and sa-omap.c - * by Vitaly Wool <vitalywool@gmail.com> - * - * This file is licenced under the GPL. - */ - -#include <linux/device.h> -#include <linux/platform_device.h> -#include <asm/mach-pnx8550/usb.h> -#include <asm/mach-pnx8550/int.h> -#include <asm/mach-pnx8550/pci.h> - -#ifndef CONFIG_PNX8550 -#error "This file is PNX8550 bus glue. CONFIG_PNX8550 must be defined." -#endif - -extern int usb_disabled(void); - -/*-------------------------------------------------------------------------*/ - -static void pnx8550_start_hc(struct platform_device *dev) -{ - /* - * Set register CLK48CTL to enable and 48MHz - */ - outl(0x00000003, PCI_BASE | 0x0004770c); - - /* - * Set register CLK12CTL to enable and 48MHz - */ - outl(0x00000003, PCI_BASE | 0x00047710); - - udelay(100); -} - -static void pnx8550_stop_hc(struct platform_device *dev) -{ - udelay(10); -} - - -/*-------------------------------------------------------------------------*/ - -/* configure so an HC device and id are always provided */ -/* always called with process context; sleeping is OK */ - - -/** - * usb_hcd_pnx8550_probe - initialize pnx8550-based HCDs - * Context: !in_interrupt() - * - * Allocates basic resources for this USB host controller, and - * then invokes the start() method for the HCD associated with it - * through the hotplug entry's driver_data. - * - */ -int usb_hcd_pnx8550_probe (const struct hc_driver *driver, - struct platform_device *dev) -{ - int retval; - struct usb_hcd *hcd; - - if (dev->resource[0].flags != IORESOURCE_MEM || - dev->resource[1].flags != IORESOURCE_IRQ) { - dev_err (&dev->dev,"invalid resource type\n"); - return -ENOMEM; - } - - hcd = usb_create_hcd (driver, &dev->dev, "pnx8550"); - if (!hcd) - return -ENOMEM; - hcd->rsrc_start = dev->resource[0].start; - hcd->rsrc_len = dev->resource[0].end - dev->resource[0].start + 1; - - if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) { - dev_err(&dev->dev, "request_mem_region [0x%08llx, 0x%08llx] " - "failed\n", hcd->rsrc_start, hcd->rsrc_len); - retval = -EBUSY; - goto err1; - } - - hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len); - if (!hcd->regs) { - dev_err(&dev->dev, "ioremap [[0x%08llx, 0x%08llx] failed\n", - hcd->rsrc_start, hcd->rsrc_len); - retval = -ENOMEM; - goto err2; - } - - pnx8550_start_hc(dev); - - ohci_hcd_init(hcd_to_ohci(hcd)); - - retval = usb_add_hcd(hcd, dev->resource[1].start, 0); - if (retval == 0) - return retval; - - pnx8550_stop_hc(dev); - iounmap(hcd->regs); - err2: - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); - err1: - usb_put_hcd(hcd); - return retval; -} - - -/* may be called without controller electrically present */ -/* may be called with controller, bus, and devices active */ - -/** - * usb_hcd_pnx8550_remove - shutdown processing for pnx8550-based HCDs - * @dev: USB Host Controller being removed - * Context: !in_interrupt() - * - * Reverses the effect of usb_hcd_pnx8550_probe(), first invoking - * the HCD's stop() method. It is always called from a thread - * context, normally "rmmod", "apmd", or something similar. - * - */ -void usb_hcd_pnx8550_remove (struct usb_hcd *hcd, struct platform_device *dev) -{ - usb_remove_hcd(hcd); - pnx8550_stop_hc(dev); - iounmap(hcd->regs); - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); - usb_put_hcd(hcd); -} - -/*-------------------------------------------------------------------------*/ - -static int __devinit -ohci_pnx8550_start (struct usb_hcd *hcd) -{ - struct ohci_hcd *ohci = hcd_to_ohci (hcd); - int ret; - - ohci_dbg (ohci, "ohci_pnx8550_start, ohci:%p", ohci); - - if ((ret = ohci_init(ohci)) < 0) - return ret; - - if ((ret = ohci_run (ohci)) < 0) { - dev_err(hcd->self.controller, "can't start %s", - hcd->self.bus_name); - ohci_stop (hcd); - return ret; - } - - return 0; -} - -/*-------------------------------------------------------------------------*/ - -static const struct hc_driver ohci_pnx8550_hc_driver = { - .description = hcd_name, - .product_desc = "PNX8550 OHCI", - .hcd_priv_size = sizeof(struct ohci_hcd), - - /* - * generic hardware linkage - */ - .irq = ohci_irq, - .flags = HCD_USB11 | HCD_MEMORY, - - /* - * basic lifecycle operations - */ - .start = ohci_pnx8550_start, - .stop = ohci_stop, - - /* - * managing i/o requests and associated device resources - */ - .urb_enqueue = ohci_urb_enqueue, - .urb_dequeue = ohci_urb_dequeue, - .endpoint_disable = ohci_endpoint_disable, - - /* - * scheduling support - */ - .get_frame_number = ohci_get_frame, - - /* - * root hub support - */ - .hub_status_data = ohci_hub_status_data, - .hub_control = ohci_hub_control, -#ifdef CONFIG_PM - .bus_suspend = ohci_bus_suspend, - .bus_resume = ohci_bus_resume, -#endif - .start_port_reset = ohci_start_port_reset, -}; - -/*-------------------------------------------------------------------------*/ - -static int ohci_hcd_pnx8550_drv_probe(struct platform_device *pdev) -{ - int ret; - - if (usb_disabled()) - return -ENODEV; - - ret = usb_hcd_pnx8550_probe(&ohci_pnx8550_hc_driver, pdev); - return ret; -} - -static int ohci_hcd_pnx8550_drv_remove(struct platform_device *pdev) -{ - struct usb_hcd *hcd = platform_get_drvdata(pdev); - - usb_hcd_pnx8550_remove(hcd, pdev); - return 0; -} - -MODULE_ALIAS("platform:pnx8550-ohci"); - -static struct platform_driver ohci_hcd_pnx8550_driver = { - .driver = { - .name = "pnx8550-ohci", - .owner = THIS_MODULE, - }, - .probe = ohci_hcd_pnx8550_drv_probe, - .remove = ohci_hcd_pnx8550_drv_remove, -}; - diff --git a/drivers/usb/host/ohci-ppc-soc.c b/drivers/usb/host/ohci-ppc-soc.c deleted file mode 100644 index 185c39ed81b7..000000000000 --- a/drivers/usb/host/ohci-ppc-soc.c +++ /dev/null @@ -1,216 +0,0 @@ -/* - * OHCI HCD (Host Controller Driver) for USB. - * - * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at> - * (C) Copyright 2000-2002 David Brownell <dbrownell@users.sourceforge.net> - * (C) Copyright 2002 Hewlett-Packard Company - * (C) Copyright 2003-2005 MontaVista Software Inc. - * - * Bus Glue for PPC On-Chip OHCI driver - * Tested on Freescale MPC5200 and IBM STB04xxx - * - * Modified by Dale Farnsworth <dale@farnsworth.org> from ohci-sa1111.c - * - * This file is licenced under the GPL. - */ - -#include <linux/platform_device.h> -#include <linux/signal.h> - -/* configure so an HC device and id are always provided */ -/* always called with process context; sleeping is OK */ - -/** - * usb_hcd_ppc_soc_probe - initialize On-Chip HCDs - * Context: !in_interrupt() - * - * Allocates basic resources for this USB host controller. - * - * Store this function in the HCD's struct pci_driver as probe(). - */ -static int usb_hcd_ppc_soc_probe(const struct hc_driver *driver, - struct platform_device *pdev) -{ - int retval; - struct usb_hcd *hcd; - struct ohci_hcd *ohci; - struct resource *res; - int irq; - - pr_debug("initializing PPC-SOC USB Controller\n"); - - res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); - if (!res) { - pr_debug("%s: no irq\n", __FILE__); - return -ENODEV; - } - irq = res->start; - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - pr_debug("%s: no reg addr\n", __FILE__); - return -ENODEV; - } - - hcd = usb_create_hcd(driver, &pdev->dev, "PPC-SOC USB"); - if (!hcd) - return -ENOMEM; - hcd->rsrc_start = res->start; - hcd->rsrc_len = resource_size(res); - - if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) { - pr_debug("%s: request_mem_region failed\n", __FILE__); - retval = -EBUSY; - goto err1; - } - - hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len); - if (!hcd->regs) { - pr_debug("%s: ioremap failed\n", __FILE__); - retval = -ENOMEM; - goto err2; - } - - ohci = hcd_to_ohci(hcd); - ohci->flags |= OHCI_QUIRK_BE_MMIO | OHCI_QUIRK_BE_DESC; - -#ifdef CONFIG_PPC_MPC52xx - /* MPC52xx doesn't need frame_no shift */ - ohci->flags |= OHCI_QUIRK_FRAME_NO; -#endif - ohci_hcd_init(ohci); - - retval = usb_add_hcd(hcd, irq, 0); - if (retval == 0) - return retval; - - pr_debug("Removing PPC-SOC USB Controller\n"); - - iounmap(hcd->regs); - err2: - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); - err1: - usb_put_hcd(hcd); - return retval; -} - - -/* may be called without controller electrically present */ -/* may be called with controller, bus, and devices active */ - -/** - * usb_hcd_ppc_soc_remove - shutdown processing for On-Chip HCDs - * @pdev: USB Host Controller being removed - * Context: !in_interrupt() - * - * Reverses the effect of usb_hcd_ppc_soc_probe(). - * It is always called from a thread - * context, normally "rmmod", "apmd", or something similar. - * - */ -static void usb_hcd_ppc_soc_remove(struct usb_hcd *hcd, - struct platform_device *pdev) -{ - usb_remove_hcd(hcd); - - pr_debug("stopping PPC-SOC USB Controller\n"); - - iounmap(hcd->regs); - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); - usb_put_hcd(hcd); -} - -static int __devinit -ohci_ppc_soc_start(struct usb_hcd *hcd) -{ - struct ohci_hcd *ohci = hcd_to_ohci(hcd); - int ret; - - if ((ret = ohci_init(ohci)) < 0) - return ret; - - if ((ret = ohci_run(ohci)) < 0) { - dev_err(hcd->self.controller, "can't start %s\n", - hcd->self.bus_name); - ohci_stop(hcd); - return ret; - } - - return 0; -} - -static const struct hc_driver ohci_ppc_soc_hc_driver = { - .description = hcd_name, - .hcd_priv_size = sizeof(struct ohci_hcd), - - /* - * generic hardware linkage - */ - .irq = ohci_irq, - .flags = HCD_USB11 | HCD_MEMORY, - - /* - * basic lifecycle operations - */ - .start = ohci_ppc_soc_start, - .stop = ohci_stop, - .shutdown = ohci_shutdown, - - /* - * managing i/o requests and associated device resources - */ - .urb_enqueue = ohci_urb_enqueue, - .urb_dequeue = ohci_urb_dequeue, - .endpoint_disable = ohci_endpoint_disable, - - /* - * scheduling support - */ - .get_frame_number = ohci_get_frame, - - /* - * root hub support - */ - .hub_status_data = ohci_hub_status_data, - .hub_control = ohci_hub_control, -#ifdef CONFIG_PM - .bus_suspend = ohci_bus_suspend, - .bus_resume = ohci_bus_resume, -#endif - .start_port_reset = ohci_start_port_reset, -}; - -static int ohci_hcd_ppc_soc_drv_probe(struct platform_device *pdev) -{ - int ret; - - if (usb_disabled()) - return -ENODEV; - - ret = usb_hcd_ppc_soc_probe(&ohci_ppc_soc_hc_driver, pdev); - return ret; -} - -static int ohci_hcd_ppc_soc_drv_remove(struct platform_device *pdev) -{ - struct usb_hcd *hcd = platform_get_drvdata(pdev); - - usb_hcd_ppc_soc_remove(hcd, pdev); - return 0; -} - -static struct platform_driver ohci_hcd_ppc_soc_driver = { - .probe = ohci_hcd_ppc_soc_drv_probe, - .remove = ohci_hcd_ppc_soc_drv_remove, - .shutdown = usb_hcd_platform_shutdown, -#ifdef CONFIG_PM - /*.suspend = ohci_hcd_ppc_soc_drv_suspend,*/ - /*.resume = ohci_hcd_ppc_soc_drv_resume,*/ -#endif - .driver = { - .name = "ppc-soc-ohci", - .owner = THIS_MODULE, - }, -}; - -MODULE_ALIAS("platform:ppc-soc-ohci"); diff --git a/drivers/usb/host/ohci-pxa27x.c b/drivers/usb/host/ohci-pxa27x.c index 2bf11440b010..156d289d3bb5 100644 --- a/drivers/usb/host/ohci-pxa27x.c +++ b/drivers/usb/host/ohci-pxa27x.c @@ -591,7 +591,7 @@ static int ohci_hcd_pxa27x_drv_resume(struct device *dev) /* Select Power Management Mode */ pxa27x_ohci_select_pmm(ohci, inf->port_mode); - ohci_finish_controller_resume(hcd); + ohci_resume(hcd, false); return 0; } diff --git a/drivers/usb/host/ohci-q.c b/drivers/usb/host/ohci-q.c index c5a1ea9145fa..177a213790d4 100644 --- a/drivers/usb/host/ohci-q.c +++ b/drivers/usb/host/ohci-q.c @@ -596,7 +596,6 @@ static void td_submit_urb ( urb_priv->ed->hwHeadP &= ~cpu_to_hc32 (ohci, ED_C); } - urb_priv->td_cnt = 0; list_add (&urb_priv->pending, &ohci->pending); if (data_len) @@ -672,7 +671,8 @@ static void td_submit_urb ( * we could often reduce the number of TDs here. */ case PIPE_ISOCHRONOUS: - for (cnt = 0; cnt < urb->number_of_packets; cnt++) { + for (cnt = urb_priv->td_cnt; cnt < urb->number_of_packets; + cnt++) { int frame = urb->start_frame; // FIXME scheduling should handle frame counter diff --git a/drivers/usb/host/ohci-s3c2410.c b/drivers/usb/host/ohci-s3c2410.c index 0d2309ca471e..e84190f25c6b 100644 --- a/drivers/usb/host/ohci-s3c2410.c +++ b/drivers/usb/host/ohci-s3c2410.c @@ -323,8 +323,6 @@ usb_hcd_s3c2410_remove(struct usb_hcd *hcd, struct platform_device *dev) { usb_remove_hcd(hcd); s3c2410_stop_hc(dev); - iounmap(hcd->regs); - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); usb_put_hcd(hcd); } @@ -353,35 +351,29 @@ static int usb_hcd_s3c2410_probe(const struct hc_driver *driver, hcd->rsrc_start = dev->resource[0].start; hcd->rsrc_len = resource_size(&dev->resource[0]); - if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) { - dev_err(&dev->dev, "request_mem_region failed\n"); - retval = -EBUSY; + hcd->regs = devm_request_and_ioremap(&dev->dev, &dev->resource[0]); + if (!hcd->regs) { + dev_err(&dev->dev, "devm_request_and_ioremap failed\n"); + retval = -ENOMEM; goto err_put; } - clk = clk_get(&dev->dev, "usb-host"); + clk = devm_clk_get(&dev->dev, "usb-host"); if (IS_ERR(clk)) { dev_err(&dev->dev, "cannot get usb-host clock\n"); retval = PTR_ERR(clk); - goto err_mem; + goto err_put; } - usb_clk = clk_get(&dev->dev, "usb-bus-host"); + usb_clk = devm_clk_get(&dev->dev, "usb-bus-host"); if (IS_ERR(usb_clk)) { dev_err(&dev->dev, "cannot get usb-bus-host clock\n"); retval = PTR_ERR(usb_clk); - goto err_clk; + goto err_put; } s3c2410_start_hc(dev, hcd); - hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len); - if (!hcd->regs) { - dev_err(&dev->dev, "ioremap failed\n"); - retval = -ENOMEM; - goto err_ioremap; - } - ohci_hcd_init(hcd_to_ohci(hcd)); retval = usb_add_hcd(hcd, dev->resource[1].start, 0); @@ -392,14 +384,6 @@ static int usb_hcd_s3c2410_probe(const struct hc_driver *driver, err_ioremap: s3c2410_stop_hc(dev); - iounmap(hcd->regs); - clk_put(usb_clk); - - err_clk: - clk_put(clk); - - err_mem: - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); err_put: usb_put_hcd(hcd); @@ -524,8 +508,7 @@ static int ohci_hcd_s3c2410_drv_resume(struct device *dev) s3c2410_start_hc(pdev, hcd); - set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); - ohci_finish_controller_resume(hcd); + ohci_resume(hcd, false); return 0; } diff --git a/drivers/usb/host/ohci-sh.c b/drivers/usb/host/ohci-sh.c deleted file mode 100644 index 76a20c278362..000000000000 --- a/drivers/usb/host/ohci-sh.c +++ /dev/null @@ -1,141 +0,0 @@ -/* - * OHCI HCD (Host Controller Driver) for USB. - * - * Copyright (C) 2008 Renesas Solutions Corp. - * - * 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 - * the Free Software Foundation; version 2 of the License. - * - * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#include <linux/platform_device.h> - -static int ohci_sh_start(struct usb_hcd *hcd) -{ - struct ohci_hcd *ohci = hcd_to_ohci(hcd); - - ohci_hcd_init(ohci); - ohci_init(ohci); - ohci_run(ohci); - return 0; -} - -static const struct hc_driver ohci_sh_hc_driver = { - .description = hcd_name, - .product_desc = "SuperH OHCI", - .hcd_priv_size = sizeof(struct ohci_hcd), - - /* - * generic hardware linkage - */ - .irq = ohci_irq, - .flags = HCD_USB11 | HCD_MEMORY, - - /* - * basic lifecycle operations - */ - .start = ohci_sh_start, - .stop = ohci_stop, - .shutdown = ohci_shutdown, - - /* - * managing i/o requests and associated device resources - */ - .urb_enqueue = ohci_urb_enqueue, - .urb_dequeue = ohci_urb_dequeue, - .endpoint_disable = ohci_endpoint_disable, - - /* - * scheduling support - */ - .get_frame_number = ohci_get_frame, - - /* - * root hub support - */ - .hub_status_data = ohci_hub_status_data, - .hub_control = ohci_hub_control, -#ifdef CONFIG_PM - .bus_suspend = ohci_bus_suspend, - .bus_resume = ohci_bus_resume, -#endif - .start_port_reset = ohci_start_port_reset, -}; - -/*-------------------------------------------------------------------------*/ - -static int ohci_hcd_sh_probe(struct platform_device *pdev) -{ - struct resource *res = NULL; - struct usb_hcd *hcd = NULL; - int irq = -1; - int ret; - - if (usb_disabled()) - return -ENODEV; - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - dev_err(&pdev->dev, "platform_get_resource error.\n"); - return -ENODEV; - } - - irq = platform_get_irq(pdev, 0); - if (irq < 0) { - dev_err(&pdev->dev, "platform_get_irq error.\n"); - return -ENODEV; - } - - /* initialize hcd */ - hcd = usb_create_hcd(&ohci_sh_hc_driver, &pdev->dev, (char *)hcd_name); - if (!hcd) { - dev_err(&pdev->dev, "Failed to create hcd\n"); - return -ENOMEM; - } - - hcd->regs = (void __iomem *)res->start; - hcd->rsrc_start = res->start; - hcd->rsrc_len = resource_size(res); - ret = usb_add_hcd(hcd, irq, IRQF_SHARED); - if (ret != 0) { - dev_err(&pdev->dev, "Failed to add hcd\n"); - usb_put_hcd(hcd); - return ret; - } - - return ret; -} - -static int ohci_hcd_sh_remove(struct platform_device *pdev) -{ - struct usb_hcd *hcd = platform_get_drvdata(pdev); - - usb_remove_hcd(hcd); - usb_put_hcd(hcd); - - return 0; -} - -static struct platform_driver ohci_hcd_sh_driver = { - .probe = ohci_hcd_sh_probe, - .remove = ohci_hcd_sh_remove, - .shutdown = usb_hcd_platform_shutdown, - .driver = { - .name = "sh_ohci", - .owner = THIS_MODULE, - }, -}; - -MODULE_ALIAS("platform:sh_ohci"); diff --git a/drivers/usb/host/ohci-sm501.c b/drivers/usb/host/ohci-sm501.c index 5596ac2ba1ca..3b5b908fd47b 100644 --- a/drivers/usb/host/ohci-sm501.c +++ b/drivers/usb/host/ohci-sm501.c @@ -238,7 +238,7 @@ static int ohci_sm501_resume(struct platform_device *pdev) ohci->next_statechange = jiffies; sm501_unit_power(dev->parent, SM501_GATE_USB_HOST, 1); - ohci_finish_controller_resume(hcd); + ohci_resume(hcd, false); return 0; } #else diff --git a/drivers/usb/host/ohci-spear.c b/drivers/usb/host/ohci-spear.c index fc7305ee3c9c..d607be33c03c 100644 --- a/drivers/usb/host/ohci-spear.c +++ b/drivers/usb/host/ohci-spear.c @@ -231,7 +231,7 @@ static int spear_ohci_hcd_drv_resume(struct platform_device *dev) ohci->next_statechange = jiffies; spear_start_ohci(ohci_p); - ohci_finish_controller_resume(hcd); + ohci_resume(hcd, false); return 0; } #endif diff --git a/drivers/usb/host/ohci-tmio.c b/drivers/usb/host/ohci-tmio.c index 60c2b0722f2e..2c9ab8f126d4 100644 --- a/drivers/usb/host/ohci-tmio.c +++ b/drivers/usb/host/ohci-tmio.c @@ -352,7 +352,7 @@ static int ohci_hcd_tmio_drv_resume(struct platform_device *dev) spin_unlock_irqrestore(&tmio->lock, flags); - ohci_finish_controller_resume(hcd); + ohci_resume(hcd, false); return 0; } diff --git a/drivers/usb/host/ohci-xls.c b/drivers/usb/host/ohci-xls.c deleted file mode 100644 index 84201cd1a472..000000000000 --- a/drivers/usb/host/ohci-xls.c +++ /dev/null @@ -1,152 +0,0 @@ -/* - * OHCI HCD for Netlogic XLS processors. - * - * (C) Copyright 2011 Netlogic Microsystems Inc. - * - * Based on ohci-au1xxx.c, and other Linux OHCI drivers. - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file COPYING in the main directory of this archive for - * more details. - */ - -#include <linux/platform_device.h> -#include <linux/signal.h> - -static int ohci_xls_probe_internal(const struct hc_driver *driver, - struct platform_device *dev) -{ - struct resource *res; - struct usb_hcd *hcd; - int retval, irq; - - /* Get our IRQ from an earlier registered Platform Resource */ - irq = platform_get_irq(dev, 0); - if (irq < 0) { - dev_err(&dev->dev, "Found HC with no IRQ\n"); - return -ENODEV; - } - - /* Get our Memory Handle */ - res = platform_get_resource(dev, IORESOURCE_MEM, 0); - if (!res) { - dev_err(&dev->dev, "MMIO Handle incorrect!\n"); - return -ENODEV; - } - - hcd = usb_create_hcd(driver, &dev->dev, "XLS"); - if (!hcd) { - retval = -ENOMEM; - goto err1; - } - hcd->rsrc_start = res->start; - hcd->rsrc_len = resource_size(res); - - if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, - driver->description)) { - dev_dbg(&dev->dev, "Controller already in use\n"); - retval = -EBUSY; - goto err2; - } - - hcd->regs = ioremap_nocache(hcd->rsrc_start, hcd->rsrc_len); - if (hcd->regs == NULL) { - dev_dbg(&dev->dev, "error mapping memory\n"); - retval = -EFAULT; - goto err3; - } - - retval = usb_add_hcd(hcd, irq, IRQF_SHARED); - if (retval != 0) - goto err4; - return retval; - -err4: - iounmap(hcd->regs); -err3: - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); -err2: - usb_put_hcd(hcd); -err1: - dev_err(&dev->dev, "init fail, %d\n", retval); - return retval; -} - -static int ohci_xls_reset(struct usb_hcd *hcd) -{ - struct ohci_hcd *ohci = hcd_to_ohci(hcd); - - ohci_hcd_init(ohci); - return ohci_init(ohci); -} - -static int __devinit ohci_xls_start(struct usb_hcd *hcd) -{ - struct ohci_hcd *ohci; - int ret; - - ohci = hcd_to_ohci(hcd); - ret = ohci_run(ohci); - if (ret < 0) { - dev_err(hcd->self.controller, "can't start %s\n", - hcd->self.bus_name); - ohci_stop(hcd); - return ret; - } - return 0; -} - -static struct hc_driver ohci_xls_hc_driver = { - .description = hcd_name, - .product_desc = "XLS OHCI Host Controller", - .hcd_priv_size = sizeof(struct ohci_hcd), - .irq = ohci_irq, - .flags = HCD_MEMORY | HCD_USB11, - .reset = ohci_xls_reset, - .start = ohci_xls_start, - .stop = ohci_stop, - .shutdown = ohci_shutdown, - .urb_enqueue = ohci_urb_enqueue, - .urb_dequeue = ohci_urb_dequeue, - .endpoint_disable = ohci_endpoint_disable, - .get_frame_number = ohci_get_frame, - .hub_status_data = ohci_hub_status_data, - .hub_control = ohci_hub_control, -#ifdef CONFIG_PM - .bus_suspend = ohci_bus_suspend, - .bus_resume = ohci_bus_resume, -#endif - .start_port_reset = ohci_start_port_reset, -}; - -static int ohci_xls_probe(struct platform_device *dev) -{ - int ret; - - pr_debug("In ohci_xls_probe"); - if (usb_disabled()) - return -ENODEV; - ret = ohci_xls_probe_internal(&ohci_xls_hc_driver, dev); - return ret; -} - -static int ohci_xls_remove(struct platform_device *dev) -{ - struct usb_hcd *hcd = platform_get_drvdata(dev); - - usb_remove_hcd(hcd); - iounmap(hcd->regs); - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); - usb_put_hcd(hcd); - return 0; -} - -static struct platform_driver ohci_xls_driver = { - .probe = ohci_xls_probe, - .remove = ohci_xls_remove, - .shutdown = usb_hcd_platform_shutdown, - .driver = { - .name = "ohci-xls-0", - .owner = THIS_MODULE, - }, -}; diff --git a/drivers/usb/host/r8a66597-hcd.c b/drivers/usb/host/r8a66597-hcd.c index fcc09e5ec0ad..b3eea0ba97a9 100644 --- a/drivers/usb/host/r8a66597-hcd.c +++ b/drivers/usb/host/r8a66597-hcd.c @@ -2036,10 +2036,8 @@ static void collect_usb_address_map(struct usb_device *udev, unsigned long *map) udev->parent->descriptor.bDeviceClass == USB_CLASS_HUB) map[udev->devnum/32] |= (1 << (udev->devnum % 32)); - usb_hub_for_each_child(udev, chix, childdev) { - if (childdev) - collect_usb_address_map(childdev, map); - } + usb_hub_for_each_child(udev, chix, childdev) + collect_usb_address_map(childdev, map); } /* this function must be called with interrupt disabled */ diff --git a/drivers/usb/host/uhci-q.c b/drivers/usb/host/uhci-q.c index d2c6f5ac4626..15921fd55048 100644 --- a/drivers/usb/host/uhci-q.c +++ b/drivers/usb/host/uhci-q.c @@ -1256,7 +1256,8 @@ static int uhci_submit_isochronous(struct uhci_hcd *uhci, struct urb *urb, struct uhci_qh *qh) { struct uhci_td *td = NULL; /* Since urb->number_of_packets > 0 */ - int i, frame; + int i; + unsigned frame, next; unsigned long destination, status; struct urb_priv *urbp = (struct urb_priv *) urb->hcpriv; @@ -1265,37 +1266,29 @@ static int uhci_submit_isochronous(struct uhci_hcd *uhci, struct urb *urb, urb->number_of_packets >= UHCI_NUMFRAMES) return -EFBIG; + uhci_get_current_frame_number(uhci); + /* Check the period and figure out the starting frame number */ if (!qh->bandwidth_reserved) { qh->period = urb->interval; - if (urb->transfer_flags & URB_ISO_ASAP) { - qh->phase = -1; /* Find the best phase */ - i = uhci_check_bandwidth(uhci, qh); - if (i) - return i; - - /* Allow a little time to allocate the TDs */ - uhci_get_current_frame_number(uhci); - frame = uhci->frame_number + 10; - - /* Move forward to the first frame having the - * correct phase */ - urb->start_frame = frame + ((qh->phase - frame) & - (qh->period - 1)); - } else { - i = urb->start_frame - uhci->last_iso_frame; - if (i <= 0 || i >= UHCI_NUMFRAMES) - return -EINVAL; - qh->phase = urb->start_frame & (qh->period - 1); - i = uhci_check_bandwidth(uhci, qh); - if (i) - return i; - } + qh->phase = -1; /* Find the best phase */ + i = uhci_check_bandwidth(uhci, qh); + if (i) + return i; + + /* Allow a little time to allocate the TDs */ + next = uhci->frame_number + 10; + frame = qh->phase; + + /* Round up to the first available slot */ + frame += (next - frame + qh->period - 1) & -qh->period; } else if (qh->period != urb->interval) { return -EINVAL; /* Can't change the period */ } else { + next = uhci->frame_number + 2; + /* Find the next unused frame */ if (list_empty(&qh->queue)) { frame = qh->iso_frame; @@ -1308,25 +1301,31 @@ static int uhci_submit_isochronous(struct uhci_hcd *uhci, struct urb *urb, lurb->number_of_packets * lurb->interval; } - if (urb->transfer_flags & URB_ISO_ASAP) { - /* Skip some frames if necessary to insure - * the start frame is in the future. + + /* Fell behind? */ + if (uhci_frame_before_eq(frame, next)) { + + /* USB_ISO_ASAP: Round up to the first available slot */ + if (urb->transfer_flags & URB_ISO_ASAP) + frame += (next - frame + qh->period - 1) & + -qh->period; + + /* + * Not ASAP: Use the next slot in the stream. If + * the entire URB falls before the threshold, fail. */ - uhci_get_current_frame_number(uhci); - if (uhci_frame_before_eq(frame, uhci->frame_number)) { - frame = uhci->frame_number + 1; - frame += ((qh->phase - frame) & - (qh->period - 1)); - } - } /* Otherwise pick up where the last URB leaves off */ - urb->start_frame = frame; + else if (!uhci_frame_before_eq(next, + frame + (urb->number_of_packets - 1) * + qh->period)) + return -EXDEV; + } } /* Make sure we won't have to go too far into the future */ if (uhci_frame_before_eq(uhci->last_iso_frame + UHCI_NUMFRAMES, - urb->start_frame + urb->number_of_packets * - urb->interval)) + frame + urb->number_of_packets * urb->interval)) return -EFBIG; + urb->start_frame = frame; status = TD_CTRL_ACTIVE | TD_CTRL_IOS; destination = (urb->pipe & PIPE_DEVEP_MASK) | usb_packetid(urb->pipe); diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c index 487bc083dead..fb51c7085ad0 100644 --- a/drivers/usb/host/xhci-mem.c +++ b/drivers/usb/host/xhci-mem.c @@ -205,7 +205,12 @@ static int xhci_alloc_segments_for_ring(struct xhci_hcd *xhci, next = xhci_segment_alloc(xhci, cycle_state, flags); if (!next) { - xhci_free_segments_for_ring(xhci, *first); + prev = *first; + while (prev) { + next = prev->next; + xhci_segment_free(xhci, prev); + prev = next; + } return -ENOMEM; } xhci_link_segments(xhci, prev, next, type); @@ -258,7 +263,7 @@ static struct xhci_ring *xhci_ring_alloc(struct xhci_hcd *xhci, return ring; fail: - xhci_ring_free(xhci, ring); + kfree(ring); return NULL; } diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c index 8345d7c23061..af259e0ec172 100644 --- a/drivers/usb/host/xhci-pci.c +++ b/drivers/usb/host/xhci-pci.c @@ -29,6 +29,7 @@ /* Device for a quirk */ #define PCI_VENDOR_ID_FRESCO_LOGIC 0x1b73 #define PCI_DEVICE_ID_FRESCO_LOGIC_PDK 0x1000 +#define PCI_DEVICE_ID_FRESCO_LOGIC_FL1400 0x1400 #define PCI_VENDOR_ID_ETRON 0x1b6f #define PCI_DEVICE_ID_ASROCK_P67 0x7023 @@ -58,8 +59,10 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci) /* Look for vendor-specific quirks */ if (pdev->vendor == PCI_VENDOR_ID_FRESCO_LOGIC && - pdev->device == PCI_DEVICE_ID_FRESCO_LOGIC_PDK) { - if (pdev->revision == 0x0) { + (pdev->device == PCI_DEVICE_ID_FRESCO_LOGIC_PDK || + pdev->device == PCI_DEVICE_ID_FRESCO_LOGIC_FL1400)) { + if (pdev->device == PCI_DEVICE_ID_FRESCO_LOGIC_PDK && + pdev->revision == 0x0) { xhci->quirks |= XHCI_RESET_EP_QUIRK; xhci_dbg(xhci, "QUIRK: Fresco Logic xHC needs configure" " endpoint cmd after reset endpoint\n"); @@ -218,15 +221,8 @@ static void xhci_pci_remove(struct pci_dev *dev) static int xhci_pci_suspend(struct usb_hcd *hcd, bool do_wakeup) { struct xhci_hcd *xhci = hcd_to_xhci(hcd); - int retval = 0; - if (hcd->state != HC_STATE_SUSPENDED || - xhci->shared_hcd->state != HC_STATE_SUSPENDED) - return -EINVAL; - - retval = xhci_suspend(xhci); - - return retval; + return xhci_suspend(xhci); } static int xhci_pci_resume(struct usb_hcd *hcd, bool hibernated) diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index 4e1a8946b8d1..cbb44b7b9d65 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -318,7 +318,7 @@ static int xhci_abort_cmd_ring(struct xhci_hcd *xhci) * seconds), then it should assume that the there are * larger problems with the xHC and assert HCRST. */ - ret = handshake(xhci, &xhci->op_regs->cmd_ring, + ret = xhci_handshake(xhci, &xhci->op_regs->cmd_ring, CMD_RING_RUNNING, 0, 5 * 1000 * 1000); if (ret < 0) { xhci_err(xhci, "Stopped the command ring failed, " @@ -3071,11 +3071,11 @@ static u32 xhci_td_remainder(unsigned int remainder) } /* - * For xHCI 1.0 host controllers, TD size is the number of packets remaining in - * the TD (*not* including this TRB). + * For xHCI 1.0 host controllers, TD size is the number of max packet sized + * packets remaining in the TD (*not* including this TRB). * * Total TD packet count = total_packet_count = - * roundup(TD size in bytes / wMaxPacketSize) + * DIV_ROUND_UP(TD size in bytes / wMaxPacketSize) * * Packets transferred up to and including this TRB = packets_transferred = * rounddown(total bytes transferred including this TRB / wMaxPacketSize) @@ -3083,15 +3083,16 @@ static u32 xhci_td_remainder(unsigned int remainder) * TD size = total_packet_count - packets_transferred * * It must fit in bits 21:17, so it can't be bigger than 31. + * The last TRB in a TD must have the TD size set to zero. */ - static u32 xhci_v1_0_td_remainder(int running_total, int trb_buff_len, - unsigned int total_packet_count, struct urb *urb) + unsigned int total_packet_count, struct urb *urb, + unsigned int num_trbs_left) { int packets_transferred; /* One TRB with a zero-length data packet. */ - if (running_total == 0 && trb_buff_len == 0) + if (num_trbs_left == 0 || (running_total == 0 && trb_buff_len == 0)) return 0; /* All the TRB queueing functions don't count the current TRB in @@ -3100,7 +3101,9 @@ static u32 xhci_v1_0_td_remainder(int running_total, int trb_buff_len, packets_transferred = (running_total + trb_buff_len) / usb_endpoint_maxp(&urb->ep->desc); - return xhci_td_remainder(total_packet_count - packets_transferred); + if ((total_packet_count - packets_transferred) > 31) + return 31 << 17; + return (total_packet_count - packets_transferred) << 17; } static int queue_bulk_sg_tx(struct xhci_hcd *xhci, gfp_t mem_flags, @@ -3127,7 +3130,7 @@ static int queue_bulk_sg_tx(struct xhci_hcd *xhci, gfp_t mem_flags, num_trbs = count_sg_trbs_needed(xhci, urb); num_sgs = urb->num_mapped_sgs; - total_packet_count = roundup(urb->transfer_buffer_length, + total_packet_count = DIV_ROUND_UP(urb->transfer_buffer_length, usb_endpoint_maxp(&urb->ep->desc)); trb_buff_len = prepare_transfer(xhci, xhci->devs[slot_id], @@ -3210,7 +3213,8 @@ static int queue_bulk_sg_tx(struct xhci_hcd *xhci, gfp_t mem_flags, running_total); } else { remainder = xhci_v1_0_td_remainder(running_total, - trb_buff_len, total_packet_count, urb); + trb_buff_len, total_packet_count, urb, + num_trbs - 1); } length_field = TRB_LEN(trb_buff_len) | remainder | @@ -3318,7 +3322,7 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags, start_cycle = ep_ring->cycle_state; running_total = 0; - total_packet_count = roundup(urb->transfer_buffer_length, + total_packet_count = DIV_ROUND_UP(urb->transfer_buffer_length, usb_endpoint_maxp(&urb->ep->desc)); /* How much data is in the first TRB? */ addr = (u64) urb->transfer_dma; @@ -3364,7 +3368,8 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags, running_total); } else { remainder = xhci_v1_0_td_remainder(running_total, - trb_buff_len, total_packet_count, urb); + trb_buff_len, total_packet_count, urb, + num_trbs - 1); } length_field = TRB_LEN(trb_buff_len) | remainder | @@ -3627,7 +3632,7 @@ static int xhci_queue_isoc_tx(struct xhci_hcd *xhci, gfp_t mem_flags, addr = start_addr + urb->iso_frame_desc[i].offset; td_len = urb->iso_frame_desc[i].length; td_remain_len = td_len; - total_packet_count = roundup(td_len, + total_packet_count = DIV_ROUND_UP(td_len, usb_endpoint_maxp(&urb->ep->desc)); /* A zero-length transfer still involves at least one packet. */ if (total_packet_count == 0) @@ -3706,7 +3711,8 @@ static int xhci_queue_isoc_tx(struct xhci_hcd *xhci, gfp_t mem_flags, } else { remainder = xhci_v1_0_td_remainder( running_total, trb_buff_len, - total_packet_count, urb); + total_packet_count, urb, + (trbs_per_td - j - 1)); } length_field = TRB_LEN(trb_buff_len) | remainder | diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index c9e419f29b74..5c72c431bab1 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -40,7 +40,7 @@ MODULE_PARM_DESC(link_quirk, "Don't clear the chain bit on a link TRB"); /* TODO: copied from ehci-hcd.c - can this be refactored? */ /* - * handshake - spin reading hc until handshake completes or fails + * xhci_handshake - spin reading hc until handshake completes or fails * @ptr: address of hc register to be read * @mask: bits to look at in result of read * @done: value of those bits when handshake succeeds @@ -52,7 +52,7 @@ MODULE_PARM_DESC(link_quirk, "Don't clear the chain bit on a link TRB"); * handshake done). There are two failure modes: "usec" have passed (major * hardware flakeout), or the register reads as all-ones (hardware removed). */ -int handshake(struct xhci_hcd *xhci, void __iomem *ptr, +int xhci_handshake(struct xhci_hcd *xhci, void __iomem *ptr, u32 mask, u32 done, int usec) { u32 result; @@ -103,7 +103,7 @@ int xhci_halt(struct xhci_hcd *xhci) xhci_dbg(xhci, "// Halt the HC\n"); xhci_quiesce(xhci); - ret = handshake(xhci, &xhci->op_regs->status, + ret = xhci_handshake(xhci, &xhci->op_regs->status, STS_HALT, STS_HALT, XHCI_MAX_HALT_USEC); if (!ret) { xhci->xhc_state |= XHCI_STATE_HALTED; @@ -132,7 +132,7 @@ static int xhci_start(struct xhci_hcd *xhci) * Wait for the HCHalted Status bit to be 0 to indicate the host is * running. */ - ret = handshake(xhci, &xhci->op_regs->status, + ret = xhci_handshake(xhci, &xhci->op_regs->status, STS_HALT, 0, XHCI_MAX_HALT_USEC); if (ret == -ETIMEDOUT) xhci_err(xhci, "Host took too long to start, " @@ -167,7 +167,7 @@ int xhci_reset(struct xhci_hcd *xhci) command |= CMD_RESET; xhci_writel(xhci, command, &xhci->op_regs->command); - ret = handshake(xhci, &xhci->op_regs->command, + ret = xhci_handshake(xhci, &xhci->op_regs->command, CMD_RESET, 0, 10 * 1000 * 1000); if (ret) return ret; @@ -177,7 +177,7 @@ int xhci_reset(struct xhci_hcd *xhci) * xHCI cannot write to any doorbells or operational registers other * than status until the "Controller Not Ready" flag is cleared. */ - ret = handshake(xhci, &xhci->op_regs->status, + ret = xhci_handshake(xhci, &xhci->op_regs->status, STS_CNR, 0, 10 * 1000 * 1000); for (i = 0; i < 2; ++i) { @@ -480,7 +480,7 @@ static bool compliance_mode_recovery_timer_quirk_check(void) if (strstr(dmi_product_name, "Z420") || strstr(dmi_product_name, "Z620") || strstr(dmi_product_name, "Z820") || - strstr(dmi_product_name, "Z1")) + strstr(dmi_product_name, "Z1 Workstation")) return true; return false; @@ -880,6 +880,10 @@ int xhci_suspend(struct xhci_hcd *xhci) struct usb_hcd *hcd = xhci_to_hcd(xhci); u32 command; + if (hcd->state != HC_STATE_SUSPENDED || + xhci->shared_hcd->state != HC_STATE_SUSPENDED) + return -EINVAL; + spin_lock_irq(&xhci->lock); clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); clear_bit(HCD_FLAG_HW_ACCESSIBLE, &xhci->shared_hcd->flags); @@ -890,7 +894,7 @@ int xhci_suspend(struct xhci_hcd *xhci) command = xhci_readl(xhci, &xhci->op_regs->command); command &= ~CMD_RUN; xhci_writel(xhci, command, &xhci->op_regs->command); - if (handshake(xhci, &xhci->op_regs->status, + if (xhci_handshake(xhci, &xhci->op_regs->status, STS_HALT, STS_HALT, XHCI_MAX_HALT_USEC)) { xhci_warn(xhci, "WARN: xHC CMD_RUN timeout\n"); spin_unlock_irq(&xhci->lock); @@ -905,7 +909,8 @@ int xhci_suspend(struct xhci_hcd *xhci) command = xhci_readl(xhci, &xhci->op_regs->command); command |= CMD_CSS; xhci_writel(xhci, command, &xhci->op_regs->command); - if (handshake(xhci, &xhci->op_regs->status, STS_SAVE, 0, 10 * 1000)) { + if (xhci_handshake(xhci, &xhci->op_regs->status, + STS_SAVE, 0, 10 * 1000)) { xhci_warn(xhci, "WARN: xHC save state timeout\n"); spin_unlock_irq(&xhci->lock); return -ETIMEDOUT; @@ -967,7 +972,7 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated) command = xhci_readl(xhci, &xhci->op_regs->command); command |= CMD_CRS; xhci_writel(xhci, command, &xhci->op_regs->command); - if (handshake(xhci, &xhci->op_regs->status, + if (xhci_handshake(xhci, &xhci->op_regs->status, STS_RESTORE, 0, 10 * 1000)) { xhci_warn(xhci, "WARN: xHC restore state timeout\n"); spin_unlock_irq(&xhci->lock); @@ -1035,7 +1040,7 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated) command = xhci_readl(xhci, &xhci->op_regs->command); command |= CMD_RUN; xhci_writel(xhci, command, &xhci->op_regs->command); - handshake(xhci, &xhci->op_regs->status, STS_HALT, + xhci_handshake(xhci, &xhci->op_regs->status, STS_HALT, 0, 250 * 1000); /* step 5: walk topology and initialize portsc, @@ -2254,7 +2259,7 @@ static bool xhci_is_async_ep(unsigned int ep_type) static bool xhci_is_sync_in_ep(unsigned int ep_type) { - return (ep_type == ISOC_IN_EP || ep_type != INT_IN_EP); + return (ep_type == ISOC_IN_EP || ep_type == INT_IN_EP); } static unsigned int xhci_get_ss_bw_consumed(struct xhci_bw_info *ep_bw) @@ -3874,7 +3879,8 @@ static int xhci_usb2_software_lpm_test(struct usb_hcd *hcd, spin_lock_irqsave(&xhci->lock, flags); /* Check L1 Status */ - ret = handshake(xhci, pm_addr, PORT_L1S_MASK, PORT_L1S_SUCCESS, 125); + ret = xhci_handshake(xhci, pm_addr, + PORT_L1S_MASK, PORT_L1S_SUCCESS, 125); if (ret != -ETIMEDOUT) { /* enter L1 successfully */ temp = xhci_readl(xhci, addr); diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index 53df4e70ca07..f791bd0aee6c 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -1720,7 +1720,7 @@ static inline void xhci_unregister_plat(void) /* xHCI host controller glue */ typedef void (*xhci_get_quirks_t)(struct device *, struct xhci_hcd *); -int handshake(struct xhci_hcd *xhci, void __iomem *ptr, +int xhci_handshake(struct xhci_hcd *xhci, void __iomem *ptr, u32 mask, u32 done, int usec); void xhci_quiesce(struct xhci_hcd *xhci); int xhci_halt(struct xhci_hcd *xhci); diff --git a/drivers/usb/misc/ezusb.c b/drivers/usb/misc/ezusb.c index 6589268a6515..e712afed947c 100644 --- a/drivers/usb/misc/ezusb.c +++ b/drivers/usb/misc/ezusb.c @@ -15,6 +15,7 @@ #include <linux/usb.h> #include <linux/firmware.h> #include <linux/ihex.h> +#include <linux/usb/ezusb.h> struct ezusb_fx_type { /* EZ-USB Control and Status Register. Bit 0 controls 8051 reset */ @@ -22,21 +23,16 @@ struct ezusb_fx_type { unsigned short max_internal_adress; }; -struct ezusb_fx_type ezusb_fx1 = { +static struct ezusb_fx_type ezusb_fx1 = { .cpucs_reg = 0x7F92, .max_internal_adress = 0x1B3F, }; -struct ezusb_fx_type ezusb_fx2 = { - .cpucs_reg = 0xE600, - .max_internal_adress = 0x3FFF, -}; - /* Commands for writing to memory */ #define WRITE_INT_RAM 0xA0 #define WRITE_EXT_RAM 0xA3 -int ezusb_writememory(struct usb_device *dev, int address, +static int ezusb_writememory(struct usb_device *dev, int address, unsigned char *data, int length, __u8 request) { int result; @@ -58,10 +54,9 @@ int ezusb_writememory(struct usb_device *dev, int address, kfree(transfer_buffer); return result; } -EXPORT_SYMBOL_GPL(ezusb_writememory); -int ezusb_set_reset(struct usb_device *dev, unsigned short cpucs_reg, - unsigned char reset_bit) +static int ezusb_set_reset(struct usb_device *dev, unsigned short cpucs_reg, + unsigned char reset_bit) { int response = ezusb_writememory(dev, cpucs_reg, &reset_bit, 1, WRITE_INT_RAM); if (response < 0) @@ -76,12 +71,6 @@ int ezusb_fx1_set_reset(struct usb_device *dev, unsigned char reset_bit) } EXPORT_SYMBOL_GPL(ezusb_fx1_set_reset); -int ezusb_fx2_set_reset(struct usb_device *dev, unsigned char reset_bit) -{ - return ezusb_set_reset(dev, ezusb_fx2.cpucs_reg, reset_bit); -} -EXPORT_SYMBOL_GPL(ezusb_fx2_set_reset); - static int ezusb_ihex_firmware_download(struct usb_device *dev, struct ezusb_fx_type fx, const char *firmware_path) @@ -151,11 +140,28 @@ int ezusb_fx1_ihex_firmware_download(struct usb_device *dev, } EXPORT_SYMBOL_GPL(ezusb_fx1_ihex_firmware_download); +#if 0 +/* + * Once someone one needs these fx2 functions, uncomment them + * and add them to ezusb.h and all should be good. + */ +static struct ezusb_fx_type ezusb_fx2 = { + .cpucs_reg = 0xE600, + .max_internal_adress = 0x3FFF, +}; + +int ezusb_fx2_set_reset(struct usb_device *dev, unsigned char reset_bit) +{ + return ezusb_set_reset(dev, ezusb_fx2.cpucs_reg, reset_bit); +} +EXPORT_SYMBOL_GPL(ezusb_fx2_set_reset); + int ezusb_fx2_ihex_firmware_download(struct usb_device *dev, const char *firmware_path) { return ezusb_ihex_firmware_download(dev, ezusb_fx2, firmware_path); } EXPORT_SYMBOL_GPL(ezusb_fx2_ihex_firmware_download); +#endif MODULE_LICENSE("GPL"); diff --git a/drivers/usb/musb/am35x.c b/drivers/usb/musb/am35x.c index c964d6af178b..3baccf765418 100644 --- a/drivers/usb/musb/am35x.c +++ b/drivers/usb/musb/am35x.c @@ -465,7 +465,6 @@ static int __devinit am35x_probe(struct platform_device *pdev) struct clk *clk; int ret = -ENOMEM; - int musbid; glue = kzalloc(sizeof(*glue), GFP_KERNEL); if (!glue) { @@ -473,18 +472,10 @@ static int __devinit am35x_probe(struct platform_device *pdev) goto err0; } - /* get the musb id */ - musbid = musb_get_id(&pdev->dev, GFP_KERNEL); - if (musbid < 0) { - dev_err(&pdev->dev, "failed to allocate musb id\n"); - ret = -ENOMEM; - goto err1; - } - - musb = platform_device_alloc("musb-hdrc", musbid); + musb = platform_device_alloc("musb-hdrc", PLATFORM_DEVID_AUTO); if (!musb) { dev_err(&pdev->dev, "failed to allocate musb device\n"); - goto err2; + goto err1; } phy_clk = clk_get(&pdev->dev, "fck"); @@ -513,7 +504,6 @@ static int __devinit am35x_probe(struct platform_device *pdev) goto err6; } - musb->id = musbid; musb->dev.parent = &pdev->dev; musb->dev.dma_mask = &am35x_dmamask; musb->dev.coherent_dma_mask = am35x_dmamask; @@ -563,9 +553,6 @@ err4: err3: platform_device_put(musb); -err2: - musb_put_id(&pdev->dev, musbid); - err1: kfree(glue); @@ -577,9 +564,7 @@ static int __devexit am35x_remove(struct platform_device *pdev) { struct am35x_glue *glue = platform_get_drvdata(pdev); - musb_put_id(&pdev->dev, glue->musb->id); - platform_device_del(glue->musb); - platform_device_put(glue->musb); + platform_device_unregister(glue->musb); clk_disable(glue->clk); clk_disable(glue->phy_clk); clk_put(glue->clk); @@ -654,15 +639,4 @@ static struct platform_driver am35x_driver = { MODULE_DESCRIPTION("AM35x MUSB Glue Layer"); MODULE_AUTHOR("Ajay Kumar Gupta <ajay.gupta@ti.com>"); MODULE_LICENSE("GPL v2"); - -static int __init am35x_init(void) -{ - return platform_driver_register(&am35x_driver); -} -module_init(am35x_init); - -static void __exit am35x_exit(void) -{ - platform_driver_unregister(&am35x_driver); -} -module_exit(am35x_exit); +module_platform_driver(am35x_driver); diff --git a/drivers/usb/musb/blackfin.c b/drivers/usb/musb/blackfin.c index e8cff9bb9d23..7e4d60a41728 100644 --- a/drivers/usb/musb/blackfin.c +++ b/drivers/usb/musb/blackfin.c @@ -455,7 +455,6 @@ static int __devinit bfin_probe(struct platform_device *pdev) struct bfin_glue *glue; int ret = -ENOMEM; - int musbid; glue = kzalloc(sizeof(*glue), GFP_KERNEL); if (!glue) { @@ -463,21 +462,12 @@ static int __devinit bfin_probe(struct platform_device *pdev) goto err0; } - /* get the musb id */ - musbid = musb_get_id(&pdev->dev, GFP_KERNEL); - if (musbid < 0) { - dev_err(&pdev->dev, "failed to allocate musb id\n"); - ret = -ENOMEM; - goto err1; - } - - musb = platform_device_alloc("musb-hdrc", musbid); + musb = platform_device_alloc("musb-hdrc", PLATFORM_DEVID_AUTO); if (!musb) { dev_err(&pdev->dev, "failed to allocate musb device\n"); - goto err2; + goto err1; } - musb->id = musbid; musb->dev.parent = &pdev->dev; musb->dev.dma_mask = &bfin_dmamask; musb->dev.coherent_dma_mask = bfin_dmamask; @@ -513,9 +503,6 @@ static int __devinit bfin_probe(struct platform_device *pdev) err3: platform_device_put(musb); -err2: - musb_put_id(&pdev->dev, musbid); - err1: kfree(glue); @@ -527,9 +514,7 @@ static int __devexit bfin_remove(struct platform_device *pdev) { struct bfin_glue *glue = platform_get_drvdata(pdev); - musb_put_id(&pdev->dev, glue->musb->id); - platform_device_del(glue->musb); - platform_device_put(glue->musb); + platform_device_unregister(glue->musb); kfree(glue); return 0; @@ -585,15 +570,4 @@ static struct platform_driver bfin_driver = { MODULE_DESCRIPTION("Blackfin MUSB Glue Layer"); MODULE_AUTHOR("Bryan Wy <cooloney@kernel.org>"); MODULE_LICENSE("GPL v2"); - -static int __init bfin_init(void) -{ - return platform_driver_register(&bfin_driver); -} -module_init(bfin_init); - -static void __exit bfin_exit(void) -{ - platform_driver_unregister(&bfin_driver); -} -module_exit(bfin_exit); +module_platform_driver(bfin_driver); diff --git a/drivers/usb/musb/cppi_dma.c b/drivers/usb/musb/cppi_dma.c index e19da82b4782..3a6c2fd1f913 100644 --- a/drivers/usb/musb/cppi_dma.c +++ b/drivers/usb/musb/cppi_dma.c @@ -1314,6 +1314,7 @@ irqreturn_t cppi_interrupt(int irq, void *dev_id) return IRQ_HANDLED; } +EXPORT_SYMBOL_GPL(cppi_interrupt); /* Instantiate a software object representing a DMA controller. */ struct dma_controller *__devinit diff --git a/drivers/usb/musb/da8xx.c b/drivers/usb/musb/da8xx.c index 8bc44b76eec2..67b8ae704e9a 100644 --- a/drivers/usb/musb/da8xx.c +++ b/drivers/usb/musb/da8xx.c @@ -480,7 +480,6 @@ static int __devinit da8xx_probe(struct platform_device *pdev) struct clk *clk; int ret = -ENOMEM; - int musbid; glue = kzalloc(sizeof(*glue), GFP_KERNEL); if (!glue) { @@ -488,18 +487,10 @@ static int __devinit da8xx_probe(struct platform_device *pdev) goto err0; } - /* get the musb id */ - musbid = musb_get_id(&pdev->dev, GFP_KERNEL); - if (musbid < 0) { - dev_err(&pdev->dev, "failed to allocate musb id\n"); - ret = -ENOMEM; - goto err1; - } - - musb = platform_device_alloc("musb-hdrc", musbid); + musb = platform_device_alloc("musb-hdrc", PLATFORM_DEVID_AUTO); if (!musb) { dev_err(&pdev->dev, "failed to allocate musb device\n"); - goto err2; + goto err1; } clk = clk_get(&pdev->dev, "usb20"); @@ -515,7 +506,6 @@ static int __devinit da8xx_probe(struct platform_device *pdev) goto err4; } - musb->id = musbid; musb->dev.parent = &pdev->dev; musb->dev.dma_mask = &da8xx_dmamask; musb->dev.coherent_dma_mask = da8xx_dmamask; @@ -558,9 +548,6 @@ err4: err3: platform_device_put(musb); -err2: - musb_put_id(&pdev->dev, musbid); - err1: kfree(glue); @@ -572,9 +559,7 @@ static int __devexit da8xx_remove(struct platform_device *pdev) { struct da8xx_glue *glue = platform_get_drvdata(pdev); - musb_put_id(&pdev->dev, glue->musb->id); - platform_device_del(glue->musb); - platform_device_put(glue->musb); + platform_device_unregister(glue->musb); clk_disable(glue->clk); clk_put(glue->clk); kfree(glue); @@ -593,15 +578,4 @@ static struct platform_driver da8xx_driver = { MODULE_DESCRIPTION("DA8xx/OMAP-L1x MUSB Glue Layer"); MODULE_AUTHOR("Sergei Shtylyov <sshtylyov@ru.mvista.com>"); MODULE_LICENSE("GPL v2"); - -static int __init da8xx_init(void) -{ - return platform_driver_register(&da8xx_driver); -} -module_init(da8xx_init); - -static void __exit da8xx_exit(void) -{ - platform_driver_unregister(&da8xx_driver); -} -module_exit(da8xx_exit); +module_platform_driver(da8xx_driver); diff --git a/drivers/usb/musb/davinci.c b/drivers/usb/musb/davinci.c index 606bfd00cde6..b3c0a943950c 100644 --- a/drivers/usb/musb/davinci.c +++ b/drivers/usb/musb/davinci.c @@ -512,7 +512,6 @@ static int __devinit davinci_probe(struct platform_device *pdev) struct clk *clk; int ret = -ENOMEM; - int musbid; glue = kzalloc(sizeof(*glue), GFP_KERNEL); if (!glue) { @@ -520,18 +519,10 @@ static int __devinit davinci_probe(struct platform_device *pdev) goto err0; } - /* get the musb id */ - musbid = musb_get_id(&pdev->dev, GFP_KERNEL); - if (musbid < 0) { - dev_err(&pdev->dev, "failed to allocate musb id\n"); - ret = -ENOMEM; - goto err1; - } - - musb = platform_device_alloc("musb-hdrc", musbid); + musb = platform_device_alloc("musb-hdrc", PLATFORM_DEVID_AUTO); if (!musb) { dev_err(&pdev->dev, "failed to allocate musb device\n"); - goto err2; + goto err1; } clk = clk_get(&pdev->dev, "usb"); @@ -547,7 +538,6 @@ static int __devinit davinci_probe(struct platform_device *pdev) goto err4; } - musb->id = musbid; musb->dev.parent = &pdev->dev; musb->dev.dma_mask = &davinci_dmamask; musb->dev.coherent_dma_mask = davinci_dmamask; @@ -590,9 +580,6 @@ err4: err3: platform_device_put(musb); -err2: - musb_put_id(&pdev->dev, musbid); - err1: kfree(glue); @@ -604,9 +591,7 @@ static int __devexit davinci_remove(struct platform_device *pdev) { struct davinci_glue *glue = platform_get_drvdata(pdev); - musb_put_id(&pdev->dev, glue->musb->id); - platform_device_del(glue->musb); - platform_device_put(glue->musb); + platform_device_unregister(glue->musb); clk_disable(glue->clk); clk_put(glue->clk); kfree(glue); @@ -625,15 +610,4 @@ static struct platform_driver davinci_driver = { MODULE_DESCRIPTION("DaVinci MUSB Glue Layer"); MODULE_AUTHOR("Felipe Balbi <balbi@ti.com>"); MODULE_LICENSE("GPL v2"); - -static int __init davinci_init(void) -{ - return platform_driver_register(&davinci_driver); -} -module_init(davinci_init); - -static void __exit davinci_exit(void) -{ - platform_driver_unregister(&davinci_driver); -} -module_exit(davinci_exit); +module_platform_driver(davinci_driver); diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c index bb56a0e8b23b..774d8154a286 100644 --- a/drivers/usb/musb/musb_core.c +++ b/drivers/usb/musb/musb_core.c @@ -116,7 +116,6 @@ #define MUSB_DRIVER_NAME "musb-hdrc" const char musb_driver_name[] = MUSB_DRIVER_NAME; -static DEFINE_IDA(musb_ida); MODULE_DESCRIPTION(DRIVER_INFO); MODULE_AUTHOR(DRIVER_AUTHOR); @@ -133,35 +132,6 @@ static inline struct musb *dev_to_musb(struct device *dev) /*-------------------------------------------------------------------------*/ -int musb_get_id(struct device *dev, gfp_t gfp_mask) -{ - int ret; - int id; - - ret = ida_pre_get(&musb_ida, gfp_mask); - if (!ret) { - dev_err(dev, "failed to reserve resource for id\n"); - return -ENOMEM; - } - - ret = ida_get_new(&musb_ida, &id); - if (ret < 0) { - dev_err(dev, "failed to allocate a new id\n"); - return ret; - } - - return id; -} -EXPORT_SYMBOL_GPL(musb_get_id); - -void musb_put_id(struct device *dev, int id) -{ - - dev_dbg(dev, "removing id %d\n", id); - ida_remove(&musb_ida, id); -} -EXPORT_SYMBOL_GPL(musb_put_id); - #ifndef CONFIG_BLACKFIN static int musb_ulpi_read(struct usb_phy *phy, u32 offset) { @@ -467,12 +437,12 @@ void musb_hnp_stop(struct musb *musb) */ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb, - u8 devctl, u8 power) + u8 devctl) { struct usb_otg *otg = musb->xceiv->otg; irqreturn_t handled = IRQ_NONE; - dev_dbg(musb->controller, "<== Power=%02x, DevCtl=%02x, int_usb=0x%x\n", power, devctl, + dev_dbg(musb->controller, "<== DevCtl=%02x, int_usb=0x%x\n", devctl, int_usb); /* in host mode, the peripheral may issue remote wakeup. @@ -485,6 +455,7 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb, if (devctl & MUSB_DEVCTL_HM) { void __iomem *mbase = musb->mregs; + u8 power; switch (musb->xceiv->state) { case OTG_STATE_A_SUSPEND: @@ -492,6 +463,7 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb, * will stop RESUME signaling */ + power = musb_readb(musb->mregs, MUSB_POWER); if (power & MUSB_POWER_SUSPENDM) { /* spurious */ musb->int_usb &= ~MUSB_INTR_SUSPEND; @@ -655,8 +627,8 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb, } if (int_usb & MUSB_INTR_SUSPEND) { - dev_dbg(musb->controller, "SUSPEND (%s) devctl %02x power %02x\n", - otg_state_string(musb->xceiv->state), devctl, power); + dev_dbg(musb->controller, "SUSPEND (%s) devctl %02x\n", + otg_state_string(musb->xceiv->state), devctl); handled = IRQ_HANDLED; switch (musb->xceiv->state) { @@ -722,8 +694,10 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb, if (is_peripheral_active(musb)) { /* REVISIT HNP; just force disconnect */ } - musb_writew(musb->mregs, MUSB_INTRTXE, musb->epmask); - musb_writew(musb->mregs, MUSB_INTRRXE, musb->epmask & 0xfffe); + musb->intrtxe = musb->epmask; + musb_writew(musb->mregs, MUSB_INTRTXE, musb->intrtxe); + musb->intrrxe = musb->epmask & 0xfffe; + musb_writew(musb->mregs, MUSB_INTRRXE, musb->intrrxe); musb_writeb(musb->mregs, MUSB_INTRUSBE, 0xf7); musb->port1_status &= ~(USB_PORT_STAT_LOW_SPEED |USB_PORT_STAT_HIGH_SPEED @@ -944,8 +918,10 @@ void musb_start(struct musb *musb) dev_dbg(musb->controller, "<== devctl %02x\n", devctl); /* Set INT enable registers, enable interrupts */ - musb_writew(regs, MUSB_INTRTXE, musb->epmask); - musb_writew(regs, MUSB_INTRRXE, musb->epmask & 0xfffe); + musb->intrtxe = musb->epmask; + musb_writew(regs, MUSB_INTRTXE, musb->intrtxe); + musb->intrrxe = musb->epmask & 0xfffe; + musb_writew(regs, MUSB_INTRRXE, musb->intrrxe); musb_writeb(regs, MUSB_INTRUSBE, 0xf7); musb_writeb(regs, MUSB_TESTMODE, 0); @@ -983,7 +959,9 @@ static void musb_generic_disable(struct musb *musb) /* disable interrupts */ musb_writeb(mbase, MUSB_INTRUSBE, 0); + musb->intrtxe = 0; musb_writew(mbase, MUSB_INTRTXE, 0); + musb->intrrxe = 0; musb_writew(mbase, MUSB_INTRRXE, 0); /* off */ @@ -1523,33 +1501,6 @@ static int __devinit musb_core_init(u16 musb_type, struct musb *musb) /*-------------------------------------------------------------------------*/ -#if defined(CONFIG_SOC_OMAP2430) || defined(CONFIG_SOC_OMAP3430) || \ - defined(CONFIG_ARCH_OMAP4) || defined(CONFIG_ARCH_U8500) - -static irqreturn_t generic_interrupt(int irq, void *__hci) -{ - unsigned long flags; - irqreturn_t retval = IRQ_NONE; - struct musb *musb = __hci; - - spin_lock_irqsave(&musb->lock, flags); - - musb->int_usb = musb_readb(musb->mregs, MUSB_INTRUSB); - musb->int_tx = musb_readw(musb->mregs, MUSB_INTRTX); - musb->int_rx = musb_readw(musb->mregs, MUSB_INTRRX); - - if (musb->int_usb || musb->int_tx || musb->int_rx) - retval = musb_interrupt(musb); - - spin_unlock_irqrestore(&musb->lock, flags); - - return retval; -} - -#else -#define generic_interrupt NULL -#endif - /* * handle all the irqs defined by the HDRC core. for now we expect: other * irq sources (phy, dma, etc) will be handled first, musb->int_* values @@ -1560,12 +1511,11 @@ static irqreturn_t generic_interrupt(int irq, void *__hci) irqreturn_t musb_interrupt(struct musb *musb) { irqreturn_t retval = IRQ_NONE; - u8 devctl, power; + u8 devctl; int ep_num; u32 reg; devctl = musb_readb(musb->mregs, MUSB_DEVCTL); - power = musb_readb(musb->mregs, MUSB_POWER); dev_dbg(musb->controller, "** IRQ %s usb%04x tx%04x rx%04x\n", (devctl & MUSB_DEVCTL_HM) ? "host" : "peripheral", @@ -1576,7 +1526,7 @@ irqreturn_t musb_interrupt(struct musb *musb) */ if (musb->int_usb) retval |= musb_stage0_irq(musb, musb->int_usb, - devctl, power); + devctl); /* "stage 1" is handling endpoint irqs */ @@ -1919,7 +1869,8 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl) musb->ops = plat->platform_ops; /* The musb_platform_init() call: - * - adjusts musb->mregs and musb->isr if needed, + * - adjusts musb->mregs + * - sets the musb->isr * - may initialize an integrated tranceiver * - initializes musb->xceiv, usually by otg_get_phy() * - stops powering VBUS @@ -1929,7 +1880,6 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl) * external/discrete ones in various flavors (twl4030 family, * isp1504, non-OTG, etc) mostly hooking up through ULPI. */ - musb->isr = generic_interrupt; status = musb_platform_init(musb); if (status < 0) goto fail1; @@ -2120,8 +2070,6 @@ static void musb_save_context(struct musb *musb) musb->context.testmode = musb_readb(musb_base, MUSB_TESTMODE); musb->context.busctl = musb_read_ulpi_buscontrol(musb->mregs); musb->context.power = musb_readb(musb_base, MUSB_POWER); - musb->context.intrtxe = musb_readw(musb_base, MUSB_INTRTXE); - musb->context.intrrxe = musb_readw(musb_base, MUSB_INTRRXE); musb->context.intrusbe = musb_readb(musb_base, MUSB_INTRUSBE); musb->context.index = musb_readb(musb_base, MUSB_INDEX); musb->context.devctl = musb_readb(musb_base, MUSB_DEVCTL); @@ -2194,8 +2142,8 @@ static void musb_restore_context(struct musb *musb) musb_writeb(musb_base, MUSB_TESTMODE, musb->context.testmode); musb_write_ulpi_buscontrol(musb->mregs, musb->context.busctl); musb_writeb(musb_base, MUSB_POWER, musb->context.power); - musb_writew(musb_base, MUSB_INTRTXE, musb->context.intrtxe); - musb_writew(musb_base, MUSB_INTRRXE, musb->context.intrrxe); + musb_writew(musb_base, MUSB_INTRTXE, musb->intrtxe); + musb_writew(musb_base, MUSB_INTRRXE, musb->intrrxe); musb_writeb(musb_base, MUSB_INTRUSBE, musb->context.intrusbe); musb_writeb(musb_base, MUSB_DEVCTL, musb->context.devctl); diff --git a/drivers/usb/musb/musb_core.h b/drivers/usb/musb/musb_core.h index c158aacd6de8..7fb4819a6f11 100644 --- a/drivers/usb/musb/musb_core.h +++ b/drivers/usb/musb/musb_core.h @@ -288,7 +288,6 @@ struct musb_csr_regs { struct musb_context_registers { u8 power; - u16 intrtxe, intrrxe; u8 intrusbe; u16 frame; u8 index, testmode; @@ -313,6 +312,8 @@ struct musb { struct work_struct irq_work; u16 hwvers; + u16 intrrxe; + u16 intrtxe; /* this hub status bit is reserved by USB 2.0 and not seen by usbcore */ #define MUSB_PORT_STAT_RESUME (1 << 31) @@ -521,8 +522,6 @@ extern const char musb_driver_name[]; extern void musb_start(struct musb *musb); extern void musb_stop(struct musb *musb); -extern int musb_get_id(struct device *dev, gfp_t gfp_mask); -extern void musb_put_id(struct device *dev, int id); extern void musb_write_fifo(struct musb_hw_ep *ep, u16 len, const u8 *src); extern void musb_read_fifo(struct musb_hw_ep *ep, u16 len, u8 *dst); diff --git a/drivers/usb/musb/musb_dsps.c b/drivers/usb/musb/musb_dsps.c index ff5f112053d2..b108473e4d5f 100644 --- a/drivers/usb/musb/musb_dsps.c +++ b/drivers/usb/musb/musb_dsps.c @@ -124,8 +124,44 @@ struct dsps_glue { const struct dsps_musb_wrapper *wrp; /* wrapper register offsets */ struct timer_list timer[2]; /* otg_workaround timer */ unsigned long last_timer[2]; /* last timer data for each instance */ + u32 __iomem *usb_ctrl[2]; }; +#define DSPS_AM33XX_CONTROL_MODULE_PHYS_0 0x44e10620 +#define DSPS_AM33XX_CONTROL_MODULE_PHYS_1 0x44e10628 + +static const resource_size_t dsps_control_module_phys[] = { + DSPS_AM33XX_CONTROL_MODULE_PHYS_0, + DSPS_AM33XX_CONTROL_MODULE_PHYS_1, +}; + +/** + * musb_dsps_phy_control - phy on/off + * @glue: struct dsps_glue * + * @id: musb instance + * @on: flag for phy to be switched on or off + * + * This is to enable the PHY using usb_ctrl register in system control + * module space. + * + * XXX: This function will be removed once we have a seperate driver for + * control module + */ +static void musb_dsps_phy_control(struct dsps_glue *glue, u8 id, u8 on) +{ + u32 usbphycfg; + + usbphycfg = readl(glue->usb_ctrl[id]); + + if (on) { + usbphycfg &= ~(USBPHY_CM_PWRDN | USBPHY_OTG_PWRDN); + usbphycfg |= USBPHY_OTGVDET_EN | USBPHY_OTGSESSEND_EN; + } else { + usbphycfg |= USBPHY_CM_PWRDN | USBPHY_OTG_PWRDN; + } + + writel(usbphycfg, glue->usb_ctrl[id]); +} /** * dsps_musb_enable - enable interrupts */ @@ -296,7 +332,7 @@ static irqreturn_t dsps_interrupt(int irq, void *hci) * Also, DRVVBUS pulses for SRP (but not at 5V) ... */ if (usbintr & MUSB_INTR_BABBLE) - pr_info("CAUTION: musb: Babble Interrupt Occured\n"); + pr_info("CAUTION: musb: Babble Interrupt Occurred\n"); if (usbintr & ((1 << wrp->drvvbus) << wrp->usb_shift)) { int drvvbus = dsps_readl(reg_base, wrp->status); @@ -365,11 +401,9 @@ static irqreturn_t dsps_interrupt(int irq, void *hci) static int dsps_musb_init(struct musb *musb) { struct device *dev = musb->controller; - struct musb_hdrc_platform_data *plat = dev->platform_data; struct platform_device *pdev = to_platform_device(dev); struct dsps_glue *glue = dev_get_drvdata(dev->parent); const struct dsps_musb_wrapper *wrp = glue->wrp; - struct omap_musb_board_data *data = plat->board_data; void __iomem *reg_base = musb->ctrl_base; u32 rev, val; int status; @@ -377,7 +411,8 @@ static int dsps_musb_init(struct musb *musb) /* mentor core register starts at offset of 0x400 from musb base */ musb->mregs += wrp->musb_core_offset; - /* Get the NOP PHY */ + /* NOP driver needs change if supporting dual instance */ + usb_nop_xceiv_register(); musb->xceiv = usb_get_phy(USB_PHY_TYPE_USB2); if (IS_ERR_OR_NULL(musb->xceiv)) return -ENODEV; @@ -395,8 +430,7 @@ static int dsps_musb_init(struct musb *musb) dsps_writel(reg_base, wrp->control, (1 << wrp->reset)); /* Start the on-chip PHY and its PLL. */ - if (data->set_phy_power) - data->set_phy_power(1); + musb_dsps_phy_control(glue, pdev->id, 1); musb->isr = dsps_interrupt; @@ -418,16 +452,13 @@ err0: static int dsps_musb_exit(struct musb *musb) { struct device *dev = musb->controller; - struct musb_hdrc_platform_data *plat = dev->platform_data; - struct omap_musb_board_data *data = plat->board_data; struct platform_device *pdev = to_platform_device(dev); struct dsps_glue *glue = dev_get_drvdata(dev->parent); del_timer_sync(&glue->timer[pdev->id]); /* Shutdown the on-chip PHY and its PLL. */ - if (data->set_phy_power) - data->set_phy_power(0); + musb_dsps_phy_control(glue, pdev->id, 0); /* NOP driver needs change if supporting dual instance */ usb_put_phy(musb->xceiv); @@ -459,24 +490,33 @@ static int __devinit dsps_create_musb_pdev(struct dsps_glue *glue, u8 id) struct resource *res; struct resource resources[2]; char res_name[11]; - int ret, musbid; + int ret; - /* get memory resource */ - snprintf(res_name, sizeof(res_name), "musb%d", id); - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, res_name); + resources[0].start = dsps_control_module_phys[id]; + resources[0].end = resources[0].start + SZ_4 - 1; + resources[0].flags = IORESOURCE_MEM; + + glue->usb_ctrl[id] = devm_request_and_ioremap(&pdev->dev, resources); + if (glue->usb_ctrl[id] == NULL) { + dev_err(dev, "Failed to obtain usb_ctrl%d memory\n", id); + ret = -ENODEV; + goto err0; + } + + /* first resource is for usbss, so start index from 1 */ + res = platform_get_resource(pdev, IORESOURCE_MEM, id + 1); if (!res) { - dev_err(dev, "%s get mem resource failed\n", res_name); + dev_err(dev, "failed to get memory for instance %d\n", id); ret = -ENODEV; goto err0; } res->parent = NULL; resources[0] = *res; - /* get irq resource */ - snprintf(res_name, sizeof(res_name), "musb%d-irq", id); - res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, res_name); + /* first resource is for usbss, so start index from 1 */ + res = platform_get_resource(pdev, IORESOURCE_IRQ, id + 1); if (!res) { - dev_err(dev, "%s get irq resource failed\n", res_name); + dev_err(dev, "failed to get irq for instance %d\n", id); ret = -ENODEV; goto err0; } @@ -484,22 +524,14 @@ static int __devinit dsps_create_musb_pdev(struct dsps_glue *glue, u8 id) resources[1] = *res; resources[1].name = "mc"; - /* get the musb id */ - musbid = musb_get_id(dev, GFP_KERNEL); - if (musbid < 0) { - dev_err(dev, "failed to allocate musb id\n"); - ret = -ENOMEM; - goto err0; - } /* allocate the child platform device */ - musb = platform_device_alloc("musb-hdrc", musbid); + musb = platform_device_alloc("musb-hdrc", PLATFORM_DEVID_AUTO); if (!musb) { dev_err(dev, "failed to allocate musb device\n"); ret = -ENOMEM; - goto err1; + goto err0; } - musb->id = musbid; musb->dev.parent = dev; musb->dev.dma_mask = &musb_dmamask; musb->dev.coherent_dma_mask = musb_dmamask; @@ -556,19 +588,10 @@ static int __devinit dsps_create_musb_pdev(struct dsps_glue *glue, u8 id) err2: platform_device_put(musb); -err1: - musb_put_id(dev, musbid); err0: return ret; } -static void dsps_delete_musb_pdev(struct dsps_glue *glue, u8 id) -{ - musb_put_id(glue->dev, glue->musb[id]->id); - platform_device_del(glue->musb[id]); - platform_device_put(glue->musb[id]); -} - static int __devinit dsps_probe(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; @@ -628,7 +651,7 @@ static int __devinit dsps_probe(struct platform_device *pdev) dev_err(&pdev->dev, "failed to create child pdev\n"); /* release resources of previously created instances */ for (i--; i >= 0 ; i--) - dsps_delete_musb_pdev(glue, i); + platform_device_unregister(glue->musb[i]); goto err3; } } @@ -653,7 +676,7 @@ static int __devexit dsps_remove(struct platform_device *pdev) /* delete the child platform device */ for (i = 0; i < wrp->instances ; i++) - dsps_delete_musb_pdev(glue, i); + platform_device_unregister(glue->musb[i]); /* disable usbss clocks */ pm_runtime_put(&pdev->dev); @@ -666,24 +689,26 @@ static int __devexit dsps_remove(struct platform_device *pdev) #ifdef CONFIG_PM_SLEEP static int dsps_suspend(struct device *dev) { - struct musb_hdrc_platform_data *plat = dev->platform_data; - struct omap_musb_board_data *data = plat->board_data; + struct platform_device *pdev = to_platform_device(dev->parent); + struct dsps_glue *glue = platform_get_drvdata(pdev); + const struct dsps_musb_wrapper *wrp = glue->wrp; + int i; - /* Shutdown the on-chip PHY and its PLL. */ - if (data->set_phy_power) - data->set_phy_power(0); + for (i = 0; i < wrp->instances; i++) + musb_dsps_phy_control(glue, i, 0); return 0; } static int dsps_resume(struct device *dev) { - struct musb_hdrc_platform_data *plat = dev->platform_data; - struct omap_musb_board_data *data = plat->board_data; + struct platform_device *pdev = to_platform_device(dev->parent); + struct dsps_glue *glue = platform_get_drvdata(pdev); + const struct dsps_musb_wrapper *wrp = glue->wrp; + int i; - /* Start the on-chip PHY and its PLL. */ - if (data->set_phy_power) - data->set_phy_power(1); + for (i = 0; i < wrp->instances; i++) + musb_dsps_phy_control(glue, i, 1); return 0; } @@ -719,7 +744,7 @@ static const struct dsps_musb_wrapper ti81xx_driver_data __devinitconst = { .rxep_bitmap = (0xfffe << 16), .musb_core_offset = 0x400, .poll_seconds = 2, - .instances = 2, + .instances = 1, }; static const struct platform_device_id musb_dsps_id_table[] __devinitconst = { diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c index d0b87e7b4abf..28b9790e84ea 100644 --- a/drivers/usb/musb/musb_gadget.c +++ b/drivers/usb/musb/musb_gadget.c @@ -1068,7 +1068,6 @@ static int musb_gadget_enable(struct usb_ep *ep, */ musb_ep_select(mbase, epnum); if (usb_endpoint_dir_in(desc)) { - u16 int_txe = musb_readw(mbase, MUSB_INTRTXE); if (hw_ep->is_shared_fifo) musb_ep->is_in = 1; @@ -1080,8 +1079,8 @@ static int musb_gadget_enable(struct usb_ep *ep, goto fail; } - int_txe |= (1 << epnum); - musb_writew(mbase, MUSB_INTRTXE, int_txe); + musb->intrtxe |= (1 << epnum); + musb_writew(mbase, MUSB_INTRTXE, musb->intrtxe); /* REVISIT if can_bulk_split(), use by updating "tmp"; * likewise high bandwidth periodic tx @@ -1108,7 +1107,6 @@ static int musb_gadget_enable(struct usb_ep *ep, musb_writew(regs, MUSB_TXCSR, csr); } else { - u16 int_rxe = musb_readw(mbase, MUSB_INTRRXE); if (hw_ep->is_shared_fifo) musb_ep->is_in = 0; @@ -1120,8 +1118,8 @@ static int musb_gadget_enable(struct usb_ep *ep, goto fail; } - int_rxe |= (1 << epnum); - musb_writew(mbase, MUSB_INTRRXE, int_rxe); + musb->intrrxe |= (1 << epnum); + musb_writew(mbase, MUSB_INTRRXE, musb->intrrxe); /* REVISIT if can_bulk_combine() use by updating "tmp" * likewise high bandwidth periodic rx @@ -1209,14 +1207,12 @@ static int musb_gadget_disable(struct usb_ep *ep) /* zero the endpoint sizes */ if (musb_ep->is_in) { - u16 int_txe = musb_readw(musb->mregs, MUSB_INTRTXE); - int_txe &= ~(1 << epnum); - musb_writew(musb->mregs, MUSB_INTRTXE, int_txe); + musb->intrtxe &= ~(1 << epnum); + musb_writew(musb->mregs, MUSB_INTRTXE, musb->intrtxe); musb_writew(epio, MUSB_TXMAXP, 0); } else { - u16 int_rxe = musb_readw(musb->mregs, MUSB_INTRRXE); - int_rxe &= ~(1 << epnum); - musb_writew(musb->mregs, MUSB_INTRRXE, int_rxe); + musb->intrrxe &= ~(1 << epnum); + musb_writew(musb->mregs, MUSB_INTRRXE, musb->intrrxe); musb_writew(epio, MUSB_RXMAXP, 0); } @@ -1532,7 +1528,7 @@ static void musb_gadget_fifo_flush(struct usb_ep *ep) void __iomem *epio = musb->endpoints[epnum].regs; void __iomem *mbase; unsigned long flags; - u16 csr, int_txe; + u16 csr; mbase = musb->mregs; @@ -1540,8 +1536,7 @@ static void musb_gadget_fifo_flush(struct usb_ep *ep) musb_ep_select(mbase, (u8) epnum); /* disable interrupts */ - int_txe = musb_readw(mbase, MUSB_INTRTXE); - musb_writew(mbase, MUSB_INTRTXE, int_txe & ~(1 << epnum)); + musb_writew(mbase, MUSB_INTRTXE, musb->intrtxe & ~(1 << epnum)); if (musb_ep->is_in) { csr = musb_readw(epio, MUSB_TXCSR); @@ -1565,7 +1560,7 @@ static void musb_gadget_fifo_flush(struct usb_ep *ep) } /* re-enable interrupt */ - musb_writew(mbase, MUSB_INTRTXE, int_txe); + musb_writew(mbase, MUSB_INTRTXE, musb->intrtxe); spin_unlock_irqrestore(&musb->lock, flags); } @@ -2154,10 +2149,9 @@ __acquires(musb->lock) u8 devctl = musb_readb(mbase, MUSB_DEVCTL); u8 power; - dev_dbg(musb->controller, "<== %s addr=%x driver '%s'\n", + dev_dbg(musb->controller, "<== %s driver '%s'\n", (devctl & MUSB_DEVCTL_BDEVICE) ? "B-Device" : "A-Device", - musb_readb(mbase, MUSB_FADDR), musb->gadget_driver ? musb->gadget_driver->driver.name : NULL diff --git a/drivers/usb/musb/musb_gadget_ep0.c b/drivers/usb/musb/musb_gadget_ep0.c index e40d7647caf1..c9c1ac4e075f 100644 --- a/drivers/usb/musb/musb_gadget_ep0.c +++ b/drivers/usb/musb/musb_gadget_ep0.c @@ -673,10 +673,8 @@ irqreturn_t musb_g_ep0_irq(struct musb *musb) csr = musb_readw(regs, MUSB_CSR0); len = musb_readb(regs, MUSB_COUNT0); - dev_dbg(musb->controller, "csr %04x, count %d, myaddr %d, ep0stage %s\n", - csr, len, - musb_readb(mbase, MUSB_FADDR), - decode_ep0stage(musb->ep0_state)); + dev_dbg(musb->controller, "csr %04x, count %d, ep0stage %s\n", + csr, len, decode_ep0stage(musb->ep0_state)); if (csr & MUSB_CSR0_P_DATAEND) { /* diff --git a/drivers/usb/musb/musb_host.c b/drivers/usb/musb/musb_host.c index 3df6a76b851d..e9f0fd9ddd2d 100644 --- a/drivers/usb/musb/musb_host.c +++ b/drivers/usb/musb/musb_host.c @@ -740,7 +740,7 @@ static void musb_ep_program(struct musb *musb, u8 epnum, csr = musb_readw(epio, MUSB_TXCSR); /* disable interrupt in case we flush */ - int_txe = musb_readw(mbase, MUSB_INTRTXE); + int_txe = musb->intrtxe; musb_writew(mbase, MUSB_INTRTXE, int_txe & ~(1 << epnum)); /* general endpoint setup */ diff --git a/drivers/usb/musb/musbhsdma.h b/drivers/usb/musb/musbhsdma.h index 320fd4afb93f..f7b13fd25257 100644 --- a/drivers/usb/musb/musbhsdma.h +++ b/drivers/usb/musb/musbhsdma.h @@ -31,10 +31,6 @@ * */ -#if defined(CONFIG_SOC_OMAP2430) || defined(CONFIG_SOC_OMAP3430) -#include "omap2430.h" -#endif - #ifndef CONFIG_BLACKFIN #define MUSB_HSDMA_BASE 0x200 diff --git a/drivers/usb/musb/omap2430.c b/drivers/usb/musb/omap2430.c index a538fe17a966..32f531e7a2e6 100644 --- a/drivers/usb/musb/omap2430.c +++ b/drivers/usb/musb/omap2430.c @@ -333,6 +333,26 @@ static void omap_musb_mailbox_work(struct work_struct *mailbox_work) omap_musb_set_mailbox(glue); } +static irqreturn_t omap2430_musb_interrupt(int irq, void *__hci) +{ + unsigned long flags; + irqreturn_t retval = IRQ_NONE; + struct musb *musb = __hci; + + spin_lock_irqsave(&musb->lock, flags); + + musb->int_usb = musb_readb(musb->mregs, MUSB_INTRUSB); + musb->int_tx = musb_readw(musb->mregs, MUSB_INTRTX); + musb->int_rx = musb_readw(musb->mregs, MUSB_INTRRX); + + if (musb->int_usb || musb->int_tx || musb->int_rx) + retval = musb_interrupt(musb); + + spin_unlock_irqrestore(&musb->lock, flags); + + return retval; +} + static int omap2430_musb_init(struct musb *musb) { u32 l; @@ -352,6 +372,8 @@ static int omap2430_musb_init(struct musb *musb) return -ENODEV; } + musb->isr = omap2430_musb_interrupt; + status = pm_runtime_get_sync(dev); if (status < 0) { dev_err(dev, "pm_runtime_get_sync FAILED %d\n", status); @@ -478,7 +500,6 @@ static int __devinit omap2430_probe(struct platform_device *pdev) struct musb_hdrc_config *config; struct resource *res; int ret = -ENOMEM; - int musbid; glue = devm_kzalloc(&pdev->dev, sizeof(*glue), GFP_KERNEL); if (!glue) { @@ -486,21 +507,12 @@ static int __devinit omap2430_probe(struct platform_device *pdev) goto err0; } - /* get the musb id */ - musbid = musb_get_id(&pdev->dev, GFP_KERNEL); - if (musbid < 0) { - dev_err(&pdev->dev, "failed to allocate musb id\n"); - ret = -ENOMEM; - goto err0; - } - - musb = platform_device_alloc("musb-hdrc", musbid); + musb = platform_device_alloc("musb-hdrc", PLATFORM_DEVID_AUTO); if (!musb) { dev_err(&pdev->dev, "failed to allocate musb device\n"); - goto err1; + goto err0; } - musb->id = musbid; musb->dev.parent = &pdev->dev; musb->dev.dma_mask = &omap2430_dmamask; musb->dev.coherent_dma_mask = omap2430_dmamask; @@ -521,7 +533,7 @@ static int __devinit omap2430_probe(struct platform_device *pdev) dev_err(&pdev->dev, "failed to allocate musb platfrom data\n"); ret = -ENOMEM; - goto err1; + goto err2; } data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); @@ -529,14 +541,14 @@ static int __devinit omap2430_probe(struct platform_device *pdev) dev_err(&pdev->dev, "failed to allocate musb board data\n"); ret = -ENOMEM; - goto err1; + goto err2; } config = devm_kzalloc(&pdev->dev, sizeof(*config), GFP_KERNEL); if (!data) { dev_err(&pdev->dev, "failed to allocate musb hdrc config\n"); - goto err1; + goto err2; } of_property_read_u32(np, "mode", (u32 *)&pdata->mode); @@ -589,9 +601,6 @@ static int __devinit omap2430_probe(struct platform_device *pdev) err2: platform_device_put(musb); -err1: - musb_put_id(&pdev->dev, musbid); - err0: return ret; } @@ -601,7 +610,6 @@ static int __devexit omap2430_remove(struct platform_device *pdev) struct omap2430_glue *glue = platform_get_drvdata(pdev); cancel_work_sync(&glue->omap_musb_mailbox_work); - musb_put_id(&pdev->dev, glue->musb->id); platform_device_unregister(glue->musb); return 0; diff --git a/drivers/usb/musb/tusb6010.c b/drivers/usb/musb/tusb6010.c index dc4d75ea13ad..812719b683d1 100644 --- a/drivers/usb/musb/tusb6010.c +++ b/drivers/usb/musb/tusb6010.c @@ -1160,7 +1160,6 @@ static int __devinit tusb_probe(struct platform_device *pdev) struct tusb6010_glue *glue; int ret = -ENOMEM; - int musbid; glue = kzalloc(sizeof(*glue), GFP_KERNEL); if (!glue) { @@ -1168,21 +1167,12 @@ static int __devinit tusb_probe(struct platform_device *pdev) goto err0; } - /* get the musb id */ - musbid = musb_get_id(&pdev->dev, GFP_KERNEL); - if (musbid < 0) { - dev_err(&pdev->dev, "failed to allocate musb id\n"); - ret = -ENOMEM; - goto err1; - } - - musb = platform_device_alloc("musb-hdrc", musbid); + musb = platform_device_alloc("musb-hdrc", PLATFORM_DEVID_AUTO); if (!musb) { dev_err(&pdev->dev, "failed to allocate musb device\n"); - goto err2; + goto err1; } - musb->id = musbid; musb->dev.parent = &pdev->dev; musb->dev.dma_mask = &tusb_dmamask; musb->dev.coherent_dma_mask = tusb_dmamask; @@ -1218,9 +1208,6 @@ static int __devinit tusb_probe(struct platform_device *pdev) err3: platform_device_put(musb); -err2: - musb_put_id(&pdev->dev, musbid); - err1: kfree(glue); @@ -1232,9 +1219,7 @@ static int __devexit tusb_remove(struct platform_device *pdev) { struct tusb6010_glue *glue = platform_get_drvdata(pdev); - musb_put_id(&pdev->dev, glue->musb->id); - platform_device_del(glue->musb); - platform_device_put(glue->musb); + platform_device_unregister(glue->musb); kfree(glue); return 0; @@ -1251,15 +1236,4 @@ static struct platform_driver tusb_driver = { MODULE_DESCRIPTION("TUSB6010 MUSB Glue Layer"); MODULE_AUTHOR("Felipe Balbi <balbi@ti.com>"); MODULE_LICENSE("GPL v2"); - -static int __init tusb_init(void) -{ - return platform_driver_register(&tusb_driver); -} -module_init(tusb_init); - -static void __exit tusb_exit(void) -{ - platform_driver_unregister(&tusb_driver); -} -module_exit(tusb_exit); +module_platform_driver(tusb_driver); diff --git a/drivers/usb/musb/ux500.c b/drivers/usb/musb/ux500.c index d62a91fedc22..286f1be6594a 100644 --- a/drivers/usb/musb/ux500.c +++ b/drivers/usb/musb/ux500.c @@ -36,6 +36,26 @@ struct ux500_glue { }; #define glue_to_musb(g) platform_get_drvdata(g->musb) +static irqreturn_t ux500_musb_interrupt(int irq, void *__hci) +{ + unsigned long flags; + irqreturn_t retval = IRQ_NONE; + struct musb *musb = __hci; + + spin_lock_irqsave(&musb->lock, flags); + + musb->int_usb = musb_readb(musb->mregs, MUSB_INTRUSB); + musb->int_tx = musb_readw(musb->mregs, MUSB_INTRTX); + musb->int_rx = musb_readw(musb->mregs, MUSB_INTRRX); + + if (musb->int_usb || musb->int_tx || musb->int_rx) + retval = musb_interrupt(musb); + + spin_unlock_irqrestore(&musb->lock, flags); + + return retval; +} + static int ux500_musb_init(struct musb *musb) { musb->xceiv = usb_get_phy(USB_PHY_TYPE_USB2); @@ -44,6 +64,8 @@ static int ux500_musb_init(struct musb *musb) return -ENODEV; } + musb->isr = ux500_musb_interrupt; + return 0; } @@ -65,7 +87,6 @@ static int __devinit ux500_probe(struct platform_device *pdev) struct platform_device *musb; struct ux500_glue *glue; struct clk *clk; - int ret = -ENOMEM; glue = kzalloc(sizeof(*glue), GFP_KERNEL); @@ -74,18 +95,10 @@ static int __devinit ux500_probe(struct platform_device *pdev) goto err0; } - /* get the musb id */ - musbid = musb_get_id(&pdev->dev, GFP_KERNEL); - if (musbid < 0) { - dev_err(&pdev->dev, "failed to allocate musb id\n"); - ret = -ENOMEM; - goto err1; - } - - musb = platform_device_alloc("musb-hdrc", musbid); + musb = platform_device_alloc("musb-hdrc", PLATFORM_DEVID_AUTO); if (!musb) { dev_err(&pdev->dev, "failed to allocate musb device\n"); - goto err2; + goto err1; } clk = clk_get(&pdev->dev, "usb"); @@ -101,7 +114,6 @@ static int __devinit ux500_probe(struct platform_device *pdev) goto err4; } - musb->id = musbid; musb->dev.parent = &pdev->dev; musb->dev.dma_mask = pdev->dev.dma_mask; musb->dev.coherent_dma_mask = pdev->dev.coherent_dma_mask; @@ -144,9 +156,6 @@ err4: err3: platform_device_put(musb); -err2: - musb_put_id(&pdev->dev, musbid); - err1: kfree(glue); @@ -158,9 +167,7 @@ static int __devexit ux500_remove(struct platform_device *pdev) { struct ux500_glue *glue = platform_get_drvdata(pdev); - musb_put_id(&pdev->dev, glue->musb->id); - platform_device_del(glue->musb); - platform_device_put(glue->musb); + platform_device_unregister(glue->musb); clk_disable(glue->clk); clk_put(glue->clk); kfree(glue); @@ -219,15 +226,4 @@ static struct platform_driver ux500_driver = { MODULE_DESCRIPTION("UX500 MUSB Glue Layer"); MODULE_AUTHOR("Mian Yousaf Kaukab <mian.yousaf.kaukab@stericsson.com>"); MODULE_LICENSE("GPL v2"); - -static int __init ux500_init(void) -{ - return platform_driver_register(&ux500_driver); -} -module_init(ux500_init); - -static void __exit ux500_exit(void) -{ - platform_driver_unregister(&ux500_driver); -} -module_exit(ux500_exit); +module_platform_driver(ux500_driver); diff --git a/drivers/usb/otg/mv_otg.c b/drivers/usb/otg/mv_otg.c index 3f124e8f5792..1dd57504186d 100644 --- a/drivers/usb/otg/mv_otg.c +++ b/drivers/usb/otg/mv_otg.c @@ -958,16 +958,4 @@ static struct platform_driver mv_otg_driver = { .resume = mv_otg_resume, #endif }; - -static int __init mv_otg_init(void) -{ - return platform_driver_register(&mv_otg_driver); -} - -static void __exit mv_otg_exit(void) -{ - platform_driver_unregister(&mv_otg_driver); -} - -module_init(mv_otg_init); -module_exit(mv_otg_exit); +module_platform_driver(mv_otg_driver); diff --git a/drivers/usb/phy/Kconfig b/drivers/usb/phy/Kconfig index 63c339b3e676..7eb73c561bd2 100644 --- a/drivers/usb/phy/Kconfig +++ b/drivers/usb/phy/Kconfig @@ -32,3 +32,15 @@ config MV_U3D_PHY help Enable this to support Marvell USB 3.0 phy controller for Marvell SoC. + +config USB_RCAR_PHY + tristate "Renesas R-Car USB phy support" + depends on USB || USB_GADGET + select USB_OTG_UTILS + help + Say Y here to add support for the Renesas R-Car USB phy driver. + This chip is typically used as USB phy for USB host, gadget. + This driver supports: R8A7779 + + To compile this driver as a module, choose M here: the + module will be called rcar-phy. diff --git a/drivers/usb/phy/Makefile b/drivers/usb/phy/Makefile index b069f29f1225..1a579a860a03 100644 --- a/drivers/usb/phy/Makefile +++ b/drivers/usb/phy/Makefile @@ -8,3 +8,4 @@ obj-$(CONFIG_OMAP_USB2) += omap-usb2.o obj-$(CONFIG_USB_ISP1301) += isp1301.o obj-$(CONFIG_MV_U3D_PHY) += mv_u3d_phy.o obj-$(CONFIG_USB_EHCI_TEGRA) += tegra_usb_phy.o +obj-$(CONFIG_USB_RCAR_PHY) += rcar-phy.o diff --git a/drivers/usb/phy/rcar-phy.c b/drivers/usb/phy/rcar-phy.c new file mode 100644 index 000000000000..792f505d630c --- /dev/null +++ b/drivers/usb/phy/rcar-phy.c @@ -0,0 +1,220 @@ +/* + * Renesas R-Car USB phy driver + * + * Copyright (C) 2012 Renesas Solutions Corp. + * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/delay.h> +#include <linux/io.h> +#include <linux/usb/otg.h> +#include <linux/platform_device.h> +#include <linux/spinlock.h> +#include <linux/module.h> + +/* USBH common register */ +#define USBPCTRL0 0x0800 +#define USBPCTRL1 0x0804 +#define USBST 0x0808 +#define USBEH0 0x080C +#define USBOH0 0x081C +#define USBCTL0 0x0858 +#define EIIBC1 0x0094 +#define EIIBC2 0x009C + +/* USBPCTRL1 */ +#define PHY_RST (1 << 2) +#define PLL_ENB (1 << 1) +#define PHY_ENB (1 << 0) + +/* USBST */ +#define ST_ACT (1 << 31) +#define ST_PLL (1 << 30) + +struct rcar_usb_phy_priv { + struct usb_phy phy; + spinlock_t lock; + + void __iomem *reg0; + void __iomem *reg1; + int counter; +}; + +#define usb_phy_to_priv(p) container_of(p, struct rcar_usb_phy_priv, phy) + + +/* + * USB initial/install operation. + * + * This function setup USB phy. + * The used value and setting order came from + * [USB :: Initial setting] on datasheet. + */ +static int rcar_usb_phy_init(struct usb_phy *phy) +{ + struct rcar_usb_phy_priv *priv = usb_phy_to_priv(phy); + struct device *dev = phy->dev; + void __iomem *reg0 = priv->reg0; + void __iomem *reg1 = priv->reg1; + int i; + u32 val; + unsigned long flags; + + spin_lock_irqsave(&priv->lock, flags); + if (priv->counter++ == 0) { + + /* + * USB phy start-up + */ + + /* (1) USB-PHY standby release */ + iowrite32(PHY_ENB, (reg0 + USBPCTRL1)); + + /* (2) start USB-PHY internal PLL */ + iowrite32(PHY_ENB | PLL_ENB, (reg0 + USBPCTRL1)); + + /* (3) USB module status check */ + for (i = 0; i < 1024; i++) { + udelay(10); + val = ioread32(reg0 + USBST); + if (val == (ST_ACT | ST_PLL)) + break; + } + + if (val != (ST_ACT | ST_PLL)) { + dev_err(dev, "USB phy not ready\n"); + goto phy_init_end; + } + + /* (4) USB-PHY reset clear */ + iowrite32(PHY_ENB | PLL_ENB | PHY_RST, (reg0 + USBPCTRL1)); + + /* set platform specific port settings */ + iowrite32(0x00000000, (reg0 + USBPCTRL0)); + + /* + * EHCI IP internal buffer setting + * EHCI IP internal buffer enable + * + * These are recommended value of a datasheet + * see [USB :: EHCI internal buffer setting] + */ + iowrite32(0x00ff0040, (reg0 + EIIBC1)); + iowrite32(0x00ff0040, (reg1 + EIIBC1)); + + iowrite32(0x00000001, (reg0 + EIIBC2)); + iowrite32(0x00000001, (reg1 + EIIBC2)); + + /* + * Bus alignment settings + */ + + /* (1) EHCI bus alignment (little endian) */ + iowrite32(0x00000000, (reg0 + USBEH0)); + + /* (1) OHCI bus alignment (little endian) */ + iowrite32(0x00000000, (reg0 + USBOH0)); + } + +phy_init_end: + spin_unlock_irqrestore(&priv->lock, flags); + + return 0; +} + +static void rcar_usb_phy_shutdown(struct usb_phy *phy) +{ + struct rcar_usb_phy_priv *priv = usb_phy_to_priv(phy); + void __iomem *reg0 = priv->reg0; + unsigned long flags; + + spin_lock_irqsave(&priv->lock, flags); + + if (priv->counter-- == 1) { /* last user */ + iowrite32(0x00000000, (reg0 + USBPCTRL0)); + iowrite32(0x00000000, (reg0 + USBPCTRL1)); + } + + spin_unlock_irqrestore(&priv->lock, flags); +} + +static int __devinit rcar_usb_phy_probe(struct platform_device *pdev) +{ + struct rcar_usb_phy_priv *priv; + struct resource *res0, *res1; + struct device *dev = &pdev->dev; + void __iomem *reg0, *reg1; + int ret; + + res0 = platform_get_resource(pdev, IORESOURCE_MEM, 0); + res1 = platform_get_resource(pdev, IORESOURCE_MEM, 1); + if (!res0 || !res1) { + dev_err(dev, "Not enough platform resources\n"); + return -EINVAL; + } + + /* + * CAUTION + * + * Because this phy address is also mapped under OHCI/EHCI address area, + * this driver can't use devm_request_and_ioremap(dev, res) here + */ + reg0 = devm_ioremap_nocache(dev, res0->start, resource_size(res0)); + reg1 = devm_ioremap_nocache(dev, res1->start, resource_size(res1)); + if (!reg0 || !reg1) { + dev_err(dev, "ioremap error\n"); + return -ENOMEM; + } + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) { + dev_err(dev, "priv data allocation error\n"); + return -ENOMEM; + } + + priv->reg0 = reg0; + priv->reg1 = reg1; + priv->counter = 0; + priv->phy.dev = dev; + priv->phy.label = dev_name(dev); + priv->phy.init = rcar_usb_phy_init; + priv->phy.shutdown = rcar_usb_phy_shutdown; + spin_lock_init(&priv->lock); + + ret = usb_add_phy(&priv->phy, USB_PHY_TYPE_USB2); + if (ret < 0) { + dev_err(dev, "usb phy addition error\n"); + return ret; + } + + platform_set_drvdata(pdev, priv); + + return ret; +} + +static int __devexit rcar_usb_phy_remove(struct platform_device *pdev) +{ + struct rcar_usb_phy_priv *priv = platform_get_drvdata(pdev); + + usb_remove_phy(&priv->phy); + + return 0; +} + +static struct platform_driver rcar_usb_phy_driver = { + .driver = { + .name = "rcar_usb_phy", + }, + .probe = rcar_usb_phy_probe, + .remove = __devexit_p(rcar_usb_phy_remove), +}; + +module_platform_driver(rcar_usb_phy_driver); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("Renesas R-Car USB phy"); +MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>"); diff --git a/drivers/usb/phy/tegra_usb_phy.c b/drivers/usb/phy/tegra_usb_phy.c index 987116f9efcd..9d13c81754e0 100644 --- a/drivers/usb/phy/tegra_usb_phy.c +++ b/drivers/usb/phy/tegra_usb_phy.c @@ -29,7 +29,9 @@ #include <linux/usb/ulpi.h> #include <asm/mach-types.h> #include <linux/usb/tegra_usb_phy.h> -#include <mach/iomap.h> + +#define TEGRA_USB_BASE 0xC5000000 +#define TEGRA_USB_SIZE SZ_16K #define ULPI_VIEWPORT 0x170 diff --git a/drivers/usb/renesas_usbhs/common.c b/drivers/usb/renesas_usbhs/common.c index 072edc1cc55f..3bf922ab045e 100644 --- a/drivers/usb/renesas_usbhs/common.c +++ b/drivers/usb/renesas_usbhs/common.c @@ -132,6 +132,11 @@ void usbhs_sys_function_ctrl(struct usbhs_priv *priv, int enable) usbhs_bset(priv, SYSCFG, mask, enable ? val : 0); } +void usbhs_sys_function_pullup(struct usbhs_priv *priv, int enable) +{ + usbhs_bset(priv, SYSCFG, DPRPU, enable ? DPRPU : 0); +} + void usbhs_sys_set_test_mode(struct usbhs_priv *priv, u16 mode) { usbhs_write(priv, TESTMODE, mode); diff --git a/drivers/usb/renesas_usbhs/common.h b/drivers/usb/renesas_usbhs/common.h index dddf40a59ded..c69dd2fba360 100644 --- a/drivers/usb/renesas_usbhs/common.h +++ b/drivers/usb/renesas_usbhs/common.h @@ -285,6 +285,7 @@ void usbhs_bset(struct usbhs_priv *priv, u32 reg, u16 mask, u16 data); */ void usbhs_sys_host_ctrl(struct usbhs_priv *priv, int enable); void usbhs_sys_function_ctrl(struct usbhs_priv *priv, int enable); +void usbhs_sys_function_pullup(struct usbhs_priv *priv, int enable); void usbhs_sys_set_test_mode(struct usbhs_priv *priv, u16 mode); /* diff --git a/drivers/usb/renesas_usbhs/fifo.c b/drivers/usb/renesas_usbhs/fifo.c index c021b202c0f3..9538f0feafe2 100644 --- a/drivers/usb/renesas_usbhs/fifo.c +++ b/drivers/usb/renesas_usbhs/fifo.c @@ -163,7 +163,7 @@ static int usbhsf_pkt_handler(struct usbhs_pipe *pipe, int type) func = pkt->handler->dma_done; break; default: - dev_err(dev, "unknown pkt hander\n"); + dev_err(dev, "unknown pkt handler\n"); goto __usbhs_pkt_handler_end; } @@ -192,8 +192,8 @@ void usbhs_pkt_start(struct usbhs_pipe *pipe) /* * irq enable/disable function */ -#define usbhsf_irq_empty_ctrl(p, e) usbhsf_irq_callback_ctrl(p, bempsts, e) -#define usbhsf_irq_ready_ctrl(p, e) usbhsf_irq_callback_ctrl(p, brdysts, e) +#define usbhsf_irq_empty_ctrl(p, e) usbhsf_irq_callback_ctrl(p, irq_bempsts, e) +#define usbhsf_irq_ready_ctrl(p, e) usbhsf_irq_callback_ctrl(p, irq_brdysts, e) #define usbhsf_irq_callback_ctrl(pipe, status, enable) \ ({ \ struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); \ @@ -202,9 +202,9 @@ void usbhs_pkt_start(struct usbhs_pipe *pipe) if (!mod) \ return; \ if (enable) \ - mod->irq_##status |= status; \ + mod->status |= status; \ else \ - mod->irq_##status &= ~status; \ + mod->status &= ~status; \ usbhs_irq_callback_update(priv, mod); \ }) @@ -488,6 +488,8 @@ static int usbhsf_pio_try_push(struct usbhs_pkt *pkt, int *is_done) usbhs_pipe_data_sequence(pipe, pkt->sequence); pkt->sequence = -1; /* -1 sequence will be ignored */ + usbhs_pipe_set_trans_count_if_bulk(pipe, pkt->length); + ret = usbhsf_fifo_select(pipe, fifo, 1); if (ret < 0) return 0; @@ -594,6 +596,7 @@ static int usbhsf_prepare_pop(struct usbhs_pkt *pkt, int *is_done) usbhs_pipe_data_sequence(pipe, pkt->sequence); pkt->sequence = -1; /* -1 sequence will be ignored */ + usbhs_pipe_set_trans_count_if_bulk(pipe, pkt->length); usbhs_pipe_enable(pipe); usbhsf_rx_irq_ctrl(pipe, 1); @@ -795,6 +798,7 @@ static void xfer_work(struct work_struct *work) dev_dbg(dev, " %s %d (%d/ %d)\n", fifo->name, usbhs_pipe_number(pipe), pkt->length, pkt->zero); + usbhs_pipe_set_trans_count_if_bulk(pipe, pkt->trans); usbhs_pipe_enable(pipe); usbhsf_dma_start(pipe, fifo); dma_async_issue_pending(chan); diff --git a/drivers/usb/renesas_usbhs/mod.c b/drivers/usb/renesas_usbhs/mod.c index 61933a90e5bf..6a030b931a3b 100644 --- a/drivers/usb/renesas_usbhs/mod.c +++ b/drivers/usb/renesas_usbhs/mod.c @@ -151,7 +151,7 @@ int usbhs_mod_probe(struct usbhs_priv *priv) goto mod_init_host_err; /* irq settings */ - ret = request_irq(priv->irq, usbhs_interrupt, + ret = devm_request_irq(dev, priv->irq, usbhs_interrupt, priv->irqflags, dev_name(dev), priv); if (ret) { dev_err(dev, "irq request err\n"); @@ -172,7 +172,6 @@ void usbhs_mod_remove(struct usbhs_priv *priv) { usbhs_mod_host_remove(priv); usbhs_mod_gadget_remove(priv); - free_irq(priv->irq, priv); } /* diff --git a/drivers/usb/renesas_usbhs/mod_gadget.c b/drivers/usb/renesas_usbhs/mod_gadget.c index 28478ce26c34..dd41f61893ef 100644 --- a/drivers/usb/renesas_usbhs/mod_gadget.c +++ b/drivers/usb/renesas_usbhs/mod_gadget.c @@ -883,6 +883,16 @@ static int usbhsg_get_frame(struct usb_gadget *gadget) return usbhs_frame_get_num(priv); } +static int usbhsg_pullup(struct usb_gadget *gadget, int is_on) +{ + struct usbhsg_gpriv *gpriv = usbhsg_gadget_to_gpriv(gadget); + struct usbhs_priv *priv = usbhsg_gpriv_to_priv(gpriv); + + usbhs_sys_function_pullup(priv, is_on); + + return 0; +} + static int usbhsg_set_selfpowered(struct usb_gadget *gadget, int is_self) { struct usbhsg_gpriv *gpriv = usbhsg_gadget_to_gpriv(gadget); @@ -900,6 +910,7 @@ static struct usb_gadget_ops usbhsg_gadget_ops = { .set_selfpowered = usbhsg_set_selfpowered, .udc_start = usbhsg_gadget_start, .udc_stop = usbhsg_gadget_stop, + .pullup = usbhsg_pullup, }; static int usbhsg_start(struct usbhs_priv *priv) diff --git a/drivers/usb/renesas_usbhs/mod_host.c b/drivers/usb/renesas_usbhs/mod_host.c index 069cd765400c..3d3cd6ca2689 100644 --- a/drivers/usb/renesas_usbhs/mod_host.c +++ b/drivers/usb/renesas_usbhs/mod_host.c @@ -85,6 +85,7 @@ struct usbhsh_ep { struct usbhsh_device *udev; /* attached udev */ struct usb_host_endpoint *ep; struct list_head ep_list; /* list to usbhsh_device */ + unsigned int counter; /* pipe attach counter */ }; #define USBHSH_DEVICE_MAX 10 /* see DEVADDn / DCPMAXP / PIPEMAXP */ @@ -271,8 +272,12 @@ static int usbhsh_pipe_attach(struct usbhsh_hpriv *hpriv, /******************** spin lock ********************/ usbhs_lock(priv, flags); - if (unlikely(usbhsh_uep_to_pipe(uep))) { - dev_err(dev, "uep already has pipe\n"); + /* + * if uep has been attached to pipe, + * reuse it + */ + if (usbhsh_uep_to_pipe(uep)) { + ret = 0; goto usbhsh_pipe_attach_done; } @@ -320,6 +325,9 @@ static int usbhsh_pipe_attach(struct usbhsh_hpriv *hpriv, } usbhsh_pipe_attach_done: + if (0 == ret) + uep->counter++; + usbhs_unlock(priv, flags); /******************** spin unlock ******************/ @@ -346,7 +354,7 @@ static void usbhsh_pipe_detach(struct usbhsh_hpriv *hpriv, if (unlikely(!pipe)) { dev_err(dev, "uep doens't have pipe\n"); - } else { + } else if (1 == uep->counter--) { /* last user */ struct usb_host_endpoint *ep = usbhsh_uep_to_ep(uep); struct usbhsh_device *udev = usbhsh_uep_to_udev(uep); @@ -391,6 +399,7 @@ static int usbhsh_endpoint_attach(struct usbhsh_hpriv *hpriv, /* * init endpoint */ + uep->counter = 0; INIT_LIST_HEAD(&uep->ep_list); list_add_tail(&uep->ep_list, &udev->ep_list_head); @@ -686,9 +695,9 @@ static int usbhsh_queue_push(struct usb_hcd *hcd, } if (usb_pipein(urb->pipe)) - pipe->handler = &usbhs_fifo_pio_pop_handler; + pipe->handler = &usbhs_fifo_dma_pop_handler; else - pipe->handler = &usbhs_fifo_pio_push_handler; + pipe->handler = &usbhs_fifo_dma_push_handler; buf = (void *)(urb->transfer_buffer + urb->actual_length); len = urb->transfer_buffer_length - urb->actual_length; @@ -921,6 +930,19 @@ static int usbhsh_dcp_queue_push(struct usb_hcd *hcd, */ static int usbhsh_dma_map_ctrl(struct usbhs_pkt *pkt, int map) { + if (map) { + struct usbhsh_request *ureq = usbhsh_pkt_to_ureq(pkt); + struct urb *urb = ureq->urb; + + /* it can not use scatter/gather */ + if (urb->num_sgs) + return -EINVAL; + + pkt->dma = urb->transfer_dma; + if (!pkt->dma) + return -EINVAL; + } + return 0; } @@ -946,7 +968,6 @@ static int usbhsh_urb_enqueue(struct usb_hcd *hcd, struct usb_host_endpoint *ep = urb->ep; struct usbhsh_device *new_udev = NULL; int is_dir_in = usb_pipein(urb->pipe); - int i; int ret; dev_dbg(dev, "%s (%s)\n", __func__, is_dir_in ? "in" : "out"); @@ -992,13 +1013,7 @@ static int usbhsh_urb_enqueue(struct usb_hcd *hcd, * attach pipe to endpoint * see [image of mod_host] */ - for (i = 0; i < 1024; i++) { - ret = usbhsh_pipe_attach(hpriv, urb); - if (ret < 0) - msleep(100); - else - break; - } + ret = usbhsh_pipe_attach(hpriv, urb); if (ret < 0) { dev_err(dev, "pipe attach failed\n"); goto usbhsh_urb_enqueue_error_free_endpoint; @@ -1072,8 +1087,6 @@ static void usbhsh_endpoint_disable(struct usb_hcd *hcd, static int usbhsh_hub_status_data(struct usb_hcd *hcd, char *buf) { struct usbhsh_hpriv *hpriv = usbhsh_hcd_to_hpriv(hcd); - struct usbhs_priv *priv = usbhsh_hpriv_to_priv(hpriv); - struct device *dev = usbhs_priv_to_dev(priv); int roothub_id = 1; /* only 1 root hub */ /* @@ -1085,8 +1098,6 @@ static int usbhsh_hub_status_data(struct usb_hcd *hcd, char *buf) else *buf = 0; - dev_dbg(dev, "%s (%02x)\n", __func__, *buf); - return !!(*buf); } diff --git a/drivers/usb/renesas_usbhs/pipe.c b/drivers/usb/renesas_usbhs/pipe.c index 122526cfd32b..7926e1c700f1 100644 --- a/drivers/usb/renesas_usbhs/pipe.c +++ b/drivers/usb/renesas_usbhs/pipe.c @@ -93,6 +93,82 @@ static void usbhsp_pipe_cfg_set(struct usbhs_pipe *pipe, u16 mask, u16 val) } /* + * PIPEnTRN/PIPEnTRE functions + */ +static void usbhsp_pipe_trn_set(struct usbhs_pipe *pipe, u16 mask, u16 val) +{ + struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); + struct device *dev = usbhs_priv_to_dev(priv); + int num = usbhs_pipe_number(pipe); + u16 reg; + + /* + * It is impossible to calculate address, + * since PIPEnTRN addresses were mapped randomly. + */ +#define CASE_PIPExTRN(a) \ + case 0x ## a: \ + reg = PIPE ## a ## TRN; \ + break; + + switch (num) { + CASE_PIPExTRN(1); + CASE_PIPExTRN(2); + CASE_PIPExTRN(3); + CASE_PIPExTRN(4); + CASE_PIPExTRN(5); + CASE_PIPExTRN(B); + CASE_PIPExTRN(C); + CASE_PIPExTRN(D); + CASE_PIPExTRN(E); + CASE_PIPExTRN(F); + CASE_PIPExTRN(9); + CASE_PIPExTRN(A); + default: + dev_err(dev, "unknown pipe (%d)\n", num); + return; + } + __usbhsp_pipe_xxx_set(pipe, 0, reg, mask, val); +} + +static void usbhsp_pipe_tre_set(struct usbhs_pipe *pipe, u16 mask, u16 val) +{ + struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); + struct device *dev = usbhs_priv_to_dev(priv); + int num = usbhs_pipe_number(pipe); + u16 reg; + + /* + * It is impossible to calculate address, + * since PIPEnTRE addresses were mapped randomly. + */ +#define CASE_PIPExTRE(a) \ + case 0x ## a: \ + reg = PIPE ## a ## TRE; \ + break; + + switch (num) { + CASE_PIPExTRE(1); + CASE_PIPExTRE(2); + CASE_PIPExTRE(3); + CASE_PIPExTRE(4); + CASE_PIPExTRE(5); + CASE_PIPExTRE(B); + CASE_PIPExTRE(C); + CASE_PIPExTRE(D); + CASE_PIPExTRE(E); + CASE_PIPExTRE(F); + CASE_PIPExTRE(9); + CASE_PIPExTRE(A); + default: + dev_err(dev, "unknown pipe (%d)\n", num); + return; + } + + __usbhsp_pipe_xxx_set(pipe, 0, reg, mask, val); +} + +/* * PIPEBUF */ static void usbhsp_pipe_buf_set(struct usbhs_pipe *pipe, u16 mask, u16 val) @@ -264,6 +340,31 @@ int usbhs_pipe_is_stall(struct usbhs_pipe *pipe) return (int)(pid == PID_STALL10 || pid == PID_STALL11); } +void usbhs_pipe_set_trans_count_if_bulk(struct usbhs_pipe *pipe, int len) +{ + if (!usbhs_pipe_type_is(pipe, USB_ENDPOINT_XFER_BULK)) + return; + + /* + * clear and disable transfer counter for IN/OUT pipe + */ + usbhsp_pipe_tre_set(pipe, TRCLR | TRENB, TRCLR); + + /* + * Only IN direction bulk pipe can use transfer count. + * Without using this function, + * received data will break if it was large data size. + * see PIPEnTRN/PIPEnTRE for detail + */ + if (usbhs_pipe_is_dir_in(pipe)) { + int maxp = usbhs_pipe_get_maxpacket(pipe); + + usbhsp_pipe_trn_set(pipe, 0xffff, DIV_ROUND_UP(len, maxp)); + usbhsp_pipe_tre_set(pipe, TRENB, TRENB); /* enable */ + } +} + + /* * pipe setup */ diff --git a/drivers/usb/renesas_usbhs/pipe.h b/drivers/usb/renesas_usbhs/pipe.h index 3d80c7b1fd1b..b476fde955bf 100644 --- a/drivers/usb/renesas_usbhs/pipe.h +++ b/drivers/usb/renesas_usbhs/pipe.h @@ -88,6 +88,7 @@ void usbhs_pipe_enable(struct usbhs_pipe *pipe); void usbhs_pipe_disable(struct usbhs_pipe *pipe); void usbhs_pipe_stall(struct usbhs_pipe *pipe); int usbhs_pipe_is_stall(struct usbhs_pipe *pipe); +void usbhs_pipe_set_trans_count_if_bulk(struct usbhs_pipe *pipe, int len); void usbhs_pipe_select_fifo(struct usbhs_pipe *pipe, struct usbhs_fifo *fifo); void usbhs_pipe_config_update(struct usbhs_pipe *pipe, u16 devsel, u16 epnum, u16 maxp); diff --git a/drivers/usb/serial/aircable.c b/drivers/usb/serial/aircable.c index 54e1bb6372e7..6d110a3bc7e7 100644 --- a/drivers/usb/serial/aircable.c +++ b/drivers/usb/serial/aircable.c @@ -68,10 +68,6 @@ #define THROTTLED 0x01 #define ACTUALLY_THROTTLED 0x02 -/* - * Version Information - */ -#define DRIVER_VERSION "v2.0" #define DRIVER_AUTHOR "Naranjo, Manuel Francisco <naranjo.manuel@gmail.com>, Johan Hovold <jhovold@gmail.com>" #define DRIVER_DESC "AIRcable USB Driver" @@ -192,5 +188,4 @@ module_usb_serial_driver(serial_drivers, id_table); MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_VERSION(DRIVER_VERSION); MODULE_LICENSE("GPL"); diff --git a/drivers/usb/serial/ark3116.c b/drivers/usb/serial/ark3116.c index bd50a8a41a0f..a88882c0e237 100644 --- a/drivers/usb/serial/ark3116.c +++ b/drivers/usb/serial/ark3116.c @@ -37,11 +37,6 @@ #include <linux/mutex.h> #include <linux/spinlock.h> -/* - * Version information - */ - -#define DRIVER_VERSION "v0.7" #define DRIVER_AUTHOR "Bart Hartgers <bart.hartgers+ark3116@gmail.com>" #define DRIVER_DESC "USB ARK3116 serial/IrDA driver" #define DRIVER_DEV_DESC "ARK3116 RS232/IrDA" diff --git a/drivers/usb/serial/belkin_sa.c b/drivers/usb/serial/belkin_sa.c index ea29556f0d72..b72a4c166705 100644 --- a/drivers/usb/serial/belkin_sa.c +++ b/drivers/usb/serial/belkin_sa.c @@ -37,10 +37,6 @@ #include <linux/usb/serial.h> #include "belkin_sa.h" -/* - * Version Information - */ -#define DRIVER_VERSION "v1.3" #define DRIVER_AUTHOR "William Greathouse <wgreathouse@smva.com>" #define DRIVER_DESC "USB Belkin Serial converter driver" @@ -509,5 +505,4 @@ module_usb_serial_driver(serial_drivers, id_table); MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_VERSION(DRIVER_VERSION); MODULE_LICENSE("GPL"); diff --git a/drivers/usb/serial/cp210x.c b/drivers/usb/serial/cp210x.c index eb033fc92a15..2858d8a9eac8 100644 --- a/drivers/usb/serial/cp210x.c +++ b/drivers/usb/serial/cp210x.c @@ -24,10 +24,6 @@ #include <linux/uaccess.h> #include <linux/usb/serial.h> -/* - * Version Information - */ -#define DRIVER_VERSION "v0.09" #define DRIVER_DESC "Silicon Labs CP210x RS232 serial adaptor driver" /* @@ -35,8 +31,7 @@ */ static int cp210x_open(struct tty_struct *tty, struct usb_serial_port *); static void cp210x_close(struct usb_serial_port *); -static void cp210x_get_termios(struct tty_struct *, - struct usb_serial_port *port); +static void cp210x_get_termios(struct tty_struct *, struct usb_serial_port *); static void cp210x_get_termios_port(struct usb_serial_port *port, unsigned int *cflagp, unsigned int *baudp); static void cp210x_change_speed(struct tty_struct *, struct usb_serial_port *, @@ -169,7 +164,7 @@ struct cp210x_serial_private { static struct usb_serial_driver cp210x_device = { .driver = { .owner = THIS_MODULE, - .name = "cp210x", + .name = "cp210x", }, .id_table = id_table, .num_ports = 1, @@ -179,7 +174,7 @@ static struct usb_serial_driver cp210x_device = { .close = cp210x_close, .break_ctl = cp210x_break_ctl, .set_termios = cp210x_set_termios, - .tiocmget = cp210x_tiocmget, + .tiocmget = cp210x_tiocmget, .tiocmset = cp210x_tiocmset, .attach = cp210x_startup, .release = cp210x_release, @@ -281,7 +276,7 @@ static int cp210x_get_config(struct usb_serial_port *port, u8 request, int result, i, length; /* Number of integers required to contain the array */ - length = (((size - 1) | 3) + 1)/4; + length = (((size - 1) | 3) + 1) / 4; buf = kcalloc(length, sizeof(__le32), GFP_KERNEL); if (!buf) { @@ -328,12 +323,11 @@ static int cp210x_set_config(struct usb_serial_port *port, u8 request, int result, i, length; /* Number of integers required to contain the array */ - length = (((size - 1) | 3) + 1)/4; + length = (((size - 1) | 3) + 1) / 4; buf = kmalloc(length * sizeof(__le32), GFP_KERNEL); if (!buf) { - dev_err(&port->dev, "%s - out of memory.\n", - __func__); + dev_err(&port->dev, "%s - out of memory.\n", __func__); return -ENOMEM; } @@ -384,7 +378,8 @@ static inline int cp210x_set_config_single(struct usb_serial_port *port, * cp210x_quantise_baudrate * Quantises the baud rate as per AN205 Table 1 */ -static unsigned int cp210x_quantise_baudrate(unsigned int baud) { +static unsigned int cp210x_quantise_baudrate(unsigned int baud) +{ if (baud <= 300) baud = 300; else if (baud <= 600) baud = 600; @@ -467,9 +462,7 @@ static void cp210x_get_termios(struct tty_struct *tty, cp210x_get_termios_port(tty->driver_data, &tty->termios.c_cflag, &baud); tty_encode_baud_rate(tty, baud, baud); - } - - else { + } else { unsigned int cflag; cflag = 0; cp210x_get_termios_port(port, &cflag, &baud); @@ -693,8 +686,8 @@ static void cp210x_set_termios(struct tty_struct *tty, break;*/ default: dev_dbg(dev, "cp210x driver does not support the number of bits requested, using 8 bit mode\n"); - bits |= BITS_DATA_8; - break; + bits |= BITS_DATA_8; + break; } if (cp210x_set_config(port, CP210X_SET_LINE_CTL, &bits, 2)) dev_dbg(dev, "Number of data bits requested not supported by device\n"); @@ -767,7 +760,7 @@ static void cp210x_set_termios(struct tty_struct *tty, } -static int cp210x_tiocmset (struct tty_struct *tty, +static int cp210x_tiocmset(struct tty_struct *tty, unsigned int set, unsigned int clear) { struct usb_serial_port *port = tty->driver_data; @@ -809,7 +802,7 @@ static void cp210x_dtr_rts(struct usb_serial_port *p, int on) cp210x_tiocmset_port(p, 0, TIOCM_DTR|TIOCM_RTS); } -static int cp210x_tiocmget (struct tty_struct *tty) +static int cp210x_tiocmget(struct tty_struct *tty) { struct usb_serial_port *port = tty->driver_data; unsigned int control; @@ -829,7 +822,7 @@ static int cp210x_tiocmget (struct tty_struct *tty) return result; } -static void cp210x_break_ctl (struct tty_struct *tty, int break_state) +static void cp210x_break_ctl(struct tty_struct *tty, int break_state) { struct usb_serial_port *port = tty->driver_data; unsigned int state; @@ -874,5 +867,4 @@ static void cp210x_release(struct usb_serial *serial) module_usb_serial_driver(serial_drivers, id_table); MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_VERSION(DRIVER_VERSION); MODULE_LICENSE("GPL"); diff --git a/drivers/usb/serial/cyberjack.c b/drivers/usb/serial/cyberjack.c index 4ee77dcbe690..69a4fa1cee25 100644 --- a/drivers/usb/serial/cyberjack.c +++ b/drivers/usb/serial/cyberjack.c @@ -43,10 +43,6 @@ #define CYBERJACK_LOCAL_BUF_SIZE 32 -/* - * Version Information - */ -#define DRIVER_VERSION "v1.01" #define DRIVER_AUTHOR "Matthias Bruestle" #define DRIVER_DESC "REINER SCT cyberJack pinpad/e-com USB Chipcard Reader Driver" @@ -441,5 +437,4 @@ module_usb_serial_driver(serial_drivers, id_table); MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_VERSION(DRIVER_VERSION); MODULE_LICENSE("GPL"); diff --git a/drivers/usb/serial/cypress_m8.c b/drivers/usb/serial/cypress_m8.c index f0da1279c114..fd8c35fd452e 100644 --- a/drivers/usb/serial/cypress_m8.c +++ b/drivers/usb/serial/cypress_m8.c @@ -50,10 +50,6 @@ static bool stats; static int interval; static bool unstable_bauds; -/* - * Version Information - */ -#define DRIVER_VERSION "v1.10" #define DRIVER_AUTHOR "Lonnie Mendez <dignome@gmail.com>, Neil Whelchel <koyama@firstlight.net>" #define DRIVER_DESC "Cypress USB to Serial Driver" @@ -1303,7 +1299,6 @@ module_usb_serial_driver(serial_drivers, id_table_combined); MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_VERSION(DRIVER_VERSION); MODULE_LICENSE("GPL"); module_param(stats, bool, S_IRUGO | S_IWUSR); diff --git a/drivers/usb/serial/digi_acceleport.c b/drivers/usb/serial/digi_acceleport.c index b50fa1c6d885..45d4af62967f 100644 --- a/drivers/usb/serial/digi_acceleport.c +++ b/drivers/usb/serial/digi_acceleport.c @@ -32,10 +32,6 @@ /* Defines */ -/* - * Version Information - */ -#define DRIVER_VERSION "v1.80.1.2" #define DRIVER_AUTHOR "Peter Berger <pberger@brimson.com>, Al Borchers <borchers@steinerpoint.com>" #define DRIVER_DESC "Digi AccelePort USB-2/USB-4 Serial Converter driver" diff --git a/drivers/usb/serial/empeg.c b/drivers/usb/serial/empeg.c index 43ede4a1e12c..0f658618db13 100644 --- a/drivers/usb/serial/empeg.c +++ b/drivers/usb/serial/empeg.c @@ -28,10 +28,6 @@ #include <linux/usb.h> #include <linux/usb/serial.h> -/* - * Version Information - */ -#define DRIVER_VERSION "v1.3" #define DRIVER_AUTHOR "Greg Kroah-Hartman <greg@kroah.com>, Gary Brubaker <xavyer@ix.netcom.com>" #define DRIVER_DESC "USB Empeg Mark I/II Driver" diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index be845873e23d..8c3379b52f24 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -73,7 +73,6 @@ struct ftdi_private { char prev_status; /* Used for TIOCMIWAIT */ bool dev_gone; /* Used to abort TIOCMIWAIT */ char transmit_empty; /* If transmitter is empty or not */ - struct usb_serial_port *port; __u16 interface; /* FT2232C, FT2232H or FT4232H port interface (0 for FT232/245) */ @@ -923,6 +922,9 @@ static int ftdi_get_icount(struct tty_struct *tty, static int ftdi_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg); static void ftdi_break_ctl(struct tty_struct *tty, int break_state); +static int ftdi_chars_in_buffer(struct tty_struct *tty); +static int ftdi_get_modem_status(struct tty_struct *tty, + unsigned char status[2]); static unsigned short int ftdi_232am_baud_base_to_divisor(int baud, int base); static unsigned short int ftdi_232am_baud_to_divisor(int baud); @@ -957,6 +959,7 @@ static struct usb_serial_driver ftdi_sio_device = { .ioctl = ftdi_ioctl, .set_termios = ftdi_set_termios, .break_ctl = ftdi_break_ctl, + .chars_in_buffer = ftdi_chars_in_buffer, }; static struct usb_serial_driver * const serial_drivers[] = { @@ -1090,6 +1093,7 @@ static int update_mctrl(struct usb_serial_port *port, unsigned int set, __func__, (set & TIOCM_DTR) ? "HIGH" : (clear & TIOCM_DTR) ? "LOW" : "unchanged", (set & TIOCM_RTS) ? "HIGH" : (clear & TIOCM_RTS) ? "LOW" : "unchanged"); + rv = usb_translate_errors(rv); } else { dev_dbg(dev, "%s - DTR %s, RTS %s\n", __func__, (set & TIOCM_DTR) ? "HIGH" : (clear & TIOCM_DTR) ? "LOW" : "unchanged", @@ -1682,7 +1686,6 @@ static int ftdi_sio_port_probe(struct usb_serial_port *port) kref_init(&priv->kref); mutex_init(&priv->cfg_lock); - memset(&priv->icount, 0x00, sizeof(priv->icount)); init_waitqueue_head(&priv->delta_msr_wait); priv->flags = ASYNC_LOW_LATENCY; @@ -1691,7 +1694,6 @@ static int ftdi_sio_port_probe(struct usb_serial_port *port) if (quirk && quirk->port_probe) quirk->port_probe(priv); - priv->port = port; usb_set_serial_port_data(port, priv); ftdi_determine_type(port); @@ -2089,6 +2091,29 @@ static void ftdi_break_ctl(struct tty_struct *tty, int break_state) } +static int ftdi_chars_in_buffer(struct tty_struct *tty) +{ + struct usb_serial_port *port = tty->driver_data; + int chars; + unsigned char buf[2]; + int ret; + + chars = usb_serial_generic_chars_in_buffer(tty); + if (chars) + goto out; + + /* Check if hardware buffer is empty. */ + ret = ftdi_get_modem_status(tty, buf); + if (ret == 2) { + if (!(buf[1] & FTDI_RS_TEMT)) + chars = 1; + } +out: + dev_dbg(&port->dev, "%s - %d\n", __func__, chars); + + return chars; +} + /* old_termios contains the original termios settings and tty->termios contains * the new setting to be used * WARNING: set_termios calls this with old_termios in kernel space @@ -2272,7 +2297,14 @@ no_c_cflag_changes: } } -static int ftdi_tiocmget(struct tty_struct *tty) +/* + * Get modem-control status. + * + * Returns the number of status bytes retrieved (device dependant), or + * negative error code. + */ +static int ftdi_get_modem_status(struct tty_struct *tty, + unsigned char status[2]) { struct usb_serial_port *port = tty->driver_data; struct ftdi_private *priv = usb_get_serial_port_data(port); @@ -2312,16 +2344,43 @@ static int ftdi_tiocmget(struct tty_struct *tty) FTDI_SIO_GET_MODEM_STATUS_REQUEST_TYPE, 0, priv->interface, buf, len, WDR_TIMEOUT); - if (ret < 0) + if (ret < 0) { + dev_err(&port->dev, "failed to get modem status: %d\n", ret); + ret = usb_translate_errors(ret); goto out; + } - ret = (buf[0] & FTDI_SIO_DSR_MASK ? TIOCM_DSR : 0) | - (buf[0] & FTDI_SIO_CTS_MASK ? TIOCM_CTS : 0) | - (buf[0] & FTDI_SIO_RI_MASK ? TIOCM_RI : 0) | - (buf[0] & FTDI_SIO_RLSD_MASK ? TIOCM_CD : 0) | - priv->last_dtr_rts; + status[0] = buf[0]; + if (ret > 1) + status[1] = buf[1]; + else + status[1] = 0; + + dev_dbg(&port->dev, "%s - 0x%02x%02x\n", __func__, status[0], + status[1]); out: kfree(buf); + + return ret; +} + +static int ftdi_tiocmget(struct tty_struct *tty) +{ + struct usb_serial_port *port = tty->driver_data; + struct ftdi_private *priv = usb_get_serial_port_data(port); + unsigned char buf[2]; + int ret; + + ret = ftdi_get_modem_status(tty, buf); + if (ret < 0) + return ret; + + ret = (buf[0] & FTDI_SIO_DSR_MASK ? TIOCM_DSR : 0) | + (buf[0] & FTDI_SIO_CTS_MASK ? TIOCM_CTS : 0) | + (buf[0] & FTDI_SIO_RI_MASK ? TIOCM_RI : 0) | + (buf[0] & FTDI_SIO_RLSD_MASK ? TIOCM_CD : 0) | + priv->last_dtr_rts; + return ret; } diff --git a/drivers/usb/serial/generic.c b/drivers/usb/serial/generic.c index 296612153ea2..2ea70a631996 100644 --- a/drivers/usb/serial/generic.c +++ b/drivers/usb/serial/generic.c @@ -262,6 +262,7 @@ int usb_serial_generic_chars_in_buffer(struct tty_struct *tty) dev_dbg(&port->dev, "%s - returns %d\n", __func__, chars); return chars; } +EXPORT_SYMBOL_GPL(usb_serial_generic_chars_in_buffer); static int usb_serial_generic_submit_read_urb(struct usb_serial_port *port, int index, gfp_t mem_flags) diff --git a/drivers/usb/serial/hp4x.c b/drivers/usb/serial/hp4x.c index 0bbaf21a9d1e..2cba60d90c79 100644 --- a/drivers/usb/serial/hp4x.c +++ b/drivers/usb/serial/hp4x.c @@ -20,10 +20,6 @@ #include <linux/usb.h> #include <linux/usb/serial.h> -/* - * Version Information - */ -#define DRIVER_VERSION "v1.00" #define DRIVER_DESC "HP4x (48/49) Generic Serial driver" #define HP_VENDOR_ID 0x03f0 @@ -52,5 +48,4 @@ static struct usb_serial_driver * const serial_drivers[] = { module_usb_serial_driver(serial_drivers, id_table); MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_VERSION(DRIVER_VERSION); MODULE_LICENSE("GPL"); diff --git a/drivers/usb/serial/io_edgeport.c b/drivers/usb/serial/io_edgeport.c index 5acc0d13864a..7b770c7f8b11 100644 --- a/drivers/usb/serial/io_edgeport.c +++ b/drivers/usb/serial/io_edgeport.c @@ -51,10 +51,6 @@ #include "io_ionsp.h" /* info for the iosp messages */ #include "io_16654.h" /* 16654 UART defines */ -/* - * Version Information - */ -#define DRIVER_VERSION "v2.7" #define DRIVER_AUTHOR "Greg Kroah-Hartman <greg@kroah.com> and David Iacovelli" #define DRIVER_DESC "Edgeport USB Serial Driver" diff --git a/drivers/usb/serial/io_ti.c b/drivers/usb/serial/io_ti.c index 60023c2d2a31..58184f3de686 100644 --- a/drivers/usb/serial/io_ti.c +++ b/drivers/usb/serial/io_ti.c @@ -40,10 +40,6 @@ #include "io_usbvend.h" #include "io_ti.h" -/* - * Version Information - */ -#define DRIVER_VERSION "v0.7mode043006" #define DRIVER_AUTHOR "Greg Kroah-Hartman <greg@kroah.com> and David Iacovelli" #define DRIVER_DESC "Edgeport USB Serial Driver" diff --git a/drivers/usb/serial/ipaq.c b/drivers/usb/serial/ipaq.c index 1068bf22e27e..76c9a847da5d 100644 --- a/drivers/usb/serial/ipaq.c +++ b/drivers/usb/serial/ipaq.c @@ -25,11 +25,6 @@ #define KP_RETRIES 100 -/* - * Version Information - */ - -#define DRIVER_VERSION "v1.0" #define DRIVER_AUTHOR "Ganesh Varadarajan <ganesh@veritas.com>" #define DRIVER_DESC "USB PocketPC PDA driver" diff --git a/drivers/usb/serial/ipw.c b/drivers/usb/serial/ipw.c index 4264821a3b34..155eab14b30e 100644 --- a/drivers/usb/serial/ipw.c +++ b/drivers/usb/serial/ipw.c @@ -49,10 +49,6 @@ #include <linux/uaccess.h> #include "usb-wwan.h" -/* - * Version Information - */ -#define DRIVER_VERSION "v0.4" #define DRIVER_AUTHOR "Roelf Diedericks" #define DRIVER_DESC "IPWireless tty driver" diff --git a/drivers/usb/serial/iuu_phoenix.c b/drivers/usb/serial/iuu_phoenix.c index cd5533e81de7..1e1fbed65ef2 100644 --- a/drivers/usb/serial/iuu_phoenix.c +++ b/drivers/usb/serial/iuu_phoenix.c @@ -32,10 +32,6 @@ #include "iuu_phoenix.h" #include <linux/random.h> -/* - * Version Information - */ -#define DRIVER_VERSION "v0.12" #define DRIVER_DESC "Infinity USB Unlimited Phoenix driver" static const struct usb_device_id id_table[] = { @@ -1164,7 +1160,7 @@ static ssize_t store_vcc_mode(struct device *dev, struct iuu_private *priv = usb_get_serial_port_data(port); unsigned long v; - if (strict_strtoul(buf, 10, &v)) { + if (kstrtoul(buf, 10, &v)) { dev_err(dev, "%s - vcc_mode: %s is not a unsigned long\n", __func__, buf); goto fail_store_vcc_mode; @@ -1232,8 +1228,6 @@ MODULE_AUTHOR("Alain Degreffe eczema@ecze.com"); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); -MODULE_VERSION(DRIVER_VERSION); - module_param(xmas, bool, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(xmas, "Xmas colors enabled or not"); diff --git a/drivers/usb/serial/keyspan.c b/drivers/usb/serial/keyspan.c index 7179b0c5f814..991ca6a690a0 100644 --- a/drivers/usb/serial/keyspan.c +++ b/drivers/usb/serial/keyspan.c @@ -44,10 +44,6 @@ #include <linux/usb/ezusb.h> #include "keyspan.h" -/* - * Version Information - */ -#define DRIVER_VERSION "v1.1.5" #define DRIVER_AUTHOR "Hugh Blemings <hugh@misc.nu" #define DRIVER_DESC "Keyspan USB to Serial Converter Driver" diff --git a/drivers/usb/serial/keyspan_pda.c b/drivers/usb/serial/keyspan_pda.c index bb87e29c4ac2..41b01092af07 100644 --- a/drivers/usb/serial/keyspan_pda.c +++ b/drivers/usb/serial/keyspan_pda.c @@ -42,10 +42,6 @@ #undef XIRCOM #endif -/* - * Version Information - */ -#define DRIVER_VERSION "v1.1" #define DRIVER_AUTHOR "Brian Warner <warner@lothar.com>" #define DRIVER_DESC "USB Keyspan PDA Converter driver" diff --git a/drivers/usb/serial/kl5kusb105.c b/drivers/usb/serial/kl5kusb105.c index 1f4517864cd2..fc9e14a1e9b3 100644 --- a/drivers/usb/serial/kl5kusb105.c +++ b/drivers/usb/serial/kl5kusb105.c @@ -49,10 +49,6 @@ #include <linux/usb/serial.h> #include "kl5kusb105.h" -/* - * Version Information - */ -#define DRIVER_VERSION "v0.4" #define DRIVER_AUTHOR "Utz-Uwe Haus <haus@uuhaus.de>, Johan Hovold <jhovold@gmail.com>" #define DRIVER_DESC "KLSI KL5KUSB105 chipset USB->Serial Converter driver" diff --git a/drivers/usb/serial/kobil_sct.c b/drivers/usb/serial/kobil_sct.c index c9ca7a5b12e0..b747ba615d0b 100644 --- a/drivers/usb/serial/kobil_sct.c +++ b/drivers/usb/serial/kobil_sct.c @@ -38,8 +38,6 @@ #include <linux/ioctl.h> #include "kobil_sct.h" -/* Version Information */ -#define DRIVER_VERSION "21/05/2004" #define DRIVER_AUTHOR "KOBIL Systems GmbH - http://www.kobil.com" #define DRIVER_DESC "KOBIL USB Smart Card Terminal Driver (experimental)" diff --git a/drivers/usb/serial/mct_u232.c b/drivers/usb/serial/mct_u232.c index 8a2081004107..b6911757c855 100644 --- a/drivers/usb/serial/mct_u232.c +++ b/drivers/usb/serial/mct_u232.c @@ -38,10 +38,6 @@ #include <linux/ioctl.h> #include "mct_u232.h" -/* - * Version Information - */ -#define DRIVER_VERSION "z2.1" /* Linux in-kernel version */ #define DRIVER_AUTHOR "Wolfgang Grandegger <wolfgang@ces.ch>" #define DRIVER_DESC "Magic Control Technology USB-RS232 converter driver" diff --git a/drivers/usb/serial/metro-usb.c b/drivers/usb/serial/metro-usb.c index 6f29c74eb769..3d258448c29a 100644 --- a/drivers/usb/serial/metro-usb.c +++ b/drivers/usb/serial/metro-usb.c @@ -20,8 +20,6 @@ #include <linux/uaccess.h> #include <linux/usb/serial.h> -/* Version Information */ -#define DRIVER_VERSION "v1.2.0.0" #define DRIVER_DESC "Metrologic Instruments Inc. - USB-POS driver" /* Product information. */ diff --git a/drivers/usb/serial/mos7720.c b/drivers/usb/serial/mos7720.c index 75267421aad8..f57a6b1fe787 100644 --- a/drivers/usb/serial/mos7720.c +++ b/drivers/usb/serial/mos7720.c @@ -36,10 +36,6 @@ #include <linux/uaccess.h> #include <linux/parport.h> -/* - * Version Information - */ -#define DRIVER_VERSION "2.1" #define DRIVER_AUTHOR "Aspire Communications pvt Ltd." #define DRIVER_DESC "Moschip USB Serial Driver" diff --git a/drivers/usb/serial/mos7840.c b/drivers/usb/serial/mos7840.c index 1cf3375ec1af..66d9e088d9d9 100644 --- a/drivers/usb/serial/mos7840.c +++ b/drivers/usb/serial/mos7840.c @@ -35,10 +35,6 @@ #include <linux/usb/serial.h> #include <linux/uaccess.h> -/* - * Version Information - */ -#define DRIVER_VERSION "1.3.2" #define DRIVER_DESC "Moschip 7840/7820 USB Serial Driver" /* diff --git a/drivers/usb/serial/omninet.c b/drivers/usb/serial/omninet.c index 9ab73d295774..7818af931a48 100644 --- a/drivers/usb/serial/omninet.c +++ b/drivers/usb/serial/omninet.c @@ -23,10 +23,6 @@ #include <linux/usb.h> #include <linux/usb/serial.h> -/* - * Version Information - */ -#define DRIVER_VERSION "v1.1" #define DRIVER_AUTHOR "Alessandro Zummo" #define DRIVER_DESC "USB ZyXEL omni.net LCD PLUS Driver" diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index 5dee7d61241e..5839f4d662dc 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -28,7 +28,6 @@ device features. */ -#define DRIVER_VERSION "v0.7.2" #define DRIVER_AUTHOR "Matthias Urlichs <smurf@smurf.noris.de>" #define DRIVER_DESC "USB Driver for GSM modems" @@ -733,23 +732,23 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE(ANYDATA_VENDOR_ID, ANYDATA_PRODUCT_ADU_620UW) }, { USB_DEVICE(AXESSTEL_VENDOR_ID, AXESSTEL_PRODUCT_MV110H) }, { USB_DEVICE(YISO_VENDOR_ID, YISO_PRODUCT_U893) }, - { USB_DEVICE(BANDRICH_VENDOR_ID, BANDRICH_PRODUCT_C100_1) }, - { USB_DEVICE(BANDRICH_VENDOR_ID, BANDRICH_PRODUCT_C100_2) }, - { USB_DEVICE(BANDRICH_VENDOR_ID, BANDRICH_PRODUCT_1004) }, - { USB_DEVICE(BANDRICH_VENDOR_ID, BANDRICH_PRODUCT_1005) }, - { USB_DEVICE(BANDRICH_VENDOR_ID, BANDRICH_PRODUCT_1006) }, - { USB_DEVICE(BANDRICH_VENDOR_ID, BANDRICH_PRODUCT_1007) }, - { USB_DEVICE(BANDRICH_VENDOR_ID, BANDRICH_PRODUCT_1008) }, - { USB_DEVICE(BANDRICH_VENDOR_ID, BANDRICH_PRODUCT_1009) }, - { USB_DEVICE(BANDRICH_VENDOR_ID, BANDRICH_PRODUCT_100A) }, - { USB_DEVICE(BANDRICH_VENDOR_ID, BANDRICH_PRODUCT_100B) }, - { USB_DEVICE(BANDRICH_VENDOR_ID, BANDRICH_PRODUCT_100C) }, - { USB_DEVICE(BANDRICH_VENDOR_ID, BANDRICH_PRODUCT_100D) }, - { USB_DEVICE(BANDRICH_VENDOR_ID, BANDRICH_PRODUCT_100E) }, - { USB_DEVICE(BANDRICH_VENDOR_ID, BANDRICH_PRODUCT_100F) }, - { USB_DEVICE(BANDRICH_VENDOR_ID, BANDRICH_PRODUCT_1010) }, - { USB_DEVICE(BANDRICH_VENDOR_ID, BANDRICH_PRODUCT_1011) }, - { USB_DEVICE(BANDRICH_VENDOR_ID, BANDRICH_PRODUCT_1012) }, + { USB_DEVICE_INTERFACE_CLASS(BANDRICH_VENDOR_ID, BANDRICH_PRODUCT_C100_1, 0xff) }, + { USB_DEVICE_INTERFACE_CLASS(BANDRICH_VENDOR_ID, BANDRICH_PRODUCT_C100_2, 0xff) }, + { USB_DEVICE_INTERFACE_CLASS(BANDRICH_VENDOR_ID, BANDRICH_PRODUCT_1004, 0xff) }, + { USB_DEVICE_INTERFACE_CLASS(BANDRICH_VENDOR_ID, BANDRICH_PRODUCT_1005, 0xff) }, + { USB_DEVICE_INTERFACE_CLASS(BANDRICH_VENDOR_ID, BANDRICH_PRODUCT_1006, 0xff) }, + { USB_DEVICE_INTERFACE_CLASS(BANDRICH_VENDOR_ID, BANDRICH_PRODUCT_1007, 0xff) }, + { USB_DEVICE_INTERFACE_CLASS(BANDRICH_VENDOR_ID, BANDRICH_PRODUCT_1008, 0xff) }, + { USB_DEVICE_INTERFACE_CLASS(BANDRICH_VENDOR_ID, BANDRICH_PRODUCT_1009, 0xff) }, + { USB_DEVICE_INTERFACE_CLASS(BANDRICH_VENDOR_ID, BANDRICH_PRODUCT_100A, 0xff) }, + { USB_DEVICE_INTERFACE_CLASS(BANDRICH_VENDOR_ID, BANDRICH_PRODUCT_100B, 0xff) }, + { USB_DEVICE_INTERFACE_CLASS(BANDRICH_VENDOR_ID, BANDRICH_PRODUCT_100C, 0xff) }, + { USB_DEVICE_INTERFACE_CLASS(BANDRICH_VENDOR_ID, BANDRICH_PRODUCT_100D, 0xff) }, + { USB_DEVICE_INTERFACE_CLASS(BANDRICH_VENDOR_ID, BANDRICH_PRODUCT_100E, 0xff) }, + { USB_DEVICE_INTERFACE_CLASS(BANDRICH_VENDOR_ID, BANDRICH_PRODUCT_100F, 0xff) }, + { USB_DEVICE_INTERFACE_CLASS(BANDRICH_VENDOR_ID, BANDRICH_PRODUCT_1010, 0xff) }, + { USB_DEVICE_INTERFACE_CLASS(BANDRICH_VENDOR_ID, BANDRICH_PRODUCT_1011, 0xff) }, + { USB_DEVICE_INTERFACE_CLASS(BANDRICH_VENDOR_ID, BANDRICH_PRODUCT_1012, 0xff) }, { USB_DEVICE(KYOCERA_VENDOR_ID, KYOCERA_PRODUCT_KPC650) }, { USB_DEVICE(KYOCERA_VENDOR_ID, KYOCERA_PRODUCT_KPC680) }, { USB_DEVICE(QUALCOMM_VENDOR_ID, 0x6000)}, /* ZTE AC8700 */ @@ -1165,22 +1164,22 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE(LONGCHEER_VENDOR_ID, ZOOM_PRODUCT_4597) }, { USB_DEVICE(HAIER_VENDOR_ID, HAIER_PRODUCT_CE100) }, /* Pirelli */ - { USB_DEVICE(PIRELLI_VENDOR_ID, PIRELLI_PRODUCT_C100_1)}, - { USB_DEVICE(PIRELLI_VENDOR_ID, PIRELLI_PRODUCT_C100_2)}, - { USB_DEVICE(PIRELLI_VENDOR_ID, PIRELLI_PRODUCT_1004)}, - { USB_DEVICE(PIRELLI_VENDOR_ID, PIRELLI_PRODUCT_1005)}, - { USB_DEVICE(PIRELLI_VENDOR_ID, PIRELLI_PRODUCT_1006)}, - { USB_DEVICE(PIRELLI_VENDOR_ID, PIRELLI_PRODUCT_1007)}, - { USB_DEVICE(PIRELLI_VENDOR_ID, PIRELLI_PRODUCT_1008)}, - { USB_DEVICE(PIRELLI_VENDOR_ID, PIRELLI_PRODUCT_1009)}, - { USB_DEVICE(PIRELLI_VENDOR_ID, PIRELLI_PRODUCT_100A)}, - { USB_DEVICE(PIRELLI_VENDOR_ID, PIRELLI_PRODUCT_100B) }, - { USB_DEVICE(PIRELLI_VENDOR_ID, PIRELLI_PRODUCT_100C) }, - { USB_DEVICE(PIRELLI_VENDOR_ID, PIRELLI_PRODUCT_100D) }, - { USB_DEVICE(PIRELLI_VENDOR_ID, PIRELLI_PRODUCT_100E) }, - { USB_DEVICE(PIRELLI_VENDOR_ID, PIRELLI_PRODUCT_100F) }, - { USB_DEVICE(PIRELLI_VENDOR_ID, PIRELLI_PRODUCT_1011)}, - { USB_DEVICE(PIRELLI_VENDOR_ID, PIRELLI_PRODUCT_1012)}, + { USB_DEVICE_INTERFACE_CLASS(PIRELLI_VENDOR_ID, PIRELLI_PRODUCT_C100_1, 0xff) }, + { USB_DEVICE_INTERFACE_CLASS(PIRELLI_VENDOR_ID, PIRELLI_PRODUCT_C100_2, 0xff) }, + { USB_DEVICE_INTERFACE_CLASS(PIRELLI_VENDOR_ID, PIRELLI_PRODUCT_1004, 0xff) }, + { USB_DEVICE_INTERFACE_CLASS(PIRELLI_VENDOR_ID, PIRELLI_PRODUCT_1005, 0xff) }, + { USB_DEVICE_INTERFACE_CLASS(PIRELLI_VENDOR_ID, PIRELLI_PRODUCT_1006, 0xff) }, + { USB_DEVICE_INTERFACE_CLASS(PIRELLI_VENDOR_ID, PIRELLI_PRODUCT_1007, 0xff) }, + { USB_DEVICE_INTERFACE_CLASS(PIRELLI_VENDOR_ID, PIRELLI_PRODUCT_1008, 0xff) }, + { USB_DEVICE_INTERFACE_CLASS(PIRELLI_VENDOR_ID, PIRELLI_PRODUCT_1009, 0xff) }, + { USB_DEVICE_INTERFACE_CLASS(PIRELLI_VENDOR_ID, PIRELLI_PRODUCT_100A, 0xff) }, + { USB_DEVICE_INTERFACE_CLASS(PIRELLI_VENDOR_ID, PIRELLI_PRODUCT_100B, 0xff) }, + { USB_DEVICE_INTERFACE_CLASS(PIRELLI_VENDOR_ID, PIRELLI_PRODUCT_100C, 0xff) }, + { USB_DEVICE_INTERFACE_CLASS(PIRELLI_VENDOR_ID, PIRELLI_PRODUCT_100D, 0xff) }, + { USB_DEVICE_INTERFACE_CLASS(PIRELLI_VENDOR_ID, PIRELLI_PRODUCT_100E, 0xff) }, + { USB_DEVICE_INTERFACE_CLASS(PIRELLI_VENDOR_ID, PIRELLI_PRODUCT_100F, 0xff) }, + { USB_DEVICE_INTERFACE_CLASS(PIRELLI_VENDOR_ID, PIRELLI_PRODUCT_1011, 0xff) }, + { USB_DEVICE_INTERFACE_CLASS(PIRELLI_VENDOR_ID, PIRELLI_PRODUCT_1012, 0xff) }, /* Cinterion */ { USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_EU3_E) }, { USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_EU3_P) }, @@ -1341,20 +1340,10 @@ static int option_probe(struct usb_serial *serial, &serial->interface->cur_altsetting->desc; struct usb_device_descriptor *dev_desc = &serial->dev->descriptor; - /* - * D-Link DWM 652 still exposes CD-Rom emulation interface in modem - * mode. - */ - if (dev_desc->idVendor == DLINK_VENDOR_ID && - dev_desc->idProduct == DLINK_PRODUCT_DWM_652 && - iface_desc->bInterfaceClass == 0x08) + /* Never bind to the CD-Rom emulation interface */ + if (iface_desc->bInterfaceClass == 0x08) return -ENODEV; - /* Bandrich modem and AT command interface is 0xff */ - if ((dev_desc->idVendor == BANDRICH_VENDOR_ID || - dev_desc->idVendor == PIRELLI_VENDOR_ID) && - iface_desc->bInterfaceClass != 0xff) - return -ENODEV; /* * Don't bind reserved interfaces (like network ones) which often have * the same class/subclass/protocol as the serial interfaces. Look at @@ -1369,9 +1358,9 @@ static int option_probe(struct usb_serial *serial, * Don't bind network interface on Samsung GT-B3730, it is handled by * a separate module. */ - if (dev_desc->idVendor == SAMSUNG_VENDOR_ID && - dev_desc->idProduct == SAMSUNG_PRODUCT_GT_B3730 && - iface_desc->bInterfaceClass != USB_CLASS_CDC_DATA) + if (dev_desc->idVendor == cpu_to_le16(SAMSUNG_VENDOR_ID) && + dev_desc->idProduct == cpu_to_le16(SAMSUNG_PRODUCT_GT_B3730) && + iface_desc->bInterfaceClass != USB_CLASS_CDC_DATA) return -ENODEV; /* Store device id so we can use it during attach. */ @@ -1509,5 +1498,4 @@ static int option_send_setup(struct usb_serial_port *port) MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_VERSION(DRIVER_VERSION); MODULE_LICENSE("GPL"); diff --git a/drivers/usb/serial/oti6858.c b/drivers/usb/serial/oti6858.c index cee9a52ca891..d217fd6ee43f 100644 --- a/drivers/usb/serial/oti6858.c +++ b/drivers/usb/serial/oti6858.c @@ -57,7 +57,6 @@ #define OTI6858_DESCRIPTION \ "Ours Technology Inc. OTi-6858 USB to serial adapter driver" #define OTI6858_AUTHOR "Tomasz Michal Lukaszewski <FIXME@FIXME>" -#define OTI6858_VERSION "0.2" static const struct usb_device_id id_table[] = { { USB_DEVICE(OTI6858_VENDOR_ID, OTI6858_PRODUCT_ID) }, @@ -899,5 +898,4 @@ module_usb_serial_driver(serial_drivers, id_table); MODULE_DESCRIPTION(OTI6858_DESCRIPTION); MODULE_AUTHOR(OTI6858_AUTHOR); -MODULE_VERSION(OTI6858_VERSION); MODULE_LICENSE("GPL"); diff --git a/drivers/usb/serial/quatech2.c b/drivers/usb/serial/quatech2.c index ffcfc962ab10..d152be97d041 100644 --- a/drivers/usb/serial/quatech2.c +++ b/drivers/usb/serial/quatech2.c @@ -65,8 +65,6 @@ #define QT2_WRITE_BUFFER_SIZE 512 /* size of write buffer */ #define QT2_WRITE_CONTROL_SIZE 5 /* control bytes used for a write */ -/* Version Information */ -#define DRIVER_VERSION "v0.1" #define DRIVER_DESC "Quatech 2nd gen USB to Serial Driver" #define USB_VENDOR_ID_QUATECH 0x061d diff --git a/drivers/usb/serial/siemens_mpi.c b/drivers/usb/serial/siemens_mpi.c index e4a1787cdbac..a76b1ae54a2a 100644 --- a/drivers/usb/serial/siemens_mpi.c +++ b/drivers/usb/serial/siemens_mpi.c @@ -16,8 +16,6 @@ #include <linux/usb.h> #include <linux/usb/serial.h> -/* Version Information */ -#define DRIVER_VERSION "Version 0.1 09/26/2005" #define DRIVER_AUTHOR "Thomas Hergenhahn@web.de http://libnodave.sf.net" #define DRIVER_DESC "Driver for Siemens USB/MPI adapter" diff --git a/drivers/usb/serial/sierra.c b/drivers/usb/serial/sierra.c index 270860f6bb2a..af06f2f5f38b 100644 --- a/drivers/usb/serial/sierra.c +++ b/drivers/usb/serial/sierra.c @@ -18,7 +18,7 @@ */ /* Uncomment to log function calls */ /* #define DEBUG */ -#define DRIVER_VERSION "v.1.7.16" + #define DRIVER_AUTHOR "Kevin Lloyd, Elina Pasheva, Matthew Safar, Rory Filer" #define DRIVER_DESC "USB Driver for Sierra Wireless USB modems" @@ -1078,7 +1078,6 @@ module_usb_serial_driver(serial_drivers, id_table); MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_VERSION(DRIVER_VERSION); MODULE_LICENSE("GPL"); module_param(nmea, bool, S_IRUGO | S_IWUSR); diff --git a/drivers/usb/serial/spcp8x5.c b/drivers/usb/serial/spcp8x5.c index 769c137f8975..a42536af1256 100644 --- a/drivers/usb/serial/spcp8x5.c +++ b/drivers/usb/serial/spcp8x5.c @@ -28,9 +28,6 @@ #include <linux/usb.h> #include <linux/usb/serial.h> - -/* Version Information */ -#define DRIVER_VERSION "v0.10" #define DRIVER_DESC "SPCP8x5 USB to serial adaptor driver" #define SPCP8x5_007_VID 0x04FC @@ -651,5 +648,4 @@ static struct usb_serial_driver * const serial_drivers[] = { module_usb_serial_driver(serial_drivers, id_table); MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_VERSION(DRIVER_VERSION); MODULE_LICENSE("GPL"); diff --git a/drivers/usb/serial/ssu100.c b/drivers/usb/serial/ssu100.c index 868d1e6852e2..4543ea350229 100644 --- a/drivers/usb/serial/ssu100.c +++ b/drivers/usb/serial/ssu100.c @@ -46,8 +46,6 @@ #define FULLPWRBIT 0x00000080 #define NEXT_BOARD_POWER_BIT 0x00000004 -/* Version Information */ -#define DRIVER_VERSION "v0.1" #define DRIVER_DESC "Quatech SSU-100 USB to Serial Driver" #define USB_VENDOR_ID_QUATECH 0x061d /* Quatech VID */ diff --git a/drivers/usb/serial/usb_wwan.c b/drivers/usb/serial/usb_wwan.c index 61a73ad1a187..2be2b5b639ae 100644 --- a/drivers/usb/serial/usb_wwan.c +++ b/drivers/usb/serial/usb_wwan.c @@ -19,7 +19,6 @@ - controlling the baud rate doesn't make sense */ -#define DRIVER_VERSION "v0.7.2" #define DRIVER_AUTHOR "Matthias Urlichs <smurf@smurf.noris.de>" #define DRIVER_DESC "USB Driver for GSM modems" @@ -710,5 +709,4 @@ EXPORT_SYMBOL(usb_wwan_resume); MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_VERSION(DRIVER_VERSION); MODULE_LICENSE("GPL"); diff --git a/drivers/usb/serial/vivopay-serial.c b/drivers/usb/serial/vivopay-serial.c index 0c0aa876c209..6299526ff8c3 100644 --- a/drivers/usb/serial/vivopay-serial.c +++ b/drivers/usb/serial/vivopay-serial.c @@ -10,8 +10,6 @@ #include <linux/usb.h> #include <linux/usb/serial.h> - -#define DRIVER_VERSION "v1.0" #define DRIVER_DESC "ViVOpay USB Serial Driver" #define VIVOPAY_VENDOR_ID 0x1d5f @@ -42,5 +40,4 @@ module_usb_serial_driver(serial_drivers, id_table); MODULE_AUTHOR("Forest Bond <forest.bond@outpostembedded.com>"); MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_VERSION(DRIVER_VERSION); MODULE_LICENSE("GPL"); diff --git a/drivers/usb/storage/realtek_cr.c b/drivers/usb/storage/realtek_cr.c index d36446dd7ae8..ea5f2586fbdd 100644 --- a/drivers/usb/storage/realtek_cr.c +++ b/drivers/usb/storage/realtek_cr.c @@ -455,7 +455,7 @@ static int rts51x_check_status(struct us_data *us, u8 lun) u8 buf[16]; retval = rts51x_read_status(us, lun, buf, 16, &(chip->status_len)); - if (retval < 0) + if (retval != STATUS_SUCCESS) return -EIO; US_DEBUGP("chip->status_len = %d\n", chip->status_len); diff --git a/drivers/usb/usb-skeleton.c b/drivers/usb/usb-skeleton.c index 0616f235bd6b..ce310170829f 100644 --- a/drivers/usb/usb-skeleton.c +++ b/drivers/usb/usb-skeleton.c @@ -105,20 +105,15 @@ static int skel_open(struct inode *inode, struct file *file) goto exit; } - /* increment our usage count for the device */ - kref_get(&dev->kref); - - /* lock the device to allow correctly handling errors - * in resumption */ - mutex_lock(&dev->io_mutex); - retval = usb_autopm_get_interface(interface); if (retval) - goto out_err; + goto exit; + + /* increment our usage count for the device */ + kref_get(&dev->kref); /* save our object in the file's private structure */ file->private_data = dev; - mutex_unlock(&dev->io_mutex); exit: return retval; diff --git a/drivers/usb/wusbcore/devconnect.c b/drivers/usb/wusbcore/devconnect.c index 231009af65a3..1d365316960c 100644 --- a/drivers/usb/wusbcore/devconnect.c +++ b/drivers/usb/wusbcore/devconnect.c @@ -847,19 +847,6 @@ static void wusb_dev_bos_rm(struct wusb_dev *wusb_dev) wusb_dev->wusb_cap_descr = NULL; }; -static struct usb_wireless_cap_descriptor wusb_cap_descr_default = { - .bLength = sizeof(wusb_cap_descr_default), - .bDescriptorType = USB_DT_DEVICE_CAPABILITY, - .bDevCapabilityType = USB_CAP_TYPE_WIRELESS_USB, - - .bmAttributes = USB_WIRELESS_BEACON_NONE, - .wPHYRates = cpu_to_le16(USB_WIRELESS_PHY_53), - .bmTFITXPowerInfo = 0, - .bmFFITXPowerInfo = 0, - .bmBandGroup = cpu_to_le16(0x0001), /* WUSB1.0[7.4.1] bottom */ - .bReserved = 0 -}; - /* * USB stack's device addition Notifier Callback * diff --git a/drivers/uwb/umc-bus.c b/drivers/uwb/umc-bus.c index 82a84d53120f..5c5b3fc9088a 100644 --- a/drivers/uwb/umc-bus.c +++ b/drivers/uwb/umc-bus.c @@ -63,7 +63,7 @@ int umc_controller_reset(struct umc_dev *umc) struct device *parent = umc->dev.parent; int ret = 0; - if (device_trylock(parent)) + if (!device_trylock(parent)) return -EAGAIN; ret = device_for_each_child(parent, parent, umc_bus_pre_reset_helper); if (ret >= 0) diff --git a/include/linux/usb.h b/include/linux/usb.h index 10278d18709c..689b14b26c8d 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h @@ -482,6 +482,7 @@ struct usb3_lpm_parameters { * @connect_time: time device was first connected * @do_remote_wakeup: remote wakeup should be enabled * @reset_resume: needs reset instead of resume + * @port_is_suspended: the upstream port is suspended (L2 or U3) * @wusb_dev: if this is a Wireless USB device, link to the WUSB * specific data for the device. * @slot_id: Slot ID assigned by xHCI @@ -560,6 +561,7 @@ struct usb_device { unsigned do_remote_wakeup:1; unsigned reset_resume:1; + unsigned port_is_suspended:1; #endif struct wusb_dev *wusb_dev; int slot_id; @@ -588,8 +590,9 @@ extern struct usb_device *usb_hub_find_child(struct usb_device *hdev, */ #define usb_hub_for_each_child(hdev, port1, child) \ for (port1 = 1, child = usb_hub_find_child(hdev, port1); \ - port1 <= hdev->maxchild; \ - child = usb_hub_find_child(hdev, ++port1)) + port1 <= hdev->maxchild; \ + child = usb_hub_find_child(hdev, ++port1)) \ + if (!child) continue; else /* USB device locking */ #define usb_lock_device(udev) device_lock(&(udev)->dev) @@ -805,6 +808,22 @@ static inline int usb_make_path(struct usb_device *dev, char *buf, size_t size) .bcdDevice_hi = (hi) /** + * USB_DEVICE_INTERFACE_CLASS - describe a usb device with a specific interface class + * @vend: the 16 bit USB Vendor ID + * @prod: the 16 bit USB Product ID + * @cl: bInterfaceClass value + * + * This macro is used to create a struct usb_device_id that matches a + * specific interface class of devices. + */ +#define USB_DEVICE_INTERFACE_CLASS(vend, prod, cl) \ + .match_flags = USB_DEVICE_ID_MATCH_DEVICE | \ + USB_DEVICE_ID_MATCH_INT_CLASS, \ + .idVendor = (vend), \ + .idProduct = (prod), \ + .bInterfaceClass = (cl) + +/** * USB_DEVICE_INTERFACE_PROTOCOL - describe a usb device with a specific interface protocol * @vend: the 16 bit USB Vendor ID * @prod: the 16 bit USB Product ID @@ -1129,8 +1148,8 @@ extern int usb_disabled(void); * Note: URB_DIR_IN/OUT is automatically set in usb_submit_urb(). */ #define URB_SHORT_NOT_OK 0x0001 /* report short reads as errors */ -#define URB_ISO_ASAP 0x0002 /* iso-only, urb->start_frame - * ignored */ +#define URB_ISO_ASAP 0x0002 /* iso-only; use the first unexpired + * slot in the schedule */ #define URB_NO_TRANSFER_DMA_MAP 0x0004 /* urb->transfer_dma valid on submit */ #define URB_NO_FSBR 0x0020 /* UHCI-specific */ #define URB_ZERO_PACKET 0x0040 /* Finish bulk OUT with short packet */ @@ -1309,15 +1328,20 @@ typedef void (*usb_complete_t)(struct urb *); * the transfer interval in the endpoint descriptor is logarithmic. * Device drivers must convert that value to linear units themselves.) * - * Isochronous URBs normally use the URB_ISO_ASAP transfer flag, telling - * the host controller to schedule the transfer as soon as bandwidth - * utilization allows, and then set start_frame to reflect the actual frame - * selected during submission. Otherwise drivers must specify the start_frame - * and handle the case where the transfer can't begin then. However, drivers - * won't know how bandwidth is currently allocated, and while they can - * find the current frame using usb_get_current_frame_number () they can't - * know the range for that frame number. (Ranges for frame counter values - * are HC-specific, and can go from 256 to 65536 frames from "now".) + * If an isochronous endpoint queue isn't already running, the host + * controller will schedule a new URB to start as soon as bandwidth + * utilization allows. If the queue is running then a new URB will be + * scheduled to start in the first transfer slot following the end of the + * preceding URB, if that slot has not already expired. If the slot has + * expired (which can happen when IRQ delivery is delayed for a long time), + * the scheduling behavior depends on the URB_ISO_ASAP flag. If the flag + * is clear then the URB will be scheduled to start in the expired slot, + * implying that some of its packets will not be transferred; if the flag + * is set then the URB will be scheduled in the first unexpired slot, + * breaking the queue's synchronization. Upon URB completion, the + * start_frame field will be set to the (micro)frame number in which the + * transfer was scheduled. Ranges for frame counter values are HC-specific + * and can go from as low as 256 to as high as 65536 frames. * * Isochronous URBs have a different data transfer model, in part because * the quality of service is only "best effort". Callers provide specially diff --git a/include/linux/usb/composite.h b/include/linux/usb/composite.h index f8dda0621800..b09c37e04a91 100644 --- a/include/linux/usb/composite.h +++ b/include/linux/usb/composite.h @@ -38,6 +38,7 @@ #include <linux/version.h> #include <linux/usb/ch9.h> #include <linux/usb/gadget.h> +#include <linux/log2.h> /* * USB function drivers should return USB_GADGET_DELAYED_STATUS if they @@ -51,6 +52,7 @@ /* big enough to hold our biggest descriptor */ #define USB_COMP_EP0_BUFSIZ 1024 +#define USB_MS_TO_HS_INTERVAL(x) (ilog2((x * 1000 / 125)) + 1) struct usb_configuration; /** @@ -117,7 +119,7 @@ struct usb_configuration; struct usb_function { const char *name; struct usb_gadget_strings **strings; - struct usb_descriptor_header **descriptors; + struct usb_descriptor_header **fs_descriptors; struct usb_descriptor_header **hs_descriptors; struct usb_descriptor_header **ss_descriptors; diff --git a/include/linux/usb/ehci_pdriver.h b/include/linux/usb/ehci_pdriver.h index c9d09f8b7ff2..99238b096f7e 100644 --- a/include/linux/usb/ehci_pdriver.h +++ b/include/linux/usb/ehci_pdriver.h @@ -29,6 +29,8 @@ * initialization. * @port_power_off: set to 1 if the controller needs to be powered down * after initialization. + * @no_io_watchdog: set to 1 if the controller does not need the I/O + * watchdog to run. * * These are general configuration options for the EHCI controller. All of * these options are activating more or less workarounds for some hardware. @@ -39,8 +41,7 @@ struct usb_ehci_pdata { unsigned has_synopsys_hc_bug:1; unsigned big_endian_desc:1; unsigned big_endian_mmio:1; - unsigned port_power_on:1; - unsigned port_power_off:1; + unsigned no_io_watchdog:1; /* Turn on all power and clocks */ int (*power_on)(struct platform_device *pdev); diff --git a/include/linux/usb/ezusb.h b/include/linux/usb/ezusb.h index fc618d8d1e92..639ee45779fb 100644 --- a/include/linux/usb/ezusb.h +++ b/include/linux/usb/ezusb.h @@ -1,16 +1,8 @@ #ifndef __EZUSB_H #define __EZUSB_H - -extern int ezusb_writememory(struct usb_device *dev, int address, - unsigned char *data, int length, __u8 bRequest); - extern int ezusb_fx1_set_reset(struct usb_device *dev, unsigned char reset_bit); -extern int ezusb_fx2_set_reset(struct usb_device *dev, unsigned char reset_bit); - extern int ezusb_fx1_ihex_firmware_download(struct usb_device *dev, const char *firmware_path); -extern int ezusb_fx2_ihex_firmware_download(struct usb_device *dev, - const char *firmware_path); #endif /* __EZUSB_H */ diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h index 5b6e50888248..0af6569b8cc6 100644 --- a/include/linux/usb/gadget.h +++ b/include/linux/usb/gadget.h @@ -939,6 +939,13 @@ static inline void usb_free_descriptors(struct usb_descriptor_header **v) kfree(v); } +struct usb_function; +int usb_assign_descriptors(struct usb_function *f, + struct usb_descriptor_header **fs, + struct usb_descriptor_header **hs, + struct usb_descriptor_header **ss); +void usb_free_all_descriptors(struct usb_function *f); + /*-------------------------------------------------------------------------*/ /* utility to simplify map/unmap of usb_requests to/from DMA */ diff --git a/include/linux/usb/ohci_pdriver.h b/include/linux/usb/ohci_pdriver.h index 74e7755168b7..012f2b7eb2b6 100644 --- a/include/linux/usb/ohci_pdriver.h +++ b/include/linux/usb/ohci_pdriver.h @@ -25,6 +25,7 @@ * @big_endian_desc: BE descriptors * @big_endian_mmio: BE registers * @no_big_frame_no: no big endian frame_no shift + * @num_ports: number of ports * * These are general configuration options for the OHCI controller. All of * these options are activating more or less workarounds for some hardware. @@ -33,6 +34,7 @@ struct usb_ohci_pdata { unsigned big_endian_desc:1; unsigned big_endian_mmio:1; unsigned no_big_frame_no:1; + unsigned int num_ports; /* Turn on all power and clocks */ int (*power_on)(struct platform_device *pdev); |