From 500fdf8becb9c8d51970c7ac6a4fa308a5481ebe Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Fri, 19 Aug 2011 18:10:57 +0300 Subject: usb: gadget: introduce gadget_is_dwc3() ... to check whether we're running on DesignWare USB3 DRD Controller. Signed-off-by: Felipe Balbi Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/gadget_chips.h | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/gadget_chips.h b/drivers/usb/gadget/gadget_chips.h index f3a83cd0ef50..a8855d0b7f3b 100644 --- a/drivers/usb/gadget/gadget_chips.h +++ b/drivers/usb/gadget/gadget_chips.h @@ -31,6 +31,7 @@ #define gadget_is_ci13xxx_msm(g) (!strcmp("ci13xxx_msm", (g)->name)) #define gadget_is_ci13xxx_pci(g) (!strcmp("ci13xxx_pci", (g)->name)) #define gadget_is_dummy(g) (!strcmp("dummy_udc", (g)->name)) +#define gadget_is_dwc3(g) (!strcmp("dwc3-gadget", (g)->name)) #define gadget_is_fsl_qe(g) (!strcmp("fsl_qe_udc", (g)->name)) #define gadget_is_fsl_usb2(g) (!strcmp("fsl-usb2-udc", (g)->name)) #define gadget_is_goku(g) (!strcmp("goku_udc", (g)->name)) @@ -115,6 +116,8 @@ static inline int usb_gadget_controller_number(struct usb_gadget *gadget) return 0x30; else if (gadget_is_net2272(gadget)) return 0x31; + else if (gadget_is_dwc3(gadget)) + return 0x32; return -ENOENT; } -- cgit From 72246da40f3719af3bfd104a2365b32537c27d83 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Fri, 19 Aug 2011 18:10:58 +0300 Subject: usb: Introduce DesignWare USB3 DRD Driver The DesignWare USB3 is a highly configurable IP Core which can be instantiated as Dual-Role Device (DRD), Peripheral Only and Host Only (XHCI) configurations. Several other parameters can be configured like amount of FIFO space, amount of TX and RX endpoints, amount of Host Interrupters, etc. The current driver has been validated with a virtual model of version 1.73a of that core and with an FPGA burned with version 1.83a of the DRD core. We have support for PCIe bus, which is used on FPGA prototyping, and for the OMAP5, more adaptation (or glue) layers can be easily added and the driver is half prepared to handle any possible configuration the HW engineer has chosen considering we have the information on one of the GHWPARAMS registers to do runtime checking of certain features. More runtime checks can, and should, be added in order to make this driver even more flexible with regards to number of endpoints, FIFO sizes, transfer types, etc. While this supports only the device side, for now, we will add support for Host side (xHCI - see the updated series Sebastian has sent [1]) and OTG after we have it all stabilized. [1] http://marc.info/?l=linux-usb&m=131341992020339&w=2 Signed-off-by: Felipe Balbi Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/Kconfig | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index 5a084b9cfa3c..bb799d5b9ab6 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -303,6 +303,18 @@ config USB_PXA_U2O PXA9xx Processor series include a high speed USB2.0 device controller, which support high speed and full speed USB peripheral. +config USB_GADGET_DWC3 + tristate "DesignWare USB3.0 (DRD) Controller" + depends on USB_DWC3 + select USB_GADGET_DUALSPEED + select USB_GADGET_SUPERSPEED + help + DesignWare USB3.0 controller is a SuperSpeed USB3.0 Controller + which can be configured for peripheral-only, host-only, hub-only + and Dual-Role operation. This Controller was first integrated into + the OMAP5 series of processors. More information about the OMAP5 + version of this controller, refer to http://www.ti.com/omap5. + # # Controllers available in both integrated and discrete versions # -- cgit From da4fc14c9955bbcafb9cdcc34f9772f3e9481bb8 Mon Sep 17 00:00:00 2001 From: Heiko Stübner Date: Sun, 21 Aug 2011 14:31:17 +0200 Subject: s3c-hsudc: Fix possible nullpointer dereference during probe The usb-interrupt is requested before the endpoints are initalised. If an interrupt happens in the time between request_irq and the init of the endpoint-data (as seen on the Qisda ESx00 ebook-platforms), it is therefore possible for the interrupt handler to access endpoint- data before its creation resulting in a null-pointer dereference. This patch simply moves the irq request below the endpoint init. Signed-off-by: Heiko Stuebner Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/s3c-hsudc.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/s3c-hsudc.c b/drivers/usb/gadget/s3c-hsudc.c index 3fa717c5f4bc..00056c27a1c8 100644 --- a/drivers/usb/gadget/s3c-hsudc.c +++ b/drivers/usb/gadget/s3c-hsudc.c @@ -1269,19 +1269,6 @@ static int s3c_hsudc_probe(struct platform_device *pdev) goto err_remap; } - ret = platform_get_irq(pdev, 0); - if (ret < 0) { - dev_err(dev, "unable to obtain IRQ number\n"); - goto err_irq; - } - hsudc->irq = ret; - - ret = request_irq(hsudc->irq, s3c_hsudc_irq, 0, driver_name, hsudc); - if (ret < 0) { - dev_err(dev, "irq request failed\n"); - goto err_irq; - } - spin_lock_init(&hsudc->lock); device_initialize(&hsudc->gadget.dev); @@ -1299,6 +1286,19 @@ static int s3c_hsudc_probe(struct platform_device *pdev) s3c_hsudc_setup_ep(hsudc); + ret = platform_get_irq(pdev, 0); + if (ret < 0) { + dev_err(dev, "unable to obtain IRQ number\n"); + goto err_irq; + } + hsudc->irq = ret; + + ret = request_irq(hsudc->irq, s3c_hsudc_irq, 0, driver_name, hsudc); + if (ret < 0) { + dev_err(dev, "irq request failed\n"); + goto err_irq; + } + hsudc->uclk = clk_get(&pdev->dev, "usb-device"); if (IS_ERR(hsudc->uclk)) { dev_err(dev, "failed to find usb-device clock source\n"); -- cgit From 938fbe54f33e97c2911d0665ec613d7f0c967d9a Mon Sep 17 00:00:00 2001 From: Heiko Stübner Date: Sun, 21 Aug 2011 14:32:14 +0200 Subject: s3c-hsudc: Add basic otg transceiver handling Makes it possible to use i.e. gpio-vbus to handle vbus events. Signed-off-by: Heiko Stuebner Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/s3c-hsudc.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/s3c-hsudc.c b/drivers/usb/gadget/s3c-hsudc.c index 00056c27a1c8..3e96cc5bb77f 100644 --- a/drivers/usb/gadget/s3c-hsudc.c +++ b/drivers/usb/gadget/s3c-hsudc.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include @@ -137,6 +138,7 @@ struct s3c_hsudc { struct usb_gadget_driver *driver; struct device *dev; struct s3c24xx_hsudc_platdata *pd; + struct otg_transceiver *transceiver; spinlock_t lock; void __iomem *regs; struct resource *mem_rsrc; @@ -1171,6 +1173,22 @@ static int s3c_hsudc_start(struct usb_gadget_driver *driver, return ret; } + /* connect to bus through transceiver */ + if (hsudc->transceiver) { + ret = otg_set_peripheral(hsudc->transceiver, &hsudc->gadget); + if (ret) { + dev_err(hsudc->dev, "%s: can't bind to transceiver\n", + hsudc->gadget.name); + driver->unbind(&hsudc->gadget); + + device_del(&hsudc->gadget.dev); + + hsudc->driver = NULL; + hsudc->gadget.dev.driver = NULL; + return ret; + } + } + enable_irq(hsudc->irq); dev_info(hsudc->dev, "bound driver %s\n", driver->driver.name); @@ -1201,6 +1219,9 @@ static int s3c_hsudc_stop(struct usb_gadget_driver *driver) s3c_hsudc_stop_activity(hsudc, driver); spin_unlock_irqrestore(&hsudc->lock, flags); + if (hsudc->transceiver) + (void) otg_set_peripheral(hsudc->transceiver, NULL); + driver->unbind(&hsudc->gadget); device_del(&hsudc->gadget.dev); disable_irq(hsudc->irq); @@ -1247,6 +1268,8 @@ static int s3c_hsudc_probe(struct platform_device *pdev) hsudc->dev = dev; hsudc->pd = pdev->dev.platform_data; + hsudc->transceiver = otg_get_transceiver(); + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) { dev_err(dev, "unable to obtain driver resource data\n"); -- cgit From 29cc88979a8818cd8c5019426e945aed118b400e Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 23 Aug 2011 03:12:03 -0700 Subject: USB: use usb_endpoint_maxp() instead of le16_to_cpu() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Now ${LINUX}/drivers/usb/* can use usb_endpoint_maxp(desc) to get maximum packet size instead of le16_to_cpu(desc->wMaxPacketSize). This patch fix it up Cc: Armin Fuerst Cc: Pavel Machek Cc: Johannes Erdfelt Cc: Vojtech Pavlik Cc: Oliver Neukum Cc: David Kubicek Cc: Johan Hovold Cc: Brad Hards Acked-by: Felipe Balbi Cc: Sebastian Andrzej Siewior Cc: Thomas Dahlmann Cc: David Brownell Cc: David Lopo Cc: Alan Stern Cc: Michal Nazarewicz Cc: Xie Xiaobo Cc: Li Yang Cc: Jiang Bo Cc: Yuan-hsin Chen Cc: Darius Augulis Cc: Xiaochen Shen Cc: Yoshihiro Shimoda Cc: OKI SEMICONDUCTOR, Cc: Robert Jarzmik Cc: Ben Dooks Cc: Thomas Abraham Cc: Herbert Pötzl Cc: Arnaud Patard Cc: Roman Weissgaerber Acked-by: Sarah Sharp Cc: Tony Olech Cc: Florian Floe Echtler Cc: Christian Lucht Cc: Juergen Stuber Cc: Georges Toth Cc: Bill Ryder Cc: Kuba Ober Cc: Inaky Perez-Gonzalez Signed-off-by: Kuninori Morimoto Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/amd5536udc.c | 2 +- drivers/usb/gadget/at91_udc.c | 2 +- drivers/usb/gadget/atmel_usba_udc.c | 4 ++-- drivers/usb/gadget/ci13xxx_udc.c | 2 +- drivers/usb/gadget/composite.c | 2 +- drivers/usb/gadget/dummy_hcd.c | 4 ++-- drivers/usb/gadget/epautoconf.c | 2 +- drivers/usb/gadget/f_mass_storage.c | 3 +-- drivers/usb/gadget/file_storage.c | 2 +- drivers/usb/gadget/fsl_qe_udc.c | 2 +- drivers/usb/gadget/fsl_udc_core.c | 2 +- drivers/usb/gadget/fusb300_udc.c | 2 +- drivers/usb/gadget/imx_udc.c | 2 +- drivers/usb/gadget/langwell_udc.c | 2 +- drivers/usb/gadget/m66592-udc.c | 4 ++-- drivers/usb/gadget/mv_udc_core.c | 2 +- drivers/usb/gadget/net2272.c | 2 +- drivers/usb/gadget/net2280.c | 4 ++-- drivers/usb/gadget/omap_udc.c | 7 +++---- drivers/usb/gadget/pch_udc.c | 6 +++--- drivers/usb/gadget/pxa25x_udc.c | 14 ++++++-------- drivers/usb/gadget/pxa27x_udc.c | 2 +- drivers/usb/gadget/r8a66597-udc.c | 4 ++-- drivers/usb/gadget/s3c-hsotg.c | 2 +- drivers/usb/gadget/s3c-hsudc.c | 6 +++--- drivers/usb/gadget/s3c2410_udc.c | 2 +- 26 files changed, 42 insertions(+), 46 deletions(-) (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/amd5536udc.c b/drivers/usb/gadget/amd5536udc.c index 70f2b376c86d..d65d8392be75 100644 --- a/drivers/usb/gadget/amd5536udc.c +++ b/drivers/usb/gadget/amd5536udc.c @@ -354,7 +354,7 @@ udc_ep_enable(struct usb_ep *usbep, const struct usb_endpoint_descriptor *desc) writel(tmp, &dev->ep[ep->num].regs->ctl); /* set max packet size */ - maxpacket = le16_to_cpu(desc->wMaxPacketSize); + maxpacket = usb_endpoint_maxp(desc); tmp = readl(&dev->ep[ep->num].regs->bufout_maxpkt); tmp = AMD_ADDBITS(tmp, maxpacket, UDC_EP_MAX_PKT_SIZE); ep->ep.maxpacket = maxpacket; diff --git a/drivers/usb/gadget/at91_udc.c b/drivers/usb/gadget/at91_udc.c index ddb118a76807..d01fa5badd66 100644 --- a/drivers/usb/gadget/at91_udc.c +++ b/drivers/usb/gadget/at91_udc.c @@ -487,7 +487,7 @@ static int at91_ep_enable(struct usb_ep *_ep, || !desc || ep->desc || _ep->name == ep0name || desc->bDescriptorType != USB_DT_ENDPOINT - || (maxpacket = le16_to_cpu(desc->wMaxPacketSize)) == 0 + || (maxpacket = usb_endpoint_maxp(desc)) == 0 || maxpacket > ep->maxpacket) { DBG("bad ep or descriptor\n"); return -EINVAL; diff --git a/drivers/usb/gadget/atmel_usba_udc.c b/drivers/usb/gadget/atmel_usba_udc.c index 5b1665eb1bef..722c468e9b3c 100644 --- a/drivers/usb/gadget/atmel_usba_udc.c +++ b/drivers/usb/gadget/atmel_usba_udc.c @@ -527,7 +527,7 @@ usba_ep_enable(struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc) DBG(DBG_GADGET, "%s: ep_enable: desc=%p\n", ep->ep.name, desc); - maxpacket = le16_to_cpu(desc->wMaxPacketSize) & 0x7ff; + maxpacket = usb_endpoint_maxp(desc) & 0x7ff; if (((desc->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK) != ep->index) || ep->index == 0 @@ -571,7 +571,7 @@ usba_ep_enable(struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc) * Bits 11:12 specify number of _additional_ * transactions per microframe. */ - nr_trans = ((le16_to_cpu(desc->wMaxPacketSize) >> 11) & 3) + 1; + nr_trans = ((usb_endpoint_maxp(desc) >> 11) & 3) + 1; if (nr_trans > 3) return -EINVAL; diff --git a/drivers/usb/gadget/ci13xxx_udc.c b/drivers/usb/gadget/ci13xxx_udc.c index 1265a8502ea0..83428f56253b 100644 --- a/drivers/usb/gadget/ci13xxx_udc.c +++ b/drivers/usb/gadget/ci13xxx_udc.c @@ -2101,7 +2101,7 @@ static int ep_enable(struct usb_ep *ep, mEp->num = usb_endpoint_num(desc); mEp->type = usb_endpoint_type(desc); - mEp->ep.maxpacket = __constant_le16_to_cpu(desc->wMaxPacketSize); + mEp->ep.maxpacket = usb_endpoint_maxp(desc); dbg_event(_usb_addr(mEp), "ENABLE", 0); diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c index aef47414f5d5..8065464523b1 100644 --- a/drivers/usb/gadget/composite.c +++ b/drivers/usb/gadget/composite.c @@ -164,7 +164,7 @@ int config_ep_by_speed(struct usb_gadget *g, ep_found: /* commit results */ - _ep->maxpacket = le16_to_cpu(chosen_desc->wMaxPacketSize); + _ep->maxpacket = usb_endpoint_maxp(chosen_desc); _ep->desc = chosen_desc; _ep->comp_desc = NULL; _ep->maxburst = 0; diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c index e755a9d267fc..7b06d39d6203 100644 --- a/drivers/usb/gadget/dummy_hcd.c +++ b/drivers/usb/gadget/dummy_hcd.c @@ -439,7 +439,7 @@ dummy_enable (struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc) * maximum packet size. * For SS devices the wMaxPacketSize is limited by 1024. */ - max = le16_to_cpu(desc->wMaxPacketSize) & 0x7ff; + max = usb_endpoint_maxp(desc) & 0x7ff; /* drivers must not request bad settings, since lower levels * (hardware or its drivers) may not check. some endpoints @@ -1277,7 +1277,7 @@ static int periodic_bytes (struct dummy *dum, struct dummy_ep *ep) int tmp; /* high bandwidth mode */ - tmp = le16_to_cpu(ep->desc->wMaxPacketSize); + tmp = usb_endpoint_maxp(ep->desc); tmp = (tmp >> 11) & 0x03; tmp *= 8 /* applies to entire frame */; limit += limit * tmp; diff --git a/drivers/usb/gadget/epautoconf.c b/drivers/usb/gadget/epautoconf.c index 7a7e6b7e1fd6..cdca7ebb7b48 100644 --- a/drivers/usb/gadget/epautoconf.c +++ b/drivers/usb/gadget/epautoconf.c @@ -158,7 +158,7 @@ ep_matches ( * where it's an output parameter representing the full speed limit. * the usb spec fixes high speed bulk maxpacket at 512 bytes. */ - max = 0x7ff & le16_to_cpu(desc->wMaxPacketSize); + max = 0x7ff & usb_endpoint_maxp(desc); switch (type) { case USB_ENDPOINT_XFER_INT: /* INT: limit 64 bytes full speed, 1024 high/super speed */ diff --git a/drivers/usb/gadget/f_mass_storage.c b/drivers/usb/gadget/f_mass_storage.c index 5b9339582007..4ce3decda1db 100644 --- a/drivers/usb/gadget/f_mass_storage.c +++ b/drivers/usb/gadget/f_mass_storage.c @@ -2401,8 +2401,7 @@ reset: goto reset; fsg->bulk_out->driver_data = common; fsg->bulk_out_enabled = 1; - common->bulk_out_maxpacket = - le16_to_cpu(fsg->bulk_out->desc->wMaxPacketSize); + common->bulk_out_maxpacket = usb_endpoint_maxp(fsg->bulk_out->desc); clear_bit(IGNORE_BULK_OUT, &fsg->atomic_bitflags); /* Allocate the requests */ diff --git a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c index 639e14a2fd15..39ece40a045f 100644 --- a/drivers/usb/gadget/file_storage.c +++ b/drivers/usb/gadget/file_storage.c @@ -2801,7 +2801,7 @@ reset: if ((rc = enable_endpoint(fsg, fsg->bulk_out, d)) != 0) goto reset; fsg->bulk_out_enabled = 1; - fsg->bulk_out_maxpacket = le16_to_cpu(d->wMaxPacketSize); + fsg->bulk_out_maxpacket = usb_endpoint_maxp(d); clear_bit(IGNORE_BULK_OUT, &fsg->atomic_bitflags); if (transport_is_cbi()) { diff --git a/drivers/usb/gadget/fsl_qe_udc.c b/drivers/usb/gadget/fsl_qe_udc.c index 3bf872e1ad39..2a03e4de11c1 100644 --- a/drivers/usb/gadget/fsl_qe_udc.c +++ b/drivers/usb/gadget/fsl_qe_udc.c @@ -540,7 +540,7 @@ static int qe_ep_init(struct qe_udc *udc, int reval = 0; u16 max = 0; - max = le16_to_cpu(desc->wMaxPacketSize); + max = usb_endpoint_maxp(desc); /* check the max package size validate for this endpoint */ /* Refer to USB2.0 spec table 9-13, diff --git a/drivers/usb/gadget/fsl_udc_core.c b/drivers/usb/gadget/fsl_udc_core.c index de24a4233c25..d6993507165b 100644 --- a/drivers/usb/gadget/fsl_udc_core.c +++ b/drivers/usb/gadget/fsl_udc_core.c @@ -559,7 +559,7 @@ static int fsl_ep_enable(struct usb_ep *_ep, if (!udc->driver || (udc->gadget.speed == USB_SPEED_UNKNOWN)) return -ESHUTDOWN; - max = le16_to_cpu(desc->wMaxPacketSize); + max = usb_endpoint_maxp(desc); /* Disable automatic zlp generation. Driver is responsible to indicate * explicitly through req->req.zero. This is needed to enable multi-td diff --git a/drivers/usb/gadget/fusb300_udc.c b/drivers/usb/gadget/fusb300_udc.c index 4ec888f90002..d9ee6c37a6c1 100644 --- a/drivers/usb/gadget/fusb300_udc.c +++ b/drivers/usb/gadget/fusb300_udc.c @@ -220,7 +220,7 @@ static int config_ep(struct fusb300_ep *ep, info.type = desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK; info.dir_in = (desc->bEndpointAddress & USB_ENDPOINT_DIR_MASK) ? 1 : 0; - info.maxpacket = le16_to_cpu(desc->wMaxPacketSize); + info.maxpacket = usb_endpoint_maxp(desc); info.epnum = desc->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK; if ((info.type == USB_ENDPOINT_XFER_INT) || diff --git a/drivers/usb/gadget/imx_udc.c b/drivers/usb/gadget/imx_udc.c index 692fd9b2248b..bf08bfcd90b8 100644 --- a/drivers/usb/gadget/imx_udc.c +++ b/drivers/usb/gadget/imx_udc.c @@ -689,7 +689,7 @@ static int imx_ep_enable(struct usb_ep *usb_ep, return -EINVAL; } - if (imx_ep->fifosize < le16_to_cpu(desc->wMaxPacketSize)) { + if (imx_ep->fifosize < usb_endpoint_maxp(desc)) { D_ERR(imx_usb->dev, "<%s> bad %s maxpacket\n", __func__, usb_ep->name); return -ERANGE; diff --git a/drivers/usb/gadget/langwell_udc.c b/drivers/usb/gadget/langwell_udc.c index a06e2c27b435..5bf9942eb454 100644 --- a/drivers/usb/gadget/langwell_udc.c +++ b/drivers/usb/gadget/langwell_udc.c @@ -283,7 +283,7 @@ static int langwell_ep_enable(struct usb_ep *_ep, if (!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN) return -ESHUTDOWN; - max = le16_to_cpu(desc->wMaxPacketSize); + max = usb_endpoint_maxp(desc); /* * disable HW zero length termination select diff --git a/drivers/usb/gadget/m66592-udc.c b/drivers/usb/gadget/m66592-udc.c index 491f825ed5c9..5e597c3c44f3 100644 --- a/drivers/usb/gadget/m66592-udc.c +++ b/drivers/usb/gadget/m66592-udc.c @@ -370,7 +370,7 @@ static void m66592_ep_setting(struct m66592 *m66592, struct m66592_ep *ep, ep->pipectr = get_pipectr_addr(pipenum); ep->pipenum = pipenum; - ep->ep.maxpacket = le16_to_cpu(desc->wMaxPacketSize); + ep->ep.maxpacket = usb_endpoint_maxp(desc); m66592->pipenum2ep[pipenum] = ep; m66592->epaddr2ep[desc->bEndpointAddress&USB_ENDPOINT_NUMBER_MASK] = ep; INIT_LIST_HEAD(&ep->queue); @@ -447,7 +447,7 @@ static int alloc_pipe_config(struct m66592_ep *ep, ep->type = info.type; info.epnum = desc->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK; - info.maxpacket = le16_to_cpu(desc->wMaxPacketSize); + info.maxpacket = usb_endpoint_maxp(desc); info.interval = desc->bInterval; if (desc->bEndpointAddress & USB_ENDPOINT_DIR_MASK) info.dir_in = 1; diff --git a/drivers/usb/gadget/mv_udc_core.c b/drivers/usb/gadget/mv_udc_core.c index ce1ac2bcb314..263dec40af32 100644 --- a/drivers/usb/gadget/mv_udc_core.c +++ b/drivers/usb/gadget/mv_udc_core.c @@ -493,7 +493,7 @@ static int mv_ep_enable(struct usb_ep *_ep, return -ESHUTDOWN; direction = ep_dir(ep); - max = le16_to_cpu(desc->wMaxPacketSize); + max = usb_endpoint_maxp(desc); /* * disable HW zero length termination select diff --git a/drivers/usb/gadget/net2272.c b/drivers/usb/gadget/net2272.c index ab98ea926a11..6fef1c02448e 100644 --- a/drivers/usb/gadget/net2272.c +++ b/drivers/usb/gadget/net2272.c @@ -204,7 +204,7 @@ net2272_enable(struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc) if (!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN) return -ESHUTDOWN; - max = le16_to_cpu(desc->wMaxPacketSize) & 0x1fff; + max = usb_endpoint_maxp(desc) & 0x1fff; spin_lock_irqsave(&dev->lock, flags); _ep->maxpacket = max & 0x7fff; diff --git a/drivers/usb/gadget/net2280.c b/drivers/usb/gadget/net2280.c index 3dd40b4e675c..8d3673fadfe1 100644 --- a/drivers/usb/gadget/net2280.c +++ b/drivers/usb/gadget/net2280.c @@ -169,7 +169,7 @@ net2280_enable (struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc) return -EDOM; /* sanity check ep-e/ep-f since their fifos are small */ - max = le16_to_cpu (desc->wMaxPacketSize) & 0x1fff; + max = usb_endpoint_maxp (desc) & 0x1fff; if (ep->num > 4 && max > 64) return -ERANGE; @@ -1640,7 +1640,7 @@ show_queues (struct device *_dev, struct device_attribute *attr, char *buf) default: val = "iso"; break; }; val; }), - le16_to_cpu (d->wMaxPacketSize) & 0x1fff, + usb_endpoint_maxp (d) & 0x1fff, ep->dma ? "dma" : "pio", ep->fifo_size ); } else /* ep0 should only have one transfer queued */ diff --git a/drivers/usb/gadget/omap_udc.c b/drivers/usb/gadget/omap_udc.c index 740c7daed279..b7a7799ddd4f 100644 --- a/drivers/usb/gadget/omap_udc.c +++ b/drivers/usb/gadget/omap_udc.c @@ -166,15 +166,14 @@ static int omap_ep_enable(struct usb_ep *_ep, if (!_ep || !desc || ep->desc || desc->bDescriptorType != USB_DT_ENDPOINT || ep->bEndpointAddress != desc->bEndpointAddress - || ep->maxpacket < le16_to_cpu - (desc->wMaxPacketSize)) { + || ep->maxpacket < usb_endpoint_maxp(desc)) { DBG("%s, bad ep or descriptor\n", __func__); return -EINVAL; } - maxp = le16_to_cpu (desc->wMaxPacketSize); + maxp = usb_endpoint_maxp(desc); if ((desc->bmAttributes == USB_ENDPOINT_XFER_BULK && maxp != ep->maxpacket) - || le16_to_cpu(desc->wMaxPacketSize) > ep->maxpacket + || usb_endpoint_maxp(desc) > ep->maxpacket || !desc->wMaxPacketSize) { DBG("%s, bad %s maxpacket\n", __func__, _ep->name); return -ERANGE; diff --git a/drivers/usb/gadget/pch_udc.c b/drivers/usb/gadget/pch_udc.c index f96615ab6b77..b69ae3eec687 100644 --- a/drivers/usb/gadget/pch_udc.c +++ b/drivers/usb/gadget/pch_udc.c @@ -947,7 +947,7 @@ static void pch_udc_ep_enable(struct pch_udc_ep *ep, else buff_size = UDC_EPOUT_BUFF_SIZE; pch_udc_ep_set_bufsz(ep, buff_size, ep->in); - pch_udc_ep_set_maxpkt(ep, le16_to_cpu(desc->wMaxPacketSize)); + pch_udc_ep_set_maxpkt(ep, usb_endpoint_maxp(desc)); pch_udc_ep_set_nak(ep); pch_udc_ep_fifo_flush(ep, ep->in); /* Configure the endpoint */ @@ -957,7 +957,7 @@ static void pch_udc_ep_enable(struct pch_udc_ep *ep, (cfg->cur_cfg << UDC_CSR_NE_CFG_SHIFT) | (cfg->cur_intf << UDC_CSR_NE_INTF_SHIFT) | (cfg->cur_alt << UDC_CSR_NE_ALT_SHIFT) | - le16_to_cpu(desc->wMaxPacketSize) << UDC_CSR_NE_MAX_PKT_SHIFT; + usb_endpoint_maxp(desc) << UDC_CSR_NE_MAX_PKT_SHIFT; if (ep->in) pch_udc_write_csr(ep->dev, val, UDC_EPIN_IDX(ep->num)); @@ -1466,7 +1466,7 @@ static int pch_udc_pcd_ep_enable(struct usb_ep *usbep, ep->desc = desc; ep->halted = 0; pch_udc_ep_enable(ep, &ep->dev->cfg_data, desc); - ep->ep.maxpacket = le16_to_cpu(desc->wMaxPacketSize); + ep->ep.maxpacket = usb_endpoint_maxp(desc); pch_udc_enable_ep_interrupts(ep->dev, PCH_UDC_EPINT(ep->in, ep->num)); spin_unlock_irqrestore(&dev->lock, iflags); return 0; diff --git a/drivers/usb/gadget/pxa25x_udc.c b/drivers/usb/gadget/pxa25x_udc.c index e4e59b4de25d..7862465291d1 100644 --- a/drivers/usb/gadget/pxa25x_udc.c +++ b/drivers/usb/gadget/pxa25x_udc.c @@ -232,8 +232,7 @@ static int pxa25x_ep_enable (struct usb_ep *_ep, if (!_ep || !desc || ep->desc || _ep->name == ep0name || desc->bDescriptorType != USB_DT_ENDPOINT || ep->bEndpointAddress != desc->bEndpointAddress - || ep->fifo_size < le16_to_cpu - (desc->wMaxPacketSize)) { + || ep->fifo_size < usb_endpoint_maxp (desc)) { DMSG("%s, bad ep or descriptor\n", __func__); return -EINVAL; } @@ -248,7 +247,7 @@ static int pxa25x_ep_enable (struct usb_ep *_ep, /* hardware _could_ do smaller, but driver doesn't */ if ((desc->bmAttributes == USB_ENDPOINT_XFER_BULK - && le16_to_cpu (desc->wMaxPacketSize) + && usb_endpoint_maxp (desc) != BULK_FIFO_SIZE) || !desc->wMaxPacketSize) { DMSG("%s, bad %s maxpacket\n", __func__, _ep->name); @@ -264,7 +263,7 @@ static int pxa25x_ep_enable (struct usb_ep *_ep, ep->desc = desc; ep->stopped = 0; ep->pio_irqs = 0; - ep->ep.maxpacket = le16_to_cpu (desc->wMaxPacketSize); + ep->ep.maxpacket = usb_endpoint_maxp (desc); /* flush fifo (mostly for OUT buffers) */ pxa25x_ep_fifo_flush (_ep); @@ -401,7 +400,7 @@ write_fifo (struct pxa25x_ep *ep, struct pxa25x_request *req) { unsigned max; - max = le16_to_cpu(ep->desc->wMaxPacketSize); + max = usb_endpoint_maxp(ep->desc); do { unsigned count; int is_last, is_short; @@ -671,8 +670,7 @@ pxa25x_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags) * we can report per-packet status. that also helps with dma. */ if (unlikely (ep->bmAttributes == USB_ENDPOINT_XFER_ISOC - && req->req.length > le16_to_cpu - (ep->desc->wMaxPacketSize))) + && req->req.length > usb_endpoint_maxp (ep->desc))) return -EMSGSIZE; DBG(DBG_NOISY, "%s queue req %p, len %d buf %p\n", @@ -1105,7 +1103,7 @@ udc_seq_show(struct seq_file *m, void *_d) tmp = *dev->ep [i].reg_udccs; seq_printf(m, "%s max %d %s udccs %02x irqs %lu\n", - ep->ep.name, le16_to_cpu(desc->wMaxPacketSize), + ep->ep.name, usb_endpoint_maxp(desc), "pio", tmp, ep->pio_irqs); /* TODO translate all five groups of udccs bits! */ diff --git a/drivers/usb/gadget/pxa27x_udc.c b/drivers/usb/gadget/pxa27x_udc.c index 85b68c75dc9d..d21455f457e2 100644 --- a/drivers/usb/gadget/pxa27x_udc.c +++ b/drivers/usb/gadget/pxa27x_udc.c @@ -1439,7 +1439,7 @@ static int pxa_ep_enable(struct usb_ep *_ep, return -EINVAL; } - if (ep->fifo_size < le16_to_cpu(desc->wMaxPacketSize)) { + if (ep->fifo_size < usb_endpoint_maxp(desc)) { ep_err(ep, "bad maxpacket\n"); return -ERANGE; } diff --git a/drivers/usb/gadget/r8a66597-udc.c b/drivers/usb/gadget/r8a66597-udc.c index 50991e5bd5e8..61d0c65802e8 100644 --- a/drivers/usb/gadget/r8a66597-udc.c +++ b/drivers/usb/gadget/r8a66597-udc.c @@ -341,7 +341,7 @@ static void r8a66597_ep_setting(struct r8a66597 *r8a66597, ep->pipectr = get_pipectr_addr(pipenum); ep->pipenum = pipenum; - ep->ep.maxpacket = le16_to_cpu(desc->wMaxPacketSize); + ep->ep.maxpacket = usb_endpoint_maxp(desc); r8a66597->pipenum2ep[pipenum] = ep; r8a66597->epaddr2ep[desc->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK] = ep; @@ -420,7 +420,7 @@ static int alloc_pipe_config(struct r8a66597_ep *ep, ep->type = info.type; info.epnum = desc->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK; - info.maxpacket = le16_to_cpu(desc->wMaxPacketSize); + info.maxpacket = usb_endpoint_maxp(desc); info.interval = desc->bInterval; if (desc->bEndpointAddress & USB_ENDPOINT_DIR_MASK) info.dir_in = 1; diff --git a/drivers/usb/gadget/s3c-hsotg.c b/drivers/usb/gadget/s3c-hsotg.c index 8bdee67ce09a..39b134dec94c 100644 --- a/drivers/usb/gadget/s3c-hsotg.c +++ b/drivers/usb/gadget/s3c-hsotg.c @@ -2297,7 +2297,7 @@ static int s3c_hsotg_ep_enable(struct usb_ep *ep, return -EINVAL; } - mps = le16_to_cpu(desc->wMaxPacketSize); + mps = usb_endpoint_maxp(desc); /* note, we handle this here instead of s3c_hsotg_set_ep_maxpacket */ diff --git a/drivers/usb/gadget/s3c-hsudc.c b/drivers/usb/gadget/s3c-hsudc.c index 3e96cc5bb77f..25829b4398da 100644 --- a/drivers/usb/gadget/s3c-hsudc.c +++ b/drivers/usb/gadget/s3c-hsudc.c @@ -761,11 +761,11 @@ static int s3c_hsudc_ep_enable(struct usb_ep *_ep, if (!_ep || !desc || hsep->desc || _ep->name == ep0name || desc->bDescriptorType != USB_DT_ENDPOINT || hsep->bEndpointAddress != desc->bEndpointAddress - || ep_maxpacket(hsep) < le16_to_cpu(desc->wMaxPacketSize)) + || ep_maxpacket(hsep) < usb_endpoint_maxp(desc)) return -EINVAL; if ((desc->bmAttributes == USB_ENDPOINT_XFER_BULK - && le16_to_cpu(desc->wMaxPacketSize) != ep_maxpacket(hsep)) + && usb_endpoint_maxp(desc) != ep_maxpacket(hsep)) || !desc->wMaxPacketSize) return -ERANGE; @@ -781,7 +781,7 @@ static int s3c_hsudc_ep_enable(struct usb_ep *_ep, hsep->stopped = hsep->wedge = 0; hsep->desc = desc; - hsep->ep.maxpacket = le16_to_cpu(desc->wMaxPacketSize); + hsep->ep.maxpacket = usb_endpoint_maxp(desc); s3c_hsudc_set_halt(_ep, 0); __set_bit(ep_index(hsep), hsudc->regs + S3C_EIER); diff --git a/drivers/usb/gadget/s3c2410_udc.c b/drivers/usb/gadget/s3c2410_udc.c index 8d31848aab09..257285448678 100644 --- a/drivers/usb/gadget/s3c2410_udc.c +++ b/drivers/usb/gadget/s3c2410_udc.c @@ -1082,7 +1082,7 @@ static int s3c2410_udc_ep_enable(struct usb_ep *_ep, if (!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN) return -ESHUTDOWN; - max = le16_to_cpu(desc->wMaxPacketSize) & 0x1fff; + max = usb_endpoint_maxp(desc) & 0x1fff; local_irq_save (flags); _ep->maxpacket = max & 0x7ff; -- cgit From 2e5a08a3693e4c5bd251afc13246bc86fc9fafc3 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Wed, 24 Aug 2011 08:41:11 +0200 Subject: USB gadget i.MX1: remove dependency on ARCH_MXC The ARCH_MX1 scheduled for removal. Instead, depend on ARCH_MXC and make clear in the Kconfig text that only i.MX1 has this hardware. Signed-off-by: Sascha Hauer Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/Kconfig | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index bb799d5b9ab6..fe5637983892 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -255,12 +255,11 @@ config USB_S3C_HSOTG integrated into the S3C64XX series SoC. config USB_IMX - tristate "Freescale IMX USB Peripheral Controller" - depends on ARCH_MX1 + tristate "Freescale i.MX1 USB Peripheral Controller" + depends on ARCH_MXC help - Freescale's IMX series include an integrated full speed - USB 1.1 device controller. The controller in the IMX series - is register-compatible. + Freescale's i.MX1 includes an integrated full speed + USB 1.1 device controller. It has Six fixed-function endpoints, as well as endpoint zero (for control transfers). -- cgit From 3f565a363cee14d2ed281823196d455bfc7c4170 Mon Sep 17 00:00:00 2001 From: Peiyu Li Date: Wed, 17 Aug 2011 22:52:59 -0700 Subject: usb: gadget: storage: adapt logic block size to bound block devices Now the mass storage driver has fixed logic block size of 512 bytes. The mass storage gadget read/write bound devices only through VFS, so the bottom level devices actually are just RAW devices to the driver and connected PC. As a RAW, hosts can always format, read and write it right in 512 bytes logic block and don't care about the actual logic block size of devices bound to the gadget. But if we want to share the bound block device partition between target board and PC, in case the logic block size of the bound block device is 4KB, we execute the following steps: 1. connect a board with mass storage gadget to PC(the board has set one partition of on-board block device as file name of the mass storage) 2. PC format the mass storage to VFAT by default logic block size and read/write it 3. disconnect boards from PC 4. target board mount the partition as VFAT Step 4 will fail since kernel on target thinks the logic block size of the bound partition as 4KB. A typical error is "FAT: logical sector size too small for device (logical sector size = 512)" If we execute opposite steps: 1. format the partition to VFAT on target board and read/write this partition 2. connect the board to Windows PC as usb mass storage gadget, windows will think the disk is not formatted So the conclusion is that only as a gadget, the mass storage driver has no any problem. But being shared VFAT or other filesystem on PC and target board, it will fail. This patch adapts logic block size to bound block devices and fix the issue. Cc: Michal Nazarewicz Acked-by: Alan Stern Signed-off-by: Peiyu Li Signed-off-by: Xianglong Du Signed-off-by: Huayi Li Signed-off-by: Barry Song Signed-off-by: Felipe Balbi --- drivers/usb/gadget/f_mass_storage.c | 63 ++++++++++++++++++++++--------------- drivers/usb/gadget/file_storage.c | 50 ++++++++++++++--------------- drivers/usb/gadget/storage_common.c | 23 +++++++++++--- 3 files changed, 79 insertions(+), 57 deletions(-) (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/f_mass_storage.c b/drivers/usb/gadget/f_mass_storage.c index 4ce3decda1db..1cdb1fa1b158 100644 --- a/drivers/usb/gadget/f_mass_storage.c +++ b/drivers/usb/gadget/f_mass_storage.c @@ -112,8 +112,7 @@ * is not loaded (an empty string as "filename" in the fsg_config * structure causes error). The CD-ROM emulation includes a single * data track and no audio tracks; hence there need be only one - * backing file per LUN. Note also that the CD-ROM block length is - * set to 512 rather than the more common value 2048. + * backing file per LUN. * * * MSF includes support for module parameters. If gadget using it @@ -771,7 +770,7 @@ static int do_read(struct fsg_common *common) curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; return -EINVAL; } - file_offset = ((loff_t) lba) << 9; + file_offset = ((loff_t) lba) << curlun->blkbits; /* Carry out the file reads */ amount_left = common->data_size_from_cmnd; @@ -812,7 +811,8 @@ static int do_read(struct fsg_common *common) if (amount == 0) { curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; - curlun->sense_data_info = file_offset >> 9; + curlun->sense_data_info = + file_offset >> curlun->blkbits; curlun->info_valid = 1; bh->inreq->length = 0; bh->state = BUF_STATE_FULL; @@ -835,7 +835,7 @@ static int do_read(struct fsg_common *common) } else if (nread < amount) { LDBG(curlun, "partial file read: %d/%u\n", (int)nread, amount); - nread -= (nread & 511); /* Round down to a block */ + nread = round_down(nread, curlun->blksize); } file_offset += nread; amount_left -= nread; @@ -846,7 +846,8 @@ static int do_read(struct fsg_common *common) /* 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 >> 9; + curlun->sense_data_info = + file_offset >> curlun->blkbits; curlun->info_valid = 1; break; } @@ -921,7 +922,7 @@ static int do_write(struct fsg_common *common) /* Carry out the file writes */ get_some_more = 1; - file_offset = usb_offset = ((loff_t) lba) << 9; + file_offset = usb_offset = ((loff_t) lba) << curlun->blkbits; amount_left_to_req = common->data_size_from_cmnd; amount_left_to_write = common->data_size_from_cmnd; @@ -954,11 +955,12 @@ static int do_write(struct fsg_common *common) get_some_more = 0; curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; - curlun->sense_data_info = usb_offset >> 9; + curlun->sense_data_info = + usb_offset >> curlun->blkbits; curlun->info_valid = 1; continue; } - amount -= amount & 511; + amount = round_down(amount, curlun->blksize); if (amount == 0) { /* @@ -1002,7 +1004,8 @@ static int do_write(struct fsg_common *common) /* Did something go wrong with the transfer? */ if (bh->outreq->status != 0) { curlun->sense_data = SS_COMMUNICATION_FAILURE; - curlun->sense_data_info = file_offset >> 9; + curlun->sense_data_info = + file_offset >> curlun->blkbits; curlun->info_valid = 1; break; } @@ -1033,8 +1036,7 @@ static int do_write(struct fsg_common *common) } else if (nwritten < amount) { LDBG(curlun, "partial file write: %d/%u\n", (int)nwritten, amount); - nwritten -= (nwritten & 511); - /* Round down to a block */ + nwritten = round_down(nwritten, curlun->blksize); } file_offset += nwritten; amount_left_to_write -= nwritten; @@ -1043,7 +1045,8 @@ static int do_write(struct fsg_common *common) /* If an error occurred, report it and its position */ if (nwritten < amount) { curlun->sense_data = SS_WRITE_ERROR; - curlun->sense_data_info = file_offset >> 9; + curlun->sense_data_info = + file_offset >> curlun->blkbits; curlun->info_valid = 1; break; } @@ -1129,8 +1132,8 @@ static int do_verify(struct fsg_common *common) return -EIO; /* No default reply */ /* Prepare to carry out the file verify */ - amount_left = verification_length << 9; - file_offset = ((loff_t) lba) << 9; + 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); @@ -1157,7 +1160,8 @@ static int do_verify(struct fsg_common *common) if (amount == 0) { curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; - curlun->sense_data_info = file_offset >> 9; + curlun->sense_data_info = + file_offset >> curlun->blkbits; curlun->info_valid = 1; break; } @@ -1179,11 +1183,12 @@ static int do_verify(struct fsg_common *common) } else if (nread < amount) { LDBG(curlun, "partial file verify: %d/%u\n", (int)nread, amount); - nread -= nread & 511; /* Round down to a sector */ + nread = round_down(nread, curlun->blksize); } if (nread == 0) { curlun->sense_data = SS_UNRECOVERED_READ_ERROR; - curlun->sense_data_info = file_offset >> 9; + curlun->sense_data_info = + file_offset >> curlun->blkbits; curlun->info_valid = 1; break; } @@ -1289,7 +1294,7 @@ static int do_read_capacity(struct fsg_common *common, struct fsg_buffhd *bh) put_unaligned_be32(curlun->num_sectors - 1, &buf[0]); /* Max logical block */ - put_unaligned_be32(512, &buf[4]); /* Block length */ + put_unaligned_be32(curlun->blksize, &buf[4]);/* Block length */ return 8; } @@ -1527,7 +1532,7 @@ static int do_read_format_capacities(struct fsg_common *common, put_unaligned_be32(curlun->num_sectors, &buf[0]); /* Number of blocks */ - put_unaligned_be32(512, &buf[4]); /* Block length */ + put_unaligned_be32(curlun->blksize, &buf[4]);/* Block length */ buf[4] = 0x02; /* Current capacity */ return 12; } @@ -2022,7 +2027,8 @@ static int do_scsi_command(struct fsg_common *common) case READ_6: i = common->cmnd[4]; - common->data_size_from_cmnd = (i == 0 ? 256 : i) << 9; + common->data_size_from_cmnd = (i == 0 ? 256 : i) << + common->curlun->blkbits; reply = check_command(common, 6, DATA_DIR_TO_HOST, (7<<1) | (1<<4), 1, "READ(6)"); @@ -2032,7 +2038,8 @@ static int do_scsi_command(struct fsg_common *common) case READ_10: common->data_size_from_cmnd = - get_unaligned_be16(&common->cmnd[7]) << 9; + get_unaligned_be16(&common->cmnd[7]) << + common->curlun->blkbits; reply = check_command(common, 10, DATA_DIR_TO_HOST, (1<<1) | (0xf<<2) | (3<<7), 1, "READ(10)"); @@ -2042,7 +2049,8 @@ static int do_scsi_command(struct fsg_common *common) case READ_12: common->data_size_from_cmnd = - get_unaligned_be32(&common->cmnd[6]) << 9; + get_unaligned_be32(&common->cmnd[6]) << + common->curlun->blkbits; reply = check_command(common, 12, DATA_DIR_TO_HOST, (1<<1) | (0xf<<2) | (0xf<<6), 1, "READ(12)"); @@ -2142,7 +2150,8 @@ static int do_scsi_command(struct fsg_common *common) case WRITE_6: i = common->cmnd[4]; - common->data_size_from_cmnd = (i == 0 ? 256 : i) << 9; + common->data_size_from_cmnd = (i == 0 ? 256 : i) << + common->curlun->blkbits; reply = check_command(common, 6, DATA_DIR_FROM_HOST, (7<<1) | (1<<4), 1, "WRITE(6)"); @@ -2152,7 +2161,8 @@ static int do_scsi_command(struct fsg_common *common) case WRITE_10: common->data_size_from_cmnd = - get_unaligned_be16(&common->cmnd[7]) << 9; + get_unaligned_be16(&common->cmnd[7]) << + common->curlun->blkbits; reply = check_command(common, 10, DATA_DIR_FROM_HOST, (1<<1) | (0xf<<2) | (3<<7), 1, "WRITE(10)"); @@ -2162,7 +2172,8 @@ static int do_scsi_command(struct fsg_common *common) case WRITE_12: common->data_size_from_cmnd = - get_unaligned_be32(&common->cmnd[6]) << 9; + get_unaligned_be32(&common->cmnd[6]) << + common->curlun->blkbits; reply = check_command(common, 12, DATA_DIR_FROM_HOST, (1<<1) | (0xf<<2) | (0xf<<6), 1, "WRITE(12)"); diff --git a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c index 39ece40a045f..59d97750cecd 100644 --- a/drivers/usb/gadget/file_storage.c +++ b/drivers/usb/gadget/file_storage.c @@ -69,8 +69,7 @@ * 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. Note also that the CD-ROM block - * length is set to 512 rather than the more common value 2048. + * 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 @@ -1158,7 +1157,7 @@ static int do_read(struct fsg_dev *fsg) curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; return -EINVAL; } - file_offset = ((loff_t) lba) << 9; + file_offset = ((loff_t) lba) << curlun->blkbits; /* Carry out the file reads */ amount_left = fsg->data_size_from_cmnd; @@ -1196,7 +1195,7 @@ static int do_read(struct fsg_dev *fsg) if (amount == 0) { curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; - curlun->sense_data_info = file_offset >> 9; + curlun->sense_data_info = file_offset >> curlun->blkbits; curlun->info_valid = 1; bh->inreq->length = 0; bh->state = BUF_STATE_FULL; @@ -1221,7 +1220,7 @@ static int do_read(struct fsg_dev *fsg) } else if (nread < amount) { LDBG(curlun, "partial file read: %d/%u\n", (int) nread, amount); - nread -= (nread & 511); // Round down to a block + nread = round_down(nread, curlun->blksize); } file_offset += nread; amount_left -= nread; @@ -1232,7 +1231,7 @@ static int do_read(struct fsg_dev *fsg) /* 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 >> 9; + curlun->sense_data_info = file_offset >> curlun->blkbits; curlun->info_valid = 1; break; } @@ -1303,7 +1302,7 @@ static int do_write(struct fsg_dev *fsg) /* Carry out the file writes */ get_some_more = 1; - file_offset = usb_offset = ((loff_t) lba) << 9; + 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) { @@ -1333,11 +1332,11 @@ static int do_write(struct fsg_dev *fsg) get_some_more = 0; curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; - curlun->sense_data_info = usb_offset >> 9; + curlun->sense_data_info = usb_offset >> curlun->blkbits; curlun->info_valid = 1; continue; } - amount -= (amount & 511); + amount = round_down(amount, curlun->blksize); if (amount == 0) { /* Why were we were asked to transfer a @@ -1376,7 +1375,7 @@ static int do_write(struct fsg_dev *fsg) /* Did something go wrong with the transfer? */ if (bh->outreq->status != 0) { curlun->sense_data = SS_COMMUNICATION_FAILURE; - curlun->sense_data_info = file_offset >> 9; + curlun->sense_data_info = file_offset >> curlun->blkbits; curlun->info_valid = 1; break; } @@ -1408,8 +1407,7 @@ static int do_write(struct fsg_dev *fsg) } else if (nwritten < amount) { LDBG(curlun, "partial file write: %d/%u\n", (int) nwritten, amount); - nwritten -= (nwritten & 511); - // Round down to a block + nwritten = round_down(nwritten, curlun->blksize); } file_offset += nwritten; amount_left_to_write -= nwritten; @@ -1418,7 +1416,7 @@ static int do_write(struct fsg_dev *fsg) /* If an error occurred, report it and its position */ if (nwritten < amount) { curlun->sense_data = SS_WRITE_ERROR; - curlun->sense_data_info = file_offset >> 9; + curlun->sense_data_info = file_offset >> curlun->blkbits; curlun->info_valid = 1; break; } @@ -1500,8 +1498,8 @@ static int do_verify(struct fsg_dev *fsg) return -EIO; // No default reply /* Prepare to carry out the file verify */ - amount_left = verification_length << 9; - file_offset = ((loff_t) lba) << 9; + 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); @@ -1527,7 +1525,7 @@ static int do_verify(struct fsg_dev *fsg) if (amount == 0) { curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; - curlun->sense_data_info = file_offset >> 9; + curlun->sense_data_info = file_offset >> curlun->blkbits; curlun->info_valid = 1; break; } @@ -1550,11 +1548,11 @@ static int do_verify(struct fsg_dev *fsg) } else if (nread < amount) { LDBG(curlun, "partial file verify: %d/%u\n", (int) nread, amount); - nread -= (nread & 511); // Round down to a sector + nread = round_down(nread, curlun->blksize); } if (nread == 0) { curlun->sense_data = SS_UNRECOVERED_READ_ERROR; - curlun->sense_data_info = file_offset >> 9; + curlun->sense_data_info = file_offset >> curlun->blkbits; curlun->info_valid = 1; break; } @@ -1668,7 +1666,7 @@ static int do_read_capacity(struct fsg_dev *fsg, struct fsg_buffhd *bh) put_unaligned_be32(curlun->num_sectors - 1, &buf[0]); /* Max logical block */ - put_unaligned_be32(512, &buf[4]); /* Block length */ + put_unaligned_be32(curlun->blksize, &buf[4]); /* Block length */ return 8; } @@ -1890,7 +1888,7 @@ static int do_read_format_capacities(struct fsg_dev *fsg, put_unaligned_be32(curlun->num_sectors, &buf[0]); /* Number of blocks */ - put_unaligned_be32(512, &buf[4]); /* Block length */ + put_unaligned_be32(curlun->blksize, &buf[4]); /* Block length */ buf[4] = 0x02; /* Current capacity */ return 12; } @@ -2415,7 +2413,7 @@ static int do_scsi_command(struct fsg_dev *fsg) case READ_6: i = fsg->cmnd[4]; - fsg->data_size_from_cmnd = (i == 0 ? 256 : i) << 9; + fsg->data_size_from_cmnd = (i == 0 ? 256 : i) << fsg->curlun->blkbits; if ((reply = check_command(fsg, 6, DATA_DIR_TO_HOST, (7<<1) | (1<<4), 1, "READ(6)")) == 0) @@ -2424,7 +2422,7 @@ static int do_scsi_command(struct fsg_dev *fsg) case READ_10: fsg->data_size_from_cmnd = - get_unaligned_be16(&fsg->cmnd[7]) << 9; + get_unaligned_be16(&fsg->cmnd[7]) << fsg->curlun->blkbits; if ((reply = check_command(fsg, 10, DATA_DIR_TO_HOST, (1<<1) | (0xf<<2) | (3<<7), 1, "READ(10)")) == 0) @@ -2433,7 +2431,7 @@ static int do_scsi_command(struct fsg_dev *fsg) case READ_12: fsg->data_size_from_cmnd = - get_unaligned_be32(&fsg->cmnd[6]) << 9; + get_unaligned_be32(&fsg->cmnd[6]) << fsg->curlun->blkbits; if ((reply = check_command(fsg, 12, DATA_DIR_TO_HOST, (1<<1) | (0xf<<2) | (0xf<<6), 1, "READ(12)")) == 0) @@ -2519,7 +2517,7 @@ static int do_scsi_command(struct fsg_dev *fsg) case WRITE_6: i = fsg->cmnd[4]; - fsg->data_size_from_cmnd = (i == 0 ? 256 : i) << 9; + fsg->data_size_from_cmnd = (i == 0 ? 256 : i) << fsg->curlun->blkbits; if ((reply = check_command(fsg, 6, DATA_DIR_FROM_HOST, (7<<1) | (1<<4), 1, "WRITE(6)")) == 0) @@ -2528,7 +2526,7 @@ static int do_scsi_command(struct fsg_dev *fsg) case WRITE_10: fsg->data_size_from_cmnd = - get_unaligned_be16(&fsg->cmnd[7]) << 9; + get_unaligned_be16(&fsg->cmnd[7]) << fsg->curlun->blkbits; if ((reply = check_command(fsg, 10, DATA_DIR_FROM_HOST, (1<<1) | (0xf<<2) | (3<<7), 1, "WRITE(10)")) == 0) @@ -2537,7 +2535,7 @@ static int do_scsi_command(struct fsg_dev *fsg) case WRITE_12: fsg->data_size_from_cmnd = - get_unaligned_be32(&fsg->cmnd[6]) << 9; + get_unaligned_be32(&fsg->cmnd[6]) << fsg->curlun->blkbits; if ((reply = check_command(fsg, 12, DATA_DIR_FROM_HOST, (1<<1) | (0xf<<2) | (0xf<<6), 1, "WRITE(12)")) == 0) diff --git a/drivers/usb/gadget/storage_common.c b/drivers/usb/gadget/storage_common.c index d3dd227a2bfc..3ea70d8549ef 100644 --- a/drivers/usb/gadget/storage_common.c +++ b/drivers/usb/gadget/storage_common.c @@ -247,6 +247,8 @@ struct fsg_lun { u32 sense_data_info; u32 unit_attention_data; + unsigned int blkbits; /* Bits of logical block size of bound block device */ + unsigned int blksize; /* logical block size of bound block device */ struct device dev; }; @@ -580,13 +582,24 @@ static int fsg_lun_open(struct fsg_lun *curlun, const char *filename) rc = (int) size; goto out; } - num_sectors = size >> 9; /* File size in 512-byte blocks */ + + if (curlun->cdrom) { + curlun->blksize = 2048; + curlun->blkbits = 11; + } else if (inode->i_bdev) { + curlun->blksize = bdev_logical_block_size(inode->i_bdev); + curlun->blkbits = blksize_bits(curlun->blksize); + } else { + curlun->blksize = 512; + curlun->blkbits = 9; + } + + num_sectors = size >> curlun->blkbits; /* File size in logic-block-size blocks */ min_sectors = 1; if (curlun->cdrom) { - num_sectors &= ~3; /* Reduce to a multiple of 2048 */ - min_sectors = 300*4; /* Smallest track is 300 frames */ - if (num_sectors >= 256*60*75*4) { - num_sectors = (256*60*75 - 1) * 4; + min_sectors = 300; /* Smallest track is 300 frames */ + if (num_sectors >= 256*60*75) { + num_sectors = 256*60*75 - 1; LINFO(curlun, "file too big: %s\n", filename); LINFO(curlun, "using only first %d blocks\n", (int) num_sectors); -- cgit From 04eee25b1d754a837360504b7af426d1f86ffeb7 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Thu, 18 Aug 2011 14:29:00 -0400 Subject: USB: gadget: storage: remove alignment assumption This patch (as1481) fixes a problem affecting g_file_storage and g_mass_storage when running at SuperSpeed. The two drivers currently assume that the bulk-out maxpacket size can evenly divide the SCSI block size, which is 512 bytes. But SuperSpeed bulk endpoints have a maxpacket size of 1024, so the assumption is no longer true. This patch removes that assumption from the drivers, by getting rid of a small optimization (they try to align VFS reads and writes on page cache boundaries). If a command's starting logical block address is 512 bytes below the end of a page, it's not okay to issue a USB command for just those 512 bytes when the maxpacket size is 1024 -- it would result in either babble (for an OUT transfer) or a short packet (for an IN transfer). Also, for backward compatibility, the test for writes extending beyond the end of the backing storage has to be changed. If the host tries to do this, we should accept the data that fits in the backing storage and ignore the rest. Because the storage's end may not align with a USB packet boundary, this means we may have to accept a USB OUT transfer that extends beyond the end of the storage and then write out only the part of the data that fits. Signed-off-by: Alan Stern Acked-by: Michal Nazarewicz Signed-off-by: Felipe Balbi --- drivers/usb/gadget/f_mass_storage.c | 63 ++++++++++++---------------------- drivers/usb/gadget/file_storage.c | 67 +++++++++++++++---------------------- 2 files changed, 49 insertions(+), 81 deletions(-) (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/f_mass_storage.c b/drivers/usb/gadget/f_mass_storage.c index 1cdb1fa1b158..4306a8339487 100644 --- a/drivers/usb/gadget/f_mass_storage.c +++ b/drivers/usb/gadget/f_mass_storage.c @@ -744,7 +744,6 @@ static int do_read(struct fsg_common *common) u32 amount_left; loff_t file_offset, file_offset_tmp; unsigned int amount; - unsigned int partial_page; ssize_t nread; /* @@ -783,18 +782,10 @@ static int do_read(struct fsg_common *common) * 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. - * Finally, if we're not at a page boundary, don't read past - * the next page. - * If this means reading 0 then we were asked to read past - * the end of file. */ amount = min(amount_left, FSG_BUFLEN); amount = min((loff_t)amount, curlun->file_length - file_offset); - partial_page = file_offset & (PAGE_CACHE_SIZE - 1); - if (partial_page > 0) - amount = min(amount, (unsigned int)PAGE_CACHE_SIZE - - partial_page); /* Wait for the next buffer to become available */ bh = common->next_buffhd_to_fill; @@ -840,6 +831,12 @@ static int do_read(struct fsg_common *common) file_offset += nread; amount_left -= nread; common->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; @@ -878,7 +875,6 @@ static int do_write(struct fsg_common *common) u32 amount_left_to_req, amount_left_to_write; loff_t usb_offset, file_offset, file_offset_tmp; unsigned int amount; - unsigned int partial_page; ssize_t nwritten; int rc; @@ -934,24 +930,13 @@ static int do_write(struct fsg_common *common) /* * Figure out how much we want to get: - * Try to get the remaining amount. - * But don't get more than the buffer size. - * And don't try to go past the end of the file. - * If we're not at a page boundary, - * don't go past the next page. - * If this means getting 0, then we were asked - * to write past the end of file. - * Finally, round down to a block boundary. + * Try to get the remaining amount, + * but not more than the buffer size. */ amount = min(amount_left_to_req, FSG_BUFLEN); - amount = min((loff_t)amount, - curlun->file_length - usb_offset); - partial_page = usb_offset & (PAGE_CACHE_SIZE - 1); - if (partial_page > 0) - amount = min(amount, - (unsigned int)PAGE_CACHE_SIZE - partial_page); - - if (amount == 0) { + + /* 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; @@ -960,16 +945,6 @@ static int do_write(struct fsg_common *common) curlun->info_valid = 1; continue; } - amount = round_down(amount, curlun->blksize); - if (amount == 0) { - - /* - * Why were we were asked to transfer a - * partial block? - */ - get_some_more = 0; - continue; - } /* Get the next buffer */ usb_offset += amount; @@ -979,8 +954,9 @@ static int do_write(struct fsg_common *common) get_some_more = 0; /* - * amount is always divisible by 512, hence by - * the bulk-out maxpacket size + * Except at the end of the transfer, amount will be + * equal to the buffer size, which is divisible by + * the bulk-out maxpacket size. */ bh->outreq->length = amount; bh->bulk_out_intended_length = amount; @@ -1019,6 +995,11 @@ static int do_write(struct fsg_common *common) amount = curlun->file_length - file_offset; } + /* 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, @@ -1051,6 +1032,7 @@ static int do_write(struct fsg_common *common) break; } + empty_write: /* Did the host decide to stop early? */ if (bh->outreq->actual != bh->outreq->length) { common->short_packet_received = 1; @@ -1151,8 +1133,6 @@ static int do_verify(struct fsg_common *common) * 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. - * If this means reading 0 then we were asked to read - * past the end of file. */ amount = min(amount_left, FSG_BUFLEN); amount = min((loff_t)amount, @@ -1628,7 +1608,8 @@ static int throw_away_data(struct fsg_common *common) amount = min(common->usb_amount_left, FSG_BUFLEN); /* - * amount is always divisible by 512, hence by + * Except at the end of the transfer, amount will be + * equal to the buffer size, which is divisible by * the bulk-out maxpacket size. */ bh->outreq->length = amount; diff --git a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c index 59d97750cecd..c6f96a2b3110 100644 --- a/drivers/usb/gadget/file_storage.c +++ b/drivers/usb/gadget/file_storage.c @@ -1135,7 +1135,6 @@ static int do_read(struct fsg_dev *fsg) u32 amount_left; loff_t file_offset, file_offset_tmp; unsigned int amount; - unsigned int partial_page; ssize_t nread; /* Get the starting Logical Block Address and check that it's @@ -1170,17 +1169,10 @@ static int do_read(struct fsg_dev *fsg) * 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. - * Finally, if we're not at a page boundary, don't read past - * the next page. - * If this means reading 0 then we were asked to read past - * the end of file. */ + */ amount = min((unsigned int) amount_left, mod_data.buflen); amount = min((loff_t) amount, curlun->file_length - file_offset); - partial_page = file_offset & (PAGE_CACHE_SIZE - 1); - if (partial_page > 0) - amount = min(amount, (unsigned int) PAGE_CACHE_SIZE - - partial_page); /* Wait for the next buffer to become available */ bh = fsg->next_buffhd_to_fill; @@ -1225,6 +1217,11 @@ static int do_read(struct fsg_dev *fsg) 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; @@ -1261,7 +1258,6 @@ static int do_write(struct fsg_dev *fsg) u32 amount_left_to_req, amount_left_to_write; loff_t usb_offset, file_offset, file_offset_tmp; unsigned int amount; - unsigned int partial_page; ssize_t nwritten; int rc; @@ -1312,23 +1308,13 @@ static int do_write(struct fsg_dev *fsg) if (bh->state == BUF_STATE_EMPTY && get_some_more) { /* Figure out how much we want to get: - * Try to get the remaining amount. - * But don't get more than the buffer size. - * And don't try to go past the end of the file. - * If we're not at a page boundary, - * don't go past the next page. - * If this means getting 0, then we were asked - * to write past the end of file. - * Finally, round down to a block boundary. */ + * Try to get the remaining amount, + * but not more than the buffer size. + */ amount = min(amount_left_to_req, mod_data.buflen); - amount = min((loff_t) amount, curlun->file_length - - usb_offset); - partial_page = usb_offset & (PAGE_CACHE_SIZE - 1); - if (partial_page > 0) - amount = min(amount, - (unsigned int) PAGE_CACHE_SIZE - partial_page); - - if (amount == 0) { + + /* 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; @@ -1336,14 +1322,6 @@ static int do_write(struct fsg_dev *fsg) curlun->info_valid = 1; continue; } - amount = round_down(amount, curlun->blksize); - if (amount == 0) { - - /* Why were we were asked to transfer a - * partial block? */ - get_some_more = 0; - continue; - } /* Get the next buffer */ usb_offset += amount; @@ -1352,8 +1330,10 @@ static int do_write(struct fsg_dev *fsg) if (amount_left_to_req == 0) get_some_more = 0; - /* amount is always divisible by 512, hence by - * the bulk-out maxpacket size */ + /* Except at the end of the transfer, amount will be + * equal to the buffer size, which is divisible by + * the bulk-out maxpacket size. + */ bh->outreq->length = bh->bulk_out_intended_length = amount; bh->outreq->short_not_ok = 1; @@ -1389,6 +1369,11 @@ static int do_write(struct fsg_dev *fsg) amount = curlun->file_length - file_offset; } + /* 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, @@ -1421,6 +1406,7 @@ static int do_write(struct fsg_dev *fsg) break; } + empty_write: /* Did the host decide to stop early? */ if (bh->outreq->actual != bh->outreq->length) { fsg->short_packet_received = 1; @@ -1517,8 +1503,7 @@ static int do_verify(struct fsg_dev *fsg) * 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. - * If this means reading 0 then we were asked to read - * past the end of file. */ + */ amount = min((unsigned int) amount_left, mod_data.buflen); amount = min((loff_t) amount, curlun->file_length - file_offset); @@ -1981,8 +1966,10 @@ static int throw_away_data(struct fsg_dev *fsg) amount = min(fsg->usb_amount_left, (u32) mod_data.buflen); - /* amount is always divisible by 512, hence by - * the bulk-out maxpacket size */ + /* Except at the end of the transfer, amount will be + * equal to the buffer size, which is divisible by + * the bulk-out maxpacket size. + */ bh->outreq->length = bh->bulk_out_intended_length = amount; bh->outreq->short_not_ok = 1; -- cgit From 6532c7fdb2c3a2ec1b949ecd2ff5375069c1639a Mon Sep 17 00:00:00 2001 From: Per Forlin Date: Fri, 19 Aug 2011 21:21:27 +0200 Subject: usb: gadget: storage: make FSG_NUM_BUFFERS variable size FSG_NUM_BUFFERS is set to 2 as default. Usually 2 buffers are enough to establish a good buffering pipeline. The number may be increased in order to compensate a for bursty VFS behaviour. Here follows a description of system that may require more than 2 buffers. * CPU ondemand governor active * latency cost for wake up and/or frequency change * DMA for IO Use case description. * Data transfer from MMC via VFS to USB. * DMA shuffles data from MMC and to USB. * The CPU wakes up every now and then to pass data in and out from VFS, which cause the bursty VFS behaviour. Test set up * Running dd on the host reading from the mass storage device * cmdline: dd if=/dev/sdb of=/dev/null bs=4k count=$((256*100)) * Caches are dropped on the host and on the device before each run Measurements on a Snowball board with ondemand_governor active. FSG_NUM_BUFFERS 2 104857600 bytes (105 MB) copied, 5.62173 s, 18.7 MB/s 104857600 bytes (105 MB) copied, 5.61811 s, 18.7 MB/s 104857600 bytes (105 MB) copied, 5.57817 s, 18.8 MB/s FSG_NUM_BUFFERS 4 104857600 bytes (105 MB) copied, 5.26839 s, 19.9 MB/s 104857600 bytes (105 MB) copied, 5.2691 s, 19.9 MB/s 104857600 bytes (105 MB) copied, 5.2711 s, 19.9 MB/s There may not be one optimal number for all boards. This is why the number is added to Kconfig. If selecting USB_GADGET_DEBUG_FILES this value may be set by a module parameter as well. Signed-off-by: Per Forlin Acked-by: Michal Nazarewicz Acked-by: Alan Stern Signed-off-by: Felipe Balbi --- drivers/usb/gadget/Kconfig | 16 ++++++++++++++++ drivers/usb/gadget/f_mass_storage.c | 29 +++++++++++++++++++++-------- drivers/usb/gadget/file_storage.c | 27 +++++++++++++++++---------- drivers/usb/gadget/storage_common.c | 33 +++++++++++++++++++++++++++++++-- 4 files changed, 85 insertions(+), 20 deletions(-) (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index fe5637983892..a60b472a0b39 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -96,6 +96,22 @@ config USB_GADGET_VBUS_DRAW This value will be used except for system-specific gadget drivers that have more specific information. +config USB_GADGET_STORAGE_NUM_BUFFERS + int "Number of storage pipeline buffers" + range 2 4 + default 2 + help + Usually 2 buffers are enough to establish a good buffering + pipeline. The number may be increased in order to compensate + for a bursty VFS behaviour. For instance there may be CPU wake up + latencies that makes the VFS to appear bursty in a system with + an CPU on-demand governor. Especially if DMA is doing IO to + offload the CPU. In this case the CPU will go into power + save often and spin up occasionally to move data within VFS. + If selecting USB_GADGET_DEBUG_FILES this value may be set by + a module parameter as well. + If unsure, say 2. + # # USB Peripheral Controller Support # diff --git a/drivers/usb/gadget/f_mass_storage.c b/drivers/usb/gadget/f_mass_storage.c index 4306a8339487..756941473148 100644 --- a/drivers/usb/gadget/f_mass_storage.c +++ b/drivers/usb/gadget/f_mass_storage.c @@ -362,7 +362,7 @@ struct fsg_common { struct fsg_buffhd *next_buffhd_to_fill; struct fsg_buffhd *next_buffhd_to_drain; - struct fsg_buffhd buffhds[FSG_NUM_BUFFERS]; + struct fsg_buffhd *buffhds; int cmnd_size; u8 cmnd[MAX_COMMAND_SIZE]; @@ -2340,7 +2340,7 @@ reset: if (common->fsg) { fsg = common->fsg; - for (i = 0; i < FSG_NUM_BUFFERS; ++i) { + for (i = 0; i < fsg_num_buffers; ++i) { struct fsg_buffhd *bh = &common->buffhds[i]; if (bh->inreq) { @@ -2397,7 +2397,7 @@ reset: clear_bit(IGNORE_BULK_OUT, &fsg->atomic_bitflags); /* Allocate the requests */ - for (i = 0; i < FSG_NUM_BUFFERS; ++i) { + for (i = 0; i < fsg_num_buffers; ++i) { struct fsg_buffhd *bh = &common->buffhds[i]; rc = alloc_request(common, fsg->bulk_in, &bh->inreq); @@ -2466,7 +2466,7 @@ static void handle_exception(struct fsg_common *common) /* Cancel all the pending transfers */ if (likely(common->fsg)) { - for (i = 0; i < FSG_NUM_BUFFERS; ++i) { + for (i = 0; i < fsg_num_buffers; ++i) { bh = &common->buffhds[i]; if (bh->inreq_busy) usb_ep_dequeue(common->fsg->bulk_in, bh->inreq); @@ -2478,7 +2478,7 @@ static void handle_exception(struct fsg_common *common) /* Wait until everything is idle */ for (;;) { int num_active = 0; - for (i = 0; i < FSG_NUM_BUFFERS; ++i) { + for (i = 0; i < fsg_num_buffers; ++i) { bh = &common->buffhds[i]; num_active += bh->inreq_busy + bh->outreq_busy; } @@ -2501,7 +2501,7 @@ static void handle_exception(struct fsg_common *common) */ spin_lock_irq(&common->lock); - for (i = 0; i < FSG_NUM_BUFFERS; ++i) { + for (i = 0; i < fsg_num_buffers; ++i) { bh = &common->buffhds[i]; bh->state = BUF_STATE_EMPTY; } @@ -2710,6 +2710,10 @@ static struct fsg_common *fsg_common_init(struct fsg_common *common, int nluns, i, rc; char *pathbuf; + rc = fsg_num_buffers_validate(); + if (rc != 0) + return ERR_PTR(rc); + /* Find out how many LUNs there should be */ nluns = cfg->nluns; if (nluns < 1 || nluns > FSG_MAX_LUNS) { @@ -2728,6 +2732,14 @@ static struct fsg_common *fsg_common_init(struct fsg_common *common, common->free_storage_on_release = 0; } + common->buffhds = kcalloc(fsg_num_buffers, + sizeof *(common->buffhds), GFP_KERNEL); + if (!common->buffhds) { + if (common->free_storage_on_release) + kfree(common); + return ERR_PTR(-ENOMEM); + } + common->ops = cfg->ops; common->private_data = cfg->private_data; @@ -2805,7 +2817,7 @@ static struct fsg_common *fsg_common_init(struct fsg_common *common, /* Data buffers cyclic list */ bh = common->buffhds; - i = FSG_NUM_BUFFERS; + i = fsg_num_buffers; goto buffhds_first_it; do { bh->next = bh + 1; @@ -2931,12 +2943,13 @@ static void fsg_common_release(struct kref *ref) { struct fsg_buffhd *bh = common->buffhds; - unsigned i = FSG_NUM_BUFFERS; + unsigned i = fsg_num_buffers; do { kfree(bh->buf); } while (++bh, --i); } + kfree(common->buffhds); if (common->free_storage_on_release) kfree(common); } diff --git a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c index c6f96a2b3110..4b9797d07a67 100644 --- a/drivers/usb/gadget/file_storage.c +++ b/drivers/usb/gadget/file_storage.c @@ -460,7 +460,6 @@ struct fsg_dev { struct fsg_buffhd *next_buffhd_to_fill; struct fsg_buffhd *next_buffhd_to_drain; - struct fsg_buffhd buffhds[FSG_NUM_BUFFERS]; int thread_wakeup_needed; struct completion thread_notifier; @@ -487,6 +486,8 @@ struct fsg_dev { 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 *); @@ -2737,7 +2738,7 @@ static int do_set_interface(struct fsg_dev *fsg, int altsetting) reset: /* Deallocate the requests */ - for (i = 0; i < FSG_NUM_BUFFERS; ++i) { + for (i = 0; i < fsg_num_buffers; ++i) { struct fsg_buffhd *bh = &fsg->buffhds[i]; if (bh->inreq) { @@ -2798,7 +2799,7 @@ reset: } /* Allocate the requests */ - for (i = 0; i < FSG_NUM_BUFFERS; ++i) { + 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) @@ -2894,7 +2895,7 @@ static void handle_exception(struct fsg_dev *fsg) /* 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) { + for (i = 0; i < fsg_num_buffers; ++i) { bh = &fsg->buffhds[i]; if (bh->inreq_busy) usb_ep_dequeue(fsg->bulk_in, bh->inreq); @@ -2905,7 +2906,7 @@ static void handle_exception(struct fsg_dev *fsg) /* Wait until everything is idle */ for (;;) { num_active = fsg->intreq_busy; - for (i = 0; i < FSG_NUM_BUFFERS; ++i) { + for (i = 0; i < fsg_num_buffers; ++i) { bh = &fsg->buffhds[i]; num_active += bh->inreq_busy + bh->outreq_busy; } @@ -2927,7 +2928,7 @@ static void handle_exception(struct fsg_dev *fsg) * state, and the exception. Then invoke the handler. */ spin_lock_irq(&fsg->lock); - for (i = 0; i < FSG_NUM_BUFFERS; ++i) { + for (i = 0; i < fsg_num_buffers; ++i) { bh = &fsg->buffhds[i]; bh->state = BUF_STATE_EMPTY; } @@ -3157,7 +3158,7 @@ static void /* __init_or_exit */ fsg_unbind(struct usb_gadget *gadget) } /* Free the data buffers */ - for (i = 0; i < FSG_NUM_BUFFERS; ++i) + for (i = 0; i < fsg_num_buffers; ++i) kfree(fsg->buffhds[i].buf); /* Free the request and buffer for endpoint 0 */ @@ -3445,7 +3446,7 @@ static int __init fsg_bind(struct usb_gadget *gadget) req->complete = ep0_complete; /* Allocate the data buffers */ - for (i = 0; i < FSG_NUM_BUFFERS; ++i) { + for (i = 0; i < fsg_num_buffers; ++i) { struct fsg_buffhd *bh = &fsg->buffhds[i]; /* Allocate for the bulk-in endpoint. We assume that @@ -3456,7 +3457,7 @@ static int __init fsg_bind(struct usb_gadget *gadget) goto out; bh->next = bh + 1; } - fsg->buffhds[FSG_NUM_BUFFERS - 1].next = &fsg->buffhds[0]; + fsg->buffhds[fsg_num_buffers - 1].next = &fsg->buffhds[0]; /* This should reflect the actual gadget power source */ usb_gadget_set_selfpowered(gadget); @@ -3572,7 +3573,9 @@ static int __init fsg_alloc(void) { struct fsg_dev *fsg; - fsg = kzalloc(sizeof *fsg, GFP_KERNEL); + fsg = kzalloc(sizeof *fsg + + fsg_num_buffers * sizeof *(fsg->buffhds), GFP_KERNEL); + if (!fsg) return -ENOMEM; spin_lock_init(&fsg->lock); @@ -3590,6 +3593,10 @@ 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; diff --git a/drivers/usb/gadget/storage_common.c b/drivers/usb/gadget/storage_common.c index 3ea70d8549ef..9fd379998608 100644 --- a/drivers/usb/gadget/storage_common.c +++ b/drivers/usb/gadget/storage_common.c @@ -52,6 +52,12 @@ * characters rather then a pointer to void. */ +/* + * When USB_GADGET_DEBUG_FILES is defined the module param num_buffers + * sets the number of pipeline buffers (length of the fsg_buffhd array). + * The valid range of num_buffers is: num >= 2 && num <= 4. + */ + #include #include @@ -264,8 +270,31 @@ static struct fsg_lun *fsg_lun_from_dev(struct device *dev) #define EP0_BUFSIZE 256 #define DELAYED_STATUS (EP0_BUFSIZE + 999) /* An impossibly large value */ -/* Number of buffers we will use. 2 is enough for double-buffering */ -#define FSG_NUM_BUFFERS 2 +#ifdef CONFIG_USB_GADGET_DEBUG_FILES + +static unsigned int fsg_num_buffers = CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS; +module_param_named(num_buffers, fsg_num_buffers, uint, S_IRUGO); +MODULE_PARM_DESC(num_buffers, "Number of pipeline buffers"); + +#else + +/* + * Number of buffers we will use. + * 2 is usually enough for good buffering pipeline + */ +#define fsg_num_buffers CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS + +#endif /* CONFIG_USB_DEBUG */ + +/* check if fsg_num_buffers is within a valid range */ +static inline int fsg_num_buffers_validate(void) +{ + if (fsg_num_buffers >= 2 && fsg_num_buffers <= 4) + return 0; + pr_err("fsg_num_buffers %u is out of range (%d to %d)\n", + fsg_num_buffers, 2 ,4); + return -EINVAL; +} /* Default size of buffer length. */ #define FSG_BUFLEN ((u32)16384) -- cgit From ef7f584ce7b40bcfc108477d2711270379ca8596 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Fri, 26 Aug 2011 12:48:15 +0300 Subject: usb: gadget: audio: actually support both speeds While testing g_audio with HighSpeed UDC on a FS Hub, we had no configurations to present to the host. That's because both speeds where mutually exclusive. Signed-off-by: Felipe Balbi --- drivers/usb/gadget/f_audio.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/f_audio.c b/drivers/usb/gadget/f_audio.c index a9a4eade7e80..ddeaa45cd886 100644 --- a/drivers/usb/gadget/f_audio.c +++ b/drivers/usb/gadget/f_audio.c @@ -681,17 +681,18 @@ f_audio_bind(struct usb_configuration *c, struct usb_function *f) status = -ENOMEM; - /* supcard all relevant hardware speeds... we expect that when + /* 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 */ - - /* copy descriptors, and track endpoint copies */ if (gadget_is_dualspeed(c->cdev->gadget)) { c->highspeed = true; f->hs_descriptors = usb_copy_descriptors(f_audio_desc); - } else - f->descriptors = usb_copy_descriptors(f_audio_desc); + } return 0; -- cgit From 7c5881d1625d844cdfcc027a970f0d034b982ba5 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Mon, 29 Aug 2011 11:54:08 +0300 Subject: usb: gadget: audio: queue wLength-sized requests On Audio class, the wLength field of the Setup packet, contains the data payload size of the following Data phase. Instead of harcoding values, use wLength. This also fixes a bug where Gadget driver had to receive 3 bytes, but it was queueing a ZLP. Signed-off-by: Felipe Balbi --- drivers/usb/gadget/f_audio.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/f_audio.c b/drivers/usb/gadget/f_audio.c index ddeaa45cd886..ec7ffcd0d0cd 100644 --- a/drivers/usb/gadget/f_audio.c +++ b/drivers/usb/gadget/f_audio.c @@ -460,7 +460,7 @@ static int audio_set_endpoint_req(struct usb_function *f, switch (ctrl->bRequest) { case UAC_SET_CUR: - value = 0; + value = len; break; case UAC_SET_MIN: @@ -499,7 +499,7 @@ static int audio_get_endpoint_req(struct usb_function *f, case UAC_GET_MIN: case UAC_GET_MAX: case UAC_GET_RES: - value = 3; + value = len; break; case UAC_GET_MEM: break; -- cgit From 28c9fc68ebd32d473a8787d05c74e3f39c6c866b Mon Sep 17 00:00:00 2001 From: Klaus Schwarzkopf Date: Fri, 9 Sep 2011 16:10:44 +0200 Subject: usb gadget: clean up FSF boilerplate text remove the following two paragraphs as they are not needed: This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc.,59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. Signed-off-by: Klaus Schwarzkopf Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/amd5536udc.c | 9 --------- drivers/usb/gadget/amd5536udc.h | 9 --------- drivers/usb/gadget/at91_udc.c | 10 ---------- drivers/usb/gadget/at91_udc.h | 10 ---------- drivers/usb/gadget/cdc2.c | 9 --------- drivers/usb/gadget/ci13xxx_msm.c | 11 ----------- drivers/usb/gadget/composite.c | 9 --------- drivers/usb/gadget/config.c | 9 --------- drivers/usb/gadget/dbgp.c | 1 - drivers/usb/gadget/dummy_hcd.c | 9 --------- drivers/usb/gadget/epautoconf.c | 10 ---------- drivers/usb/gadget/ether.c | 9 --------- drivers/usb/gadget/f_ecm.c | 9 --------- drivers/usb/gadget/f_eem.c | 9 --------- drivers/usb/gadget/f_fs.c | 9 --------- drivers/usb/gadget/f_hid.c | 9 --------- drivers/usb/gadget/f_loopback.c | 9 --------- drivers/usb/gadget/f_ncm.c | 9 --------- drivers/usb/gadget/f_obex.c | 9 --------- drivers/usb/gadget/f_phonet.c | 10 ---------- drivers/usb/gadget/f_rndis.c | 9 --------- drivers/usb/gadget/f_sourcesink.c | 9 --------- drivers/usb/gadget/f_subset.c | 9 --------- drivers/usb/gadget/f_uvc.c | 1 - drivers/usb/gadget/f_uvc.h | 1 - drivers/usb/gadget/fusb300_udc.c | 10 ---------- drivers/usb/gadget/fusb300_udc.h | 10 ---------- drivers/usb/gadget/g_ffs.c | 9 --------- drivers/usb/gadget/hid.c | 9 --------- drivers/usb/gadget/imx_udc.h | 5 ----- drivers/usb/gadget/inode.c | 9 --------- drivers/usb/gadget/langwell_udc.c | 10 ---------- drivers/usb/gadget/langwell_udc.h | 10 ---------- drivers/usb/gadget/m66592-udc.c | 10 ---------- drivers/usb/gadget/m66592-udc.h | 10 ---------- drivers/usb/gadget/mass_storage.c | 9 --------- drivers/usb/gadget/multi.c | 9 --------- drivers/usb/gadget/ncm.c | 9 --------- drivers/usb/gadget/ndis.h | 6 ------ drivers/usb/gadget/net2280.c | 9 --------- drivers/usb/gadget/net2280.h | 9 --------- drivers/usb/gadget/omap_udc.c | 9 --------- drivers/usb/gadget/pch_udc.c | 9 --------- drivers/usb/gadget/printer.c | 9 --------- drivers/usb/gadget/pxa25x_udc.c | 10 ---------- drivers/usb/gadget/pxa25x_udc.h | 9 --------- drivers/usb/gadget/pxa27x_udc.c | 10 ---------- drivers/usb/gadget/pxa27x_udc.h | 9 --------- drivers/usb/gadget/r8a66597-udc.c | 10 ---------- drivers/usb/gadget/r8a66597-udc.h | 10 ---------- drivers/usb/gadget/s3c2410_udc.c | 10 ---------- drivers/usb/gadget/s3c2410_udc.h | 10 ---------- drivers/usb/gadget/storage_common.c | 9 --------- drivers/usb/gadget/u_ether.c | 9 --------- drivers/usb/gadget/u_ether.h | 9 --------- drivers/usb/gadget/uvc.h | 1 - drivers/usb/gadget/uvc_queue.c | 1 - drivers/usb/gadget/uvc_v4l2.c | 1 - drivers/usb/gadget/uvc_video.c | 1 - drivers/usb/gadget/webcam.c | 2 +- drivers/usb/gadget/zero.c | 9 --------- 61 files changed, 1 insertion(+), 496 deletions(-) (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/amd5536udc.c b/drivers/usb/gadget/amd5536udc.c index d65d8392be75..ded8d6fddb53 100644 --- a/drivers/usb/gadget/amd5536udc.c +++ b/drivers/usb/gadget/amd5536udc.c @@ -8,15 +8,6 @@ * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* diff --git a/drivers/usb/gadget/amd5536udc.h b/drivers/usb/gadget/amd5536udc.h index 1d1c7543468e..f87e29c65325 100644 --- a/drivers/usb/gadget/amd5536udc.h +++ b/drivers/usb/gadget/amd5536udc.h @@ -8,15 +8,6 @@ * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef AMD5536UDC_H diff --git a/drivers/usb/gadget/at91_udc.c b/drivers/usb/gadget/at91_udc.c index d01fa5badd66..0a1b6d10ab7a 100644 --- a/drivers/usb/gadget/at91_udc.c +++ b/drivers/usb/gadget/at91_udc.c @@ -9,16 +9,6 @@ * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. */ #undef VERBOSE_DEBUG diff --git a/drivers/usb/gadget/at91_udc.h b/drivers/usb/gadget/at91_udc.h index 108ca54f9092..3c0315b86ace 100644 --- a/drivers/usb/gadget/at91_udc.h +++ b/drivers/usb/gadget/at91_udc.h @@ -7,16 +7,6 @@ * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the - * Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef AT91_UDC_H diff --git a/drivers/usb/gadget/cdc2.c b/drivers/usb/gadget/cdc2.c index b1c1afbb8750..672674c2fb3d 100644 --- a/drivers/usb/gadget/cdc2.c +++ b/drivers/usb/gadget/cdc2.c @@ -8,15 +8,6 @@ * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include diff --git a/drivers/usb/gadget/ci13xxx_msm.c b/drivers/usb/gadget/ci13xxx_msm.c index 470981ad6f77..4eedfe557154 100644 --- a/drivers/usb/gadget/ci13xxx_msm.c +++ b/drivers/usb/gadget/ci13xxx_msm.c @@ -3,17 +3,6 @@ * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and * only 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., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - * */ #include diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c index 8065464523b1..c77aca11ad53 100644 --- a/drivers/usb/gadget/composite.c +++ b/drivers/usb/gadget/composite.c @@ -7,15 +7,6 @@ * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* #define VERBOSE_DEBUG */ diff --git a/drivers/usb/gadget/config.c b/drivers/usb/gadget/config.c index b2c001334876..7542a72ce51a 100644 --- a/drivers/usb/gadget/config.c +++ b/drivers/usb/gadget/config.c @@ -7,15 +7,6 @@ * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include diff --git a/drivers/usb/gadget/dbgp.c b/drivers/usb/gadget/dbgp.c index 8beefdd36787..f855ecf7a637 100644 --- a/drivers/usb/gadget/dbgp.c +++ b/drivers/usb/gadget/dbgp.c @@ -4,7 +4,6 @@ * Copyright (C) 2010 Stephane Duverger * * Released under the GPLv2. - * */ /* verbose messages */ diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c index 7b06d39d6203..ab8f1b488d54 100644 --- a/drivers/usb/gadget/dummy_hcd.c +++ b/drivers/usb/gadget/dummy_hcd.c @@ -10,15 +10,6 @@ * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ diff --git a/drivers/usb/gadget/epautoconf.c b/drivers/usb/gadget/epautoconf.c index cdca7ebb7b48..596a0b464e61 100644 --- a/drivers/usb/gadget/epautoconf.c +++ b/drivers/usb/gadget/epautoconf.c @@ -7,16 +7,6 @@ * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * */ #include diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c index aafc84f33e26..0cd764d59351 100644 --- a/drivers/usb/gadget/ether.c +++ b/drivers/usb/gadget/ether.c @@ -9,15 +9,6 @@ * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* #define VERBOSE_DEBUG */ diff --git a/drivers/usb/gadget/f_ecm.c b/drivers/usb/gadget/f_ecm.c index 3691a0cb9465..11c07cb7d337 100644 --- a/drivers/usb/gadget/f_ecm.c +++ b/drivers/usb/gadget/f_ecm.c @@ -8,15 +8,6 @@ * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* #define VERBOSE_DEBUG */ diff --git a/drivers/usb/gadget/f_eem.c b/drivers/usb/gadget/f_eem.c index 046c6d0e6960..1a7b2dd7d408 100644 --- a/drivers/usb/gadget/f_eem.c +++ b/drivers/usb/gadget/f_eem.c @@ -9,15 +9,6 @@ * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include diff --git a/drivers/usb/gadget/f_fs.c b/drivers/usb/gadget/f_fs.c index c161a9aaeb7e..6b1c20b6c9b2 100644 --- a/drivers/usb/gadget/f_fs.c +++ b/drivers/usb/gadget/f_fs.c @@ -12,15 +12,6 @@ * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ diff --git a/drivers/usb/gadget/f_hid.c b/drivers/usb/gadget/f_hid.c index 83a266bdb40e..b2113420b806 100644 --- a/drivers/usb/gadget/f_hid.c +++ b/drivers/usb/gadget/f_hid.c @@ -7,15 +7,6 @@ * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include diff --git a/drivers/usb/gadget/f_loopback.c b/drivers/usb/gadget/f_loopback.c index ca660d40b11a..6d87f288df4e 100644 --- a/drivers/usb/gadget/f_loopback.c +++ b/drivers/usb/gadget/f_loopback.c @@ -8,15 +8,6 @@ * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* #define VERBOSE_DEBUG */ diff --git a/drivers/usb/gadget/f_ncm.c b/drivers/usb/gadget/f_ncm.c index ae69ed7e6b99..aab8eded045b 100644 --- a/drivers/usb/gadget/f_ncm.c +++ b/drivers/usb/gadget/f_ncm.c @@ -13,15 +13,6 @@ * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include diff --git a/drivers/usb/gadget/f_obex.c b/drivers/usb/gadget/f_obex.c index 394502abeb96..e3f74bf5da2d 100644 --- a/drivers/usb/gadget/f_obex.c +++ b/drivers/usb/gadget/f_obex.c @@ -10,15 +10,6 @@ * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* #define VERBOSE_DEBUG */ diff --git a/drivers/usb/gadget/f_phonet.c b/drivers/usb/gadget/f_phonet.c index 8f3eab1af885..349077033338 100644 --- a/drivers/usb/gadget/f_phonet.c +++ b/drivers/usb/gadget/f_phonet.c @@ -8,16 +8,6 @@ * 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., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA */ #include diff --git a/drivers/usb/gadget/f_rndis.c b/drivers/usb/gadget/f_rndis.c index 3ea4666be3d0..704d1d94f72a 100644 --- a/drivers/usb/gadget/f_rndis.c +++ b/drivers/usb/gadget/f_rndis.c @@ -11,15 +11,6 @@ * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* #define VERBOSE_DEBUG */ diff --git a/drivers/usb/gadget/f_sourcesink.c b/drivers/usb/gadget/f_sourcesink.c index e18b4f520951..168906d2b5d4 100644 --- a/drivers/usb/gadget/f_sourcesink.c +++ b/drivers/usb/gadget/f_sourcesink.c @@ -8,15 +8,6 @@ * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* #define VERBOSE_DEBUG */ diff --git a/drivers/usb/gadget/f_subset.c b/drivers/usb/gadget/f_subset.c index 3dc53754ab60..c1540648125a 100644 --- a/drivers/usb/gadget/f_subset.c +++ b/drivers/usb/gadget/f_subset.c @@ -8,15 +8,6 @@ * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include diff --git a/drivers/usb/gadget/f_uvc.c b/drivers/usb/gadget/f_uvc.c index 7a8b9aa4aea5..2022fe492148 100644 --- a/drivers/usb/gadget/f_uvc.c +++ b/drivers/usb/gadget/f_uvc.c @@ -8,7 +8,6 @@ * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * */ #include diff --git a/drivers/usb/gadget/f_uvc.h b/drivers/usb/gadget/f_uvc.h index e18a6636c283..abf832935134 100644 --- a/drivers/usb/gadget/f_uvc.h +++ b/drivers/usb/gadget/f_uvc.h @@ -8,7 +8,6 @@ * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * */ #ifndef _F_UVC_H_ diff --git a/drivers/usb/gadget/fusb300_udc.c b/drivers/usb/gadget/fusb300_udc.c index d9ee6c37a6c1..cd9cbba8c063 100644 --- a/drivers/usb/gadget/fusb300_udc.c +++ b/drivers/usb/gadget/fusb300_udc.c @@ -8,16 +8,6 @@ * 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 #include diff --git a/drivers/usb/gadget/fusb300_udc.h b/drivers/usb/gadget/fusb300_udc.h index f51aa2ef1f90..92745bd03064 100644 --- a/drivers/usb/gadget/fusb300_udc.h +++ b/drivers/usb/gadget/fusb300_udc.h @@ -8,16 +8,6 @@ * 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 - * */ diff --git a/drivers/usb/gadget/g_ffs.c b/drivers/usb/gadget/g_ffs.c index 704c2800ac00..0519d77915ec 100644 --- a/drivers/usb/gadget/g_ffs.c +++ b/drivers/usb/gadget/g_ffs.c @@ -8,15 +8,6 @@ * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #define pr_fmt(fmt) "g_ffs: " fmt diff --git a/drivers/usb/gadget/hid.c b/drivers/usb/gadget/hid.c index 9fb575034a0e..f888c3ede860 100644 --- a/drivers/usb/gadget/hid.c +++ b/drivers/usb/gadget/hid.c @@ -9,15 +9,6 @@ * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ diff --git a/drivers/usb/gadget/imx_udc.h b/drivers/usb/gadget/imx_udc.h index 7136c242b4ec..d118fb777840 100644 --- a/drivers/usb/gadget/imx_udc.h +++ b/drivers/usb/gadget/imx_udc.h @@ -8,11 +8,6 @@ * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #ifndef __LINUX_USB_GADGET_IMX_H diff --git a/drivers/usb/gadget/inode.c b/drivers/usb/gadget/inode.c index 1b240990448f..a392ec0d2d51 100644 --- a/drivers/usb/gadget/inode.c +++ b/drivers/usb/gadget/inode.c @@ -8,15 +8,6 @@ * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ diff --git a/drivers/usb/gadget/langwell_udc.c b/drivers/usb/gadget/langwell_udc.c index 5bf9942eb454..6e444995d398 100644 --- a/drivers/usb/gadget/langwell_udc.c +++ b/drivers/usb/gadget/langwell_udc.c @@ -5,16 +5,6 @@ * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope 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. - * */ diff --git a/drivers/usb/gadget/langwell_udc.h b/drivers/usb/gadget/langwell_udc.h index f1d9c1bb04f3..1bec66f95c36 100644 --- a/drivers/usb/gadget/langwell_udc.h +++ b/drivers/usb/gadget/langwell_udc.h @@ -5,16 +5,6 @@ * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope 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 diff --git a/drivers/usb/gadget/m66592-udc.c b/drivers/usb/gadget/m66592-udc.c index 5e597c3c44f3..c27e5e8f54d0 100644 --- a/drivers/usb/gadget/m66592-udc.c +++ b/drivers/usb/gadget/m66592-udc.c @@ -8,16 +8,6 @@ * 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 diff --git a/drivers/usb/gadget/m66592-udc.h b/drivers/usb/gadget/m66592-udc.h index 7b93d579af37..9d9f7e39f037 100644 --- a/drivers/usb/gadget/m66592-udc.h +++ b/drivers/usb/gadget/m66592-udc.h @@ -8,16 +8,6 @@ * 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 - * */ #ifndef __M66592_UDC_H__ diff --git a/drivers/usb/gadget/mass_storage.c b/drivers/usb/gadget/mass_storage.c index d3eb27427c58..d2a9dcb67088 100644 --- a/drivers/usb/gadget/mass_storage.c +++ b/drivers/usb/gadget/mass_storage.c @@ -10,15 +10,6 @@ * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ diff --git a/drivers/usb/gadget/multi.c b/drivers/usb/gadget/multi.c index 8c7b74717d85..7e7f515b8b19 100644 --- a/drivers/usb/gadget/multi.c +++ b/drivers/usb/gadget/multi.c @@ -10,15 +10,6 @@ * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ diff --git a/drivers/usb/gadget/ncm.c b/drivers/usb/gadget/ncm.c index 62ee5087dcac..89530034dff1 100644 --- a/drivers/usb/gadget/ncm.c +++ b/drivers/usb/gadget/ncm.c @@ -14,15 +14,6 @@ * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* #define DEBUG */ diff --git a/drivers/usb/gadget/ndis.h b/drivers/usb/gadget/ndis.h index df886cec5ef4..b0e52fc277b4 100644 --- a/drivers/usb/gadget/ndis.h +++ b/drivers/usb/gadget/ndis.h @@ -10,12 +10,6 @@ * * This source code is offered for use in the public domain. You may * use, modify or distribute it freely. - * - * This code is distributed in the hope that it will be useful but - * WITHOUT ANY WARRANTY. ALL WARRANTIES, EXPRESS OR IMPLIED ARE HEREBY - * DISCLAIMED. This includes but is not limited to warranties of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * */ #ifndef _LINUX_NDIS_H diff --git a/drivers/usb/gadget/net2280.c b/drivers/usb/gadget/net2280.c index 8d3673fadfe1..3c14c4ea8efd 100644 --- a/drivers/usb/gadget/net2280.c +++ b/drivers/usb/gadget/net2280.c @@ -33,15 +33,6 @@ * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #undef DEBUG /* messages on error and most fault paths */ diff --git a/drivers/usb/gadget/net2280.h b/drivers/usb/gadget/net2280.h index c36852263d93..a844be0d683a 100644 --- a/drivers/usb/gadget/net2280.h +++ b/drivers/usb/gadget/net2280.h @@ -11,15 +11,6 @@ * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include diff --git a/drivers/usb/gadget/omap_udc.c b/drivers/usb/gadget/omap_udc.c index b7a7799ddd4f..ae9c89b5801a 100644 --- a/drivers/usb/gadget/omap_udc.c +++ b/drivers/usb/gadget/omap_udc.c @@ -10,15 +10,6 @@ * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #undef DEBUG diff --git a/drivers/usb/gadget/pch_udc.c b/drivers/usb/gadget/pch_udc.c index b69ae3eec687..550d6dcdf104 100644 --- a/drivers/usb/gadget/pch_udc.c +++ b/drivers/usb/gadget/pch_udc.c @@ -4,15 +4,6 @@ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include diff --git a/drivers/usb/gadget/printer.c b/drivers/usb/gadget/printer.c index a341dde6f9c3..5d3e697b7d5d 100644 --- a/drivers/usb/gadget/printer.c +++ b/drivers/usb/gadget/printer.c @@ -8,15 +8,6 @@ * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include diff --git a/drivers/usb/gadget/pxa25x_udc.c b/drivers/usb/gadget/pxa25x_udc.c index 7862465291d1..a33fc1792641 100644 --- a/drivers/usb/gadget/pxa25x_udc.c +++ b/drivers/usb/gadget/pxa25x_udc.c @@ -11,16 +11,6 @@ * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * */ /* #define VERBOSE_DEBUG */ diff --git a/drivers/usb/gadget/pxa25x_udc.h b/drivers/usb/gadget/pxa25x_udc.h index f572c5617462..4634cd361f29 100644 --- a/drivers/usb/gadget/pxa25x_udc.h +++ b/drivers/usb/gadget/pxa25x_udc.h @@ -9,15 +9,6 @@ * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef __LINUX_USB_GADGET_PXA25X_H diff --git a/drivers/usb/gadget/pxa27x_udc.c b/drivers/usb/gadget/pxa27x_udc.c index d21455f457e2..18b6b091f2a6 100644 --- a/drivers/usb/gadget/pxa27x_udc.c +++ b/drivers/usb/gadget/pxa27x_udc.c @@ -8,16 +8,6 @@ * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * */ #include #include diff --git a/drivers/usb/gadget/pxa27x_udc.h b/drivers/usb/gadget/pxa27x_udc.h index b01696eab068..7f4e8f424e80 100644 --- a/drivers/usb/gadget/pxa27x_udc.h +++ b/drivers/usb/gadget/pxa27x_udc.h @@ -9,15 +9,6 @@ * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef __LINUX_USB_GADGET_PXA27X_H diff --git a/drivers/usb/gadget/r8a66597-udc.c b/drivers/usb/gadget/r8a66597-udc.c index 61d0c65802e8..bca3f415d20d 100644 --- a/drivers/usb/gadget/r8a66597-udc.c +++ b/drivers/usb/gadget/r8a66597-udc.c @@ -8,16 +8,6 @@ * 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 diff --git a/drivers/usb/gadget/r8a66597-udc.h b/drivers/usb/gadget/r8a66597-udc.h index 503f766c23a7..a373c4e64b44 100644 --- a/drivers/usb/gadget/r8a66597-udc.h +++ b/drivers/usb/gadget/r8a66597-udc.h @@ -8,16 +8,6 @@ * 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 - * */ #ifndef __R8A66597_H__ diff --git a/drivers/usb/gadget/s3c2410_udc.c b/drivers/usb/gadget/s3c2410_udc.c index 257285448678..3f587b0411b0 100644 --- a/drivers/usb/gadget/s3c2410_udc.c +++ b/drivers/usb/gadget/s3c2410_udc.c @@ -10,16 +10,6 @@ * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * */ #include diff --git a/drivers/usb/gadget/s3c2410_udc.h b/drivers/usb/gadget/s3c2410_udc.h index 9e0bece4f241..a48f619cb1cc 100644 --- a/drivers/usb/gadget/s3c2410_udc.h +++ b/drivers/usb/gadget/s3c2410_udc.h @@ -9,16 +9,6 @@ * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * */ #ifndef _S3C2410_UDC_H diff --git a/drivers/usb/gadget/storage_common.c b/drivers/usb/gadget/storage_common.c index d3dd227a2bfc..571d9730fca9 100644 --- a/drivers/usb/gadget/storage_common.c +++ b/drivers/usb/gadget/storage_common.c @@ -9,15 +9,6 @@ * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ diff --git a/drivers/usb/gadget/u_ether.c b/drivers/usb/gadget/u_ether.c index dfed4c1d96c0..29c854bbca44 100644 --- a/drivers/usb/gadget/u_ether.c +++ b/drivers/usb/gadget/u_ether.c @@ -9,15 +9,6 @@ * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* #define VERBOSE_DEBUG */ diff --git a/drivers/usb/gadget/u_ether.h b/drivers/usb/gadget/u_ether.h index c966440ddd70..8012357e98aa 100644 --- a/drivers/usb/gadget/u_ether.h +++ b/drivers/usb/gadget/u_ether.h @@ -9,15 +9,6 @@ * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef __U_ETHER_H diff --git a/drivers/usb/gadget/uvc.h b/drivers/usb/gadget/uvc.h index 5b7919460fd2..b80d5143b279 100644 --- a/drivers/usb/gadget/uvc.h +++ b/drivers/usb/gadget/uvc.h @@ -8,7 +8,6 @@ * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * */ #ifndef _UVC_GADGET_H_ diff --git a/drivers/usb/gadget/uvc_queue.c b/drivers/usb/gadget/uvc_queue.c index aa0ad34e0f1f..d776adb2da67 100644 --- a/drivers/usb/gadget/uvc_queue.c +++ b/drivers/usb/gadget/uvc_queue.c @@ -8,7 +8,6 @@ * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * */ #include diff --git a/drivers/usb/gadget/uvc_v4l2.c b/drivers/usb/gadget/uvc_v4l2.c index 52f8f9e513af..927291c8087c 100644 --- a/drivers/usb/gadget/uvc_v4l2.c +++ b/drivers/usb/gadget/uvc_v4l2.c @@ -8,7 +8,6 @@ * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * */ #include diff --git a/drivers/usb/gadget/uvc_video.c b/drivers/usb/gadget/uvc_video.c index b08f35438d70..b0e53a8ea4f7 100644 --- a/drivers/usb/gadget/uvc_video.c +++ b/drivers/usb/gadget/uvc_video.c @@ -8,7 +8,6 @@ * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * */ #include diff --git a/drivers/usb/gadget/webcam.c b/drivers/usb/gadget/webcam.c index df6882de50bf..668fe128f2ef 100644 --- a/drivers/usb/gadget/webcam.c +++ b/drivers/usb/gadget/webcam.c @@ -8,8 +8,8 @@ * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * */ + #include #include #include diff --git a/drivers/usb/gadget/zero.c b/drivers/usb/gadget/zero.c index 00e2fd2d4791..20697cc132d1 100644 --- a/drivers/usb/gadget/zero.c +++ b/drivers/usb/gadget/zero.c @@ -8,15 +8,6 @@ * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -- cgit From e538dfdae85244fd2c4231725d82cc1f1bc4942c Mon Sep 17 00:00:00 2001 From: Michal Nazarewicz Date: Tue, 30 Aug 2011 17:11:19 +0200 Subject: usb: Provide usb_speed_string() function In a few places in the kernel, the code prints a human-readable USB device speed (eg. "high speed"). This involves a switch statement sometimes wrapped around in ({ ... }) block leading to code repetition. To mitigate this issue, this commit introduces usb_speed_string() function, which returns a human-readable name of provided speed. It also changes a few places switch was used to use this new function. This changes a bit the way the speed is printed in few instances at the same time standardising it. Signed-off-by: Michal Nazarewicz Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/amd5536udc.c | 9 ++----- drivers/usb/gadget/atmel_usba_udc.c | 9 +++---- drivers/usb/gadget/composite.c | 22 +++------------ drivers/usb/gadget/file_storage.c | 15 +++-------- drivers/usb/gadget/fsl_udc_core.c | 53 +++++++++++++------------------------ drivers/usb/gadget/gmidi.c | 11 +------- drivers/usb/gadget/langwell_udc.c | 50 ++++++++++++---------------------- drivers/usb/gadget/net2272.c | 4 +-- drivers/usb/gadget/net2280.c | 4 +-- drivers/usb/gadget/printer.c | 14 +++------- drivers/usb/gadget/s3c-hsotg.c | 8 ++---- drivers/usb/gadget/udc-core.c | 19 ++----------- 12 files changed, 60 insertions(+), 158 deletions(-) (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/amd5536udc.c b/drivers/usb/gadget/amd5536udc.c index ded8d6fddb53..4730016d7cd4 100644 --- a/drivers/usb/gadget/amd5536udc.c +++ b/drivers/usb/gadget/amd5536udc.c @@ -3005,13 +3005,8 @@ __acquires(dev->lock) /* link up all endpoints */ udc_setup_endpoints(dev); - if (dev->gadget.speed == USB_SPEED_HIGH) { - dev_info(&dev->pdev->dev, "Connect: speed = %s\n", - "high"); - } else if (dev->gadget.speed == USB_SPEED_FULL) { - dev_info(&dev->pdev->dev, "Connect: speed = %s\n", - "full"); - } + dev_info(&dev->pdev->dev, "Connect: %s\n", + usb_speed_string(dev->gadget.speed)); /* init ep 0 */ activate_control_endpoints(dev); diff --git a/drivers/usb/gadget/atmel_usba_udc.c b/drivers/usb/gadget/atmel_usba_udc.c index 722c468e9b3c..271a9d873608 100644 --- a/drivers/usb/gadget/atmel_usba_udc.c +++ b/drivers/usb/gadget/atmel_usba_udc.c @@ -1718,13 +1718,12 @@ static irqreturn_t usba_udc_irq(int irq, void *devid) spin_lock(&udc->lock); } - if (status & USBA_HIGH_SPEED) { - DBG(DBG_BUS, "High-speed bus reset detected\n"); + if (status & USBA_HIGH_SPEED) udc->gadget.speed = USB_SPEED_HIGH; - } else { - DBG(DBG_BUS, "Full-speed bus reset detected\n"); + else udc->gadget.speed = USB_SPEED_FULL; - } + DBG(DBG_BUS, "%s bus reset detected\n", + usb_speed_string(udc->gadget.speed)); ep0 = &usba_ep[0]; ep0->desc = &usba_ep0_desc; diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c index c77aca11ad53..e74fd55c33d9 100644 --- a/drivers/usb/gadget/composite.c +++ b/drivers/usb/gadget/composite.c @@ -617,25 +617,9 @@ static int set_config(struct usb_composite_dev *cdev, result = 0; } - INFO(cdev, "%s speed config #%d: %s\n", - ({ char *speed; - switch (gadget->speed) { - case USB_SPEED_LOW: - speed = "low"; - break; - case USB_SPEED_FULL: - speed = "full"; - break; - case USB_SPEED_HIGH: - speed = "high"; - break; - case USB_SPEED_SUPER: - speed = "super"; - break; - default: - speed = "?"; - break; - } ; speed; }), number, c ? c->label : "unconfigured"); + INFO(cdev, "%s config #%d: %s\n", + usb_speed_string(gadget->speed), + number, c ? c->label : "unconfigured"); if (!c) goto done; diff --git a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c index 39ece40a045f..4ac8084b579c 100644 --- a/drivers/usb/gadget/file_storage.c +++ b/drivers/usb/gadget/file_storage.c @@ -2862,17 +2862,10 @@ static int do_set_config(struct fsg_dev *fsg, u8 new_config) fsg->config = new_config; if ((rc = do_set_interface(fsg, 0)) != 0) fsg->config = 0; // Reset on errors - else { - char *speed; - - switch (fsg->gadget->speed) { - case USB_SPEED_LOW: speed = "low"; break; - case USB_SPEED_FULL: speed = "full"; break; - case USB_SPEED_HIGH: speed = "high"; break; - default: speed = "?"; break; - } - INFO(fsg, "%s speed config #%d\n", speed, fsg->config); - } + else + INFO(fsg, "%s config #%d\n", + usb_speed_string(fsg->gadget->speed), + fsg->config); } return rc; } diff --git a/drivers/usb/gadget/fsl_udc_core.c b/drivers/usb/gadget/fsl_udc_core.c index d6993507165b..b2c44e1d5813 100644 --- a/drivers/usb/gadget/fsl_udc_core.c +++ b/drivers/usb/gadget/fsl_udc_core.c @@ -1715,34 +1715,31 @@ static void dtd_complete_irq(struct fsl_udc *udc) } } +static inline enum usb_device_speed portscx_device_speed(u32 reg) +{ + switch (speed & PORTSCX_PORT_SPEED_MASK) { + case PORTSCX_PORT_SPEED_HIGH: + return USB_SPEED_HIGH; + case PORTSCX_PORT_SPEED_FULL: + return USB_SPEED_FULL; + case PORTSCX_PORT_SPEED_LOW: + return USB_SPEED_LOW; + default: + return USB_SPEED_UNKNOWN; + } +} + /* Process a port change interrupt */ static void port_change_irq(struct fsl_udc *udc) { - u32 speed; - if (udc->bus_reset) udc->bus_reset = 0; /* Bus resetting is finished */ - if (!(fsl_readl(&dr_regs->portsc1) & PORTSCX_PORT_RESET)) { + if (!(fsl_readl(&dr_regs->portsc1) & PORTSCX_PORT_RESET)) /* Get the speed */ - speed = (fsl_readl(&dr_regs->portsc1) - & PORTSCX_PORT_SPEED_MASK); - switch (speed) { - case PORTSCX_PORT_SPEED_HIGH: - udc->gadget.speed = USB_SPEED_HIGH; - break; - case PORTSCX_PORT_SPEED_FULL: - udc->gadget.speed = USB_SPEED_FULL; - break; - case PORTSCX_PORT_SPEED_LOW: - udc->gadget.speed = USB_SPEED_LOW; - break; - default: - udc->gadget.speed = USB_SPEED_UNKNOWN; - break; - } - } + udc->gadget.speed = + portscx_device_speed(fsl_readl(&dr_regs->portsc1)); /* Update USB state */ if (!udc->resume_state) @@ -2167,20 +2164,8 @@ static int fsl_proc_read(char *page, char **start, off_t off, int count, default: s = "None"; break; } - s;} ), ( { - char *s; - switch (tmp_reg & PORTSCX_PORT_SPEED_UNDEF) { - case PORTSCX_PORT_SPEED_FULL: - s = "Full Speed"; break; - case PORTSCX_PORT_SPEED_LOW: - s = "Low Speed"; break; - case PORTSCX_PORT_SPEED_HIGH: - s = "High Speed"; break; - default: - s = "Undefined"; break; - } - s; - } ), + s;} ), + usb_speed_string(portscx_device_speed(tmp_reg)), (tmp_reg & PORTSCX_PHY_LOW_POWER_SPD) ? "Normal PHY mode" : "Low power mode", (tmp_reg & PORTSCX_PORT_RESET) ? "In Reset" : diff --git a/drivers/usb/gadget/gmidi.c b/drivers/usb/gadget/gmidi.c index 8b9220e128a7..893b967b0aff 100644 --- a/drivers/usb/gadget/gmidi.c +++ b/drivers/usb/gadget/gmidi.c @@ -640,17 +640,8 @@ gmidi_set_config(struct gmidi_device *dev, unsigned number, gfp_t gfp_flags) if (result) { gmidi_reset_config(dev); } else { - char *speed; - - switch (gadget->speed) { - case USB_SPEED_LOW: speed = "low"; break; - case USB_SPEED_FULL: speed = "full"; break; - case USB_SPEED_HIGH: speed = "high"; break; - default: speed = "?"; break; - } - dev->config = number; - INFO(dev, "%s speed\n", speed); + INFO(dev, "%s speed\n", usb_speed_string(gadget->speed)); } return result; } diff --git a/drivers/usb/gadget/langwell_udc.c b/drivers/usb/gadget/langwell_udc.c index 6e444995d398..c88158f307a8 100644 --- a/drivers/usb/gadget/langwell_udc.c +++ b/drivers/usb/gadget/langwell_udc.c @@ -1690,20 +1690,7 @@ static ssize_t show_langwell_udc(struct device *_dev, "BmAttributes: %d\n\n", LPM_PTS(tmp_reg), (tmp_reg & LPM_STS) ? 1 : 0, - ({ - char *s; - switch (LPM_PSPD(tmp_reg)) { - case LPM_SPEED_FULL: - s = "Full Speed"; break; - case LPM_SPEED_LOW: - s = "Low Speed"; break; - case LPM_SPEED_HIGH: - s = "High Speed"; break; - default: - s = "Unknown Speed"; break; - } - s; - }), + usb_speed_string(lpm_device_speed(tmp_reg)), (tmp_reg & LPM_PFSC) ? "Force Full Speed" : "Not Force", (tmp_reg & LPM_PHCD) ? "Disabled" : "Enabled", LPM_BA(tmp_reg)); @@ -2647,12 +2634,24 @@ done: dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__); } +static inline enum usb_device_speed lpm_device_speed(u32 reg) +{ + switch (LPM_PSPD(reg)) { + case LPM_SPEED_HIGH: + return USB_SPEED_HIGH; + case LPM_SPEED_FULL: + return USB_SPEED_FULL; + case LPM_SPEED_LOW: + return USB_SPEED_LOW; + default: + return USB_SPEED_UNKNOWN; + } +} /* port change detect interrupt handler */ static void handle_port_change(struct langwell_udc *dev) { u32 portsc1, devlc; - u32 speed; dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__); @@ -2667,24 +2666,9 @@ static void handle_port_change(struct langwell_udc *dev) /* bus reset is finished */ if (!(portsc1 & PORTS_PR)) { /* get the speed */ - speed = LPM_PSPD(devlc); - switch (speed) { - case LPM_SPEED_HIGH: - dev->gadget.speed = USB_SPEED_HIGH; - break; - case LPM_SPEED_FULL: - dev->gadget.speed = USB_SPEED_FULL; - break; - case LPM_SPEED_LOW: - dev->gadget.speed = USB_SPEED_LOW; - break; - default: - dev->gadget.speed = USB_SPEED_UNKNOWN; - break; - } - dev_vdbg(&dev->pdev->dev, - "speed = %d, dev->gadget.speed = %d\n", - speed, dev->gadget.speed); + dev->gadget.speed = lpm_device_speed(devlc); + dev_vdbg(&dev->pdev->dev, "dev->gadget.speed = %d\n", + dev->gadget.speed); } /* LPM L0 to L1 */ diff --git a/drivers/usb/gadget/net2272.c b/drivers/usb/gadget/net2272.c index 6fef1c02448e..08a4a36550d2 100644 --- a/drivers/usb/gadget/net2272.c +++ b/drivers/usb/gadget/net2272.c @@ -1764,8 +1764,8 @@ net2272_handle_stat0_irqs(struct net2272 *dev, u8 stat) dev->gadget.speed = USB_SPEED_HIGH; else dev->gadget.speed = USB_SPEED_FULL; - dev_dbg(dev->dev, "%s speed\n", - (dev->gadget.speed == USB_SPEED_HIGH) ? "high" : "full"); + dev_dbg(dev->dev, "%s\n", + usb_speed_string(dev->gadget.speed)); } ep = &dev->ep[0]; diff --git a/drivers/usb/gadget/net2280.c b/drivers/usb/gadget/net2280.c index 3c14c4ea8efd..db508d0bb3af 100644 --- a/drivers/usb/gadget/net2280.c +++ b/drivers/usb/gadget/net2280.c @@ -2257,9 +2257,7 @@ static void handle_stat0_irqs (struct net2280 *dev, u32 stat) else dev->gadget.speed = USB_SPEED_FULL; net2280_led_speed (dev, dev->gadget.speed); - DEBUG (dev, "%s speed\n", - (dev->gadget.speed == USB_SPEED_HIGH) - ? "high" : "full"); + DEBUG(dev, "%s\n", usb_speed_string(dev->gadget.speed)); } ep = &dev->ep [0]; diff --git a/drivers/usb/gadget/printer.c b/drivers/usb/gadget/printer.c index 5d3e697b7d5d..68a0efbc2719 100644 --- a/drivers/usb/gadget/printer.c +++ b/drivers/usb/gadget/printer.c @@ -962,23 +962,15 @@ printer_set_config(struct printer_dev *dev, unsigned number) usb_gadget_vbus_draw(dev->gadget, dev->gadget->is_otg ? 8 : 100); } else { - char *speed; unsigned power; power = 2 * config_desc.bMaxPower; usb_gadget_vbus_draw(dev->gadget, power); - switch (gadget->speed) { - case USB_SPEED_FULL: speed = "full"; break; -#ifdef CONFIG_USB_GADGET_DUALSPEED - case USB_SPEED_HIGH: speed = "high"; break; -#endif - default: speed = "?"; break; - } - dev->config = number; - INFO(dev, "%s speed config #%d: %d mA, %s\n", - speed, number, power, driver_desc); + INFO(dev, "%s config #%d: %d mA, %s\n", + usb_speed_string(gadget->speed), + number, power, driver_desc); } return result; } diff --git a/drivers/usb/gadget/s3c-hsotg.c b/drivers/usb/gadget/s3c-hsotg.c index 39b134dec94c..a552453dc946 100644 --- a/drivers/usb/gadget/s3c-hsotg.c +++ b/drivers/usb/gadget/s3c-hsotg.c @@ -1951,30 +1951,26 @@ static void s3c_hsotg_irq_enumdone(struct s3c_hsotg *hsotg) case S3C_DSTS_EnumSpd_FS: case S3C_DSTS_EnumSpd_FS48: hsotg->gadget.speed = USB_SPEED_FULL; - dev_info(hsotg->dev, "new device is full-speed\n"); - ep0_mps = EP0_MPS_LIMIT; ep_mps = 64; break; case S3C_DSTS_EnumSpd_HS: - dev_info(hsotg->dev, "new device is high-speed\n"); hsotg->gadget.speed = USB_SPEED_HIGH; - ep0_mps = EP0_MPS_LIMIT; ep_mps = 512; break; case S3C_DSTS_EnumSpd_LS: hsotg->gadget.speed = USB_SPEED_LOW; - dev_info(hsotg->dev, "new device is low-speed\n"); - /* note, we don't actually support LS in this driver at the * moment, and the documentation seems to imply that it isn't * supported by the PHYs on some of the devices. */ break; } + dev_info(hsotg->dev, "new device is %s\n", + usb_speed_string(hsotg->gadget.speed)); /* we should now know the maximum packet size for an * endpoint, so set the endpoints to a default value. */ diff --git a/drivers/usb/gadget/udc-core.c b/drivers/usb/gadget/udc-core.c index 05ba47214361..5e77a46a429a 100644 --- a/drivers/usb/gadget/udc-core.c +++ b/drivers/usb/gadget/udc-core.c @@ -375,23 +375,8 @@ static ssize_t usb_udc_speed_show(struct device *dev, struct device_attribute *attr, char *buf) { struct usb_udc *udc = container_of(dev, struct usb_udc, dev); - struct usb_gadget *gadget = udc->gadget; - - switch (gadget->speed) { - case USB_SPEED_LOW: - return snprintf(buf, PAGE_SIZE, "low-speed\n"); - case USB_SPEED_FULL: - return snprintf(buf, PAGE_SIZE, "full-speed\n"); - case USB_SPEED_HIGH: - return snprintf(buf, PAGE_SIZE, "high-speed\n"); - case USB_SPEED_WIRELESS: - return snprintf(buf, PAGE_SIZE, "wireless\n"); - case USB_SPEED_SUPER: - return snprintf(buf, PAGE_SIZE, "super-speed\n"); - case USB_SPEED_UNKNOWN: /* FALLTHROUGH */ - default: - return snprintf(buf, PAGE_SIZE, "UNKNOWN\n"); - } + return snprintf(buf, PAGE_SIZE, "%s\n", + usb_speed_string(udc->gadget->speed)); } static DEVICE_ATTR(speed, S_IRUSR, usb_udc_speed_show, NULL); -- cgit From fba9e546eac984d46c4a16253344d7297c24d75c Mon Sep 17 00:00:00 2001 From: Heiko Stübner Date: Sun, 4 Sep 2011 21:56:02 +0200 Subject: s3c-hsudc: implement vbus_draw hook When a transceiver is available use otg_set_power to submit the target current to it. Signed-off-by: Heiko Stuebner Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/s3c-hsudc.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/s3c-hsudc.c b/drivers/usb/gadget/s3c-hsudc.c index 25829b4398da..8d54f893cefe 100644 --- a/drivers/usb/gadget/s3c-hsudc.c +++ b/drivers/usb/gadget/s3c-hsudc.c @@ -1241,10 +1241,24 @@ static int s3c_hsudc_gadget_getframe(struct usb_gadget *gadget) return s3c_hsudc_read_frameno(to_hsudc(gadget)); } +static int s3c_hsudc_vbus_draw(struct usb_gadget *gadget, unsigned mA) +{ + struct s3c_hsudc *hsudc = the_controller; + + if (!hsudc) + return -ENODEV; + + if (hsudc->transceiver) + return otg_set_power(hsudc->transceiver, mA); + + return -EOPNOTSUPP; +} + static struct usb_gadget_ops s3c_hsudc_gadget_ops = { .get_frame = s3c_hsudc_gadget_getframe, .start = s3c_hsudc_start, .stop = s3c_hsudc_stop, + .vbus_draw = s3c_hsudc_vbus_draw, }; static int s3c_hsudc_probe(struct platform_device *pdev) -- cgit From 8582d86143c690c68cc42f996def466a035bee34 Mon Sep 17 00:00:00 2001 From: Fabian Godehardt Date: Thu, 1 Sep 2011 14:15:46 +0200 Subject: USB: g_printer: fix bug in unregistration The allocated chardevice region range is only 1 device but on unregister it currently tries to deregister 2. Found this while doing a insmod/rmmod/insmod/rm... of the module which seemed to eat major numbers. Signed-off-by: Fabian Godehardt Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/printer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/printer.c b/drivers/usb/gadget/printer.c index 68a0efbc2719..65a8834f274b 100644 --- a/drivers/usb/gadget/printer.c +++ b/drivers/usb/gadget/printer.c @@ -1594,7 +1594,7 @@ cleanup(void) if (status) ERROR(dev, "usb_gadget_unregister_driver %x\n", status); - unregister_chrdev_region(g_printer_devno, 2); + unregister_chrdev_region(g_printer_devno, 1); class_destroy(usb_gadget_class); mutex_unlock(&usb_printer_gadget.lock_printer_io); } -- cgit From b5dd18d8747010e3f3eb1cc76a49f94291938559 Mon Sep 17 00:00:00 2001 From: Yong Zhang Date: Wed, 7 Sep 2011 16:10:52 +0800 Subject: USB: irq: Remove IRQF_DISABLED This flag is a NOOP and can be removed now. Signed-off-by: Yong Zhang Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/at91_udc.c | 4 ++-- drivers/usb/gadget/fusb300_udc.c | 4 ++-- drivers/usb/gadget/imx_udc.c | 2 +- drivers/usb/gadget/m66592-udc.c | 2 +- drivers/usb/gadget/mv_udc_core.c | 2 +- drivers/usb/gadget/omap_udc.c | 2 +- drivers/usb/gadget/pxa25x_udc.c | 6 +++--- drivers/usb/gadget/r8a66597-udc.c | 2 +- drivers/usb/gadget/s3c2410_udc.c | 4 ++-- 9 files changed, 14 insertions(+), 14 deletions(-) (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/at91_udc.c b/drivers/usb/gadget/at91_udc.c index 0a1b6d10ab7a..e10cf3c63929 100644 --- a/drivers/usb/gadget/at91_udc.c +++ b/drivers/usb/gadget/at91_udc.c @@ -1810,7 +1810,7 @@ static int __init at91udc_probe(struct platform_device *pdev) /* request UDC and maybe VBUS irqs */ udc->udp_irq = platform_get_irq(pdev, 0); retval = request_irq(udc->udp_irq, at91_udc_irq, - IRQF_DISABLED, driver_name, udc); + 0, driver_name, udc); if (retval < 0) { DBG("request irq %d failed\n", udc->udp_irq); goto fail1; @@ -1838,7 +1838,7 @@ static int __init at91udc_probe(struct platform_device *pdev) jiffies + VBUS_POLL_TIMEOUT); } else { if (request_irq(udc->board.vbus_pin, at91_vbus_irq, - IRQF_DISABLED, driver_name, udc)) { + 0, driver_name, udc)) { DBG("request vbus irq %d failed\n", udc->board.vbus_pin); retval = -EBUSY; diff --git a/drivers/usb/gadget/fusb300_udc.c b/drivers/usb/gadget/fusb300_udc.c index cd9cbba8c063..e593f2849fa9 100644 --- a/drivers/usb/gadget/fusb300_udc.c +++ b/drivers/usb/gadget/fusb300_udc.c @@ -1469,7 +1469,7 @@ static int __init fusb300_probe(struct platform_device *pdev) fusb300->gadget.name = udc_name; fusb300->reg = reg; - ret = request_irq(ires->start, fusb300_irq, IRQF_DISABLED | IRQF_SHARED, + ret = request_irq(ires->start, fusb300_irq, IRQF_SHARED, udc_name, fusb300); if (ret < 0) { pr_err("request_irq error (%d)\n", ret); @@ -1477,7 +1477,7 @@ static int __init fusb300_probe(struct platform_device *pdev) } ret = request_irq(ires1->start, fusb300_irq, - IRQF_DISABLED | IRQF_SHARED, udc_name, fusb300); + IRQF_SHARED, udc_name, fusb300); if (ret < 0) { pr_err("request_irq1 error (%d)\n", ret); goto clean_up; diff --git a/drivers/usb/gadget/imx_udc.c b/drivers/usb/gadget/imx_udc.c index bf08bfcd90b8..2d978c0e7ced 100644 --- a/drivers/usb/gadget/imx_udc.c +++ b/drivers/usb/gadget/imx_udc.c @@ -1478,7 +1478,7 @@ static int __init imx_udc_probe(struct platform_device *pdev) for (i = 0; i < IMX_USB_NB_EP + 1; i++) { ret = request_irq(imx_usb->usbd_int[i], intr_handler(i), - IRQF_DISABLED, driver_name, imx_usb); + 0, driver_name, imx_usb); if (ret) { dev_err(&pdev->dev, "can't get irq %i, err %d\n", imx_usb->usbd_int[i], ret); diff --git a/drivers/usb/gadget/m66592-udc.c b/drivers/usb/gadget/m66592-udc.c index c27e5e8f54d0..91d0af2a24a8 100644 --- a/drivers/usb/gadget/m66592-udc.c +++ b/drivers/usb/gadget/m66592-udc.c @@ -1664,7 +1664,7 @@ static int __init m66592_probe(struct platform_device *pdev) m66592->timer.data = (unsigned long)m66592; m66592->reg = reg; - ret = request_irq(ires->start, m66592_irq, IRQF_DISABLED | IRQF_SHARED, + ret = request_irq(ires->start, m66592_irq, IRQF_SHARED, udc_name, m66592); if (ret < 0) { pr_err("request_irq error (%d)\n", ret); diff --git a/drivers/usb/gadget/mv_udc_core.c b/drivers/usb/gadget/mv_udc_core.c index 263dec40af32..0d0e9e39f8b2 100644 --- a/drivers/usb/gadget/mv_udc_core.c +++ b/drivers/usb/gadget/mv_udc_core.c @@ -2049,7 +2049,7 @@ int mv_udc_probe(struct platform_device *dev) } udc->irq = r->start; if (request_irq(udc->irq, mv_udc_irq, - IRQF_DISABLED | IRQF_SHARED, driver_name, udc)) { + IRQF_SHARED, driver_name, udc)) { dev_err(&dev->dev, "Request irq %d for UDC failed\n", udc->irq); retval = -ENODEV; diff --git a/drivers/usb/gadget/omap_udc.c b/drivers/usb/gadget/omap_udc.c index ae9c89b5801a..788989a10223 100644 --- a/drivers/usb/gadget/omap_udc.c +++ b/drivers/usb/gadget/omap_udc.c @@ -2958,7 +2958,7 @@ known: } #ifdef USE_ISO status = request_irq(pdev->resource[3].start, omap_udc_iso_irq, - IRQF_DISABLED, "omap_udc iso", udc); + 0, "omap_udc iso", udc); if (status != 0) { ERR("can't get irq %d, err %d\n", (int) pdev->resource[3].start, status); diff --git a/drivers/usb/gadget/pxa25x_udc.c b/drivers/usb/gadget/pxa25x_udc.c index a33fc1792641..c090a7e3ecf8 100644 --- a/drivers/usb/gadget/pxa25x_udc.c +++ b/drivers/usb/gadget/pxa25x_udc.c @@ -2190,7 +2190,7 @@ static int __init pxa25x_udc_probe(struct platform_device *pdev) /* irq setup after old hardware state is cleaned up */ retval = request_irq(irq, pxa25x_udc_irq, - IRQF_DISABLED, driver_name, dev); + 0, driver_name, dev); if (retval != 0) { pr_err("%s: can't get irq %d, err %d\n", driver_name, irq, retval); @@ -2202,7 +2202,7 @@ static int __init pxa25x_udc_probe(struct platform_device *pdev) if (machine_is_lubbock()) { retval = request_irq(LUBBOCK_USB_DISC_IRQ, lubbock_vbus_irq, - IRQF_DISABLED | IRQF_SAMPLE_RANDOM, + IRQF_SAMPLE_RANDOM, driver_name, dev); if (retval != 0) { pr_err("%s: can't get irq %i, err %d\n", @@ -2211,7 +2211,7 @@ static int __init pxa25x_udc_probe(struct platform_device *pdev) } retval = request_irq(LUBBOCK_USB_IRQ, lubbock_vbus_irq, - IRQF_DISABLED | IRQF_SAMPLE_RANDOM, + IRQF_SAMPLE_RANDOM, driver_name, dev); if (retval != 0) { pr_err("%s: can't get irq %i, err %d\n", diff --git a/drivers/usb/gadget/r8a66597-udc.c b/drivers/usb/gadget/r8a66597-udc.c index bca3f415d20d..d3f81c96cd78 100644 --- a/drivers/usb/gadget/r8a66597-udc.c +++ b/drivers/usb/gadget/r8a66597-udc.c @@ -1633,7 +1633,7 @@ static int __init r8a66597_probe(struct platform_device *pdev) disable_controller(r8a66597); /* make sure controller is disabled */ - ret = request_irq(irq, r8a66597_irq, IRQF_DISABLED | IRQF_SHARED, + ret = request_irq(irq, r8a66597_irq, IRQF_SHARED, udc_name, r8a66597); if (ret < 0) { printk(KERN_ERR "request_irq error (%d)\n", ret); diff --git a/drivers/usb/gadget/s3c2410_udc.c b/drivers/usb/gadget/s3c2410_udc.c index 3f587b0411b0..b8643771fa80 100644 --- a/drivers/usb/gadget/s3c2410_udc.c +++ b/drivers/usb/gadget/s3c2410_udc.c @@ -1893,7 +1893,7 @@ static int s3c2410_udc_probe(struct platform_device *pdev) /* irq setup after old hardware state is cleaned up */ retval = request_irq(IRQ_USBD, s3c2410_udc_irq, - IRQF_DISABLED, gadget_name, udc); + 0, gadget_name, udc); if (retval != 0) { dev_err(dev, "cannot get irq %i, err %d\n", IRQ_USBD, retval); @@ -1917,7 +1917,7 @@ static int s3c2410_udc_probe(struct platform_device *pdev) } retval = request_irq(irq, s3c2410_udc_vbus_irq, - IRQF_DISABLED | IRQF_TRIGGER_RISING + IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_SHARED, gadget_name, udc); -- cgit From 865569ba5a8b0cc840e2b9c16ca6b42d6d5306b4 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Thu, 8 Sep 2011 14:12:18 +0300 Subject: usb: gadget: udc-core: fix bug on soft_connect interface We should not be using dev_get_drvdata() because we never call dev_set_drvdata(). Let's use container_of() as all other sysfs attributes. Signed-off-by: Felipe Balbi Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/udc-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/udc-core.c b/drivers/usb/gadget/udc-core.c index 5e77a46a429a..022baeca7c94 100644 --- a/drivers/usb/gadget/udc-core.c +++ b/drivers/usb/gadget/udc-core.c @@ -356,7 +356,7 @@ static DEVICE_ATTR(srp, S_IWUSR, NULL, usb_udc_srp_store); static ssize_t usb_udc_softconn_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t n) { - struct usb_udc *udc = dev_get_drvdata(dev); + struct usb_udc *udc = container_of(dev, struct usb_udc, dev); if (sysfs_streq(buf, "connect")) { usb_gadget_connect(udc->gadget); -- cgit From 5023829969f56b78a16da94f34c605bbbb344018 Mon Sep 17 00:00:00 2001 From: Shaun Silk Date: Mon, 26 Sep 2011 11:26:43 +1000 Subject: USB: gadget: u_serial.c: fixed a brace coding style issue Signed-off-by: Shaun Silk Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/u_serial.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/u_serial.c b/drivers/usb/gadget/u_serial.c index a8aa46962d81..3a4a664bab44 100644 --- a/drivers/usb/gadget/u_serial.c +++ b/drivers/usb/gadget/u_serial.c @@ -552,9 +552,8 @@ recycle: /* Push from tty to ldisc; without low_latency set this is handled by * a workqueue, so we won't get callbacks and can hold port_lock */ - if (tty && do_push) { + if (tty && do_push) tty_flip_buffer_push(tty); - } /* We want our data queue to become empty ASAP, keeping data -- cgit From 0a85577627fc81936d3dbdfb349964024adcb01d Mon Sep 17 00:00:00 2001 From: Yoshihiro Shimoda Date: Fri, 30 Sep 2011 20:07:08 +0900 Subject: usb: gadget: r8a66597-udc: change prototype of r8a66597_write_fifo Signed-off-by: Yoshihiro Shimoda Signed-off-by: Felipe Balbi --- drivers/usb/gadget/r8a66597-udc.c | 4 ++-- drivers/usb/gadget/r8a66597-udc.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/r8a66597-udc.c b/drivers/usb/gadget/r8a66597-udc.c index d3f81c96cd78..60c62e418f0e 100644 --- a/drivers/usb/gadget/r8a66597-udc.c +++ b/drivers/usb/gadget/r8a66597-udc.c @@ -723,7 +723,7 @@ static void irq_ep0_write(struct r8a66597_ep *ep, struct r8a66597_request *req) /* write fifo */ if (req->req.buf) { if (size > 0) - r8a66597_write_fifo(r8a66597, ep->fifoaddr, buf, size); + r8a66597_write_fifo(r8a66597, ep, buf, size); if ((size == 0) || ((size % ep->ep.maxpacket) != 0)) r8a66597_bset(r8a66597, BVAL, ep->fifoctr); } @@ -770,7 +770,7 @@ static void irq_packet_write(struct r8a66597_ep *ep, /* write fifo */ if (req->req.buf) { - r8a66597_write_fifo(r8a66597, ep->fifoaddr, buf, size); + r8a66597_write_fifo(r8a66597, ep, buf, size); if ((size == 0) || ((size % ep->ep.maxpacket) != 0) || ((bufsize != ep->ep.maxpacket) diff --git a/drivers/usb/gadget/r8a66597-udc.h b/drivers/usb/gadget/r8a66597-udc.h index a373c4e64b44..31047f899c37 100644 --- a/drivers/usb/gadget/r8a66597-udc.h +++ b/drivers/usb/gadget/r8a66597-udc.h @@ -173,11 +173,11 @@ static inline void r8a66597_write(struct r8a66597 *r8a66597, u16 val, } static inline void r8a66597_write_fifo(struct r8a66597 *r8a66597, - unsigned long offset, + struct r8a66597_ep *ep, unsigned char *buf, int len) { - void __iomem *fifoaddr = r8a66597->reg + offset; + void __iomem *fifoaddr = r8a66597->reg + ep->fifoaddr; int adj = 0; int i; -- cgit From 5c481a639068ac34bd1dcd183f37b7a65d0e3841 Mon Sep 17 00:00:00 2001 From: Yoshihiro Shimoda Date: Fri, 30 Sep 2011 20:07:21 +0900 Subject: usb: gadget: r8a66597-udc: add function for external controller R8A66597 has the pin of WR0 and WR1. So, if one write-pin of CPU connects to the pins, we have to change the setting of FIFOSEL register in the controller. If we don't change the setting, the controller cannot send the data of odd length. Signed-off-by: Yoshihiro Shimoda Signed-off-by: Felipe Balbi --- drivers/usb/gadget/r8a66597-udc.h | 34 +++++++++++++++++++--------------- 1 file changed, 19 insertions(+), 15 deletions(-) (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/r8a66597-udc.h b/drivers/usb/gadget/r8a66597-udc.h index 31047f899c37..f9ac2d713c57 100644 --- a/drivers/usb/gadget/r8a66597-udc.h +++ b/drivers/usb/gadget/r8a66597-udc.h @@ -172,6 +172,21 @@ static inline void r8a66597_write(struct r8a66597 *r8a66597, u16 val, iowrite16(val, r8a66597->reg + offset); } +static inline void r8a66597_mdfy(struct r8a66597 *r8a66597, + u16 val, u16 pat, unsigned long offset) +{ + u16 tmp; + tmp = r8a66597_read(r8a66597, offset); + tmp = tmp & (~pat); + tmp = tmp | val; + r8a66597_write(r8a66597, tmp, offset); +} + +#define r8a66597_bclr(r8a66597, val, offset) \ + r8a66597_mdfy(r8a66597, 0, val, offset) +#define r8a66597_bset(r8a66597, val, offset) \ + r8a66597_mdfy(r8a66597, val, 0, offset) + static inline void r8a66597_write_fifo(struct r8a66597 *r8a66597, struct r8a66597_ep *ep, unsigned char *buf, @@ -205,18 +220,12 @@ static inline void r8a66597_write_fifo(struct r8a66597 *r8a66597, adj = 0x01; /* 16-bit wide */ } + if (r8a66597->pdata->wr0_shorted_to_wr1) + r8a66597_bclr(r8a66597, MBW_16, ep->fifosel); for (i = 0; i < len; i++) iowrite8(buf[i], fifoaddr + adj - (i & adj)); -} - -static inline void r8a66597_mdfy(struct r8a66597 *r8a66597, - u16 val, u16 pat, unsigned long offset) -{ - u16 tmp; - tmp = r8a66597_read(r8a66597, offset); - tmp = tmp & (~pat); - tmp = tmp | val; - r8a66597_write(r8a66597, tmp, offset); + if (r8a66597->pdata->wr0_shorted_to_wr1) + r8a66597_bclr(r8a66597, MBW_16, ep->fifosel); } static inline u16 get_xtal_from_pdata(struct r8a66597_platdata *pdata) @@ -241,11 +250,6 @@ static inline u16 get_xtal_from_pdata(struct r8a66597_platdata *pdata) return clock; } -#define r8a66597_bclr(r8a66597, val, offset) \ - r8a66597_mdfy(r8a66597, 0, val, offset) -#define r8a66597_bset(r8a66597, val, offset) \ - r8a66597_mdfy(r8a66597, val, 0, offset) - #define get_pipectr_addr(pipenum) (PIPE1CTR + (pipenum - 1) * 2) #define enable_irq_ready(r8a66597, pipenum) \ -- cgit From 12158f4280b4d42ef03b70a47d11b48dd8aad511 Mon Sep 17 00:00:00 2001 From: Yoshihiro Shimoda Date: Fri, 30 Sep 2011 20:07:30 +0900 Subject: usb: gadget: r8a66597-udc: use dev_*() instead of printk() This patch also fix the balance of braces. Signed-off-by: Yoshihiro Shimoda Signed-off-by: Felipe Balbi --- drivers/usb/gadget/r8a66597-udc.c | 99 +++++++++++++++++++++++---------------- drivers/usb/gadget/r8a66597-udc.h | 1 + 2 files changed, 60 insertions(+), 40 deletions(-) (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/r8a66597-udc.c b/drivers/usb/gadget/r8a66597-udc.c index 60c62e418f0e..34abb12a88e8 100644 --- a/drivers/usb/gadget/r8a66597-udc.c +++ b/drivers/usb/gadget/r8a66597-udc.c @@ -105,13 +105,15 @@ static inline u16 control_reg_get_pid(struct r8a66597 *r8a66597, u16 pipenum) u16 pid = 0; unsigned long offset; - if (pipenum == 0) + if (pipenum == 0) { pid = r8a66597_read(r8a66597, DCPCTR) & PID; - else if (pipenum < R8A66597_MAX_NUM_PIPE) { + } else if (pipenum < R8A66597_MAX_NUM_PIPE) { offset = get_pipectr_addr(pipenum); pid = r8a66597_read(r8a66597, offset) & PID; - } else - printk(KERN_ERR "unexpect pipe num (%d)\n", pipenum); + } else { + dev_err(r8a66597_to_dev(r8a66597), "unexpect pipe num (%d)\n", + pipenum); + } return pid; } @@ -121,13 +123,15 @@ static inline void control_reg_set_pid(struct r8a66597 *r8a66597, u16 pipenum, { unsigned long offset; - if (pipenum == 0) + if (pipenum == 0) { r8a66597_mdfy(r8a66597, pid, PID, DCPCTR); - else if (pipenum < R8A66597_MAX_NUM_PIPE) { + } else if (pipenum < R8A66597_MAX_NUM_PIPE) { offset = get_pipectr_addr(pipenum); r8a66597_mdfy(r8a66597, pid, PID, offset); - } else - printk(KERN_ERR "unexpect pipe num (%d)\n", pipenum); + } else { + dev_err(r8a66597_to_dev(r8a66597), "unexpect pipe num (%d)\n", + pipenum); + } } static inline void pipe_start(struct r8a66597 *r8a66597, u16 pipenum) @@ -150,13 +154,15 @@ static inline u16 control_reg_get(struct r8a66597 *r8a66597, u16 pipenum) u16 ret = 0; unsigned long offset; - if (pipenum == 0) + if (pipenum == 0) { ret = r8a66597_read(r8a66597, DCPCTR); - else if (pipenum < R8A66597_MAX_NUM_PIPE) { + } else if (pipenum < R8A66597_MAX_NUM_PIPE) { offset = get_pipectr_addr(pipenum); ret = r8a66597_read(r8a66597, offset); - } else - printk(KERN_ERR "unexpect pipe num (%d)\n", pipenum); + } else { + dev_err(r8a66597_to_dev(r8a66597), "unexpect pipe num (%d)\n", + pipenum); + } return ret; } @@ -167,13 +173,15 @@ static inline void control_reg_sqclr(struct r8a66597 *r8a66597, u16 pipenum) pipe_stop(r8a66597, pipenum); - if (pipenum == 0) + if (pipenum == 0) { r8a66597_bset(r8a66597, SQCLR, DCPCTR); - else if (pipenum < R8A66597_MAX_NUM_PIPE) { + } else if (pipenum < R8A66597_MAX_NUM_PIPE) { offset = get_pipectr_addr(pipenum); r8a66597_bset(r8a66597, SQCLR, offset); - } else - printk(KERN_ERR "unexpect pipe num(%d)\n", pipenum); + } else { + dev_err(r8a66597_to_dev(r8a66597), "unexpect pipe num (%d)\n", + pipenum); + } } static inline int get_buffer_size(struct r8a66597 *r8a66597, u16 pipenum) @@ -287,17 +295,18 @@ static void pipe_buffer_release(struct r8a66597 *r8a66597, if (info->pipe == 0) return; - if (is_bulk_pipe(info->pipe)) + if (is_bulk_pipe(info->pipe)) { r8a66597->bulk--; - else if (is_interrupt_pipe(info->pipe)) + } else if (is_interrupt_pipe(info->pipe)) { r8a66597->interrupt--; - else if (is_isoc_pipe(info->pipe)) { + } else if (is_isoc_pipe(info->pipe)) { r8a66597->isochronous--; if (info->type == R8A66597_BULK) r8a66597->bulk--; - } else - printk(KERN_ERR "ep_release: unexpect pipenum (%d)\n", - info->pipe); + } else { + dev_err(r8a66597_to_dev(r8a66597), + "ep_release: unexpect pipenum (%d)\n", info->pipe); + } } static void pipe_initialize(struct r8a66597_ep *ep) @@ -371,7 +380,8 @@ static int alloc_pipe_config(struct r8a66597_ep *ep, case USB_ENDPOINT_XFER_BULK: if (r8a66597->bulk >= R8A66597_MAX_NUM_BULK) { if (r8a66597->isochronous >= R8A66597_MAX_NUM_ISOC) { - printk(KERN_ERR "bulk pipe is insufficient\n"); + dev_err(r8a66597_to_dev(r8a66597), + "bulk pipe is insufficient\n"); return -ENODEV; } else { info.pipe = R8A66597_BASE_PIPENUM_ISOC @@ -387,7 +397,8 @@ static int alloc_pipe_config(struct r8a66597_ep *ep, break; case USB_ENDPOINT_XFER_INT: if (r8a66597->interrupt >= R8A66597_MAX_NUM_INT) { - printk(KERN_ERR "interrupt pipe is insufficient\n"); + dev_err(r8a66597_to_dev(r8a66597), + "interrupt pipe is insufficient\n"); return -ENODEV; } info.pipe = R8A66597_BASE_PIPENUM_INT + r8a66597->interrupt; @@ -396,7 +407,8 @@ static int alloc_pipe_config(struct r8a66597_ep *ep, break; case USB_ENDPOINT_XFER_ISOC: if (r8a66597->isochronous >= R8A66597_MAX_NUM_ISOC) { - printk(KERN_ERR "isochronous pipe is insufficient\n"); + dev_err(r8a66597_to_dev(r8a66597), + "isochronous pipe is insufficient\n"); return -ENODEV; } info.pipe = R8A66597_BASE_PIPENUM_ISOC + r8a66597->isochronous; @@ -404,7 +416,7 @@ static int alloc_pipe_config(struct r8a66597_ep *ep, counter = &r8a66597->isochronous; break; default: - printk(KERN_ERR "unexpect xfer type\n"); + dev_err(r8a66597_to_dev(r8a66597), "unexpect xfer type\n"); return -EINVAL; } ep->type = info.type; @@ -419,7 +431,8 @@ static int alloc_pipe_config(struct r8a66597_ep *ep, ret = pipe_buffer_setting(r8a66597, &info); if (ret < 0) { - printk(KERN_ERR "pipe_buffer_setting fail\n"); + dev_err(r8a66597_to_dev(r8a66597), + "pipe_buffer_setting fail\n"); return ret; } @@ -554,7 +567,8 @@ static void start_ep0(struct r8a66597_ep *ep, struct r8a66597_request *req) control_end(ep->r8a66597, 0); break; default: - printk(KERN_ERR "start_ep0: unexpect ctsq(%x)\n", ctsq); + dev_err(r8a66597_to_dev(ep->r8a66597), + "start_ep0: unexpect ctsq(%x)\n", ctsq); break; } } @@ -708,7 +722,8 @@ static void irq_ep0_write(struct r8a66597_ep *ep, struct r8a66597_request *req) do { tmp = r8a66597_read(r8a66597, ep->fifoctr); if (i++ > 100000) { - printk(KERN_ERR "pipe0 is busy. maybe cpu i/o bus" + dev_err(r8a66597_to_dev(r8a66597), + "pipe0 is busy. maybe cpu i/o bus " "conflict. please power off this controller."); return; } @@ -759,7 +774,8 @@ static void irq_packet_write(struct r8a66597_ep *ep, if (unlikely((tmp & FRDY) == 0)) { pipe_stop(r8a66597, pipenum); pipe_irq_disable(r8a66597, pipenum); - printk(KERN_ERR "write fifo not ready. pipnum=%d\n", pipenum); + dev_err(r8a66597_to_dev(r8a66597), + "write fifo not ready. pipnum=%d\n", pipenum); return; } @@ -809,7 +825,7 @@ static void irq_packet_read(struct r8a66597_ep *ep, req->req.status = -EPIPE; pipe_stop(r8a66597, pipenum); pipe_irq_disable(r8a66597, pipenum); - printk(KERN_ERR "read fifo not ready"); + dev_err(r8a66597_to_dev(r8a66597), "read fifo not ready"); return; } @@ -1085,7 +1101,7 @@ static void r8a66597_update_usb_speed(struct r8a66597 *r8a66597) break; default: r8a66597->gadget.speed = USB_SPEED_UNKNOWN; - printk(KERN_ERR "USB speed unknown\n"); + dev_err(r8a66597_to_dev(r8a66597), "USB speed unknown\n"); } } @@ -1148,7 +1164,8 @@ __acquires(r8a66597->lock) control_end(r8a66597, 0); break; default: - printk(KERN_ERR "ctrl_stage: unexpect ctsq(%x)\n", ctsq); + dev_err(r8a66597_to_dev(r8a66597), + "ctrl_stage: unexpect ctsq(%x)\n", ctsq); break; } } @@ -1448,13 +1465,15 @@ static int r8a66597_start(struct usb_gadget_driver *driver, retval = device_add(&r8a66597->gadget.dev); if (retval) { - printk(KERN_ERR "device_add error (%d)\n", retval); + dev_err(r8a66597_to_dev(r8a66597), "device_add error (%d)\n", + retval); goto error; } retval = bind(&r8a66597->gadget); if (retval) { - printk(KERN_ERR "bind to driver error (%d)\n", retval); + dev_err(r8a66597_to_dev(r8a66597), + "bind to driver error (%d)\n", retval); device_del(&r8a66597->gadget.dev); goto error; } @@ -1569,7 +1588,7 @@ static int __init r8a66597_probe(struct platform_device *pdev) res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) { ret = -ENODEV; - printk(KERN_ERR "platform_get_resource error.\n"); + dev_err(&pdev->dev, "platform_get_resource error.\n"); goto clean_up; } @@ -1579,14 +1598,14 @@ static int __init r8a66597_probe(struct platform_device *pdev) if (irq < 0) { ret = -ENODEV; - printk(KERN_ERR "platform_get_irq error.\n"); + dev_err(&pdev->dev, "platform_get_irq error.\n"); goto clean_up; } reg = ioremap(res->start, resource_size(res)); if (reg == NULL) { ret = -ENOMEM; - printk(KERN_ERR "ioremap error.\n"); + dev_err(&pdev->dev, "ioremap error.\n"); goto clean_up; } @@ -1594,7 +1613,7 @@ static int __init r8a66597_probe(struct platform_device *pdev) r8a66597 = kzalloc(sizeof(struct r8a66597), GFP_KERNEL); if (r8a66597 == NULL) { ret = -ENOMEM; - printk(KERN_ERR "kzalloc error\n"); + dev_err(&pdev->dev, "kzalloc error\n"); goto clean_up; } @@ -1636,7 +1655,7 @@ static int __init r8a66597_probe(struct platform_device *pdev) ret = request_irq(irq, r8a66597_irq, IRQF_SHARED, udc_name, r8a66597); if (ret < 0) { - printk(KERN_ERR "request_irq error (%d)\n", ret); + dev_err(&pdev->dev, "request_irq error (%d)\n", ret); goto clean_up2; } diff --git a/drivers/usb/gadget/r8a66597-udc.h b/drivers/usb/gadget/r8a66597-udc.h index f9ac2d713c57..832ee59c8e45 100644 --- a/drivers/usb/gadget/r8a66597-udc.h +++ b/drivers/usb/gadget/r8a66597-udc.h @@ -114,6 +114,7 @@ struct r8a66597 { #define gadget_to_r8a66597(_gadget) \ container_of(_gadget, struct r8a66597, gadget) #define r8a66597_to_gadget(r8a66597) (&r8a66597->gadget) +#define r8a66597_to_dev(r8a66597) (r8a66597->gadget.dev.parent) static inline u16 r8a66597_read(struct r8a66597 *r8a66597, unsigned long offset) { -- cgit From b8a56e17e18cca2402b390c10b8d7f3cd0f6265b Mon Sep 17 00:00:00 2001 From: Yoshihiro Shimoda Date: Fri, 30 Sep 2011 20:07:38 +0900 Subject: usb: gadget: r8a66597-udc: add support for SUDMAC SH7757 has a USB function with internal DMA controller (SUDMAC). This patch supports the SUDMAC. The SUDMAC is incompatible with general-purpose DMAC. So, it doesn't use dmaengine. Signed-off-by: Yoshihiro Shimoda Signed-off-by: Felipe Balbi --- drivers/usb/gadget/r8a66597-udc.c | 364 ++++++++++++++++++++++++++++++++++++-- drivers/usb/gadget/r8a66597-udc.h | 26 ++- 2 files changed, 370 insertions(+), 20 deletions(-) (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/r8a66597-udc.c b/drivers/usb/gadget/r8a66597-udc.c index 34abb12a88e8..035879b98dd9 100644 --- a/drivers/usb/gadget/r8a66597-udc.c +++ b/drivers/usb/gadget/r8a66597-udc.c @@ -18,13 +18,14 @@ #include #include #include +#include #include #include #include "r8a66597-udc.h" -#define DRIVER_VERSION "2009-08-18" +#define DRIVER_VERSION "2011-09-26" static const char udc_name[] = "r8a66597_udc"; static const char *r8a66597_ep_name[] = { @@ -184,6 +185,54 @@ static inline void control_reg_sqclr(struct r8a66597 *r8a66597, u16 pipenum) } } +static void control_reg_sqset(struct r8a66597 *r8a66597, u16 pipenum) +{ + unsigned long offset; + + pipe_stop(r8a66597, pipenum); + + if (pipenum == 0) { + r8a66597_bset(r8a66597, SQSET, DCPCTR); + } else if (pipenum < R8A66597_MAX_NUM_PIPE) { + offset = get_pipectr_addr(pipenum); + r8a66597_bset(r8a66597, SQSET, offset); + } else { + dev_err(r8a66597_to_dev(r8a66597), + "unexpect pipe num(%d)\n", pipenum); + } +} + +static u16 control_reg_sqmon(struct r8a66597 *r8a66597, u16 pipenum) +{ + unsigned long offset; + + if (pipenum == 0) { + return r8a66597_read(r8a66597, DCPCTR) & SQMON; + } else if (pipenum < R8A66597_MAX_NUM_PIPE) { + offset = get_pipectr_addr(pipenum); + return r8a66597_read(r8a66597, offset) & SQMON; + } else { + dev_err(r8a66597_to_dev(r8a66597), + "unexpect pipe num(%d)\n", pipenum); + } + + return 0; +} + +static u16 save_usb_toggle(struct r8a66597 *r8a66597, u16 pipenum) +{ + return control_reg_sqmon(r8a66597, pipenum); +} + +static void restore_usb_toggle(struct r8a66597 *r8a66597, u16 pipenum, + u16 toggle) +{ + if (toggle) + control_reg_sqset(r8a66597, pipenum); + else + control_reg_sqclr(r8a66597, pipenum); +} + static inline int get_buffer_size(struct r8a66597 *r8a66597, u16 pipenum) { u16 tmp; @@ -220,18 +269,51 @@ static inline unsigned short mbw_value(struct r8a66597 *r8a66597) return MBW_16; } +static void r8a66597_change_curpipe(struct r8a66597 *r8a66597, u16 pipenum, + u16 isel, u16 fifosel) +{ + u16 tmp, mask, loop; + int i = 0; + + if (!pipenum) { + mask = ISEL | CURPIPE; + loop = isel; + } else { + mask = CURPIPE; + loop = pipenum; + } + r8a66597_mdfy(r8a66597, loop, mask, fifosel); + + do { + tmp = r8a66597_read(r8a66597, fifosel); + if (i++ > 1000000) { + dev_err(r8a66597_to_dev(r8a66597), + "r8a66597: register%x, loop %x " + "is timeout\n", fifosel, loop); + break; + } + ndelay(1); + } while ((tmp & mask) != loop); +} + static inline void pipe_change(struct r8a66597 *r8a66597, u16 pipenum) { struct r8a66597_ep *ep = r8a66597->pipenum2ep[pipenum]; if (ep->use_dma) - return; + r8a66597_bclr(r8a66597, DREQE, ep->fifosel); r8a66597_mdfy(r8a66597, pipenum, CURPIPE, ep->fifosel); ndelay(450); - r8a66597_bset(r8a66597, mbw_value(r8a66597), ep->fifosel); + if (r8a66597_is_sudmac(r8a66597) && ep->use_dma) + r8a66597_bclr(r8a66597, mbw_value(r8a66597), ep->fifosel); + else + r8a66597_bset(r8a66597, mbw_value(r8a66597), ep->fifosel); + + if (ep->use_dma) + r8a66597_bset(r8a66597, DREQE, ep->fifosel); } static int pipe_buffer_setting(struct r8a66597 *r8a66597, @@ -336,9 +418,15 @@ static void r8a66597_ep_setting(struct r8a66597 *r8a66597, ep->fifoaddr = CFIFO; ep->fifosel = CFIFOSEL; ep->fifoctr = CFIFOCTR; - ep->fifotrn = 0; ep->pipectr = get_pipectr_addr(pipenum); + if (is_bulk_pipe(pipenum) || is_isoc_pipe(pipenum)) { + ep->pipetre = get_pipetre_addr(pipenum); + ep->pipetrn = get_pipetrn_addr(pipenum); + } else { + ep->pipetre = 0; + ep->pipetrn = 0; + } ep->pipenum = pipenum; ep->ep.maxpacket = usb_endpoint_maxp(desc); r8a66597->pipenum2ep[pipenum] = ep; @@ -498,6 +586,124 @@ static void start_ep0_write(struct r8a66597_ep *ep, } } +static void disable_fifosel(struct r8a66597 *r8a66597, u16 pipenum, + u16 fifosel) +{ + u16 tmp; + + tmp = r8a66597_read(r8a66597, fifosel) & CURPIPE; + if (tmp == pipenum) + r8a66597_change_curpipe(r8a66597, 0, 0, fifosel); +} + +static void change_bfre_mode(struct r8a66597 *r8a66597, u16 pipenum, + int enable) +{ + struct r8a66597_ep *ep = r8a66597->pipenum2ep[pipenum]; + u16 tmp, toggle; + + /* check current BFRE bit */ + r8a66597_write(r8a66597, pipenum, PIPESEL); + tmp = r8a66597_read(r8a66597, PIPECFG) & R8A66597_BFRE; + if ((enable && tmp) || (!enable && !tmp)) + return; + + /* change BFRE bit */ + pipe_stop(r8a66597, pipenum); + disable_fifosel(r8a66597, pipenum, CFIFOSEL); + disable_fifosel(r8a66597, pipenum, D0FIFOSEL); + disable_fifosel(r8a66597, pipenum, D1FIFOSEL); + + toggle = save_usb_toggle(r8a66597, pipenum); + + r8a66597_write(r8a66597, pipenum, PIPESEL); + if (enable) + r8a66597_bset(r8a66597, R8A66597_BFRE, PIPECFG); + else + r8a66597_bclr(r8a66597, R8A66597_BFRE, PIPECFG); + + /* initialize for internal BFRE flag */ + r8a66597_bset(r8a66597, ACLRM, ep->pipectr); + r8a66597_bclr(r8a66597, ACLRM, ep->pipectr); + + restore_usb_toggle(r8a66597, pipenum, toggle); +} + +static int sudmac_alloc_channel(struct r8a66597 *r8a66597, + struct r8a66597_ep *ep, + struct r8a66597_request *req) +{ + struct r8a66597_dma *dma; + + if (!r8a66597_is_sudmac(r8a66597)) + return -ENODEV; + + /* Check transfer type */ + if (!is_bulk_pipe(ep->pipenum)) + return -EIO; + + if (r8a66597->dma.used) + return -EBUSY; + + /* set SUDMAC parameters */ + dma = &r8a66597->dma; + dma->used = 1; + if (ep->desc->bEndpointAddress & USB_DIR_IN) { + dma->dir = 1; + } else { + dma->dir = 0; + change_bfre_mode(r8a66597, ep->pipenum, 1); + } + + /* set r8a66597_ep paramters */ + ep->use_dma = 1; + ep->dma = dma; + ep->fifoaddr = D0FIFO; + ep->fifosel = D0FIFOSEL; + ep->fifoctr = D0FIFOCTR; + + /* dma mapping */ + req->req.dma = dma_map_single(r8a66597_to_dev(ep->r8a66597), + req->req.buf, req->req.length, + dma->dir ? DMA_TO_DEVICE : DMA_FROM_DEVICE); + + return 0; +} + +static void sudmac_free_channel(struct r8a66597 *r8a66597, + struct r8a66597_ep *ep, + struct r8a66597_request *req) +{ + if (!r8a66597_is_sudmac(r8a66597)) + return; + + dma_unmap_single(r8a66597_to_dev(ep->r8a66597), + req->req.dma, req->req.length, + ep->dma->dir ? DMA_TO_DEVICE : DMA_FROM_DEVICE); + + r8a66597_bclr(r8a66597, DREQE, ep->fifosel); + r8a66597_change_curpipe(r8a66597, 0, 0, ep->fifosel); + + ep->dma->used = 0; + ep->use_dma = 0; + ep->fifoaddr = CFIFO; + ep->fifosel = CFIFOSEL; + ep->fifoctr = CFIFOCTR; +} + +static void sudmac_start(struct r8a66597 *r8a66597, struct r8a66597_ep *ep, + struct r8a66597_request *req) +{ + BUG_ON(req->req.length == 0); + + r8a66597_sudmac_write(r8a66597, LBA_WAIT, CH0CFG); + r8a66597_sudmac_write(r8a66597, req->req.dma, CH0BA); + r8a66597_sudmac_write(r8a66597, req->req.length, CH0BBC); + r8a66597_sudmac_write(r8a66597, CH0ENDE, DINTCTRL); + + r8a66597_sudmac_write(r8a66597, DEN, CH0DEN); +} + static void start_packet_write(struct r8a66597_ep *ep, struct r8a66597_request *req) { @@ -508,11 +714,29 @@ static void start_packet_write(struct r8a66597_ep *ep, disable_irq_empty(r8a66597, ep->pipenum); pipe_start(r8a66597, ep->pipenum); - tmp = r8a66597_read(r8a66597, ep->fifoctr); - if (unlikely((tmp & FRDY) == 0)) - pipe_irq_enable(r8a66597, ep->pipenum); - else - irq_packet_write(ep, req); + if (req->req.length == 0) { + transfer_complete(ep, req, 0); + } else { + r8a66597_write(r8a66597, ~(1 << ep->pipenum), BRDYSTS); + if (sudmac_alloc_channel(r8a66597, ep, req) < 0) { + /* PIO mode */ + pipe_change(r8a66597, ep->pipenum); + disable_irq_empty(r8a66597, ep->pipenum); + pipe_start(r8a66597, ep->pipenum); + tmp = r8a66597_read(r8a66597, ep->fifoctr); + if (unlikely((tmp & FRDY) == 0)) + pipe_irq_enable(r8a66597, ep->pipenum); + else + irq_packet_write(ep, req); + } else { + /* DMA mode */ + pipe_change(r8a66597, ep->pipenum); + disable_irq_nrdy(r8a66597, ep->pipenum); + pipe_start(r8a66597, ep->pipenum); + enable_irq_nrdy(r8a66597, ep->pipenum); + sudmac_start(r8a66597, ep, req); + } + } } static void start_packet_read(struct r8a66597_ep *ep, @@ -527,17 +751,26 @@ static void start_packet_read(struct r8a66597_ep *ep, pipe_start(r8a66597, pipenum); pipe_irq_enable(r8a66597, pipenum); } else { - if (ep->use_dma) { - r8a66597_bset(r8a66597, TRCLR, ep->fifosel); - pipe_change(r8a66597, pipenum); - r8a66597_bset(r8a66597, TRENB, ep->fifosel); + pipe_stop(r8a66597, pipenum); + if (ep->pipetre) { + enable_irq_nrdy(r8a66597, pipenum); + r8a66597_write(r8a66597, TRCLR, ep->pipetre); r8a66597_write(r8a66597, - (req->req.length + ep->ep.maxpacket - 1) - / ep->ep.maxpacket, - ep->fifotrn); + DIV_ROUND_UP(req->req.length, ep->ep.maxpacket), + ep->pipetrn); + r8a66597_bset(r8a66597, TRENB, ep->pipetre); + } + + if (sudmac_alloc_channel(r8a66597, ep, req) < 0) { + /* PIO mode */ + change_bfre_mode(r8a66597, ep->pipenum, 0); + pipe_start(r8a66597, pipenum); /* trigger once */ + pipe_irq_enable(r8a66597, pipenum); + } else { + pipe_change(r8a66597, pipenum); + sudmac_start(r8a66597, ep, req); + pipe_start(r8a66597, pipenum); /* trigger once */ } - pipe_start(r8a66597, pipenum); /* trigger once */ - pipe_irq_enable(r8a66597, pipenum); } } @@ -694,6 +927,9 @@ __acquires(r8a66597->lock) if (!list_empty(&ep->queue)) restart = 1; + if (ep->use_dma) + sudmac_free_channel(ep->r8a66597, ep, req); + spin_unlock(&ep->r8a66597->lock); req->req.complete(&ep->ep, &req->req); spin_lock(&ep->r8a66597->lock); @@ -1170,6 +1406,65 @@ __acquires(r8a66597->lock) } } +static void sudmac_finish(struct r8a66597 *r8a66597, struct r8a66597_ep *ep) +{ + u16 pipenum; + struct r8a66597_request *req; + u32 len; + int i = 0; + + pipenum = ep->pipenum; + pipe_change(r8a66597, pipenum); + + while (!(r8a66597_read(r8a66597, ep->fifoctr) & FRDY)) { + udelay(1); + if (unlikely(i++ >= 10000)) { /* timeout = 10 msec */ + dev_err(r8a66597_to_dev(r8a66597), + "%s: FRDY was not set (%d)\n", + __func__, pipenum); + return; + } + } + + r8a66597_bset(r8a66597, BCLR, ep->fifoctr); + req = get_request_from_ep(ep); + + /* prepare parameters */ + len = r8a66597_sudmac_read(r8a66597, CH0CBC); + req->req.actual += len; + + /* clear */ + r8a66597_sudmac_write(r8a66597, CH0STCLR, DSTSCLR); + + /* check transfer finish */ + if ((!req->req.zero && (req->req.actual == req->req.length)) + || (len % ep->ep.maxpacket)) { + if (ep->dma->dir) { + disable_irq_ready(r8a66597, pipenum); + enable_irq_empty(r8a66597, pipenum); + } else { + /* Clear the interrupt flag for next transfer */ + r8a66597_write(r8a66597, ~(1 << pipenum), BRDYSTS); + transfer_complete(ep, req, 0); + } + } +} + +static void r8a66597_sudmac_irq(struct r8a66597 *r8a66597) +{ + u32 irqsts; + struct r8a66597_ep *ep; + u16 pipenum; + + irqsts = r8a66597_sudmac_read(r8a66597, DINTSTS); + if (irqsts & CH0ENDS) { + r8a66597_sudmac_write(r8a66597, CH0ENDC, DINTSTSCLR); + pipenum = (r8a66597_read(r8a66597, D0FIFOSEL) & CURPIPE); + ep = r8a66597->pipenum2ep[pipenum]; + sudmac_finish(r8a66597, ep); + } +} + static irqreturn_t r8a66597_irq(int irq, void *_r8a66597) { struct r8a66597 *r8a66597 = _r8a66597; @@ -1180,6 +1475,9 @@ static irqreturn_t r8a66597_irq(int irq, void *_r8a66597) u16 savepipe; u16 mask0; + if (r8a66597_is_sudmac(r8a66597)) + r8a66597_sudmac_irq(r8a66597); + spin_lock(&r8a66597->lock); intsts0 = r8a66597_read(r8a66597, INTSTS0); @@ -1556,6 +1854,8 @@ static int __exit r8a66597_remove(struct platform_device *pdev) usb_del_gadget_udc(&r8a66597->gadget); del_timer_sync(&r8a66597->timer); iounmap(r8a66597->reg); + if (r8a66597->pdata->sudmac) + iounmap(r8a66597->sudmac_reg); free_irq(platform_get_irq(pdev, 0), r8a66597); r8a66597_free_request(&r8a66597->ep[0].ep, r8a66597->ep0_req); #ifdef CONFIG_HAVE_CLK @@ -1572,6 +1872,26 @@ static void nop_completion(struct usb_ep *ep, struct usb_request *r) { } +static int __init r8a66597_sudmac_ioremap(struct r8a66597 *r8a66597, + struct platform_device *pdev) +{ + struct resource *res; + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "sudmac"); + if (!res) { + dev_err(&pdev->dev, "platform_get_resource error(sudmac).\n"); + return -ENODEV; + } + + r8a66597->sudmac_reg = ioremap(res->start, resource_size(res)); + if (r8a66597->sudmac_reg == NULL) { + dev_err(&pdev->dev, "ioremap error(sudmac).\n"); + return -ENOMEM; + } + + return 0; +} + static int __init r8a66597_probe(struct platform_device *pdev) { #ifdef CONFIG_HAVE_CLK @@ -1649,6 +1969,11 @@ static int __init r8a66597_probe(struct platform_device *pdev) clk_enable(r8a66597->clk); } #endif + if (r8a66597->pdata->sudmac) { + ret = r8a66597_sudmac_ioremap(r8a66597, pdev); + if (ret < 0) + goto clean_up2; + } disable_controller(r8a66597); /* make sure controller is disabled */ @@ -1681,7 +2006,6 @@ static int __init r8a66597_probe(struct platform_device *pdev) r8a66597->ep[0].fifoaddr = CFIFO; r8a66597->ep[0].fifosel = CFIFOSEL; r8a66597->ep[0].fifoctr = CFIFOCTR; - r8a66597->ep[0].fifotrn = 0; r8a66597->ep[0].pipectr = get_pipectr_addr(0); r8a66597->pipenum2ep[0] = &r8a66597->ep[0]; r8a66597->epaddr2ep[0] = &r8a66597->ep[0]; @@ -1714,6 +2038,8 @@ clean_up2: #endif clean_up: if (r8a66597) { + if (r8a66597->sudmac_reg) + iounmap(r8a66597->sudmac_reg); if (r8a66597->ep0_req) r8a66597_free_request(&r8a66597->ep[0].ep, r8a66597->ep0_req); diff --git a/drivers/usb/gadget/r8a66597-udc.h b/drivers/usb/gadget/r8a66597-udc.h index 832ee59c8e45..8e3de61cd4b8 100644 --- a/drivers/usb/gadget/r8a66597-udc.h +++ b/drivers/usb/gadget/r8a66597-udc.h @@ -43,6 +43,7 @@ ((pipenum >= R8A66597_BASE_PIPENUM_ISOC) && \ (pipenum < (R8A66597_BASE_PIPENUM_ISOC + R8A66597_MAX_NUM_ISOC))) +#define r8a66597_is_sudmac(r8a66597) (r8a66597->pdata->sudmac) struct r8a66597_pipe_info { u16 pipe; u16 epnum; @@ -60,6 +61,7 @@ struct r8a66597_request { struct r8a66597_ep { struct usb_ep ep; struct r8a66597 *r8a66597; + struct r8a66597_dma *dma; struct list_head queue; unsigned busy:1; @@ -75,13 +77,20 @@ struct r8a66597_ep { unsigned char fifoaddr; unsigned char fifosel; unsigned char fifoctr; - unsigned char fifotrn; unsigned char pipectr; + unsigned char pipetre; + unsigned char pipetrn; +}; + +struct r8a66597_dma { + unsigned used:1; + unsigned dir:1; /* 1 = IN(write), 0 = OUT(read) */ }; struct r8a66597 { spinlock_t lock; void __iomem *reg; + void __iomem *sudmac_reg; #ifdef CONFIG_HAVE_CLK struct clk *clk; @@ -94,6 +103,7 @@ struct r8a66597 { struct r8a66597_ep ep[R8A66597_MAX_NUM_PIPE]; struct r8a66597_ep *pipenum2ep[R8A66597_MAX_NUM_PIPE]; struct r8a66597_ep *epaddr2ep[16]; + struct r8a66597_dma dma; struct timer_list timer; struct usb_request *ep0_req; /* for internal request */ @@ -251,7 +261,21 @@ static inline u16 get_xtal_from_pdata(struct r8a66597_platdata *pdata) return clock; } +static inline u32 r8a66597_sudmac_read(struct r8a66597 *r8a66597, + unsigned long offset) +{ + return ioread32(r8a66597->sudmac_reg + offset); +} + +static inline void r8a66597_sudmac_write(struct r8a66597 *r8a66597, u32 val, + unsigned long offset) +{ + iowrite32(val, r8a66597->sudmac_reg + offset); +} + #define get_pipectr_addr(pipenum) (PIPE1CTR + (pipenum - 1) * 2) +#define get_pipetre_addr(pipenum) (PIPE1TRE + (pipenum - 1) * 4) +#define get_pipetrn_addr(pipenum) (PIPE1TRN + (pipenum - 1) * 4) #define enable_irq_ready(r8a66597, pipenum) \ enable_pipe_irq(r8a66597, pipenum, BRDYENB) -- cgit From 56526c0b8d752bf243a21722455807518925685f Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Fri, 7 Oct 2011 13:57:42 -0700 Subject: usb gadget: fix langwell_udc.c build error Move function to fix langwell_udc.c build error: drivers/usb/gadget/langwell_udc.c: In function 'show_langwell_udc': drivers/usb/gadget/langwell_udc.c:1693:3: error: implicit declaration of function 'lpm_device_speed' drivers/usb/gadget/langwell_udc.c: At top level: drivers/usb/gadget/langwell_udc.c:2637:37: error: conflicting types for 'lpm_device_speed' drivers/usb/gadget/langwell_udc.c:1693:20: note: previous implicit declaration of 'lpm_device_speed' was here Signed-off-by: Randy Dunlap Acked-by: Felipe Balbi Cc: linux-usb@vger.kernel.org --- drivers/usb/gadget/langwell_udc.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/langwell_udc.c b/drivers/usb/gadget/langwell_udc.c index c88158f307a8..cb728d3079af 100644 --- a/drivers/usb/gadget/langwell_udc.c +++ b/drivers/usb/gadget/langwell_udc.c @@ -1562,6 +1562,20 @@ static ssize_t show_function(struct device *_dev, static DEVICE_ATTR(function, S_IRUGO, show_function, NULL); +static inline enum usb_device_speed lpm_device_speed(u32 reg) +{ + switch (LPM_PSPD(reg)) { + case LPM_SPEED_HIGH: + return USB_SPEED_HIGH; + case LPM_SPEED_FULL: + return USB_SPEED_FULL; + case LPM_SPEED_LOW: + return USB_SPEED_LOW; + default: + return USB_SPEED_UNKNOWN; + } +} + /* device "langwell_udc" sysfs attribute file */ static ssize_t show_langwell_udc(struct device *_dev, struct device_attribute *attr, char *buf) @@ -2634,20 +2648,6 @@ done: dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__); } -static inline enum usb_device_speed lpm_device_speed(u32 reg) -{ - switch (LPM_PSPD(reg)) { - case LPM_SPEED_HIGH: - return USB_SPEED_HIGH; - case LPM_SPEED_FULL: - return USB_SPEED_FULL; - case LPM_SPEED_LOW: - return USB_SPEED_LOW; - default: - return USB_SPEED_UNKNOWN; - } -} - /* port change detect interrupt handler */ static void handle_port_change(struct langwell_udc *dev) { -- cgit From d5daf49b58661ec4af7a55b277176efbf945ca05 Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Wed, 28 Sep 2011 16:41:32 +0200 Subject: USB: gadget: midi: add midi function driver This patch adds f_midi.c to implement a USB gadget function that works with the composite framework, so it can be combined with other USB functions. The code for the ALSA/MIDI logic was taken from the midi device gadget, other parts have been rewritten to benefit from the dynamic descriptor allocation features. This was successfully tested on an OMAP3 board. Signed-off-by: Daniel Mack Cc: Greg Kroah-Hartman Signed-off-by: Felipe Balbi --- drivers/usb/gadget/f_midi.c | 923 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 923 insertions(+) create mode 100644 drivers/usb/gadget/f_midi.c (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/f_midi.c b/drivers/usb/gadget/f_midi.c new file mode 100644 index 000000000000..5064ea4efbed --- /dev/null +++ b/drivers/usb/gadget/f_midi.c @@ -0,0 +1,923 @@ +/* + * f_midi.c -- USB MIDI class function driver + * + * Copyright (C) 2006 Thumtronics Pty Ltd. + * Developed for Thumtronics by Grey Innovation + * Ben Williamson + * + * Rewritten for the composite framework + * Copyright (C) 2011 Daniel Mack + * + * Based on drivers/usb/gadget/f_audio.c, + * Copyright (C) 2008 Bryan Wu + * Copyright (C) 2008 Analog Devices, Inc + * + * and drivers/usb/gadget/midi.c, + * Copyright (C) 2006 Thumtronics Pty Ltd. + * Ben Williamson + * + * Licensed under the GPL-2 or later. + */ + +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + +MODULE_AUTHOR("Ben Williamson"); +MODULE_LICENSE("GPL v2"); + +static const char f_midi_shortname[] = "f_midi"; +static const char f_midi_longname[] = "MIDI Gadget"; + +/* + * This is a gadget, and the IN/OUT naming is from the host's perspective. + * USB -> OUT endpoint -> rawmidi + * USB <- IN endpoint <- rawmidi + */ +struct gmidi_in_port { + struct f_midi *midi; + int active; + uint8_t cable; /* cable number << 4 */ + uint8_t state; +#define STATE_UNKNOWN 0 +#define STATE_1PARAM 1 +#define STATE_2PARAM_1 2 +#define STATE_2PARAM_2 3 +#define STATE_SYSEX_0 4 +#define STATE_SYSEX_1 5 +#define STATE_SYSEX_2 6 + uint8_t data[2]; +}; + +struct f_midi { + struct usb_function func; + struct usb_gadget *gadget; + struct usb_ep *in_ep, *out_ep; + struct snd_card *card; + struct snd_rawmidi *rmidi; + struct snd_rawmidi_substream *in_substream; + struct snd_rawmidi_substream *out_substream; + + /* For the moment we only support one port in + each direction, but in_port is kept as a + separate struct so we can have more later. */ + struct gmidi_in_port in_port; + unsigned long out_triggered; + struct tasklet_struct tasklet; + int index; + char *id; + unsigned int buflen, qlen; +}; + +static inline struct f_midi *func_to_midi(struct usb_function *f) +{ + return container_of(f, struct f_midi, func); +} + +static void f_midi_transmit(struct f_midi *midi, struct usb_request *req); + +DECLARE_UAC_AC_HEADER_DESCRIPTOR(1); +DECLARE_USB_MIDI_OUT_JACK_DESCRIPTOR(1); +DECLARE_USB_MS_ENDPOINT_DESCRIPTOR(1); + +/* B.3.1 Standard AC Interface Descriptor */ +static struct usb_interface_descriptor ac_interface_desc __initdata = { + .bLength = USB_DT_INTERFACE_SIZE, + .bDescriptorType = USB_DT_INTERFACE, + /* .bInterfaceNumber = DYNAMIC */ + /* .bNumEndpoints = DYNAMIC */ + .bInterfaceClass = USB_CLASS_AUDIO, + .bInterfaceSubClass = USB_SUBCLASS_AUDIOCONTROL, + /* .iInterface = DYNAMIC */ +}; + +/* B.3.2 Class-Specific AC Interface Descriptor */ +static struct uac1_ac_header_descriptor_1 ac_header_desc __initdata = { + .bLength = UAC_DT_AC_HEADER_SIZE(1), + .bDescriptorType = USB_DT_CS_INTERFACE, + .bDescriptorSubtype = USB_MS_HEADER, + .bcdADC = cpu_to_le16(0x0100), + .wTotalLength = cpu_to_le16(UAC_DT_AC_HEADER_SIZE(1)), + .bInCollection = 1, + /* .baInterfaceNr = DYNAMIC */ +}; + +/* B.4.1 Standard MS Interface Descriptor */ +static struct usb_interface_descriptor ms_interface_desc __initdata = { + .bLength = USB_DT_INTERFACE_SIZE, + .bDescriptorType = USB_DT_INTERFACE, + /* .bInterfaceNumber = DYNAMIC */ + .bNumEndpoints = 2, + .bInterfaceClass = USB_CLASS_AUDIO, + .bInterfaceSubClass = USB_SUBCLASS_MIDISTREAMING, + /* .iInterface = DYNAMIC */ +}; + +/* B.4.2 Class-Specific MS Interface Descriptor */ +static struct usb_ms_header_descriptor ms_header_desc __initdata = { + .bLength = USB_DT_MS_HEADER_SIZE, + .bDescriptorType = USB_DT_CS_INTERFACE, + .bDescriptorSubtype = USB_MS_HEADER, + .bcdMSC = cpu_to_le16(0x0100), + .wTotalLength = cpu_to_le16(USB_DT_MS_HEADER_SIZE + + 2*USB_DT_MIDI_IN_SIZE + + 2*USB_DT_MIDI_OUT_SIZE(1)), +}; + +#define JACK_IN_EMB 1 +#define JACK_IN_EXT 2 +#define JACK_OUT_EMB 3 +#define JACK_OUT_EXT 4 + +/* B.4.3 MIDI IN Jack Descriptors */ +static const struct usb_midi_in_jack_descriptor jack_in_emb_desc = { + .bLength = USB_DT_MIDI_IN_SIZE, + .bDescriptorType = USB_DT_CS_INTERFACE, + .bDescriptorSubtype = USB_MS_MIDI_IN_JACK, + .bJackType = USB_MS_EMBEDDED, + .bJackID = JACK_IN_EMB, +}; + +static const struct usb_midi_in_jack_descriptor jack_in_ext_desc = { + .bLength = USB_DT_MIDI_IN_SIZE, + .bDescriptorType = USB_DT_CS_INTERFACE, + .bDescriptorSubtype = USB_MS_MIDI_IN_JACK, + .bJackType = USB_MS_EXTERNAL, + .bJackID = JACK_IN_EXT, +}; + +/* B.4.4 MIDI OUT Jack Descriptors */ +static const struct usb_midi_out_jack_descriptor_1 jack_out_emb_desc = { + .bLength = USB_DT_MIDI_OUT_SIZE(1), + .bDescriptorType = USB_DT_CS_INTERFACE, + .bDescriptorSubtype = USB_MS_MIDI_OUT_JACK, + .bJackType = USB_MS_EMBEDDED, + .bJackID = JACK_OUT_EMB, + .bNrInputPins = 1, + .pins = { + [0] = { + .baSourceID = JACK_IN_EXT, + .baSourcePin = 1, + } + } +}; + +static const struct usb_midi_out_jack_descriptor_1 jack_out_ext_desc = { + .bLength = USB_DT_MIDI_OUT_SIZE(1), + .bDescriptorType = USB_DT_CS_INTERFACE, + .bDescriptorSubtype = USB_MS_MIDI_OUT_JACK, + .bJackType = USB_MS_EXTERNAL, + .bJackID = JACK_OUT_EXT, + .bNrInputPins = 1, + .pins = { + [0] = { + .baSourceID = JACK_IN_EMB, + .baSourcePin = 1, + } + } +}; + +/* B.5.1 Standard Bulk OUT Endpoint Descriptor */ +static struct usb_endpoint_descriptor bulk_out_desc = { + .bLength = USB_DT_ENDPOINT_AUDIO_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = USB_DIR_OUT, + .bmAttributes = USB_ENDPOINT_XFER_BULK, +}; + +/* B.5.2 Class-specific MS Bulk OUT Endpoint Descriptor */ +static const struct usb_ms_endpoint_descriptor_1 ms_out_desc = { + .bLength = USB_DT_MS_ENDPOINT_SIZE(1), + .bDescriptorType = USB_DT_CS_ENDPOINT, + .bDescriptorSubtype = USB_MS_GENERAL, + .bNumEmbMIDIJack = 1, + .baAssocJackID = { + [0] = JACK_IN_EMB, + } +}; + +/* B.6.1 Standard Bulk IN Endpoint Descriptor */ +static struct usb_endpoint_descriptor bulk_in_desc = { + .bLength = USB_DT_ENDPOINT_AUDIO_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = USB_DIR_IN, + .bmAttributes = USB_ENDPOINT_XFER_BULK, +}; + +/* B.6.2 Class-specific MS Bulk IN Endpoint Descriptor */ +static const struct usb_ms_endpoint_descriptor_1 ms_in_desc = { + .bLength = USB_DT_MS_ENDPOINT_SIZE(1), + .bDescriptorType = USB_DT_CS_ENDPOINT, + .bDescriptorSubtype = USB_MS_GENERAL, + .bNumEmbMIDIJack = 1, + .baAssocJackID = { + [0] = JACK_OUT_EMB, + } +}; + +static struct usb_descriptor_header *midi_function[] = { + (struct usb_descriptor_header *)&ac_interface_desc, + (struct usb_descriptor_header *)&ac_header_desc, + (struct usb_descriptor_header *)&ms_interface_desc, + + (struct usb_descriptor_header *)&ms_header_desc, + (struct usb_descriptor_header *)&jack_in_emb_desc, + (struct usb_descriptor_header *)&jack_in_ext_desc, + (struct usb_descriptor_header *)&jack_out_emb_desc, + (struct usb_descriptor_header *)&jack_out_ext_desc, + /* If you add more jacks, update ms_header_desc.wTotalLength */ + + (struct usb_descriptor_header *)&bulk_out_desc, + (struct usb_descriptor_header *)&ms_out_desc, + (struct usb_descriptor_header *)&bulk_in_desc, + (struct usb_descriptor_header *)&ms_in_desc, + NULL, +}; + +/* string IDs are assigned dynamically */ + +#define STRING_FUNC_IDX 0 + +static struct usb_string midi_string_defs[] = { + [STRING_FUNC_IDX].s = "MIDI function", + { } /* end of list */ +}; + +static struct usb_gadget_strings midi_stringtab = { + .language = 0x0409, /* en-us */ + .strings = midi_string_defs, +}; + +static struct usb_gadget_strings *midi_strings[] = { + &midi_stringtab, + NULL, +}; + +static struct usb_request *alloc_ep_req(struct usb_ep *ep, unsigned length) +{ + struct usb_request *req; + + req = usb_ep_alloc_request(ep, GFP_ATOMIC); + if (req) { + req->length = length; + req->buf = kmalloc(length, GFP_ATOMIC); + if (!req->buf) { + usb_ep_free_request(ep, req); + req = NULL; + } + } + return req; +} + +static void free_ep_req(struct usb_ep *ep, struct usb_request *req) +{ + kfree(req->buf); + usb_ep_free_request(ep, req); +} + +static const uint8_t f_midi_cin_length[] = { + 0, 0, 2, 3, 3, 1, 2, 3, 3, 3, 3, 3, 2, 2, 3, 1 +}; + +/* + * Receives a chunk of MIDI data. + */ +static void f_midi_read_data(struct usb_ep *ep, int cable, + uint8_t *data, int length) +{ + struct f_midi *midi = ep->driver_data; + /* cable is ignored, because for now we only have one. */ + + if (!midi->out_substream) + /* Nobody is listening - throw it on the floor. */ + return; + + if (!test_bit(midi->out_substream->number, &midi->out_triggered)) + return; + + snd_rawmidi_receive(midi->out_substream, data, length); +} + +static void f_midi_handle_out_data(struct usb_ep *ep, struct usb_request *req) +{ + unsigned int i; + u8 *buf = req->buf; + + for (i = 0; i + 3 < req->actual; i += 4) + if (buf[i] != 0) { + int cable = buf[i] >> 4; + int length = f_midi_cin_length[buf[i] & 0x0f]; + f_midi_read_data(ep, cable, &buf[i + 1], length); + } +} + +static void +f_midi_complete(struct usb_ep *ep, struct usb_request *req) +{ + struct f_midi *midi = ep->driver_data; + struct usb_composite_dev *cdev = midi->func.config->cdev; + int status = req->status; + + switch (status) { + case 0: /* normal completion */ + if (ep == midi->out_ep) { + /* We received stuff. req is queued again, below */ + f_midi_handle_out_data(ep, req); + } else if (ep == midi->in_ep) { + /* Our transmit completed. See if there's more to go. + * f_midi_transmit eats req, don't queue it again. */ + f_midi_transmit(midi, req); + return; + } + break; + + /* this endpoint is normally active while we're configured */ + case -ECONNABORTED: /* hardware forced ep reset */ + case -ECONNRESET: /* request dequeued */ + case -ESHUTDOWN: /* disconnect from host */ + VDBG(cdev, "%s gone (%d), %d/%d\n", ep->name, status, + req->actual, req->length); + if (ep == midi->out_ep) + f_midi_handle_out_data(ep, req); + + free_ep_req(ep, req); + return; + + case -EOVERFLOW: /* buffer overrun on read means that + * we didn't provide a big enough buffer. + */ + default: + DBG(cdev, "%s complete --> %d, %d/%d\n", ep->name, + status, req->actual, req->length); + break; + case -EREMOTEIO: /* short read */ + break; + } + + status = usb_ep_queue(ep, req, GFP_ATOMIC); + if (status) { + ERROR(cdev, "kill %s: resubmit %d bytes --> %d\n", + ep->name, req->length, status); + usb_ep_set_halt(ep); + /* FIXME recover later ... somehow */ + } +} + +static int f_midi_start_ep(struct f_midi *midi, + struct usb_function *f, + struct usb_ep *ep) +{ + int err; + struct usb_composite_dev *cdev = f->config->cdev; + + if (ep->driver_data) + usb_ep_disable(ep); + + err = config_ep_by_speed(midi->gadget, f, ep); + if (err) { + ERROR(cdev, "can't configure %s: %d\n", ep->name, err); + return err; + } + + err = usb_ep_enable(ep); + if (err) { + ERROR(cdev, "can't start %s: %d\n", ep->name, err); + return err; + } + + ep->driver_data = midi; + + return 0; +} + +static int f_midi_set_alt(struct usb_function *f, unsigned intf, unsigned alt) +{ + struct f_midi *midi = func_to_midi(f); + struct usb_composite_dev *cdev = f->config->cdev; + unsigned i; + int err; + + err = f_midi_start_ep(midi, f, midi->in_ep); + if (err) + return err; + + err = f_midi_start_ep(midi, f, midi->out_ep); + if (err) + return err; + + if (midi->out_ep->driver_data) + usb_ep_disable(midi->out_ep); + + err = config_ep_by_speed(midi->gadget, f, midi->out_ep); + if (err) { + ERROR(cdev, "can't configure %s: %d\n", + midi->out_ep->name, err); + return err; + } + + err = usb_ep_enable(midi->out_ep); + if (err) { + ERROR(cdev, "can't start %s: %d\n", + midi->out_ep->name, err); + return err; + } + + midi->out_ep->driver_data = midi; + + /* allocate a bunch of read buffers and queue them all at once. */ + for (i = 0; i < midi->qlen && err == 0; i++) { + struct usb_request *req = + alloc_ep_req(midi->out_ep, midi->buflen); + if (req == NULL) + return -ENOMEM; + + req->complete = f_midi_complete; + err = usb_ep_queue(midi->out_ep, req, GFP_ATOMIC); + if (err) { + ERROR(midi, "%s queue req: %d\n", + midi->out_ep->name, err); + } + } + + return 0; +} + +static void f_midi_disable(struct usb_function *f) +{ + struct f_midi *midi = func_to_midi(f); + struct usb_composite_dev *cdev = f->config->cdev; + + DBG(cdev, "disable\n"); + + /* + * just disable endpoints, forcing completion of pending i/o. + * all our completion handlers free their requests in this case. + */ + usb_ep_disable(midi->in_ep); + usb_ep_disable(midi->out_ep); +} + +static void f_midi_unbind(struct usb_configuration *c, struct usb_function *f) +{ + struct usb_composite_dev *cdev = f->config->cdev; + struct f_midi *midi = func_to_midi(f); + struct snd_card *card; + + DBG(cdev, "unbind\n"); + + /* just to be sure */ + f_midi_disable(f); + + card = midi->card; + midi->card = NULL; + if (card) + snd_card_free(card); + + kfree(midi->id); + midi->id = NULL; + + usb_free_descriptors(f->descriptors); + kfree(midi); +} + +static int f_midi_snd_free(struct snd_device *device) +{ + return 0; +} + +static void f_midi_transmit_packet(struct usb_request *req, uint8_t p0, + uint8_t p1, uint8_t p2, uint8_t p3) +{ + unsigned length = req->length; + u8 *buf = (u8 *)req->buf + length; + + buf[0] = p0; + buf[1] = p1; + buf[2] = p2; + buf[3] = p3; + req->length = length + 4; +} + +/* + * Converts MIDI commands to USB MIDI packets. + */ +static void f_midi_transmit_byte(struct usb_request *req, + struct gmidi_in_port *port, uint8_t b) +{ + uint8_t p0 = port->cable; + + if (b >= 0xf8) { + f_midi_transmit_packet(req, p0 | 0x0f, b, 0, 0); + } else if (b >= 0xf0) { + switch (b) { + case 0xf0: + port->data[0] = b; + port->state = STATE_SYSEX_1; + break; + case 0xf1: + case 0xf3: + port->data[0] = b; + port->state = STATE_1PARAM; + break; + case 0xf2: + port->data[0] = b; + port->state = STATE_2PARAM_1; + break; + case 0xf4: + case 0xf5: + port->state = STATE_UNKNOWN; + break; + case 0xf6: + f_midi_transmit_packet(req, p0 | 0x05, 0xf6, 0, 0); + port->state = STATE_UNKNOWN; + break; + case 0xf7: + switch (port->state) { + case STATE_SYSEX_0: + f_midi_transmit_packet(req, + p0 | 0x05, 0xf7, 0, 0); + break; + case STATE_SYSEX_1: + f_midi_transmit_packet(req, + p0 | 0x06, port->data[0], 0xf7, 0); + break; + case STATE_SYSEX_2: + f_midi_transmit_packet(req, + p0 | 0x07, port->data[0], + port->data[1], 0xf7); + break; + } + port->state = STATE_UNKNOWN; + break; + } + } else if (b >= 0x80) { + port->data[0] = b; + if (b >= 0xc0 && b <= 0xdf) + port->state = STATE_1PARAM; + else + port->state = STATE_2PARAM_1; + } else { /* b < 0x80 */ + switch (port->state) { + case STATE_1PARAM: + if (port->data[0] < 0xf0) { + p0 |= port->data[0] >> 4; + } else { + p0 |= 0x02; + port->state = STATE_UNKNOWN; + } + f_midi_transmit_packet(req, p0, port->data[0], b, 0); + break; + case STATE_2PARAM_1: + port->data[1] = b; + port->state = STATE_2PARAM_2; + break; + case STATE_2PARAM_2: + if (port->data[0] < 0xf0) { + p0 |= port->data[0] >> 4; + port->state = STATE_2PARAM_1; + } else { + p0 |= 0x03; + port->state = STATE_UNKNOWN; + } + f_midi_transmit_packet(req, + p0, port->data[0], port->data[1], b); + break; + case STATE_SYSEX_0: + port->data[0] = b; + port->state = STATE_SYSEX_1; + break; + case STATE_SYSEX_1: + port->data[1] = b; + port->state = STATE_SYSEX_2; + break; + case STATE_SYSEX_2: + f_midi_transmit_packet(req, + p0 | 0x04, port->data[0], port->data[1], b); + port->state = STATE_SYSEX_0; + break; + } + } +} + +static void f_midi_transmit(struct f_midi *midi, struct usb_request *req) +{ + struct usb_ep *ep = midi->in_ep; + struct gmidi_in_port *port = &midi->in_port; + + if (!ep) + return; + + if (!req) + req = alloc_ep_req(ep, midi->buflen); + + if (!req) { + ERROR(midi, "gmidi_transmit: alloc_ep_request failed\n"); + return; + } + req->length = 0; + req->complete = f_midi_complete; + + if (port->active) { + while (req->length + 3 < midi->buflen) { + uint8_t b; + if (snd_rawmidi_transmit(midi->in_substream, &b, 1) != 1) { + port->active = 0; + break; + } + f_midi_transmit_byte(req, port, b); + } + } + + if (req->length > 0) + usb_ep_queue(ep, req, GFP_ATOMIC); + else + free_ep_req(ep, req); +} + +static void f_midi_in_tasklet(unsigned long data) +{ + struct f_midi *midi = (struct f_midi *) data; + f_midi_transmit(midi, NULL); +} + +static int f_midi_in_open(struct snd_rawmidi_substream *substream) +{ + struct f_midi *midi = substream->rmidi->private_data; + + VDBG(midi, "%s()\n", __func__); + midi->in_substream = substream; + midi->in_port.state = STATE_UNKNOWN; + return 0; +} + +static int f_midi_in_close(struct snd_rawmidi_substream *substream) +{ + struct f_midi *midi = substream->rmidi->private_data; + + VDBG(midi, "%s()\n", __func__); + return 0; +} + +static void f_midi_in_trigger(struct snd_rawmidi_substream *substream, int up) +{ + struct f_midi *midi = substream->rmidi->private_data; + + VDBG(midi, "%s() %d\n", __func__, up); + midi->in_port.active = up; + if (up) + tasklet_hi_schedule(&midi->tasklet); +} + +static int f_midi_out_open(struct snd_rawmidi_substream *substream) +{ + struct f_midi *midi = substream->rmidi->private_data; + + VDBG(midi, "%s()\n", __func__); + midi->out_substream = substream; + return 0; +} + +static int f_midi_out_close(struct snd_rawmidi_substream *substream) +{ + struct f_midi *midi = substream->rmidi->private_data; + + VDBG(midi, "%s()\n", __func__); + return 0; +} + +static void f_midi_out_trigger(struct snd_rawmidi_substream *substream, int up) +{ + struct f_midi *midi = substream->rmidi->private_data; + + VDBG(midi, "%s()\n", __func__); + + if (up) + set_bit(substream->number, &midi->out_triggered); + else + clear_bit(substream->number, &midi->out_triggered); +} + +static struct snd_rawmidi_ops gmidi_in_ops = { + .open = f_midi_in_open, + .close = f_midi_in_close, + .trigger = f_midi_in_trigger, +}; + +static struct snd_rawmidi_ops gmidi_out_ops = { + .open = f_midi_out_open, + .close = f_midi_out_close, + .trigger = f_midi_out_trigger +}; + +/* register as a sound "card" */ +static int f_midi_register_card(struct f_midi *midi) +{ + struct snd_card *card; + struct snd_rawmidi *rmidi; + int err; + int out_ports = 1; + int in_ports = 1; + static struct snd_device_ops ops = { + .dev_free = f_midi_snd_free, + }; + + err = snd_card_create(midi->index, midi->id, THIS_MODULE, 0, &card); + if (err < 0) { + ERROR(midi, "snd_card_create() failed\n"); + goto fail; + } + midi->card = card; + + err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, midi, &ops); + if (err < 0) { + ERROR(midi, "snd_device_new() failed: error %d\n", err); + goto fail; + } + + strcpy(card->driver, f_midi_longname); + strcpy(card->longname, f_midi_longname); + strcpy(card->shortname, f_midi_shortname); + + /* Set up rawmidi */ + midi->in_port.midi = midi; + midi->in_port.active = 0; + snd_component_add(card, "MIDI"); + err = snd_rawmidi_new(card, card->longname, 0, + out_ports, in_ports, &rmidi); + if (err < 0) { + ERROR(midi, "snd_rawmidi_new() failed: error %d\n", err); + goto fail; + } + midi->rmidi = rmidi; + strcpy(rmidi->name, card->shortname); + rmidi->info_flags = SNDRV_RAWMIDI_INFO_OUTPUT | + SNDRV_RAWMIDI_INFO_INPUT | + SNDRV_RAWMIDI_INFO_DUPLEX; + rmidi->private_data = midi; + + /* + * Yes, rawmidi OUTPUT = USB IN, and rawmidi INPUT = USB OUT. + * It's an upside-down world being a gadget. + */ + snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, &gmidi_in_ops); + snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT, &gmidi_out_ops); + + snd_card_set_dev(card, &midi->gadget->dev); + + /* register it - we're ready to go */ + err = snd_card_register(card); + if (err < 0) { + ERROR(midi, "snd_card_register() failed\n"); + goto fail; + } + + VDBG(midi, "%s() finished ok\n", __func__); + return 0; + +fail: + if (midi->card) { + snd_card_free(midi->card); + midi->card = NULL; + } + return err; +} + +/* MIDI function driver setup/binding */ + +static int __init +f_midi_bind(struct usb_configuration *c, struct usb_function *f) +{ + struct usb_composite_dev *cdev = c->cdev; + struct f_midi *midi = func_to_midi(f); + int status; + + /* maybe allocate device-global string ID */ + if (midi_string_defs[0].id == 0) { + status = usb_string_id(c->cdev); + if (status < 0) + goto fail; + midi_string_defs[0].id = status; + } + + /* We have two interfaces, AudioControl and MIDIStreaming */ + status = usb_interface_id(c, f); + if (status < 0) + goto fail; + ac_interface_desc.bInterfaceNumber = status; + + status = usb_interface_id(c, f); + if (status < 0) + goto fail; + ms_interface_desc.bInterfaceNumber = status; + ac_header_desc.baInterfaceNr[0] = status; + + status = -ENODEV; + + /* allocate instance-specific endpoints */ + midi->in_ep = usb_ep_autoconfig(cdev->gadget, &bulk_in_desc); + if (!midi->in_ep) + goto fail; + midi->in_ep->driver_data = cdev; /* claim */ + + midi->out_ep = usb_ep_autoconfig(cdev->gadget, &bulk_out_desc); + if (!midi->out_ep) + goto fail; + midi->out_ep->driver_data = cdev; /* claim */ + + /* + * support all relevant hardware speeds... we expect that when + * hardware is dual speed, all bulk-capable endpoints work at + * both speeds + */ + /* copy descriptors, and track endpoint copies */ + 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); + } + + return 0; + +fail: + /* we might as well release our claims on endpoints */ + if (midi->out_ep) + midi->out_ep->driver_data = NULL; + if (midi->in_ep) + midi->in_ep->driver_data = NULL; + + ERROR(cdev, "%s: can't bind, err %d\n", f->name, status); + + return status; +} + +/** + * f_midi_bind_config - add USB MIDI function to a configuration + * @c: the configuration to supcard the USB audio function + * @index: the soundcard index to use for the ALSA device creation + * @id: the soundcard id to use for the ALSA device creation + * @buflen: the buffer length to use + * @qlen the number of read requests to pre-allocate + * Context: single threaded during gadget setup + * + * Returns zero on success, else negative errno. + */ +int __init f_midi_bind_config(struct usb_configuration *c, + int index, char *id, + unsigned int buflen, + unsigned int qlen) +{ + struct f_midi *midi; + int status; + + /* allocate and initialize one new instance */ + midi = kzalloc(sizeof *midi, GFP_KERNEL); + if (!midi) { + status = -ENOMEM; + goto fail; + } + + midi->gadget = c->cdev->gadget; + tasklet_init(&midi->tasklet, f_midi_in_tasklet, (unsigned long) midi); + + /* set up ALSA midi devices */ + status = f_midi_register_card(midi); + if (status < 0) + goto setup_fail; + + midi->func.name = "gmidi function"; + midi->func.strings = midi_strings; + midi->func.bind = f_midi_bind; + midi->func.unbind = f_midi_unbind; + midi->func.set_alt = f_midi_set_alt; + midi->func.disable = f_midi_disable; + + midi->id = kstrdup(id, GFP_KERNEL); + midi->index = index; + midi->buflen = buflen; + midi->qlen = qlen; + + status = usb_add_function(c, &midi->func); + if (status) + goto setup_fail; + + return 0; + +setup_fail: + kfree(midi); +fail: + return status; +} + -- cgit From 2672eea5a38b35e6d28f851e990e110e217271eb Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Wed, 28 Sep 2011 16:41:33 +0200 Subject: USB: gadget: midi: refactor the device code Make use of the newly added MIDI function in f_midi.c and strip down the MIDI gadget code radically. Also use the generic framework function to avoid code duplication and rename some symbols to bring them in sync with other code in the gadget framework. [ balbi@ti.com : fix Section mismatch warnings. rebased on top of usb_speed_string() patch to avoid conflicts. ] Signed-off-by: Daniel Mack Cc: Greg Kroah-Hartman Signed-off-by: Felipe Balbi --- drivers/usb/gadget/f_midi.c | 2 +- drivers/usb/gadget/gmidi.c | 1275 +++---------------------------------------- 2 files changed, 80 insertions(+), 1197 deletions(-) (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/f_midi.c b/drivers/usb/gadget/f_midi.c index 5064ea4efbed..84cbf85d23f8 100644 --- a/drivers/usb/gadget/f_midi.c +++ b/drivers/usb/gadget/f_midi.c @@ -225,7 +225,7 @@ static const struct usb_ms_endpoint_descriptor_1 ms_in_desc = { } }; -static struct usb_descriptor_header *midi_function[] = { +static struct usb_descriptor_header *midi_function[] __initdata = { (struct usb_descriptor_header *)&ac_interface_desc, (struct usb_descriptor_header *)&ac_header_desc, (struct usb_descriptor_header *)&ms_interface_desc, diff --git a/drivers/usb/gadget/gmidi.c b/drivers/usb/gadget/gmidi.c index 893b967b0aff..e7c8c3907133 100644 --- a/drivers/usb/gadget/gmidi.c +++ b/drivers/usb/gadget/gmidi.c @@ -36,134 +36,35 @@ #include "gadget_chips.h" - -/* - * Kbuild is not very cooperative with respect to linking separately - * compiled library objects into one module. So for now we won't use - * separate compilation ... ensuring init/exit sections work to shrink - * the runtime footprint, and giving us at least some parts of what - * a "gcc --combine ... part1.c part2.c part3.c ... " build would. - */ +#include "composite.c" #include "usbstring.c" #include "config.c" #include "epautoconf.c" +#include "f_midi.c" /*-------------------------------------------------------------------------*/ - MODULE_AUTHOR("Ben Williamson"); MODULE_LICENSE("GPL v2"); -#define DRIVER_VERSION "25 Jul 2006" - static const char shortname[] = "g_midi"; static const char longname[] = "MIDI Gadget"; static int index = SNDRV_DEFAULT_IDX1; -static char *id = SNDRV_DEFAULT_STR1; - -module_param(index, int, 0444); +module_param(index, int, S_IRUGO); MODULE_PARM_DESC(index, "Index value for the USB MIDI Gadget adapter."); -module_param(id, charp, 0444); -MODULE_PARM_DESC(id, "ID string for the USB MIDI Gadget adapter."); - -/* Some systems will want different product identifiers published in the - * device descriptor, either numbers or strings or both. These string - * parameters are in UTF-8 (superset of ASCII's 7 bit characters). - */ - -static ushort idVendor; -module_param(idVendor, ushort, S_IRUGO); -MODULE_PARM_DESC(idVendor, "USB Vendor ID"); - -static ushort idProduct; -module_param(idProduct, ushort, S_IRUGO); -MODULE_PARM_DESC(idProduct, "USB Product ID"); - -static ushort bcdDevice; -module_param(bcdDevice, ushort, S_IRUGO); -MODULE_PARM_DESC(bcdDevice, "USB Device version (BCD)"); - -static char *iManufacturer; -module_param(iManufacturer, charp, S_IRUGO); -MODULE_PARM_DESC(iManufacturer, "USB Manufacturer string"); - -static char *iProduct; -module_param(iProduct, charp, S_IRUGO); -MODULE_PARM_DESC(iProduct, "USB Product string"); - -static char *iSerialNumber; -module_param(iSerialNumber, charp, S_IRUGO); -MODULE_PARM_DESC(iSerialNumber, "SerialNumber"); - -/* - * this version autoconfigures as much as possible, - * which is reasonable for most "bulk-only" drivers. - */ -static const char *EP_IN_NAME; -static const char *EP_OUT_NAME; +static char *id = SNDRV_DEFAULT_STR1; +module_param(id, charp, S_IRUGO); +MODULE_PARM_DESC(id, "ID string for the USB MIDI Gadget adapter."); -/* big enough to hold our biggest descriptor */ -#define USB_BUFSIZ 256 - - -/* This is a gadget, and the IN/OUT naming is from the host's perspective. - USB -> OUT endpoint -> rawmidi - USB <- IN endpoint <- rawmidi */ -struct gmidi_in_port { - struct gmidi_device* dev; - int active; - uint8_t cable; /* cable number << 4 */ - uint8_t state; -#define STATE_UNKNOWN 0 -#define STATE_1PARAM 1 -#define STATE_2PARAM_1 2 -#define STATE_2PARAM_2 3 -#define STATE_SYSEX_0 4 -#define STATE_SYSEX_1 5 -#define STATE_SYSEX_2 6 - uint8_t data[2]; -}; - -struct gmidi_device { - spinlock_t lock; - struct usb_gadget *gadget; - struct usb_request *req; /* for control responses */ - u8 config; - struct usb_ep *in_ep, *out_ep; - struct snd_card *card; - struct snd_rawmidi *rmidi; - struct snd_rawmidi_substream *in_substream; - struct snd_rawmidi_substream *out_substream; - - /* For the moment we only support one port in - each direction, but in_port is kept as a - separate struct so we can have more later. */ - struct gmidi_in_port in_port; - unsigned long out_triggered; - struct tasklet_struct tasklet; -}; - -static void gmidi_transmit(struct gmidi_device* dev, struct usb_request* req); - - -#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 INFO(d, fmt, args...) \ - dev_info(&(d)->gadget->dev , fmt , ## args) - - -static unsigned buflen = 256; -static unsigned qlen = 32; - +static unsigned int buflen = 256; module_param(buflen, uint, S_IRUGO); -module_param(qlen, uint, S_IRUGO); +MODULE_PARM_DESC(buflen, "MIDI buffer length"); +static unsigned int qlen = 32; +module_param(qlen, uint, S_IRUGO); +MODULE_PARM_DESC(qlen, "USB read request queue length"); /* Thanks to Grey Innovation for donating this product ID. * @@ -173,1140 +74,122 @@ module_param(qlen, uint, S_IRUGO); #define DRIVER_VENDOR_NUM 0x17b3 /* Grey Innovation */ #define DRIVER_PRODUCT_NUM 0x0004 /* Linux-USB "MIDI Gadget" */ +/* string IDs are assigned dynamically */ -/* - * DESCRIPTORS ... most are static, but strings and (full) - * configuration descriptors are built on demand. - */ - -#define STRING_MANUFACTURER 25 -#define STRING_PRODUCT 42 -#define STRING_SERIAL 101 -#define STRING_MIDI_GADGET 250 - -/* We only have the one configuration, it's number 1. */ -#define GMIDI_CONFIG 1 - -/* We have two interfaces- AudioControl and MIDIStreaming */ -#define GMIDI_AC_INTERFACE 0 -#define GMIDI_MS_INTERFACE 1 -#define GMIDI_NUM_INTERFACES 2 +#define STRING_MANUFACTURER_IDX 0 +#define STRING_PRODUCT_IDX 1 +#define STRING_DESCRIPTION_IDX 2 -DECLARE_UAC_AC_HEADER_DESCRIPTOR(1); -DECLARE_USB_MIDI_OUT_JACK_DESCRIPTOR(1); -DECLARE_USB_MS_ENDPOINT_DESCRIPTOR(1); - -/* B.1 Device Descriptor */ static struct usb_device_descriptor device_desc = { .bLength = USB_DT_DEVICE_SIZE, .bDescriptorType = USB_DT_DEVICE, - .bcdUSB = cpu_to_le16(0x0200), + .bcdUSB = __constant_cpu_to_le16(0x0200), .bDeviceClass = USB_CLASS_PER_INTERFACE, - .idVendor = cpu_to_le16(DRIVER_VENDOR_NUM), - .idProduct = cpu_to_le16(DRIVER_PRODUCT_NUM), - .iManufacturer = STRING_MANUFACTURER, - .iProduct = STRING_PRODUCT, + .idVendor = __constant_cpu_to_le16(DRIVER_VENDOR_NUM), + .idProduct = __constant_cpu_to_le16(DRIVER_PRODUCT_NUM), + /* .iManufacturer = DYNAMIC */ + /* .iProduct = DYNAMIC */ .bNumConfigurations = 1, }; -/* B.2 Configuration Descriptor */ -static struct usb_config_descriptor config_desc = { - .bLength = USB_DT_CONFIG_SIZE, - .bDescriptorType = USB_DT_CONFIG, - /* compute wTotalLength on the fly */ - .bNumInterfaces = GMIDI_NUM_INTERFACES, - .bConfigurationValue = GMIDI_CONFIG, - .iConfiguration = STRING_MIDI_GADGET, - /* - * FIXME: When embedding this driver in a device, - * these need to be set to reflect the actual - * power properties of the device. Is it selfpowered? - */ - .bmAttributes = USB_CONFIG_ATT_ONE, - .bMaxPower = CONFIG_USB_GADGET_VBUS_DRAW / 2, -}; - -/* B.3.1 Standard AC Interface Descriptor */ -static const struct usb_interface_descriptor ac_interface_desc = { - .bLength = USB_DT_INTERFACE_SIZE, - .bDescriptorType = USB_DT_INTERFACE, - .bInterfaceNumber = GMIDI_AC_INTERFACE, - .bNumEndpoints = 0, - .bInterfaceClass = USB_CLASS_AUDIO, - .bInterfaceSubClass = USB_SUBCLASS_AUDIOCONTROL, - .iInterface = STRING_MIDI_GADGET, -}; - -/* B.3.2 Class-Specific AC Interface Descriptor */ -static const struct uac1_ac_header_descriptor_1 ac_header_desc = { - .bLength = UAC_DT_AC_HEADER_SIZE(1), - .bDescriptorType = USB_DT_CS_INTERFACE, - .bDescriptorSubtype = USB_MS_HEADER, - .bcdADC = cpu_to_le16(0x0100), - .wTotalLength = cpu_to_le16(UAC_DT_AC_HEADER_SIZE(1)), - .bInCollection = 1, - .baInterfaceNr = { - [0] = GMIDI_MS_INTERFACE, - } -}; - -/* B.4.1 Standard MS Interface Descriptor */ -static const struct usb_interface_descriptor ms_interface_desc = { - .bLength = USB_DT_INTERFACE_SIZE, - .bDescriptorType = USB_DT_INTERFACE, - .bInterfaceNumber = GMIDI_MS_INTERFACE, - .bNumEndpoints = 2, - .bInterfaceClass = USB_CLASS_AUDIO, - .bInterfaceSubClass = USB_SUBCLASS_MIDISTREAMING, - .iInterface = STRING_MIDI_GADGET, -}; - -/* B.4.2 Class-Specific MS Interface Descriptor */ -static const struct usb_ms_header_descriptor ms_header_desc = { - .bLength = USB_DT_MS_HEADER_SIZE, - .bDescriptorType = USB_DT_CS_INTERFACE, - .bDescriptorSubtype = USB_MS_HEADER, - .bcdMSC = cpu_to_le16(0x0100), - .wTotalLength = cpu_to_le16(USB_DT_MS_HEADER_SIZE - + 2*USB_DT_MIDI_IN_SIZE - + 2*USB_DT_MIDI_OUT_SIZE(1)), -}; - -#define JACK_IN_EMB 1 -#define JACK_IN_EXT 2 -#define JACK_OUT_EMB 3 -#define JACK_OUT_EXT 4 - -/* B.4.3 MIDI IN Jack Descriptors */ -static const struct usb_midi_in_jack_descriptor jack_in_emb_desc = { - .bLength = USB_DT_MIDI_IN_SIZE, - .bDescriptorType = USB_DT_CS_INTERFACE, - .bDescriptorSubtype = USB_MS_MIDI_IN_JACK, - .bJackType = USB_MS_EMBEDDED, - .bJackID = JACK_IN_EMB, -}; - -static const struct usb_midi_in_jack_descriptor jack_in_ext_desc = { - .bLength = USB_DT_MIDI_IN_SIZE, - .bDescriptorType = USB_DT_CS_INTERFACE, - .bDescriptorSubtype = USB_MS_MIDI_IN_JACK, - .bJackType = USB_MS_EXTERNAL, - .bJackID = JACK_IN_EXT, -}; - -/* B.4.4 MIDI OUT Jack Descriptors */ -static const struct usb_midi_out_jack_descriptor_1 jack_out_emb_desc = { - .bLength = USB_DT_MIDI_OUT_SIZE(1), - .bDescriptorType = USB_DT_CS_INTERFACE, - .bDescriptorSubtype = USB_MS_MIDI_OUT_JACK, - .bJackType = USB_MS_EMBEDDED, - .bJackID = JACK_OUT_EMB, - .bNrInputPins = 1, - .pins = { - [0] = { - .baSourceID = JACK_IN_EXT, - .baSourcePin = 1, - } - } -}; - -static const struct usb_midi_out_jack_descriptor_1 jack_out_ext_desc = { - .bLength = USB_DT_MIDI_OUT_SIZE(1), - .bDescriptorType = USB_DT_CS_INTERFACE, - .bDescriptorSubtype = USB_MS_MIDI_OUT_JACK, - .bJackType = USB_MS_EXTERNAL, - .bJackID = JACK_OUT_EXT, - .bNrInputPins = 1, - .pins = { - [0] = { - .baSourceID = JACK_IN_EMB, - .baSourcePin = 1, - } - } -}; - -/* B.5.1 Standard Bulk OUT Endpoint Descriptor */ -static struct usb_endpoint_descriptor bulk_out_desc = { - .bLength = USB_DT_ENDPOINT_AUDIO_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = USB_DIR_OUT, - .bmAttributes = USB_ENDPOINT_XFER_BULK, -}; - -/* B.5.2 Class-specific MS Bulk OUT Endpoint Descriptor */ -static const struct usb_ms_endpoint_descriptor_1 ms_out_desc = { - .bLength = USB_DT_MS_ENDPOINT_SIZE(1), - .bDescriptorType = USB_DT_CS_ENDPOINT, - .bDescriptorSubtype = USB_MS_GENERAL, - .bNumEmbMIDIJack = 1, - .baAssocJackID = { - [0] = JACK_IN_EMB, - } -}; - -/* B.6.1 Standard Bulk IN Endpoint Descriptor */ -static struct usb_endpoint_descriptor bulk_in_desc = { - .bLength = USB_DT_ENDPOINT_AUDIO_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = USB_DIR_IN, - .bmAttributes = USB_ENDPOINT_XFER_BULK, -}; - -/* B.6.2 Class-specific MS Bulk IN Endpoint Descriptor */ -static const struct usb_ms_endpoint_descriptor_1 ms_in_desc = { - .bLength = USB_DT_MS_ENDPOINT_SIZE(1), - .bDescriptorType = USB_DT_CS_ENDPOINT, - .bDescriptorSubtype = USB_MS_GENERAL, - .bNumEmbMIDIJack = 1, - .baAssocJackID = { - [0] = JACK_OUT_EMB, - } -}; - -static const struct usb_descriptor_header *gmidi_function [] = { - (struct usb_descriptor_header *)&ac_interface_desc, - (struct usb_descriptor_header *)&ac_header_desc, - (struct usb_descriptor_header *)&ms_interface_desc, - - (struct usb_descriptor_header *)&ms_header_desc, - (struct usb_descriptor_header *)&jack_in_emb_desc, - (struct usb_descriptor_header *)&jack_in_ext_desc, - (struct usb_descriptor_header *)&jack_out_emb_desc, - (struct usb_descriptor_header *)&jack_out_ext_desc, - /* If you add more jacks, update ms_header_desc.wTotalLength */ - - (struct usb_descriptor_header *)&bulk_out_desc, - (struct usb_descriptor_header *)&ms_out_desc, - (struct usb_descriptor_header *)&bulk_in_desc, - (struct usb_descriptor_header *)&ms_in_desc, - NULL, -}; - -static char manufacturer[50]; -static char product_desc[40] = "MIDI Gadget"; -static char serial_number[20]; - -/* static strings, in UTF-8 */ -static struct usb_string strings [] = { - { STRING_MANUFACTURER, manufacturer, }, - { STRING_PRODUCT, product_desc, }, - { STRING_SERIAL, serial_number, }, - { STRING_MIDI_GADGET, longname, }, - { } /* end of list */ +static struct usb_string strings_dev[] = { + [STRING_MANUFACTURER_IDX].s = "Grey Innovation", + [STRING_PRODUCT_IDX].s = "MIDI Gadget", + [STRING_DESCRIPTION_IDX].s = "MIDI", + { } /* end of list */ }; -static struct usb_gadget_strings stringtab = { +static struct usb_gadget_strings stringtab_dev = { .language = 0x0409, /* en-us */ - .strings = strings, + .strings = strings_dev, }; -static int config_buf(struct usb_gadget *gadget, - u8 *buf, u8 type, unsigned index) -{ - int len; - - /* only one configuration */ - if (index != 0) { - return -EINVAL; - } - len = usb_gadget_config_buf(&config_desc, - buf, USB_BUFSIZ, gmidi_function); - if (len < 0) { - return len; - } - ((struct usb_config_descriptor *)buf)->bDescriptorType = type; - return len; -} - -static struct usb_request *alloc_ep_req(struct usb_ep *ep, unsigned length) -{ - struct usb_request *req; - - req = usb_ep_alloc_request(ep, GFP_ATOMIC); - if (req) { - req->length = length; - req->buf = kmalloc(length, GFP_ATOMIC); - if (!req->buf) { - usb_ep_free_request(ep, req); - req = NULL; - } - } - return req; -} - -static void free_ep_req(struct usb_ep *ep, struct usb_request *req) -{ - kfree(req->buf); - usb_ep_free_request(ep, req); -} - -static const uint8_t gmidi_cin_length[] = { - 0, 0, 2, 3, 3, 1, 2, 3, 3, 3, 3, 3, 2, 2, 3, 1 +static struct usb_gadget_strings *dev_strings[] = { + &stringtab_dev, + NULL, }; -/* - * Receives a chunk of MIDI data. - */ -static void gmidi_read_data(struct usb_ep *ep, int cable, - uint8_t *data, int length) -{ - struct gmidi_device *dev = ep->driver_data; - /* cable is ignored, because for now we only have one. */ - - if (!dev->out_substream) { - /* Nobody is listening - throw it on the floor. */ - return; - } - if (!test_bit(dev->out_substream->number, &dev->out_triggered)) { - return; - } - snd_rawmidi_receive(dev->out_substream, data, length); -} - -static void gmidi_handle_out_data(struct usb_ep *ep, struct usb_request *req) -{ - unsigned i; - u8 *buf = req->buf; - - for (i = 0; i + 3 < req->actual; i += 4) { - if (buf[i] != 0) { - int cable = buf[i] >> 4; - int length = gmidi_cin_length[buf[i] & 0x0f]; - gmidi_read_data(ep, cable, &buf[i + 1], length); - } - } -} - -static void gmidi_complete(struct usb_ep *ep, struct usb_request *req) -{ - struct gmidi_device *dev = ep->driver_data; - int status = req->status; - - switch (status) { - case 0: /* normal completion */ - if (ep == dev->out_ep) { - /* we received stuff. - req is queued again, below */ - gmidi_handle_out_data(ep, req); - } else if (ep == dev->in_ep) { - /* our transmit completed. - see if there's more to go. - gmidi_transmit eats req, don't queue it again. */ - gmidi_transmit(dev, req); - return; - } - break; - - /* this endpoint is normally active while we're configured */ - case -ECONNABORTED: /* hardware forced ep reset */ - case -ECONNRESET: /* request dequeued */ - case -ESHUTDOWN: /* disconnect from host */ - VDBG(dev, "%s gone (%d), %d/%d\n", ep->name, status, - req->actual, req->length); - if (ep == dev->out_ep) { - gmidi_handle_out_data(ep, req); - } - free_ep_req(ep, req); - return; - - case -EOVERFLOW: /* buffer overrun on read means that - * we didn't provide a big enough - * buffer. - */ - default: - DBG(dev, "%s complete --> %d, %d/%d\n", ep->name, - status, req->actual, req->length); - break; - case -EREMOTEIO: /* short read */ - break; - } - - status = usb_ep_queue(ep, req, GFP_ATOMIC); - if (status) { - ERROR(dev, "kill %s: resubmit %d bytes --> %d\n", - ep->name, req->length, status); - usb_ep_set_halt(ep); - /* FIXME recover later ... somehow */ - } -} - -static int set_gmidi_config(struct gmidi_device *dev, gfp_t gfp_flags) -{ - int err = 0; - struct usb_request *req; - struct usb_ep *ep; - unsigned i; - - dev->in_ep->desc = &bulk_in_desc; - err = usb_ep_enable(dev->in_ep); - if (err) { - ERROR(dev, "can't start %s: %d\n", dev->in_ep->name, err); - goto fail; - } - dev->in_ep->driver_data = dev; - - dev->out_ep->desc = &bulk_out_desc; - err = usb_ep_enable(dev->out_ep); - if (err) { - ERROR(dev, "can't start %s: %d\n", dev->out_ep->name, err); - goto fail; - } - dev->out_ep->driver_data = dev; - - /* allocate a bunch of read buffers and queue them all at once. */ - ep = dev->out_ep; - for (i = 0; i < qlen && err == 0; i++) { - req = alloc_ep_req(ep, buflen); - if (req) { - req->complete = gmidi_complete; - err = usb_ep_queue(ep, req, GFP_ATOMIC); - if (err) { - DBG(dev, "%s queue req: %d\n", ep->name, err); - } - } else { - err = -ENOMEM; - } - } -fail: - /* caller is responsible for cleanup on error */ - return err; -} - - -static void gmidi_reset_config(struct gmidi_device *dev) -{ - if (dev->config == 0) { - return; - } - - DBG(dev, "reset config\n"); - - /* just disable endpoints, forcing completion of pending i/o. - * all our completion handlers free their requests in this case. - */ - usb_ep_disable(dev->in_ep); - usb_ep_disable(dev->out_ep); - dev->config = 0; -} - -/* change our operational config. this code must agree with the code - * that returns config descriptors, and altsetting code. - * - * it's also responsible for power management interactions. some - * configurations might not work with our current power sources. - * - * note that some device controller hardware will constrain what this - * code can do, perhaps by disallowing more than one configuration or - * by limiting configuration choices (like the pxa2xx). - */ -static int -gmidi_set_config(struct gmidi_device *dev, unsigned number, gfp_t gfp_flags) -{ - int result = 0; - struct usb_gadget *gadget = dev->gadget; - -#if 0 - /* FIXME */ - /* Hacking this bit out fixes a bug where on receipt of two - USB_REQ_SET_CONFIGURATION messages, we end up with no - buffered OUT requests waiting for data. This is clearly - hiding a bug elsewhere, because if the config didn't - change then we really shouldn't do anything. */ - /* Having said that, when we do "change" from config 1 - to config 1, we at least gmidi_reset_config() which - clears out any requests on endpoints, so it's not like - we leak or anything. */ - if (number == dev->config) { - return 0; - } -#endif - - gmidi_reset_config(dev); - - switch (number) { - case GMIDI_CONFIG: - result = set_gmidi_config(dev, gfp_flags); - break; - default: - result = -EINVAL; - /* FALL THROUGH */ - case 0: - return result; - } - - if (!result && (!dev->in_ep || !dev->out_ep)) { - result = -ENODEV; - } - if (result) { - gmidi_reset_config(dev); - } else { - dev->config = number; - INFO(dev, "%s speed\n", usb_speed_string(gadget->speed)); - } - return result; -} - - -static void gmidi_setup_complete(struct usb_ep *ep, struct usb_request *req) +static int __exit midi_unbind(struct usb_composite_dev *dev) { - if (req->status || req->actual != req->length) { - DBG((struct gmidi_device *) ep->driver_data, - "setup complete --> %d, %d/%d\n", - req->status, req->actual, req->length); - } -} - -/* - * The setup() callback implements all the ep0 functionality that's - * not handled lower down, in hardware or the hardware driver (like - * device and endpoint feature flags, and their status). It's all - * housekeeping for the gadget function we're implementing. Most of - * the work is in config-specific setup. - */ -static int gmidi_setup(struct usb_gadget *gadget, - const struct usb_ctrlrequest *ctrl) -{ - struct gmidi_device *dev = get_gadget_data(gadget); - struct usb_request *req = dev->req; - 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); - - /* usually this stores reply data in the pre-allocated ep0 buffer, - * but config change events will reconfigure hardware. - */ - req->zero = 0; - switch (ctrl->bRequest) { - - case USB_REQ_GET_DESCRIPTOR: - if (ctrl->bRequestType != USB_DIR_IN) { - goto unknown; - } - switch (w_value >> 8) { - - case USB_DT_DEVICE: - device_desc.bMaxPacketSize0 = gadget->ep0->maxpacket; - value = min(w_length, (u16) sizeof(device_desc)); - memcpy(req->buf, &device_desc, value); - break; - case USB_DT_CONFIG: - value = config_buf(gadget, req->buf, - w_value >> 8, - w_value & 0xff); - if (value >= 0) { - value = min(w_length, (u16)value); - } - break; - - case USB_DT_STRING: - /* wIndex == language code. - * this driver only handles one language, you can - * add string tables for other languages, using - * any UTF-8 characters - */ - value = usb_gadget_get_string(&stringtab, - w_value & 0xff, req->buf); - if (value >= 0) { - value = min(w_length, (u16)value); - } - break; - } - break; - - /* currently two configs, two speeds */ - case USB_REQ_SET_CONFIGURATION: - if (ctrl->bRequestType != 0) { - goto unknown; - } - if (gadget->a_hnp_support) { - DBG(dev, "HNP available\n"); - } else if (gadget->a_alt_hnp_support) { - DBG(dev, "HNP needs a different root port\n"); - } else { - VDBG(dev, "HNP inactive\n"); - } - spin_lock(&dev->lock); - value = gmidi_set_config(dev, w_value, GFP_ATOMIC); - spin_unlock(&dev->lock); - break; - case USB_REQ_GET_CONFIGURATION: - if (ctrl->bRequestType != USB_DIR_IN) { - goto unknown; - } - *(u8 *)req->buf = dev->config; - value = min(w_length, (u16)1); - break; - - /* until we add altsetting support, or other interfaces, - * only 0/0 are possible. pxa2xx only supports 0/0 (poorly) - * and already killed pending endpoint I/O. - */ - case USB_REQ_SET_INTERFACE: - if (ctrl->bRequestType != USB_RECIP_INTERFACE) { - goto unknown; - } - spin_lock(&dev->lock); - if (dev->config && w_index < GMIDI_NUM_INTERFACES - && w_value == 0) - { - u8 config = dev->config; - - /* resets interface configuration, forgets about - * previous transaction state (queued bufs, etc) - * and re-inits endpoint state (toggle etc) - * no response queued, just zero status == success. - * if we had more than one interface we couldn't - * use this "reset the config" shortcut. - */ - gmidi_reset_config(dev); - gmidi_set_config(dev, config, GFP_ATOMIC); - value = 0; - } - spin_unlock(&dev->lock); - break; - case USB_REQ_GET_INTERFACE: - if (ctrl->bRequestType != (USB_DIR_IN|USB_RECIP_INTERFACE)) { - goto unknown; - } - if (!dev->config) { - break; - } - if (w_index >= GMIDI_NUM_INTERFACES) { - value = -EDOM; - break; - } - *(u8 *)req->buf = 0; - value = min(w_length, (u16)1); - break; - - default: -unknown: - VDBG(dev, "unknown control req%02x.%02x v%04x i%04x l%d\n", - ctrl->bRequestType, ctrl->bRequest, - w_value, w_index, w_length); - } - - /* respond with data transfer before status phase? */ - if (value >= 0) { - req->length = value; - req->zero = value < w_length; - value = usb_ep_queue(gadget->ep0, req, GFP_ATOMIC); - if (value < 0) { - DBG(dev, "ep_queue --> %d\n", value); - req->status = 0; - gmidi_setup_complete(gadget->ep0, req); - } - } - - /* device either stalls (value < 0) or reports success */ - return value; -} - -static void gmidi_disconnect(struct usb_gadget *gadget) -{ - struct gmidi_device *dev = get_gadget_data(gadget); - unsigned long flags; - - spin_lock_irqsave(&dev->lock, flags); - gmidi_reset_config(dev); - - /* a more significant application might have some non-usb - * activities to quiesce here, saving resources like power - * or pushing the notification up a network stack. - */ - spin_unlock_irqrestore(&dev->lock, flags); - - /* next we may get setup() calls to enumerate new connections; - * or an unbind() during shutdown (including removing module). - */ -} - -static void /* __init_or_exit */ gmidi_unbind(struct usb_gadget *gadget) -{ - struct gmidi_device *dev = get_gadget_data(gadget); - struct snd_card *card; - - DBG(dev, "unbind\n"); - - card = dev->card; - dev->card = NULL; - if (card) { - snd_card_free(card); - } - - /* we've already been disconnected ... no i/o is active */ - if (dev->req) { - dev->req->length = USB_BUFSIZ; - free_ep_req(gadget->ep0, dev->req); - } - kfree(dev); - set_gadget_data(gadget, NULL); -} - -static int gmidi_snd_free(struct snd_device *device) -{ - return 0; -} - -static void gmidi_transmit_packet(struct usb_request *req, uint8_t p0, - uint8_t p1, uint8_t p2, uint8_t p3) -{ - unsigned length = req->length; - u8 *buf = (u8 *)req->buf + length; - - buf[0] = p0; - buf[1] = p1; - buf[2] = p2; - buf[3] = p3; - req->length = length + 4; -} - -/* - * Converts MIDI commands to USB MIDI packets. - */ -static void gmidi_transmit_byte(struct usb_request *req, - struct gmidi_in_port *port, uint8_t b) -{ - uint8_t p0 = port->cable; - - if (b >= 0xf8) { - gmidi_transmit_packet(req, p0 | 0x0f, b, 0, 0); - } else if (b >= 0xf0) { - switch (b) { - case 0xf0: - port->data[0] = b; - port->state = STATE_SYSEX_1; - break; - case 0xf1: - case 0xf3: - port->data[0] = b; - port->state = STATE_1PARAM; - break; - case 0xf2: - port->data[0] = b; - port->state = STATE_2PARAM_1; - break; - case 0xf4: - case 0xf5: - port->state = STATE_UNKNOWN; - break; - case 0xf6: - gmidi_transmit_packet(req, p0 | 0x05, 0xf6, 0, 0); - port->state = STATE_UNKNOWN; - break; - case 0xf7: - switch (port->state) { - case STATE_SYSEX_0: - gmidi_transmit_packet(req, - p0 | 0x05, 0xf7, 0, 0); - break; - case STATE_SYSEX_1: - gmidi_transmit_packet(req, - p0 | 0x06, port->data[0], 0xf7, 0); - break; - case STATE_SYSEX_2: - gmidi_transmit_packet(req, - p0 | 0x07, port->data[0], - port->data[1], 0xf7); - break; - } - port->state = STATE_UNKNOWN; - break; - } - } else if (b >= 0x80) { - port->data[0] = b; - if (b >= 0xc0 && b <= 0xdf) - port->state = STATE_1PARAM; - else - port->state = STATE_2PARAM_1; - } else { /* b < 0x80 */ - switch (port->state) { - case STATE_1PARAM: - if (port->data[0] < 0xf0) { - p0 |= port->data[0] >> 4; - } else { - p0 |= 0x02; - port->state = STATE_UNKNOWN; - } - gmidi_transmit_packet(req, p0, port->data[0], b, 0); - break; - case STATE_2PARAM_1: - port->data[1] = b; - port->state = STATE_2PARAM_2; - break; - case STATE_2PARAM_2: - if (port->data[0] < 0xf0) { - p0 |= port->data[0] >> 4; - port->state = STATE_2PARAM_1; - } else { - p0 |= 0x03; - port->state = STATE_UNKNOWN; - } - gmidi_transmit_packet(req, - p0, port->data[0], port->data[1], b); - break; - case STATE_SYSEX_0: - port->data[0] = b; - port->state = STATE_SYSEX_1; - break; - case STATE_SYSEX_1: - port->data[1] = b; - port->state = STATE_SYSEX_2; - break; - case STATE_SYSEX_2: - gmidi_transmit_packet(req, - p0 | 0x04, port->data[0], port->data[1], b); - port->state = STATE_SYSEX_0; - break; - } - } -} - -static void gmidi_transmit(struct gmidi_device *dev, struct usb_request *req) -{ - struct usb_ep *ep = dev->in_ep; - struct gmidi_in_port *port = &dev->in_port; - - if (!ep) { - return; - } - if (!req) { - req = alloc_ep_req(ep, buflen); - } - if (!req) { - ERROR(dev, "gmidi_transmit: alloc_ep_request failed\n"); - return; - } - req->length = 0; - req->complete = gmidi_complete; - - if (port->active) { - while (req->length + 3 < buflen) { - uint8_t b; - if (snd_rawmidi_transmit(dev->in_substream, &b, 1) - != 1) - { - port->active = 0; - break; - } - gmidi_transmit_byte(req, port, b); - } - } - if (req->length > 0) { - usb_ep_queue(ep, req, GFP_ATOMIC); - } else { - free_ep_req(ep, req); - } -} - -static void gmidi_in_tasklet(unsigned long data) -{ - struct gmidi_device *dev = (struct gmidi_device *)data; - - gmidi_transmit(dev, NULL); -} - -static int gmidi_in_open(struct snd_rawmidi_substream *substream) -{ - struct gmidi_device *dev = substream->rmidi->private_data; - - VDBG(dev, "gmidi_in_open\n"); - dev->in_substream = substream; - dev->in_port.state = STATE_UNKNOWN; - return 0; -} - -static int gmidi_in_close(struct snd_rawmidi_substream *substream) -{ - struct gmidi_device *dev = substream->rmidi->private_data; - - VDBG(dev, "gmidi_in_close\n"); - return 0; -} - -static void gmidi_in_trigger(struct snd_rawmidi_substream *substream, int up) -{ - struct gmidi_device *dev = substream->rmidi->private_data; - - VDBG(dev, "gmidi_in_trigger %d\n", up); - dev->in_port.active = up; - if (up) { - tasklet_hi_schedule(&dev->tasklet); - } -} - -static int gmidi_out_open(struct snd_rawmidi_substream *substream) -{ - struct gmidi_device *dev = substream->rmidi->private_data; - - VDBG(dev, "gmidi_out_open\n"); - dev->out_substream = substream; return 0; } -static int gmidi_out_close(struct snd_rawmidi_substream *substream) -{ - struct gmidi_device *dev = substream->rmidi->private_data; - - VDBG(dev, "gmidi_out_close\n"); - return 0; -} - -static void gmidi_out_trigger(struct snd_rawmidi_substream *substream, int up) -{ - struct gmidi_device *dev = substream->rmidi->private_data; - - VDBG(dev, "gmidi_out_trigger %d\n", up); - if (up) { - set_bit(substream->number, &dev->out_triggered); - } else { - clear_bit(substream->number, &dev->out_triggered); - } -} - -static struct snd_rawmidi_ops gmidi_in_ops = { - .open = gmidi_in_open, - .close = gmidi_in_close, - .trigger = gmidi_in_trigger, +static struct usb_configuration midi_config = { + .label = "MIDI Gadget", + .bConfigurationValue = 1, + /* .iConfiguration = DYNAMIC */ + .bmAttributes = USB_CONFIG_ATT_ONE, + .bMaxPower = CONFIG_USB_GADGET_VBUS_DRAW / 2, }; -static struct snd_rawmidi_ops gmidi_out_ops = { - .open = gmidi_out_open, - .close = gmidi_out_close, - .trigger = gmidi_out_trigger -}; - -/* register as a sound "card" */ -static int gmidi_register_card(struct gmidi_device *dev) +static int __init midi_bind_config(struct usb_configuration *c) { - struct snd_card *card; - struct snd_rawmidi *rmidi; - int err; - int out_ports = 1; - int in_ports = 1; - static struct snd_device_ops ops = { - .dev_free = gmidi_snd_free, - }; - - err = snd_card_create(index, id, THIS_MODULE, 0, &card); - if (err < 0) { - ERROR(dev, "snd_card_create failed\n"); - goto fail; - } - dev->card = card; - - err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, dev, &ops); - if (err < 0) { - ERROR(dev, "snd_device_new failed: error %d\n", err); - goto fail; - } - - strcpy(card->driver, longname); - strcpy(card->longname, longname); - strcpy(card->shortname, shortname); - - /* Set up rawmidi */ - dev->in_port.dev = dev; - dev->in_port.active = 0; - snd_component_add(card, "MIDI"); - err = snd_rawmidi_new(card, "USB MIDI Gadget", 0, - out_ports, in_ports, &rmidi); - if (err < 0) { - ERROR(dev, "snd_rawmidi_new failed: error %d\n", err); - goto fail; - } - dev->rmidi = rmidi; - strcpy(rmidi->name, card->shortname); - rmidi->info_flags = SNDRV_RAWMIDI_INFO_OUTPUT | - SNDRV_RAWMIDI_INFO_INPUT | - SNDRV_RAWMIDI_INFO_DUPLEX; - rmidi->private_data = dev; - - /* Yes, rawmidi OUTPUT = USB IN, and rawmidi INPUT = USB OUT. - It's an upside-down world being a gadget. */ - snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, &gmidi_in_ops); - snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT, &gmidi_out_ops); - - snd_card_set_dev(card, &dev->gadget->dev); - - /* register it - we're ready to go */ - err = snd_card_register(card); - if (err < 0) { - ERROR(dev, "snd_card_register failed\n"); - goto fail; - } - - VDBG(dev, "gmidi_register_card finished ok\n"); - return 0; - -fail: - if (dev->card) { - snd_card_free(dev->card); - dev->card = NULL; - } - return err; + return f_midi_bind_config(c, index, id, buflen, qlen); } -/* - * Creates an output endpoint, and initializes output ports. - */ -static int __init gmidi_bind(struct usb_gadget *gadget) +static int __init midi_bind(struct usb_composite_dev *cdev) { - struct gmidi_device *dev; - struct usb_ep *in_ep, *out_ep; - int gcnum, err = 0; + struct usb_gadget *gadget = cdev->gadget; + int gcnum, status; - /* support optional vendor/distro customization */ - if (idVendor) { - if (!idProduct) { - pr_err("idVendor needs idProduct!\n"); - return -ENODEV; - } - device_desc.idVendor = cpu_to_le16(idVendor); - device_desc.idProduct = cpu_to_le16(idProduct); - if (bcdDevice) { - device_desc.bcdDevice = cpu_to_le16(bcdDevice); - } - } - if (iManufacturer) { - strlcpy(manufacturer, iManufacturer, sizeof(manufacturer)); - } else { - snprintf(manufacturer, sizeof(manufacturer), "%s %s with %s", - init_utsname()->sysname, init_utsname()->release, - gadget->name); - } - if (iProduct) { - strlcpy(product_desc, iProduct, sizeof(product_desc)); - } - if (iSerialNumber) { - device_desc.iSerialNumber = STRING_SERIAL, - strlcpy(serial_number, iSerialNumber, sizeof(serial_number)); - } + status = usb_string_id(cdev); + if (status < 0) + return status; + strings_dev[STRING_MANUFACTURER_IDX].id = status; + device_desc.iManufacturer = status; - /* Bulk-only drivers like this one SHOULD be able to - * autoconfigure on any sane usb controller driver, - * but there may also be important quirks to address. - */ - usb_ep_autoconfig_reset(gadget); - in_ep = usb_ep_autoconfig(gadget, &bulk_in_desc); - if (!in_ep) { -autoconf_fail: - pr_err("%s: can't autoconfigure on %s\n", - shortname, gadget->name); - return -ENODEV; - } - EP_IN_NAME = in_ep->name; - in_ep->driver_data = in_ep; /* claim */ + status = usb_string_id(cdev); + if (status < 0) + return status; + strings_dev[STRING_PRODUCT_IDX].id = status; + device_desc.iProduct = status; - out_ep = usb_ep_autoconfig(gadget, &bulk_out_desc); - if (!out_ep) { - goto autoconf_fail; - } - EP_OUT_NAME = out_ep->name; - out_ep->driver_data = out_ep; /* claim */ + /* config description */ + status = usb_string_id(cdev); + if (status < 0) + return status; + strings_dev[STRING_DESCRIPTION_IDX].id = status; + + midi_config.iConfiguration = status; gcnum = usb_gadget_controller_number(gadget); - if (gcnum >= 0) { - device_desc.bcdDevice = cpu_to_le16(0x0200 + gcnum); - } else { + if (gcnum < 0) { /* gmidi is so simple (no altsettings) that * it SHOULD NOT have problems with bulk-capable hardware. * so warn about unrecognized controllers, don't panic. */ pr_warning("%s: controller '%s' not recognized\n", - shortname, gadget->name); + __func__, gadget->name); device_desc.bcdDevice = cpu_to_le16(0x9999); + } else { + device_desc.bcdDevice = cpu_to_le16(0x0200 + gcnum); } + status = usb_add_config(cdev, &midi_config, midi_bind_config); + if (status < 0) + return status; - /* ok, we made sense of the hardware ... */ - dev = kzalloc(sizeof(*dev), GFP_KERNEL); - if (!dev) { - return -ENOMEM; - } - spin_lock_init(&dev->lock); - dev->gadget = gadget; - dev->in_ep = in_ep; - dev->out_ep = out_ep; - set_gadget_data(gadget, dev); - tasklet_init(&dev->tasklet, gmidi_in_tasklet, (unsigned long)dev); - - /* preallocate control response and buffer */ - dev->req = alloc_ep_req(gadget->ep0, USB_BUFSIZ); - if (!dev->req) { - err = -ENOMEM; - goto fail; - } - - dev->req->complete = gmidi_setup_complete; - - gadget->ep0->driver_data = dev; - - INFO(dev, "%s, version: " DRIVER_VERSION "\n", longname); - INFO(dev, "using %s, OUT %s IN %s\n", gadget->name, - EP_OUT_NAME, EP_IN_NAME); - - /* register as an ALSA sound card */ - err = gmidi_register_card(dev); - if (err < 0) { - goto fail; - } - - VDBG(dev, "gmidi_bind finished ok\n"); + pr_info("%s\n", longname); return 0; - -fail: - gmidi_unbind(gadget); - return err; -} - - -static void gmidi_suspend(struct usb_gadget *gadget) -{ - struct gmidi_device *dev = get_gadget_data(gadget); - - if (gadget->speed == USB_SPEED_UNKNOWN) { - return; - } - - DBG(dev, "suspend\n"); -} - -static void gmidi_resume(struct usb_gadget *gadget) -{ - struct gmidi_device *dev = get_gadget_data(gadget); - - DBG(dev, "resume\n"); } - -static struct usb_gadget_driver gmidi_driver = { - .speed = USB_SPEED_FULL, - .function = (char *)longname, - .unbind = gmidi_unbind, - - .setup = gmidi_setup, - .disconnect = gmidi_disconnect, - - .suspend = gmidi_suspend, - .resume = gmidi_resume, - - .driver = { - .name = (char *)shortname, - .owner = THIS_MODULE, - }, +static struct usb_composite_driver midi_driver = { + .name = (char *) longname, + .dev = &device_desc, + .strings = dev_strings, + .max_speed = USB_SPEED_HIGH, + .unbind = __exit_p(midi_unbind), }; -static int __init gmidi_init(void) +static int __init midi_init(void) { - return usb_gadget_probe_driver(&gmidi_driver, gmidi_bind); + return usb_composite_probe(&midi_driver, midi_bind); } -module_init(gmidi_init); +module_init(midi_init); -static void __exit gmidi_cleanup(void) +static void __exit midi_cleanup(void) { - usb_gadget_unregister_driver(&gmidi_driver); + usb_composite_unregister(&midi_driver); } -module_exit(gmidi_cleanup); +module_exit(midi_cleanup); -- cgit From c8933c3f79568263c90a46f06cf80419e6c63c97 Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Wed, 28 Sep 2011 16:41:34 +0200 Subject: USB: gadget: f_midi: allow a dynamic number of input and output ports The code in the MIDI gadget was already sort of prepared for multi-port configuration, so the streaming logic itself didn't need much tweaking. However, the descriptors change when the number of ports do, and so some rework of the the preparation algorithms were necessary. Successfully tested on Linux and Max OS X hosts for both input and output streams. Signed-off-by: Daniel Mack Cc: Greg Kroah-Hartman Signed-off-by: Felipe Balbi --- drivers/usb/gadget/f_midi.c | 287 +++++++++++++++++++++++++++----------------- drivers/usb/gadget/gmidi.c | 12 +- 2 files changed, 191 insertions(+), 108 deletions(-) (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/f_midi.c b/drivers/usb/gadget/f_midi.c index 84cbf85d23f8..44858dc074d3 100644 --- a/drivers/usb/gadget/f_midi.c +++ b/drivers/usb/gadget/f_midi.c @@ -39,6 +39,13 @@ MODULE_LICENSE("GPL v2"); static const char f_midi_shortname[] = "f_midi"; static const char f_midi_longname[] = "MIDI Gadget"; +/* + * We can only handle 16 cables on one single endpoint, as cable numbers are + * stored in 4-bit fields. And as the interface currently only holds one + * single endpoint, this is the maximum number of ports we can allow. + */ +#define MAX_PORTS 16 + /* * This is a gadget, and the IN/OUT naming is from the host's perspective. * USB -> OUT endpoint -> rawmidi @@ -47,7 +54,7 @@ static const char f_midi_longname[] = "MIDI Gadget"; struct gmidi_in_port { struct f_midi *midi; int active; - uint8_t cable; /* cable number << 4 */ + uint8_t cable; uint8_t state; #define STATE_UNKNOWN 0 #define STATE_1PARAM 1 @@ -65,15 +72,15 @@ struct f_midi { struct usb_ep *in_ep, *out_ep; struct snd_card *card; struct snd_rawmidi *rmidi; - struct snd_rawmidi_substream *in_substream; - struct snd_rawmidi_substream *out_substream; - /* For the moment we only support one port in - each direction, but in_port is kept as a - separate struct so we can have more later. */ - struct gmidi_in_port in_port; + struct snd_rawmidi_substream *in_substream[MAX_PORTS]; + struct snd_rawmidi_substream *out_substream[MAX_PORTS]; + struct gmidi_in_port *in_port[MAX_PORTS]; + unsigned long out_triggered; struct tasklet_struct tasklet; + unsigned int in_ports; + unsigned int out_ports; int index; char *id; unsigned int buflen, qlen; @@ -88,7 +95,8 @@ static void f_midi_transmit(struct f_midi *midi, struct usb_request *req); DECLARE_UAC_AC_HEADER_DESCRIPTOR(1); DECLARE_USB_MIDI_OUT_JACK_DESCRIPTOR(1); -DECLARE_USB_MS_ENDPOINT_DESCRIPTOR(1); +DECLARE_USB_MIDI_OUT_JACK_DESCRIPTOR(16); +DECLARE_USB_MS_ENDPOINT_DESCRIPTOR(16); /* B.3.1 Standard AC Interface Descriptor */ static struct usb_interface_descriptor ac_interface_desc __initdata = { @@ -129,62 +137,27 @@ static struct usb_ms_header_descriptor ms_header_desc __initdata = { .bDescriptorType = USB_DT_CS_INTERFACE, .bDescriptorSubtype = USB_MS_HEADER, .bcdMSC = cpu_to_le16(0x0100), - .wTotalLength = cpu_to_le16(USB_DT_MS_HEADER_SIZE - + 2*USB_DT_MIDI_IN_SIZE - + 2*USB_DT_MIDI_OUT_SIZE(1)), -}; - -#define JACK_IN_EMB 1 -#define JACK_IN_EXT 2 -#define JACK_OUT_EMB 3 -#define JACK_OUT_EXT 4 - -/* B.4.3 MIDI IN Jack Descriptors */ -static const struct usb_midi_in_jack_descriptor jack_in_emb_desc = { - .bLength = USB_DT_MIDI_IN_SIZE, - .bDescriptorType = USB_DT_CS_INTERFACE, - .bDescriptorSubtype = USB_MS_MIDI_IN_JACK, - .bJackType = USB_MS_EMBEDDED, - .bJackID = JACK_IN_EMB, + /* .wTotalLength = DYNAMIC */ }; -static const struct usb_midi_in_jack_descriptor jack_in_ext_desc = { - .bLength = USB_DT_MIDI_IN_SIZE, - .bDescriptorType = USB_DT_CS_INTERFACE, - .bDescriptorSubtype = USB_MS_MIDI_IN_JACK, - .bJackType = USB_MS_EXTERNAL, - .bJackID = JACK_IN_EXT, +/* B.4.3 Embedded MIDI IN Jack Descriptor */ +static struct usb_midi_in_jack_descriptor jack_in_emb_desc = { + .bLength = USB_DT_MIDI_IN_SIZE, + .bDescriptorType = USB_DT_CS_INTERFACE, + .bDescriptorSubtype = USB_MS_MIDI_IN_JACK, + .bJackType = USB_MS_EMBEDDED, + /* .bJackID = DYNAMIC */ }; -/* B.4.4 MIDI OUT Jack Descriptors */ -static const struct usb_midi_out_jack_descriptor_1 jack_out_emb_desc = { - .bLength = USB_DT_MIDI_OUT_SIZE(1), +/* B.4.4 Embedded MIDI OUT Jack Descriptor */ +static struct usb_midi_out_jack_descriptor_16 jack_out_emb_desc = { + /* .bLength = DYNAMIC */ .bDescriptorType = USB_DT_CS_INTERFACE, .bDescriptorSubtype = USB_MS_MIDI_OUT_JACK, .bJackType = USB_MS_EMBEDDED, - .bJackID = JACK_OUT_EMB, - .bNrInputPins = 1, - .pins = { - [0] = { - .baSourceID = JACK_IN_EXT, - .baSourcePin = 1, - } - } -}; - -static const struct usb_midi_out_jack_descriptor_1 jack_out_ext_desc = { - .bLength = USB_DT_MIDI_OUT_SIZE(1), - .bDescriptorType = USB_DT_CS_INTERFACE, - .bDescriptorSubtype = USB_MS_MIDI_OUT_JACK, - .bJackType = USB_MS_EXTERNAL, - .bJackID = JACK_OUT_EXT, - .bNrInputPins = 1, - .pins = { - [0] = { - .baSourceID = JACK_IN_EMB, - .baSourcePin = 1, - } - } + /* .bJackID = DYNAMIC */ + /* .bNrInputPins = DYNAMIC */ + /* .pins = DYNAMIC */ }; /* B.5.1 Standard Bulk OUT Endpoint Descriptor */ @@ -196,14 +169,12 @@ static struct usb_endpoint_descriptor bulk_out_desc = { }; /* B.5.2 Class-specific MS Bulk OUT Endpoint Descriptor */ -static const struct usb_ms_endpoint_descriptor_1 ms_out_desc = { - .bLength = USB_DT_MS_ENDPOINT_SIZE(1), +static struct usb_ms_endpoint_descriptor_16 ms_out_desc = { + /* .bLength = DYNAMIC */ .bDescriptorType = USB_DT_CS_ENDPOINT, .bDescriptorSubtype = USB_MS_GENERAL, - .bNumEmbMIDIJack = 1, - .baAssocJackID = { - [0] = JACK_IN_EMB, - } + /* .bNumEmbMIDIJack = DYNAMIC */ + /* .baAssocJackID = DYNAMIC */ }; /* B.6.1 Standard Bulk IN Endpoint Descriptor */ @@ -215,33 +186,12 @@ static struct usb_endpoint_descriptor bulk_in_desc = { }; /* B.6.2 Class-specific MS Bulk IN Endpoint Descriptor */ -static const struct usb_ms_endpoint_descriptor_1 ms_in_desc = { - .bLength = USB_DT_MS_ENDPOINT_SIZE(1), +static struct usb_ms_endpoint_descriptor_16 ms_in_desc = { + /* .bLength = DYNAMIC */ .bDescriptorType = USB_DT_CS_ENDPOINT, .bDescriptorSubtype = USB_MS_GENERAL, - .bNumEmbMIDIJack = 1, - .baAssocJackID = { - [0] = JACK_OUT_EMB, - } -}; - -static struct usb_descriptor_header *midi_function[] __initdata = { - (struct usb_descriptor_header *)&ac_interface_desc, - (struct usb_descriptor_header *)&ac_header_desc, - (struct usb_descriptor_header *)&ms_interface_desc, - - (struct usb_descriptor_header *)&ms_header_desc, - (struct usb_descriptor_header *)&jack_in_emb_desc, - (struct usb_descriptor_header *)&jack_in_ext_desc, - (struct usb_descriptor_header *)&jack_out_emb_desc, - (struct usb_descriptor_header *)&jack_out_ext_desc, - /* If you add more jacks, update ms_header_desc.wTotalLength */ - - (struct usb_descriptor_header *)&bulk_out_desc, - (struct usb_descriptor_header *)&ms_out_desc, - (struct usb_descriptor_header *)&bulk_in_desc, - (struct usb_descriptor_header *)&ms_in_desc, - NULL, + /* .bNumEmbMIDIJack = DYNAMIC */ + /* .baAssocJackID = DYNAMIC */ }; /* string IDs are assigned dynamically */ @@ -296,16 +246,16 @@ static void f_midi_read_data(struct usb_ep *ep, int cable, uint8_t *data, int length) { struct f_midi *midi = ep->driver_data; - /* cable is ignored, because for now we only have one. */ + struct snd_rawmidi_substream *substream = midi->out_substream[cable]; - if (!midi->out_substream) + if (!substream) /* Nobody is listening - throw it on the floor. */ return; - if (!test_bit(midi->out_substream->number, &midi->out_triggered)) + if (!test_bit(cable, &midi->out_triggered)) return; - snd_rawmidi_receive(midi->out_substream, data, length); + snd_rawmidi_receive(substream, data, length); } static void f_midi_handle_out_data(struct usb_ep *ep, struct usb_request *req) @@ -514,7 +464,7 @@ static void f_midi_transmit_packet(struct usb_request *req, uint8_t p0, static void f_midi_transmit_byte(struct usb_request *req, struct gmidi_in_port *port, uint8_t b) { - uint8_t p0 = port->cable; + uint8_t p0 = port->cable << 4; if (b >= 0xf8) { f_midi_transmit_packet(req, p0 | 0x0f, b, 0, 0); @@ -612,7 +562,7 @@ static void f_midi_transmit_byte(struct usb_request *req, static void f_midi_transmit(struct f_midi *midi, struct usb_request *req) { struct usb_ep *ep = midi->in_ep; - struct gmidi_in_port *port = &midi->in_port; + int i; if (!ep) return; @@ -627,10 +577,16 @@ static void f_midi_transmit(struct f_midi *midi, struct usb_request *req) req->length = 0; req->complete = f_midi_complete; - if (port->active) { + for (i = 0; i < MAX_PORTS; i++) { + struct gmidi_in_port *port = midi->in_port[i]; + struct snd_rawmidi_substream *substream = midi->in_substream[i]; + + if (!port || !port->active || !substream) + continue; + while (req->length + 3 < midi->buflen) { uint8_t b; - if (snd_rawmidi_transmit(midi->in_substream, &b, 1) != 1) { + if (snd_rawmidi_transmit(substream, &b, 1) != 1) { port->active = 0; break; } @@ -654,9 +610,12 @@ static int f_midi_in_open(struct snd_rawmidi_substream *substream) { struct f_midi *midi = substream->rmidi->private_data; + if (!midi->in_port[substream->number]) + return -EINVAL; + VDBG(midi, "%s()\n", __func__); - midi->in_substream = substream; - midi->in_port.state = STATE_UNKNOWN; + midi->in_substream[substream->number] = substream; + midi->in_port[substream->number]->state = STATE_UNKNOWN; return 0; } @@ -672,8 +631,11 @@ static void f_midi_in_trigger(struct snd_rawmidi_substream *substream, int up) { struct f_midi *midi = substream->rmidi->private_data; + if (!midi->in_port[substream->number]) + return; + VDBG(midi, "%s() %d\n", __func__, up); - midi->in_port.active = up; + midi->in_port[substream->number]->active = up; if (up) tasklet_hi_schedule(&midi->tasklet); } @@ -682,8 +644,11 @@ static int f_midi_out_open(struct snd_rawmidi_substream *substream) { struct f_midi *midi = substream->rmidi->private_data; + if (!substream->number >= MAX_PORTS) + return -EINVAL; + VDBG(midi, "%s()\n", __func__); - midi->out_substream = substream; + midi->out_substream[substream->number] = substream; return 0; } @@ -725,8 +690,6 @@ static int f_midi_register_card(struct f_midi *midi) struct snd_card *card; struct snd_rawmidi *rmidi; int err; - int out_ports = 1; - int in_ports = 1; static struct snd_device_ops ops = { .dev_free = f_midi_snd_free, }; @@ -749,11 +712,9 @@ static int f_midi_register_card(struct f_midi *midi) strcpy(card->shortname, f_midi_shortname); /* Set up rawmidi */ - midi->in_port.midi = midi; - midi->in_port.active = 0; snd_component_add(card, "MIDI"); err = snd_rawmidi_new(card, card->longname, 0, - out_ports, in_ports, &rmidi); + midi->out_ports, midi->in_ports, &rmidi); if (err < 0) { ERROR(midi, "snd_rawmidi_new() failed: error %d\n", err); goto fail; @@ -797,9 +758,12 @@ fail: static int __init f_midi_bind(struct usb_configuration *c, struct usb_function *f) { + struct usb_descriptor_header *midi_function[(MAX_PORTS * 2) + 12]; + struct usb_midi_in_jack_descriptor jack_in_ext_desc[MAX_PORTS]; + struct usb_midi_out_jack_descriptor_1 jack_out_ext_desc[MAX_PORTS]; struct usb_composite_dev *cdev = c->cdev; struct f_midi *midi = func_to_midi(f); - int status; + int status, n, jack = 1, i = 0; /* maybe allocate device-global string ID */ if (midi_string_defs[0].id == 0) { @@ -834,6 +798,94 @@ f_midi_bind(struct usb_configuration *c, struct usb_function *f) goto fail; midi->out_ep->driver_data = cdev; /* claim */ + /* + * construct the function's descriptor set. As the number of + * input and output MIDI ports is configurable, we have to do + * it that way. + */ + + /* add the headers - these are always the same */ + midi_function[i++] = (struct usb_descriptor_header *) &ac_interface_desc; + midi_function[i++] = (struct usb_descriptor_header *) &ac_header_desc; + midi_function[i++] = (struct usb_descriptor_header *) &ms_interface_desc; + + /* calculate the header's wTotalLength */ + n = USB_DT_MS_HEADER_SIZE + + (1 + midi->in_ports) * USB_DT_MIDI_IN_SIZE + + (1 + midi->out_ports) * USB_DT_MIDI_OUT_SIZE(1); + ms_header_desc.wTotalLength = cpu_to_le16(n); + + midi_function[i++] = (struct usb_descriptor_header *) &ms_header_desc; + + /* we have one embedded IN jack */ + jack_in_emb_desc.bJackID = jack++; + midi_function[i++] = (struct usb_descriptor_header *) &jack_in_emb_desc; + + /* and a dynamic amount of external IN jacks */ + for (n = 0; n < midi->in_ports; n++) { + struct usb_midi_in_jack_descriptor *ext = &jack_in_ext_desc[n]; + + ext->bLength = USB_DT_MIDI_IN_SIZE; + ext->bDescriptorType = USB_DT_CS_INTERFACE; + ext->bDescriptorSubtype = USB_MS_MIDI_IN_JACK; + ext->bJackType = USB_MS_EXTERNAL; + ext->bJackID = jack++; + ext->iJack = 0; + + midi_function[i++] = (struct usb_descriptor_header *) ext; + } + + /* one embedded OUT jack ... */ + jack_out_emb_desc.bLength = USB_DT_MIDI_OUT_SIZE(midi->in_ports); + jack_out_emb_desc.bJackID = jack++; + jack_out_emb_desc.bNrInputPins = midi->in_ports; + /* ... which referencess all external IN jacks */ + for (n = 0; n < midi->in_ports; n++) { + jack_out_emb_desc.pins[n].baSourceID = jack_in_ext_desc[n].bJackID; + jack_out_emb_desc.pins[n].baSourcePin = 1; + } + + midi_function[i++] = (struct usb_descriptor_header *) &jack_out_emb_desc; + + /* and multiple external OUT jacks ... */ + for (n = 0; n < midi->out_ports; n++) { + struct usb_midi_out_jack_descriptor_1 *ext = &jack_out_ext_desc[n]; + int m; + + ext->bLength = USB_DT_MIDI_OUT_SIZE(1); + ext->bDescriptorType = USB_DT_CS_INTERFACE; + ext->bDescriptorSubtype = USB_MS_MIDI_OUT_JACK; + ext->bJackType = USB_MS_EXTERNAL; + ext->bJackID = jack++; + ext->bNrInputPins = 1; + ext->iJack = 0; + /* ... which all reference the same embedded IN jack */ + for (m = 0; m < midi->out_ports; m++) { + ext->pins[m].baSourceID = jack_in_emb_desc.bJackID; + ext->pins[m].baSourcePin = 1; + } + + midi_function[i++] = (struct usb_descriptor_header *) ext; + } + + /* configure the endpoint descriptors ... */ + ms_out_desc.bLength = USB_DT_MS_ENDPOINT_SIZE(midi->in_ports); + ms_out_desc.bNumEmbMIDIJack = midi->in_ports; + for (n = 0; n < midi->in_ports; n++) + ms_out_desc.baAssocJackID[n] = jack_in_emb_desc.bJackID; + + ms_in_desc.bLength = USB_DT_MS_ENDPOINT_SIZE(midi->out_ports); + ms_in_desc.bNumEmbMIDIJack = midi->out_ports; + for (n = 0; n < midi->out_ports; n++) + ms_in_desc.baAssocJackID[n] = jack_out_emb_desc.bJackID; + + /* ... and add them to the list */ + midi_function[i++] = (struct usb_descriptor_header *) &bulk_out_desc; + midi_function[i++] = (struct usb_descriptor_header *) &ms_out_desc; + midi_function[i++] = (struct usb_descriptor_header *) &bulk_in_desc; + midi_function[i++] = (struct usb_descriptor_header *) &ms_in_desc; + midi_function[i++] = NULL; + /* * support all relevant hardware speeds... we expect that when * hardware is dual speed, all bulk-capable endpoints work at @@ -876,11 +928,17 @@ fail: */ int __init f_midi_bind_config(struct usb_configuration *c, int index, char *id, + unsigned int in_ports, + unsigned int out_ports, unsigned int buflen, unsigned int qlen) { struct f_midi *midi; - int status; + int status, i; + + /* sanity check */ + if (in_ports > MAX_PORTS || out_ports > MAX_PORTS) + return -EINVAL; /* allocate and initialize one new instance */ midi = kzalloc(sizeof *midi, GFP_KERNEL); @@ -889,10 +947,25 @@ int __init f_midi_bind_config(struct usb_configuration *c, goto fail; } + for (i = 0; i < in_ports; i++) { + struct gmidi_in_port *port = kzalloc(sizeof(*port), GFP_KERNEL); + if (!port) { + status = -ENOMEM; + goto fail; + } + + port->midi = midi; + port->active = 0; + port->cable = i; + midi->in_port[i] = port; + } + midi->gadget = c->cdev->gadget; tasklet_init(&midi->tasklet, f_midi_in_tasklet, (unsigned long) midi); /* set up ALSA midi devices */ + midi->in_ports = in_ports; + midi->out_ports = out_ports; status = f_midi_register_card(midi); if (status < 0) goto setup_fail; diff --git a/drivers/usb/gadget/gmidi.c b/drivers/usb/gadget/gmidi.c index e7c8c3907133..8fcde37aa6d4 100644 --- a/drivers/usb/gadget/gmidi.c +++ b/drivers/usb/gadget/gmidi.c @@ -66,6 +66,14 @@ static unsigned int qlen = 32; module_param(qlen, uint, S_IRUGO); MODULE_PARM_DESC(qlen, "USB read request queue length"); +static unsigned int in_ports = 1; +module_param(in_ports, uint, S_IRUGO); +MODULE_PARM_DESC(in_ports, "Number of MIDI input ports"); + +static unsigned int out_ports = 1; +module_param(out_ports, uint, S_IRUGO); +MODULE_PARM_DESC(out_ports, "Number of MIDI output ports"); + /* Thanks to Grey Innovation for donating this product ID. * * DO NOT REUSE THESE IDs with a protocol-incompatible driver!! Ever!! @@ -124,7 +132,9 @@ static struct usb_configuration midi_config = { static int __init midi_bind_config(struct usb_configuration *c) { - return f_midi_bind_config(c, index, id, buflen, qlen); + return f_midi_bind_config(c, index, id, + in_ports, out_ports, + buflen, qlen); } static int __init midi_bind(struct usb_composite_dev *cdev) -- cgit From fe69676530f182bbb1fe0edd027e18751a1a2595 Mon Sep 17 00:00:00 2001 From: Paul Zimmerman Date: Fri, 30 Sep 2011 15:26:06 -0700 Subject: usb: gadget: storage: fix mass storage gadgets to work with Synopsys UDC The Synopsys USB device controller requires all OUT transfer request lengths to be aligned to max packet size. The mass storage gadgets do not meet this requirement for Super Speed. The gadgets already have a function which performs this alignment for CBW packets, so use it for data packets too. The alternative would be to implement bounce buffers in the DWC3 driver, but that could have a significant impact on performance. This version is based upon a more-correct patch written by Alan Stern. Signed-off-by: Paul Zimmerman Signed-off-by: Felipe Balbi --- drivers/usb/gadget/f_mass_storage.c | 18 +++++++++--------- drivers/usb/gadget/file_storage.c | 18 +++++++++--------- 2 files changed, 18 insertions(+), 18 deletions(-) (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/f_mass_storage.c b/drivers/usb/gadget/f_mass_storage.c index 756941473148..927ee88278bd 100644 --- a/drivers/usb/gadget/f_mass_storage.c +++ b/drivers/usb/gadget/f_mass_storage.c @@ -958,9 +958,7 @@ static int do_write(struct fsg_common *common) * equal to the buffer size, which is divisible by * the bulk-out maxpacket size. */ - bh->outreq->length = amount; - bh->bulk_out_intended_length = amount; - bh->outreq->short_not_ok = 1; + set_bulk_out_req_length(common, bh, amount); if (!start_out_transfer(common, bh)) /* Dunno what to do if common->fsg is NULL */ return -EIO; @@ -995,6 +993,11 @@ static int do_write(struct fsg_common *common) 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) @@ -1034,7 +1037,7 @@ static int do_write(struct fsg_common *common) empty_write: /* Did the host decide to stop early? */ - if (bh->outreq->actual != bh->outreq->length) { + if (bh->outreq->actual < bh->bulk_out_intended_length) { common->short_packet_received = 1; break; } @@ -1592,7 +1595,7 @@ static int throw_away_data(struct fsg_common *common) common->next_buffhd_to_drain = bh->next; /* A short packet or an error ends everything */ - if (bh->outreq->actual != bh->outreq->length || + if (bh->outreq->actual < bh->bulk_out_intended_length || bh->outreq->status != 0) { raise_exception(common, FSG_STATE_ABORT_BULK_OUT); @@ -1612,9 +1615,7 @@ static int throw_away_data(struct fsg_common *common) * equal to the buffer size, which is divisible by * the bulk-out maxpacket size. */ - bh->outreq->length = amount; - bh->bulk_out_intended_length = amount; - bh->outreq->short_not_ok = 1; + set_bulk_out_req_length(common, bh, amount); if (!start_out_transfer(common, bh)) /* Dunno what to do if common->fsg is NULL */ return -EIO; @@ -2289,7 +2290,6 @@ static int get_next_command(struct fsg_common *common) /* Queue a request to read a Bulk-only CBW */ set_bulk_out_req_length(common, bh, USB_BULK_CB_WRAP_LEN); - bh->outreq->short_not_ok = 1; if (!start_out_transfer(common, bh)) /* Don't know what to do if common->fsg is NULL */ return -EIO; diff --git a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c index 12ac30b21ba6..a230009db734 100644 --- a/drivers/usb/gadget/file_storage.c +++ b/drivers/usb/gadget/file_storage.c @@ -1335,9 +1335,7 @@ static int do_write(struct fsg_dev *fsg) * equal to the buffer size, which is divisible by * the bulk-out maxpacket size. */ - bh->outreq->length = bh->bulk_out_intended_length = - amount; - bh->outreq->short_not_ok = 1; + 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; @@ -1370,6 +1368,11 @@ static int do_write(struct fsg_dev *fsg) 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) @@ -1409,7 +1412,7 @@ static int do_write(struct fsg_dev *fsg) empty_write: /* Did the host decide to stop early? */ - if (bh->outreq->actual != bh->outreq->length) { + if (bh->outreq->actual < bh->bulk_out_intended_length) { fsg->short_packet_received = 1; break; } @@ -1953,7 +1956,7 @@ static int throw_away_data(struct fsg_dev *fsg) fsg->next_buffhd_to_drain = bh->next; /* A short packet or an error ends everything */ - if (bh->outreq->actual != bh->outreq->length || + if (bh->outreq->actual < bh->bulk_out_intended_length || bh->outreq->status != 0) { raise_exception(fsg, FSG_STATE_ABORT_BULK_OUT); return -EINTR; @@ -1971,9 +1974,7 @@ static int throw_away_data(struct fsg_dev *fsg) * equal to the buffer size, which is divisible by * the bulk-out maxpacket size. */ - bh->outreq->length = bh->bulk_out_intended_length = - amount; - bh->outreq->short_not_ok = 1; + 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; @@ -2652,7 +2653,6 @@ static int get_next_command(struct fsg_dev *fsg) /* Queue a request to read a Bulk-only CBW */ set_bulk_out_req_length(fsg, bh, USB_BULK_CB_WRAP_LEN); - bh->outreq->short_not_ok = 1; start_transfer(fsg, fsg->bulk_out, bh->outreq, &bh->outreq_busy, &bh->state); -- cgit From d5546b380583f009bc18504e7f946fa16d861381 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Sat, 1 Oct 2011 22:03:33 +0200 Subject: usb: gadget: pxa25x: is_vbus_present is gone A recent commit obsoleted the is_vbus_present function, so we must not use it any more. Signed-off-by: Arnd Bergmann Signed-off-by: Felipe Balbi --- drivers/usb/gadget/pxa25x_udc.h | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/pxa25x_udc.h b/drivers/usb/gadget/pxa25x_udc.h index 4634cd361f29..8eaf4e43726b 100644 --- a/drivers/usb/gadget/pxa25x_udc.h +++ b/drivers/usb/gadget/pxa25x_udc.h @@ -152,8 +152,6 @@ static struct pxa25x_udc *the_controller; #ifdef DEBUG -static int is_vbus_present(void); - static const char *state_name[] = { "EP0_IDLE", "EP0_IN_DATA_PHASE", "EP0_OUT_DATA_PHASE", @@ -205,8 +203,7 @@ dump_state(struct pxa25x_udc *dev) u32 tmp; unsigned i; - DMSG("%s %s, uicr %02X.%02X, usir %02X.%02x, ufnr %02X.%02X\n", - is_vbus_present() ? "host " : "disconnected", + DMSG("%s, uicr %02X.%02X, usir %02X.%02x, ufnr %02X.%02X\n", state_name[dev->ep0state], UICR1, UICR0, USIR1, USIR0, UFNRH, UFNRL); dump_udccr("udccr"); @@ -223,9 +220,6 @@ dump_state(struct pxa25x_udc *dev) } else DMSG("ep0 driver '%s'\n", dev->driver->driver.name); - if (!is_vbus_present()) - return; - dump_udccs0 ("udccs0"); DMSG("ep0 IN %lu/%lu, OUT %lu/%lu\n", dev->stats.write.bytes, dev->stats.write.ops, -- cgit From 1a8060d9e5c0d9488f7f1aa830ed37adcaba6adb Mon Sep 17 00:00:00 2001 From: Robert Schwebel Date: Thu, 6 Oct 2011 21:36:26 +0200 Subject: usb: gadget: at91_udc: change french comments to english While being there, change C++ style comments to /* */. Signed-off-by: Robert Schwebel Cc: Greg Kroah-Hartman Cc: linux-usb@vger.kernel.org Signed-off-by: Felipe Balbi --- drivers/usb/gadget/at91_udc.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/at91_udc.c b/drivers/usb/gadget/at91_udc.c index e10cf3c63929..8efe0fa9228d 100644 --- a/drivers/usb/gadget/at91_udc.c +++ b/drivers/usb/gadget/at91_udc.c @@ -450,7 +450,7 @@ static void nuke(struct at91_ep *ep, int status) { struct at91_request *req; - // terminer chaque requete dans la queue + /* terminate any request in the queue */ ep->stopped = 1; if (list_empty(&ep->queue)) return; @@ -778,7 +778,7 @@ static const struct usb_ep_ops at91_ep_ops = { .queue = at91_ep_queue, .dequeue = at91_ep_dequeue, .set_halt = at91_ep_set_halt, - // there's only imprecise fifo status reporting + /* there's only imprecise fifo status reporting */ }; /*-------------------------------------------------------------------------*/ @@ -836,7 +836,7 @@ static void udc_reinit(struct at91_udc *udc) ep->fifo_bank = 0; ep->ep.maxpacket = ep->maxpacket; ep->creg = (void __iomem *) udc->udp_baseaddr + AT91_UDP_CSR(i); - // initialiser une queue par endpoint + /* initialize one queue per endpoint */ INIT_LIST_HEAD(&ep->queue); } } @@ -942,7 +942,7 @@ static int at91_vbus_session(struct usb_gadget *gadget, int is_active) struct at91_udc *udc = to_udc(gadget); unsigned long flags; - // VDBG("vbus %s\n", is_active ? "on" : "off"); + /* VDBG("vbus %s\n", is_active ? "on" : "off"); */ spin_lock_irqsave(&udc->lock, flags); udc->vbus = (is_active != 0); if (udc->driver) @@ -993,7 +993,7 @@ static const struct usb_gadget_ops at91_udc_ops = { * VBUS-powered devices may also also want to support bigger * power budgets after an appropriate SET_CONFIGURATION. */ - // .vbus_power = at91_vbus_power, + /* .vbus_power = at91_vbus_power, */ }; /*-------------------------------------------------------------------------*/ @@ -1062,7 +1062,7 @@ static void handle_setup(struct at91_udc *udc, struct at91_ep *ep, u32 csr) ep->is_in = 0; } } else { - // REVISIT this happens sometimes under load; why?? + /* REVISIT this happens sometimes under load; why?? */ ERR("SETUP len %d, csr %08x\n", rxcount, csr); status = -EINVAL; } @@ -1441,7 +1441,7 @@ static irqreturn_t at91_udc_irq (int irq, void *_udc) at91_udp_write(udc, AT91_UDP_IDR, AT91_UDP_RXSUSP); at91_udp_write(udc, AT91_UDP_IER, AT91_UDP_RXRSM); at91_udp_write(udc, AT91_UDP_ICR, AT91_UDP_RXSUSP); - // VDBG("bus suspend\n"); + /* VDBG("bus suspend\n"); */ if (udc->suspended) continue; udc->suspended = 1; @@ -1463,7 +1463,7 @@ static irqreturn_t at91_udc_irq (int irq, void *_udc) at91_udp_write(udc, AT91_UDP_IDR, AT91_UDP_RXRSM); at91_udp_write(udc, AT91_UDP_IER, AT91_UDP_RXSUSP); at91_udp_write(udc, AT91_UDP_ICR, AT91_UDP_RXRSM); - // VDBG("bus resume\n"); + /* VDBG("bus resume\n"); */ if (!udc->suspended) continue; udc->suspended = 0; -- cgit From 5bc639fc55b51f828b20747eb1c48a669053b1e5 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Sat, 8 Oct 2011 13:08:01 +0300 Subject: usb: gadget: langwell: don't use the_controller when it's not needed in most cases, we can fetch our structure by calling dev_get_drvdata(). Signed-off-by: Felipe Balbi --- drivers/usb/gadget/langwell_udc.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/langwell_udc.c b/drivers/usb/gadget/langwell_udc.c index cb728d3079af..444bd11d3f4b 100644 --- a/drivers/usb/gadget/langwell_udc.c +++ b/drivers/usb/gadget/langwell_udc.c @@ -1551,7 +1551,7 @@ static void stop_activity(struct langwell_udc *dev, static ssize_t show_function(struct device *_dev, struct device_attribute *attr, char *buf) { - struct langwell_udc *dev = the_controller; + struct langwell_udc *dev = dev_get_drvdata(_dev); if (!dev->driver || !dev->driver->function || strlen(dev->driver->function) > PAGE_SIZE) @@ -1580,7 +1580,7 @@ static inline enum usb_device_speed lpm_device_speed(u32 reg) static ssize_t show_langwell_udc(struct device *_dev, struct device_attribute *attr, char *buf) { - struct langwell_udc *dev = the_controller; + struct langwell_udc *dev = dev_get_drvdata(_dev); struct langwell_request *req; struct langwell_ep *ep = NULL; char *next; @@ -1812,7 +1812,7 @@ static DEVICE_ATTR(langwell_udc, S_IRUGO, show_langwell_udc, NULL); static ssize_t store_remote_wakeup(struct device *_dev, struct device_attribute *attr, const char *buf, size_t count) { - struct langwell_udc *dev = the_controller; + struct langwell_udc *dev = dev_get_drvdata(_dev); unsigned long flags; ssize_t rc = count; @@ -2973,7 +2973,7 @@ static irqreturn_t langwell_irq(int irq, void *_dev) /* release device structure */ static void gadget_release(struct device *_dev) { - struct langwell_udc *dev = the_controller; + struct langwell_udc *dev = dev_get_drvdata(_dev); dev_dbg(&dev->pdev->dev, "---> %s()\n", __func__); @@ -3031,7 +3031,7 @@ static void sram_deinit(struct langwell_udc *dev) /* tear down the binding between this driver and the pci device */ static void langwell_udc_remove(struct pci_dev *pdev) { - struct langwell_udc *dev = the_controller; + struct langwell_udc *dev = pci_get_drvdata(pdev); DECLARE_COMPLETION(done); @@ -3378,7 +3378,7 @@ error: /* device controller suspend */ static int langwell_udc_suspend(struct pci_dev *pdev, pm_message_t state) { - struct langwell_udc *dev = the_controller; + struct langwell_udc *dev = pci_get_drvdata(pdev); dev_dbg(&dev->pdev->dev, "---> %s()\n", __func__); @@ -3426,7 +3426,7 @@ static int langwell_udc_suspend(struct pci_dev *pdev, pm_message_t state) /* device controller resume */ static int langwell_udc_resume(struct pci_dev *pdev) { - struct langwell_udc *dev = the_controller; + struct langwell_udc *dev = pci_get_drvdata(pdev); size_t size; dev_dbg(&dev->pdev->dev, "---> %s()\n", __func__); @@ -3508,7 +3508,7 @@ static int langwell_udc_resume(struct pci_dev *pdev) /* pci driver shutdown */ static void langwell_udc_shutdown(struct pci_dev *pdev) { - struct langwell_udc *dev = the_controller; + struct langwell_udc *dev = pci_get_drvdata(pdev); u32 usbmode; dev_dbg(&dev->pdev->dev, "---> %s()\n", __func__); -- cgit From 2c7f098916e3eb5473724d0653eca9f446997915 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Sat, 8 Oct 2011 13:17:34 +0300 Subject: usb: gadget: langwell: convert to new style with this patch we can finally remove the global "the_controller" pointer. Signed-off-by: Felipe Balbi --- drivers/usb/gadget/langwell_udc.c | 67 +++++++++++---------------------------- drivers/usb/gadget/langwell_udc.h | 2 ++ 2 files changed, 21 insertions(+), 48 deletions(-) (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/langwell_udc.c b/drivers/usb/gadget/langwell_udc.c index 444bd11d3f4b..7a133631bc2b 100644 --- a/drivers/usb/gadget/langwell_udc.c +++ b/drivers/usb/gadget/langwell_udc.c @@ -50,9 +50,6 @@ static const char driver_name[] = "langwell_udc"; static const char driver_desc[] = DRIVER_DESC; -/* controller device global variable */ -static struct langwell_udc *the_controller; - /* for endpoint 0 operations */ static const struct usb_endpoint_descriptor langwell_ep0_desc = { @@ -1311,9 +1308,12 @@ static int langwell_pullup(struct usb_gadget *_gadget, int is_on) return 0; } -static int langwell_start(struct usb_gadget_driver *driver, - int (*bind)(struct usb_gadget *)); -static int langwell_stop(struct usb_gadget_driver *driver); +static int langwell_start(struct usb_gadget *g, + struct usb_gadget_driver *driver); + +static int langwell_stop(struct usb_gadget *g, + struct usb_gadget_driver *driver); + /* device controller usb_gadget_ops structure */ static const struct usb_gadget_ops langwell_ops = { @@ -1335,8 +1335,8 @@ static const struct usb_gadget_ops langwell_ops = { /* D+ pullup, software-controlled connect/disconnect to USB host */ .pullup = langwell_pullup, - .start = langwell_start, - .stop = langwell_stop, + .udc_start = langwell_start, + .udc_stop = langwell_stop, }; @@ -1848,21 +1848,15 @@ static DEVICE_ATTR(remote_wakeup, S_IWUSR, NULL, store_remote_wakeup); * the driver might get unbound. */ -static int langwell_start(struct usb_gadget_driver *driver, - int (*bind)(struct usb_gadget *)) +static int langwell_start(struct usb_gadget *g, + struct usb_gadget_driver *driver) { - struct langwell_udc *dev = the_controller; + struct langwell_udc *dev = gadget_to_langwell(g); unsigned long flags; int retval; - if (!dev) - return -ENODEV; - dev_dbg(&dev->pdev->dev, "---> %s()\n", __func__); - if (dev->driver) - return -EBUSY; - spin_lock_irqsave(&dev->lock, flags); /* hook up the driver ... */ @@ -1872,18 +1866,9 @@ static int langwell_start(struct usb_gadget_driver *driver, spin_unlock_irqrestore(&dev->lock, flags); - retval = bind(&dev->gadget); - if (retval) { - dev_dbg(&dev->pdev->dev, "bind to driver %s --> %d\n", - driver->driver.name, retval); - dev->driver = NULL; - dev->gadget.dev.driver = NULL; - return retval; - } - retval = device_create_file(&dev->pdev->dev, &dev_attr_function); if (retval) - goto err_unbind; + goto err; dev->usb_state = USB_STATE_ATTACHED; dev->ep0_state = WAIT_FOR_SETUP; @@ -1900,31 +1885,27 @@ static int langwell_start(struct usb_gadget_driver *driver, dev_info(&dev->pdev->dev, "register driver: %s\n", driver->driver.name); dev_dbg(&dev->pdev->dev, "<--- %s()\n", __func__); + return 0; -err_unbind: - driver->unbind(&dev->gadget); +err: dev->gadget.dev.driver = NULL; dev->driver = NULL; dev_dbg(&dev->pdev->dev, "<--- %s()\n", __func__); + return retval; } /* unregister gadget driver */ -static int langwell_stop(struct usb_gadget_driver *driver) +static int langwell_stop(struct usb_gadget *g, + struct usb_gadget_driver *driver) { - struct langwell_udc *dev = the_controller; + struct langwell_udc *dev = gadget_to_langwell(g); unsigned long flags; - if (!dev) - return -ENODEV; - dev_dbg(&dev->pdev->dev, "---> %s()\n", __func__); - if (unlikely(!driver || !driver->unbind)) - return -EINVAL; - /* exit PHY low power suspend */ if (dev->pdev->device != 0x0829) langwell_phy_low_power(dev, 0); @@ -1947,8 +1928,6 @@ static int langwell_stop(struct usb_gadget_driver *driver) stop_activity(dev, driver); spin_unlock_irqrestore(&dev->lock, flags); - /* unbind gadget driver */ - driver->unbind(&dev->gadget); dev->gadget.dev.driver = NULL; dev->driver = NULL; @@ -1957,6 +1936,7 @@ static int langwell_stop(struct usb_gadget_driver *driver) dev_info(&dev->pdev->dev, "unregistered driver '%s'\n", driver->driver.name); dev_dbg(&dev->pdev->dev, "<--- %s()\n", __func__); + return 0; } @@ -3098,8 +3078,6 @@ static void langwell_udc_remove(struct pci_dev *pdev) /* free dev, wait for the release() finished */ wait_for_completion(&done); - - the_controller = NULL; } @@ -3118,11 +3096,6 @@ static int langwell_udc_probe(struct pci_dev *pdev, size_t size; int retval; - if (the_controller) { - dev_warn(&pdev->dev, "ignoring\n"); - return -EBUSY; - } - /* alloc, and start init */ dev = kzalloc(sizeof *dev, GFP_KERNEL); if (dev == NULL) { @@ -3342,8 +3315,6 @@ static int langwell_udc_probe(struct pci_dev *pdev, "After langwell_udc_probe(), print all registers:\n"); print_all_registers(dev); - the_controller = dev; - retval = device_register(&dev->gadget.dev); if (retval) goto error; diff --git a/drivers/usb/gadget/langwell_udc.h b/drivers/usb/gadget/langwell_udc.h index 1bec66f95c36..ef79e242b7b0 100644 --- a/drivers/usb/gadget/langwell_udc.h +++ b/drivers/usb/gadget/langwell_udc.h @@ -221,3 +221,5 @@ struct langwell_udc { u16 dev_status; }; +#define gadget_to_langwell(g) container_of((g), struct langwell_udc, gadget) + -- cgit From 96f8db6a77e3490608e5b5b3f57e7201f8c85496 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Mon, 10 Oct 2011 10:33:47 +0300 Subject: usb: gadget: net2272: convert to new style with this patch we can finally remove the global "the controller" pointer. Signed-off-by: Felipe Balbi --- drivers/usb/gadget/net2272.c | 72 ++++++++++++-------------------------------- 1 file changed, 19 insertions(+), 53 deletions(-) (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/net2272.c b/drivers/usb/gadget/net2272.c index 08a4a36550d2..d1b76368472f 100644 --- a/drivers/usb/gadget/net2272.c +++ b/drivers/usb/gadget/net2272.c @@ -1172,17 +1172,18 @@ net2272_pullup(struct usb_gadget *_gadget, int is_on) return 0; } -static int net2272_start(struct usb_gadget_driver *driver, - int (*bind)(struct usb_gadget *)); -static int net2272_stop(struct usb_gadget_driver *driver); +static int net2272_start(struct usb_gadget *_gadget, + struct usb_gadget_driver *driver); +static int net2272_stop(struct usb_gadget *_gadget, + struct usb_gadget_driver *driver); static const struct usb_gadget_ops net2272_ops = { - .get_frame = net2272_get_frame, - .wakeup = net2272_wakeup, + .get_frame = net2272_get_frame, + .wakeup = net2272_wakeup, .set_selfpowered = net2272_set_selfpowered, - .pullup = net2272_pullup, - .start = net2272_start, - .stop = net2272_stop, + .pullup = net2272_pullup, + .udc_start = net2272_start, + .udc_stop = net2272_stop, }; /*---------------------------------------------------------------------------*/ @@ -1356,8 +1357,6 @@ net2272_set_fifo_mode(struct net2272 *dev, int mode) /*---------------------------------------------------------------------------*/ -static struct net2272 *the_controller; - static void net2272_usb_reset(struct net2272 *dev) { @@ -1453,20 +1452,17 @@ net2272_ep0_start(struct net2272 *dev) * disconnect is reported. then a host may connect again, or * the driver might get unbound. */ -static int net2272_start(struct usb_gadget_driver *driver, - int (*bind)(struct usb_gadget *)) +static int net2272_start(struct usb_gadget *_gadget, + struct usb_gadget_driver *driver) { - struct net2272 *dev = the_controller; - int ret; + struct net2272 *dev; unsigned i; - if (!driver || !bind || !driver->unbind || !driver->setup || + if (!driver || !driver->unbind || !driver->setup || driver->speed != USB_SPEED_HIGH) return -EINVAL; - if (!dev) - return -ENODEV; - if (dev->driver) - return -EBUSY; + + dev = container_of(_gadget, struct net2272, gadget); for (i = 0; i < 4; ++i) dev->ep[i].irqs = 0; @@ -1475,14 +1471,6 @@ static int net2272_start(struct usb_gadget_driver *driver, driver->driver.bus = NULL; dev->driver = driver; dev->gadget.dev.driver = &driver->driver; - ret = bind(&dev->gadget); - if (ret) { - dev_dbg(dev->dev, "bind to driver %s --> %d\n", - driver->driver.name, ret); - dev->driver = NULL; - dev->gadget.dev.driver = NULL; - return ret; - } /* ... then enable host detection and ep0; and we're ready * for set_configuration as well as eventual disconnect. @@ -1510,33 +1498,21 @@ stop_activity(struct net2272 *dev, struct usb_gadget_driver *driver) for (i = 0; i < 4; ++i) net2272_dequeue_all(&dev->ep[i]); - /* report disconnect; the driver is already quiesced */ - if (driver) { - spin_unlock(&dev->lock); - driver->disconnect(&dev->gadget); - spin_lock(&dev->lock); - - } net2272_usb_reinit(dev); } -static int net2272_stop(struct usb_gadget_driver *driver) +static int net2272_stop(struct usb_gadget *_gadget, + struct usb_gadget_driver *driver) { - struct net2272 *dev = the_controller; + struct net2272 *dev; unsigned long flags; - if (!dev) - return -ENODEV; - if (!driver || driver != dev->driver) - return -EINVAL; + dev = container_of(_gadget, struct net2272, gadget); spin_lock_irqsave(&dev->lock, flags); stop_activity(dev, driver); spin_unlock_irqrestore(&dev->lock, flags); - net2272_pullup(&dev->gadget, 0); - - driver->unbind(&dev->gadget); dev->gadget.dev.driver = NULL; dev->driver = NULL; @@ -2238,7 +2214,6 @@ net2272_remove(struct net2272 *dev) device_remove_file(dev->dev, &dev_attr_registers); dev_info(dev->dev, "unbind\n"); - the_controller = NULL; } static struct net2272 * __devinit @@ -2246,11 +2221,6 @@ net2272_probe_init(struct device *dev, unsigned int irq) { struct net2272 *ret; - if (the_controller) { - dev_warn(dev, "ignoring\n"); - return ERR_PTR(-EBUSY); - } - if (!irq) { dev_dbg(dev, "No IRQ!\n"); return ERR_PTR(-ENODEV); @@ -2307,8 +2277,6 @@ net2272_probe_fin(struct net2272 *dev, unsigned int irqflags) dma_mode_string()); dev_info(dev->dev, "version: %s\n", driver_vers); - the_controller = dev; - ret = device_register(&dev->gadget.dev); if (ret) goto err_irq; @@ -2684,8 +2652,6 @@ net2272_plat_probe(struct platform_device *pdev) dev_info(&pdev->dev, "running in 16-bit, %sbyte swap local bus mode\n", (net2272_read(dev, LOCCTL) & (1 << BYTE_SWAP)) ? "" : "no "); - the_controller = dev; - return 0; err_io: -- cgit From 4cf5e00b055ba5e4f3852e477a2a4346730ea283 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Mon, 10 Oct 2011 10:37:17 +0300 Subject: usb: gadget: net2280: convert to new style with this patch we can finally remove the global "the_controller" pointer. Signed-off-by: Felipe Balbi --- drivers/usb/gadget/net2280.c | 70 +++++++++++--------------------------------- 1 file changed, 17 insertions(+), 53 deletions(-) (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/net2280.c b/drivers/usb/gadget/net2280.c index db508d0bb3af..2680fcc011d4 100644 --- a/drivers/usb/gadget/net2280.c +++ b/drivers/usb/gadget/net2280.c @@ -1401,17 +1401,18 @@ static int net2280_pullup(struct usb_gadget *_gadget, int is_on) return 0; } -static int net2280_start(struct usb_gadget_driver *driver, - int (*bind)(struct usb_gadget *)); -static int net2280_stop(struct usb_gadget_driver *driver); +static int net2280_start(struct usb_gadget *_gadget, + struct usb_gadget_driver *driver); +static int net2280_stop(struct usb_gadget *_gadget, + struct usb_gadget_driver *driver); static const struct usb_gadget_ops net2280_ops = { .get_frame = net2280_get_frame, .wakeup = net2280_wakeup, .set_selfpowered = net2280_set_selfpowered, .pullup = net2280_pullup, - .start = net2280_start, - .stop = net2280_stop, + .udc_start = net2280_start, + .udc_stop = net2280_stop, }; /*-------------------------------------------------------------------------*/ @@ -1744,8 +1745,6 @@ static void set_fifo_mode (struct net2280 *dev, int mode) * perhaps to bind specific drivers to specific devices. */ -static struct net2280 *the_controller; - static void usb_reset (struct net2280 *dev) { u32 tmp; @@ -1871,10 +1870,10 @@ static void ep0_start (struct net2280 *dev) * disconnect is reported. then a host may connect again, or * the driver might get unbound. */ -static int net2280_start(struct usb_gadget_driver *driver, - int (*bind)(struct usb_gadget *)) +static int net2280_start(struct usb_gadget *_gadget, + struct usb_gadget_driver *driver) { - struct net2280 *dev = the_controller; + struct net2280 *dev; int retval; unsigned i; @@ -1882,14 +1881,11 @@ static int net2280_start(struct usb_gadget_driver *driver, * (dev->usb->xcvrdiag & FORCE_FULL_SPEED_MODE) * "must not be used in normal operation" */ - if (!driver - || driver->speed != USB_SPEED_HIGH - || !bind || !driver->setup) + if (!driver || driver->speed != USB_SPEED_HIGH + || !driver->setup) return -EINVAL; - if (!dev) - return -ENODEV; - if (dev->driver) - return -EBUSY; + + dev = container_of (_gadget, struct net2280, gadget); for (i = 0; i < 7; i++) dev->ep [i].irqs = 0; @@ -1899,14 +1895,6 @@ static int net2280_start(struct usb_gadget_driver *driver, driver->driver.bus = NULL; dev->driver = driver; dev->gadget.dev.driver = &driver->driver; - retval = bind(&dev->gadget); - if (retval) { - DEBUG (dev, "bind to driver %s --> %d\n", - driver->driver.name, retval); - dev->driver = NULL; - dev->gadget.dev.driver = NULL; - return retval; - } retval = device_create_file (&dev->pdev->dev, &dev_attr_function); if (retval) goto err_unbind; @@ -1952,33 +1940,21 @@ stop_activity (struct net2280 *dev, struct usb_gadget_driver *driver) for (i = 0; i < 7; i++) nuke (&dev->ep [i]); - /* report disconnect; the driver is already quiesced */ - if (driver) { - spin_unlock (&dev->lock); - driver->disconnect (&dev->gadget); - spin_lock (&dev->lock); - } - usb_reinit (dev); } -static int net2280_stop(struct usb_gadget_driver *driver) +static int net2280_stop(struct usb_gadget *_gadget, + struct usb_gadget_driver *driver) { - struct net2280 *dev = the_controller; + struct net2280 *dev; unsigned long flags; - if (!dev) - return -ENODEV; - if (!driver || driver != dev->driver || !driver->unbind) - return -EINVAL; + dev = container_of (_gadget, struct net2280, gadget); spin_lock_irqsave (&dev->lock, flags); stop_activity (dev, driver); spin_unlock_irqrestore (&dev->lock, flags); - net2280_pullup (&dev->gadget, 0); - - driver->unbind (&dev->gadget); dev->gadget.dev.driver = NULL; dev->driver = NULL; @@ -2698,8 +2674,6 @@ static void net2280_remove (struct pci_dev *pdev) pci_set_drvdata (pdev, NULL); INFO (dev, "unbind\n"); - - the_controller = NULL; } /* wrap this driver around the specified device, but @@ -2713,14 +2687,6 @@ static int net2280_probe (struct pci_dev *pdev, const struct pci_device_id *id) void __iomem *base = NULL; int retval, i; - /* if you want to support more than one controller in a system, - * usb_gadget_driver_{register,unregister}() must change. - */ - if (the_controller) { - dev_warn (&pdev->dev, "ignoring\n"); - return -EBUSY; - } - /* alloc, and start init */ dev = kzalloc (sizeof *dev, GFP_KERNEL); if (dev == NULL){ @@ -2847,8 +2813,6 @@ static int net2280_probe (struct pci_dev *pdev, const struct pci_device_id *id) use_dma ? (use_dma_chaining ? "chaining" : "enabled") : "disabled"); - the_controller = dev; - retval = device_register (&dev->gadget.dev); if (retval) goto done; retval = device_create_file (&pdev->dev, &dev_attr_registers); -- cgit From 478ff25adef3d0ec394c8870fcf317c26839b482 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Mon, 10 Oct 2011 17:18:51 +0300 Subject: usb: gadget: r8a66597: convert to new style convert to new style UDC registration and remove the global 'the_controller' pointer. Signed-off-by: Felipe Balbi --- drivers/usb/gadget/r8a66597-udc.c | 37 ++++++++----------------------------- 1 file changed, 8 insertions(+), 29 deletions(-) (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/r8a66597-udc.c b/drivers/usb/gadget/r8a66597-udc.c index 035879b98dd9..68a826a1b866 100644 --- a/drivers/usb/gadget/r8a66597-udc.c +++ b/drivers/usb/gadget/r8a66597-udc.c @@ -1738,23 +1738,18 @@ static struct usb_ep_ops r8a66597_ep_ops = { }; /*-------------------------------------------------------------------------*/ -static struct r8a66597 *the_controller; - -static int r8a66597_start(struct usb_gadget_driver *driver, - int (*bind)(struct usb_gadget *)) +static int r8a66597_start(struct usb_gadget *gadget, + struct usb_gadget_driver *driver) { - struct r8a66597 *r8a66597 = the_controller; + struct r8a66597 *r8a66597 = gadget_to_r8a66597(gadget); int retval; if (!driver || driver->speed != USB_SPEED_HIGH - || !bind || !driver->setup) return -EINVAL; if (!r8a66597) return -ENODEV; - if (r8a66597->driver) - return -EBUSY; /* hook up the driver */ driver->driver.bus = NULL; @@ -1768,14 +1763,6 @@ static int r8a66597_start(struct usb_gadget_driver *driver, goto error; } - retval = bind(&r8a66597->gadget); - if (retval) { - dev_err(r8a66597_to_dev(r8a66597), - "bind to driver error (%d)\n", retval); - device_del(&r8a66597->gadget.dev); - goto error; - } - init_controller(r8a66597); r8a66597_bset(r8a66597, VBSE, INTENB0); if (r8a66597_read(r8a66597, INTSTS0) & VBSTS) { @@ -1796,23 +1783,17 @@ error: return retval; } -static int r8a66597_stop(struct usb_gadget_driver *driver) +static int r8a66597_stop(struct usb_gadget *gadget, + struct usb_gadget_driver *driver) { - struct r8a66597 *r8a66597 = the_controller; + struct r8a66597 *r8a66597 = gadget_to_r8a66597(gadget); unsigned long flags; - if (driver != r8a66597->driver || !driver->unbind) - return -EINVAL; - spin_lock_irqsave(&r8a66597->lock, flags); - if (r8a66597->gadget.speed != USB_SPEED_UNKNOWN) - r8a66597_usb_disconnect(r8a66597); r8a66597_bclr(r8a66597, VBSE, INTENB0); disable_controller(r8a66597); spin_unlock_irqrestore(&r8a66597->lock, flags); - driver->unbind(&r8a66597->gadget); - device_del(&r8a66597->gadget.dev); r8a66597->driver = NULL; return 0; @@ -1842,8 +1823,8 @@ static int r8a66597_pullup(struct usb_gadget *gadget, int is_on) static struct usb_gadget_ops r8a66597_gadget_ops = { .get_frame = r8a66597_get_frame, - .start = r8a66597_start, - .stop = r8a66597_stop, + .udc_start = r8a66597_start, + .udc_stop = r8a66597_stop, .pullup = r8a66597_pullup, }; @@ -2010,8 +1991,6 @@ static int __init r8a66597_probe(struct platform_device *pdev) r8a66597->pipenum2ep[0] = &r8a66597->ep[0]; r8a66597->epaddr2ep[0] = &r8a66597->ep[0]; - the_controller = r8a66597; - r8a66597->ep0_req = r8a66597_alloc_request(&r8a66597->ep[0].ep, GFP_KERNEL); if (r8a66597->ep0_req == NULL) -- cgit From 089b837a39552ee49a4ea4c188e8c3517473f10c Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Mon, 10 Oct 2011 09:43:44 +0300 Subject: usb: gadget: fix typo for default U1/U2 exit latencies s/DEFULT/DEFAULT/, no functional changes. Signed-off-by: Felipe Balbi --- drivers/usb/gadget/composite.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c index e74fd55c33d9..8a5529d214fb 100644 --- a/drivers/usb/gadget/composite.c +++ b/drivers/usb/gadget/composite.c @@ -542,9 +542,9 @@ static int bos_desc(struct usb_composite_dev *cdev) if (cdev->gadget->ops->get_config_params) cdev->gadget->ops->get_config_params(&dcd_config_params); else { - dcd_config_params.bU1devExitLat = USB_DEFULT_U1_DEV_EXIT_LAT; + dcd_config_params.bU1devExitLat = USB_DEFAULT_U1_DEV_EXIT_LAT; dcd_config_params.bU2DevExitLat = - cpu_to_le16(USB_DEFULT_U2_DEV_EXIT_LAT); + cpu_to_le16(USB_DEFAULT_U2_DEV_EXIT_LAT); } ss_cap->bU1devExitLat = dcd_config_params.bU1devExitLat; ss_cap->bU2DevExitLat = dcd_config_params.bU2DevExitLat; -- cgit From 4bb99b7c82bac1488a0228d2363db1f68d90f6f3 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Wed, 3 Aug 2011 14:33:27 +0300 Subject: usb: gadget: storage: add superspeed support this patch adds superspeed descriptors for the storage gadgets. Acked-by: Michal Nazarewicz Acked-by: Alan Stern Signed-off-by: Felipe Balbi --- drivers/usb/gadget/f_mass_storage.c | 22 +++++++ drivers/usb/gadget/file_storage.c | 59 +++++++++++++++--- drivers/usb/gadget/mass_storage.c | 2 +- drivers/usb/gadget/storage_common.c | 120 +++++++++++++++++++++++++++++++++++- 4 files changed, 190 insertions(+), 13 deletions(-) (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/f_mass_storage.c b/drivers/usb/gadget/f_mass_storage.c index 927ee88278bd..52583a235330 100644 --- a/drivers/usb/gadget/f_mass_storage.c +++ b/drivers/usb/gadget/f_mass_storage.c @@ -3023,6 +3023,28 @@ static int fsg_bind(struct usb_configuration *c, struct usb_function *f) } } + if (gadget_is_superspeed(gadget)) { + unsigned max_burst; + + /* 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_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; + } + } + return 0; autoconf_fail: diff --git a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c index a230009db734..5779549d7dc6 100644 --- a/drivers/usb/gadget/file_storage.c +++ b/drivers/usb/gadget/file_storage.c @@ -586,7 +586,19 @@ dev_qualifier = { .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 @@ -935,7 +947,8 @@ static int standard_setup_req(struct fsg_dev *fsg, break; case USB_DT_DEVICE_QUALIFIER: VDBG(fsg, "get device qualifier\n"); - if (!gadget_is_dualspeed(fsg->gadget)) + if (!gadget_is_dualspeed(fsg->gadget) || + fsg->gadget->speed == USB_SPEED_SUPER) break; /* * Assume ep0 uses the same maxpacket value for both @@ -948,7 +961,8 @@ static int standard_setup_req(struct fsg_dev *fsg, case USB_DT_OTHER_SPEED_CONFIG: VDBG(fsg, "get other-speed config descriptor\n"); - if (!gadget_is_dualspeed(fsg->gadget)) + if (!gadget_is_dualspeed(fsg->gadget) || + fsg->gadget->speed == USB_SPEED_SUPER) break; goto get_config; case USB_DT_CONFIG: @@ -967,7 +981,15 @@ get_config: 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 */ @@ -2777,13 +2799,15 @@ reset: /* Enable the endpoints */ d = fsg_ep_desc(fsg->gadget, - &fsg_fs_bulk_in_desc, &fsg_hs_bulk_in_desc); + &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_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; @@ -2792,7 +2816,8 @@ reset: if (transport_is_cbi()) { d = fsg_ep_desc(fsg->gadget, - &fsg_fs_intr_in_desc, &fsg_hs_intr_in_desc); + &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; @@ -3424,6 +3449,24 @@ static int __init fsg_bind(struct usb_gadget *gadget) 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; @@ -3540,11 +3583,7 @@ static void fsg_resume(struct usb_gadget *gadget) /*-------------------------------------------------------------------------*/ static struct usb_gadget_driver fsg_driver = { -#ifdef CONFIG_USB_GADGET_DUALSPEED - .speed = USB_SPEED_HIGH, -#else - .speed = USB_SPEED_FULL, -#endif + .speed = USB_SPEED_SUPER, .function = (char *) fsg_string_product, .unbind = fsg_unbind, .disconnect = fsg_disconnect, diff --git a/drivers/usb/gadget/mass_storage.c b/drivers/usb/gadget/mass_storage.c index d2a9dcb67088..e24f72f82a47 100644 --- a/drivers/usb/gadget/mass_storage.c +++ b/drivers/usb/gadget/mass_storage.c @@ -160,7 +160,7 @@ static struct usb_composite_driver msg_driver = { .name = "g_mass_storage", .dev = &msg_device_desc, .iProduct = DRIVER_DESC, - .max_speed = USB_SPEED_HIGH, + .max_speed = USB_SPEED_SUPER, .needs_serial = 1, }; diff --git a/drivers/usb/gadget/storage_common.c b/drivers/usb/gadget/storage_common.c index 523626274c0f..c7f291a331df 100644 --- a/drivers/usb/gadget/storage_common.c +++ b/drivers/usb/gadget/storage_common.c @@ -515,12 +515,128 @@ static struct usb_descriptor_header *fsg_hs_function[] = { NULL, }; +static struct usb_endpoint_descriptor +fsg_ss_bulk_in_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + + /* bEndpointAddress copied from fs_bulk_in_desc during fsg_bind() */ + .bmAttributes = USB_ENDPOINT_XFER_BULK, + .wMaxPacketSize = cpu_to_le16(1024), +}; + +static struct usb_ss_ep_comp_descriptor fsg_ss_bulk_in_comp_desc = { + .bLength = sizeof(fsg_ss_bulk_in_comp_desc), + .bDescriptorType = USB_DT_SS_ENDPOINT_COMP, + + /*.bMaxBurst = DYNAMIC, */ +}; + +static struct usb_endpoint_descriptor +fsg_ss_bulk_out_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + + /* bEndpointAddress copied from fs_bulk_out_desc during fsg_bind() */ + .bmAttributes = USB_ENDPOINT_XFER_BULK, + .wMaxPacketSize = cpu_to_le16(1024), +}; + +static struct usb_ss_ep_comp_descriptor fsg_ss_bulk_out_comp_desc = { + .bLength = sizeof(fsg_ss_bulk_in_comp_desc), + .bDescriptorType = USB_DT_SS_ENDPOINT_COMP, + + /*.bMaxBurst = DYNAMIC, */ +}; + +#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, + .bDevCapabilityType = USB_CAP_TYPE_EXT, + + .bmAttributes = cpu_to_le32(USB_LPM_SUPPORT), +}; + +static __maybe_unused struct usb_ss_cap_descriptor fsg_ss_cap_desc = { + .bLength = USB_DT_USB_SS_CAP_SIZE, + .bDescriptorType = USB_DT_DEVICE_CAPABILITY, + .bDevCapabilityType = USB_SS_CAP_TYPE, + + /* .bmAttributes = LTM is not supported yet */ + + .wSpeedSupported = cpu_to_le16(USB_LOW_SPEED_OPERATION + | USB_FULL_SPEED_OPERATION + | USB_HIGH_SPEED_OPERATION + | USB_5GBPS_OPERATION), + .bFunctionalitySupport = USB_LOW_SPEED_OPERATION, + .bU1devExitLat = USB_DEFAULT_U1_DEV_EXIT_LAT, + .bU2DevExitLat = USB_DEFAULT_U2_DEV_EXIT_LAT, +}; + +static __maybe_unused struct usb_bos_descriptor fsg_bos_desc = { + .bLength = USB_DT_BOS_SIZE, + .bDescriptorType = USB_DT_BOS, + + .wTotalLength = USB_DT_BOS_SIZE + + USB_DT_USB_EXT_CAP_SIZE + + USB_DT_USB_SS_CAP_SIZE, + + .bNumDeviceCaps = 2, +}; + +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, +}; + /* Maxpacket and other transfer characteristics vary by speed. */ static __maybe_unused struct usb_endpoint_descriptor * fsg_ep_desc(struct usb_gadget *g, struct usb_endpoint_descriptor *fs, - struct usb_endpoint_descriptor *hs) + struct usb_endpoint_descriptor *hs, + struct usb_endpoint_descriptor *ss) { - if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH) + if (gadget_is_superspeed(g) && g->speed == USB_SPEED_SUPER) + return ss; + else if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH) return hs; return fs; } -- cgit From dde34cc5019b51088c18ca789d4b1a20cf9bc617 Mon Sep 17 00:00:00 2001 From: Neil Zhang Date: Wed, 12 Oct 2011 16:49:24 +0800 Subject: usb: gadget: mv_udc: refine the driver structure This patch do the following things: 1. Add header and Copyright for marvell usb driver. 2. Add mv_usb.h in include/linux/platform_data, make the driver fits all the marvell platform using the same ChipIdea usb ip. 3. Some SOC may has mutiple clock sources, so let me define it in mv_usb_platform_data and give two helper functions named udc_clock_enable/udc_clock_disable to deal with the clocks. 4. Different SOCs will have some difference in PHY initialization, so we will remove file mv_udc_phy.c and add two funtions in mv_usb_platform_data, let the platform relative driver to realize it. 5. Rewrite probe function according to the modification list above. Find it will kernel panic when probe failed. The root cause is as follows: When probe failed, the error handle may call device_unregister() which in return will call gadget_release.In current code, gadget_release have two issues: 1: the_controller is a NULL pointer. 2: if we free udc here, then the following code in probe will access NULL pointer. Signed-off-by: Neil Zhang Signed-off-by: Felipe Balbi --- drivers/usb/gadget/Makefile | 2 +- drivers/usb/gadget/mv_udc.h | 17 +++- drivers/usb/gadget/mv_udc_core.c | 158 +++++++++++++++++++++-------- drivers/usb/gadget/mv_udc_phy.c | 214 --------------------------------------- 4 files changed, 132 insertions(+), 259 deletions(-) delete mode 100644 drivers/usb/gadget/mv_udc_phy.c (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile index 9ba725af4a08..c36da63009db 100644 --- a/drivers/usb/gadget/Makefile +++ b/drivers/usb/gadget/Makefile @@ -28,7 +28,7 @@ obj-$(CONFIG_USB_S3C_HSUDC) += s3c-hsudc.o obj-$(CONFIG_USB_LANGWELL) += langwell_udc.o obj-$(CONFIG_USB_EG20T) += pch_udc.o obj-$(CONFIG_USB_PXA_U2O) += mv_udc.o -mv_udc-y := mv_udc_core.o mv_udc_phy.o +mv_udc-y := mv_udc_core.o obj-$(CONFIG_USB_CI13XXX_MSM) += ci13xxx_msm.o obj-$(CONFIG_USB_FUSB300) += fusb300_udc.o diff --git a/drivers/usb/gadget/mv_udc.h b/drivers/usb/gadget/mv_udc.h index 65f1f7c3bd4e..d3d26454b8bb 100644 --- a/drivers/usb/gadget/mv_udc.h +++ b/drivers/usb/gadget/mv_udc.h @@ -1,3 +1,11 @@ +/* + * Copyright (C) 2011 Marvell International Ltd. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ #ifndef __MV_UDC_H #define __MV_UDC_H @@ -201,7 +209,12 @@ struct mv_udc { remote_wakeup:1, softconnected:1, force_fs:1; - struct clk *clk; + + struct mv_usb_platform_data *pdata; + + /* some SOC has mutiple clock sources for USB*/ + unsigned int clknum; + struct clk *clk[0]; }; /* endpoint data structure */ @@ -289,6 +302,4 @@ struct mv_dtd { struct mv_dtd *next_dtd_virt; }; -extern int mv_udc_phy_init(unsigned int base); - #endif diff --git a/drivers/usb/gadget/mv_udc_core.c b/drivers/usb/gadget/mv_udc_core.c index 0d0e9e39f8b2..40a25e75cc6a 100644 --- a/drivers/usb/gadget/mv_udc_core.c +++ b/drivers/usb/gadget/mv_udc_core.c @@ -1,3 +1,14 @@ +/* + * Copyright (C) 2011 Marvell International Ltd. All rights reserved. + * Author: Chao Xie + * Neil Zhang + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + #include #include #include @@ -22,6 +33,7 @@ #include #include #include +#include #include #include @@ -45,6 +57,8 @@ #define LOOPS_USEC (1 << LOOPS_USEC_SHIFT) #define LOOPS(timeout) ((timeout) >> LOOPS_USEC_SHIFT) +static DECLARE_COMPLETION(release_done); + static const char driver_name[] = "mv_udc"; static const char driver_desc[] = DRIVER_DESC; @@ -987,6 +1001,22 @@ static struct usb_ep_ops mv_ep_ops = { .fifo_flush = mv_ep_fifo_flush, /* flush fifo */ }; +static void udc_clock_enable(struct mv_udc *udc) +{ + unsigned int i; + + for (i = 0; i < udc->clknum; i++) + clk_enable(udc->clk[i]); +} + +static void udc_clock_disable(struct mv_udc *udc) +{ + unsigned int i; + + for (i = 0; i < udc->clknum; i++) + clk_disable(udc->clk[i]); +} + static void udc_stop(struct mv_udc *udc) { u32 tmp; @@ -1877,18 +1907,15 @@ static void gadget_release(struct device *_dev) struct mv_udc *udc = the_controller; complete(udc->done); - kfree(udc); } static int mv_udc_remove(struct platform_device *dev) { struct mv_udc *udc = the_controller; - DECLARE_COMPLETION(done); + int clk_i; usb_del_gadget_udc(&udc->gadget); - udc->done = &done; - /* free memory allocated in probe */ if (udc->dtd_pool) dma_pool_destroy(udc->dtd_pool); @@ -1915,10 +1942,14 @@ static int mv_udc_remove(struct platform_device *dev) kfree(udc->status_req); } + for (clk_i = 0; clk_i <= udc->clknum; clk_i++) + clk_put(udc->clk[clk_i]); + device_unregister(&udc->gadget.dev); /* free dev, wait for the release() finished */ - wait_for_completion(&done); + wait_for_completion(udc->done); + kfree(udc); the_controller = NULL; @@ -1927,33 +1958,46 @@ static int mv_udc_remove(struct platform_device *dev) int mv_udc_probe(struct platform_device *dev) { + struct mv_usb_platform_data *pdata = dev->dev.platform_data; struct mv_udc *udc; int retval = 0; + int clk_i = 0; struct resource *r; size_t size; - udc = kzalloc(sizeof *udc, GFP_KERNEL); + if (pdata == NULL) { + dev_err(&dev->dev, "missing platform_data\n"); + return -ENODEV; + } + + size = sizeof(*udc) + sizeof(struct clk *) * pdata->clknum; + udc = kzalloc(size, GFP_KERNEL); if (udc == NULL) { dev_err(&dev->dev, "failed to allocate memory for udc\n"); - retval = -ENOMEM; - goto error; + return -ENOMEM; } + the_controller = udc; + udc->done = &release_done; + udc->pdata = dev->dev.platform_data; spin_lock_init(&udc->lock); udc->dev = dev; - udc->clk = clk_get(&dev->dev, "U2OCLK"); - if (IS_ERR(udc->clk)) { - retval = PTR_ERR(udc->clk); - goto error; + udc->clknum = pdata->clknum; + for (clk_i = 0; clk_i < udc->clknum; clk_i++) { + udc->clk[clk_i] = clk_get(&dev->dev, pdata->clkname[clk_i]); + if (IS_ERR(udc->clk[clk_i])) { + retval = PTR_ERR(udc->clk[clk_i]); + goto err_put_clk; + } } - r = platform_get_resource_byname(udc->dev, IORESOURCE_MEM, "u2o"); + r = platform_get_resource_byname(udc->dev, IORESOURCE_MEM, "capregs"); if (r == NULL) { dev_err(&dev->dev, "no I/O memory resource defined\n"); retval = -ENODEV; - goto error; + goto err_put_clk; } udc->cap_regs = (struct mv_cap_regs __iomem *) @@ -1961,29 +2005,31 @@ int mv_udc_probe(struct platform_device *dev) if (udc->cap_regs == NULL) { dev_err(&dev->dev, "failed to map I/O memory\n"); retval = -EBUSY; - goto error; + goto err_put_clk; } - r = platform_get_resource_byname(udc->dev, IORESOURCE_MEM, "u2ophy"); + r = platform_get_resource_byname(udc->dev, IORESOURCE_MEM, "phyregs"); if (r == NULL) { dev_err(&dev->dev, "no phy I/O memory resource defined\n"); retval = -ENODEV; - goto error; + goto err_iounmap_capreg; } udc->phy_regs = (unsigned int)ioremap(r->start, resource_size(r)); if (udc->phy_regs == 0) { dev_err(&dev->dev, "failed to map phy I/O memory\n"); retval = -EBUSY; - goto error; + goto err_iounmap_capreg; } /* we will acces controller register, so enable the clk */ - clk_enable(udc->clk); - retval = mv_udc_phy_init(udc->phy_regs); - if (retval) { - dev_err(&dev->dev, "phy initialization error %d\n", retval); - goto error; + udc_clock_enable(udc); + if (pdata->phy_init) { + retval = pdata->phy_init(udc->phy_regs); + if (retval) { + dev_err(&dev->dev, "phy init error %d\n", retval); + goto err_iounmap_phyreg; + } } udc->op_regs = (struct mv_op_regs __iomem *)((u32)udc->cap_regs @@ -1999,7 +2045,7 @@ int mv_udc_probe(struct platform_device *dev) if (udc->ep_dqh == NULL) { dev_err(&dev->dev, "allocate dQH memory failed\n"); retval = -ENOMEM; - goto error; + goto err_disable_clock; } udc->ep_dqh_size = size; @@ -2012,7 +2058,7 @@ int mv_udc_probe(struct platform_device *dev) if (!udc->dtd_pool) { retval = -ENOMEM; - goto error; + goto err_free_dma; } size = udc->max_eps * sizeof(struct mv_ep) *2; @@ -2020,7 +2066,7 @@ int mv_udc_probe(struct platform_device *dev) if (udc->eps == NULL) { dev_err(&dev->dev, "allocate ep memory failed\n"); retval = -ENOMEM; - goto error; + goto err_destroy_dma; } /* initialize ep0 status request structure */ @@ -2028,7 +2074,7 @@ int mv_udc_probe(struct platform_device *dev) if (!udc->status_req) { dev_err(&dev->dev, "allocate status_req memory failed\n"); retval = -ENOMEM; - goto error; + goto err_free_eps; } INIT_LIST_HEAD(&udc->status_req->queue); @@ -2045,7 +2091,7 @@ int mv_udc_probe(struct platform_device *dev) if (r == NULL) { dev_err(&dev->dev, "no IRQ resource defined\n"); retval = -ENODEV; - goto error; + goto err_free_status_req; } udc->irq = r->start; if (request_irq(udc->irq, mv_udc_irq, @@ -2053,7 +2099,7 @@ int mv_udc_probe(struct platform_device *dev) dev_err(&dev->dev, "Request irq %d for UDC failed\n", udc->irq); retval = -ENODEV; - goto error; + goto err_free_status_req; } /* initialize gadget structure */ @@ -2072,18 +2118,43 @@ int mv_udc_probe(struct platform_device *dev) retval = device_register(&udc->gadget.dev); if (retval) - goto error; + goto err_free_irq; eps_init(udc); - the_controller = udc; - retval = usb_add_gadget_udc(&dev->dev, &udc->gadget); - if (!retval) - return retval; -error: - if (udc) - mv_udc_remove(udc->dev); + if (retval) + goto err_unregister; + + return 0; + +err_unregister: + device_unregister(&udc->gadget.dev); +err_free_irq: + free_irq(udc->irq, &dev->dev); +err_free_status_req: + kfree(udc->status_req->req.buf); + kfree(udc->status_req); +err_free_eps: + kfree(udc->eps); +err_destroy_dma: + dma_pool_destroy(udc->dtd_pool); +err_free_dma: + dma_free_coherent(&dev->dev, udc->ep_dqh_size, + udc->ep_dqh, udc->ep_dqh_dma); +err_disable_clock: + if (udc->pdata->phy_deinit) + udc->pdata->phy_deinit(udc->phy_regs); + udc_clock_disable(udc); +err_iounmap_phyreg: + iounmap((void *)udc->phy_regs); +err_iounmap_capreg: + iounmap(udc->cap_regs); +err_put_clk: + for (clk_i--; clk_i >= 0; clk_i--) + clk_put(udc->clk[clk_i]); + the_controller = NULL; + kfree(udc); return retval; } @@ -2102,11 +2173,16 @@ static int mv_udc_resume(struct device *_dev) struct mv_udc *udc = the_controller; int retval; - retval = mv_udc_phy_init(udc->phy_regs); - if (retval) { - dev_err(_dev, "phy initialization error %d\n", retval); - return retval; + if (udc->pdata->phy_init) { + retval = udc->pdata->phy_init(udc->phy_regs); + if (retval) { + dev_err(&udc->dev->dev, + "init phy error %d when resume back\n", + retval); + return retval; + } } + udc_reset(udc); ep0_reset(udc); udc_start(udc); diff --git a/drivers/usb/gadget/mv_udc_phy.c b/drivers/usb/gadget/mv_udc_phy.c deleted file mode 100644 index d4dea97e38a5..000000000000 --- a/drivers/usb/gadget/mv_udc_phy.c +++ /dev/null @@ -1,214 +0,0 @@ -#include -#include -#include -#include - -#include - -#ifdef CONFIG_ARCH_MMP - -#define UTMI_REVISION 0x0 -#define UTMI_CTRL 0x4 -#define UTMI_PLL 0x8 -#define UTMI_TX 0xc -#define UTMI_RX 0x10 -#define UTMI_IVREF 0x14 -#define UTMI_T0 0x18 -#define UTMI_T1 0x1c -#define UTMI_T2 0x20 -#define UTMI_T3 0x24 -#define UTMI_T4 0x28 -#define UTMI_T5 0x2c -#define UTMI_RESERVE 0x30 -#define UTMI_USB_INT 0x34 -#define UTMI_DBG_CTL 0x38 -#define UTMI_OTG_ADDON 0x3c - -/* For UTMICTRL Register */ -#define UTMI_CTRL_USB_CLK_EN (1 << 31) -/* pxa168 */ -#define UTMI_CTRL_SUSPEND_SET1 (1 << 30) -#define UTMI_CTRL_SUSPEND_SET2 (1 << 29) -#define UTMI_CTRL_RXBUF_PDWN (1 << 24) -#define UTMI_CTRL_TXBUF_PDWN (1 << 11) - -#define UTMI_CTRL_INPKT_DELAY_SHIFT 30 -#define UTMI_CTRL_INPKT_DELAY_SOF_SHIFT 28 -#define UTMI_CTRL_PU_REF_SHIFT 20 -#define UTMI_CTRL_ARC_PULLDN_SHIFT 12 -#define UTMI_CTRL_PLL_PWR_UP_SHIFT 1 -#define UTMI_CTRL_PWR_UP_SHIFT 0 -/* For UTMI_PLL Register */ -#define UTMI_PLL_CLK_BLK_EN_SHIFT 24 -#define UTMI_PLL_FBDIV_SHIFT 4 -#define UTMI_PLL_REFDIV_SHIFT 0 -#define UTMI_PLL_FBDIV_MASK 0x00000FF0 -#define UTMI_PLL_REFDIV_MASK 0x0000000F -#define UTMI_PLL_ICP_MASK 0x00007000 -#define UTMI_PLL_KVCO_MASK 0x00031000 -#define UTMI_PLL_PLLCALI12_SHIFT 29 -#define UTMI_PLL_PLLCALI12_MASK (0x3 << 29) -#define UTMI_PLL_PLLVDD18_SHIFT 27 -#define UTMI_PLL_PLLVDD18_MASK (0x3 << 27) -#define UTMI_PLL_PLLVDD12_SHIFT 25 -#define UTMI_PLL_PLLVDD12_MASK (0x3 << 25) -#define UTMI_PLL_KVCO_SHIFT 15 -#define UTMI_PLL_ICP_SHIFT 12 -/* For UTMI_TX Register */ -#define UTMI_TX_REG_EXT_FS_RCAL_SHIFT 27 -#define UTMI_TX_REG_EXT_FS_RCAL_MASK (0xf << 27) -#define UTMI_TX_REG_EXT_FS_RCAL_EN_MASK 26 -#define UTMI_TX_REG_EXT_FS_RCAL_EN (0x1 << 26) -#define UTMI_TX_LOW_VDD_EN_SHIFT 11 -#define UTMI_TX_IMPCAL_VTH_SHIFT 14 -#define UTMI_TX_IMPCAL_VTH_MASK (0x7 << 14) -#define UTMI_TX_CK60_PHSEL_SHIFT 17 -#define UTMI_TX_CK60_PHSEL_MASK (0xf << 17) -#define UTMI_TX_TXVDD12_SHIFT 22 -#define UTMI_TX_TXVDD12_MASK (0x3 << 22) -#define UTMI_TX_AMP_SHIFT 0 -#define UTMI_TX_AMP_MASK (0x7 << 0) -/* For UTMI_RX Register */ -#define UTMI_RX_SQ_THRESH_SHIFT 4 -#define UTMI_RX_SQ_THRESH_MASK (0xf << 4) -#define UTMI_REG_SQ_LENGTH_SHIFT 15 -#define UTMI_REG_SQ_LENGTH_MASK (0x3 << 15) - -#define REG_RCAL_START 0x00001000 -#define VCOCAL_START 0x00200000 -#define KVCO_EXT 0x00400000 -#define PLL_READY 0x00800000 -#define CLK_BLK_EN 0x01000000 -#endif - -static unsigned int u2o_read(unsigned int base, unsigned int offset) -{ - return readl(base + offset); -} - -static void u2o_set(unsigned int base, unsigned int offset, unsigned int value) -{ - unsigned int reg; - - reg = readl(base + offset); - reg |= value; - writel(reg, base + offset); - readl(base + offset); -} - -static void u2o_clear(unsigned int base, unsigned int offset, - unsigned int value) -{ - unsigned int reg; - - reg = readl(base + offset); - reg &= ~value; - writel(reg, base + offset); - readl(base + offset); -} - -static void u2o_write(unsigned int base, unsigned int offset, - unsigned int value) -{ - writel(value, base + offset); - readl(base + offset); -} - -#ifdef CONFIG_ARCH_MMP -int mv_udc_phy_init(unsigned int base) -{ - unsigned long timeout; - - /* Initialize the USB PHY power */ - if (cpu_is_pxa910()) { - u2o_set(base, UTMI_CTRL, (1 << UTMI_CTRL_INPKT_DELAY_SOF_SHIFT) - | (1 << UTMI_CTRL_PU_REF_SHIFT)); - } - - u2o_set(base, UTMI_CTRL, 1 << UTMI_CTRL_PLL_PWR_UP_SHIFT); - u2o_set(base, UTMI_CTRL, 1 << UTMI_CTRL_PWR_UP_SHIFT); - - /* UTMI_PLL settings */ - u2o_clear(base, UTMI_PLL, UTMI_PLL_PLLVDD18_MASK - | UTMI_PLL_PLLVDD12_MASK | UTMI_PLL_PLLCALI12_MASK - | UTMI_PLL_FBDIV_MASK | UTMI_PLL_REFDIV_MASK - | UTMI_PLL_ICP_MASK | UTMI_PLL_KVCO_MASK); - - u2o_set(base, UTMI_PLL, (0xee << UTMI_PLL_FBDIV_SHIFT) - | (0xb << UTMI_PLL_REFDIV_SHIFT) - | (3 << UTMI_PLL_PLLVDD18_SHIFT) - | (3 << UTMI_PLL_PLLVDD12_SHIFT) - | (3 << UTMI_PLL_PLLCALI12_SHIFT) - | (1 << UTMI_PLL_ICP_SHIFT) | (3 << UTMI_PLL_KVCO_SHIFT)); - - /* UTMI_TX */ - u2o_clear(base, UTMI_TX, UTMI_TX_REG_EXT_FS_RCAL_EN_MASK - | UTMI_TX_TXVDD12_MASK - | UTMI_TX_CK60_PHSEL_MASK | UTMI_TX_IMPCAL_VTH_MASK - | UTMI_TX_REG_EXT_FS_RCAL_MASK | UTMI_TX_AMP_MASK); - u2o_set(base, UTMI_TX, (3 << UTMI_TX_TXVDD12_SHIFT) - | (4 << UTMI_TX_CK60_PHSEL_SHIFT) - | (4 << UTMI_TX_IMPCAL_VTH_SHIFT) - | (8 << UTMI_TX_REG_EXT_FS_RCAL_SHIFT) - | (3 << UTMI_TX_AMP_SHIFT)); - - /* UTMI_RX */ - u2o_clear(base, UTMI_RX, UTMI_RX_SQ_THRESH_MASK - | UTMI_REG_SQ_LENGTH_MASK); - if (cpu_is_pxa168()) - u2o_set(base, UTMI_RX, (7 << UTMI_RX_SQ_THRESH_SHIFT) - | (2 << UTMI_REG_SQ_LENGTH_SHIFT)); - else - u2o_set(base, UTMI_RX, (0x7 << UTMI_RX_SQ_THRESH_SHIFT) - | (2 << UTMI_REG_SQ_LENGTH_SHIFT)); - - /* UTMI_IVREF */ - if (cpu_is_pxa168()) - /* - * fixing Microsoft Altair board interface with NEC hub issue - - * Set UTMI_IVREF from 0x4a3 to 0x4bf - */ - u2o_write(base, UTMI_IVREF, 0x4bf); - - /* calibrate */ - timeout = jiffies + 100; - while ((u2o_read(base, UTMI_PLL) & PLL_READY) == 0) { - if (time_after(jiffies, timeout)) - return -ETIME; - cpu_relax(); - } - - /* toggle VCOCAL_START bit of UTMI_PLL */ - udelay(200); - u2o_set(base, UTMI_PLL, VCOCAL_START); - udelay(40); - u2o_clear(base, UTMI_PLL, VCOCAL_START); - - /* toggle REG_RCAL_START bit of UTMI_TX */ - udelay(200); - u2o_set(base, UTMI_TX, REG_RCAL_START); - udelay(40); - u2o_clear(base, UTMI_TX, REG_RCAL_START); - udelay(200); - - /* make sure phy is ready */ - timeout = jiffies + 100; - while ((u2o_read(base, UTMI_PLL) & PLL_READY) == 0) { - if (time_after(jiffies, timeout)) - return -ETIME; - cpu_relax(); - } - - if (cpu_is_pxa168()) { - u2o_set(base, UTMI_RESERVE, 1 << 5); - /* Turn on UTMI PHY OTG extension */ - u2o_write(base, UTMI_OTG_ADDON, 1); - } - return 0; -} -#else -int mv_udc_phy_init(unsigned int base) -{ - return 0; -} -#endif -- cgit From 5d0b8d0f3af46c5364bc36f814cf2c407012dd1b Mon Sep 17 00:00:00 2001 From: Neil Zhang Date: Wed, 12 Oct 2011 16:49:25 +0800 Subject: usb: gadget: mv_udc: add section information Tag the probe function as __devinit. Tag the remove function as __devexit. Signed-off-by: Neil Zhang Signed-off-by: Felipe Balbi --- drivers/usb/gadget/mv_udc_core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/mv_udc_core.c b/drivers/usb/gadget/mv_udc_core.c index 40a25e75cc6a..cd4de00a3ff5 100644 --- a/drivers/usb/gadget/mv_udc_core.c +++ b/drivers/usb/gadget/mv_udc_core.c @@ -1909,7 +1909,7 @@ static void gadget_release(struct device *_dev) complete(udc->done); } -static int mv_udc_remove(struct platform_device *dev) +static int __devexit mv_udc_remove(struct platform_device *dev) { struct mv_udc *udc = the_controller; int clk_i; @@ -1956,7 +1956,7 @@ static int mv_udc_remove(struct platform_device *dev) return 0; } -int mv_udc_probe(struct platform_device *dev) +static int __devinit mv_udc_probe(struct platform_device *dev) { struct mv_usb_platform_data *pdata = dev->dev.platform_data; struct mv_udc *udc; -- cgit From 4540a9ab319f1a55ded5f635da66da60d3c93e69 Mon Sep 17 00:00:00 2001 From: Neil Zhang Date: Wed, 12 Oct 2011 16:49:26 +0800 Subject: usb: gadget: mv_udc: fix kernel panic on some platforms Some platforms will use usb to download images, the controller may not be stopped correctly when start kernel. In some cases, it may have some pending interrupts, and they will be triggered immediately when we finish requesting irq in function probe. But we haven't finished the device initialization at this time. So let's stop udc here to avoid this case occurred. Signed-off-by: Neil Zhang Signed-off-by: Felipe Balbi --- drivers/usb/gadget/mv_udc_core.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/mv_udc_core.c b/drivers/usb/gadget/mv_udc_core.c index cd4de00a3ff5..84655289aea9 100644 --- a/drivers/usb/gadget/mv_udc_core.c +++ b/drivers/usb/gadget/mv_udc_core.c @@ -2037,6 +2037,13 @@ static int __devinit mv_udc_probe(struct platform_device *dev) & CAPLENGTH_MASK)); udc->max_eps = readl(&udc->cap_regs->dccparams) & DCCPARAMS_DEN_MASK; + /* + * some platform will use usb to download image, it may not disconnect + * usb gadget before loading kernel. So first stop udc here. + */ + udc_stop(udc); + writel(0xFFFFFFFF, &udc->op_regs->usbsts); + size = udc->max_eps * sizeof(struct mv_dqh) *2; size = (size + DQH_ALIGNMENT - 1) & ~(DQH_ALIGNMENT - 1); udc->ep_dqh = dma_alloc_coherent(&dev->dev, size, -- cgit From bedcff970e16d36324ddbfa61de33e4640c9d619 Mon Sep 17 00:00:00 2001 From: Neil Zhang Date: Wed, 12 Oct 2011 16:49:27 +0800 Subject: usb: gadget: mv_udc: fix a clerical error The max size of data payload is in bit0 - bit10, so we need use 0x7ff as the bitmask to fetch from usb_endpoint_descriptor.wMaxPacketSize. Signed-off-by: Neil Zhang Signed-off-by: Felipe Balbi --- drivers/usb/gadget/mv_udc_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/mv_udc_core.c b/drivers/usb/gadget/mv_udc_core.c index 84655289aea9..e2b302f11d07 100644 --- a/drivers/usb/gadget/mv_udc_core.c +++ b/drivers/usb/gadget/mv_udc_core.c @@ -546,7 +546,7 @@ static int mv_ep_enable(struct usb_ep *_ep, case USB_ENDPOINT_XFER_ISOC: /* Calculate transactions needed for high bandwidth iso */ mult = (unsigned char)(1 + ((max >> 11) & 0x03)); - max = max & 0x8ff; /* bit 0~10 */ + max = max & 0x7ff; /* bit 0~10 */ /* 3 transactions at most */ if (mult > 3) goto en_done; -- cgit From 43ad9f3faea18d7b3e1183753d3e6372a7037edf Mon Sep 17 00:00:00 2001 From: Neil Zhang Date: Wed, 12 Oct 2011 16:49:28 +0800 Subject: usb: gadget: mv_udc: ep0 needn't set toggle flag According to ChipIdea datasheet, there is no toggle flag for ep0. Signed-off-by: Neil Zhang Signed-off-by: Felipe Balbi --- drivers/usb/gadget/mv_udc_core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/mv_udc_core.c b/drivers/usb/gadget/mv_udc_core.c index e2b302f11d07..80168d11841d 100644 --- a/drivers/usb/gadget/mv_udc_core.c +++ b/drivers/usb/gadget/mv_udc_core.c @@ -98,12 +98,12 @@ static void ep0_reset(struct mv_udc *udc) epctrlx = readl(&udc->op_regs->epctrlx[0]); if (i) { /* TX */ - epctrlx |= EPCTRL_TX_ENABLE | EPCTRL_TX_DATA_TOGGLE_RST + epctrlx |= EPCTRL_TX_ENABLE | (USB_ENDPOINT_XFER_CONTROL << EPCTRL_TX_EP_TYPE_SHIFT); } else { /* RX */ - epctrlx |= EPCTRL_RX_ENABLE | EPCTRL_RX_DATA_TOGGLE_RST + epctrlx |= EPCTRL_RX_ENABLE | (USB_ENDPOINT_XFER_CONTROL << EPCTRL_RX_EP_TYPE_SHIFT); } -- cgit From fbebe1f070a73c108415bb9ee0483570650e2712 Mon Sep 17 00:00:00 2001 From: Neil Zhang Date: Wed, 12 Oct 2011 16:49:29 +0800 Subject: usb: gadget: mv_udc: init next dtd ptr for dqh when init ep0 Set next dtd ptr to EP_QUEUE_HEAD_NEXT_TERMINATE for dqh when init ep0. It means the dQH is empty. Signed-off-by: Neil Zhang Signed-off-by: Felipe Balbi --- drivers/usb/gadget/mv_udc_core.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/mv_udc_core.c b/drivers/usb/gadget/mv_udc_core.c index 80168d11841d..8dab8c4d10bd 100644 --- a/drivers/usb/gadget/mv_udc_core.c +++ b/drivers/usb/gadget/mv_udc_core.c @@ -96,6 +96,8 @@ static void ep0_reset(struct mv_udc *udc) (EP0_MAX_PKT_SIZE << EP_QUEUE_HEAD_MAX_PKT_LEN_POS) | EP_QUEUE_HEAD_IOS; + ep->dqh->next_dtd_ptr = EP_QUEUE_HEAD_NEXT_TERMINATE; + epctrlx = readl(&udc->op_regs->epctrlx[0]); if (i) { /* TX */ epctrlx |= EPCTRL_TX_ENABLE -- cgit From 96c2bbb09d0742148a305d7afbdf7c5803fd78c1 Mon Sep 17 00:00:00 2001 From: Neil Zhang Date: Wed, 12 Oct 2011 16:49:30 +0800 Subject: usb: gadget: mv_udc: fix bug when handle setup package. For the code doesn't restrict controller ep must be ep0, so we will go through all the eps and check if there is a setup package received. And also we just need to acknowledge the corresponding bit in ENDPTSETUPSTAT register. Signed-off-by: Neil Zhang Signed-off-by: Felipe Balbi --- drivers/usb/gadget/mv_udc_core.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/mv_udc_core.c b/drivers/usb/gadget/mv_udc_core.c index 8dab8c4d10bd..fcb980def624 100644 --- a/drivers/usb/gadget/mv_udc_core.c +++ b/drivers/usb/gadget/mv_udc_core.c @@ -1631,8 +1631,7 @@ static void get_setup_data(struct mv_udc *udc, u8 ep_num, u8 *buffer_ptr) dqh = &udc->ep_dqh[ep_num * 2 + EP_DIR_OUT]; /* Clear bit in ENDPTSETUPSTAT */ - temp = readl(&udc->op_regs->epsetupstat); - writel(temp | (1 << ep_num), &udc->op_regs->epsetupstat); + writel((1 << ep_num), &udc->op_regs->epsetupstat); /* while a hazard exists when setup package arrives */ do { -- cgit From 27cec2b2f7a4d2394af63a3dc7928975f4c072f4 Mon Sep 17 00:00:00 2001 From: Neil Zhang Date: Wed, 12 Oct 2011 16:49:31 +0800 Subject: usb: gadget: mv_udc: add missing spinlock in ep enable/disable The ep enable / disable functions can be called from interrupt context, and they are not race safe on SMP systems. The critical data can be modified in more than one routing. Make them race safe by using IRQ-safe spinlock functions. Signed-off-by: Neil Zhang Signed-off-by: Felipe Balbi --- drivers/usb/gadget/mv_udc_core.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/mv_udc_core.c b/drivers/usb/gadget/mv_udc_core.c index fcb980def624..501b05a253cc 100644 --- a/drivers/usb/gadget/mv_udc_core.c +++ b/drivers/usb/gadget/mv_udc_core.c @@ -497,6 +497,7 @@ static int mv_ep_enable(struct usb_ep *_ep, u16 max = 0; u32 bit_pos, epctrlx, direction; unsigned char zlt = 0, ios = 0, mult = 0; + unsigned long flags; ep = container_of(_ep, struct mv_ep, ep); udc = ep->udc; @@ -517,9 +518,6 @@ static int mv_ep_enable(struct usb_ep *_ep, */ zlt = 1; - /* Get the endpoint queue head address */ - dqh = (struct mv_dqh *)ep->dqh; - bit_pos = 1 << ((direction == EP_DIR_OUT ? 0 : 16) + ep->ep_num); /* Check if the Endpoint is Primed */ @@ -556,6 +554,10 @@ static int mv_ep_enable(struct usb_ep *_ep, default: goto en_done; } + + spin_lock_irqsave(&udc->lock, flags); + /* Get the endpoint queue head address */ + dqh = ep->dqh; dqh->max_packet_length = (max << EP_QUEUE_HEAD_MAX_PKT_LEN_POS) | (mult << EP_QUEUE_HEAD_MULT_POS) | (zlt ? EP_QUEUE_HEAD_ZLT_SEL : 0) @@ -600,6 +602,8 @@ static int mv_ep_enable(struct usb_ep *_ep, writel(epctrlx, &udc->op_regs->epctrlx[ep->ep_num]); } + spin_unlock_irqrestore(&udc->lock, flags); + return 0; en_done: return -EINVAL; @@ -611,6 +615,7 @@ static int mv_ep_disable(struct usb_ep *_ep) struct mv_ep *ep; struct mv_dqh *dqh; u32 bit_pos, epctrlx, direction; + unsigned long flags; ep = container_of(_ep, struct mv_ep, ep); if ((_ep == NULL) || !ep->desc) @@ -621,6 +626,8 @@ static int mv_ep_disable(struct usb_ep *_ep) /* Get the endpoint queue head address */ dqh = ep->dqh; + spin_lock_irqsave(&udc->lock, flags); + direction = ep_dir(ep); bit_pos = 1 << ((direction == EP_DIR_OUT ? 0 : 16) + ep->ep_num); @@ -639,6 +646,9 @@ static int mv_ep_disable(struct usb_ep *_ep) ep->desc = NULL; ep->stopped = 1; + + spin_unlock_irqrestore(&udc->lock, flags); + return 0; } -- cgit From 615268b05f6c719f5151c351022aa79ab73a0898 Mon Sep 17 00:00:00 2001 From: Neil Zhang Date: Wed, 12 Oct 2011 16:49:32 +0800 Subject: usb: gadget: mv_udc: set unused endpoint with right type According to the comment right above the code, we should use USB_ENDPOINT_XFER_BULK instead. Signed-off-by: Neil Zhang Signed-off-by: Felipe Balbi --- drivers/usb/gadget/mv_udc_core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/mv_udc_core.c b/drivers/usb/gadget/mv_udc_core.c index 501b05a253cc..16bfcb919a72 100644 --- a/drivers/usb/gadget/mv_udc_core.c +++ b/drivers/usb/gadget/mv_udc_core.c @@ -590,14 +590,14 @@ static int mv_ep_enable(struct usb_ep *_ep, */ epctrlx = readl(&udc->op_regs->epctrlx[ep->ep_num]); if ((epctrlx & EPCTRL_RX_ENABLE) == 0) { - epctrlx |= ((desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) + epctrlx |= (USB_ENDPOINT_XFER_BULK << EPCTRL_RX_EP_TYPE_SHIFT); writel(epctrlx, &udc->op_regs->epctrlx[ep->ep_num]); } epctrlx = readl(&udc->op_regs->epctrlx[ep->ep_num]); if ((epctrlx & EPCTRL_TX_ENABLE) == 0) { - epctrlx |= ((desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) + epctrlx |= (USB_ENDPOINT_XFER_BULK << EPCTRL_TX_EP_TYPE_SHIFT); writel(epctrlx, &udc->op_regs->epctrlx[ep->ep_num]); } -- cgit From 0c70840b22d9f3b762f21a28bface1a42c0c5ba2 Mon Sep 17 00:00:00 2001 From: Neil Zhang Date: Wed, 12 Oct 2011 16:49:33 +0800 Subject: usb: gadget: mv_udc: rewrite fifo flush 1: Add parameter check. 2: For controller endpoint, we need to flush in and out directions. 3: delete redundant code, make it more readable. Signed-off-by: Neil Zhang Signed-off-by: Felipe Balbi --- drivers/usb/gadget/mv_udc_core.c | 45 ++++++++++++++++------------------------ 1 file changed, 18 insertions(+), 27 deletions(-) (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/mv_udc_core.c b/drivers/usb/gadget/mv_udc_core.c index 16bfcb919a72..843a479fa25c 100644 --- a/drivers/usb/gadget/mv_udc_core.c +++ b/drivers/usb/gadget/mv_udc_core.c @@ -681,37 +681,28 @@ static void mv_ep_fifo_flush(struct usb_ep *_ep) { struct mv_udc *udc; u32 bit_pos, direction; - struct mv_ep *ep = container_of(_ep, struct mv_ep, ep); + struct mv_ep *ep; unsigned int loops; + if (!_ep) + return; + + ep = container_of(_ep, struct mv_ep, ep); + if (!ep->desc) + return; + udc = ep->udc; direction = ep_dir(ep); - bit_pos = 1 << ((direction == EP_DIR_OUT ? 0 : 16) + ep->ep_num); - /* - * Flushing will halt the pipe - * Write 1 to the Flush register - */ - writel(bit_pos, &udc->op_regs->epflush); - /* Wait until flushing completed */ - loops = LOOPS(FLUSH_TIMEOUT); - while (readl(&udc->op_regs->epflush) & bit_pos) { - /* - * ENDPTFLUSH bit should be cleared to indicate this - * operation is complete - */ - if (loops == 0) { - dev_err(&udc->dev->dev, - "TIMEOUT for ENDPTFLUSH=0x%x, bit_pos=0x%x\n", - (unsigned)readl(&udc->op_regs->epflush), - (unsigned)bit_pos); - return; - } - loops--; - udelay(LOOPS_USEC); - } + if (ep->ep_num == 0) + bit_pos = (1 << 16) | 1; + else if (direction == EP_DIR_OUT) + bit_pos = 1 << ep->ep_num; + else + bit_pos = 1 << (16 + ep->ep_num); + loops = LOOPS(EPSTATUS_TIMEOUT); - while (readl(&udc->op_regs->epstatus) & bit_pos) { + do { unsigned int inter_loops; if (loops == 0) { @@ -726,7 +717,7 @@ static void mv_ep_fifo_flush(struct usb_ep *_ep) /* Wait until flushing completed */ inter_loops = LOOPS(FLUSH_TIMEOUT); - while (readl(&udc->op_regs->epflush) & bit_pos) { + while (readl(&udc->op_regs->epflush)) { /* * ENDPTFLUSH bit should be cleared to indicate this * operation is complete @@ -743,7 +734,7 @@ static void mv_ep_fifo_flush(struct usb_ep *_ep) udelay(LOOPS_USEC); } loops--; - } + } while (readl(&udc->op_regs->epstatus) & bit_pos); } /* queues (submits) an I/O request to an endpoint */ -- cgit From 366162245e619d59c9d615774ab3aa639deb7725 Mon Sep 17 00:00:00 2001 From: Neil Zhang Date: Wed, 12 Oct 2011 16:49:34 +0800 Subject: usb: gadget: mv_udc: correct ep0 state This patch is going to correct the ep0 state, and the unexpected ep0 package warning can be removed. Signed-off-by: Neil Zhang Signed-off-by: Felipe Balbi --- drivers/usb/gadget/mv_udc_core.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/mv_udc_core.c b/drivers/usb/gadget/mv_udc_core.c index 843a479fa25c..f8dc5b3dd796 100644 --- a/drivers/usb/gadget/mv_udc_core.c +++ b/drivers/usb/gadget/mv_udc_core.c @@ -1343,6 +1343,7 @@ udc_prime_status(struct mv_udc *udc, u8 direction, u16 status, bool empty) ep = &udc->eps[0]; udc->ep0_dir = direction; + udc->ep0_state = WAIT_FOR_OUT_STATUS; req = udc->status_req; @@ -1421,6 +1422,8 @@ static void ch9getstatus(struct mv_udc *udc, u8 ep_num, retval = udc_prime_status(udc, EP_DIR_IN, status, false); if (retval) ep0_stall(udc); + else + udc->ep0_state = DATA_STATE_XMIT; } static void ch9clearfeature(struct mv_udc *udc, struct usb_ctrlrequest *setup) @@ -1466,8 +1469,6 @@ static void ch9clearfeature(struct mv_udc *udc, struct usb_ctrlrequest *setup) if (udc_prime_status(udc, EP_DIR_IN, 0, true)) ep0_stall(udc); - else - udc->ep0_state = DATA_STATE_XMIT; out: return; } -- cgit From 046b07ac0458fba8c5ca8d9ee04658c02066ee03 Mon Sep 17 00:00:00 2001 From: Neil Zhang Date: Wed, 12 Oct 2011 16:49:35 +0800 Subject: usb: gadget: mv_udc: add shutdown function for it put the device in idle when shutdown. Signed-off-by: Neil Zhang Signed-off-by: Felipe Balbi --- drivers/usb/gadget/mv_udc_core.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/mv_udc_core.c b/drivers/usb/gadget/mv_udc_core.c index f8dc5b3dd796..ffa6f3097a64 100644 --- a/drivers/usb/gadget/mv_udc_core.c +++ b/drivers/usb/gadget/mv_udc_core.c @@ -2206,9 +2206,21 @@ static const struct dev_pm_ops mv_udc_pm_ops = { }; #endif +static void mv_udc_shutdown(struct platform_device *dev) +{ + struct mv_udc *udc = the_controller; + u32 mode; + + /* reset controller mode to IDLE */ + mode = readl(&udc->op_regs->usbmode); + mode &= ~3; + writel(mode, &udc->op_regs->usbmode); +} + static struct platform_driver udc_driver = { .probe = mv_udc_probe, .remove = __exit_p(mv_udc_remove), + .shutdown = mv_udc_shutdown, .driver = { .owner = THIS_MODULE, .name = "pxa-u2o", -- cgit From daec765da767e4a6a30e1298862b28f2cae9a73f Mon Sep 17 00:00:00 2001 From: Neil Zhang Date: Wed, 12 Oct 2011 16:49:36 +0800 Subject: usb: gadget: mv_udc: fix dtd dma confusion The controller will prime failure sometimes when do the iperf test. Add delay to wait controller release dtd dma before we free it. Then the issue is gone. Signed-off-by: Neil Zhang Signed-off-by: Felipe Balbi --- drivers/usb/gadget/mv_udc_core.c | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/mv_udc_core.c b/drivers/usb/gadget/mv_udc_core.c index ffa6f3097a64..9d960f1f7c7f 100644 --- a/drivers/usb/gadget/mv_udc_core.c +++ b/drivers/usb/gadget/mv_udc_core.c @@ -138,6 +138,7 @@ static int process_ep_req(struct mv_udc *udc, int index, int i, direction; int retval = 0; u32 errors; + u32 bit_pos; curr_dqh = &udc->ep_dqh[index]; direction = index % 2; @@ -155,10 +156,20 @@ static int process_ep_req(struct mv_udc *udc, int index, errors = curr_dtd->size_ioc_sts & DTD_ERROR_MASK; if (!errors) { - remaining_length += + remaining_length = (curr_dtd->size_ioc_sts & DTD_PACKET_SIZE) >> DTD_LENGTH_BIT_POS; actual -= remaining_length; + + if (remaining_length) { + if (direction) { + dev_dbg(&udc->dev->dev, + "TX dTD remains data\n"); + retval = -EPROTO; + break; + } else + break; + } } else { dev_info(&udc->dev->dev, "complete_tr error: ep=%d %s: error = 0x%x\n", @@ -180,6 +191,20 @@ static int process_ep_req(struct mv_udc *udc, int index, if (retval) return retval; + if (direction == EP_DIR_OUT) + bit_pos = 1 << curr_req->ep->ep_num; + else + bit_pos = 1 << (16 + curr_req->ep->ep_num); + + while ((curr_dqh->curr_dtd_ptr == curr_dtd->td_dma)) { + if (curr_dtd->dtd_next == EP_QUEUE_HEAD_NEXT_TERMINATE) { + while (readl(&udc->op_regs->epstatus) & bit_pos) + udelay(1); + break; + } + udelay(1); + } + curr_req->req.actual = actual; return 0; -- cgit From 46e172dfb38c9dad2ea52d8c161834c1f0bd2473 Mon Sep 17 00:00:00 2001 From: Neil Zhang Date: Wed, 12 Oct 2011 16:49:37 +0800 Subject: usb: gadget: mv_udc: use DMA API for status_req's dma address use DMA API for status_req's dma address, it is needed by dtd. Signed-off-by: Neil Zhang Signed-off-by: Felipe Balbi --- drivers/usb/gadget/mv_udc_core.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/mv_udc_core.c b/drivers/usb/gadget/mv_udc_core.c index 9d960f1f7c7f..1f47d03d6871 100644 --- a/drivers/usb/gadget/mv_udc_core.c +++ b/drivers/usb/gadget/mv_udc_core.c @@ -1385,6 +1385,13 @@ udc_prime_status(struct mv_udc *udc, u8 direction, u16 status, bool empty) req->req.complete = NULL; req->dtd_count = 0; + if (req->req.dma == DMA_ADDR_INVALID) { + req->req.dma = dma_map_single(ep->udc->gadget.dev.parent, + req->req.buf, req->req.length, + ep_dir(ep) ? DMA_TO_DEVICE : DMA_FROM_DEVICE); + req->mapped = 1; + } + /* prime the data phase */ if (!req_to_dtd(req)) retval = queue_dtd(ep, req); @@ -2115,7 +2122,7 @@ static int __devinit mv_udc_probe(struct platform_device *dev) /* allocate a small amount of memory to get valid address */ udc->status_req->req.buf = kzalloc(8, GFP_KERNEL); - udc->status_req->req.dma = virt_to_phys(udc->status_req->req.buf); + udc->status_req->req.dma = DMA_ADDR_INVALID; udc->resume_state = USB_STATE_NOTATTACHED; udc->usb_state = USB_STATE_POWERED; -- cgit From fb22cbac8242e92d643e5d5cb81bc6307fa6fc9c Mon Sep 17 00:00:00 2001 From: Neil Zhang Date: Wed, 12 Oct 2011 16:49:38 +0800 Subject: usb: gadget: mv_udc: add test mode support Add test mode support for marvell udc driver. Signed-off-by: Neil Zhang Signed-off-by: Felipe Balbi --- drivers/usb/gadget/mv_udc.h | 2 ++ drivers/usb/gadget/mv_udc_core.c | 71 +++++++++++++++++++++++++++++----------- 2 files changed, 54 insertions(+), 19 deletions(-) (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/mv_udc.h b/drivers/usb/gadget/mv_udc.h index d3d26454b8bb..3e5e6ea7b0fb 100644 --- a/drivers/usb/gadget/mv_udc.h +++ b/drivers/usb/gadget/mv_udc.h @@ -202,6 +202,7 @@ struct mv_udc { unsigned int ep0_dir; unsigned int dev_addr; + unsigned int test_mode; int errors; unsigned softconnect:1, @@ -238,6 +239,7 @@ struct mv_req { struct mv_dtd *dtd, *head, *tail; struct mv_ep *ep; struct list_head queue; + unsigned int test_mode; unsigned dtd_count; unsigned mapped:1; }; diff --git a/drivers/usb/gadget/mv_udc_core.c b/drivers/usb/gadget/mv_udc_core.c index 1f47d03d6871..333b85b96292 100644 --- a/drivers/usb/gadget/mv_udc_core.c +++ b/drivers/usb/gadget/mv_udc_core.c @@ -1204,11 +1204,6 @@ static const struct usb_gadget_ops mv_ops = { .stop = mv_udc_stop, }; -static void mv_udc_testmode(struct mv_udc *udc, u16 index, bool enter) -{ - dev_info(&udc->dev->dev, "Test Mode is not support yet\n"); -} - static int eps_init(struct mv_udc *udc) { struct mv_ep *ep; @@ -1359,6 +1354,31 @@ static int mv_udc_stop(struct usb_gadget_driver *driver) return 0; } +static void mv_set_ptc(struct mv_udc *udc, u32 mode) +{ + u32 portsc; + + portsc = readl(&udc->op_regs->portsc[0]); + portsc |= mode << 16; + writel(portsc, &udc->op_regs->portsc[0]); +} + +static void prime_status_complete(struct usb_ep *ep, struct usb_request *_req) +{ + struct mv_udc *udc = the_controller; + struct mv_req *req = container_of(_req, struct mv_req, req); + unsigned long flags; + + dev_info(&udc->dev->dev, "switch to test mode %d\n", req->test_mode); + + spin_lock_irqsave(&udc->lock, flags); + if (req->test_mode) { + mv_set_ptc(udc, req->test_mode); + req->test_mode = 0; + } + spin_unlock_irqrestore(&udc->lock, flags); +} + static int udc_prime_status(struct mv_udc *udc, u8 direction, u16 status, bool empty) { @@ -1382,7 +1402,12 @@ udc_prime_status(struct mv_udc *udc, u8 direction, u16 status, bool empty) req->ep = ep; req->req.status = -EINPROGRESS; req->req.actual = 0; - req->req.complete = NULL; + if (udc->test_mode) { + req->req.complete = prime_status_complete; + req->test_mode = udc->test_mode; + udc->test_mode = 0; + } else + req->req.complete = NULL; req->dtd_count = 0; if (req->req.dma == DMA_ADDR_INVALID) { @@ -1412,6 +1437,17 @@ out: return retval; } +static void mv_udc_testmode(struct mv_udc *udc, u16 index) +{ + if (index <= TEST_FORCE_EN) { + udc->test_mode = index; + if (udc_prime_status(udc, EP_DIR_IN, 0, true)) + ep0_stall(udc); + } else + dev_err(&udc->dev->dev, + "This test mode(%d) is not supported\n", index); +} + static void ch9setaddress(struct mv_udc *udc, struct usb_ctrlrequest *setup) { udc->dev_addr = (u8)setup->wValue; @@ -1470,9 +1506,6 @@ static void ch9clearfeature(struct mv_udc *udc, struct usb_ctrlrequest *setup) case USB_DEVICE_REMOTE_WAKEUP: udc->remote_wakeup = 0; break; - case USB_DEVICE_TEST_MODE: - mv_udc_testmode(udc, 0, false); - break; default: goto out; } @@ -1518,16 +1551,16 @@ static void ch9setfeature(struct mv_udc *udc, struct usb_ctrlrequest *setup) break; case USB_DEVICE_TEST_MODE: if (setup->wIndex & 0xFF - && udc->gadget.speed != USB_SPEED_HIGH) - goto out; - if (udc->usb_state == USB_STATE_CONFIGURED - || udc->usb_state == USB_STATE_ADDRESS - || udc->usb_state == USB_STATE_DEFAULT) - mv_udc_testmode(udc, - setup->wIndex & 0xFF00, true); - else - goto out; - break; + || udc->gadget.speed != USB_SPEED_HIGH) + ep0_stall(udc); + + if (udc->usb_state != USB_STATE_CONFIGURED + && udc->usb_state != USB_STATE_ADDRESS + && udc->usb_state != USB_STATE_DEFAULT) + ep0_stall(udc); + + mv_udc_testmode(udc, (setup->wIndex >> 8)); + goto out; default: goto out; } -- cgit From 1aec033b955ba358dbf365aa7d0bbd49079c8559 Mon Sep 17 00:00:00 2001 From: Neil Zhang Date: Wed, 12 Oct 2011 16:49:39 +0800 Subject: usb: gadget: mv_udc: add clock gating support This patch is going to support clock gating when vbus detection is posible. Clock and phy will be on only when usb gadget is used(vbus valid). Signed-off-by: Neil Zhang Signed-off-by: Felipe Balbi --- drivers/usb/gadget/mv_udc.h | 7 +- drivers/usb/gadget/mv_udc_core.c | 189 ++++++++++++++++++++++++++++++++++++--- 2 files changed, 185 insertions(+), 11 deletions(-) (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/mv_udc.h b/drivers/usb/gadget/mv_udc.h index 3e5e6ea7b0fb..daa75c12f336 100644 --- a/drivers/usb/gadget/mv_udc.h +++ b/drivers/usb/gadget/mv_udc.h @@ -209,7 +209,12 @@ struct mv_udc { vbus_active:1, remote_wakeup:1, softconnected:1, - force_fs:1; + force_fs:1, + clock_gating:1, + active:1; + + struct work_struct vbus_work; + struct workqueue_struct *qwork; struct mv_usb_platform_data *pdata; diff --git a/drivers/usb/gadget/mv_udc_core.c b/drivers/usb/gadget/mv_udc_core.c index 333b85b96292..046ab122ee88 100644 --- a/drivers/usb/gadget/mv_udc_core.c +++ b/drivers/usb/gadget/mv_udc_core.c @@ -67,6 +67,7 @@ static struct mv_udc *the_controller; int mv_usb_otgsc; static void nuke(struct mv_ep *ep, int status); +static void stop_activity(struct mv_udc *udc, struct usb_gadget_driver *driver); /* for endpoint 0 operations */ static const struct usb_endpoint_descriptor mv_ep0_desc = { @@ -1133,6 +1134,40 @@ static int udc_reset(struct mv_udc *udc) return 0; } +static int mv_udc_enable(struct mv_udc *udc) +{ + int retval; + + if (udc->clock_gating == 0 || udc->active) + return 0; + + dev_dbg(&udc->dev->dev, "enable udc\n"); + udc_clock_enable(udc); + if (udc->pdata->phy_init) { + retval = udc->pdata->phy_init(udc->phy_regs); + if (retval) { + dev_err(&udc->dev->dev, + "init phy error %d\n", retval); + udc_clock_disable(udc); + return retval; + } + } + udc->active = 1; + + return 0; +} + +static void mv_udc_disable(struct mv_udc *udc) +{ + if (udc->clock_gating && udc->active) { + dev_dbg(&udc->dev->dev, "disable udc\n"); + if (udc->pdata->phy_deinit) + udc->pdata->phy_deinit(udc->phy_regs); + udc_clock_disable(udc); + udc->active = 0; + } +} + static int mv_udc_get_frame(struct usb_gadget *gadget) { struct mv_udc *udc; @@ -1168,22 +1203,68 @@ static int mv_udc_wakeup(struct usb_gadget *gadget) return 0; } +static int mv_udc_vbus_session(struct usb_gadget *gadget, int is_active) +{ + struct mv_udc *udc; + unsigned long flags; + int retval = 0; + + udc = container_of(gadget, struct mv_udc, gadget); + spin_lock_irqsave(&udc->lock, flags); + + dev_dbg(&udc->dev->dev, "%s: softconnect %d, vbus_active %d\n", + __func__, udc->softconnect, udc->vbus_active); + + udc->vbus_active = (is_active != 0); + if (udc->driver && udc->softconnect && udc->vbus_active) { + retval = mv_udc_enable(udc); + if (retval == 0) { + /* Clock is disabled, need re-init registers */ + udc_reset(udc); + ep0_reset(udc); + udc_start(udc); + } + } else if (udc->driver && udc->softconnect) { + /* stop all the transfer in queue*/ + stop_activity(udc, udc->driver); + udc_stop(udc); + mv_udc_disable(udc); + } + + spin_unlock_irqrestore(&udc->lock, flags); + return retval; +} + static int mv_udc_pullup(struct usb_gadget *gadget, int is_on) { struct mv_udc *udc; unsigned long flags; + int retval = 0; udc = container_of(gadget, struct mv_udc, gadget); spin_lock_irqsave(&udc->lock, flags); + dev_dbg(&udc->dev->dev, "%s: softconnect %d, vbus_active %d\n", + __func__, udc->softconnect, udc->vbus_active); + udc->softconnect = (is_on != 0); - if (udc->driver && udc->softconnect) - udc_start(udc); - else + if (udc->driver && udc->softconnect && udc->vbus_active) { + retval = mv_udc_enable(udc); + if (retval == 0) { + /* Clock is disabled, need re-init registers */ + udc_reset(udc); + ep0_reset(udc); + udc_start(udc); + } + } else if (udc->driver && udc->vbus_active) { + /* stop all the transfer in queue*/ + stop_activity(udc, udc->driver); udc_stop(udc); + mv_udc_disable(udc); + } spin_unlock_irqrestore(&udc->lock, flags); - return 0; + return retval; } static int mv_udc_start(struct usb_gadget_driver *driver, @@ -1198,6 +1279,9 @@ static const struct usb_gadget_ops mv_ops = { /* tries to wake up the host connected to this gadget */ .wakeup = mv_udc_wakeup, + /* notify controller that VBUS is powered or not */ + .vbus_session = mv_udc_vbus_session, + /* D+ pullup, software-controlled connect/disconnect to USB host */ .pullup = mv_udc_pullup, .start = mv_udc_start, @@ -1310,7 +1394,7 @@ static int mv_udc_start(struct usb_gadget_driver *driver, udc->usb_state = USB_STATE_ATTACHED; udc->ep0_state = WAIT_FOR_SETUP; - udc->ep0_dir = USB_DIR_OUT; + udc->ep0_dir = EP_DIR_OUT; spin_unlock_irqrestore(&udc->lock, flags); @@ -1322,9 +1406,13 @@ static int mv_udc_start(struct usb_gadget_driver *driver, udc->gadget.dev.driver = NULL; return retval; } - udc_reset(udc); - ep0_reset(udc); - udc_start(udc); + + /* pullup is always on */ + mv_udc_pullup(&udc->gadget, 1); + + /* When boot with cable attached, there will be no vbus irq occurred */ + if (udc->qwork) + queue_work(udc->qwork, &udc->vbus_work); return 0; } @@ -1337,13 +1425,16 @@ static int mv_udc_stop(struct usb_gadget_driver *driver) if (!udc) return -ENODEV; - udc_stop(udc); - spin_lock_irqsave(&udc->lock, flags); + mv_udc_enable(udc); + udc_stop(udc); + /* stop all usb activities */ udc->gadget.speed = USB_SPEED_UNKNOWN; stop_activity(udc, driver); + mv_udc_disable(udc); + spin_unlock_irqrestore(&udc->lock, flags); /* unbind gadget driver */ @@ -1969,6 +2060,35 @@ static irqreturn_t mv_udc_irq(int irq, void *dev) return IRQ_HANDLED; } +static irqreturn_t mv_udc_vbus_irq(int irq, void *dev) +{ + struct mv_udc *udc = (struct mv_udc *)dev; + + /* polling VBUS and init phy may cause too much time*/ + if (udc->qwork) + queue_work(udc->qwork, &udc->vbus_work); + + return IRQ_HANDLED; +} + +static void mv_udc_vbus_work(struct work_struct *work) +{ + struct mv_udc *udc; + unsigned int vbus; + + udc = container_of(work, struct mv_udc, vbus_work); + if (!udc->pdata->vbus) + return; + + vbus = udc->pdata->vbus->poll(); + dev_info(&udc->dev->dev, "vbus is %d\n", vbus); + + if (vbus == VBUS_HIGH) + mv_udc_vbus_session(&udc->gadget, 1); + else if (vbus == VBUS_LOW) + mv_udc_vbus_session(&udc->gadget, 0); +} + /* release device structure */ static void gadget_release(struct device *_dev) { @@ -1984,6 +2104,14 @@ static int __devexit mv_udc_remove(struct platform_device *dev) usb_del_gadget_udc(&udc->gadget); + if (udc->qwork) { + flush_workqueue(udc->qwork); + destroy_workqueue(udc->qwork); + } + + if (udc->pdata && udc->pdata->vbus && udc->clock_gating) + free_irq(udc->pdata->vbus->irq, &dev->dev); + /* free memory allocated in probe */ if (udc->dtd_pool) dma_pool_destroy(udc->dtd_pool); @@ -1997,6 +2125,8 @@ static int __devexit mv_udc_remove(struct platform_device *dev) if (udc->irq) free_irq(udc->irq, &dev->dev); + mv_udc_disable(udc); + if (udc->cap_regs) iounmap(udc->cap_regs); udc->cap_regs = NULL; @@ -2197,13 +2327,52 @@ static int __devinit mv_udc_probe(struct platform_device *dev) eps_init(udc); + /* VBUS detect: we can disable/enable clock on demand.*/ + if (pdata->vbus) { + udc->clock_gating = 1; + retval = request_threaded_irq(pdata->vbus->irq, NULL, + mv_udc_vbus_irq, IRQF_ONESHOT, "vbus", udc); + if (retval) { + dev_info(&dev->dev, + "Can not request irq for VBUS, " + "disable clock gating\n"); + udc->clock_gating = 0; + } + + udc->qwork = create_singlethread_workqueue("mv_udc_queue"); + if (!udc->qwork) { + dev_err(&dev->dev, "cannot create workqueue\n"); + retval = -ENOMEM; + goto err_unregister; + } + + INIT_WORK(&udc->vbus_work, mv_udc_vbus_work); + } + + /* + * When clock gating is supported, we can disable clk and phy. + * If not, it means that VBUS detection is not supported, we + * have to enable vbus active all the time to let controller work. + */ + if (udc->clock_gating) { + if (udc->pdata->phy_deinit) + udc->pdata->phy_deinit(udc->phy_regs); + udc_clock_disable(udc); + } else + udc->vbus_active = 1; + retval = usb_add_gadget_udc(&dev->dev, &udc->gadget); if (retval) goto err_unregister; + dev_info(&dev->dev, "successful probe UDC device %s clock gating.\n", + udc->clock_gating ? "with" : "without"); + return 0; err_unregister: + if (udc->pdata && udc->pdata->vbus && udc->clock_gating) + free_irq(pdata->vbus->irq, &dev->dev); device_unregister(&udc->gadget.dev); err_free_irq: free_irq(udc->irq, &dev->dev); -- cgit From 431879a762277ddb9df959bba80216f3ef3d8e17 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Thu, 13 Oct 2011 20:27:54 +0300 Subject: usb: gadget: mv_udc: fix compile warning | drivers/usb/gadget/mv_udc_core.c: In function 'handle_setup_packet': | drivers/usb/gadget/mv_udc_core.c:1556:6: warning: 'status' may be \ used uninitialized in this function Signed-off-by: Felipe Balbi --- drivers/usb/gadget/mv_udc_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/mv_udc_core.c b/drivers/usb/gadget/mv_udc_core.c index 046ab122ee88..fbed5d08beee 100644 --- a/drivers/usb/gadget/mv_udc_core.c +++ b/drivers/usb/gadget/mv_udc_core.c @@ -1553,7 +1553,7 @@ static void ch9setaddress(struct mv_udc *udc, struct usb_ctrlrequest *setup) static void ch9getstatus(struct mv_udc *udc, u8 ep_num, struct usb_ctrlrequest *setup) { - u16 status; + u16 status = 0; int retval; if ((setup->bRequestType & (USB_DIR_IN | USB_TYPE_MASK)) -- cgit From fa3ae0c158c70e6cf227b3a194659ee7fed8c588 Mon Sep 17 00:00:00 2001 From: Klaus Schwarzkopf Date: Mon, 10 Oct 2011 10:32:23 +0200 Subject: usb: gadget: add new usb gadget for ACM and mass storage This driver provides two functions in one configuration: a mass storage, and a ACM (serial port) link. Heavily based on multi.c and cdc2.c Signed-off-by: Klaus Schwarzkopf Signed-off-by: Felipe Balbi --- drivers/usb/gadget/Kconfig | 10 ++ drivers/usb/gadget/Makefile | 2 + drivers/usb/gadget/acm_ms.c | 256 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 268 insertions(+) create mode 100644 drivers/usb/gadget/acm_ms.c (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index a60b472a0b39..b21cd376c11a 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -873,6 +873,16 @@ config USB_G_NOKIA It's only really useful for N900 hardware. If you're building a kernel for N900, say Y or M here. If unsure, say N. +config USB_G_ACM_MS + tristate "CDC Composite Device (ACM and mass storage)" + depends on BLOCK + help + This driver provides two functions in one configuration: + a mass storage, and a CDC ACM (serial port) link. + + Say "y" to link the driver statically, or "m" to build a + dynamically linked module called "g_acm_ms". + config USB_G_MULTI tristate "Multifunction Composite Gadget (EXPERIMENTAL)" depends on BLOCK && NET diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile index c36da63009db..b54ac6190890 100644 --- a/drivers/usb/gadget/Makefile +++ b/drivers/usb/gadget/Makefile @@ -51,6 +51,7 @@ g_dbgp-y := dbgp.o g_nokia-y := nokia.o g_webcam-y := webcam.o g_ncm-y := ncm.o +g_acm_ms-y := acm_ms.o obj-$(CONFIG_USB_ZERO) += g_zero.o obj-$(CONFIG_USB_AUDIO) += g_audio.o @@ -69,3 +70,4 @@ obj-$(CONFIG_USB_G_MULTI) += g_multi.o obj-$(CONFIG_USB_G_NOKIA) += g_nokia.o obj-$(CONFIG_USB_G_WEBCAM) += g_webcam.o obj-$(CONFIG_USB_G_NCM) += g_ncm.o +obj-$(CONFIG_USB_G_ACM_MS) += g_acm_ms.o diff --git a/drivers/usb/gadget/acm_ms.c b/drivers/usb/gadget/acm_ms.c new file mode 100644 index 000000000000..fdb7aec3bd0c --- /dev/null +++ b/drivers/usb/gadget/acm_ms.c @@ -0,0 +1,256 @@ +/* + * acm_ms.c -- Composite driver, with ACM and mass storage support + * + * Copyright (C) 2008 David Brownell + * Copyright (C) 2008 Nokia Corporation + * Author: David Brownell + * Modified: Klaus Schwarzkopf + * + * Heavily based on multi.c and cdc2.c + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include +#include + +#include "u_serial.h" + +#define DRIVER_DESC "Composite Gadget (ACM + MS)" +#define DRIVER_VERSION "2011/10/10" + +/*-------------------------------------------------------------------------*/ + +/* + * DO NOT REUSE THESE IDs with a protocol-incompatible driver!! Ever!! + * Instead: allocate your own, using normal USB-IF procedures. + */ +#define ACM_MS_VENDOR_NUM 0x1d6b /* Linux Foundation */ +#define ACM_MS_PRODUCT_NUM 0x0106 /* Composite Gadget: ACM + MS*/ + +/*-------------------------------------------------------------------------*/ + +/* + * Kbuild is not very cooperative with respect to linking separately + * compiled library objects into one module. So for now we won't use + * separate compilation ... ensuring init/exit sections work to shrink + * the runtime footprint, and giving us at least some parts of what + * a "gcc --combine ... part1.c part2.c part3.c ... " build would. + */ + +#include "composite.c" +#include "usbstring.c" +#include "config.c" +#include "epautoconf.c" +#include "u_serial.c" +#include "f_acm.c" +#include "f_mass_storage.c" + +/*-------------------------------------------------------------------------*/ + +static struct usb_device_descriptor device_desc = { + .bLength = sizeof device_desc, + .bDescriptorType = USB_DT_DEVICE, + + .bcdUSB = cpu_to_le16(0x0200), + + .bDeviceClass = USB_CLASS_MISC /* 0xEF */, + .bDeviceSubClass = 2, + .bDeviceProtocol = 1, + + /* .bMaxPacketSize0 = f(hardware) */ + + /* Vendor and product id can be overridden by module parameters. */ + .idVendor = cpu_to_le16(ACM_MS_VENDOR_NUM), + .idProduct = cpu_to_le16(ACM_MS_PRODUCT_NUM), + /* .bcdDevice = f(hardware) */ + /* .iManufacturer = DYNAMIC */ + /* .iProduct = DYNAMIC */ + /* NO SERIAL NUMBER */ + /*.bNumConfigurations = DYNAMIC*/ +}; + +static struct usb_otg_descriptor otg_descriptor = { + .bLength = sizeof otg_descriptor, + .bDescriptorType = USB_DT_OTG, + + /* + * REVISIT SRP-only hardware is possible, although + * it would not be called "OTG" ... + */ + .bmAttributes = USB_OTG_SRP | USB_OTG_HNP, +}; + +static const struct usb_descriptor_header *otg_desc[] = { + (struct usb_descriptor_header *) &otg_descriptor, + NULL, +}; + + +/* string IDs are assigned dynamically */ + +#define STRING_MANUFACTURER_IDX 0 +#define STRING_PRODUCT_IDX 1 + +static char manufacturer[50]; + +static struct usb_string strings_dev[] = { + [STRING_MANUFACTURER_IDX].s = manufacturer, + [STRING_PRODUCT_IDX].s = DRIVER_DESC, + { } /* end of list */ +}; + +static struct usb_gadget_strings stringtab_dev = { + .language = 0x0409, /* en-us */ + .strings = strings_dev, +}; + +static struct usb_gadget_strings *dev_strings[] = { + &stringtab_dev, + NULL, +}; + +/****************************** Configurations ******************************/ + +static struct fsg_module_parameters fsg_mod_data = { .stall = 1 }; +FSG_MODULE_PARAMETERS(/* no prefix */, fsg_mod_data); + +static struct fsg_common fsg_common; + +/*-------------------------------------------------------------------------*/ + +/* + * We _always_ have both ACM and mass storage functions. + */ +static int __init acm_ms_do_config(struct usb_configuration *c) +{ + int status; + + if (gadget_is_otg(c->cdev->gadget)) { + c->descriptors = otg_desc; + c->bmAttributes |= USB_CONFIG_ATT_WAKEUP; + } + + + status = acm_bind_config(c, 0); + if (status < 0) + return status; + + status = fsg_bind_config(c->cdev, c, &fsg_common); + if (status < 0) + return status; + + return 0; +} + +static struct usb_configuration acm_ms_config_driver = { + .label = DRIVER_DESC, + .bConfigurationValue = 1, + /* .iConfiguration = DYNAMIC */ + .bmAttributes = USB_CONFIG_ATT_SELFPOWER, +}; + +/*-------------------------------------------------------------------------*/ + +static int __init acm_ms_bind(struct usb_composite_dev *cdev) +{ + int gcnum; + struct usb_gadget *gadget = cdev->gadget; + int status; + void *retp; + + /* set up serial link layer */ + status = gserial_setup(cdev->gadget, 1); + if (status < 0) + return status; + + /* set up mass storage function */ + retp = fsg_common_from_params(&fsg_common, cdev, &fsg_mod_data); + if (IS_ERR(retp)) { + status = PTR_ERR(retp); + goto fail0; + } + + /* set bcdDevice */ + gcnum = usb_gadget_controller_number(gadget); + if (gcnum >= 0) { + device_desc.bcdDevice = cpu_to_le16(0x0300 | gcnum); + } else { + WARNING(cdev, "controller '%s' not recognized; trying %s\n", + gadget->name, + acm_ms_config_driver.label); + device_desc.bcdDevice = + cpu_to_le16(0x0300 | 0x0099); + } + + /* + * Allocate string descriptor numbers ... note that string + * contents can be overridden by the composite_dev glue. + */ + + /* device descriptor strings: manufacturer, product */ + snprintf(manufacturer, sizeof manufacturer, "%s %s with %s", + init_utsname()->sysname, init_utsname()->release, + gadget->name); + status = usb_string_id(cdev); + if (status < 0) + goto fail1; + strings_dev[STRING_MANUFACTURER_IDX].id = status; + device_desc.iManufacturer = status; + + status = usb_string_id(cdev); + if (status < 0) + goto fail1; + strings_dev[STRING_PRODUCT_IDX].id = status; + device_desc.iProduct = status; + + /* register our configuration */ + status = usb_add_config(cdev, &acm_ms_config_driver, acm_ms_do_config); + if (status < 0) + goto fail1; + + dev_info(&gadget->dev, "%s, version: " DRIVER_VERSION "\n", + DRIVER_DESC); + fsg_common_put(&fsg_common); + return 0; + + /* error recovery */ +fail1: + fsg_common_put(&fsg_common); +fail0: + gserial_cleanup(); + return status; +} + +static int __exit acm_ms_unbind(struct usb_composite_dev *cdev) +{ + gserial_cleanup(); + + return 0; +} + +static struct usb_composite_driver acm_ms_driver = { + .name = "g_acm_ms", + .dev = &device_desc, + .strings = dev_strings, + .unbind = __exit_p(acm_ms_unbind), +}; + +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_AUTHOR("Klaus Schwarzkopf "); +MODULE_LICENSE("GPL v2"); + +static int __init init(void) +{ + return usb_composite_probe(&acm_ms_driver, acm_ms_bind); +} +module_init(init); + +static void __exit cleanup(void) +{ + usb_composite_unregister(&acm_ms_driver); +} +module_exit(cleanup); -- cgit From 91960c2ef095c4b0744349e80a933921cbdcfd6e Mon Sep 17 00:00:00 2001 From: Yauheni Kaliuta Date: Thu, 13 Oct 2011 14:19:05 +0300 Subject: usb: gadget: file_storage: fix race on unloading There is a race, reproduced rarely if you unload the module when host finishes mass storage device initialization (reading partition table and so on): fsg_unbind() code first closes lun files then waits for worker thread to finish its work, as the result the thread may operate on already closed device with an oops and backtrace: [ 484.937225] [] (touch_atime+0x4/0x140) from [] (generic_file_aio_read+0x678/0x6f0) [ 484.946563] [] (generic_file_aio_read+0x678/0x6f0) from [] (do_sync_read+0xb0/0xf4) [ 484.955963] [] (do_sync_read+0xb0/0xf4) from [] (vfs_read+0xac/0x144) [ 484.964172] [] (vfs_read+0xac/0x144) from [] (fsg_setup+0x7f4/0x900 [g_file_storage]) [ 484.973785] [] (fsg_setup+0x7f4/0x900 [g_file_storage]) from [] (fsg_main_thread+0x85c/0x175c [g_file_storage]) [ 484.985626] [] (fsg_main_thread+0x85c/0x175c [g_file_storage]) from [] (kthread+0x7c/0x84) [ 484.995666] [] (kthread+0x7c/0x84) from [] (kernel_thread_exit+0x0/0x8) [ 485.004028] Code: eaffffd0 e28dd008 e8bd8df0 e92d40f7 (e591400c) Change the order in unbind: wait for the thread first, then close the files. Signed-off-by: Yauheni Kaliuta Acked-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/file_storage.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c index 5779549d7dc6..3ac4f51cd0bb 100644 --- a/drivers/usb/gadget/file_storage.c +++ b/drivers/usb/gadget/file_storage.c @@ -3153,6 +3153,15 @@ static void /* __init_or_exit */ fsg_unbind(struct usb_gadget *gadget) 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]; @@ -3166,15 +3175,6 @@ static void /* __init_or_exit */ fsg_unbind(struct usb_gadget *gadget) } } - /* 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); - } - /* Free the data buffers */ for (i = 0; i < fsg_num_buffers; ++i) kfree(fsg->buffhds[i].buf); -- cgit From 0889551267e7b6b4d27dc9f726f3d0cb0d976105 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Tue, 18 Oct 2011 09:24:36 +0300 Subject: USB: gadget: midi: fix range check in f_midi_out_open() ! has higher precedence than >= and since neither 0 nor 1 are greater than 8 the condition is always false. Signed-off-by: Dan Carpenter Acked-by: Daniel Mack Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/f_midi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/f_midi.c b/drivers/usb/gadget/f_midi.c index 44858dc074d3..ef1bc7a174ef 100644 --- a/drivers/usb/gadget/f_midi.c +++ b/drivers/usb/gadget/f_midi.c @@ -644,7 +644,7 @@ static int f_midi_out_open(struct snd_rawmidi_substream *substream) { struct f_midi *midi = substream->rmidi->private_data; - if (!substream->number >= MAX_PORTS) + if (substream->number >= MAX_PORTS) return -EINVAL; VDBG(midi, "%s()\n", __func__); -- cgit From 0f8fd43c42f2cc249943be76a4db0d058c16b6dc Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Tue, 18 Oct 2011 09:25:34 +0300 Subject: USB: gadget: midi: memory leak in f_midi_bind_config() There is a small memory leak on the error paths. Signed-off-by: Dan Carpenter Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/f_midi.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/f_midi.c b/drivers/usb/gadget/f_midi.c index ef1bc7a174ef..67b222908cf9 100644 --- a/drivers/usb/gadget/f_midi.c +++ b/drivers/usb/gadget/f_midi.c @@ -951,7 +951,7 @@ int __init f_midi_bind_config(struct usb_configuration *c, struct gmidi_in_port *port = kzalloc(sizeof(*port), GFP_KERNEL); if (!port) { status = -ENOMEM; - goto fail; + goto setup_fail; } port->midi = midi; @@ -989,6 +989,8 @@ int __init f_midi_bind_config(struct usb_configuration *c, return 0; setup_fail: + for (--i; i >= 0; i--) + kfree(midi->in_port[i]); kfree(midi); fail: return status; -- cgit