From 680681747ff933fdedfbf11bd03c369e5b14085c Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Thu, 26 May 2011 00:02:56 -0700 Subject: usb/gadget: (fusb300_udc) Remove unused function fusb300_ep0_complete fusb300_ep0_complete() is an empty function, not called from anywhere, and causes the following build warning. fusb300_udc.c:983: warning: fusb300_ep0_complete defined but not used Remove it. Signed-off-by: Guenter Roeck Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/fusb300_udc.c | 5 ----- 1 file changed, 5 deletions(-) (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/fusb300_udc.c b/drivers/usb/gadget/fusb300_udc.c index 763d462454b..b82a1149145 100644 --- a/drivers/usb/gadget/fusb300_udc.c +++ b/drivers/usb/gadget/fusb300_udc.c @@ -980,11 +980,6 @@ static void set_address(struct fusb300 *fusb300, struct usb_ctrlrequest *ctrl) } \ } while (0) -static void fusb300_ep0_complete(struct usb_ep *ep, - struct usb_request *req) -{ -} - static int setup_packet(struct fusb300 *fusb300, struct usb_ctrlrequest *ctrl) { u8 *p = (u8 *)ctrl; -- cgit v1.2.3-70-g09d2 From ceb80363b2ec1091dffd78064771e3d4679f69c7 Mon Sep 17 00:00:00 2001 From: Seth Levy Date: Mon, 6 Jun 2011 19:42:44 -0400 Subject: USB: net2272: driver for PLX NET2272 USB device controller This is based on the last release from PLX: http://www.plxtech.com/files/products/net2000/software/selectiontool/RE061204-net2272-linux2.6.18.tgz I've managed to contact them and they've confirmed that this driver was wholly written by PLX (Seth Levy). While they have no problem with it being merged (and they've already licensed it as GPL), they don't have any interest in doing so themselves as this is an old part for them. ADI has long had an add-on card which has this part on it, so we've been keeping it up-to-date out of tree. But now that PLX has confirmed the source of the driver, we can can take the next step of cleaning it up and getting it merged. So here we are! I've done quite a large clean up of the driver and attempted to address all the common issues. Hopefully in the process, I haven't broken anything. While it seems to still work with the board that I have access to, it is not a PCI variant. So I have not tested any of the PCI logic myself (beyond clean compile). Perhaps someone who actually has a card and cares can do so. I'll try to address further feedback, but don't expect miracles. I'm not really familiar with the part itself, just the platform glue. Signed-off-by: Seth Levy Signed-off-by: Ash Aziz Signed-off-by: Roy Huang Signed-off-by: Michael Hennerich Signed-off-by: Mike Frysinger Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/Kconfig | 29 + drivers/usb/gadget/Makefile | 1 + drivers/usb/gadget/gadget_chips.h | 8 + drivers/usb/gadget/net2272.c | 2718 +++++++++++++++++++++++++++++++++++++ drivers/usb/gadget/net2272.h | 601 ++++++++ 5 files changed, 3357 insertions(+) create mode 100644 drivers/usb/gadget/net2272.c create mode 100644 drivers/usb/gadget/net2272.h (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index 58456d1aec2..be44545d680 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -480,6 +480,35 @@ config USB_CI13XXX_PCI default USB_GADGET select USB_GADGET_SELECTED +config USB_GADGET_NET2272 + boolean "PLX NET2272" + select USB_GADGET_DUALSPEED + help + PLX NET2272 is a USB peripheral controller which supports + both full and high speed USB 2.0 data transfers. + + It has three configurable endpoints, as well as endpoint zero + (for control transfer). + Say "y" to link the driver statically, or "m" to build a + dynamically linked module called "net2272" and force all + gadget drivers to also be dynamically linked. + +config USB_GADGET_NET2272_DMA + boolean "Support external DMA controller" + depends on USB_GADGET_NET2272 + help + The NET2272 part can optionally support an external DMA + controller, but your board has to have support in the + driver itself. + + If unsure, say "N" here. The driver works fine in PIO mode. + +config USB_NET2272 + tristate + depends on USB_GADGET_NET2272 + default USB_GADGET + select USB_GADGET_SELECTED + config USB_GADGET_NET2280 boolean "NetChip 228x" depends on PCI diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile index 4fe92b18a05..345261738b1 100644 --- a/drivers/usb/gadget/Makefile +++ b/drivers/usb/gadget/Makefile @@ -4,6 +4,7 @@ ccflags-$(CONFIG_USB_GADGET_DEBUG) := -DDEBUG obj-$(CONFIG_USB_DUMMY_HCD) += dummy_hcd.o +obj-$(CONFIG_USB_NET2272) += net2272.o obj-$(CONFIG_USB_NET2280) += net2280.o obj-$(CONFIG_USB_AMD5536UDC) += amd5536udc.o obj-$(CONFIG_USB_PXA25X) += pxa25x_udc.o diff --git a/drivers/usb/gadget/gadget_chips.h b/drivers/usb/gadget/gadget_chips.h index bcdac7c73e8..13c2f9e9440 100644 --- a/drivers/usb/gadget/gadget_chips.h +++ b/drivers/usb/gadget/gadget_chips.h @@ -15,6 +15,12 @@ #ifndef __GADGET_CHIPS_H #define __GADGET_CHIPS_H +#ifdef CONFIG_USB_GADGET_NET2272 +#define gadget_is_net2272(g) !strcmp("net2272", (g)->name) +#else +#define gadget_is_net2272(g) 0 +#endif + #ifdef CONFIG_USB_GADGET_NET2280 #define gadget_is_net2280(g) !strcmp("net2280", (g)->name) #else @@ -223,6 +229,8 @@ static inline int usb_gadget_controller_number(struct usb_gadget *gadget) return 0x29; else if (gadget_is_s3c_hsudc(gadget)) return 0x30; + else if (gadget_is_net2272(gadget)) + return 0x31; return -ENOENT; } diff --git a/drivers/usb/gadget/net2272.c b/drivers/usb/gadget/net2272.c new file mode 100644 index 00000000000..29151c44f47 --- /dev/null +++ b/drivers/usb/gadget/net2272.c @@ -0,0 +1,2718 @@ +/* + * Driver for PLX NET2272 USB device controller + * + * Copyright (C) 2005-2006 PLX Technology, Inc. + * Copyright (C) 2006-2011 Analog Devices, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "net2272.h" + +#define DRIVER_DESC "PLX NET2272 USB Peripheral Controller" + +static const char driver_name[] = "net2272"; +static const char driver_vers[] = "2006 October 17/mainline"; +static const char driver_desc[] = DRIVER_DESC; + +static const char ep0name[] = "ep0"; +static const char * const ep_name[] = { + ep0name, + "ep-a", "ep-b", "ep-c", +}; + +#define DMA_ADDR_INVALID (~(dma_addr_t)0) +#ifdef CONFIG_USB_GADGET_NET2272_DMA +/* + * use_dma: the NET2272 can use an external DMA controller. + * Note that since there is no generic DMA api, some functions, + * notably request_dma, start_dma, and cancel_dma will need to be + * modified for your platform's particular dma controller. + * + * If use_dma is disabled, pio will be used instead. + */ +static int use_dma = 0; +module_param(use_dma, bool, 0644); + +/* + * dma_ep: selects the endpoint for use with dma (1=ep-a, 2=ep-b) + * The NET2272 can only use dma for a single endpoint at a time. + * At some point this could be modified to allow either endpoint + * to take control of dma as it becomes available. + * + * Note that DMA should not be used on OUT endpoints unless it can + * be guaranteed that no short packets will arrive on an IN endpoint + * while the DMA operation is pending. Otherwise the OUT DMA will + * terminate prematurely (See NET2272 Errata 630-0213-0101) + */ +static ushort dma_ep = 1; +module_param(dma_ep, ushort, 0644); + +/* + * dma_mode: net2272 dma mode setting (see LOCCTL1 definiton): + * mode 0 == Slow DREQ mode + * mode 1 == Fast DREQ mode + * mode 2 == Burst mode + */ +static ushort dma_mode = 2; +module_param(dma_mode, ushort, 0644); +#else +#define use_dma 0 +#define dma_ep 1 +#define dma_mode 2 +#endif + +/* + * fifo_mode: net2272 buffer configuration: + * mode 0 == ep-{a,b,c} 512db each + * mode 1 == ep-a 1k, ep-{b,c} 512db + * mode 2 == ep-a 1k, ep-b 1k, ep-c 512db + * mode 3 == ep-a 1k, ep-b disabled, ep-c 512db + */ +static ushort fifo_mode = 0; +module_param(fifo_mode, ushort, 0644); + +/* + * enable_suspend: When enabled, the driver will respond to + * USB suspend requests by powering down the NET2272. Otherwise, + * USB suspend requests will be ignored. This is acceptible for + * self-powered devices. For bus powered devices set this to 1. + */ +static ushort enable_suspend = 0; +module_param(enable_suspend, ushort, 0644); + +static void assert_out_naking(struct net2272_ep *ep, const char *where) +{ + u8 tmp; + +#ifndef DEBUG + return; +#endif + + tmp = net2272_ep_read(ep, EP_STAT0); + if ((tmp & (1 << NAK_OUT_PACKETS)) == 0) { + dev_dbg(ep->dev->dev, "%s %s %02x !NAK\n", + ep->ep.name, where, tmp); + net2272_ep_write(ep, EP_RSPSET, 1 << ALT_NAK_OUT_PACKETS); + } +} +#define ASSERT_OUT_NAKING(ep) assert_out_naking(ep, __func__) + +static void stop_out_naking(struct net2272_ep *ep) +{ + u8 tmp = net2272_ep_read(ep, EP_STAT0); + + if ((tmp & (1 << NAK_OUT_PACKETS)) != 0) + net2272_ep_write(ep, EP_RSPCLR, 1 << ALT_NAK_OUT_PACKETS); +} + +#define PIPEDIR(bAddress) (usb_pipein(bAddress) ? "in" : "out") + +static char *type_string(u8 bmAttributes) +{ + switch ((bmAttributes) & USB_ENDPOINT_XFERTYPE_MASK) { + case USB_ENDPOINT_XFER_BULK: return "bulk"; + case USB_ENDPOINT_XFER_ISOC: return "iso"; + case USB_ENDPOINT_XFER_INT: return "intr"; + default: return "control"; + } +} + +static char *buf_state_string(unsigned state) +{ + switch (state) { + case BUFF_FREE: return "free"; + case BUFF_VALID: return "valid"; + case BUFF_LCL: return "local"; + case BUFF_USB: return "usb"; + default: return "unknown"; + } +} + +static char *dma_mode_string(void) +{ + if (!use_dma) + return "PIO"; + switch (dma_mode) { + case 0: return "SLOW DREQ"; + case 1: return "FAST DREQ"; + case 2: return "BURST"; + default: return "invalid"; + } +} + +static void net2272_dequeue_all(struct net2272_ep *); +static int net2272_kick_dma(struct net2272_ep *, struct net2272_request *); +static int net2272_fifo_status(struct usb_ep *); + +static struct usb_ep_ops net2272_ep_ops; + +/*---------------------------------------------------------------------------*/ + +static int +net2272_enable(struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc) +{ + struct net2272 *dev; + struct net2272_ep *ep; + u32 max; + u8 tmp; + unsigned long flags; + + ep = container_of(_ep, struct net2272_ep, ep); + if (!_ep || !desc || ep->desc || _ep->name == ep0name + || desc->bDescriptorType != USB_DT_ENDPOINT) + return -EINVAL; + dev = ep->dev; + if (!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN) + return -ESHUTDOWN; + + max = le16_to_cpu(desc->wMaxPacketSize) & 0x1fff; + + spin_lock_irqsave(&dev->lock, flags); + _ep->maxpacket = max & 0x7fff; + ep->desc = desc; + + /* net2272_ep_reset() has already been called */ + ep->stopped = 0; + ep->wedged = 0; + + /* set speed-dependent max packet */ + net2272_ep_write(ep, EP_MAXPKT0, max & 0xff); + net2272_ep_write(ep, EP_MAXPKT1, (max & 0xff00) >> 8); + + /* set type, direction, address; reset fifo counters */ + net2272_ep_write(ep, EP_STAT1, 1 << BUFFER_FLUSH); + tmp = usb_endpoint_type(desc); + if (usb_endpoint_xfer_bulk(desc)) { + /* catch some particularly blatant driver bugs */ + if ((dev->gadget.speed == USB_SPEED_HIGH && max != 512) || + (dev->gadget.speed == USB_SPEED_FULL && max > 64)) { + spin_unlock_irqrestore(&dev->lock, flags); + return -ERANGE; + } + } + ep->is_iso = usb_endpoint_xfer_isoc(desc) ? 1 : 0; + tmp <<= ENDPOINT_TYPE; + tmp |= ((desc->bEndpointAddress & 0x0f) << ENDPOINT_NUMBER); + tmp |= usb_endpoint_dir_in(desc) << ENDPOINT_DIRECTION; + tmp |= (1 << ENDPOINT_ENABLE); + + /* for OUT transfers, block the rx fifo until a read is posted */ + ep->is_in = usb_endpoint_dir_in(desc); + if (!ep->is_in) + net2272_ep_write(ep, EP_RSPSET, 1 << ALT_NAK_OUT_PACKETS); + + net2272_ep_write(ep, EP_CFG, tmp); + + /* enable irqs */ + tmp = (1 << ep->num) | net2272_read(dev, IRQENB0); + net2272_write(dev, IRQENB0, tmp); + + tmp = (1 << DATA_PACKET_RECEIVED_INTERRUPT_ENABLE) + | (1 << DATA_PACKET_TRANSMITTED_INTERRUPT_ENABLE) + | net2272_ep_read(ep, EP_IRQENB); + net2272_ep_write(ep, EP_IRQENB, tmp); + + tmp = desc->bEndpointAddress; + dev_dbg(dev->dev, "enabled %s (ep%d%s-%s) max %04x cfg %02x\n", + _ep->name, tmp & 0x0f, PIPEDIR(tmp), + type_string(desc->bmAttributes), max, + net2272_ep_read(ep, EP_CFG)); + + spin_unlock_irqrestore(&dev->lock, flags); + return 0; +} + +static void net2272_ep_reset(struct net2272_ep *ep) +{ + u8 tmp; + + ep->desc = NULL; + INIT_LIST_HEAD(&ep->queue); + + ep->ep.maxpacket = ~0; + ep->ep.ops = &net2272_ep_ops; + + /* disable irqs, endpoint */ + net2272_ep_write(ep, EP_IRQENB, 0); + + /* init to our chosen defaults, notably so that we NAK OUT + * packets until the driver queues a read. + */ + tmp = (1 << NAK_OUT_PACKETS_MODE) | (1 << ALT_NAK_OUT_PACKETS); + net2272_ep_write(ep, EP_RSPSET, tmp); + + tmp = (1 << INTERRUPT_MODE) | (1 << HIDE_STATUS_PHASE); + if (ep->num != 0) + tmp |= (1 << ENDPOINT_TOGGLE) | (1 << ENDPOINT_HALT); + + net2272_ep_write(ep, EP_RSPCLR, tmp); + + /* scrub most status bits, and flush any fifo state */ + net2272_ep_write(ep, EP_STAT0, + (1 << DATA_IN_TOKEN_INTERRUPT) + | (1 << DATA_OUT_TOKEN_INTERRUPT) + | (1 << DATA_PACKET_TRANSMITTED_INTERRUPT) + | (1 << DATA_PACKET_RECEIVED_INTERRUPT) + | (1 << SHORT_PACKET_TRANSFERRED_INTERRUPT)); + + net2272_ep_write(ep, EP_STAT1, + (1 << TIMEOUT) + | (1 << USB_OUT_ACK_SENT) + | (1 << USB_OUT_NAK_SENT) + | (1 << USB_IN_ACK_RCVD) + | (1 << USB_IN_NAK_SENT) + | (1 << USB_STALL_SENT) + | (1 << LOCAL_OUT_ZLP) + | (1 << BUFFER_FLUSH)); + + /* fifo size is handled seperately */ +} + +static int net2272_disable(struct usb_ep *_ep) +{ + struct net2272_ep *ep; + unsigned long flags; + + ep = container_of(_ep, struct net2272_ep, ep); + if (!_ep || !ep->desc || _ep->name == ep0name) + return -EINVAL; + + spin_lock_irqsave(&ep->dev->lock, flags); + net2272_dequeue_all(ep); + net2272_ep_reset(ep); + + dev_vdbg(ep->dev->dev, "disabled %s\n", _ep->name); + + spin_unlock_irqrestore(&ep->dev->lock, flags); + return 0; +} + +/*---------------------------------------------------------------------------*/ + +static struct usb_request * +net2272_alloc_request(struct usb_ep *_ep, gfp_t gfp_flags) +{ + struct net2272_ep *ep; + struct net2272_request *req; + + if (!_ep) + return NULL; + ep = container_of(_ep, struct net2272_ep, ep); + + req = kzalloc(sizeof(*req), gfp_flags); + if (!req) + return NULL; + + req->req.dma = DMA_ADDR_INVALID; + INIT_LIST_HEAD(&req->queue); + + return &req->req; +} + +static void +net2272_free_request(struct usb_ep *_ep, struct usb_request *_req) +{ + struct net2272_ep *ep; + struct net2272_request *req; + + ep = container_of(_ep, struct net2272_ep, ep); + if (!_ep || !_req) + return; + + req = container_of(_req, struct net2272_request, req); + WARN_ON(!list_empty(&req->queue)); + kfree(req); +} + +static void +net2272_done(struct net2272_ep *ep, struct net2272_request *req, int status) +{ + struct net2272 *dev; + unsigned stopped = ep->stopped; + + if (ep->num == 0) { + if (ep->dev->protocol_stall) { + ep->stopped = 1; + set_halt(ep); + } + allow_status(ep); + } + + list_del_init(&req->queue); + + if (req->req.status == -EINPROGRESS) + req->req.status = status; + else + status = req->req.status; + + dev = ep->dev; + if (use_dma && req->mapped) { + dma_unmap_single(dev->dev, req->req.dma, req->req.length, + ep->is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE); + req->req.dma = DMA_ADDR_INVALID; + req->mapped = 0; + } + + if (status && status != -ESHUTDOWN) + dev_vdbg(dev->dev, "complete %s req %p stat %d len %u/%u buf %p\n", + ep->ep.name, &req->req, status, + req->req.actual, req->req.length, req->req.buf); + + /* don't modify queue heads during completion callback */ + ep->stopped = 1; + spin_unlock(&dev->lock); + req->req.complete(&ep->ep, &req->req); + spin_lock(&dev->lock); + ep->stopped = stopped; +} + +static int +net2272_write_packet(struct net2272_ep *ep, u8 *buf, + struct net2272_request *req, unsigned max) +{ + u16 __iomem *ep_data = net2272_reg_addr(ep->dev, EP_DATA); + u16 *bufp; + unsigned length, count; + u8 tmp; + + length = min(req->req.length - req->req.actual, max); + req->req.actual += length; + + dev_vdbg(ep->dev->dev, "write packet %s req %p max %u len %u avail %u\n", + ep->ep.name, req, max, length, + (net2272_ep_read(ep, EP_AVAIL1) << 8) | net2272_ep_read(ep, EP_AVAIL0)); + + count = length; + bufp = (u16 *)buf; + + while (likely(count >= 2)) { + /* no byte-swap required; chip endian set during init */ + writew(*bufp++, ep_data); + count -= 2; + } + buf = (u8 *)bufp; + + /* write final byte by placing the NET2272 into 8-bit mode */ + if (unlikely(count)) { + tmp = net2272_read(ep->dev, LOCCTL); + net2272_write(ep->dev, LOCCTL, tmp & ~(1 << DATA_WIDTH)); + writeb(*buf, ep_data); + net2272_write(ep->dev, LOCCTL, tmp); + } + return length; +} + +/* returns: 0: still running, 1: completed, negative: errno */ +static int +net2272_write_fifo(struct net2272_ep *ep, struct net2272_request *req) +{ + u8 *buf; + unsigned count, max; + int status; + + dev_vdbg(ep->dev->dev, "write_fifo %s actual %d len %d\n", + ep->ep.name, req->req.actual, req->req.length); + + /* + * Keep loading the endpoint until the final packet is loaded, + * or the endpoint buffer is full. + */ + top: + /* + * Clear interrupt status + * - Packet Transmitted interrupt will become set again when the + * host successfully takes another packet + */ + net2272_ep_write(ep, EP_STAT0, (1 << DATA_PACKET_TRANSMITTED_INTERRUPT)); + while (!(net2272_ep_read(ep, EP_STAT0) & (1 << BUFFER_FULL))) { + buf = req->req.buf + req->req.actual; + prefetch(buf); + + /* force pagesel */ + net2272_ep_read(ep, EP_STAT0); + + max = (net2272_ep_read(ep, EP_AVAIL1) << 8) | + (net2272_ep_read(ep, EP_AVAIL0)); + + if (max < ep->ep.maxpacket) + max = (net2272_ep_read(ep, EP_AVAIL1) << 8) + | (net2272_ep_read(ep, EP_AVAIL0)); + + count = net2272_write_packet(ep, buf, req, max); + /* see if we are done */ + if (req->req.length == req->req.actual) { + /* validate short or zlp packet */ + if (count < ep->ep.maxpacket) + set_fifo_bytecount(ep, 0); + net2272_done(ep, req, 0); + + if (!list_empty(&ep->queue)) { + req = list_entry(ep->queue.next, + struct net2272_request, + queue); + status = net2272_kick_dma(ep, req); + + if (status < 0) + if ((net2272_ep_read(ep, EP_STAT0) + & (1 << BUFFER_EMPTY))) + goto top; + } + return 1; + } + net2272_ep_write(ep, EP_STAT0, (1 << DATA_PACKET_TRANSMITTED_INTERRUPT)); + } + return 0; +} + +static void +net2272_out_flush(struct net2272_ep *ep) +{ + ASSERT_OUT_NAKING(ep); + + net2272_ep_write(ep, EP_STAT0, (1 << DATA_OUT_TOKEN_INTERRUPT) + | (1 << DATA_PACKET_RECEIVED_INTERRUPT)); + net2272_ep_write(ep, EP_STAT1, 1 << BUFFER_FLUSH); +} + +static int +net2272_read_packet(struct net2272_ep *ep, u8 *buf, + struct net2272_request *req, unsigned avail) +{ + u16 __iomem *ep_data = net2272_reg_addr(ep->dev, EP_DATA); + unsigned is_short; + u16 *bufp; + + req->req.actual += avail; + + dev_vdbg(ep->dev->dev, "read packet %s req %p len %u avail %u\n", + ep->ep.name, req, avail, + (net2272_ep_read(ep, EP_AVAIL1) << 8) | net2272_ep_read(ep, EP_AVAIL0)); + + is_short = (avail < ep->ep.maxpacket); + + if (unlikely(avail == 0)) { + /* remove any zlp from the buffer */ + (void)readw(ep_data); + return is_short; + } + + /* Ensure we get the final byte */ + if (unlikely(avail % 2)) + avail++; + bufp = (u16 *)buf; + + do { + *bufp++ = readw(ep_data); + avail -= 2; + } while (avail); + + /* + * To avoid false endpoint available race condition must read + * ep stat0 twice in the case of a short transfer + */ + if (net2272_ep_read(ep, EP_STAT0) & (1 << SHORT_PACKET_TRANSFERRED_INTERRUPT)) + net2272_ep_read(ep, EP_STAT0); + + return is_short; +} + +static int +net2272_read_fifo(struct net2272_ep *ep, struct net2272_request *req) +{ + u8 *buf; + unsigned is_short; + int count; + int tmp; + int cleanup = 0; + int status = -1; + + dev_vdbg(ep->dev->dev, "read_fifo %s actual %d len %d\n", + ep->ep.name, req->req.actual, req->req.length); + + top: + do { + buf = req->req.buf + req->req.actual; + prefetchw(buf); + + count = (net2272_ep_read(ep, EP_AVAIL1) << 8) + | net2272_ep_read(ep, EP_AVAIL0); + + net2272_ep_write(ep, EP_STAT0, + (1 << SHORT_PACKET_TRANSFERRED_INTERRUPT) | + (1 << DATA_PACKET_RECEIVED_INTERRUPT)); + + tmp = req->req.length - req->req.actual; + + if (count > tmp) { + if ((tmp % ep->ep.maxpacket) != 0) { + dev_err(ep->dev->dev, + "%s out fifo %d bytes, expected %d\n", + ep->ep.name, count, tmp); + cleanup = 1; + } + count = (tmp > 0) ? tmp : 0; + } + + is_short = net2272_read_packet(ep, buf, req, count); + + /* completion */ + if (unlikely(cleanup || is_short || + ((req->req.actual == req->req.length) + && !req->req.zero))) { + + if (cleanup) { + net2272_out_flush(ep); + net2272_done(ep, req, -EOVERFLOW); + } else + net2272_done(ep, req, 0); + + /* re-initialize endpoint transfer registers + * otherwise they may result in erroneous pre-validation + * for subsequent control reads + */ + if (unlikely(ep->num == 0)) { + net2272_ep_write(ep, EP_TRANSFER2, 0); + net2272_ep_write(ep, EP_TRANSFER1, 0); + net2272_ep_write(ep, EP_TRANSFER0, 0); + } + + if (!list_empty(&ep->queue)) { + req = list_entry(ep->queue.next, + struct net2272_request, queue); + status = net2272_kick_dma(ep, req); + if ((status < 0) && + !(net2272_ep_read(ep, EP_STAT0) & (1 << BUFFER_EMPTY))) + goto top; + } + return 1; + } + } while (!(net2272_ep_read(ep, EP_STAT0) & (1 << BUFFER_EMPTY))); + + return 0; +} + +static void +net2272_pio_advance(struct net2272_ep *ep) +{ + struct net2272_request *req; + + if (unlikely(list_empty(&ep->queue))) + return; + + req = list_entry(ep->queue.next, struct net2272_request, queue); + (ep->is_in ? net2272_write_fifo : net2272_read_fifo)(ep, req); +} + +/* returns 0 on success, else negative errno */ +static int +net2272_request_dma(struct net2272 *dev, unsigned ep, u32 buf, + unsigned len, unsigned dir) +{ + dev_vdbg(dev->dev, "request_dma ep %d buf %08x len %d dir %d\n", + ep, buf, len, dir); + + /* The NET2272 only supports a single dma channel */ + if (dev->dma_busy) + return -EBUSY; + /* + * EP_TRANSFER (used to determine the number of bytes received + * in an OUT transfer) is 24 bits wide; don't ask for more than that. + */ + if ((dir == 1) && (len > 0x1000000)) + return -EINVAL; + + dev->dma_busy = 1; + + /* initialize platform's dma */ +#ifdef CONFIG_PCI + /* NET2272 addr, buffer addr, length, etc. */ + switch (dev->dev_id) { + case PCI_DEVICE_ID_RDK1: + /* Setup PLX 9054 DMA mode */ + writel((1 << LOCAL_BUS_WIDTH) | + (1 << TA_READY_INPUT_ENABLE) | + (0 << LOCAL_BURST_ENABLE) | + (1 << DONE_INTERRUPT_ENABLE) | + (1 << LOCAL_ADDRESSING_MODE) | + (1 << DEMAND_MODE) | + (1 << DMA_EOT_ENABLE) | + (1 << FAST_SLOW_TERMINATE_MODE_SELECT) | + (1 << DMA_CHANNEL_INTERRUPT_SELECT), + dev->rdk1.plx9054_base_addr + DMAMODE0); + + writel(0x100000, dev->rdk1.plx9054_base_addr + DMALADR0); + writel(buf, dev->rdk1.plx9054_base_addr + DMAPADR0); + writel(len, dev->rdk1.plx9054_base_addr + DMASIZ0); + writel((dir << DIRECTION_OF_TRANSFER) | + (1 << INTERRUPT_AFTER_TERMINAL_COUNT), + dev->rdk1.plx9054_base_addr + DMADPR0); + writel((1 << LOCAL_DMA_CHANNEL_0_INTERRUPT_ENABLE) | + readl(dev->rdk1.plx9054_base_addr + INTCSR), + dev->rdk1.plx9054_base_addr + INTCSR); + + break; + } +#endif + + net2272_write(dev, DMAREQ, + (0 << DMA_BUFFER_VALID) | + (1 << DMA_REQUEST_ENABLE) | + (1 << DMA_CONTROL_DACK) | + (dev->dma_eot_polarity << EOT_POLARITY) | + (dev->dma_dack_polarity << DACK_POLARITY) | + (dev->dma_dreq_polarity << DREQ_POLARITY) | + ((ep >> 1) << DMA_ENDPOINT_SELECT)); + + (void) net2272_read(dev, SCRATCH); + + return 0; +} + +static void +net2272_start_dma(struct net2272 *dev) +{ + /* start platform's dma controller */ +#ifdef CONFIG_PCI + switch (dev->dev_id) { + case PCI_DEVICE_ID_RDK1: + writeb((1 << CHANNEL_ENABLE) | (1 << CHANNEL_START), + dev->rdk1.plx9054_base_addr + DMACSR0); + break; + } +#endif +} + +/* returns 0 on success, else negative errno */ +static int +net2272_kick_dma(struct net2272_ep *ep, struct net2272_request *req) +{ + unsigned size; + u8 tmp; + + if (!use_dma || (ep->num < 1) || (ep->num > 2) || !ep->dma) + return -EINVAL; + + /* don't use dma for odd-length transfers + * otherwise, we'd need to deal with the last byte with pio + */ + if (req->req.length & 1) + return -EINVAL; + + dev_vdbg(ep->dev->dev, "kick_dma %s req %p dma %08x\n", + ep->ep.name, req, req->req.dma); + + net2272_ep_write(ep, EP_RSPSET, 1 << ALT_NAK_OUT_PACKETS); + + /* The NET2272 can only use DMA on one endpoint at a time */ + if (ep->dev->dma_busy) + return -EBUSY; + + /* Make sure we only DMA an even number of bytes (we'll use + * pio to complete the transfer) + */ + size = req->req.length; + size &= ~1; + + /* device-to-host transfer */ + if (ep->is_in) { + /* initialize platform's dma controller */ + if (net2272_request_dma(ep->dev, ep->num, req->req.dma, size, 0)) + /* unable to obtain DMA channel; return error and use pio mode */ + return -EBUSY; + req->req.actual += size; + + /* host-to-device transfer */ + } else { + tmp = net2272_ep_read(ep, EP_STAT0); + + /* initialize platform's dma controller */ + if (net2272_request_dma(ep->dev, ep->num, req->req.dma, size, 1)) + /* unable to obtain DMA channel; return error and use pio mode */ + return -EBUSY; + + if (!(tmp & (1 << BUFFER_EMPTY))) + ep->not_empty = 1; + else + ep->not_empty = 0; + + + /* allow the endpoint's buffer to fill */ + net2272_ep_write(ep, EP_RSPCLR, 1 << ALT_NAK_OUT_PACKETS); + + /* this transfer completed and data's already in the fifo + * return error so pio gets used. + */ + if (tmp & (1 << SHORT_PACKET_TRANSFERRED_INTERRUPT)) { + + /* deassert dreq */ + net2272_write(ep->dev, DMAREQ, + (0 << DMA_BUFFER_VALID) | + (0 << DMA_REQUEST_ENABLE) | + (1 << DMA_CONTROL_DACK) | + (ep->dev->dma_eot_polarity << EOT_POLARITY) | + (ep->dev->dma_dack_polarity << DACK_POLARITY) | + (ep->dev->dma_dreq_polarity << DREQ_POLARITY) | + ((ep->num >> 1) << DMA_ENDPOINT_SELECT)); + + return -EBUSY; + } + } + + /* Don't use per-packet interrupts: use dma interrupts only */ + net2272_ep_write(ep, EP_IRQENB, 0); + + net2272_start_dma(ep->dev); + + return 0; +} + +static void net2272_cancel_dma(struct net2272 *dev) +{ +#ifdef CONFIG_PCI + switch (dev->dev_id) { + case PCI_DEVICE_ID_RDK1: + writeb(0, dev->rdk1.plx9054_base_addr + DMACSR0); + writeb(1 << CHANNEL_ABORT, dev->rdk1.plx9054_base_addr + DMACSR0); + while (!(readb(dev->rdk1.plx9054_base_addr + DMACSR0) & + (1 << CHANNEL_DONE))) + continue; /* wait for dma to stabalize */ + + /* dma abort generates an interrupt */ + writeb(1 << CHANNEL_CLEAR_INTERRUPT, + dev->rdk1.plx9054_base_addr + DMACSR0); + break; + } +#endif + + dev->dma_busy = 0; +} + +/*---------------------------------------------------------------------------*/ + +static int +net2272_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags) +{ + struct net2272_request *req; + struct net2272_ep *ep; + struct net2272 *dev; + unsigned long flags; + int status = -1; + u8 s; + + req = container_of(_req, struct net2272_request, req); + if (!_req || !_req->complete || !_req->buf + || !list_empty(&req->queue)) + return -EINVAL; + ep = container_of(_ep, struct net2272_ep, ep); + if (!_ep || (!ep->desc && ep->num != 0)) + return -EINVAL; + dev = ep->dev; + if (!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN) + return -ESHUTDOWN; + + /* set up dma mapping in case the caller didn't */ + if (use_dma && ep->dma && _req->dma == DMA_ADDR_INVALID) { + _req->dma = dma_map_single(dev->dev, _req->buf, _req->length, + ep->is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE); + req->mapped = 1; + } + + dev_vdbg(dev->dev, "%s queue req %p, len %d buf %p dma %08x %s\n", + _ep->name, _req, _req->length, _req->buf, + _req->dma, _req->zero ? "zero" : "!zero"); + + spin_lock_irqsave(&dev->lock, flags); + + _req->status = -EINPROGRESS; + _req->actual = 0; + + /* kickstart this i/o queue? */ + if (list_empty(&ep->queue) && !ep->stopped) { + /* maybe there's no control data, just status ack */ + if (ep->num == 0 && _req->length == 0) { + net2272_done(ep, req, 0); + dev_vdbg(dev->dev, "%s status ack\n", ep->ep.name); + goto done; + } + + /* Return zlp, don't let it block subsequent packets */ + s = net2272_ep_read(ep, EP_STAT0); + if (s & (1 << BUFFER_EMPTY)) { + /* Buffer is empty check for a blocking zlp, handle it */ + if ((s & (1 << NAK_OUT_PACKETS)) && + net2272_ep_read(ep, EP_STAT1) & (1 << LOCAL_OUT_ZLP)) { + dev_dbg(dev->dev, "WARNING: returning ZLP short packet termination!\n"); + /* + * Request is going to terminate with a short packet ... + * hope the client is ready for it! + */ + status = net2272_read_fifo(ep, req); + /* clear short packet naking */ + net2272_ep_write(ep, EP_STAT0, (1 << NAK_OUT_PACKETS)); + goto done; + } + } + + /* try dma first */ + status = net2272_kick_dma(ep, req); + + if (status < 0) { + /* dma failed (most likely in use by another endpoint) + * fallback to pio + */ + status = 0; + + if (ep->is_in) + status = net2272_write_fifo(ep, req); + else { + s = net2272_ep_read(ep, EP_STAT0); + if ((s & (1 << BUFFER_EMPTY)) == 0) + status = net2272_read_fifo(ep, req); + } + + if (unlikely(status != 0)) { + if (status > 0) + status = 0; + req = NULL; + } + } + } + if (likely(req != 0)) + list_add_tail(&req->queue, &ep->queue); + + if (likely(!list_empty(&ep->queue))) + net2272_ep_write(ep, EP_RSPCLR, 1 << ALT_NAK_OUT_PACKETS); + done: + spin_unlock_irqrestore(&dev->lock, flags); + + return 0; +} + +/* dequeue ALL requests */ +static void +net2272_dequeue_all(struct net2272_ep *ep) +{ + struct net2272_request *req; + + /* called with spinlock held */ + ep->stopped = 1; + + while (!list_empty(&ep->queue)) { + req = list_entry(ep->queue.next, + struct net2272_request, + queue); + net2272_done(ep, req, -ESHUTDOWN); + } +} + +/* dequeue JUST ONE request */ +static int +net2272_dequeue(struct usb_ep *_ep, struct usb_request *_req) +{ + struct net2272_ep *ep; + struct net2272_request *req; + unsigned long flags; + int stopped; + + ep = container_of(_ep, struct net2272_ep, ep); + if (!_ep || (!ep->desc && ep->num != 0) || !_req) + return -EINVAL; + + spin_lock_irqsave(&ep->dev->lock, flags); + stopped = ep->stopped; + ep->stopped = 1; + + /* make sure it's still queued on this endpoint */ + list_for_each_entry(req, &ep->queue, queue) { + if (&req->req == _req) + break; + } + if (&req->req != _req) { + spin_unlock_irqrestore(&ep->dev->lock, flags); + return -EINVAL; + } + + /* queue head may be partially complete */ + if (ep->queue.next == &req->queue) { + dev_dbg(ep->dev->dev, "unlink (%s) pio\n", _ep->name); + net2272_done(ep, req, -ECONNRESET); + } + req = NULL; + ep->stopped = stopped; + + spin_unlock_irqrestore(&ep->dev->lock, flags); + return 0; +} + +/*---------------------------------------------------------------------------*/ + +static int +net2272_set_halt_and_wedge(struct usb_ep *_ep, int value, int wedged) +{ + struct net2272_ep *ep; + unsigned long flags; + int ret = 0; + + ep = container_of(_ep, struct net2272_ep, ep); + if (!_ep || (!ep->desc && ep->num != 0)) + return -EINVAL; + if (!ep->dev->driver || ep->dev->gadget.speed == USB_SPEED_UNKNOWN) + return -ESHUTDOWN; + if (ep->desc /* not ep0 */ && usb_endpoint_xfer_isoc(ep->desc)) + return -EINVAL; + + spin_lock_irqsave(&ep->dev->lock, flags); + if (!list_empty(&ep->queue)) + ret = -EAGAIN; + else if (ep->is_in && value && net2272_fifo_status(_ep) != 0) + ret = -EAGAIN; + else { + dev_vdbg(ep->dev->dev, "%s %s %s\n", _ep->name, + value ? "set" : "clear", + wedged ? "wedge" : "halt"); + /* set/clear */ + if (value) { + if (ep->num == 0) + ep->dev->protocol_stall = 1; + else + set_halt(ep); + if (wedged) + ep->wedged = 1; + } else { + clear_halt(ep); + ep->wedged = 0; + } + } + spin_unlock_irqrestore(&ep->dev->lock, flags); + + return ret; +} + +static int +net2272_set_halt(struct usb_ep *_ep, int value) +{ + return net2272_set_halt_and_wedge(_ep, value, 0); +} + +static int +net2272_set_wedge(struct usb_ep *_ep) +{ + if (!_ep || _ep->name == ep0name) + return -EINVAL; + return net2272_set_halt_and_wedge(_ep, 1, 1); +} + +static int +net2272_fifo_status(struct usb_ep *_ep) +{ + struct net2272_ep *ep; + u16 avail; + + ep = container_of(_ep, struct net2272_ep, ep); + if (!_ep || (!ep->desc && ep->num != 0)) + return -ENODEV; + if (!ep->dev->driver || ep->dev->gadget.speed == USB_SPEED_UNKNOWN) + return -ESHUTDOWN; + + avail = net2272_ep_read(ep, EP_AVAIL1) << 8; + avail |= net2272_ep_read(ep, EP_AVAIL0); + if (avail > ep->fifo_size) + return -EOVERFLOW; + if (ep->is_in) + avail = ep->fifo_size - avail; + return avail; +} + +static void +net2272_fifo_flush(struct usb_ep *_ep) +{ + struct net2272_ep *ep; + + ep = container_of(_ep, struct net2272_ep, ep); + if (!_ep || (!ep->desc && ep->num != 0)) + return; + if (!ep->dev->driver || ep->dev->gadget.speed == USB_SPEED_UNKNOWN) + return; + + net2272_ep_write(ep, EP_STAT1, 1 << BUFFER_FLUSH); +} + +static struct usb_ep_ops net2272_ep_ops = { + .enable = net2272_enable, + .disable = net2272_disable, + + .alloc_request = net2272_alloc_request, + .free_request = net2272_free_request, + + .queue = net2272_queue, + .dequeue = net2272_dequeue, + + .set_halt = net2272_set_halt, + .set_wedge = net2272_set_wedge, + .fifo_status = net2272_fifo_status, + .fifo_flush = net2272_fifo_flush, +}; + +/*---------------------------------------------------------------------------*/ + +static int +net2272_get_frame(struct usb_gadget *_gadget) +{ + struct net2272 *dev; + unsigned long flags; + u16 ret; + + if (!_gadget) + return -ENODEV; + dev = container_of(_gadget, struct net2272, gadget); + spin_lock_irqsave(&dev->lock, flags); + + ret = net2272_read(dev, FRAME1) << 8; + ret |= net2272_read(dev, FRAME0); + + spin_unlock_irqrestore(&dev->lock, flags); + return ret; +} + +static int +net2272_wakeup(struct usb_gadget *_gadget) +{ + struct net2272 *dev; + u8 tmp; + unsigned long flags; + + if (!_gadget) + return 0; + dev = container_of(_gadget, struct net2272, gadget); + + spin_lock_irqsave(&dev->lock, flags); + tmp = net2272_read(dev, USBCTL0); + if (tmp & (1 << IO_WAKEUP_ENABLE)) + net2272_write(dev, USBCTL1, (1 << GENERATE_RESUME)); + + spin_unlock_irqrestore(&dev->lock, flags); + + return 0; +} + +static int +net2272_set_selfpowered(struct usb_gadget *_gadget, int value) +{ + struct net2272 *dev; + + if (!_gadget) + return -ENODEV; + dev = container_of(_gadget, struct net2272, gadget); + + dev->is_selfpowered = value; + + return 0; +} + +static int +net2272_pullup(struct usb_gadget *_gadget, int is_on) +{ + struct net2272 *dev; + u8 tmp; + unsigned long flags; + + if (!_gadget) + return -ENODEV; + dev = container_of(_gadget, struct net2272, gadget); + + spin_lock_irqsave(&dev->lock, flags); + tmp = net2272_read(dev, USBCTL0); + dev->softconnect = (is_on != 0); + if (is_on) + tmp |= (1 << USB_DETECT_ENABLE); + else + tmp &= ~(1 << USB_DETECT_ENABLE); + net2272_write(dev, USBCTL0, tmp); + spin_unlock_irqrestore(&dev->lock, flags); + + return 0; +} + +static const struct usb_gadget_ops net2272_ops = { + .get_frame = net2272_get_frame, + .wakeup = net2272_wakeup, + .set_selfpowered = net2272_set_selfpowered, + .pullup = net2272_pullup +}; + +/*---------------------------------------------------------------------------*/ + +static ssize_t +net2272_show_registers(struct device *_dev, struct device_attribute *attr, char *buf) +{ + struct net2272 *dev; + char *next; + unsigned size, t; + unsigned long flags; + u8 t1, t2; + int i; + const char *s; + + dev = dev_get_drvdata(_dev); + next = buf; + size = PAGE_SIZE; + spin_lock_irqsave(&dev->lock, flags); + + if (dev->driver) + s = dev->driver->driver.name; + else + s = "(none)"; + + /* Main Control Registers */ + t = scnprintf(next, size, "%s version %s," + "chiprev %02x, locctl %02x\n" + "irqenb0 %02x irqenb1 %02x " + "irqstat0 %02x irqstat1 %02x\n", + driver_name, driver_vers, dev->chiprev, + net2272_read(dev, LOCCTL), + net2272_read(dev, IRQENB0), + net2272_read(dev, IRQENB1), + net2272_read(dev, IRQSTAT0), + net2272_read(dev, IRQSTAT1)); + size -= t; + next += t; + + /* DMA */ + t1 = net2272_read(dev, DMAREQ); + t = scnprintf(next, size, "\ndmareq %02x: %s %s%s%s%s\n", + t1, ep_name[(t1 & 0x01) + 1], + t1 & (1 << DMA_CONTROL_DACK) ? "dack " : "", + t1 & (1 << DMA_REQUEST_ENABLE) ? "reqenb " : "", + t1 & (1 << DMA_REQUEST) ? "req " : "", + t1 & (1 << DMA_BUFFER_VALID) ? "valid " : ""); + size -= t; + next += t; + + /* USB Control Registers */ + t1 = net2272_read(dev, USBCTL1); + if (t1 & (1 << VBUS_PIN)) { + if (t1 & (1 << USB_HIGH_SPEED)) + s = "high speed"; + else if (dev->gadget.speed == USB_SPEED_UNKNOWN) + s = "powered"; + else + s = "full speed"; + } else + s = "not attached"; + t = scnprintf(next, size, + "usbctl0 %02x usbctl1 %02x addr 0x%02x (%s)\n", + net2272_read(dev, USBCTL0), t1, + net2272_read(dev, OURADDR), s); + size -= t; + next += t; + + /* Endpoint Registers */ + for (i = 0; i < 4; ++i) { + struct net2272_ep *ep; + + ep = &dev->ep[i]; + if (i && !ep->desc) + continue; + + t1 = net2272_ep_read(ep, EP_CFG); + t2 = net2272_ep_read(ep, EP_RSPSET); + t = scnprintf(next, size, + "\n%s\tcfg %02x rsp (%02x) %s%s%s%s%s%s%s%s" + "irqenb %02x\n", + ep->ep.name, t1, t2, + (t2 & (1 << ALT_NAK_OUT_PACKETS)) ? "NAK " : "", + (t2 & (1 << HIDE_STATUS_PHASE)) ? "hide " : "", + (t2 & (1 << AUTOVALIDATE)) ? "auto " : "", + (t2 & (1 << INTERRUPT_MODE)) ? "interrupt " : "", + (t2 & (1 << CONTROL_STATUS_PHASE_HANDSHAKE)) ? "status " : "", + (t2 & (1 << NAK_OUT_PACKETS_MODE)) ? "NAKmode " : "", + (t2 & (1 << ENDPOINT_TOGGLE)) ? "DATA1 " : "DATA0 ", + (t2 & (1 << ENDPOINT_HALT)) ? "HALT " : "", + net2272_ep_read(ep, EP_IRQENB)); + size -= t; + next += t; + + t = scnprintf(next, size, + "\tstat0 %02x stat1 %02x avail %04x " + "(ep%d%s-%s)%s\n", + net2272_ep_read(ep, EP_STAT0), + net2272_ep_read(ep, EP_STAT1), + (net2272_ep_read(ep, EP_AVAIL1) << 8) | net2272_ep_read(ep, EP_AVAIL0), + t1 & 0x0f, + ep->is_in ? "in" : "out", + type_string(t1 >> 5), + ep->stopped ? "*" : ""); + size -= t; + next += t; + + t = scnprintf(next, size, + "\tep_transfer %06x\n", + ((net2272_ep_read(ep, EP_TRANSFER2) & 0xff) << 16) | + ((net2272_ep_read(ep, EP_TRANSFER1) & 0xff) << 8) | + ((net2272_ep_read(ep, EP_TRANSFER0) & 0xff))); + size -= t; + next += t; + + t1 = net2272_ep_read(ep, EP_BUFF_STATES) & 0x03; + t2 = (net2272_ep_read(ep, EP_BUFF_STATES) >> 2) & 0x03; + t = scnprintf(next, size, + "\tbuf-a %s buf-b %s\n", + buf_state_string(t1), + buf_state_string(t2)); + size -= t; + next += t; + } + + spin_unlock_irqrestore(&dev->lock, flags); + + return PAGE_SIZE - size; +} +static DEVICE_ATTR(registers, S_IRUGO, net2272_show_registers, NULL); + +/*---------------------------------------------------------------------------*/ + +static void +net2272_set_fifo_mode(struct net2272 *dev, int mode) +{ + u8 tmp; + + tmp = net2272_read(dev, LOCCTL) & 0x3f; + tmp |= (mode << 6); + net2272_write(dev, LOCCTL, tmp); + + INIT_LIST_HEAD(&dev->gadget.ep_list); + + /* always ep-a, ep-c ... maybe not ep-b */ + list_add_tail(&dev->ep[1].ep.ep_list, &dev->gadget.ep_list); + + switch (mode) { + case 0: + list_add_tail(&dev->ep[2].ep.ep_list, &dev->gadget.ep_list); + dev->ep[1].fifo_size = dev->ep[2].fifo_size = 512; + break; + case 1: + list_add_tail(&dev->ep[2].ep.ep_list, &dev->gadget.ep_list); + dev->ep[1].fifo_size = 1024; + dev->ep[2].fifo_size = 512; + break; + case 2: + list_add_tail(&dev->ep[2].ep.ep_list, &dev->gadget.ep_list); + dev->ep[1].fifo_size = dev->ep[2].fifo_size = 1024; + break; + case 3: + dev->ep[1].fifo_size = 1024; + break; + } + + /* ep-c is always 2 512 byte buffers */ + list_add_tail(&dev->ep[3].ep.ep_list, &dev->gadget.ep_list); + dev->ep[3].fifo_size = 512; +} + +/*---------------------------------------------------------------------------*/ + +static struct net2272 *the_controller; + +static void +net2272_usb_reset(struct net2272 *dev) +{ + dev->gadget.speed = USB_SPEED_UNKNOWN; + + net2272_cancel_dma(dev); + + net2272_write(dev, IRQENB0, 0); + net2272_write(dev, IRQENB1, 0); + + /* clear irq state */ + net2272_write(dev, IRQSTAT0, 0xff); + net2272_write(dev, IRQSTAT1, ~(1 << SUSPEND_REQUEST_INTERRUPT)); + + net2272_write(dev, DMAREQ, + (0 << DMA_BUFFER_VALID) | + (0 << DMA_REQUEST_ENABLE) | + (1 << DMA_CONTROL_DACK) | + (dev->dma_eot_polarity << EOT_POLARITY) | + (dev->dma_dack_polarity << DACK_POLARITY) | + (dev->dma_dreq_polarity << DREQ_POLARITY) | + ((dma_ep >> 1) << DMA_ENDPOINT_SELECT)); + + net2272_cancel_dma(dev); + net2272_set_fifo_mode(dev, (fifo_mode <= 3) ? fifo_mode : 0); + + /* Set the NET2272 ep fifo data width to 16-bit mode and for correct byte swapping + * note that the higher level gadget drivers are expected to convert data to little endian. + * Enable byte swap for your local bus/cpu if needed by setting BYTE_SWAP in LOCCTL here + */ + net2272_write(dev, LOCCTL, net2272_read(dev, LOCCTL) | (1 << DATA_WIDTH)); + net2272_write(dev, LOCCTL1, (dma_mode << DMA_MODE)); +} + +static void +net2272_usb_reinit(struct net2272 *dev) +{ + int i; + + /* basic endpoint init */ + for (i = 0; i < 4; ++i) { + struct net2272_ep *ep = &dev->ep[i]; + + ep->ep.name = ep_name[i]; + ep->dev = dev; + ep->num = i; + ep->not_empty = 0; + + if (use_dma && ep->num == dma_ep) + ep->dma = 1; + + if (i > 0 && i <= 3) + ep->fifo_size = 512; + else + ep->fifo_size = 64; + net2272_ep_reset(ep); + } + dev->ep[0].ep.maxpacket = 64; + + dev->gadget.ep0 = &dev->ep[0].ep; + dev->ep[0].stopped = 0; + INIT_LIST_HEAD(&dev->gadget.ep0->ep_list); +} + +static void +net2272_ep0_start(struct net2272 *dev) +{ + struct net2272_ep *ep0 = &dev->ep[0]; + + net2272_ep_write(ep0, EP_RSPSET, + (1 << NAK_OUT_PACKETS_MODE) | + (1 << ALT_NAK_OUT_PACKETS)); + net2272_ep_write(ep0, EP_RSPCLR, + (1 << HIDE_STATUS_PHASE) | + (1 << CONTROL_STATUS_PHASE_HANDSHAKE)); + net2272_write(dev, USBCTL0, + (dev->softconnect << USB_DETECT_ENABLE) | + (1 << USB_ROOT_PORT_WAKEUP_ENABLE) | + (1 << IO_WAKEUP_ENABLE)); + net2272_write(dev, IRQENB0, + (1 << SETUP_PACKET_INTERRUPT_ENABLE) | + (1 << ENDPOINT_0_INTERRUPT_ENABLE) | + (1 << DMA_DONE_INTERRUPT_ENABLE)); + net2272_write(dev, IRQENB1, + (1 << VBUS_INTERRUPT_ENABLE) | + (1 << ROOT_PORT_RESET_INTERRUPT_ENABLE) | + (1 << SUSPEND_REQUEST_CHANGE_INTERRUPT_ENABLE)); +} + +/* when a driver is successfully registered, it will receive + * control requests including set_configuration(), which enables + * non-control requests. then usb traffic follows until a + * disconnect is reported. then a host may connect again, or + * the driver might get unbound. + */ +int usb_gadget_probe_driver(struct usb_gadget_driver *driver, + int (*bind)(struct usb_gadget *)) +{ + struct net2272 *dev = the_controller; + int ret; + unsigned i; + + if (!driver || !bind || !driver->unbind || !driver->setup || + driver->speed != USB_SPEED_HIGH) + return -EINVAL; + if (!dev) + return -ENODEV; + if (dev->driver) + return -EBUSY; + + for (i = 0; i < 4; ++i) + dev->ep[i].irqs = 0; + /* hook up the driver ... */ + dev->softconnect = 1; + driver->driver.bus = NULL; + dev->driver = driver; + dev->gadget.dev.driver = &driver->driver; + ret = bind(&dev->gadget); + if (ret) { + dev_dbg(dev->dev, "bind to driver %s --> %d\n", + driver->driver.name, ret); + dev->driver = NULL; + dev->gadget.dev.driver = NULL; + return ret; + } + + /* ... then enable host detection and ep0; and we're ready + * for set_configuration as well as eventual disconnect. + */ + net2272_ep0_start(dev); + + dev_dbg(dev->dev, "%s ready\n", driver->driver.name); + + return 0; +} +EXPORT_SYMBOL(usb_gadget_probe_driver); + +static void +stop_activity(struct net2272 *dev, struct usb_gadget_driver *driver) +{ + int i; + + /* don't disconnect if it's not connected */ + if (dev->gadget.speed == USB_SPEED_UNKNOWN) + driver = NULL; + + /* stop hardware; prevent new request submissions; + * and kill any outstanding requests. + */ + net2272_usb_reset(dev); + for (i = 0; i < 4; ++i) + net2272_dequeue_all(&dev->ep[i]); + + /* report disconnect; the driver is already quiesced */ + if (driver) { + spin_unlock(&dev->lock); + driver->disconnect(&dev->gadget); + spin_lock(&dev->lock); + + } + net2272_usb_reinit(dev); +} + +int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) +{ + struct net2272 *dev = the_controller; + unsigned long flags; + + if (!dev) + return -ENODEV; + if (!driver || driver != dev->driver) + return -EINVAL; + + spin_lock_irqsave(&dev->lock, flags); + stop_activity(dev, driver); + spin_unlock_irqrestore(&dev->lock, flags); + + net2272_pullup(&dev->gadget, 0); + + driver->unbind(&dev->gadget); + dev->gadget.dev.driver = NULL; + dev->driver = NULL; + + dev_dbg(dev->dev, "unregistered driver '%s'\n", driver->driver.name); + return 0; +} +EXPORT_SYMBOL(usb_gadget_unregister_driver); + +/*---------------------------------------------------------------------------*/ +/* handle ep-a/ep-b dma completions */ +static void +net2272_handle_dma(struct net2272_ep *ep) +{ + struct net2272_request *req; + unsigned len; + int status; + + if (!list_empty(&ep->queue)) + req = list_entry(ep->queue.next, + struct net2272_request, queue); + else + req = NULL; + + dev_vdbg(ep->dev->dev, "handle_dma %s req %p\n", ep->ep.name, req); + + /* Ensure DREQ is de-asserted */ + net2272_write(ep->dev, DMAREQ, + (0 << DMA_BUFFER_VALID) + | (0 << DMA_REQUEST_ENABLE) + | (1 << DMA_CONTROL_DACK) + | (ep->dev->dma_eot_polarity << EOT_POLARITY) + | (ep->dev->dma_dack_polarity << DACK_POLARITY) + | (ep->dev->dma_dreq_polarity << DREQ_POLARITY) + | ((ep->dma >> 1) << DMA_ENDPOINT_SELECT)); + + ep->dev->dma_busy = 0; + + net2272_ep_write(ep, EP_IRQENB, + (1 << DATA_PACKET_RECEIVED_INTERRUPT_ENABLE) + | (1 << DATA_PACKET_TRANSMITTED_INTERRUPT_ENABLE) + | net2272_ep_read(ep, EP_IRQENB)); + + /* device-to-host transfer completed */ + if (ep->is_in) { + /* validate a short packet or zlp if necessary */ + if ((req->req.length % ep->ep.maxpacket != 0) || + req->req.zero) + set_fifo_bytecount(ep, 0); + + net2272_done(ep, req, 0); + if (!list_empty(&ep->queue)) { + req = list_entry(ep->queue.next, + struct net2272_request, queue); + status = net2272_kick_dma(ep, req); + if (status < 0) + net2272_pio_advance(ep); + } + + /* host-to-device transfer completed */ + } else { + /* terminated with a short packet? */ + if (net2272_read(ep->dev, IRQSTAT0) & + (1 << DMA_DONE_INTERRUPT)) { + /* abort system dma */ + net2272_cancel_dma(ep->dev); + } + + /* EP_TRANSFER will contain the number of bytes + * actually received. + * NOTE: There is no overflow detection on EP_TRANSFER: + * We can't deal with transfers larger than 2^24 bytes! + */ + len = (net2272_ep_read(ep, EP_TRANSFER2) << 16) + | (net2272_ep_read(ep, EP_TRANSFER1) << 8) + | (net2272_ep_read(ep, EP_TRANSFER0)); + + if (ep->not_empty) + len += 4; + + req->req.actual += len; + + /* get any remaining data */ + net2272_pio_advance(ep); + } +} + +/*---------------------------------------------------------------------------*/ + +static void +net2272_handle_ep(struct net2272_ep *ep) +{ + struct net2272_request *req; + u8 stat0, stat1; + + if (!list_empty(&ep->queue)) + req = list_entry(ep->queue.next, + struct net2272_request, queue); + else + req = NULL; + + /* ack all, and handle what we care about */ + stat0 = net2272_ep_read(ep, EP_STAT0); + stat1 = net2272_ep_read(ep, EP_STAT1); + ep->irqs++; + + dev_vdbg(ep->dev->dev, "%s ack ep_stat0 %02x, ep_stat1 %02x, req %p\n", + ep->ep.name, stat0, stat1, req ? &req->req : 0); + + net2272_ep_write(ep, EP_STAT0, stat0 & + ~((1 << NAK_OUT_PACKETS) + | (1 << SHORT_PACKET_TRANSFERRED_INTERRUPT))); + net2272_ep_write(ep, EP_STAT1, stat1); + + /* data packet(s) received (in the fifo, OUT) + * direction must be validated, otherwise control read status phase + * could be interpreted as a valid packet + */ + if (!ep->is_in && (stat0 & (1 << DATA_PACKET_RECEIVED_INTERRUPT))) + net2272_pio_advance(ep); + /* data packet(s) transmitted (IN) */ + else if (stat0 & (1 << DATA_PACKET_TRANSMITTED_INTERRUPT)) + net2272_pio_advance(ep); +} + +static struct net2272_ep * +net2272_get_ep_by_addr(struct net2272 *dev, u16 wIndex) +{ + struct net2272_ep *ep; + + if ((wIndex & USB_ENDPOINT_NUMBER_MASK) == 0) + return &dev->ep[0]; + + list_for_each_entry(ep, &dev->gadget.ep_list, ep.ep_list) { + u8 bEndpointAddress; + + if (!ep->desc) + continue; + bEndpointAddress = ep->desc->bEndpointAddress; + if ((wIndex ^ bEndpointAddress) & USB_DIR_IN) + continue; + if ((wIndex & 0x0f) == (bEndpointAddress & 0x0f)) + return ep; + } + return NULL; +} + +/* + * USB Test Packet: + * JKJKJKJK * 9 + * JJKKJJKK * 8 + * JJJJKKKK * 8 + * JJJJJJJKKKKKKK * 8 + * JJJJJJJK * 8 + * {JKKKKKKK * 10}, JK + */ +static const u8 net2272_test_packet[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, + 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, + 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0x7F, 0xBF, 0xDF, 0xEF, 0xF7, 0xFB, 0xFD, + 0xFC, 0x7E, 0xBF, 0xDF, 0xEF, 0xF7, 0xFD, 0x7E +}; + +static void +net2272_set_test_mode(struct net2272 *dev, int mode) +{ + int i; + + /* Disable all net2272 interrupts: + * Nothing but a power cycle should stop the test. + */ + net2272_write(dev, IRQENB0, 0x00); + net2272_write(dev, IRQENB1, 0x00); + + /* Force tranceiver to high-speed */ + net2272_write(dev, XCVRDIAG, 1 << FORCE_HIGH_SPEED); + + net2272_write(dev, PAGESEL, 0); + net2272_write(dev, EP_STAT0, 1 << DATA_PACKET_TRANSMITTED_INTERRUPT); + net2272_write(dev, EP_RSPCLR, + (1 << CONTROL_STATUS_PHASE_HANDSHAKE) + | (1 << HIDE_STATUS_PHASE)); + net2272_write(dev, EP_CFG, 1 << ENDPOINT_DIRECTION); + net2272_write(dev, EP_STAT1, 1 << BUFFER_FLUSH); + + /* wait for status phase to complete */ + while (!(net2272_read(dev, EP_STAT0) & + (1 << DATA_PACKET_TRANSMITTED_INTERRUPT))) + ; + + /* Enable test mode */ + net2272_write(dev, USBTEST, mode); + + /* load test packet */ + if (mode == TEST_PACKET) { + /* switch to 8 bit mode */ + net2272_write(dev, LOCCTL, net2272_read(dev, LOCCTL) & + ~(1 << DATA_WIDTH)); + + for (i = 0; i < sizeof(net2272_test_packet); ++i) + net2272_write(dev, EP_DATA, net2272_test_packet[i]); + + /* Validate test packet */ + net2272_write(dev, EP_TRANSFER0, 0); + } +} + +static void +net2272_handle_stat0_irqs(struct net2272 *dev, u8 stat) +{ + struct net2272_ep *ep; + u8 num, scratch; + + /* starting a control request? */ + if (unlikely(stat & (1 << SETUP_PACKET_INTERRUPT))) { + union { + u8 raw[8]; + struct usb_ctrlrequest r; + } u; + int tmp = 0; + struct net2272_request *req; + + if (dev->gadget.speed == USB_SPEED_UNKNOWN) { + if (net2272_read(dev, USBCTL1) & (1 << USB_HIGH_SPEED)) + dev->gadget.speed = USB_SPEED_HIGH; + else + dev->gadget.speed = USB_SPEED_FULL; + dev_dbg(dev->dev, "%s speed\n", + (dev->gadget.speed == USB_SPEED_HIGH) ? "high" : "full"); + } + + ep = &dev->ep[0]; + ep->irqs++; + + /* make sure any leftover interrupt state is cleared */ + stat &= ~(1 << ENDPOINT_0_INTERRUPT); + while (!list_empty(&ep->queue)) { + req = list_entry(ep->queue.next, + struct net2272_request, queue); + net2272_done(ep, req, + (req->req.actual == req->req.length) ? 0 : -EPROTO); + } + ep->stopped = 0; + dev->protocol_stall = 0; + net2272_ep_write(ep, EP_STAT0, + (1 << DATA_IN_TOKEN_INTERRUPT) + | (1 << DATA_OUT_TOKEN_INTERRUPT) + | (1 << DATA_PACKET_TRANSMITTED_INTERRUPT) + | (1 << DATA_PACKET_RECEIVED_INTERRUPT) + | (1 << SHORT_PACKET_TRANSFERRED_INTERRUPT)); + net2272_ep_write(ep, EP_STAT1, + (1 << TIMEOUT) + | (1 << USB_OUT_ACK_SENT) + | (1 << USB_OUT_NAK_SENT) + | (1 << USB_IN_ACK_RCVD) + | (1 << USB_IN_NAK_SENT) + | (1 << USB_STALL_SENT) + | (1 << LOCAL_OUT_ZLP)); + + /* + * Ensure Control Read pre-validation setting is beyond maximum size + * - Control Writes can leave non-zero values in EP_TRANSFER. If + * an EP0 transfer following the Control Write is a Control Read, + * the NET2272 sees the non-zero EP_TRANSFER as an unexpected + * pre-validation count. + * - Setting EP_TRANSFER beyond the maximum EP0 transfer size ensures + * the pre-validation count cannot cause an unexpected validatation + */ + net2272_write(dev, PAGESEL, 0); + net2272_write(dev, EP_TRANSFER2, 0xff); + net2272_write(dev, EP_TRANSFER1, 0xff); + net2272_write(dev, EP_TRANSFER0, 0xff); + + u.raw[0] = net2272_read(dev, SETUP0); + u.raw[1] = net2272_read(dev, SETUP1); + u.raw[2] = net2272_read(dev, SETUP2); + u.raw[3] = net2272_read(dev, SETUP3); + u.raw[4] = net2272_read(dev, SETUP4); + u.raw[5] = net2272_read(dev, SETUP5); + u.raw[6] = net2272_read(dev, SETUP6); + u.raw[7] = net2272_read(dev, SETUP7); + /* + * If you have a big endian cpu make sure le16_to_cpus + * performs the proper byte swapping here... + */ + le16_to_cpus(&u.r.wValue); + le16_to_cpus(&u.r.wIndex); + le16_to_cpus(&u.r.wLength); + + /* ack the irq */ + net2272_write(dev, IRQSTAT0, 1 << SETUP_PACKET_INTERRUPT); + stat ^= (1 << SETUP_PACKET_INTERRUPT); + + /* watch control traffic at the token level, and force + * synchronization before letting the status phase happen. + */ + ep->is_in = (u.r.bRequestType & USB_DIR_IN) != 0; + if (ep->is_in) { + scratch = (1 << DATA_PACKET_TRANSMITTED_INTERRUPT_ENABLE) + | (1 << DATA_OUT_TOKEN_INTERRUPT_ENABLE) + | (1 << DATA_IN_TOKEN_INTERRUPT_ENABLE); + stop_out_naking(ep); + } else + scratch = (1 << DATA_PACKET_RECEIVED_INTERRUPT_ENABLE) + | (1 << DATA_OUT_TOKEN_INTERRUPT_ENABLE) + | (1 << DATA_IN_TOKEN_INTERRUPT_ENABLE); + net2272_ep_write(ep, EP_IRQENB, scratch); + + if ((u.r.bRequestType & USB_TYPE_MASK) != USB_TYPE_STANDARD) + goto delegate; + switch (u.r.bRequest) { + case USB_REQ_GET_STATUS: { + struct net2272_ep *e; + u16 status = 0; + + switch (u.r.bRequestType & USB_RECIP_MASK) { + case USB_RECIP_ENDPOINT: + e = net2272_get_ep_by_addr(dev, u.r.wIndex); + if (!e || u.r.wLength > 2) + goto do_stall; + if (net2272_ep_read(e, EP_RSPSET) & (1 << ENDPOINT_HALT)) + status = __constant_cpu_to_le16(1); + else + status = __constant_cpu_to_le16(0); + + /* don't bother with a request object! */ + net2272_ep_write(&dev->ep[0], EP_IRQENB, 0); + writew(status, net2272_reg_addr(dev, EP_DATA)); + set_fifo_bytecount(&dev->ep[0], 0); + allow_status(ep); + dev_vdbg(dev->dev, "%s stat %02x\n", + ep->ep.name, status); + goto next_endpoints; + case USB_RECIP_DEVICE: + if (u.r.wLength > 2) + goto do_stall; + if (dev->is_selfpowered) + status = (1 << USB_DEVICE_SELF_POWERED); + + /* don't bother with a request object! */ + net2272_ep_write(&dev->ep[0], EP_IRQENB, 0); + writew(status, net2272_reg_addr(dev, EP_DATA)); + set_fifo_bytecount(&dev->ep[0], 0); + allow_status(ep); + dev_vdbg(dev->dev, "device stat %02x\n", status); + goto next_endpoints; + case USB_RECIP_INTERFACE: + if (u.r.wLength > 2) + goto do_stall; + + /* don't bother with a request object! */ + net2272_ep_write(&dev->ep[0], EP_IRQENB, 0); + writew(status, net2272_reg_addr(dev, EP_DATA)); + set_fifo_bytecount(&dev->ep[0], 0); + allow_status(ep); + dev_vdbg(dev->dev, "interface status %02x\n", status); + goto next_endpoints; + } + + break; + } + case USB_REQ_CLEAR_FEATURE: { + struct net2272_ep *e; + + if (u.r.bRequestType != USB_RECIP_ENDPOINT) + goto delegate; + if (u.r.wValue != USB_ENDPOINT_HALT || + u.r.wLength != 0) + goto do_stall; + e = net2272_get_ep_by_addr(dev, u.r.wIndex); + if (!e) + goto do_stall; + if (e->wedged) { + dev_vdbg(dev->dev, "%s wedged, halt not cleared\n", + ep->ep.name); + } else { + dev_vdbg(dev->dev, "%s clear halt\n", ep->ep.name); + clear_halt(e); + } + allow_status(ep); + goto next_endpoints; + } + case USB_REQ_SET_FEATURE: { + struct net2272_ep *e; + + if (u.r.bRequestType == USB_RECIP_DEVICE) { + if (u.r.wIndex != NORMAL_OPERATION) + net2272_set_test_mode(dev, (u.r.wIndex >> 8)); + allow_status(ep); + dev_vdbg(dev->dev, "test mode: %d\n", u.r.wIndex); + goto next_endpoints; + } else if (u.r.bRequestType != USB_RECIP_ENDPOINT) + goto delegate; + if (u.r.wValue != USB_ENDPOINT_HALT || + u.r.wLength != 0) + goto do_stall; + e = net2272_get_ep_by_addr(dev, u.r.wIndex); + if (!e) + goto do_stall; + set_halt(e); + allow_status(ep); + dev_vdbg(dev->dev, "%s set halt\n", ep->ep.name); + goto next_endpoints; + } + case USB_REQ_SET_ADDRESS: { + net2272_write(dev, OURADDR, u.r.wValue & 0xff); + allow_status(ep); + break; + } + default: + delegate: + dev_vdbg(dev->dev, "setup %02x.%02x v%04x i%04x " + "ep_cfg %08x\n", + u.r.bRequestType, u.r.bRequest, + u.r.wValue, u.r.wIndex, + net2272_ep_read(ep, EP_CFG)); + spin_unlock(&dev->lock); + tmp = dev->driver->setup(&dev->gadget, &u.r); + spin_lock(&dev->lock); + } + + /* stall ep0 on error */ + if (tmp < 0) { + do_stall: + dev_vdbg(dev->dev, "req %02x.%02x protocol STALL; stat %d\n", + u.r.bRequestType, u.r.bRequest, tmp); + dev->protocol_stall = 1; + } + /* endpoint dma irq? */ + } else if (stat & (1 << DMA_DONE_INTERRUPT)) { + net2272_cancel_dma(dev); + net2272_write(dev, IRQSTAT0, 1 << DMA_DONE_INTERRUPT); + stat &= ~(1 << DMA_DONE_INTERRUPT); + num = (net2272_read(dev, DMAREQ) & (1 << DMA_ENDPOINT_SELECT)) + ? 2 : 1; + + ep = &dev->ep[num]; + net2272_handle_dma(ep); + } + + next_endpoints: + /* endpoint data irq? */ + scratch = stat & 0x0f; + stat &= ~0x0f; + for (num = 0; scratch; num++) { + u8 t; + + /* does this endpoint's FIFO and queue need tending? */ + t = 1 << num; + if ((scratch & t) == 0) + continue; + scratch ^= t; + + ep = &dev->ep[num]; + net2272_handle_ep(ep); + } + + /* some interrupts we can just ignore */ + stat &= ~(1 << SOF_INTERRUPT); + + if (stat) + dev_dbg(dev->dev, "unhandled irqstat0 %02x\n", stat); +} + +static void +net2272_handle_stat1_irqs(struct net2272 *dev, u8 stat) +{ + u8 tmp, mask; + + /* after disconnect there's nothing else to do! */ + tmp = (1 << VBUS_INTERRUPT) | (1 << ROOT_PORT_RESET_INTERRUPT); + mask = (1 << USB_HIGH_SPEED) | (1 << USB_FULL_SPEED); + + if (stat & tmp) { + net2272_write(dev, IRQSTAT1, tmp); + if ((((stat & (1 << ROOT_PORT_RESET_INTERRUPT)) && + ((net2272_read(dev, USBCTL1) & mask) == 0)) + || ((net2272_read(dev, USBCTL1) & (1 << VBUS_PIN)) + == 0)) + && (dev->gadget.speed != USB_SPEED_UNKNOWN)) { + dev_dbg(dev->dev, "disconnect %s\n", + dev->driver->driver.name); + stop_activity(dev, dev->driver); + net2272_ep0_start(dev); + return; + } + stat &= ~tmp; + + if (!stat) + return; + } + + tmp = (1 << SUSPEND_REQUEST_CHANGE_INTERRUPT); + if (stat & tmp) { + net2272_write(dev, IRQSTAT1, tmp); + if (stat & (1 << SUSPEND_REQUEST_INTERRUPT)) { + if (dev->driver->suspend) + dev->driver->suspend(&dev->gadget); + if (!enable_suspend) { + stat &= ~(1 << SUSPEND_REQUEST_INTERRUPT); + dev_dbg(dev->dev, "Suspend disabled, ignoring\n"); + } + } else { + if (dev->driver->resume) + dev->driver->resume(&dev->gadget); + } + stat &= ~tmp; + } + + /* clear any other status/irqs */ + if (stat) + net2272_write(dev, IRQSTAT1, stat); + + /* some status we can just ignore */ + stat &= ~((1 << CONTROL_STATUS_INTERRUPT) + | (1 << SUSPEND_REQUEST_INTERRUPT) + | (1 << RESUME_INTERRUPT)); + if (!stat) + return; + else + dev_dbg(dev->dev, "unhandled irqstat1 %02x\n", stat); +} + +static irqreturn_t net2272_irq(int irq, void *_dev) +{ + struct net2272 *dev = _dev; +#if defined(PLX_PCI_RDK) || defined(PLX_PCI_RDK2) + u32 intcsr; +#endif +#if defined(PLX_PCI_RDK) + u8 dmareq; +#endif + spin_lock(&dev->lock); +#if defined(PLX_PCI_RDK) + intcsr = readl(dev->rdk1.plx9054_base_addr + INTCSR); + + if ((intcsr & LOCAL_INTERRUPT_TEST) == LOCAL_INTERRUPT_TEST) { + writel(intcsr & ~(1 << PCI_INTERRUPT_ENABLE), + dev->rdk1.plx9054_base_addr + INTCSR); + net2272_handle_stat1_irqs(dev, net2272_read(dev, IRQSTAT1)); + net2272_handle_stat0_irqs(dev, net2272_read(dev, IRQSTAT0)); + intcsr = readl(dev->rdk1.plx9054_base_addr + INTCSR); + writel(intcsr | (1 << PCI_INTERRUPT_ENABLE), + dev->rdk1.plx9054_base_addr + INTCSR); + } + if ((intcsr & DMA_CHANNEL_0_TEST) == DMA_CHANNEL_0_TEST) { + writeb((1 << CHANNEL_CLEAR_INTERRUPT | (0 << CHANNEL_ENABLE)), + dev->rdk1.plx9054_base_addr + DMACSR0); + + dmareq = net2272_read(dev, DMAREQ); + if (dmareq & 0x01) + net2272_handle_dma(&dev->ep[2]); + else + net2272_handle_dma(&dev->ep[1]); + } +#endif +#if defined(PLX_PCI_RDK2) + /* see if PCI int for us by checking irqstat */ + intcsr = readl(dev->rdk2.fpga_base_addr + RDK2_IRQSTAT); + if (!intcsr & (1 << NET2272_PCI_IRQ)) + return IRQ_NONE; + /* check dma interrupts */ +#endif + /* Platform/devcice interrupt handler */ +#if !defined(PLX_PCI_RDK) + net2272_handle_stat1_irqs(dev, net2272_read(dev, IRQSTAT1)); + net2272_handle_stat0_irqs(dev, net2272_read(dev, IRQSTAT0)); +#endif + spin_unlock(&dev->lock); + + return IRQ_HANDLED; +} + +static int net2272_present(struct net2272 *dev) +{ + /* + * Quick test to see if CPU can communicate properly with the NET2272. + * Verifies connection using writes and reads to write/read and + * read-only registers. + * + * This routine is strongly recommended especially during early bring-up + * of new hardware, however for designs that do not apply Power On System + * Tests (POST) it may discarded (or perhaps minimized). + */ + unsigned int ii; + u8 val, refval; + + /* Verify NET2272 write/read SCRATCH register can write and read */ + refval = net2272_read(dev, SCRATCH); + for (ii = 0; ii < 0x100; ii += 7) { + net2272_write(dev, SCRATCH, ii); + val = net2272_read(dev, SCRATCH); + if (val != ii) { + dev_dbg(dev->dev, + "%s: write/read SCRATCH register test failed: " + "wrote:0x%2.2x, read:0x%2.2x\n", + __func__, ii, val); + return -EINVAL; + } + } + /* To be nice, we write the original SCRATCH value back: */ + net2272_write(dev, SCRATCH, refval); + + /* Verify NET2272 CHIPREV register is read-only: */ + refval = net2272_read(dev, CHIPREV_2272); + for (ii = 0; ii < 0x100; ii += 7) { + net2272_write(dev, CHIPREV_2272, ii); + val = net2272_read(dev, CHIPREV_2272); + if (val != refval) { + dev_dbg(dev->dev, + "%s: write/read CHIPREV register test failed: " + "wrote 0x%2.2x, read:0x%2.2x expected:0x%2.2x\n", + __func__, ii, val, refval); + return -EINVAL; + } + } + + /* + * Verify NET2272's "NET2270 legacy revision" register + * - NET2272 has two revision registers. The NET2270 legacy revision + * register should read the same value, regardless of the NET2272 + * silicon revision. The legacy register applies to NET2270 + * firmware being applied to the NET2272. + */ + val = net2272_read(dev, CHIPREV_LEGACY); + if (val != NET2270_LEGACY_REV) { + /* + * Unexpected legacy revision value + * - Perhaps the chip is a NET2270? + */ + dev_dbg(dev->dev, + "%s: WARNING: UNEXPECTED NET2272 LEGACY REGISTER VALUE:\n" + " - CHIPREV_LEGACY: expected 0x%2.2x, got:0x%2.2x. (Not NET2272?)\n", + __func__, NET2270_LEGACY_REV, val); + return -EINVAL; + } + + /* + * Verify NET2272 silicon revision + * - This revision register is appropriate for the silicon version + * of the NET2272 + */ + val = net2272_read(dev, CHIPREV_2272); + switch (val) { + case CHIPREV_NET2272_R1: + /* + * NET2272 Rev 1 has DMA related errata: + * - Newer silicon (Rev 1A or better) required + */ + dev_dbg(dev->dev, + "%s: Rev 1 detected: newer silicon recommended for DMA support\n", + __func__); + break; + case CHIPREV_NET2272_R1A: + break; + default: + /* NET2272 silicon version *may* not work with this firmware */ + dev_dbg(dev->dev, + "%s: unexpected silicon revision register value: " + " CHIPREV_2272: 0x%2.2x\n", + __func__, val); + /* + * Return Success, even though the chip rev is not an expected value + * - Older, pre-built firmware can attempt to operate on newer silicon + * - Often, new silicon is perfectly compatible + */ + } + + /* Success: NET2272 checks out OK */ + return 0; +} + +static void +net2272_gadget_release(struct device *_dev) +{ + struct net2272 *dev = dev_get_drvdata(_dev); + kfree(dev); +} + +/*---------------------------------------------------------------------------*/ + +static void __devexit +net2272_remove(struct net2272 *dev) +{ + /* start with the driver above us */ + if (dev->driver) { + /* should have been done already by driver model core */ + dev_warn(dev->dev, "pci remove, driver '%s' is still registered\n", + dev->driver->driver.name); + usb_gadget_unregister_driver(dev->driver); + } + + free_irq(dev->irq, dev); + iounmap(dev->base_addr); + + device_unregister(&dev->gadget.dev); + device_remove_file(dev->dev, &dev_attr_registers); + + dev_info(dev->dev, "unbind\n"); + the_controller = NULL; +} + +static struct net2272 * __devinit +net2272_probe_init(struct device *dev, unsigned int irq) +{ + struct net2272 *ret; + + if (the_controller) { + dev_warn(dev, "ignoring\n"); + return ERR_PTR(-EBUSY); + } + + if (!irq) { + dev_dbg(dev, "No IRQ!\n"); + return ERR_PTR(-ENODEV); + } + + /* alloc, and start init */ + ret = kzalloc(sizeof(*ret), GFP_KERNEL); + if (!ret) + return ERR_PTR(-ENOMEM); + + spin_lock_init(&ret->lock); + ret->irq = irq; + ret->dev = dev; + ret->gadget.ops = &net2272_ops; + ret->gadget.is_dualspeed = 1; + + /* the "gadget" abstracts/virtualizes the controller */ + dev_set_name(&ret->gadget.dev, "gadget"); + ret->gadget.dev.parent = dev; + ret->gadget.dev.dma_mask = dev->dma_mask; + ret->gadget.dev.release = net2272_gadget_release; + ret->gadget.name = driver_name; + + return ret; +} + +static int __devinit +net2272_probe_fin(struct net2272 *dev, unsigned int irqflags) +{ + int ret; + + /* See if there... */ + if (net2272_present(dev)) { + dev_warn(dev->dev, "2272 not found!\n"); + ret = -ENODEV; + goto err; + } + + net2272_usb_reset(dev); + net2272_usb_reinit(dev); + + ret = request_irq(dev->irq, net2272_irq, irqflags, driver_name, dev); + if (ret) { + dev_err(dev->dev, "request interrupt %i failed\n", dev->irq); + goto err; + } + + dev->chiprev = net2272_read(dev, CHIPREV_2272); + + /* done */ + dev_info(dev->dev, "%s\n", driver_desc); + dev_info(dev->dev, "irq %i, mem %p, chip rev %04x, dma %s\n", + dev->irq, dev->base_addr, dev->chiprev, + dma_mode_string()); + dev_info(dev->dev, "version: %s\n", driver_vers); + + the_controller = dev; + + ret = device_register(&dev->gadget.dev); + if (ret) + goto err_irq; + ret = device_create_file(dev->dev, &dev_attr_registers); + if (ret) + goto err_dev_reg; + + return 0; + + err_dev_reg: + device_unregister(&dev->gadget.dev); + err_irq: + free_irq(dev->irq, dev); + err: + return ret; +} + +#ifdef CONFIG_PCI + +/* + * wrap this driver around the specified device, but + * don't respond over USB until a gadget driver binds to us + */ + +static int __devinit +net2272_rdk1_probe(struct pci_dev *pdev, struct net2272 *dev) +{ + unsigned long resource, len, tmp; + void __iomem *mem_mapped_addr[4]; + int ret, i; + + /* + * BAR 0 holds PLX 9054 config registers + * BAR 1 is i/o memory; unused here + * BAR 2 holds EPLD config registers + * BAR 3 holds NET2272 registers + */ + + /* Find and map all address spaces */ + for (i = 0; i < 4; ++i) { + if (i == 1) + continue; /* BAR1 unused */ + + resource = pci_resource_start(pdev, i); + len = pci_resource_len(pdev, i); + + if (!request_mem_region(resource, len, driver_name)) { + dev_dbg(dev->dev, "controller already in use\n"); + ret = -EBUSY; + goto err; + } + + mem_mapped_addr[i] = ioremap_nocache(resource, len); + if (mem_mapped_addr[i] == NULL) { + release_mem_region(resource, len); + dev_dbg(dev->dev, "can't map memory\n"); + ret = -EFAULT; + goto err; + } + } + + dev->rdk1.plx9054_base_addr = mem_mapped_addr[0]; + dev->rdk1.epld_base_addr = mem_mapped_addr[2]; + dev->base_addr = mem_mapped_addr[3]; + + /* Set PLX 9054 bus width (16 bits) */ + tmp = readl(dev->rdk1.plx9054_base_addr + LBRD1); + writel((tmp & ~(3 << MEMORY_SPACE_LOCAL_BUS_WIDTH)) | W16_BIT, + dev->rdk1.plx9054_base_addr + LBRD1); + + /* Enable PLX 9054 Interrupts */ + writel(readl(dev->rdk1.plx9054_base_addr + INTCSR) | + (1 << PCI_INTERRUPT_ENABLE) | + (1 << LOCAL_INTERRUPT_INPUT_ENABLE), + dev->rdk1.plx9054_base_addr + INTCSR); + + writeb((1 << CHANNEL_CLEAR_INTERRUPT | (0 << CHANNEL_ENABLE)), + dev->rdk1.plx9054_base_addr + DMACSR0); + + /* reset */ + writeb((1 << EPLD_DMA_ENABLE) | + (1 << DMA_CTL_DACK) | + (1 << DMA_TIMEOUT_ENABLE) | + (1 << USER) | + (0 << MPX_MODE) | + (1 << BUSWIDTH) | + (1 << NET2272_RESET), + dev->base_addr + EPLD_IO_CONTROL_REGISTER); + + mb(); + writeb(readb(dev->base_addr + EPLD_IO_CONTROL_REGISTER) & + ~(1 << NET2272_RESET), + dev->base_addr + EPLD_IO_CONTROL_REGISTER); + udelay(200); + + return 0; + + err: + while (--i >= 0) { + iounmap(mem_mapped_addr[i]); + release_mem_region(pci_resource_start(pdev, i), + pci_resource_len(pdev, i)); + } + + return ret; +} + +static int __devinit +net2272_rdk2_probe(struct pci_dev *pdev, struct net2272 *dev) +{ + unsigned long resource, len; + void __iomem *mem_mapped_addr[2]; + int ret, i; + + /* + * BAR 0 holds FGPA config registers + * BAR 1 holds NET2272 registers + */ + + /* Find and map all address spaces, bar2-3 unused in rdk 2 */ + for (i = 0; i < 2; ++i) { + resource = pci_resource_start(pdev, i); + len = pci_resource_len(pdev, i); + + if (!request_mem_region(resource, len, driver_name)) { + dev_dbg(dev->dev, "controller already in use\n"); + ret = -EBUSY; + goto err; + } + + mem_mapped_addr[i] = ioremap_nocache(resource, len); + if (mem_mapped_addr[i] == NULL) { + release_mem_region(resource, len); + dev_dbg(dev->dev, "can't map memory\n"); + ret = -EFAULT; + goto err; + } + } + + dev->rdk2.fpga_base_addr = mem_mapped_addr[0]; + dev->base_addr = mem_mapped_addr[1]; + + mb(); + /* Set 2272 bus width (16 bits) and reset */ + writel((1 << CHIP_RESET), dev->rdk2.fpga_base_addr + RDK2_LOCCTLRDK); + udelay(200); + writel((1 << BUS_WIDTH), dev->rdk2.fpga_base_addr + RDK2_LOCCTLRDK); + /* Print fpga version number */ + dev_info(dev->dev, "RDK2 FPGA version %08x\n", + readl(dev->rdk2.fpga_base_addr + RDK2_FPGAREV)); + /* Enable FPGA Interrupts */ + writel((1 << NET2272_PCI_IRQ), dev->rdk2.fpga_base_addr + RDK2_IRQENB); + + return 0; + + err: + while (--i >= 0) { + iounmap(mem_mapped_addr[i]); + release_mem_region(pci_resource_start(pdev, i), + pci_resource_len(pdev, i)); + } + + return ret; +} + +static int __devinit +net2272_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) +{ + struct net2272 *dev; + int ret; + + dev = net2272_probe_init(&pdev->dev, pdev->irq); + if (IS_ERR(dev)) + return PTR_ERR(dev); + dev->dev_id = pdev->device; + + if (pci_enable_device(pdev) < 0) { + ret = -ENODEV; + goto err_free; + } + + pci_set_master(pdev); + + switch (pdev->device) { + case PCI_DEVICE_ID_RDK1: ret = net2272_rdk1_probe(pdev, dev); break; + case PCI_DEVICE_ID_RDK2: ret = net2272_rdk2_probe(pdev, dev); break; + default: BUG(); + } + if (ret) + goto err_pci; + + ret = net2272_probe_fin(dev, 0); + if (ret) + goto err_pci; + + pci_set_drvdata(pdev, dev); + + return 0; + + err_pci: + pci_disable_device(pdev); + err_free: + kfree(dev); + + return ret; +} + +static void __devexit +net2272_rdk1_remove(struct pci_dev *pdev, struct net2272 *dev) +{ + int i; + + /* disable PLX 9054 interrupts */ + writel(readl(dev->rdk1.plx9054_base_addr + INTCSR) & + ~(1 << PCI_INTERRUPT_ENABLE), + dev->rdk1.plx9054_base_addr + INTCSR); + + /* clean up resources allocated during probe() */ + iounmap(dev->rdk1.plx9054_base_addr); + iounmap(dev->rdk1.epld_base_addr); + + for (i = 0; i < 4; ++i) { + if (i == 1) + continue; /* BAR1 unused */ + release_mem_region(pci_resource_start(pdev, i), + pci_resource_len(pdev, i)); + } +} + +static void __devexit +net2272_rdk2_remove(struct pci_dev *pdev, struct net2272 *dev) +{ + int i; + + /* disable fpga interrupts + writel(readl(dev->rdk1.plx9054_base_addr + INTCSR) & + ~(1 << PCI_INTERRUPT_ENABLE), + dev->rdk1.plx9054_base_addr + INTCSR); + */ + + /* clean up resources allocated during probe() */ + iounmap(dev->rdk2.fpga_base_addr); + + for (i = 0; i < 2; ++i) + release_mem_region(pci_resource_start(pdev, i), + pci_resource_len(pdev, i)); +} + +static void __devexit +net2272_pci_remove(struct pci_dev *pdev) +{ + struct net2272 *dev = pci_get_drvdata(pdev); + + net2272_remove(dev); + + switch (pdev->device) { + case PCI_DEVICE_ID_RDK1: net2272_rdk1_remove(pdev, dev); break; + case PCI_DEVICE_ID_RDK2: net2272_rdk2_remove(pdev, dev); break; + default: BUG(); + } + + pci_disable_device(pdev); + + kfree(dev); +} + +/* Table of matching PCI IDs */ +static struct pci_device_id __devinitdata pci_ids[] = { + { /* RDK 1 card */ + .class = ((PCI_CLASS_BRIDGE_OTHER << 8) | 0xfe), + .class_mask = 0, + .vendor = PCI_VENDOR_ID_PLX, + .device = PCI_DEVICE_ID_RDK1, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + }, + { /* RDK 2 card */ + .class = ((PCI_CLASS_BRIDGE_OTHER << 8) | 0xfe), + .class_mask = 0, + .vendor = PCI_VENDOR_ID_PLX, + .device = PCI_DEVICE_ID_RDK2, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + }, + { } +}; +MODULE_DEVICE_TABLE(pci, pci_ids); + +static struct pci_driver net2272_pci_driver = { + .name = driver_name, + .id_table = pci_ids, + + .probe = net2272_pci_probe, + .remove = __devexit_p(net2272_pci_remove), +}; + +#else +# define pci_register_driver(x) 1 +# define pci_unregister_driver(x) 1 +#endif + +/*---------------------------------------------------------------------------*/ + +static int __devinit +net2272_plat_probe(struct platform_device *pdev) +{ + struct net2272 *dev; + int ret; + unsigned int irqflags; + resource_size_t base, len; + struct resource *iomem, *iomem_bus, *irq_res; + + irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + iomem_bus = platform_get_resource(pdev, IORESOURCE_BUS, 0); + if (!irq_res || !iomem) { + dev_err(&pdev->dev, "must provide irq/base addr"); + return -EINVAL; + } + + dev = net2272_probe_init(&pdev->dev, irq_res->start); + if (IS_ERR(dev)) + return PTR_ERR(dev); + + irqflags = 0; + if (irq_res->flags & IORESOURCE_IRQ_HIGHEDGE) + irqflags |= IRQF_TRIGGER_RISING; + if (irq_res->flags & IORESOURCE_IRQ_LOWEDGE) + irqflags |= IRQF_TRIGGER_FALLING; + if (irq_res->flags & IORESOURCE_IRQ_HIGHLEVEL) + irqflags |= IRQF_TRIGGER_HIGH; + if (irq_res->flags & IORESOURCE_IRQ_LOWLEVEL) + irqflags |= IRQF_TRIGGER_LOW; + + base = iomem->start; + len = resource_size(iomem); + if (iomem_bus) + dev->base_shift = iomem_bus->start; + + if (!request_mem_region(base, len, driver_name)) { + dev_dbg(dev->dev, "get request memory region!\n"); + ret = -EBUSY; + goto err; + } + dev->base_addr = ioremap_nocache(base, len); + if (!dev->base_addr) { + dev_dbg(dev->dev, "can't map memory\n"); + ret = -EFAULT; + goto err_req; + } + + ret = net2272_probe_fin(dev, IRQF_TRIGGER_LOW); + if (ret) + goto err_io; + + platform_set_drvdata(pdev, dev); + dev_info(&pdev->dev, "running in 16-bit, %sbyte swap local bus mode\n", + (net2272_read(dev, LOCCTL) & (1 << BYTE_SWAP)) ? "" : "no "); + + the_controller = dev; + + return 0; + + err_io: + iounmap(dev->base_addr); + err_req: + release_mem_region(base, len); + err: + return ret; +} + +static int __devexit +net2272_plat_remove(struct platform_device *pdev) +{ + struct net2272 *dev = platform_get_drvdata(pdev); + + net2272_remove(dev); + + release_mem_region(pdev->resource[0].start, + resource_size(&pdev->resource[0])); + + kfree(dev); + + return 0; +} + +static struct platform_driver net2272_plat_driver = { + .probe = net2272_plat_probe, + .remove = __devexit_p(net2272_plat_remove), + .driver = { + .name = driver_name, + .owner = THIS_MODULE, + }, + /* FIXME .suspend, .resume */ +}; + +static int __init net2272_init(void) +{ + return pci_register_driver(&net2272_pci_driver) & + platform_driver_register(&net2272_plat_driver); +} +module_init(net2272_init); + +static void __exit net2272_cleanup(void) +{ + pci_unregister_driver(&net2272_pci_driver); + platform_driver_unregister(&net2272_plat_driver); +} +module_exit(net2272_cleanup); + +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_AUTHOR("PLX Technology, Inc."); +MODULE_LICENSE("GPL"); diff --git a/drivers/usb/gadget/net2272.h b/drivers/usb/gadget/net2272.h new file mode 100644 index 00000000000..e5950578935 --- /dev/null +++ b/drivers/usb/gadget/net2272.h @@ -0,0 +1,601 @@ +/* + * PLX NET2272 high/full speed USB device controller + * + * Copyright (C) 2005-2006 PLX Technology, Inc. + * Copyright (C) 2006-2011 Analog Devices, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __NET2272_H__ +#define __NET2272_H__ + +/* Main Registers */ +#define REGADDRPTR 0x00 +#define REGDATA 0x01 +#define IRQSTAT0 0x02 +#define ENDPOINT_0_INTERRUPT 0 +#define ENDPOINT_A_INTERRUPT 1 +#define ENDPOINT_B_INTERRUPT 2 +#define ENDPOINT_C_INTERRUPT 3 +#define VIRTUALIZED_ENDPOINT_INTERRUPT 4 +#define SETUP_PACKET_INTERRUPT 5 +#define DMA_DONE_INTERRUPT 6 +#define SOF_INTERRUPT 7 +#define IRQSTAT1 0x03 +#define CONTROL_STATUS_INTERRUPT 1 +#define VBUS_INTERRUPT 2 +#define SUSPEND_REQUEST_INTERRUPT 3 +#define SUSPEND_REQUEST_CHANGE_INTERRUPT 4 +#define RESUME_INTERRUPT 5 +#define ROOT_PORT_RESET_INTERRUPT 6 +#define RESET_STATUS 7 +#define PAGESEL 0x04 +#define DMAREQ 0x1c +#define DMA_ENDPOINT_SELECT 0 +#define DREQ_POLARITY 1 +#define DACK_POLARITY 2 +#define EOT_POLARITY 3 +#define DMA_CONTROL_DACK 4 +#define DMA_REQUEST_ENABLE 5 +#define DMA_REQUEST 6 +#define DMA_BUFFER_VALID 7 +#define SCRATCH 0x1d +#define IRQENB0 0x20 +#define ENDPOINT_0_INTERRUPT_ENABLE 0 +#define ENDPOINT_A_INTERRUPT_ENABLE 1 +#define ENDPOINT_B_INTERRUPT_ENABLE 2 +#define ENDPOINT_C_INTERRUPT_ENABLE 3 +#define VIRTUALIZED_ENDPOINT_INTERRUPT_ENABLE 4 +#define SETUP_PACKET_INTERRUPT_ENABLE 5 +#define DMA_DONE_INTERRUPT_ENABLE 6 +#define SOF_INTERRUPT_ENABLE 7 +#define IRQENB1 0x21 +#define VBUS_INTERRUPT_ENABLE 2 +#define SUSPEND_REQUEST_INTERRUPT_ENABLE 3 +#define SUSPEND_REQUEST_CHANGE_INTERRUPT_ENABLE 4 +#define RESUME_INTERRUPT_ENABLE 5 +#define ROOT_PORT_RESET_INTERRUPT_ENABLE 6 +#define LOCCTL 0x22 +#define DATA_WIDTH 0 +#define LOCAL_CLOCK_OUTPUT 1 +#define LOCAL_CLOCK_OUTPUT_OFF 0 +#define LOCAL_CLOCK_OUTPUT_3_75MHZ 1 +#define LOCAL_CLOCK_OUTPUT_7_5MHZ 2 +#define LOCAL_CLOCK_OUTPUT_15MHZ 3 +#define LOCAL_CLOCK_OUTPUT_30MHZ 4 +#define LOCAL_CLOCK_OUTPUT_60MHZ 5 +#define DMA_SPLIT_BUS_MODE 4 +#define BYTE_SWAP 5 +#define BUFFER_CONFIGURATION 6 +#define BUFFER_CONFIGURATION_EPA512_EPB512 0 +#define BUFFER_CONFIGURATION_EPA1024_EPB512 1 +#define BUFFER_CONFIGURATION_EPA1024_EPB1024 2 +#define BUFFER_CONFIGURATION_EPA1024DB 3 +#define CHIPREV_LEGACY 0x23 +#define NET2270_LEGACY_REV 0x40 +#define LOCCTL1 0x24 +#define DMA_MODE 0 +#define SLOW_DREQ 0 +#define FAST_DREQ 1 +#define BURST_MODE 2 +#define DMA_DACK_ENABLE 2 +#define CHIPREV_2272 0x25 +#define CHIPREV_NET2272_R1 0x10 +#define CHIPREV_NET2272_R1A 0x11 +/* USB Registers */ +#define USBCTL0 0x18 +#define IO_WAKEUP_ENABLE 1 +#define USB_DETECT_ENABLE 3 +#define USB_ROOT_PORT_WAKEUP_ENABLE 5 +#define USBCTL1 0x19 +#define VBUS_PIN 0 +#define USB_FULL_SPEED 1 +#define USB_HIGH_SPEED 2 +#define GENERATE_RESUME 3 +#define VIRTUAL_ENDPOINT_ENABLE 4 +#define FRAME0 0x1a +#define FRAME1 0x1b +#define OURADDR 0x30 +#define FORCE_IMMEDIATE 7 +#define USBDIAG 0x31 +#define FORCE_TRANSMIT_CRC_ERROR 0 +#define PREVENT_TRANSMIT_BIT_STUFF 1 +#define FORCE_RECEIVE_ERROR 2 +#define FAST_TIMES 4 +#define USBTEST 0x32 +#define TEST_MODE_SELECT 0 +#define NORMAL_OPERATION 0 +#define TEST_J 1 +#define TEST_K 2 +#define TEST_SE0_NAK 3 +#define TEST_PACKET 4 +#define TEST_FORCE_ENABLE 5 +#define XCVRDIAG 0x33 +#define FORCE_FULL_SPEED 2 +#define FORCE_HIGH_SPEED 3 +#define OPMODE 4 +#define NORMAL_OPERATION 0 +#define NON_DRIVING 1 +#define DISABLE_BITSTUFF_AND_NRZI_ENCODE 2 +#define LINESTATE 6 +#define SE0_STATE 0 +#define J_STATE 1 +#define K_STATE 2 +#define SE1_STATE 3 +#define VIRTOUT0 0x34 +#define VIRTOUT1 0x35 +#define VIRTIN0 0x36 +#define VIRTIN1 0x37 +#define SETUP0 0x40 +#define SETUP1 0x41 +#define SETUP2 0x42 +#define SETUP3 0x43 +#define SETUP4 0x44 +#define SETUP5 0x45 +#define SETUP6 0x46 +#define SETUP7 0x47 +/* Endpoint Registers (Paged via PAGESEL) */ +#define EP_DATA 0x05 +#define EP_STAT0 0x06 +#define DATA_IN_TOKEN_INTERRUPT 0 +#define DATA_OUT_TOKEN_INTERRUPT 1 +#define DATA_PACKET_TRANSMITTED_INTERRUPT 2 +#define DATA_PACKET_RECEIVED_INTERRUPT 3 +#define SHORT_PACKET_TRANSFERRED_INTERRUPT 4 +#define NAK_OUT_PACKETS 5 +#define BUFFER_EMPTY 6 +#define BUFFER_FULL 7 +#define EP_STAT1 0x07 +#define TIMEOUT 0 +#define USB_OUT_ACK_SENT 1 +#define USB_OUT_NAK_SENT 2 +#define USB_IN_ACK_RCVD 3 +#define USB_IN_NAK_SENT 4 +#define USB_STALL_SENT 5 +#define LOCAL_OUT_ZLP 6 +#define BUFFER_FLUSH 7 +#define EP_TRANSFER0 0x08 +#define EP_TRANSFER1 0x09 +#define EP_TRANSFER2 0x0a +#define EP_IRQENB 0x0b +#define DATA_IN_TOKEN_INTERRUPT_ENABLE 0 +#define DATA_OUT_TOKEN_INTERRUPT_ENABLE 1 +#define DATA_PACKET_TRANSMITTED_INTERRUPT_ENABLE 2 +#define DATA_PACKET_RECEIVED_INTERRUPT_ENABLE 3 +#define SHORT_PACKET_TRANSFERRED_INTERRUPT_ENABLE 4 +#define EP_AVAIL0 0x0c +#define EP_AVAIL1 0x0d +#define EP_RSPCLR 0x0e +#define EP_RSPSET 0x0f +#define ENDPOINT_HALT 0 +#define ENDPOINT_TOGGLE 1 +#define NAK_OUT_PACKETS_MODE 2 +#define CONTROL_STATUS_PHASE_HANDSHAKE 3 +#define INTERRUPT_MODE 4 +#define AUTOVALIDATE 5 +#define HIDE_STATUS_PHASE 6 +#define ALT_NAK_OUT_PACKETS 7 +#define EP_MAXPKT0 0x28 +#define EP_MAXPKT1 0x29 +#define ADDITIONAL_TRANSACTION_OPPORTUNITIES 3 +#define NONE_ADDITIONAL_TRANSACTION 0 +#define ONE_ADDITIONAL_TRANSACTION 1 +#define TWO_ADDITIONAL_TRANSACTION 2 +#define EP_CFG 0x2a +#define ENDPOINT_NUMBER 0 +#define ENDPOINT_DIRECTION 4 +#define ENDPOINT_TYPE 5 +#define ENDPOINT_ENABLE 7 +#define EP_HBW 0x2b +#define HIGH_BANDWIDTH_OUT_TRANSACTION_PID 0 +#define DATA0_PID 0 +#define DATA1_PID 1 +#define DATA2_PID 2 +#define MDATA_PID 3 +#define EP_BUFF_STATES 0x2c +#define BUFFER_A_STATE 0 +#define BUFFER_B_STATE 2 +#define BUFF_FREE 0 +#define BUFF_VALID 1 +#define BUFF_LCL 2 +#define BUFF_USB 3 + +/*---------------------------------------------------------------------------*/ + +#define PCI_DEVICE_ID_RDK1 0x9054 + +/* PCI-RDK EPLD Registers */ +#define RDK_EPLD_IO_REGISTER1 0x00000000 +#define RDK_EPLD_USB_RESET 0 +#define RDK_EPLD_USB_POWERDOWN 1 +#define RDK_EPLD_USB_WAKEUP 2 +#define RDK_EPLD_USB_EOT 3 +#define RDK_EPLD_DPPULL 4 +#define RDK_EPLD_IO_REGISTER2 0x00000004 +#define RDK_EPLD_BUSWIDTH 0 +#define RDK_EPLD_USER 2 +#define RDK_EPLD_RESET_INTERRUPT_ENABLE 3 +#define RDK_EPLD_DMA_TIMEOUT_ENABLE 4 +#define RDK_EPLD_STATUS_REGISTER 0x00000008 +#define RDK_EPLD_USB_LRESET 0 +#define RDK_EPLD_REVISION_REGISTER 0x0000000c + +/* PCI-RDK PLX 9054 Registers */ +#define INTCSR 0x68 +#define PCI_INTERRUPT_ENABLE 8 +#define LOCAL_INTERRUPT_INPUT_ENABLE 11 +#define LOCAL_INPUT_INTERRUPT_ACTIVE 15 +#define LOCAL_DMA_CHANNEL_0_INTERRUPT_ENABLE 18 +#define LOCAL_DMA_CHANNEL_1_INTERRUPT_ENABLE 19 +#define DMA_CHANNEL_0_INTERRUPT_ACTIVE 21 +#define DMA_CHANNEL_1_INTERRUPT_ACTIVE 22 +#define CNTRL 0x6C +#define RELOAD_CONFIGURATION_REGISTERS 29 +#define PCI_ADAPTER_SOFTWARE_RESET 30 +#define DMAMODE0 0x80 +#define LOCAL_BUS_WIDTH 0 +#define INTERNAL_WAIT_STATES 2 +#define TA_READY_INPUT_ENABLE 6 +#define LOCAL_BURST_ENABLE 8 +#define SCATTER_GATHER_MODE 9 +#define DONE_INTERRUPT_ENABLE 10 +#define LOCAL_ADDRESSING_MODE 11 +#define DEMAND_MODE 12 +#define DMA_EOT_ENABLE 14 +#define FAST_SLOW_TERMINATE_MODE_SELECT 15 +#define DMA_CHANNEL_INTERRUPT_SELECT 17 +#define DMAPADR0 0x84 +#define DMALADR0 0x88 +#define DMASIZ0 0x8c +#define DMADPR0 0x90 +#define DESCRIPTOR_LOCATION 0 +#define END_OF_CHAIN 1 +#define INTERRUPT_AFTER_TERMINAL_COUNT 2 +#define DIRECTION_OF_TRANSFER 3 +#define DMACSR0 0xa8 +#define CHANNEL_ENABLE 0 +#define CHANNEL_START 1 +#define CHANNEL_ABORT 2 +#define CHANNEL_CLEAR_INTERRUPT 3 +#define CHANNEL_DONE 4 +#define DMATHR 0xb0 +#define LBRD1 0xf8 +#define MEMORY_SPACE_LOCAL_BUS_WIDTH 0 +#define W8_BIT 0 +#define W16_BIT 1 + +/* Special OR'ing of INTCSR bits */ +#define LOCAL_INTERRUPT_TEST \ + ((1 << LOCAL_INPUT_INTERRUPT_ACTIVE) | \ + (1 << LOCAL_INTERRUPT_INPUT_ENABLE)) + +#define DMA_CHANNEL_0_TEST \ + ((1 << DMA_CHANNEL_0_INTERRUPT_ACTIVE) | \ + (1 << LOCAL_DMA_CHANNEL_0_INTERRUPT_ENABLE)) + +#define DMA_CHANNEL_1_TEST \ + ((1 << DMA_CHANNEL_1_INTERRUPT_ACTIVE) | \ + (1 << LOCAL_DMA_CHANNEL_1_INTERRUPT_ENABLE)) + +/* EPLD Registers */ +#define RDK_EPLD_IO_REGISTER1 0x00000000 +#define RDK_EPLD_USB_RESET 0 +#define RDK_EPLD_USB_POWERDOWN 1 +#define RDK_EPLD_USB_WAKEUP 2 +#define RDK_EPLD_USB_EOT 3 +#define RDK_EPLD_DPPULL 4 +#define RDK_EPLD_IO_REGISTER2 0x00000004 +#define RDK_EPLD_BUSWIDTH 0 +#define RDK_EPLD_USER 2 +#define RDK_EPLD_RESET_INTERRUPT_ENABLE 3 +#define RDK_EPLD_DMA_TIMEOUT_ENABLE 4 +#define RDK_EPLD_STATUS_REGISTER 0x00000008 +#define RDK_EPLD_USB_LRESET 0 +#define RDK_EPLD_REVISION_REGISTER 0x0000000c + +#define EPLD_IO_CONTROL_REGISTER 0x400 +#define NET2272_RESET 0 +#define BUSWIDTH 1 +#define MPX_MODE 3 +#define USER 4 +#define DMA_TIMEOUT_ENABLE 5 +#define DMA_CTL_DACK 6 +#define EPLD_DMA_ENABLE 7 +#define EPLD_DMA_CONTROL_REGISTER 0x800 +#define SPLIT_DMA_MODE 0 +#define SPLIT_DMA_DIRECTION 1 +#define SPLIT_DMA_ENABLE 2 +#define SPLIT_DMA_INTERRUPT_ENABLE 3 +#define SPLIT_DMA_INTERRUPT 4 +#define EPLD_DMA_MODE 5 +#define EPLD_DMA_CONTROLLER_ENABLE 7 +#define SPLIT_DMA_ADDRESS_LOW 0xc00 +#define SPLIT_DMA_ADDRESS_HIGH 0x1000 +#define SPLIT_DMA_BYTE_COUNT_LOW 0x1400 +#define SPLIT_DMA_BYTE_COUNT_HIGH 0x1800 +#define EPLD_REVISION_REGISTER 0x1c00 +#define SPLIT_DMA_RAM 0x4000 +#define DMA_RAM_SIZE 0x1000 + +/*---------------------------------------------------------------------------*/ + +#define PCI_DEVICE_ID_RDK2 0x3272 + +/* PCI-RDK version 2 registers */ + +/* Main Control Registers */ + +#define RDK2_IRQENB 0x00 +#define RDK2_IRQSTAT 0x04 +#define PB7 23 +#define PB6 22 +#define PB5 21 +#define PB4 20 +#define PB3 19 +#define PB2 18 +#define PB1 17 +#define PB0 16 +#define GP3 23 +#define GP2 23 +#define GP1 23 +#define GP0 23 +#define DMA_RETRY_ABORT 6 +#define DMA_PAUSE_DONE 5 +#define DMA_ABORT_DONE 4 +#define DMA_OUT_FIFO_TRANSFER_DONE 3 +#define DMA_LOCAL_DONE 2 +#define DMA_PCI_DONE 1 +#define NET2272_PCI_IRQ 0 + +#define RDK2_LOCCTLRDK 0x08 +#define CHIP_RESET 3 +#define SPLIT_DMA 2 +#define MULTIPLEX_MODE 1 +#define BUS_WIDTH 0 + +#define RDK2_GPIOCTL 0x10 +#define GP3_OUT_ENABLE 7 +#define GP2_OUT_ENABLE 6 +#define GP1_OUT_ENABLE 5 +#define GP0_OUT_ENABLE 4 +#define GP3_DATA 3 +#define GP2_DATA 2 +#define GP1_DATA 1 +#define GP0_DATA 0 + +#define RDK2_LEDSW 0x14 +#define LED3 27 +#define LED2 26 +#define LED1 25 +#define LED0 24 +#define PBUTTON 16 +#define DIPSW 0 + +#define RDK2_DIAG 0x18 +#define RDK2_FAST_TIMES 2 +#define FORCE_PCI_SERR 1 +#define FORCE_PCI_INT 0 +#define RDK2_FPGAREV 0x1C + +/* Dma Control registers */ +#define RDK2_DMACTL 0x80 +#define ADDR_HOLD 24 +#define RETRY_COUNT 16 /* 23:16 */ +#define FIFO_THRESHOLD 11 /* 15:11 */ +#define MEM_WRITE_INVALIDATE 10 +#define READ_MULTIPLE 9 +#define READ_LINE 8 +#define RDK2_DMA_MODE 6 /* 7:6 */ +#define CONTROL_DACK 5 +#define EOT_ENABLE 4 +#define EOT_POLARITY 3 +#define DACK_POLARITY 2 +#define DREQ_POLARITY 1 +#define DMA_ENABLE 0 + +#define RDK2_DMASTAT 0x84 +#define GATHER_COUNT 12 /* 14:12 */ +#define FIFO_COUNT 6 /* 11:6 */ +#define FIFO_FLUSH 5 +#define FIFO_TRANSFER 4 +#define PAUSE_DONE 3 +#define ABORT_DONE 2 +#define DMA_ABORT 1 +#define DMA_START 0 + +#define RDK2_DMAPCICOUNT 0x88 +#define DMA_DIRECTION 31 +#define DMA_PCI_BYTE_COUNT 0 /* 0:23 */ + +#define RDK2_DMALOCCOUNT 0x8C /* 0:23 dma local byte count */ + +#define RDK2_DMAADDR 0x90 /* 2:31 PCI bus starting address */ + +/*---------------------------------------------------------------------------*/ + +#define REG_INDEXED_THRESHOLD (1 << 5) + +/* DRIVER DATA STRUCTURES and UTILITIES */ +struct net2272_ep { + struct usb_ep ep; + struct net2272 *dev; + unsigned long irqs; + + /* analogous to a host-side qh */ + struct list_head queue; + const struct usb_endpoint_descriptor *desc; + unsigned num:8, + fifo_size:12, + stopped:1, + wedged:1, + is_in:1, + is_iso:1, + dma:1, + not_empty:1; +}; + +struct net2272 { + /* each device provides one gadget, several endpoints */ + struct usb_gadget gadget; + struct device *dev; + unsigned short dev_id; + + spinlock_t lock; + struct net2272_ep ep[4]; + struct usb_gadget_driver *driver; + unsigned protocol_stall:1, + softconnect:1, + is_selfpowered:1, + wakeup:1, + dma_eot_polarity:1, + dma_dack_polarity:1, + dma_dreq_polarity:1, + dma_busy:1; + u16 chiprev; + u8 pagesel; + + unsigned int irq; + unsigned short fifo_mode; + + unsigned int base_shift; + u16 __iomem *base_addr; + union { +#ifdef CONFIG_PCI + struct { + void __iomem *plx9054_base_addr; + void __iomem *epld_base_addr; + } rdk1; + struct { + /* Bar0, Bar1 is base_addr both mem-mapped */ + void __iomem *fpga_base_addr; + } rdk2; +#endif + }; +}; + +static void __iomem * +net2272_reg_addr(struct net2272 *dev, unsigned int reg) +{ + return dev->base_addr + (reg << dev->base_shift); +} + +static void +net2272_write(struct net2272 *dev, unsigned int reg, u8 value) +{ + if (reg >= REG_INDEXED_THRESHOLD) { + /* + * Indexed register; use REGADDRPTR/REGDATA + * - Save and restore REGADDRPTR. This prevents REGADDRPTR from + * changes between other code sections, but it is time consuming. + * - Performance tips: either do not save and restore REGADDRPTR (if it + * is safe) or do save/restore operations only in critical sections. + u8 tmp = readb(dev->base_addr + REGADDRPTR); + */ + writeb((u8)reg, net2272_reg_addr(dev, REGADDRPTR)); + writeb(value, net2272_reg_addr(dev, REGDATA)); + /* writeb(tmp, net2272_reg_addr(dev, REGADDRPTR)); */ + } else + writeb(value, net2272_reg_addr(dev, reg)); +} + +static u8 +net2272_read(struct net2272 *dev, unsigned int reg) +{ + u8 ret; + + if (reg >= REG_INDEXED_THRESHOLD) { + /* + * Indexed register; use REGADDRPTR/REGDATA + * - Save and restore REGADDRPTR. This prevents REGADDRPTR from + * changes between other code sections, but it is time consuming. + * - Performance tips: either do not save and restore REGADDRPTR (if it + * is safe) or do save/restore operations only in critical sections. + u8 tmp = readb(dev->base_addr + REGADDRPTR); + */ + writeb((u8)reg, net2272_reg_addr(dev, REGADDRPTR)); + ret = readb(net2272_reg_addr(dev, REGDATA)); + /* writeb(tmp, net2272_reg_addr(dev, REGADDRPTR)); */ + } else + ret = readb(net2272_reg_addr(dev, reg)); + + return ret; +} + +static void +net2272_ep_write(struct net2272_ep *ep, unsigned int reg, u8 value) +{ + struct net2272 *dev = ep->dev; + + if (dev->pagesel != ep->num) { + net2272_write(dev, PAGESEL, ep->num); + dev->pagesel = ep->num; + } + net2272_write(dev, reg, value); +} + +static u8 +net2272_ep_read(struct net2272_ep *ep, unsigned int reg) +{ + struct net2272 *dev = ep->dev; + + if (dev->pagesel != ep->num) { + net2272_write(dev, PAGESEL, ep->num); + dev->pagesel = ep->num; + } + return net2272_read(dev, reg); +} + +static void allow_status(struct net2272_ep *ep) +{ + /* ep0 only */ + net2272_ep_write(ep, EP_RSPCLR, + (1 << CONTROL_STATUS_PHASE_HANDSHAKE) | + (1 << ALT_NAK_OUT_PACKETS) | + (1 << NAK_OUT_PACKETS_MODE)); + ep->stopped = 1; +} + +static void set_halt(struct net2272_ep *ep) +{ + /* ep0 and bulk/intr endpoints */ + net2272_ep_write(ep, EP_RSPCLR, 1 << CONTROL_STATUS_PHASE_HANDSHAKE); + net2272_ep_write(ep, EP_RSPSET, 1 << ENDPOINT_HALT); +} + +static void clear_halt(struct net2272_ep *ep) +{ + /* ep0 and bulk/intr endpoints */ + net2272_ep_write(ep, EP_RSPCLR, + (1 << ENDPOINT_HALT) | (1 << ENDPOINT_TOGGLE)); +} + +/* count (<= 4) bytes in the next fifo write will be valid */ +static void set_fifo_bytecount(struct net2272_ep *ep, unsigned count) +{ + /* net2272_ep_write will truncate to u8 for us */ + net2272_ep_write(ep, EP_TRANSFER2, count >> 16); + net2272_ep_write(ep, EP_TRANSFER1, count >> 8); + net2272_ep_write(ep, EP_TRANSFER0, count); +} + +struct net2272_request { + struct usb_request req; + struct list_head queue; + unsigned mapped:1, + valid:1; +}; + +#endif -- cgit v1.2.3-70-g09d2 From 664a51a81f6ba39db30cd7b7de61577ca0b2d20d Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Wed, 15 Jun 2011 16:31:37 -0400 Subject: USB: deprecate g_file_storage This patch (as1471) deprecates the File-backed Storage Driver and schedules its replacement for the 3.8 kernel release (about two years from now). Users are advised to switch to the Mass Storage Gadget instead. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- Documentation/feature-removal-schedule.txt | 7 +++++++ drivers/usb/gadget/Kconfig | 14 +++++++------- drivers/usb/gadget/file_storage.c | 2 ++ 3 files changed, 16 insertions(+), 7 deletions(-) (limited to 'drivers/usb/gadget') diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt index 1a9446b5915..21f331d0473 100644 --- a/Documentation/feature-removal-schedule.txt +++ b/Documentation/feature-removal-schedule.txt @@ -600,3 +600,10 @@ Why: Superseded by the UVCIOC_CTRL_QUERY ioctl. Who: Laurent Pinchart ---------------------------- + +What: g_file_storage driver +When: 3.8 +Why: This driver has been superseded by g_mass_storage. +Who: Alan Stern + +---------------------------- diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index 9468adbe42b..22e43fffbcc 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -877,7 +877,7 @@ config USB_FUNCTIONFS_GENERIC no Ethernet interface. config USB_FILE_STORAGE - tristate "File-backed Storage Gadget" + tristate "File-backed Storage Gadget (DEPRECATED)" depends on BLOCK help The File-backed Storage Gadget acts as a USB Mass Storage @@ -888,6 +888,9 @@ config USB_FILE_STORAGE Say "y" to link the driver statically, or "m" to build a dynamically linked module called "g_file_storage". + NOTE: This driver is deprecated. Its replacement is the + Mass Storage Gadget. + config USB_FILE_STORAGE_TEST bool "File-backed Storage Gadget testing version" depends on USB_FILE_STORAGE @@ -907,14 +910,11 @@ config USB_MASS_STORAGE device (in much the same way as the "loop" device driver), specified as a module parameter or sysfs option. - This is heavily based on File-backed Storage Gadget and in most - cases you will want to use FSG instead. This gadget is mostly - here to test the functionality of the Mass Storage Function - which may be used with composite framework. + This driver is an updated replacement for the deprecated + File-backed Storage Gadget (g_file_storage). Say "y" to link the driver statically, or "m" to build - a dynamically linked module called "g_mass_storage". If unsure, - consider File-backed Storage Gadget. + a dynamically linked module called "g_mass_storage". config USB_G_SERIAL tristate "Serial Gadget (with CDC ACM and CDC OBEX support)" diff --git a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c index 0360f56221e..83bee30cdb9 100644 --- a/drivers/usb/gadget/file_storage.c +++ b/drivers/usb/gadget/file_storage.c @@ -3486,6 +3486,8 @@ static int __init fsg_bind(struct usb_gadget *gadget) } INFO(fsg, DRIVER_DESC ", version: " DRIVER_VERSION "\n"); + INFO(fsg, "NOTE: This driver is deprecated. " + "Consider using g_mass_storage instead.\n"); INFO(fsg, "Number of LUNs=%d\n", fsg->nluns); pathbuf = kmalloc(PATH_MAX, GFP_KERNEL); -- cgit v1.2.3-70-g09d2 From 2ccea03a8f7ec93641791f2760d7cdc6cab6205f Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Tue, 28 Jun 2011 16:33:46 +0300 Subject: usb: gadget: introduce UDC Class this class will be used to abstract away several of the duplicated operations scattered among the USB gadget controller drivers. Later, we can add an atomic notifier to tell interested drivers about what's happening with the controller. Notifications such as suspend, resume, enumerated, etc. will be useful, at a minimum, for implementing usb charger detection. As part of the converting process usb_gadget_probe_driver() is no longer part of each udc but pushed into the ->stap() callback. The same for his couterpart. The core is currently set explicit to 'n'. It will be changed to 'y' once all users are converted since it provides functions which clash with other drivers. Signed-off-by: Felipe Balbi Signed-off-by: Sebastian Andrzej Siewior Acked-by: Michal Nazarewicz Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/udc-core.c | 418 ++++++++++++++++++++++++++++++++++++++++++ include/linux/usb/gadget.h | 7 + 2 files changed, 425 insertions(+) create mode 100644 drivers/usb/gadget/udc-core.c (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/udc-core.c b/drivers/usb/gadget/udc-core.c new file mode 100644 index 00000000000..83e9e5f99b4 --- /dev/null +++ b/drivers/usb/gadget/udc-core.c @@ -0,0 +1,418 @@ +/** + * udc.c - Core UDC Framework + * + * Copyright (C) 2010 Texas Instruments + * Author: Felipe Balbi + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 of + * the License as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include + +#include +#include + +/** + * struct usb_udc - describes one usb device controller + * @driver - the gadget driver pointer. For use by the class code + * @dev - the child device to the actual controller + * @gadget - the gadget. For use by the class code + * @list - for use by the udc class driver + * + * This represents the internal data structure which is used by the UDC-class + * to hold information about udc driver and gadget together. + */ +struct usb_udc { + struct usb_gadget_driver *driver; + struct usb_gadget *gadget; + struct device dev; + struct list_head list; +}; + +static struct class *udc_class; +static struct device_type udc_device_type; +static LIST_HEAD(udc_list); +static DEFINE_MUTEX(udc_lock); + +/* ------------------------------------------------------------------------- */ + +/** + * usb_gadget_start - tells usb device controller to start up + * @gadget: The gadget we want to get started + * @driver: The driver we want to bind to @gadget + * @bind: The bind function for @driver + * + * This call is issued by the UDC Class driver when it's about + * to register a gadget driver to the device controller, before + * calling gadget driver's bind() method. + * + * It allows the controller to be powered off until strictly + * necessary to have it powered on. + * + * Returns zero on success, else negative errno. + */ +static inline int usb_gadget_start(struct usb_gadget *gadget, + struct usb_gadget_driver *driver, + int (*bind)(struct usb_gadget *)) +{ + return gadget->ops->start(driver, bind); +} + +/** + * usb_gadget_stop - tells usb device controller we don't need it anymore + * @gadget: The device we want to stop activity + * @driver: The driver to unbind from @gadget + * + * This call is issued by the UDC Class driver after calling + * gadget driver's unbind() method. + * + * The details are implementation specific, but it can go as + * far as powering off UDC completely and disable its data + * line pullups. + */ +static inline void usb_gadget_stop(struct usb_gadget *gadget, + struct usb_gadget_driver *driver) +{ + gadget->ops->stop(driver); +} + +/** + * usb_udc_release - release the usb_udc struct + * @dev: the dev member within usb_udc + * + * This is called by driver's core in order to free memory once the last + * reference is released. + */ +static void usb_udc_release(struct device *dev) +{ + struct usb_udc *udc; + + udc = container_of(dev, struct usb_udc, dev); + dev_dbg(dev, "releasing '%s'\n", dev_name(dev)); + kfree(udc); +} + +/** + * usb_add_gadget_udc - adds a new gadget to the udc class driver list + * @parent: the parent device to this udc. Usually the controller + * driver's device. + * @gadget: the gadget to be added to the list + * + * Returns zero on success, negative errno otherwise. + */ +int usb_add_gadget_udc(struct device *parent, struct usb_gadget *gadget) +{ + struct usb_udc *udc; + int ret = -ENOMEM; + + udc = kzalloc(sizeof(*udc), GFP_KERNEL); + if (!udc) + goto err1; + + device_initialize(&udc->dev); + udc->dev.release = usb_udc_release; + udc->dev.class = udc_class; + udc->dev.parent = parent; + ret = dev_set_name(&udc->dev, "%s", kobject_name(&parent->kobj)); + if (ret) + goto err2; + + udc->gadget = gadget; + + mutex_lock(&udc_lock); + list_add_tail(&udc->list, &udc_list); + + ret = device_add(&udc->dev); + if (ret) + goto err3; + + mutex_unlock(&udc_lock); + + return 0; +err3: + list_del(&udc->list); + mutex_unlock(&udc_lock); + +err2: + put_device(&udc->dev); + +err1: + return ret; +} +EXPORT_SYMBOL_GPL(usb_add_gadget_udc); + +static void usb_gadget_remove_driver(struct usb_udc *udc) +{ + dev_dbg(&udc->dev, "unregistering UDC driver [%s]\n", + udc->gadget->name); + + kobject_uevent(&udc->dev.kobj, KOBJ_CHANGE); + + usb_gadget_stop(udc->gadget, udc->driver); + + udc->driver = NULL; + udc->dev.driver = NULL; +} + +/** + * usb_del_gadget_udc - deletes @udc from udc_list + * @gadget: the gadget to be removed. + * + * This, will call usb_gadget_unregister_driver() if + * the @udc is still busy. + */ +void usb_del_gadget_udc(struct usb_gadget *gadget) +{ + struct usb_udc *udc = NULL; + + mutex_lock(&udc_lock); + list_for_each_entry(udc, &udc_list, list) + if (udc->gadget == gadget) + goto found; + + dev_err(gadget->dev.parent, "gadget not registered.\n"); + mutex_unlock(&udc_lock); + + return; + +found: + dev_vdbg(gadget->dev.parent, "unregistering gadget\n"); + + list_del(&udc->list); + mutex_unlock(&udc_lock); + + if (udc->driver) + usb_gadget_remove_driver(udc); + + kobject_uevent(&udc->dev.kobj, KOBJ_REMOVE); + device_unregister(&udc->dev); +} +EXPORT_SYMBOL_GPL(usb_del_gadget_udc); + +/* ------------------------------------------------------------------------- */ + +int usb_gadget_probe_driver(struct usb_gadget_driver *driver, + int (*bind)(struct usb_gadget *)) +{ + struct usb_udc *udc = NULL; + int ret; + + if (!driver || !bind || !driver->setup) + return -EINVAL; + + mutex_lock(&udc_lock); + list_for_each_entry(udc, &udc_list, list) { + /* For now we take the first one */ + if (!udc->driver) + goto found; + } + + pr_debug("couldn't find an available UDC\n"); + mutex_unlock(&udc_lock); + return -ENODEV; + +found: + dev_dbg(&udc->dev, "registering UDC driver [%s]\n", + driver->function); + + udc->driver = driver; + udc->dev.driver = &driver->driver; + + ret = usb_gadget_start(udc->gadget, driver, bind); + if (ret) + goto err1; + + kobject_uevent(&udc->dev.kobj, KOBJ_CHANGE); + mutex_unlock(&udc_lock); + return 0; + +err1: + dev_err(&udc->dev, "failed to start %s: %d\n", + udc->driver->function, ret); + udc->driver = NULL; + udc->dev.driver = NULL; + mutex_unlock(&udc_lock); + return ret; +} +EXPORT_SYMBOL_GPL(usb_gadget_probe_driver); + +int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) +{ + struct usb_udc *udc = NULL; + int ret = -ENODEV; + + if (!driver || !driver->unbind) + return -EINVAL; + + mutex_lock(&udc_lock); + list_for_each_entry(udc, &udc_list, list) + if (udc->driver == driver) { + usb_gadget_remove_driver(udc); + ret = 0; + break; + } + + mutex_unlock(&udc_lock); + return ret; +} +EXPORT_SYMBOL_GPL(usb_gadget_unregister_driver); + +/* ------------------------------------------------------------------------- */ + +static ssize_t usb_udc_srp_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t n) +{ + struct usb_udc *udc = dev_get_drvdata(dev); + + if (sysfs_streq(buf, "1")) + usb_gadget_wakeup(udc->gadget); + + return n; +} +static DEVICE_ATTR(srp, S_IWUSR, NULL, usb_udc_srp_store); + +static ssize_t usb_udc_softconn_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t n) +{ + struct usb_udc *udc = dev_get_drvdata(dev); + + if (sysfs_streq(buf, "connect")) { + usb_gadget_connect(udc->gadget); + } else if (sysfs_streq(buf, "disconnect")) { + usb_gadget_disconnect(udc->gadget); + } else { + dev_err(dev, "unsupported command '%s'\n", buf); + return -EINVAL; + } + + return n; +} +static DEVICE_ATTR(soft_connect, S_IWUSR, NULL, usb_udc_softconn_store); + +static ssize_t usb_udc_speed_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct usb_udc *udc = dev_get_drvdata(dev); + struct usb_gadget *gadget = udc->gadget; + + switch (gadget->speed) { + case USB_SPEED_LOW: + return snprintf(buf, PAGE_SIZE, "low-speed\n"); + case USB_SPEED_FULL: + return snprintf(buf, PAGE_SIZE, "full-speed\n"); + case USB_SPEED_HIGH: + return snprintf(buf, PAGE_SIZE, "high-speed\n"); + case USB_SPEED_WIRELESS: + return snprintf(buf, PAGE_SIZE, "wireless\n"); + case USB_SPEED_SUPER: + return snprintf(buf, PAGE_SIZE, "super-speed\n"); + case USB_SPEED_UNKNOWN: /* FALLTHROUGH */ + default: + return snprintf(buf, PAGE_SIZE, "UNKNOWN\n"); + } +} +static DEVICE_ATTR(speed, S_IRUSR, usb_udc_speed_show, NULL); + +#define USB_UDC_ATTR(name) \ +ssize_t usb_udc_##name##_show(struct device *dev, \ + struct device_attribute *attr, char *buf) \ +{ \ + struct usb_udc *udc = dev_get_drvdata(dev); \ + struct usb_gadget *gadget = udc->gadget; \ + \ + return snprintf(buf, PAGE_SIZE, "%d\n", gadget->name); \ +} \ +static DEVICE_ATTR(name, S_IRUSR, usb_udc_##name##_show, NULL) + +static USB_UDC_ATTR(is_dualspeed); +static USB_UDC_ATTR(is_otg); +static USB_UDC_ATTR(is_a_peripheral); +static USB_UDC_ATTR(b_hnp_enable); +static USB_UDC_ATTR(a_hnp_support); +static USB_UDC_ATTR(a_alt_hnp_support); + +static struct attribute *usb_udc_attrs[] = { + &dev_attr_srp.attr, + &dev_attr_soft_connect.attr, + &dev_attr_speed.attr, + + &dev_attr_is_dualspeed.attr, + &dev_attr_is_otg.attr, + &dev_attr_is_a_peripheral.attr, + &dev_attr_b_hnp_enable.attr, + &dev_attr_a_hnp_support.attr, + &dev_attr_a_alt_hnp_support.attr, + NULL, +}; + +static const struct attribute_group usb_udc_attr_group = { + .attrs = usb_udc_attrs, +}; + +static const struct attribute_group *usb_udc_attr_groups[] = { + &usb_udc_attr_group, + NULL, +}; + +static int usb_udc_uevent(struct device *dev, struct kobj_uevent_env *env) +{ + struct usb_udc *udc = container_of(dev, struct usb_udc, dev); + int ret; + + ret = add_uevent_var(env, "USB_UDC_NAME=%s", udc->gadget->name); + if (ret) { + dev_err(dev, "failed to add uevent USB_UDC_NAME\n"); + return ret; + } + + if (udc->driver) { + ret = add_uevent_var(env, "USB_UDC_DRIVER=%s", + udc->driver->function); + if (ret) { + dev_err(dev, "failed to add uevent USB_UDC_DRIVER\n"); + return ret; + } + } + + return 0; +} + +static int __init usb_udc_init(void) +{ + udc_class = class_create(THIS_MODULE, "udc"); + if (IS_ERR(udc_class)) { + pr_err("failed to create udc class --> %ld\n", + PTR_ERR(udc_class)); + return PTR_ERR(udc_class); + } + + udc_class->dev_uevent = usb_udc_uevent; + udc_device_type.groups = usb_udc_attr_groups; + + return 0; +} +subsys_initcall(usb_udc_init); + +static void __exit usb_udc_exit(void) +{ + class_destroy(udc_class); +} +module_exit(usb_udc_exit); + +MODULE_DESCRIPTION("UDC Framework"); +MODULE_AUTHOR("Felipe Balbi "); +MODULE_LICENSE("GPL v2"); diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h index 55d1a88ff11..18979cfb6d6 100644 --- a/include/linux/usb/gadget.h +++ b/include/linux/usb/gadget.h @@ -418,6 +418,7 @@ static inline void usb_ep_fifo_flush(struct usb_ep *ep) /*-------------------------------------------------------------------------*/ struct usb_gadget; +struct usb_gadget_driver; /* the rest of the api to the controller hardware: device operations, * which don't involve endpoints (or i/o). @@ -431,6 +432,9 @@ struct usb_gadget_ops { int (*pullup) (struct usb_gadget *, int is_on); int (*ioctl)(struct usb_gadget *, unsigned code, unsigned long param); + int (*start)(struct usb_gadget_driver *, + int (*bind)(struct usb_gadget *)); + int (*stop)(struct usb_gadget_driver *); }; /** @@ -822,6 +826,9 @@ int usb_gadget_probe_driver(struct usb_gadget_driver *driver, */ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver); +extern int usb_add_gadget_udc(struct device *parent, struct usb_gadget *gadget); +extern void usb_del_gadget_udc(struct usb_gadget *gadget); + /*-------------------------------------------------------------------------*/ /* utility to simplify dealing with string descriptors */ -- cgit v1.2.3-70-g09d2 From 0f91349b89f37dfad7b77f7829a105b6a0f526ec Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Tue, 28 Jun 2011 16:33:47 +0300 Subject: usb: gadget: convert all users to the new udc infrastructure peripheral drivers are using usb_add_gadget()/usb_del_gadget() to register/unregister to the udc-core. The udc-core will take the first available gadget driver and attach function driver which is calling usb_gadget_register_driver(). This is the same behaviour we have right now. Only dummy_hcd was tested, the others were compiled tested. Cc: Alan Stern Cc: Anton Tikhomirov Cc: Ben Dooks Cc: Dan Carpenter Cc: Darius Augulis Cc: Eric Miao Cc: Jingoo Han Cc: Kukjin Kim Cc: Kuninori Morimoto Cc: Li Yang Cc: Michael Hennerich Acked-by: Mike Frysinger Cc: Nicolas Ferre Cc: Pavankumar Kondeti Cc: Roy Huang Cc: Russell King Cc: Toshiharu Okada Cc: Xiaochen Shen Cc: Yoshihiro Shimoda Cc: Yuan-Hsin Chen Cc: cxie4 Cc: linux-geode@lists.infradead.org Signed-off-by: Sebastian Andrzej Siewior Signed-off-by: Felipe Balbi Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/Makefile | 1 + drivers/usb/gadget/amd5536udc.c | 18 ++++++++++---- drivers/usb/gadget/at91_udc.c | 20 ++++++++++++---- drivers/usb/gadget/atmel_usba_udc.c | 26 ++++++++++++++++---- drivers/usb/gadget/ci13xxx_udc.c | 43 +++++++++++++++++++++++----------- drivers/usb/gadget/dummy_hcd.c | 31 ++++++++++++++++-------- drivers/usb/gadget/fsl_qe_udc.c | 20 ++++++++++++---- drivers/usb/gadget/fsl_udc_core.c | 20 ++++++++++++---- drivers/usb/gadget/fusb300_udc.c | 15 ++++++++---- drivers/usb/gadget/goku_udc.c | 19 +++++++++++---- drivers/usb/gadget/imx_udc.c | 20 ++++++++++++---- drivers/usb/gadget/langwell_udc.c | 20 ++++++++++------ drivers/usb/gadget/m66592-udc.c | 17 ++++++++++---- drivers/usb/gadget/mv_udc_core.c | 19 +++++++++------ drivers/usb/gadget/net2272.c | 22 +++++++++++++---- drivers/usb/gadget/net2280.c | 18 ++++++++++---- drivers/usb/gadget/omap_udc.c | 22 +++++++++++++---- drivers/usb/gadget/pch_udc.c | 16 +++++++++---- drivers/usb/gadget/pxa25x_udc.c | 19 ++++++++++----- drivers/usb/gadget/pxa27x_udc.c | 23 ++++++++++++------ drivers/usb/gadget/r8a66597-udc.c | 15 ++++++++---- drivers/usb/gadget/s3c-hsotg.c | 19 +++++++++++---- drivers/usb/gadget/s3c-hsudc.c | 16 +++++++++---- drivers/usb/gadget/s3c2410_udc.c | 29 ++++++++++++++--------- drivers/usb/musb/musb_gadget.c | 23 ++++++++++++++---- drivers/usb/renesas_usbhs/mod_gadget.c | 20 ++++++++++++---- 26 files changed, 388 insertions(+), 143 deletions(-) (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile index 345261738b1..9ba725af4a0 100644 --- a/drivers/usb/gadget/Makefile +++ b/drivers/usb/gadget/Makefile @@ -3,6 +3,7 @@ # ccflags-$(CONFIG_USB_GADGET_DEBUG) := -DDEBUG +obj-$(CONFIG_USB_GADGET) += udc-core.o obj-$(CONFIG_USB_DUMMY_HCD) += dummy_hcd.o obj-$(CONFIG_USB_NET2272) += net2272.o obj-$(CONFIG_USB_NET2280) += net2280.o diff --git a/drivers/usb/gadget/amd5536udc.c b/drivers/usb/gadget/amd5536udc.c index 95e8138cd48..70f2b376c86 100644 --- a/drivers/usb/gadget/amd5536udc.c +++ b/drivers/usb/gadget/amd5536udc.c @@ -1438,10 +1438,15 @@ static int udc_wakeup(struct usb_gadget *gadget) return 0; } +static int amd5536_start(struct usb_gadget_driver *driver, + int (*bind)(struct usb_gadget *)); +static int amd5536_stop(struct usb_gadget_driver *driver); /* gadget operations */ static const struct usb_gadget_ops udc_ops = { .wakeup = udc_wakeup, .get_frame = udc_get_frame, + .start = amd5536_start, + .stop = amd5536_stop, }; /* Setups endpoint parameters, adds endpoints to linked list */ @@ -1955,7 +1960,7 @@ static int setup_ep0(struct udc *dev) } /* Called by gadget driver to register itself */ -int usb_gadget_probe_driver(struct usb_gadget_driver *driver, +static int amd5536_start(struct usb_gadget_driver *driver, int (*bind)(struct usb_gadget *)) { struct udc *dev = udc; @@ -2002,7 +2007,6 @@ int usb_gadget_probe_driver(struct usb_gadget_driver *driver, return 0; } -EXPORT_SYMBOL(usb_gadget_probe_driver); /* shutdown requests and disconnect from gadget */ static void @@ -2027,7 +2031,7 @@ __acquires(dev->lock) } /* Called by gadget driver to unregister itself */ -int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) +static int amd5536_stop(struct usb_gadget_driver *driver) { struct udc *dev = udc; unsigned long flags; @@ -2057,8 +2061,6 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) return 0; } -EXPORT_SYMBOL(usb_gadget_unregister_driver); - /* Clear pending NAK bits */ static void udc_process_cnak_queue(struct udc *dev) @@ -3134,6 +3136,7 @@ static void udc_pci_remove(struct pci_dev *pdev) dev = pci_get_drvdata(pdev); + usb_del_gadget_udc(&udc->gadget); /* gadget driver must not be registered */ BUG_ON(dev->driver != NULL); @@ -3382,8 +3385,13 @@ static int udc_probe(struct udc *dev) "driver version: %s(for Geode5536 B1)\n", tmp); udc = dev; + retval = usb_add_gadget_udc(&udc->pdev->dev, &dev->gadget); + if (retval) + goto finished; + retval = device_register(&dev->gadget.dev); if (retval) { + usb_del_gadget_udc(&dev->gadget); put_device(&dev->gadget.dev); goto finished; } diff --git a/drivers/usb/gadget/at91_udc.c b/drivers/usb/gadget/at91_udc.c index f4690ffcb48..98cbc06c30f 100644 --- a/drivers/usb/gadget/at91_udc.c +++ b/drivers/usb/gadget/at91_udc.c @@ -985,12 +985,18 @@ static int at91_set_selfpowered(struct usb_gadget *gadget, int is_on) return 0; } +static int at91_start(struct usb_gadget_driver *driver, + int (*bind)(struct usb_gadget *)); +static int at91_stop(struct usb_gadget_driver *driver); + static const struct usb_gadget_ops at91_udc_ops = { .get_frame = at91_get_frame, .wakeup = at91_wakeup, .set_selfpowered = at91_set_selfpowered, .vbus_session = at91_vbus_session, .pullup = at91_pullup, + .start = at91_start, + .stop = at91_stop, /* * VBUS-powered devices may also also want to support bigger @@ -1628,7 +1634,7 @@ static void at91_vbus_timer(unsigned long data) schedule_work(&udc->vbus_timer_work); } -int usb_gadget_probe_driver(struct usb_gadget_driver *driver, +static int at91_start(struct usb_gadget_driver *driver, int (*bind)(struct usb_gadget *)) { struct at91_udc *udc = &controller; @@ -1672,9 +1678,8 @@ int usb_gadget_probe_driver(struct usb_gadget_driver *driver, DBG("bound to %s\n", driver->driver.name); return 0; } -EXPORT_SYMBOL(usb_gadget_probe_driver); -int usb_gadget_unregister_driver (struct usb_gadget_driver *driver) +static int at91_stop(struct usb_gadget_driver *driver) { struct at91_udc *udc = &controller; unsigned long flags; @@ -1696,7 +1701,6 @@ int usb_gadget_unregister_driver (struct usb_gadget_driver *driver) DBG("unbound from %s\n", driver->driver.name); return 0; } -EXPORT_SYMBOL (usb_gadget_unregister_driver); /*-------------------------------------------------------------------------*/ @@ -1854,13 +1858,18 @@ static int __init at91udc_probe(struct platform_device *pdev) DBG("no VBUS detection, assuming always-on\n"); udc->vbus = 1; } + retval = usb_add_gadget_udc(dev, &udc->gadget); + if (retval) + goto fail4; dev_set_drvdata(dev, udc); device_init_wakeup(dev, 1); create_debug_file(udc); INFO("%s version %s\n", driver_name, DRIVER_VERSION); return 0; - +fail4: + if (udc->board.vbus_pin > 0 && !udc->board.vbus_polled) + free_irq(udc->board.vbus_pin, udc); fail3: if (udc->board.vbus_pin > 0) gpio_free(udc->board.vbus_pin); @@ -1887,6 +1896,7 @@ static int __exit at91udc_remove(struct platform_device *pdev) DBG("remove\n"); + usb_del_gadget_udc(&udc->gadget); if (udc->driver) return -EBUSY; diff --git a/drivers/usb/gadget/atmel_usba_udc.c b/drivers/usb/gadget/atmel_usba_udc.c index db1a659702b..e6b970a2a29 100644 --- a/drivers/usb/gadget/atmel_usba_udc.c +++ b/drivers/usb/gadget/atmel_usba_udc.c @@ -1007,10 +1007,16 @@ usba_udc_set_selfpowered(struct usb_gadget *gadget, int is_selfpowered) return 0; } +static int atmel_usba_start(struct usb_gadget_driver *driver, + int (*bind)(struct usb_gadget *)); +static int atmel_usba_stop(struct usb_gadget_driver *driver); + static const struct usb_gadget_ops usba_udc_ops = { .get_frame = usba_udc_get_frame, .wakeup = usba_udc_wakeup, .set_selfpowered = usba_udc_set_selfpowered, + .start = atmel_usba_start, + .stop = atmel_usba_stop, }; static struct usb_endpoint_descriptor usba_ep0_desc = { @@ -1789,7 +1795,7 @@ out: return IRQ_HANDLED; } -int usb_gadget_probe_driver(struct usb_gadget_driver *driver, +static int atmel_usba_start(struct usb_gadget_driver *driver, int (*bind)(struct usb_gadget *)) { struct usba_udc *udc = &the_udc; @@ -1842,9 +1848,8 @@ err_driver_bind: udc->gadget.dev.driver = NULL; return ret; } -EXPORT_SYMBOL(usb_gadget_probe_driver); -int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) +static int atmel_usba_stop(struct usb_gadget_driver *driver) { struct usba_udc *udc = &the_udc; unsigned long flags; @@ -1880,7 +1885,6 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) return 0; } -EXPORT_SYMBOL(usb_gadget_unregister_driver); static int __init usba_udc_probe(struct platform_device *pdev) { @@ -2021,12 +2025,24 @@ static int __init usba_udc_probe(struct platform_device *pdev) } } + ret = usb_add_gadget_udc(&pdev->dev, &udc->gadget); + if (ret) + goto err_add_udc; + usba_init_debugfs(udc); for (i = 1; i < pdata->num_ep; i++) usba_ep_init_debugfs(udc, &usba_ep[i]); return 0; +err_add_udc: + if (gpio_is_valid(pdata->vbus_pin)) { + free_irq(gpio_to_irq(udc->vbus_pin), udc); + gpio_free(udc->vbus_pin); + } + + device_unregister(&udc->gadget.dev); + err_device_add: free_irq(irq, udc); err_request_irq: @@ -2053,6 +2069,8 @@ static int __exit usba_udc_remove(struct platform_device *pdev) udc = platform_get_drvdata(pdev); + usb_del_gadget_udc(&udc->gadget); + for (i = 1; i < pdata->num_ep; i++) usba_ep_cleanup_debugfs(&usba_ep[i]); usba_cleanup_debugfs(udc); diff --git a/drivers/usb/gadget/ci13xxx_udc.c b/drivers/usb/gadget/ci13xxx_udc.c index baaf87ed768..909bc45c0be 100644 --- a/drivers/usb/gadget/ci13xxx_udc.c +++ b/drivers/usb/gadget/ci13xxx_udc.c @@ -857,7 +857,7 @@ static void dbg_print(u8 addr, const char *name, int status, const char *extra) stamp = stamp * 1000000 + tval.tv_usec; scnprintf(dbg_data.buf[dbg_data.idx], DBG_DATA_MSG, - "%04X\t» %02X %-7.7s %4i «\t%s\n", + "%04X\t? %02X %-7.7s %4i ?\t%s\n", stamp, addr, name, status, extra); dbg_inc(&dbg_data.idx); @@ -865,7 +865,7 @@ static void dbg_print(u8 addr, const char *name, int status, const char *extra) write_unlock_irqrestore(&dbg_data.lck, flags); if (dbg_data.tty != 0) - pr_notice("%04X\t» %02X %-7.7s %4i «\t%s\n", + pr_notice("%04X\t? %02X %-7.7s %4i ?\t%s\n", stamp, addr, name, status, extra); } @@ -1025,15 +1025,15 @@ static ssize_t show_inters(struct device *dev, struct device_attribute *attr, n += scnprintf(buf + n, PAGE_SIZE - n, "*test = %d\n", isr_statistics.test); - n += scnprintf(buf + n, PAGE_SIZE - n, "» ui = %d\n", + n += scnprintf(buf + n, PAGE_SIZE - n, "? ui = %d\n", isr_statistics.ui); - n += scnprintf(buf + n, PAGE_SIZE - n, "» uei = %d\n", + n += scnprintf(buf + n, PAGE_SIZE - n, "? uei = %d\n", isr_statistics.uei); - n += scnprintf(buf + n, PAGE_SIZE - n, "» pci = %d\n", + n += scnprintf(buf + n, PAGE_SIZE - n, "? pci = %d\n", isr_statistics.pci); - n += scnprintf(buf + n, PAGE_SIZE - n, "» uri = %d\n", + n += scnprintf(buf + n, PAGE_SIZE - n, "? uri = %d\n", isr_statistics.uri); - n += scnprintf(buf + n, PAGE_SIZE - n, "» sli = %d\n", + n += scnprintf(buf + n, PAGE_SIZE - n, "? sli = %d\n", isr_statistics.sli); n += scnprintf(buf + n, PAGE_SIZE - n, "*none = %d\n", isr_statistics.none); @@ -2515,6 +2515,9 @@ static int ci13xxx_vbus_draw(struct usb_gadget *_gadget, unsigned mA) return -ENOTSUPP; } +static int ci13xxx_start(struct usb_gadget_driver *driver, + int (*bind)(struct usb_gadget *)); +static int ci13xxx_stop(struct usb_gadget_driver *driver); /** * Device operations part of the API to the USB controller hardware, * which don't involve endpoints (or i/o) @@ -2524,17 +2527,19 @@ static const struct usb_gadget_ops usb_gadget_ops = { .vbus_session = ci13xxx_vbus_session, .wakeup = ci13xxx_wakeup, .vbus_draw = ci13xxx_vbus_draw, + .start = ci13xxx_start, + .stop = ci13xxx_stop, }; /** - * usb_gadget_probe_driver: register a gadget driver + * ci13xxx_start: register a gadget driver * @driver: the driver being registered * @bind: the driver's bind callback * - * Check usb_gadget_probe_driver() at for details. + * Check ci13xxx_start() at for details. * Interrupts are enabled here. */ -int usb_gadget_probe_driver(struct usb_gadget_driver *driver, +static int ci13xxx_start(struct usb_gadget_driver *driver, int (*bind)(struct usb_gadget *)) { struct ci13xxx *udc = _udc; @@ -2657,14 +2662,13 @@ int usb_gadget_probe_driver(struct usb_gadget_driver *driver, spin_unlock_irqrestore(udc->lock, flags); return retval; } -EXPORT_SYMBOL(usb_gadget_probe_driver); /** - * usb_gadget_unregister_driver: unregister a gadget driver + * ci13xxx_stop: unregister a gadget driver * * Check usb_gadget_unregister_driver() at "usb_gadget.h" for details */ -int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) +static int ci13xxx_stop(struct usb_gadget_driver *driver) { struct ci13xxx *udc = _udc; unsigned long i, flags; @@ -2726,7 +2730,6 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) return 0; } -EXPORT_SYMBOL(usb_gadget_unregister_driver); /****************************************************************************** * BUS block @@ -2901,12 +2904,23 @@ static int udc_probe(struct ci13xxx_udc_driver *driver, struct device *dev, if (retval) goto remove_dbg; } + + retval = usb_add_gadget_udc(dev, &udc->gadget); + if (retval) + goto remove_trans; + pm_runtime_no_callbacks(&udc->gadget.dev); pm_runtime_enable(&udc->gadget.dev); _udc = udc; return retval; +remove_trans: + if (udc->transceiver) { + otg_set_peripheral(udc->transceiver, &udc->gadget); + otg_put_transceiver(udc->transceiver); + } + err("error = %i", retval); remove_dbg: #ifdef CONFIG_USB_GADGET_DEBUG_FILES @@ -2936,6 +2950,7 @@ static void udc_remove(void) err("EINVAL"); return; } + usb_del_gadget_udc(&udc->gadget); if (udc->transceiver) { otg_set_peripheral(udc->transceiver, &udc->gadget); diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c index d3dcabc1a5f..d47a565d085 100644 --- a/drivers/usb/gadget/dummy_hcd.c +++ b/drivers/usb/gadget/dummy_hcd.c @@ -710,11 +710,17 @@ static int dummy_pullup (struct usb_gadget *_gadget, int value) return 0; } +static int dummy_udc_start(struct usb_gadget_driver *driver, + int (*bind)(struct usb_gadget *)); +static int dummy_udc_stop(struct usb_gadget_driver *driver); + static const struct usb_gadget_ops dummy_ops = { .get_frame = dummy_g_get_frame, .wakeup = dummy_wakeup, .set_selfpowered = dummy_set_selfpowered, .pullup = dummy_pullup, + .start = dummy_udc_start, + .stop = dummy_udc_stop, }; /*-------------------------------------------------------------------------*/ @@ -747,8 +753,7 @@ static DEVICE_ATTR (function, S_IRUGO, show_function, NULL); * for each driver that registers: just add to a big root hub. */ -int -usb_gadget_probe_driver(struct usb_gadget_driver *driver, +static int dummy_udc_start(struct usb_gadget_driver *driver, int (*bind)(struct usb_gadget *)) { struct dummy *dum = the_controller; @@ -812,10 +817,8 @@ usb_gadget_probe_driver(struct usb_gadget_driver *driver, usb_hcd_poll_rh_status (dummy_to_hcd (dum)); return 0; } -EXPORT_SYMBOL(usb_gadget_probe_driver); -int -usb_gadget_unregister_driver (struct usb_gadget_driver *driver) +static int dummy_udc_stop(struct usb_gadget_driver *driver) { struct dummy *dum = the_controller; unsigned long flags; @@ -845,7 +848,6 @@ usb_gadget_unregister_driver (struct usb_gadget_driver *driver) usb_hcd_poll_rh_status (dummy_to_hcd (dum)); return 0; } -EXPORT_SYMBOL (usb_gadget_unregister_driver); #undef is_enabled @@ -892,11 +894,20 @@ static int dummy_udc_probe (struct platform_device *pdev) return rc; } + rc = usb_add_gadget_udc(&pdev->dev, &dum->gadget); + if (rc < 0) + goto err_udc; + rc = device_create_file (&dum->gadget.dev, &dev_attr_function); if (rc < 0) - device_unregister (&dum->gadget.dev); - else - platform_set_drvdata(pdev, dum); + goto err_dev; + platform_set_drvdata(pdev, dum); + return rc; + +err_dev: + usb_del_gadget_udc(&dum->gadget); +err_udc: + device_unregister(&dum->gadget.dev); return rc; } @@ -904,6 +915,7 @@ static int dummy_udc_remove (struct platform_device *pdev) { struct dummy *dum = platform_get_drvdata (pdev); + usb_del_gadget_udc(&dum->gadget); platform_set_drvdata (pdev, NULL); device_remove_file (&dum->gadget.dev, &dev_attr_function); device_unregister (&dum->gadget.dev); @@ -1863,7 +1875,6 @@ static void dummy_stop (struct usb_hcd *hcd) dum = hcd_to_dummy (hcd); device_remove_file (dummy_dev(dum), &dev_attr_urbs); - usb_gadget_unregister_driver (dum->driver); dev_info (dummy_dev(dum), "stopped\n"); } diff --git a/drivers/usb/gadget/fsl_qe_udc.c b/drivers/usb/gadget/fsl_qe_udc.c index 3a68e09309f..3bf872e1ad3 100644 --- a/drivers/usb/gadget/fsl_qe_udc.c +++ b/drivers/usb/gadget/fsl_qe_udc.c @@ -1927,6 +1927,10 @@ static int qe_pullup(struct usb_gadget *gadget, int is_on) return -ENOTSUPP; } +static int fsl_qe_start(struct usb_gadget_driver *driver, + int (*bind)(struct usb_gadget *)); +static int fsl_qe_stop(struct usb_gadget_driver *driver); + /* defined in usb_gadget.h */ static struct usb_gadget_ops qe_gadget_ops = { .get_frame = qe_get_frame, @@ -1935,6 +1939,8 @@ static struct usb_gadget_ops qe_gadget_ops = { .vbus_session = qe_vbus_session, .vbus_draw = qe_vbus_draw, .pullup = qe_pullup, + .start = fsl_qe_start, + .stop = fsl_qe_stop, }; /*------------------------------------------------------------------------- @@ -2320,7 +2326,7 @@ static irqreturn_t qe_udc_irq(int irq, void *_udc) /*------------------------------------------------------------------------- Gadget driver probe and unregister. --------------------------------------------------------------------------*/ -int usb_gadget_probe_driver(struct usb_gadget_driver *driver, +static int fsl_qe_start(struct usb_gadget_driver *driver, int (*bind)(struct usb_gadget *)) { int retval; @@ -2369,9 +2375,8 @@ int usb_gadget_probe_driver(struct usb_gadget_driver *driver, udc_controller->gadget.name, driver->driver.name); return 0; } -EXPORT_SYMBOL(usb_gadget_probe_driver); -int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) +static int fsl_qe_stop(struct usb_gadget_driver *driver) { struct qe_ep *loop_ep; unsigned long flags; @@ -2411,7 +2416,6 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) driver->driver.name); return 0; } -EXPORT_SYMBOL(usb_gadget_unregister_driver); /* udc structure's alloc and setup, include ep-param alloc */ static struct qe_udc __devinit *qe_udc_config(struct platform_device *ofdev) @@ -2662,11 +2666,17 @@ static int __devinit qe_udc_probe(struct platform_device *ofdev) if (ret) goto err6; + ret = usb_add_gadget_udc(&ofdev->dev, &udc_controller->gadget); + if (ret) + goto err7; + dev_info(udc_controller->dev, "%s USB controller initialized as device\n", (udc_controller->soc_type == PORT_QE) ? "QE" : "CPM"); return 0; +err7: + device_unregister(&udc_controller->gadget.dev); err6: free_irq(udc_controller->usb_irq, udc_controller); err5: @@ -2721,6 +2731,8 @@ static int __devexit qe_udc_remove(struct platform_device *ofdev) if (!udc_controller) return -ENODEV; + usb_del_gadget_udc(&udc_controller->gadget); + udc_controller->done = &done; tasklet_disable(&udc_controller->rx_tasklet); diff --git a/drivers/usb/gadget/fsl_udc_core.c b/drivers/usb/gadget/fsl_udc_core.c index 2cd9a60c7f3..5e3dbed7d00 100644 --- a/drivers/usb/gadget/fsl_udc_core.c +++ b/drivers/usb/gadget/fsl_udc_core.c @@ -1232,6 +1232,9 @@ static int fsl_pullup(struct usb_gadget *gadget, int is_on) return 0; } +static int fsl_start(struct usb_gadget_driver *driver, + int (*bind)(struct usb_gadget *)); +static int fsl_stop(struct usb_gadget_driver *driver); /* defined in gadget.h */ static struct usb_gadget_ops fsl_gadget_ops = { .get_frame = fsl_get_frame, @@ -1240,6 +1243,8 @@ static struct usb_gadget_ops fsl_gadget_ops = { .vbus_session = fsl_vbus_session, .vbus_draw = fsl_vbus_draw, .pullup = fsl_pullup, + .start = fsl_start, + .stop = fsl_stop, }; /* Set protocol stall on ep0, protocol stall will automatically be cleared @@ -1908,7 +1913,7 @@ static irqreturn_t fsl_udc_irq(int irq, void *_udc) * Hook to gadget drivers * Called by initialization code of gadget drivers *----------------------------------------------------------------*/ -int usb_gadget_probe_driver(struct usb_gadget_driver *driver, +static int fsl_start(struct usb_gadget_driver *driver, int (*bind)(struct usb_gadget *)) { int retval = -ENODEV; @@ -1976,10 +1981,9 @@ out: retval); return retval; } -EXPORT_SYMBOL(usb_gadget_probe_driver); /* Disconnect from gadget driver */ -int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) +static int fsl_stop(struct usb_gadget_driver *driver) { struct fsl_ep *loop_ep; unsigned long flags; @@ -2022,7 +2026,6 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) driver->driver.name); return 0; } -EXPORT_SYMBOL(usb_gadget_unregister_driver); /*------------------------------------------------------------------------- PROC File System Support @@ -2578,9 +2581,16 @@ static int __init fsl_udc_probe(struct platform_device *pdev) ret = -ENOMEM; goto err_unregister; } + + ret = usb_add_gadget_udc(&pdev->dev, &udc_controller->gadget); + if (ret) + goto err_del_udc; + create_proc_file(); return 0; +err_del_udc: + dma_pool_destroy(udc_controller->td_pool); err_unregister: device_unregister(&udc_controller->gadget.dev); err_free_irq: @@ -2612,6 +2622,8 @@ static int __exit fsl_udc_remove(struct platform_device *pdev) if (!udc_controller) return -ENODEV; + + usb_del_gadget_udc(&udc_controller->gadget); udc_controller->done = &done; fsl_udc_clk_release(); diff --git a/drivers/usb/gadget/fusb300_udc.c b/drivers/usb/gadget/fusb300_udc.c index b82a1149145..06353e7ba1f 100644 --- a/drivers/usb/gadget/fusb300_udc.c +++ b/drivers/usb/gadget/fusb300_udc.c @@ -1495,7 +1495,7 @@ static void init_controller(struct fusb300 *fusb300) /*------------------------------------------------------------------------*/ static struct fusb300 *the_controller; -int usb_gadget_probe_driver(struct usb_gadget_driver *driver, +static int fusb300_udc_start(struct usb_gadget_driver *driver, int (*bind)(struct usb_gadget *)) { struct fusb300 *fusb300 = the_controller; @@ -1539,9 +1539,8 @@ error: return retval; } -EXPORT_SYMBOL(usb_gadget_probe_driver); -int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) +static int fusb300_udc_stop(struct usb_gadget_driver *driver) { struct fusb300 *fusb300 = the_controller; @@ -1557,7 +1556,6 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) return 0; } -EXPORT_SYMBOL(usb_gadget_unregister_driver); /*--------------------------------------------------------------------------*/ static int fusb300_udc_pullup(struct usb_gadget *_gadget, int is_active) @@ -1567,12 +1565,15 @@ static int fusb300_udc_pullup(struct usb_gadget *_gadget, int is_active) static struct usb_gadget_ops fusb300_gadget_ops = { .pullup = fusb300_udc_pullup, + .start = fusb300_udc_start, + .stop = fusb300_udc_stop, }; static int __exit fusb300_remove(struct platform_device *pdev) { struct fusb300 *fusb300 = dev_get_drvdata(&pdev->dev); + usb_del_gadget_udc(&fusb300->gadget); iounmap(fusb300->reg); free_irq(platform_get_irq(pdev, 0), fusb300); @@ -1697,9 +1698,15 @@ static int __init fusb300_probe(struct platform_device *pdev) goto clean_up3; init_controller(fusb300); + ret = usb_add_gadget_udc(&pdev->dev, &fusb300->gadget); + if (ret) + goto err_add_udc; + dev_info(&pdev->dev, "version %s\n", DRIVER_VERSION); return 0; +err_add_udc: + fusb300_free_request(&fusb300->ep[0]->ep, fusb300->ep0_req); clean_up3: free_irq(ires->start, fusb300); diff --git a/drivers/usb/gadget/goku_udc.c b/drivers/usb/gadget/goku_udc.c index bf6e11c758d..7f87805cddc 100644 --- a/drivers/usb/gadget/goku_udc.c +++ b/drivers/usb/gadget/goku_udc.c @@ -996,8 +996,14 @@ static int goku_get_frame(struct usb_gadget *_gadget) return -EOPNOTSUPP; } +static int goku_start(struct usb_gadget_driver *driver, + int (*bind)(struct usb_gadget *)); +static int goku_stop(struct usb_gadget_driver *driver); + static const struct usb_gadget_ops goku_ops = { .get_frame = goku_get_frame, + .start = goku_start, + .stop = goku_stop, // no remote wakeup // not selfpowered }; @@ -1344,7 +1350,7 @@ static struct goku_udc *the_controller; * disconnect is reported. then a host may connect again, or * the driver might get unbound. */ -int usb_gadget_probe_driver(struct usb_gadget_driver *driver, +static int goku_start(struct usb_gadget_driver *driver, int (*bind)(struct usb_gadget *)) { struct goku_udc *dev = the_controller; @@ -1382,7 +1388,6 @@ int usb_gadget_probe_driver(struct usb_gadget_driver *driver, DBG(dev, "registered gadget driver '%s'\n", driver->driver.name); return 0; } -EXPORT_SYMBOL(usb_gadget_probe_driver); static void stop_activity(struct goku_udc *dev, struct usb_gadget_driver *driver) @@ -1408,7 +1413,7 @@ stop_activity(struct goku_udc *dev, struct usb_gadget_driver *driver) udc_enable(dev); } -int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) +static int goku_stop(struct usb_gadget_driver *driver) { struct goku_udc *dev = the_controller; unsigned long flags; @@ -1429,8 +1434,6 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) DBG(dev, "unregistered driver '%s'\n", driver->driver.name); return 0; } -EXPORT_SYMBOL(usb_gadget_unregister_driver); - /*-------------------------------------------------------------------------*/ @@ -1730,6 +1733,8 @@ static void goku_remove(struct pci_dev *pdev) DBG(dev, "%s\n", __func__); + usb_del_gadget_udc(&dev->gadget); + BUG_ON(dev->driver); #ifdef CONFIG_USB_GADGET_DEBUG_FILES @@ -1854,6 +1859,10 @@ static int goku_probe(struct pci_dev *pdev, const struct pci_device_id *id) goto err; } dev->registered = 1; + retval = usb_add_gadget_udc(&pdev->dev, &dev->gadget); + if (retval) + goto err; + return 0; err: diff --git a/drivers/usb/gadget/imx_udc.c b/drivers/usb/gadget/imx_udc.c index ade40066dec..692fd9b2248 100644 --- a/drivers/usb/gadget/imx_udc.c +++ b/drivers/usb/gadget/imx_udc.c @@ -1237,9 +1237,14 @@ irq_handler_t intr_handler(int i) ******************************************************************************* */ +static int imx_udc_start(struct usb_gadget_driver *driver, + int (*bind)(struct usb_gadget *)); +static int imx_udc_stop(struct usb_gadget_driver *driver); static const struct usb_gadget_ops imx_udc_ops = { .get_frame = imx_udc_get_frame, .wakeup = imx_udc_wakeup, + .start = imx_udc_start, + .stop = imx_udc_stop, }; static struct imx_udc_struct controller = { @@ -1324,7 +1329,7 @@ static struct imx_udc_struct controller = { * USB gadget driver functions ******************************************************************************* */ -int usb_gadget_probe_driver(struct usb_gadget_driver *driver, +static int imx_udc_start(struct usb_gadget_driver *driver, int (*bind)(struct usb_gadget *)) { struct imx_udc_struct *imx_usb = &controller; @@ -1368,9 +1373,8 @@ fail: imx_usb->gadget.dev.driver = NULL; return retval; } -EXPORT_SYMBOL(usb_gadget_probe_driver); -int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) +static int imx_udc_stop(struct usb_gadget_driver *driver) { struct imx_udc_struct *imx_usb = &controller; @@ -1394,7 +1398,6 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) return 0; } -EXPORT_SYMBOL(usb_gadget_unregister_driver); /******************************************************************************* * Module functions @@ -1504,8 +1507,14 @@ static int __init imx_udc_probe(struct platform_device *pdev) imx_usb->timer.function = handle_config; imx_usb->timer.data = (unsigned long)imx_usb; - return 0; + ret = usb_add_gadget_udc(&pdev->dev, &imx_usb->gadget); + if (ret) + goto fail4; + return 0; +fail4: + for (i = 0; i < IMX_USB_NB_EP + 1; i++) + free_irq(imx_usb->usbd_int[i], imx_usb); fail3: clk_put(clk); clk_disable(clk); @@ -1525,6 +1534,7 @@ static int __exit imx_udc_remove(struct platform_device *pdev) struct imxusb_platform_data *pdata = pdev->dev.platform_data; int i; + usb_del_gadget_udc(&imx_usb->gadget); imx_udc_disable(imx_usb); del_timer(&imx_usb->timer); diff --git a/drivers/usb/gadget/langwell_udc.c b/drivers/usb/gadget/langwell_udc.c index 9cee88a43a7..d8403ae3c2b 100644 --- a/drivers/usb/gadget/langwell_udc.c +++ b/drivers/usb/gadget/langwell_udc.c @@ -1321,7 +1321,9 @@ static int langwell_pullup(struct usb_gadget *_gadget, int is_on) return 0; } - +static int langwell_start(struct usb_gadget_driver *driver, + int (*bind)(struct usb_gadget *)); +static int langwell_stop(struct usb_gadget_driver *driver); /* device controller usb_gadget_ops structure */ static const struct usb_gadget_ops langwell_ops = { @@ -1342,6 +1344,9 @@ static const struct usb_gadget_ops langwell_ops = { /* D+ pullup, software-controlled connect/disconnect to USB host */ .pullup = langwell_pullup, + + .start = langwell_start, + .stop = langwell_stop, }; @@ -1852,7 +1857,7 @@ static DEVICE_ATTR(remote_wakeup, S_IWUSR, NULL, store_remote_wakeup); * the driver might get unbound. */ -int usb_gadget_probe_driver(struct usb_gadget_driver *driver, +static int langwell_start(struct usb_gadget_driver *driver, int (*bind)(struct usb_gadget *)) { struct langwell_udc *dev = the_controller; @@ -1914,11 +1919,9 @@ err_unbind: dev_dbg(&dev->pdev->dev, "<--- %s()\n", __func__); return retval; } -EXPORT_SYMBOL(usb_gadget_probe_driver); - /* unregister gadget driver */ -int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) +static int langwell_stop(struct usb_gadget_driver *driver) { struct langwell_udc *dev = the_controller; unsigned long flags; @@ -1965,8 +1968,6 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) dev_dbg(&dev->pdev->dev, "<--- %s()\n", __func__); return 0; } -EXPORT_SYMBOL(usb_gadget_unregister_driver); - /*-------------------------------------------------------------------------*/ @@ -3373,6 +3374,10 @@ static int langwell_udc_probe(struct pci_dev *pdev, if (retval) goto error; + retval = usb_add_gadget_udc(&pdev->dev, &dev->gadget); + if (retval) + goto error; + retval = device_create_file(&pdev->dev, &dev_attr_langwell_udc); if (retval) goto error; @@ -3403,6 +3408,7 @@ static int langwell_udc_suspend(struct pci_dev *pdev, pm_message_t state) dev_dbg(&dev->pdev->dev, "---> %s()\n", __func__); + usb_del_gadget_udc(&dev->gadget); /* disable interrupt and set controller to stop state */ langwell_udc_stop(dev); diff --git a/drivers/usb/gadget/m66592-udc.c b/drivers/usb/gadget/m66592-udc.c index 084aa080a2d..11d37821ce7 100644 --- a/drivers/usb/gadget/m66592-udc.c +++ b/drivers/usb/gadget/m66592-udc.c @@ -1454,7 +1454,7 @@ static struct usb_ep_ops m66592_ep_ops = { /*-------------------------------------------------------------------------*/ static struct m66592 *the_controller; -int usb_gadget_probe_driver(struct usb_gadget_driver *driver, +static int m66592_start(struct usb_gadget_driver *driver, int (*bind)(struct usb_gadget *)) { struct m66592 *m66592 = the_controller; @@ -1506,9 +1506,8 @@ error: return retval; } -EXPORT_SYMBOL(usb_gadget_probe_driver); -int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) +static int m66592_stop(struct usb_gadget_driver *driver) { struct m66592 *m66592 = the_controller; unsigned long flags; @@ -1533,7 +1532,6 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) m66592->driver = NULL; return 0; } -EXPORT_SYMBOL(usb_gadget_unregister_driver); /*-------------------------------------------------------------------------*/ static int m66592_get_frame(struct usb_gadget *_gadget) @@ -1544,12 +1542,16 @@ static int m66592_get_frame(struct usb_gadget *_gadget) static struct usb_gadget_ops m66592_gadget_ops = { .get_frame = m66592_get_frame, + .start = m66592_start, + .stop = m66592_stop, }; static int __exit m66592_remove(struct platform_device *pdev) { struct m66592 *m66592 = dev_get_drvdata(&pdev->dev); + usb_del_gadget_udc(&m66592->gadget); + del_timer_sync(&m66592->timer); iounmap(m66592->reg); free_irq(platform_get_irq(pdev, 0), m66592); @@ -1691,9 +1693,16 @@ static int __init m66592_probe(struct platform_device *pdev) init_controller(m66592); + ret = usb_add_gadget_udc(&pdev->dev, &m66592->gadget); + if (ret) + goto err_add_udc; + dev_info(&pdev->dev, "version %s\n", DRIVER_VERSION); return 0; +err_add_udc: + m66592_free_request(&m66592->ep[0].ep, m66592->ep0_req); + clean_up3: #ifdef CONFIG_HAVE_CLK if (m66592->pdata->on_chip) { diff --git a/drivers/usb/gadget/mv_udc_core.c b/drivers/usb/gadget/mv_udc_core.c index b1a8146b9d5..6adf38c5353 100644 --- a/drivers/usb/gadget/mv_udc_core.c +++ b/drivers/usb/gadget/mv_udc_core.c @@ -1128,6 +1128,9 @@ static int mv_udc_pullup(struct usb_gadget *gadget, int is_on) return 0; } +static int mv_udc_start(struct usb_gadget_driver *driver, + int (*bind)(struct usb_gadget *)); +static int mv_udc_stop(struct usb_gadget_driver *driver); /* device controller usb_gadget_ops structure */ static const struct usb_gadget_ops mv_ops = { @@ -1139,6 +1142,8 @@ static const struct usb_gadget_ops mv_ops = { /* D+ pullup, software-controlled connect/disconnect to USB host */ .pullup = mv_udc_pullup, + .start = mv_udc_start, + .stop = mv_udc_stop, }; static void mv_udc_testmode(struct mv_udc *udc, u16 index, bool enter) @@ -1230,7 +1235,7 @@ static void stop_activity(struct mv_udc *udc, struct usb_gadget_driver *driver) } } -int usb_gadget_probe_driver(struct usb_gadget_driver *driver, +static int mv_udc_start(struct usb_gadget_driver *driver, int (*bind)(struct usb_gadget *)) { struct mv_udc *udc = the_controller; @@ -1270,9 +1275,8 @@ int usb_gadget_probe_driver(struct usb_gadget_driver *driver, return 0; } -EXPORT_SYMBOL(usb_gadget_probe_driver); -int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) +static int mv_udc_stop(struct usb_gadget_driver *driver) { struct mv_udc *udc = the_controller; unsigned long flags; @@ -1296,7 +1300,6 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) return 0; } -EXPORT_SYMBOL(usb_gadget_unregister_driver); static int udc_prime_status(struct mv_udc *udc, u8 direction, u16 status, bool empty) @@ -1880,9 +1883,10 @@ static void gadget_release(struct device *_dev) static int mv_udc_remove(struct platform_device *dev) { struct mv_udc *udc = the_controller; - DECLARE_COMPLETION(done); + usb_del_gadget_udc(&udc->gadget); + udc->done = &done; /* free memory allocated in probe */ @@ -2074,11 +2078,12 @@ int mv_udc_probe(struct platform_device *dev) the_controller = udc; - goto out; + retval = usb_add_gadget_udc(&dev->dev, &udc->gadget); + if (!retval) + return retval; error: if (udc) mv_udc_remove(udc->dev); -out: return retval; } diff --git a/drivers/usb/gadget/net2272.c b/drivers/usb/gadget/net2272.c index 29151c44f47..7f1219e239a 100644 --- a/drivers/usb/gadget/net2272.c +++ b/drivers/usb/gadget/net2272.c @@ -1172,11 +1172,17 @@ 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 const struct usb_gadget_ops net2272_ops = { .get_frame = net2272_get_frame, .wakeup = net2272_wakeup, .set_selfpowered = net2272_set_selfpowered, - .pullup = net2272_pullup + .pullup = net2272_pullup, + .start = net2272_start, + .stop = net2272_stop, }; /*---------------------------------------------------------------------------*/ @@ -1447,7 +1453,7 @@ net2272_ep0_start(struct net2272 *dev) * disconnect is reported. then a host may connect again, or * the driver might get unbound. */ -int usb_gadget_probe_driver(struct usb_gadget_driver *driver, +static int net2272_start(struct usb_gadget_driver *driver, int (*bind)(struct usb_gadget *)) { struct net2272 *dev = the_controller; @@ -1487,7 +1493,6 @@ int usb_gadget_probe_driver(struct usb_gadget_driver *driver, return 0; } -EXPORT_SYMBOL(usb_gadget_probe_driver); static void stop_activity(struct net2272 *dev, struct usb_gadget_driver *driver) @@ -1515,7 +1520,7 @@ stop_activity(struct net2272 *dev, struct usb_gadget_driver *driver) net2272_usb_reinit(dev); } -int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) +static int net2272_stop(struct usb_gadget_driver *driver) { struct net2272 *dev = the_controller; unsigned long flags; @@ -1538,7 +1543,6 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) dev_dbg(dev->dev, "unregistered driver '%s'\n", driver->driver.name); return 0; } -EXPORT_SYMBOL(usb_gadget_unregister_driver); /*---------------------------------------------------------------------------*/ /* handle ep-a/ep-b dma completions */ @@ -2217,6 +2221,8 @@ net2272_gadget_release(struct device *_dev) static void __devexit net2272_remove(struct net2272 *dev) { + usb_del_gadget_udc(&dev->gadget); + /* start with the driver above us */ if (dev->driver) { /* should have been done already by driver model core */ @@ -2310,8 +2316,14 @@ net2272_probe_fin(struct net2272 *dev, unsigned int irqflags) if (ret) goto err_dev_reg; + ret = usb_add_gadget_udc(dev->dev, &dev->gadget); + if (ret) + goto err_add_udc; + return 0; +err_add_udc: + device_remove_file(dev->dev, &dev_attr_registers); err_dev_reg: device_unregister(&dev->gadget.dev); err_irq: diff --git a/drivers/usb/gadget/net2280.c b/drivers/usb/gadget/net2280.c index 476d88e1ae9..1e6ea6f2650 100644 --- a/drivers/usb/gadget/net2280.c +++ b/drivers/usb/gadget/net2280.c @@ -1410,11 +1410,17 @@ static int net2280_pullup(struct usb_gadget *_gadget, int is_on) return 0; } +static int net2280_start(struct usb_gadget_driver *driver, + int (*bind)(struct usb_gadget *)); +static int net2280_stop(struct usb_gadget_driver *driver); + static const struct usb_gadget_ops net2280_ops = { .get_frame = net2280_get_frame, .wakeup = net2280_wakeup, .set_selfpowered = net2280_set_selfpowered, .pullup = net2280_pullup, + .start = net2280_start, + .stop = net2280_stop, }; /*-------------------------------------------------------------------------*/ @@ -1930,7 +1936,7 @@ static void ep0_start (struct net2280 *dev) * disconnect is reported. then a host may connect again, or * the driver might get unbound. */ -int usb_gadget_probe_driver(struct usb_gadget_driver *driver, +static int net2280_start(struct usb_gadget_driver *driver, int (*bind)(struct usb_gadget *)) { struct net2280 *dev = the_controller; @@ -1994,7 +2000,6 @@ err_unbind: dev->driver = NULL; return retval; } -EXPORT_SYMBOL(usb_gadget_probe_driver); static void stop_activity (struct net2280 *dev, struct usb_gadget_driver *driver) @@ -2022,7 +2027,7 @@ stop_activity (struct net2280 *dev, struct usb_gadget_driver *driver) usb_reinit (dev); } -int usb_gadget_unregister_driver (struct usb_gadget_driver *driver) +static int net2280_stop(struct usb_gadget_driver *driver) { struct net2280 *dev = the_controller; unsigned long flags; @@ -2049,8 +2054,6 @@ int usb_gadget_unregister_driver (struct usb_gadget_driver *driver) DEBUG (dev, "unregistered driver '%s'\n", driver->driver.name); return 0; } -EXPORT_SYMBOL (usb_gadget_unregister_driver); - /*-------------------------------------------------------------------------*/ @@ -2732,6 +2735,8 @@ static void net2280_remove (struct pci_dev *pdev) { struct net2280 *dev = pci_get_drvdata (pdev); + usb_del_gadget_udc(&dev->gadget); + BUG_ON(dev->driver); /* then clean up the resources we allocated during probe() */ @@ -2916,6 +2921,9 @@ static int net2280_probe (struct pci_dev *pdev, const struct pci_device_id *id) retval = device_create_file (&pdev->dev, &dev_attr_registers); if (retval) goto done; + retval = usb_add_gadget_udc(&pdev->dev, &dev->gadget); + if (retval) + goto done; return 0; done: diff --git a/drivers/usb/gadget/omap_udc.c b/drivers/usb/gadget/omap_udc.c index 82fd2493533..740c7daed27 100644 --- a/drivers/usb/gadget/omap_udc.c +++ b/drivers/usb/gadget/omap_udc.c @@ -1375,6 +1375,10 @@ static int omap_pullup(struct usb_gadget *gadget, int is_on) return 0; } +static int omap_udc_start(struct usb_gadget_driver *driver, + int (*bind)(struct usb_gadget *)); +static int omap_udc_stop(struct usb_gadget_driver *driver); + static struct usb_gadget_ops omap_gadget_ops = { .get_frame = omap_get_frame, .wakeup = omap_wakeup, @@ -1382,6 +1386,8 @@ static struct usb_gadget_ops omap_gadget_ops = { .vbus_session = omap_vbus_session, .vbus_draw = omap_vbus_draw, .pullup = omap_pullup, + .start = omap_udc_start, + .stop = omap_udc_stop, }; /*-------------------------------------------------------------------------*/ @@ -2102,7 +2108,7 @@ static inline int machine_without_vbus_sense(void) ); } -int usb_gadget_probe_driver(struct usb_gadget_driver *driver, +static int omap_udc_start(struct usb_gadget_driver *driver, int (*bind)(struct usb_gadget *)) { int status = -ENODEV; @@ -2186,9 +2192,8 @@ done: omap_udc_enable_clock(0); return status; } -EXPORT_SYMBOL(usb_gadget_probe_driver); -int usb_gadget_unregister_driver (struct usb_gadget_driver *driver) +static int omap_udc_stop(struct usb_gadget_driver *driver) { unsigned long flags; int status = -ENODEV; @@ -2222,8 +2227,6 @@ int usb_gadget_unregister_driver (struct usb_gadget_driver *driver) DBG("unregistered driver '%s'\n", driver->driver.name); return status; } -EXPORT_SYMBOL(usb_gadget_unregister_driver); - /*-------------------------------------------------------------------------*/ @@ -2991,9 +2994,16 @@ known: create_proc_file(); status = device_add(&udc->gadget.dev); + if (status) + goto cleanup4; + + status = usb_add_gadget_udc(&pdev->dev, &udc->gadget); if (!status) return status; /* If fail, fall through */ +cleanup4: + remove_proc_file(); + #ifdef USE_ISO cleanup3: free_irq(pdev->resource[2].start, udc); @@ -3029,6 +3039,8 @@ static int __exit omap_udc_remove(struct platform_device *pdev) if (!udc) return -ENODEV; + + usb_del_gadget_udc(&udc->gadget); if (udc->driver) return -EBUSY; diff --git a/drivers/usb/gadget/pch_udc.c b/drivers/usb/gadget/pch_udc.c index 68dbcc3e4cc..f96615ab6b7 100644 --- a/drivers/usb/gadget/pch_udc.c +++ b/drivers/usb/gadget/pch_udc.c @@ -1176,6 +1176,9 @@ static int pch_udc_pcd_vbus_draw(struct usb_gadget *gadget, unsigned int mA) return -EOPNOTSUPP; } +static int pch_udc_start(struct usb_gadget_driver *driver, + int (*bind)(struct usb_gadget *)); +static int pch_udc_stop(struct usb_gadget_driver *driver); static const struct usb_gadget_ops pch_udc_ops = { .get_frame = pch_udc_pcd_get_frame, .wakeup = pch_udc_pcd_wakeup, @@ -1183,6 +1186,8 @@ static const struct usb_gadget_ops pch_udc_ops = { .pullup = pch_udc_pcd_pullup, .vbus_session = pch_udc_pcd_vbus_session, .vbus_draw = pch_udc_pcd_vbus_draw, + .start = pch_udc_start, + .stop = pch_udc_stop, }; /** @@ -2690,7 +2695,7 @@ static int init_dma_pools(struct pch_udc_dev *dev) return 0; } -int usb_gadget_probe_driver(struct usb_gadget_driver *driver, +static int pch_udc_start(struct usb_gadget_driver *driver, int (*bind)(struct usb_gadget *)) { struct pch_udc_dev *dev = pch_udc; @@ -2733,9 +2738,8 @@ int usb_gadget_probe_driver(struct usb_gadget_driver *driver, dev->connected = 1; return 0; } -EXPORT_SYMBOL(usb_gadget_probe_driver); -int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) +static int pch_udc_stop(struct usb_gadget_driver *driver) { struct pch_udc_dev *dev = pch_udc; @@ -2761,7 +2765,6 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) pch_udc_set_disconnect(dev); return 0; } -EXPORT_SYMBOL(usb_gadget_unregister_driver); static void pch_udc_shutdown(struct pci_dev *pdev) { @@ -2778,6 +2781,8 @@ static void pch_udc_remove(struct pci_dev *pdev) { struct pch_udc_dev *dev = pci_get_drvdata(pdev); + usb_del_gadget_udc(&dev->gadget); + /* gadget driver must not be registered */ if (dev->driver) dev_err(&pdev->dev, @@ -2953,6 +2958,9 @@ static int pch_udc_probe(struct pci_dev *pdev, /* Put the device in disconnected state till a driver is bound */ pch_udc_set_disconnect(dev); + retval = usb_add_gadget_udc(&pdev->dev, &dev->gadget); + if (retval) + goto finished; return 0; finished: diff --git a/drivers/usb/gadget/pxa25x_udc.c b/drivers/usb/gadget/pxa25x_udc.c index 774545494cf..e4e59b4de25 100644 --- a/drivers/usb/gadget/pxa25x_udc.c +++ b/drivers/usb/gadget/pxa25x_udc.c @@ -1011,12 +1011,18 @@ static int pxa25x_udc_vbus_draw(struct usb_gadget *_gadget, unsigned mA) return -EOPNOTSUPP; } +static int pxa25x_start(struct usb_gadget_driver *driver, + int (*bind)(struct usb_gadget *)); +static int pxa25x_stop(struct usb_gadget_driver *driver); + static const struct usb_gadget_ops pxa25x_udc_ops = { .get_frame = pxa25x_udc_get_frame, .wakeup = pxa25x_udc_wakeup, .vbus_session = pxa25x_udc_vbus_session, .pullup = pxa25x_udc_pullup, .vbus_draw = pxa25x_udc_vbus_draw, + .start = pxa25x_start, + .stop = pxa25x_stop, }; /*-------------------------------------------------------------------------*/ @@ -1263,7 +1269,7 @@ static void udc_enable (struct pxa25x_udc *dev) * disconnect is reported. then a host may connect again, or * the driver might get unbound. */ -int usb_gadget_probe_driver(struct usb_gadget_driver *driver, +static int pxa25x_start(struct usb_gadget_driver *driver, int (*bind)(struct usb_gadget *)) { struct pxa25x_udc *dev = the_controller; @@ -1322,7 +1328,6 @@ fail: bind_fail: return retval; } -EXPORT_SYMBOL(usb_gadget_probe_driver); static void stop_activity(struct pxa25x_udc *dev, struct usb_gadget_driver *driver) @@ -1351,7 +1356,7 @@ stop_activity(struct pxa25x_udc *dev, struct usb_gadget_driver *driver) udc_reinit(dev); } -int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) +static int pxa25x_stop(struct usb_gadget_driver *driver) { struct pxa25x_udc *dev = the_controller; @@ -1379,8 +1384,6 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) dump_state(dev); return 0; } -EXPORT_SYMBOL(usb_gadget_unregister_driver); - /*-------------------------------------------------------------------------*/ @@ -2231,8 +2234,11 @@ static int __init pxa25x_udc_probe(struct platform_device *pdev) #endif create_debug_files(dev); - return 0; + retval = usb_add_gadget_udc(&pdev->dev, &dev->gadget); + if (!retval) + return retval; + remove_debug_files(dev); #ifdef CONFIG_ARCH_LUBBOCK lubbock_fail0: free_irq(LUBBOCK_USB_DISC_IRQ, dev); @@ -2261,6 +2267,7 @@ static int __exit pxa25x_udc_remove(struct platform_device *pdev) { struct pxa25x_udc *dev = platform_get_drvdata(pdev); + usb_del_gadget_udc(&dev->gadget); if (dev->driver) return -EBUSY; diff --git a/drivers/usb/gadget/pxa27x_udc.c b/drivers/usb/gadget/pxa27x_udc.c index 57607696735..85b68c75dc9 100644 --- a/drivers/usb/gadget/pxa27x_udc.c +++ b/drivers/usb/gadget/pxa27x_udc.c @@ -1680,12 +1680,18 @@ static int pxa_udc_vbus_draw(struct usb_gadget *_gadget, unsigned mA) return -EOPNOTSUPP; } +static int pxa27x_udc_start(struct usb_gadget_driver *driver, + int (*bind)(struct usb_gadget *)); +static int pxa27x_udc_stop(struct usb_gadget_driver *driver); + static const struct usb_gadget_ops pxa_udc_ops = { .get_frame = pxa_udc_get_frame, .wakeup = pxa_udc_wakeup, .pullup = pxa_udc_pullup, .vbus_session = pxa_udc_vbus_session, .vbus_draw = pxa_udc_vbus_draw, + .start = pxa27x_udc_start, + .stop = pxa27x_udc_stop, }; /** @@ -1791,7 +1797,7 @@ static void udc_enable(struct pxa_udc *udc) } /** - * usb_gadget_probe_driver - Register gadget driver + * pxa27x_start - Register gadget driver * @driver: gadget driver * @bind: bind function * @@ -1805,7 +1811,7 @@ static void udc_enable(struct pxa_udc *udc) * * Returns 0 if no error, -EINVAL, -ENODEV, -EBUSY otherwise */ -int usb_gadget_probe_driver(struct usb_gadget_driver *driver, +static int pxa27x_udc_start(struct usb_gadget_driver *driver, int (*bind)(struct usb_gadget *)) { struct pxa_udc *udc = the_controller; @@ -1860,8 +1866,6 @@ add_fail: udc->gadget.dev.driver = NULL; return retval; } -EXPORT_SYMBOL(usb_gadget_probe_driver); - /** * stop_activity - Stops udc endpoints @@ -1888,12 +1892,12 @@ static void stop_activity(struct pxa_udc *udc, struct usb_gadget_driver *driver) } /** - * usb_gadget_unregister_driver - Unregister the gadget driver + * pxa27x_udc_stop - Unregister the gadget driver * @driver: gadget driver * * Returns 0 if no error, -ENODEV, -EINVAL otherwise */ -int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) +static int pxa27x_udc_stop(struct usb_gadget_driver *driver) { struct pxa_udc *udc = the_controller; @@ -1917,7 +1921,6 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) return otg_set_peripheral(udc->transceiver, NULL); return 0; } -EXPORT_SYMBOL(usb_gadget_unregister_driver); /** * handle_ep0_ctrl_req - handle control endpoint control request @@ -2516,9 +2519,14 @@ static int __init pxa_udc_probe(struct platform_device *pdev) driver_name, IRQ_USB, retval); goto err_irq; } + retval = usb_add_gadget_udc(&pdev->dev, &udc->gadget); + if (retval) + goto err_add_udc; pxa_init_debugfs(udc); return 0; +err_add_udc: + free_irq(udc->irq, udc); err_irq: iounmap(udc->regs); err_map: @@ -2537,6 +2545,7 @@ static int __exit pxa_udc_remove(struct platform_device *_dev) struct pxa_udc *udc = platform_get_drvdata(_dev); int gpio = udc->mach->gpio_pullup; + usb_del_gadget_udc(&udc->gadget); usb_gadget_unregister_driver(udc->driver); free_irq(udc->irq, udc); pxa_cleanup_debugfs(udc); diff --git a/drivers/usb/gadget/r8a66597-udc.c b/drivers/usb/gadget/r8a66597-udc.c index 6dcc1f68fa6..51b655f3b47 100644 --- a/drivers/usb/gadget/r8a66597-udc.c +++ b/drivers/usb/gadget/r8a66597-udc.c @@ -1410,7 +1410,7 @@ static struct usb_ep_ops r8a66597_ep_ops = { /*-------------------------------------------------------------------------*/ static struct r8a66597 *the_controller; -int usb_gadget_probe_driver(struct usb_gadget_driver *driver, +static int r8a66597_start(struct usb_gadget_driver *driver, int (*bind)(struct usb_gadget *)) { struct r8a66597 *r8a66597 = the_controller; @@ -1462,9 +1462,8 @@ error: return retval; } -EXPORT_SYMBOL(usb_gadget_probe_driver); -int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) +static int r8a66597_stop(struct usb_gadget_driver *driver) { struct r8a66597 *r8a66597 = the_controller; unsigned long flags; @@ -1488,7 +1487,6 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) r8a66597->driver = NULL; return 0; } -EXPORT_SYMBOL(usb_gadget_unregister_driver); /*-------------------------------------------------------------------------*/ static int r8a66597_get_frame(struct usb_gadget *_gadget) @@ -1499,12 +1497,15 @@ static int r8a66597_get_frame(struct usb_gadget *_gadget) static struct usb_gadget_ops r8a66597_gadget_ops = { .get_frame = r8a66597_get_frame, + .start = r8a66597_start, + .stop = r8a66597_stop, }; static int __exit r8a66597_remove(struct platform_device *pdev) { struct r8a66597 *r8a66597 = dev_get_drvdata(&pdev->dev); + usb_del_gadget_udc(&r8a66597->gadget); del_timer_sync(&r8a66597->timer); iounmap(r8a66597->reg); free_irq(platform_get_irq(pdev, 0), r8a66597); @@ -1647,9 +1648,15 @@ static int __init r8a66597_probe(struct platform_device *pdev) init_controller(r8a66597); + ret = usb_add_gadget_udc(&pdev->dev, &r8a66597->gadget); + if (ret) + goto err_add_udc; + dev_info(&pdev->dev, "version %s\n", DRIVER_VERSION); return 0; +err_add_udc: + r8a66597_free_request(&r8a66597->ep[0].ep, r8a66597->ep0_req); clean_up3: free_irq(irq, r8a66597); clean_up2: diff --git a/drivers/usb/gadget/s3c-hsotg.c b/drivers/usb/gadget/s3c-hsotg.c index 0dfee282878..8bdee67ce09 100644 --- a/drivers/usb/gadget/s3c-hsotg.c +++ b/drivers/usb/gadget/s3c-hsotg.c @@ -2574,7 +2574,7 @@ static int s3c_hsotg_corereset(struct s3c_hsotg *hsotg) return 0; } -int usb_gadget_probe_driver(struct usb_gadget_driver *driver, +static int s3c_hsotg_start(struct usb_gadget_driver *driver, int (*bind)(struct usb_gadget *)) { struct s3c_hsotg *hsotg = our_hsotg; @@ -2745,9 +2745,8 @@ err: hsotg->gadget.dev.driver = NULL; return ret; } -EXPORT_SYMBOL(usb_gadget_probe_driver); -int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) +static int s3c_hsotg_stop(struct usb_gadget_driver *driver) { struct s3c_hsotg *hsotg = our_hsotg; int ep; @@ -2775,7 +2774,6 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) return 0; } -EXPORT_SYMBOL(usb_gadget_unregister_driver); static int s3c_hsotg_gadget_getframe(struct usb_gadget *gadget) { @@ -2784,6 +2782,8 @@ static int s3c_hsotg_gadget_getframe(struct usb_gadget *gadget) static struct usb_gadget_ops s3c_hsotg_gadget_ops = { .get_frame = s3c_hsotg_gadget_getframe, + .start = s3c_hsotg_start, + .stop = s3c_hsotg_stop, }; /** @@ -3403,6 +3403,10 @@ static int __devinit s3c_hsotg_probe(struct platform_device *pdev) for (epnum = 0; epnum < S3C_HSOTG_EPS; epnum++) s3c_hsotg_initep(hsotg, &hsotg->eps[epnum], epnum); + ret = usb_add_gadget_udc(&pdev->dev, &hsotg->gadget); + if (ret) + goto err_add_udc; + s3c_hsotg_create_debug(hsotg); s3c_hsotg_dump(hsotg); @@ -3410,6 +3414,11 @@ static int __devinit s3c_hsotg_probe(struct platform_device *pdev) our_hsotg = hsotg; return 0; +err_add_udc: + s3c_hsotg_gate(pdev, false); + clk_disable(hsotg->clk); + clk_put(hsotg->clk); + err_regs: iounmap(hsotg->regs); @@ -3427,6 +3436,8 @@ static int __devexit s3c_hsotg_remove(struct platform_device *pdev) { struct s3c_hsotg *hsotg = platform_get_drvdata(pdev); + usb_del_gadget_udc(&hsotg->gadget); + s3c_hsotg_delete_debug(hsotg); usb_gadget_unregister_driver(hsotg->driver); diff --git a/drivers/usb/gadget/s3c-hsudc.c b/drivers/usb/gadget/s3c-hsudc.c index d5e3e1e5862..dc9f42823a4 100644 --- a/drivers/usb/gadget/s3c-hsudc.c +++ b/drivers/usb/gadget/s3c-hsudc.c @@ -1133,7 +1133,7 @@ static irqreturn_t s3c_hsudc_irq(int irq, void *_dev) return IRQ_HANDLED; } -int usb_gadget_probe_driver(struct usb_gadget_driver *driver, +static int s3c_hsudc_start(struct usb_gadget_driver *driver, int (*bind)(struct usb_gadget *)) { struct s3c_hsudc *hsudc = the_controller; @@ -1181,9 +1181,8 @@ int usb_gadget_probe_driver(struct usb_gadget_driver *driver, return 0; } -EXPORT_SYMBOL(usb_gadget_probe_driver); -int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) +static int s3c_hsudc_stop(struct usb_gadget_driver *driver) { struct s3c_hsudc *hsudc = the_controller; unsigned long flags; @@ -1210,7 +1209,6 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) driver->driver.name); return 0; } -EXPORT_SYMBOL(usb_gadget_unregister_driver); static inline u32 s3c_hsudc_read_frameno(struct s3c_hsudc *hsudc) { @@ -1224,6 +1222,8 @@ static int s3c_hsudc_gadget_getframe(struct usb_gadget *gadget) static struct usb_gadget_ops s3c_hsudc_gadget_ops = { .get_frame = s3c_hsudc_gadget_getframe, + .start = s3c_hsudc_start, + .stop = s3c_hsudc_stop, }; static int s3c_hsudc_probe(struct platform_device *pdev) @@ -1311,7 +1311,15 @@ static int s3c_hsudc_probe(struct platform_device *pdev) disable_irq(hsudc->irq); local_irq_enable(); + + ret = usb_add_gadget_udc(&pdev->dev, &hsudc->gadget); + if (ret) + goto err_add_udc; + return 0; +err_add_udc: + clk_disable(hsudc->uclk); + clk_put(hsudc->uclk); err_clk: free_irq(hsudc->irq, hsudc); err_irq: diff --git a/drivers/usb/gadget/s3c2410_udc.c b/drivers/usb/gadget/s3c2410_udc.c index 100f2635cf0..1c19cd3f6a5 100644 --- a/drivers/usb/gadget/s3c2410_udc.c +++ b/drivers/usb/gadget/s3c2410_udc.c @@ -1552,6 +1552,10 @@ static int s3c2410_vbus_draw(struct usb_gadget *_gadget, unsigned ma) return -ENOTSUPP; } +static int s3c2410_udc_start(struct usb_gadget_driver *driver, + int (*bind)(struct usb_gadget *)); +static int s3c2410_udc_stop(struct usb_gadget_driver *driver); + static const struct usb_gadget_ops s3c2410_ops = { .get_frame = s3c2410_udc_get_frame, .wakeup = s3c2410_udc_wakeup, @@ -1559,6 +1563,8 @@ static const struct usb_gadget_ops s3c2410_ops = { .pullup = s3c2410_udc_pullup, .vbus_session = s3c2410_udc_vbus_session, .vbus_draw = s3c2410_vbus_draw, + .start = s3c2410_udc_start, + .stop = s3c2410_udc_stop, }; static void s3c2410_udc_command(enum s3c2410_udc_cmd_e cmd) @@ -1672,10 +1678,7 @@ static void s3c2410_udc_enable(struct s3c2410_udc *dev) s3c2410_udc_command(S3C2410_UDC_P_ENABLE); } -/* - * usb_gadget_probe_driver - */ -int usb_gadget_probe_driver(struct usb_gadget_driver *driver, +static int s3c2410_udc_start(struct usb_gadget_driver *driver, int (*bind)(struct usb_gadget *)) { struct s3c2410_udc *udc = the_controller; @@ -1730,12 +1733,8 @@ register_error: udc->gadget.dev.driver = NULL; return retval; } -EXPORT_SYMBOL(usb_gadget_probe_driver); -/* - * usb_gadget_unregister_driver - */ -int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) +static int s3c2410_udc_stop(struct usb_gadget_driver *driver) { struct s3c2410_udc *udc = the_controller; @@ -1955,6 +1954,10 @@ static int s3c2410_udc_probe(struct platform_device *pdev) goto err_vbus_irq; } + retval = usb_add_gadget_udc(&pdev->dev, &udc->gadget); + if (retval) + goto err_add_udc; + if (s3c2410_udc_debugfs_root) { udc->regs_info = debugfs_create_file("registers", S_IRUGO, s3c2410_udc_debugfs_root, @@ -1967,6 +1970,10 @@ static int s3c2410_udc_probe(struct platform_device *pdev) return 0; +err_add_udc: + if (udc_info && !udc_info->udc_command && + gpio_is_valid(udc_info->pullup_pin)) + gpio_free(udc_info->pullup_pin); err_vbus_irq: if (udc_info && udc_info->vbus_pin > 0) free_irq(gpio_to_irq(udc_info->vbus_pin), udc); @@ -1992,6 +1999,8 @@ static int s3c2410_udc_remove(struct platform_device *pdev) unsigned int irq; dev_dbg(&pdev->dev, "%s()\n", __func__); + + usb_del_gadget_udc(&udc->gadget); if (udc->driver) return -EBUSY; @@ -2105,8 +2114,6 @@ static void __exit udc_exit(void) debugfs_remove(s3c2410_udc_debugfs_root); } -EXPORT_SYMBOL(usb_gadget_unregister_driver); - module_init(udc_init); module_exit(udc_exit); diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c index 0a50a35e185..728572cf709 100644 --- a/drivers/usb/musb/musb_gadget.c +++ b/drivers/usb/musb/musb_gadget.c @@ -1704,6 +1704,10 @@ static int musb_gadget_pullup(struct usb_gadget *gadget, int is_on) return 0; } +static int musb_gadget_start(struct usb_gadget_driver *driver, + int (*bind)(struct usb_gadget *)); +static int musb_gadget_stop(struct usb_gadget_driver *driver); + static const struct usb_gadget_ops musb_gadget_operations = { .get_frame = musb_gadget_get_frame, .wakeup = musb_gadget_wakeup, @@ -1711,6 +1715,8 @@ static const struct usb_gadget_ops musb_gadget_operations = { /* .vbus_session = musb_gadget_vbus_session, */ .vbus_draw = musb_gadget_vbus_draw, .pullup = musb_gadget_pullup, + .start = musb_gadget_start, + .stop = musb_gadget_stop, }; /* ----------------------------------------------------------------------- */ @@ -1835,7 +1841,16 @@ int __init musb_gadget_setup(struct musb *musb) if (status != 0) { put_device(&musb->g.dev); the_gadget = NULL; + return status; } + status = usb_add_gadget_udc(musb->controller, &musb->g); + if (status) + goto err; + + return 0; +err: + device_unregister(&musb->g.dev); + the_gadget = NULL; return status; } @@ -1844,6 +1859,7 @@ void musb_gadget_cleanup(struct musb *musb) if (musb != the_gadget) return; + usb_del_gadget_udc(&musb->g); device_unregister(&musb->g.dev); the_gadget = NULL; } @@ -1860,7 +1876,7 @@ void musb_gadget_cleanup(struct musb *musb) * @param bind the driver's bind function * @return <0 if error, 0 if everything is fine */ -int usb_gadget_probe_driver(struct usb_gadget_driver *driver, +static int musb_gadget_start(struct usb_gadget_driver *driver, int (*bind)(struct usb_gadget *)) { struct musb *musb = the_gadget; @@ -1962,7 +1978,6 @@ err1: err0: return retval; } -EXPORT_SYMBOL(usb_gadget_probe_driver); static void stop_activity(struct musb *musb, struct usb_gadget_driver *driver) { @@ -2012,7 +2027,7 @@ static void stop_activity(struct musb *musb, struct usb_gadget_driver *driver) * * @param driver the gadget driver to unregister */ -int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) +static int musb_gadget_stop(struct usb_gadget_driver *driver) { struct musb *musb = the_gadget; unsigned long flags; @@ -2071,8 +2086,6 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) return 0; } -EXPORT_SYMBOL(usb_gadget_unregister_driver); - /* ----------------------------------------------------------------------- */ diff --git a/drivers/usb/renesas_usbhs/mod_gadget.c b/drivers/usb/renesas_usbhs/mod_gadget.c index aa591b66383..c9c56e7a1b1 100644 --- a/drivers/usb/renesas_usbhs/mod_gadget.c +++ b/drivers/usb/renesas_usbhs/mod_gadget.c @@ -725,7 +725,7 @@ static int usbhsg_try_stop(struct usbhs_priv *priv, u32 status) * */ struct usbhsg_gpriv *the_controller; -int usb_gadget_probe_driver(struct usb_gadget_driver *driver, +static int usbhsg_gadget_start(struct usb_gadget_driver *driver, int (*bind)(struct usb_gadget *)) { struct usbhsg_gpriv *gpriv = the_controller; @@ -775,9 +775,8 @@ add_fail: return ret; } -EXPORT_SYMBOL(usb_gadget_probe_driver); -int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) +static int usbhsg_gadget_stop(struct usb_gadget_driver *driver) { struct usbhsg_gpriv *gpriv = the_controller; struct usbhs_priv *priv; @@ -806,7 +805,6 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) return 0; } -EXPORT_SYMBOL(usb_gadget_unregister_driver); /* * usb gadget ops @@ -821,6 +819,8 @@ static int usbhsg_get_frame(struct usb_gadget *gadget) static struct usb_gadget_ops usbhsg_gadget_ops = { .get_frame = usbhsg_get_frame, + .start = usbhsg_gadget_start, + .stop = usbhsg_gadget_stop, }; static int usbhsg_start(struct usbhs_priv *priv) @@ -840,6 +840,7 @@ int __devinit usbhs_mod_gadget_probe(struct usbhs_priv *priv) struct device *dev = usbhs_priv_to_dev(priv); int pipe_size = usbhs_get_dparam(priv, pipe_size); int i; + int ret; gpriv = kzalloc(sizeof(struct usbhsg_gpriv), GFP_KERNEL); if (!gpriv) { @@ -850,6 +851,7 @@ int __devinit usbhs_mod_gadget_probe(struct usbhs_priv *priv) uep = kzalloc(sizeof(struct usbhsg_uep) * pipe_size, GFP_KERNEL); if (!uep) { dev_err(dev, "Could not allocate ep\n"); + ret = -ENOMEM; goto usbhs_mod_gadget_probe_err_gpriv; } @@ -911,20 +913,28 @@ int __devinit usbhs_mod_gadget_probe(struct usbhs_priv *priv) the_controller = gpriv; + ret = usb_add_gadget_udc(dev, &gpriv->gadget); + if (ret) + goto err_add_udc; + + dev_info(dev, "gadget probed\n"); return 0; +err_add_udc: + kfree(gpriv->uep); usbhs_mod_gadget_probe_err_gpriv: kfree(gpriv); - return -ENOMEM; + return ret; } void __devexit usbhs_mod_gadget_remove(struct usbhs_priv *priv) { struct usbhsg_gpriv *gpriv = usbhsg_priv_to_gpriv(priv); + usb_del_gadget_udc(&gpriv->gadget); kfree(gpriv->uep); kfree(gpriv); } -- cgit v1.2.3-70-g09d2 From 72c973dd2b01b212a159faa330a2bc641a3ed809 Mon Sep 17 00:00:00 2001 From: Tatyana Brokhman Date: Tue, 28 Jun 2011 16:33:48 +0300 Subject: usb: gadget: add usb_endpoint_descriptor to struct usb_ep Change usb_ep_enable() prototype to use endpoint descriptor from usb_ep. This optimization spares the FDs from saving the endpoint chosen descriptor. This optimization is not full though. To fully exploit this change, one needs to update all the UDCs as well since in the current implementation each of them saves the endpoint descriptor in it's internal (and extended) endpoint structure. Signed-off-by: Tatyana Brokhman Signed-off-by: Felipe Balbi Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/dbgp.c | 8 +++++--- drivers/usb/gadget/f_acm.c | 9 ++++----- drivers/usb/gadget/f_audio.c | 5 ++--- drivers/usb/gadget/f_ecm.c | 17 ++++++++--------- drivers/usb/gadget/f_eem.c | 10 +++++----- drivers/usb/gadget/f_fs.c | 3 ++- drivers/usb/gadget/f_hid.c | 5 ++--- drivers/usb/gadget/f_loopback.c | 14 ++++++-------- drivers/usb/gadget/f_mass_storage.c | 3 ++- drivers/usb/gadget/f_ncm.c | 17 ++++++++--------- drivers/usb/gadget/f_obex.c | 6 +++--- drivers/usb/gadget/f_phonet.c | 9 ++++----- drivers/usb/gadget/f_rndis.c | 15 +++++++-------- drivers/usb/gadget/f_serial.c | 4 ++-- drivers/usb/gadget/f_sourcesink.c | 10 ++++------ drivers/usb/gadget/f_subset.c | 8 ++++---- drivers/usb/gadget/f_uvc.c | 6 ++++-- drivers/usb/gadget/file_storage.c | 3 ++- drivers/usb/gadget/gmidi.c | 6 ++++-- drivers/usb/gadget/inode.c | 6 ++++-- drivers/usb/gadget/printer.c | 26 ++++++++++++++------------ drivers/usb/gadget/u_ether.c | 12 ++++++------ drivers/usb/gadget/u_ether.h | 4 ---- drivers/usb/gadget/u_serial.c | 4 ++-- drivers/usb/gadget/u_serial.h | 2 -- include/linux/usb/gadget.h | 16 +++++++--------- 26 files changed, 111 insertions(+), 117 deletions(-) (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/dbgp.c b/drivers/usb/gadget/dbgp.c index dbe92ee8847..052209e8927 100644 --- a/drivers/usb/gadget/dbgp.c +++ b/drivers/usb/gadget/dbgp.c @@ -173,7 +173,9 @@ fail_1: static int __enable_ep(struct usb_ep *ep, struct usb_endpoint_descriptor *desc) { - int err = usb_ep_enable(ep, desc); + int err; + ep->desc = desc; + err = usb_ep_enable(ep); ep->driver_data = dbgp.gadget; return err; } @@ -268,8 +270,8 @@ static int __init dbgp_configure_endpoints(struct usb_gadget *gadget) dbgp.serial->in = dbgp.i_ep; dbgp.serial->out = dbgp.o_ep; - dbgp.serial->in_desc = &i_desc; - dbgp.serial->out_desc = &o_desc; + dbgp.serial->in->desc = &i_desc; + dbgp.serial->out->desc = &o_desc; if (gserial_setup(gadget, 1) < 0) { stp = 3; diff --git a/drivers/usb/gadget/f_acm.c b/drivers/usb/gadget/f_acm.c index bd6226cbae8..d04b4a68220 100644 --- a/drivers/usb/gadget/f_acm.c +++ b/drivers/usb/gadget/f_acm.c @@ -62,7 +62,6 @@ struct f_acm { struct acm_ep_descs hs; struct usb_ep *notify; - struct usb_endpoint_descriptor *notify_desc; struct usb_request *notify_req; struct usb_cdc_line_coding port_line_coding; /* 8-N-1 etc */ @@ -405,11 +404,11 @@ static int acm_set_alt(struct usb_function *f, unsigned intf, unsigned alt) usb_ep_disable(acm->notify); } else { VDBG(cdev, "init acm ctrl interface %d\n", intf); - acm->notify_desc = ep_choose(cdev->gadget, + acm->notify->desc = ep_choose(cdev->gadget, acm->hs.notify, acm->fs.notify); } - usb_ep_enable(acm->notify, acm->notify_desc); + usb_ep_enable(acm->notify); acm->notify->driver_data = acm; } else if (intf == acm->data_id) { @@ -418,9 +417,9 @@ static int acm_set_alt(struct usb_function *f, unsigned intf, unsigned alt) gserial_disconnect(&acm->port); } else { DBG(cdev, "activate acm ttyGS%d\n", acm->port_num); - acm->port.in_desc = ep_choose(cdev->gadget, + acm->port.in->desc = ep_choose(cdev->gadget, acm->hs.in, acm->fs.in); - acm->port.out_desc = ep_choose(cdev->gadget, + acm->port.out->desc = ep_choose(cdev->gadget, acm->hs.out, acm->fs.out); } gserial_connect(&acm->port, acm->port_num); diff --git a/drivers/usb/gadget/f_audio.c b/drivers/usb/gadget/f_audio.c index 8ee330a2ab5..02a02700b51 100644 --- a/drivers/usb/gadget/f_audio.c +++ b/drivers/usb/gadget/f_audio.c @@ -279,7 +279,6 @@ struct f_audio { /* endpoints handle full and/or high speeds */ struct usb_ep *out_ep; - struct usb_endpoint_descriptor *out_desc; spinlock_t lock; struct f_audio_buf *copy_buf; @@ -575,7 +574,7 @@ static int f_audio_set_alt(struct usb_function *f, unsigned intf, unsigned alt) if (intf == 1) { if (alt == 1) { - usb_ep_enable(out_ep, audio->out_desc); + usb_ep_enable(out_ep); out_ep->driver_data = audio; audio->copy_buf = f_audio_buffer_alloc(audio_buf_size); if (IS_ERR(audio->copy_buf)) @@ -677,6 +676,7 @@ f_audio_bind(struct usb_configuration *c, struct usb_function *f) if (!ep) goto fail; audio->out_ep = ep; + audio->out_ep->desc = &as_out_ep_desc; ep->driver_data = cdev; /* claim */ status = -ENOMEM; @@ -776,7 +776,6 @@ int __init audio_bind_config(struct usb_configuration *c) audio->card.func.set_alt = f_audio_set_alt; audio->card.func.setup = f_audio_setup; audio->card.func.disable = f_audio_disable; - audio->out_desc = &as_out_ep_desc; control_selector_init(audio); diff --git a/drivers/usb/gadget/f_ecm.c b/drivers/usb/gadget/f_ecm.c index 544257a89ed..7c996f271cc 100644 --- a/drivers/usb/gadget/f_ecm.c +++ b/drivers/usb/gadget/f_ecm.c @@ -68,7 +68,6 @@ struct f_ecm { struct ecm_ep_descs hs; struct usb_ep *notify; - struct usb_endpoint_descriptor *notify_desc; struct usb_request *notify_req; u8 notify_state; bool is_open; @@ -466,11 +465,11 @@ static int ecm_set_alt(struct usb_function *f, unsigned intf, unsigned alt) usb_ep_disable(ecm->notify); } else { VDBG(cdev, "init ecm ctrl %d\n", intf); - ecm->notify_desc = ep_choose(cdev->gadget, + ecm->notify->desc = ep_choose(cdev->gadget, ecm->hs.notify, ecm->fs.notify); } - usb_ep_enable(ecm->notify, ecm->notify_desc); + usb_ep_enable(ecm->notify); ecm->notify->driver_data = ecm; /* Data interface has two altsettings, 0 and 1 */ @@ -483,11 +482,11 @@ static int ecm_set_alt(struct usb_function *f, unsigned intf, unsigned alt) gether_disconnect(&ecm->port); } - if (!ecm->port.in) { + if (!ecm->port.in_ep->desc) { DBG(cdev, "init ecm\n"); - ecm->port.in = ep_choose(cdev->gadget, + ecm->port.in_ep->desc = ep_choose(cdev->gadget, ecm->hs.in, ecm->fs.in); - ecm->port.out = ep_choose(cdev->gadget, + ecm->port.out_ep->desc = ep_choose(cdev->gadget, ecm->hs.out, ecm->fs.out); } @@ -549,7 +548,7 @@ static void ecm_disable(struct usb_function *f) if (ecm->notify->driver_data) { usb_ep_disable(ecm->notify); ecm->notify->driver_data = NULL; - ecm->notify_desc = NULL; + ecm->notify->desc = NULL; } } @@ -723,9 +722,9 @@ fail: /* we might as well release our claims on endpoints */ if (ecm->notify) ecm->notify->driver_data = NULL; - if (ecm->port.out) + if (ecm->port.out_ep->desc) ecm->port.out_ep->driver_data = NULL; - if (ecm->port.in) + if (ecm->port.in_ep->desc) ecm->port.in_ep->driver_data = NULL; ERROR(cdev, "%s: can't bind, err %d\n", f->name, status); diff --git a/drivers/usb/gadget/f_eem.c b/drivers/usb/gadget/f_eem.c index b3c30429015..fea8e3b08b5 100644 --- a/drivers/usb/gadget/f_eem.c +++ b/drivers/usb/gadget/f_eem.c @@ -176,11 +176,11 @@ static int eem_set_alt(struct usb_function *f, unsigned intf, unsigned alt) gether_disconnect(&eem->port); } - if (!eem->port.in) { + if (!eem->port.in_ep->desc) { DBG(cdev, "init eem\n"); - eem->port.in = ep_choose(cdev->gadget, + eem->port.in_ep->desc = ep_choose(cdev->gadget, eem->hs.in, eem->fs.in); - eem->port.out = ep_choose(cdev->gadget, + eem->port.out_ep->desc = ep_choose(cdev->gadget, eem->hs.out, eem->fs.out); } @@ -289,9 +289,9 @@ fail: usb_free_descriptors(f->descriptors); /* we might as well release our claims on endpoints */ - if (eem->port.out) + if (eem->port.out_ep->desc) eem->port.out_ep->driver_data = NULL; - if (eem->port.in) + if (eem->port.in_ep->desc) eem->port.in_ep->driver_data = NULL; ERROR(cdev, "%s: can't bind, err %d\n", f->name, status); diff --git a/drivers/usb/gadget/f_fs.c b/drivers/usb/gadget/f_fs.c index 19fffccc370..c161a9aaeb7 100644 --- a/drivers/usb/gadget/f_fs.c +++ b/drivers/usb/gadget/f_fs.c @@ -1544,7 +1544,8 @@ static int ffs_func_eps_enable(struct ffs_function *func) ds = ep->descs[ep->descs[1] ? 1 : 0]; ep->ep->driver_data = ep; - ret = usb_ep_enable(ep->ep, ds); + ep->ep->desc = ds; + ret = usb_ep_enable(ep->ep); if (likely(!ret)) { epfile->ep = ep; epfile->in = usb_endpoint_dir_in(ds); diff --git a/drivers/usb/gadget/f_hid.c b/drivers/usb/gadget/f_hid.c index 598e7e2ab80..12879b6f787 100644 --- a/drivers/usb/gadget/f_hid.c +++ b/drivers/usb/gadget/f_hid.c @@ -416,7 +416,6 @@ static int hidg_set_alt(struct usb_function *f, unsigned intf, unsigned alt) { struct usb_composite_dev *cdev = f->config->cdev; struct f_hidg *hidg = func_to_hidg(f); - const struct usb_endpoint_descriptor *ep_desc; int status = 0; VDBG(cdev, "hidg_set_alt intf:%d alt:%d\n", intf, alt); @@ -426,9 +425,9 @@ static int hidg_set_alt(struct usb_function *f, unsigned intf, unsigned alt) if (hidg->in_ep->driver_data != NULL) usb_ep_disable(hidg->in_ep); - ep_desc = ep_choose(f->config->cdev->gadget, + hidg->in_ep->desc = ep_choose(f->config->cdev->gadget, hidg->hs_in_ep_desc, hidg->fs_in_ep_desc); - status = usb_ep_enable(hidg->in_ep, ep_desc); + status = usb_ep_enable(hidg->in_ep); if (status < 0) { ERROR(cdev, "Enable endpoint FAILED!\n"); goto fail; diff --git a/drivers/usb/gadget/f_loopback.c b/drivers/usb/gadget/f_loopback.c index b37960f9e75..34e3ccaf088 100644 --- a/drivers/usb/gadget/f_loopback.c +++ b/drivers/usb/gadget/f_loopback.c @@ -250,26 +250,24 @@ static int enable_loopback(struct usb_composite_dev *cdev, struct f_loopback *loop) { int result = 0; - const struct usb_endpoint_descriptor *src, *sink; struct usb_ep *ep; struct usb_request *req; unsigned i; - src = ep_choose(cdev->gadget, - &hs_loop_source_desc, &fs_loop_source_desc); - sink = ep_choose(cdev->gadget, - &hs_loop_sink_desc, &fs_loop_sink_desc); - /* one endpoint writes data back IN to the host */ ep = loop->in_ep; - result = usb_ep_enable(ep, src); + ep->desc = ep_choose(cdev->gadget, + &hs_loop_source_desc, &fs_loop_source_desc); + result = usb_ep_enable(ep); if (result < 0) return result; ep->driver_data = loop; /* one endpoint just reads OUT packets */ ep = loop->out_ep; - result = usb_ep_enable(ep, sink); + ep->desc = ep_choose(cdev->gadget, + &hs_loop_sink_desc, &fs_loop_sink_desc); + result = usb_ep_enable(ep); if (result < 0) { fail0: ep = loop->in_ep; diff --git a/drivers/usb/gadget/f_mass_storage.c b/drivers/usb/gadget/f_mass_storage.c index efb58f9f5aa..4eee4341212 100644 --- a/drivers/usb/gadget/f_mass_storage.c +++ b/drivers/usb/gadget/f_mass_storage.c @@ -2330,7 +2330,8 @@ static int enable_endpoint(struct fsg_common *common, struct usb_ep *ep, int rc; ep->driver_data = common; - rc = usb_ep_enable(ep, d); + ep->desc = (struct usb_endpoint_descriptor *)d; + rc = usb_ep_enable(ep); if (rc) ERROR(common, "can't enable %s, result %d\n", ep->name, rc); return rc; diff --git a/drivers/usb/gadget/f_ncm.c b/drivers/usb/gadget/f_ncm.c index 86902a60bcd..06daa1bc9ff 100644 --- a/drivers/usb/gadget/f_ncm.c +++ b/drivers/usb/gadget/f_ncm.c @@ -70,7 +70,6 @@ struct f_ncm { struct ncm_ep_descs hs; struct usb_ep *notify; - struct usb_endpoint_descriptor *notify_desc; struct usb_request *notify_req; u8 notify_state; bool is_open; @@ -804,11 +803,11 @@ static int ncm_set_alt(struct usb_function *f, unsigned intf, unsigned alt) usb_ep_disable(ncm->notify); } else { DBG(cdev, "init ncm ctrl %d\n", intf); - ncm->notify_desc = ep_choose(cdev->gadget, + ncm->notify->desc = ep_choose(cdev->gadget, ncm->hs.notify, ncm->fs.notify); } - usb_ep_enable(ncm->notify, ncm->notify_desc); + usb_ep_enable(ncm->notify); ncm->notify->driver_data = ncm; /* Data interface has two altsettings, 0 and 1 */ @@ -829,12 +828,12 @@ static int ncm_set_alt(struct usb_function *f, unsigned intf, unsigned alt) if (alt == 1) { struct net_device *net; - if (!ncm->port.in) { + if (!ncm->port.in_ep->desc) { DBG(cdev, "init ncm\n"); - ncm->port.in = ep_choose(cdev->gadget, + ncm->port.in_ep->desc = ep_choose(cdev->gadget, ncm->hs.in, ncm->fs.in); - ncm->port.out = ep_choose(cdev->gadget, + ncm->port.out_ep->desc = ep_choose(cdev->gadget, ncm->hs.out, ncm->fs.out); } @@ -1111,7 +1110,7 @@ static void ncm_disable(struct usb_function *f) if (ncm->notify->driver_data) { usb_ep_disable(ncm->notify); ncm->notify->driver_data = NULL; - ncm->notify_desc = NULL; + ncm->notify->desc = NULL; } } @@ -1288,9 +1287,9 @@ fail: /* we might as well release our claims on endpoints */ if (ncm->notify) ncm->notify->driver_data = NULL; - if (ncm->port.out) + if (ncm->port.out_ep->desc) ncm->port.out_ep->driver_data = NULL; - if (ncm->port.in) + if (ncm->port.in_ep->desc) ncm->port.in_ep->driver_data = NULL; ERROR(cdev, "%s: can't bind, err %d\n", f->name, status); diff --git a/drivers/usb/gadget/f_obex.c b/drivers/usb/gadget/f_obex.c index 8f8c6437147..a6dbda090ca 100644 --- a/drivers/usb/gadget/f_obex.c +++ b/drivers/usb/gadget/f_obex.c @@ -227,11 +227,11 @@ static int obex_set_alt(struct usb_function *f, unsigned intf, unsigned alt) gserial_disconnect(&obex->port); } - if (!obex->port.in_desc) { + if (!obex->port.in->desc) { DBG(cdev, "init obex ttyGS%d\n", obex->port_num); - obex->port.in_desc = ep_choose(cdev->gadget, + obex->port.in->desc = ep_choose(cdev->gadget, obex->hs.obex_in, obex->fs.obex_in); - obex->port.out_desc = ep_choose(cdev->gadget, + obex->port.out->desc = ep_choose(cdev->gadget, obex->hs.obex_out, obex->fs.obex_out); } diff --git a/drivers/usb/gadget/f_phonet.c b/drivers/usb/gadget/f_phonet.c index 5e1495097ec..dc63f161a10 100644 --- a/drivers/usb/gadget/f_phonet.c +++ b/drivers/usb/gadget/f_phonet.c @@ -427,17 +427,16 @@ static int pn_set_alt(struct usb_function *f, unsigned intf, unsigned alt) spin_lock(&port->lock); __pn_reset(f); if (alt == 1) { - struct usb_endpoint_descriptor *out, *in; int i; - out = ep_choose(gadget, + fp->out_ep->desc = ep_choose(gadget, &pn_hs_sink_desc, &pn_fs_sink_desc); - in = ep_choose(gadget, + fp->in_ep->desc = ep_choose(gadget, &pn_hs_source_desc, &pn_fs_source_desc); - usb_ep_enable(fp->out_ep, out); - usb_ep_enable(fp->in_ep, in); + usb_ep_enable(fp->out_ep); + usb_ep_enable(fp->in_ep); port->usb = fp; fp->out_ep->driver_data = fp; diff --git a/drivers/usb/gadget/f_rndis.c b/drivers/usb/gadget/f_rndis.c index fa12ec8364e..4646254a892 100644 --- a/drivers/usb/gadget/f_rndis.c +++ b/drivers/usb/gadget/f_rndis.c @@ -92,7 +92,6 @@ struct f_rndis { struct rndis_ep_descs hs; struct usb_ep *notify; - struct usb_endpoint_descriptor *notify_desc; struct usb_request *notify_req; atomic_t notify_count; }; @@ -486,11 +485,11 @@ static int rndis_set_alt(struct usb_function *f, unsigned intf, unsigned alt) usb_ep_disable(rndis->notify); } else { VDBG(cdev, "init rndis ctrl %d\n", intf); - rndis->notify_desc = ep_choose(cdev->gadget, + rndis->notify->desc = ep_choose(cdev->gadget, rndis->hs.notify, rndis->fs.notify); } - usb_ep_enable(rndis->notify, rndis->notify_desc); + usb_ep_enable(rndis->notify); rndis->notify->driver_data = rndis; } else if (intf == rndis->data_id) { @@ -501,11 +500,11 @@ static int rndis_set_alt(struct usb_function *f, unsigned intf, unsigned alt) gether_disconnect(&rndis->port); } - if (!rndis->port.in) { + if (!rndis->port.in_ep->desc) { DBG(cdev, "init rndis\n"); - rndis->port.in = ep_choose(cdev->gadget, + rndis->port.in_ep->desc = ep_choose(cdev->gadget, rndis->hs.in, rndis->fs.in); - rndis->port.out = ep_choose(cdev->gadget, + rndis->port.out_ep->desc = ep_choose(cdev->gadget, rndis->hs.out, rndis->fs.out); } @@ -738,9 +737,9 @@ fail: /* we might as well release our claims on endpoints */ if (rndis->notify) rndis->notify->driver_data = NULL; - if (rndis->port.out) + if (rndis->port.out_ep->desc) rndis->port.out_ep->driver_data = NULL; - if (rndis->port.in) + if (rndis->port.in_ep->desc) rndis->port.in_ep->driver_data = NULL; ERROR(cdev, "%s: can't bind, err %d\n", f->name, status); diff --git a/drivers/usb/gadget/f_serial.c b/drivers/usb/gadget/f_serial.c index 490b00b01a7..a9ce6261d15 100644 --- a/drivers/usb/gadget/f_serial.c +++ b/drivers/usb/gadget/f_serial.c @@ -138,9 +138,9 @@ static int gser_set_alt(struct usb_function *f, unsigned intf, unsigned alt) gserial_disconnect(&gser->port); } else { DBG(cdev, "activate generic ttyGS%d\n", gser->port_num); - gser->port.in_desc = ep_choose(cdev->gadget, + gser->port.in->desc = ep_choose(cdev->gadget, gser->hs.in, gser->fs.in); - gser->port.out_desc = ep_choose(cdev->gadget, + gser->port.out->desc = ep_choose(cdev->gadget, gser->hs.out, gser->fs.out); } gserial_connect(&gser->port, gser->port_num); diff --git a/drivers/usb/gadget/f_sourcesink.c b/drivers/usb/gadget/f_sourcesink.c index e403a534dd5..0ffddd33a55 100644 --- a/drivers/usb/gadget/f_sourcesink.c +++ b/drivers/usb/gadget/f_sourcesink.c @@ -343,15 +343,12 @@ static int enable_source_sink(struct usb_composite_dev *cdev, struct f_sourcesink *ss) { int result = 0; - const struct usb_endpoint_descriptor *src, *sink; struct usb_ep *ep; - src = ep_choose(cdev->gadget, &hs_source_desc, &fs_source_desc); - sink = ep_choose(cdev->gadget, &hs_sink_desc, &fs_sink_desc); - /* one endpoint writes (sources) zeroes IN (to the host) */ ep = ss->in_ep; - result = usb_ep_enable(ep, src); + ep->desc = ep_choose(cdev->gadget, &hs_source_desc, &fs_source_desc); + result = usb_ep_enable(ep); if (result < 0) return result; ep->driver_data = ss; @@ -367,7 +364,8 @@ fail: /* one endpoint reads (sinks) anything OUT (from the host) */ ep = ss->out_ep; - result = usb_ep_enable(ep, sink); + ep->desc = ep_choose(cdev->gadget, &hs_sink_desc, &fs_sink_desc); + result = usb_ep_enable(ep); if (result < 0) goto fail; ep->driver_data = ss; diff --git a/drivers/usb/gadget/f_subset.c b/drivers/usb/gadget/f_subset.c index 8675ca41532..aecaed1724a 100644 --- a/drivers/usb/gadget/f_subset.c +++ b/drivers/usb/gadget/f_subset.c @@ -243,9 +243,9 @@ static int geth_set_alt(struct usb_function *f, unsigned intf, unsigned alt) } DBG(cdev, "init + activate cdc subset\n"); - geth->port.in = ep_choose(cdev->gadget, + geth->port.in_ep->desc = ep_choose(cdev->gadget, geth->hs.in, geth->fs.in); - geth->port.out = ep_choose(cdev->gadget, + geth->port.out_ep->desc = ep_choose(cdev->gadget, geth->hs.out, geth->fs.out); net = gether_connect(&geth->port); @@ -334,9 +334,9 @@ geth_bind(struct usb_configuration *c, struct usb_function *f) fail: /* we might as well release our claims on endpoints */ - if (geth->port.out) + if (geth->port.out_ep->desc) geth->port.out_ep->driver_data = NULL; - if (geth->port.in) + if (geth->port.in_ep->desc) geth->port.in_ep->driver_data = NULL; ERROR(cdev, "%s: can't bind, err %d\n", f->name, status); diff --git a/drivers/usb/gadget/f_uvc.c b/drivers/usb/gadget/f_uvc.c index be446b7e7ea..df74d031191 100644 --- a/drivers/usb/gadget/f_uvc.c +++ b/drivers/usb/gadget/f_uvc.c @@ -262,8 +262,10 @@ uvc_function_set_alt(struct usb_function *f, unsigned interface, unsigned alt) if (uvc->state != UVC_STATE_CONNECTED) return 0; - if (uvc->video.ep) - usb_ep_enable(uvc->video.ep, &uvc_streaming_ep); + if (uvc->video.ep) { + uvc->video.ep->desc = &uvc_streaming_ep; + usb_ep_enable(uvc->video.ep); + } memset(&v4l2_event, 0, sizeof(v4l2_event)); v4l2_event.type = UVC_EVENT_STREAMON; diff --git a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c index 83bee30cdb9..738591a64bb 100644 --- a/drivers/usb/gadget/file_storage.c +++ b/drivers/usb/gadget/file_storage.c @@ -2713,7 +2713,8 @@ static int enable_endpoint(struct fsg_dev *fsg, struct usb_ep *ep, int rc; ep->driver_data = fsg; - rc = usb_ep_enable(ep, d); + ep->desc = d; + rc = usb_ep_enable(ep); if (rc) ERROR(fsg, "can't enable %s, result %d\n", ep->name, rc); return rc; diff --git a/drivers/usb/gadget/gmidi.c b/drivers/usb/gadget/gmidi.c index 47b86b99d44..4f40f146743 100644 --- a/drivers/usb/gadget/gmidi.c +++ b/drivers/usb/gadget/gmidi.c @@ -537,14 +537,16 @@ static int set_gmidi_config(struct gmidi_device *dev, gfp_t gfp_flags) struct usb_ep *ep; unsigned i; - err = usb_ep_enable(dev->in_ep, &bulk_in_desc); + dev->in_ep->desc = &bulk_in_desc; + err = usb_ep_enable(dev->in_ep); if (err) { ERROR(dev, "can't start %s: %d\n", dev->in_ep->name, err); goto fail; } dev->in_ep->driver_data = dev; - err = usb_ep_enable(dev->out_ep, &bulk_out_desc); + dev->out_ep->desc = &bulk_out_desc; + err = usb_ep_enable(dev->out_ep); if (err) { ERROR(dev, "can't start %s: %d\n", dev->out_ep->name, err); goto fail; diff --git a/drivers/usb/gadget/inode.c b/drivers/usb/gadget/inode.c index a56876aaf76..a9a45569239 100644 --- a/drivers/usb/gadget/inode.c +++ b/drivers/usb/gadget/inode.c @@ -832,14 +832,16 @@ ep_config (struct file *fd, const char __user *buf, size_t len, loff_t *ptr) switch (data->dev->gadget->speed) { case USB_SPEED_LOW: case USB_SPEED_FULL: - value = usb_ep_enable (ep, &data->desc); + ep->desc = &data->desc; + value = usb_ep_enable(ep); if (value == 0) data->state = STATE_EP_ENABLED; break; #ifdef CONFIG_USB_GADGET_DUALSPEED case USB_SPEED_HIGH: /* fails if caller didn't provide that descriptor... */ - value = usb_ep_enable (ep, &data->hs_desc); + ep->desc = &data->hs_desc; + value = usb_ep_enable(ep); if (value == 0) data->state = STATE_EP_ENABLED; break; diff --git a/drivers/usb/gadget/printer.c b/drivers/usb/gadget/printer.c index 271ef94668e..00e5f19c75b 100644 --- a/drivers/usb/gadget/printer.c +++ b/drivers/usb/gadget/printer.c @@ -89,8 +89,7 @@ struct printer_dev { u8 config; s8 interface; struct usb_ep *in_ep, *out_ep; - const struct usb_endpoint_descriptor - *in, *out; + struct list_head rx_reqs; /* List of free RX structs */ struct list_head rx_reqs_active; /* List of Active RX xfers */ struct list_head rx_buffers; /* List of completed xfers */ @@ -895,19 +894,20 @@ set_printer_interface(struct printer_dev *dev) { int result = 0; - dev->in = ep_desc(dev->gadget, &hs_ep_in_desc, &fs_ep_in_desc); + dev->in_ep->desc = ep_desc(dev->gadget, &hs_ep_in_desc, &fs_ep_in_desc); dev->in_ep->driver_data = dev; - dev->out = ep_desc(dev->gadget, &hs_ep_out_desc, &fs_ep_out_desc); + dev->out_ep->desc = ep_desc(dev->gadget, &hs_ep_out_desc, + &fs_ep_out_desc); dev->out_ep->driver_data = dev; - result = usb_ep_enable(dev->in_ep, dev->in); + result = usb_ep_enable(dev->in_ep); if (result != 0) { DBG(dev, "enable %s --> %d\n", dev->in_ep->name, result); goto done; } - result = usb_ep_enable(dev->out_ep, dev->out); + result = usb_ep_enable(dev->out_ep); if (result != 0) { DBG(dev, "enable %s --> %d\n", dev->in_ep->name, result); goto done; @@ -918,8 +918,8 @@ done: if (result != 0) { (void) usb_ep_disable(dev->in_ep); (void) usb_ep_disable(dev->out_ep); - dev->in = NULL; - dev->out = NULL; + dev->in_ep->desc = NULL; + dev->out_ep->desc = NULL; } /* caller is responsible for cleanup on error */ @@ -933,12 +933,14 @@ static void printer_reset_interface(struct printer_dev *dev) DBG(dev, "%s\n", __func__); - if (dev->in) + if (dev->in_ep->desc) usb_ep_disable(dev->in_ep); - if (dev->out) + if (dev->out_ep->desc) usb_ep_disable(dev->out_ep); + dev->in_ep->desc = NULL; + dev->out_ep->desc = NULL; dev->interface = -1; } @@ -1104,9 +1106,9 @@ static void printer_soft_reset(struct printer_dev *dev) list_add(&req->list, &dev->tx_reqs); } - if (usb_ep_enable(dev->in_ep, dev->in)) + if (usb_ep_enable(dev->in_ep)) DBG(dev, "Failed to enable USB in_ep\n"); - if (usb_ep_enable(dev->out_ep, dev->out)) + if (usb_ep_enable(dev->out_ep)) DBG(dev, "Failed to enable USB out_ep\n"); wake_up_interruptible(&dev->rx_wait); diff --git a/drivers/usb/gadget/u_ether.c b/drivers/usb/gadget/u_ether.c index 2ac1d214732..b91363e88db 100644 --- a/drivers/usb/gadget/u_ether.c +++ b/drivers/usb/gadget/u_ether.c @@ -693,8 +693,8 @@ static int eth_stop(struct net_device *net) usb_ep_disable(link->out_ep); if (netif_carrier_ok(net)) { DBG(dev, "host still using in/out endpoints\n"); - usb_ep_enable(link->in_ep, link->in); - usb_ep_enable(link->out_ep, link->out); + usb_ep_enable(link->in_ep); + usb_ep_enable(link->out_ep); } } spin_unlock_irqrestore(&dev->lock, flags); @@ -871,7 +871,7 @@ struct net_device *gether_connect(struct gether *link) return ERR_PTR(-EINVAL); link->in_ep->driver_data = dev; - result = usb_ep_enable(link->in_ep, link->in); + result = usb_ep_enable(link->in_ep); if (result != 0) { DBG(dev, "enable %s --> %d\n", link->in_ep->name, result); @@ -879,7 +879,7 @@ struct net_device *gether_connect(struct gether *link) } link->out_ep->driver_data = dev; - result = usb_ep_enable(link->out_ep, link->out); + result = usb_ep_enable(link->out_ep); if (result != 0) { DBG(dev, "enable %s --> %d\n", link->out_ep->name, result); @@ -969,7 +969,7 @@ void gether_disconnect(struct gether *link) } spin_unlock(&dev->req_lock); link->in_ep->driver_data = NULL; - link->in = NULL; + link->in_ep->desc = NULL; usb_ep_disable(link->out_ep); spin_lock(&dev->req_lock); @@ -984,7 +984,7 @@ void gether_disconnect(struct gether *link) } spin_unlock(&dev->req_lock); link->out_ep->driver_data = NULL; - link->out = NULL; + link->out_ep->desc = NULL; /* finish forgetting about this USB link episode */ dev->header_len = 0; diff --git a/drivers/usb/gadget/u_ether.h b/drivers/usb/gadget/u_ether.h index b56e1e7d423..c966440ddd7 100644 --- a/drivers/usb/gadget/u_ether.h +++ b/drivers/usb/gadget/u_ether.h @@ -52,10 +52,6 @@ struct gether { struct usb_ep *in_ep; struct usb_ep *out_ep; - /* descriptors match device speed at gether_connect() time */ - struct usb_endpoint_descriptor *in; - struct usb_endpoint_descriptor *out; - bool is_zlp_ok; u16 cdc_filter; diff --git a/drivers/usb/gadget/u_serial.c b/drivers/usb/gadget/u_serial.c index 40f7716b31f..a8aa46962d8 100644 --- a/drivers/usb/gadget/u_serial.c +++ b/drivers/usb/gadget/u_serial.c @@ -1247,12 +1247,12 @@ int gserial_connect(struct gserial *gser, u8 port_num) port = ports[port_num].port; /* activate the endpoints */ - status = usb_ep_enable(gser->in, gser->in_desc); + status = usb_ep_enable(gser->in); if (status < 0) return status; gser->in->driver_data = port; - status = usb_ep_enable(gser->out, gser->out_desc); + status = usb_ep_enable(gser->out); if (status < 0) goto fail_out; gser->out->driver_data = port; diff --git a/drivers/usb/gadget/u_serial.h b/drivers/usb/gadget/u_serial.h index 300f0ed9475..9b0fe6450fb 100644 --- a/drivers/usb/gadget/u_serial.h +++ b/drivers/usb/gadget/u_serial.h @@ -35,8 +35,6 @@ struct gserial { struct usb_ep *in; struct usb_ep *out; - struct usb_endpoint_descriptor *in_desc; - struct usb_endpoint_descriptor *out_desc; /* REVISIT avoid this CDC-ACM support harder ... */ struct usb_cdc_line_coding port_line_coding; /* 9600-8-N-1 etc */ diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h index 18979cfb6d6..fe50912585f 100644 --- a/include/linux/usb/gadget.h +++ b/include/linux/usb/gadget.h @@ -132,8 +132,9 @@ struct usb_ep_ops { * @maxpacket:The maximum packet size used on this endpoint. The initial * value can sometimes be reduced (hardware allowing), according to * the endpoint descriptor used to configure the endpoint. - * @driver_data:for use by the gadget driver. all other fields are - * read-only to gadget drivers. + * @driver_data:for use by the gadget driver. + * @desc: endpoint descriptor. This pointer is set before the endpoint is + * enabled and remains valid until the endpoint is disabled. * * the bus controller driver lists all the general purpose endpoints in * gadget->ep_list. the control endpoint (gadget->ep0) is not in that list, @@ -146,6 +147,7 @@ struct usb_ep { const struct usb_ep_ops *ops; struct list_head ep_list; unsigned maxpacket:16; + const struct usb_endpoint_descriptor *desc; }; /*-------------------------------------------------------------------------*/ @@ -154,11 +156,8 @@ struct usb_ep { * usb_ep_enable - configure endpoint, making it usable * @ep:the endpoint being configured. may not be the endpoint named "ep0". * drivers discover endpoints through the ep_list of a usb_gadget. - * @desc:descriptor for desired behavior. caller guarantees this pointer - * remains valid until the endpoint is disabled; the data byte order - * is little-endian (usb-standard). * - * when configurations are set, or when interface settings change, the driver + * When configurations are set, or when interface settings change, the driver * will enable or disable the relevant endpoints. while it is enabled, an * endpoint may be used for i/o until the driver receives a disconnect() from * the host or until the endpoint is disabled. @@ -173,10 +172,9 @@ struct usb_ep { * * returns zero, or a negative error code. */ -static inline int usb_ep_enable(struct usb_ep *ep, - const struct usb_endpoint_descriptor *desc) +static inline int usb_ep_enable(struct usb_ep *ep) { - return ep->ops->enable(ep, desc); + return ep->ops->enable(ep, ep->desc); } /** -- cgit v1.2.3-70-g09d2 From 48767a4e8263620c347c3fa17812c943dd0fc2fa Mon Sep 17 00:00:00 2001 From: Tatyana Brokhman Date: Tue, 28 Jun 2011 16:33:49 +0300 Subject: usb: gadget: configure endpoint according to gadget speed Add config_ep_by_speed() to configure the endpoint according to the gadget speed. Using this function will spare the FDs from handling the endpoint chosen descriptor. Signed-off-by: Tatyana Brokhman Signed-off-by: Felipe Balbi Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/composite.c | 85 +++++++++++++++++++++++++++++++++++++++++ drivers/usb/gadget/epautoconf.c | 1 + include/linux/usb/composite.h | 3 ++ include/linux/usb/gadget.h | 3 ++ 4 files changed, 92 insertions(+) (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c index 5cbb1a41c22..1c6bd666150 100644 --- a/drivers/usb/gadget/composite.c +++ b/drivers/usb/gadget/composite.c @@ -74,6 +74,91 @@ MODULE_PARM_DESC(iSerialNumber, "SerialNumber string"); static char composite_manufacturer[50]; /*-------------------------------------------------------------------------*/ +/** + * next_ep_desc() - advance to the next EP descriptor + * @t: currect pointer within descriptor array + * + * Return: next EP descriptor or NULL + * + * Iterate over @t until either EP descriptor found or + * NULL (that indicates end of list) encountered + */ +static struct usb_descriptor_header** +next_ep_desc(struct usb_descriptor_header **t) +{ + for (; *t; t++) { + if ((*t)->bDescriptorType == USB_DT_ENDPOINT) + return t; + } + return NULL; +} + +/* + * for_each_ep_desc()- iterate over endpoint descriptors in the + * descriptors list + * @start: pointer within descriptor array. + * @ep_desc: endpoint descriptor to use as the loop cursor + */ +#define for_each_ep_desc(start, ep_desc) \ + for (ep_desc = next_ep_desc(start); \ + ep_desc; ep_desc = next_ep_desc(ep_desc+1)) + +/** + * config_ep_by_speed() - configures the given endpoint + * according to gadget speed. + * @g: pointer to the gadget + * @f: usb function + * @_ep: the endpoint to configure + * + * Return: error code, 0 on success + * + * This function chooses the right descriptors for a given + * endpoint according to gadget speed and saves it in the + * endpoint desc field. If the endpoint already has a descriptor + * assigned to it - overwrites it with currently corresponding + * descriptor. The endpoint maxpacket field is updated according + * to the chosen descriptor. + * Note: the supplied function should hold all the descriptors + * for supported speeds + */ +int config_ep_by_speed(struct usb_gadget *g, + struct usb_function *f, + struct usb_ep *_ep) +{ + struct usb_endpoint_descriptor *chosen_desc = NULL; + struct usb_descriptor_header **speed_desc = NULL; + + struct usb_descriptor_header **d_spd; /* cursor for speed desc */ + + if (!g || !f || !_ep) + return -EIO; + + /* select desired speed */ + switch (g->speed) { + case USB_SPEED_HIGH: + if (gadget_is_dualspeed(g)) { + speed_desc = f->hs_descriptors; + break; + } + /* else: fall through */ + default: + speed_desc = f->descriptors; + } + /* find descriptors */ + for_each_ep_desc(speed_desc, d_spd) { + chosen_desc = (struct usb_endpoint_descriptor *)*d_spd; + if (chosen_desc->bEndpointAddress == _ep->address) + goto ep_found; + } + return -EIO; + +ep_found: + /* commit results */ + _ep->maxpacket = le16_to_cpu(chosen_desc->wMaxPacketSize); + _ep->desc = chosen_desc; + + return 0; +} /** * usb_add_function() - add a function to a configuration diff --git a/drivers/usb/gadget/epautoconf.c b/drivers/usb/gadget/epautoconf.c index 9b7360ff5aa..0022d44060a 100644 --- a/drivers/usb/gadget/epautoconf.c +++ b/drivers/usb/gadget/epautoconf.c @@ -191,6 +191,7 @@ ep_matches ( size = 64; desc->wMaxPacketSize = cpu_to_le16(size); } + ep->address = desc->bEndpointAddress; return 1; } diff --git a/include/linux/usb/composite.h b/include/linux/usb/composite.h index b78cba466d3..2014d6b1bab 100644 --- a/include/linux/usb/composite.h +++ b/include/linux/usb/composite.h @@ -145,6 +145,9 @@ int usb_function_activate(struct usb_function *); int usb_interface_id(struct usb_configuration *, struct usb_function *); +int config_ep_by_speed(struct usb_gadget *g, struct usb_function *f, + struct usb_ep *_ep); + /** * ep_choose - select descriptor endpoint at current device speed * @g: gadget, connected and running at some speed diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h index fe50912585f..0bcc2b76bcd 100644 --- a/include/linux/usb/gadget.h +++ b/include/linux/usb/gadget.h @@ -133,6 +133,8 @@ struct usb_ep_ops { * value can sometimes be reduced (hardware allowing), according to * the endpoint descriptor used to configure the endpoint. * @driver_data:for use by the gadget driver. + * @address: used to identify the endpoint when finding descriptor that + * matches connection speed * @desc: endpoint descriptor. This pointer is set before the endpoint is * enabled and remains valid until the endpoint is disabled. * @@ -147,6 +149,7 @@ struct usb_ep { const struct usb_ep_ops *ops; struct list_head ep_list; unsigned maxpacket:16; + u8 address; const struct usb_endpoint_descriptor *desc; }; -- cgit v1.2.3-70-g09d2 From ea2a1df7b2b1de839a72217d85bfb4b7b049010c Mon Sep 17 00:00:00 2001 From: Tatyana Brokhman Date: Tue, 28 Jun 2011 16:33:50 +0300 Subject: usb: gadget: use config_ep_by_speed() instead of ep_choose() Remove obsolete functions: 1. ep_choose() 2. usb_find_endpoint() Signed-off-by: Tatyana Brokhman Signed-off-by: Felipe Balbi Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/config.c | 25 ------------------- drivers/usb/gadget/f_acm.c | 47 +++++++++++------------------------ drivers/usb/gadget/f_ecm.c | 45 +++++++++++----------------------- drivers/usb/gadget/f_eem.c | 32 +++++++----------------- drivers/usb/gadget/f_hid.c | 19 +++++--------- drivers/usb/gadget/f_loopback.c | 11 ++++++--- drivers/usb/gadget/f_mass_storage.c | 34 ++++++++++--------------- drivers/usb/gadget/f_ncm.c | 49 ++++++++++++------------------------- drivers/usb/gadget/f_obex.c | 32 +++++++----------------- drivers/usb/gadget/f_phonet.c | 12 ++++----- drivers/usb/gadget/f_rndis.c | 45 ++++++++++------------------------ drivers/usb/gadget/f_serial.c | 32 ++++++------------------ drivers/usb/gadget/f_sourcesink.c | 8 ++++-- drivers/usb/gadget/f_subset.c | 29 +++++----------------- include/linux/usb/composite.h | 15 ------------ include/linux/usb/gadget.h | 6 ----- 16 files changed, 126 insertions(+), 315 deletions(-) (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/config.c b/drivers/usb/gadget/config.c index 09084fd646a..b2c00133487 100644 --- a/drivers/usb/gadget/config.c +++ b/drivers/usb/gadget/config.c @@ -165,28 +165,3 @@ usb_copy_descriptors(struct usb_descriptor_header **src) return ret; } -/** - * usb_find_endpoint - find a copy of an endpoint descriptor - * @src: original vector of descriptors - * @copy: copy of @src - * @match: endpoint descriptor found in @src - * - * This returns the copy of the @match descriptor made for @copy. Its - * intended use is to help remembering the endpoint descriptor to use - * when enabling a given endpoint. - */ -struct usb_endpoint_descriptor * -usb_find_endpoint( - struct usb_descriptor_header **src, - struct usb_descriptor_header **copy, - struct usb_endpoint_descriptor *match -) -{ - while (*src) { - if (*src == (void *) match) - return (void *)*copy; - src++; - copy++; - } - return NULL; -} diff --git a/drivers/usb/gadget/f_acm.c b/drivers/usb/gadget/f_acm.c index d04b4a68220..3f8849339ad 100644 --- a/drivers/usb/gadget/f_acm.c +++ b/drivers/usb/gadget/f_acm.c @@ -39,12 +39,6 @@ * descriptors (roughly equivalent to CDC Unions) may sometimes help. */ -struct acm_ep_descs { - struct usb_endpoint_descriptor *in; - struct usb_endpoint_descriptor *out; - struct usb_endpoint_descriptor *notify; -}; - struct f_acm { struct gserial port; u8 ctrl_id, data_id; @@ -58,9 +52,6 @@ struct f_acm { */ spinlock_t lock; - struct acm_ep_descs fs; - struct acm_ep_descs hs; - struct usb_ep *notify; struct usb_request *notify_req; @@ -404,9 +395,8 @@ static int acm_set_alt(struct usb_function *f, unsigned intf, unsigned alt) usb_ep_disable(acm->notify); } else { VDBG(cdev, "init acm ctrl interface %d\n", intf); - acm->notify->desc = ep_choose(cdev->gadget, - acm->hs.notify, - acm->fs.notify); + if (config_ep_by_speed(cdev->gadget, f, acm->notify)) + return -EINVAL; } usb_ep_enable(acm->notify); acm->notify->driver_data = acm; @@ -415,12 +405,17 @@ static int acm_set_alt(struct usb_function *f, unsigned intf, unsigned alt) if (acm->port.in->driver_data) { DBG(cdev, "reset acm ttyGS%d\n", acm->port_num); gserial_disconnect(&acm->port); - } else { + } + if (!acm->port.in->desc || !acm->port.out->desc) { DBG(cdev, "activate acm ttyGS%d\n", acm->port_num); - acm->port.in->desc = ep_choose(cdev->gadget, - acm->hs.in, acm->fs.in); - acm->port.out->desc = ep_choose(cdev->gadget, - acm->hs.out, acm->fs.out); + if (config_ep_by_speed(cdev->gadget, f, + acm->port.in) || + config_ep_by_speed(cdev->gadget, f, + acm->port.out)) { + acm->port.in->desc = NULL; + acm->port.out->desc = NULL; + return -EINVAL; + } } gserial_connect(&acm->port, acm->port_num); @@ -628,18 +623,11 @@ acm_bind(struct usb_configuration *c, struct usb_function *f) acm->notify_req->complete = acm_cdc_notify_complete; acm->notify_req->context = acm; - /* copy descriptors, and track endpoint copies */ + /* copy descriptors */ f->descriptors = usb_copy_descriptors(acm_fs_function); if (!f->descriptors) goto fail; - acm->fs.in = usb_find_endpoint(acm_fs_function, - f->descriptors, &acm_fs_in_desc); - acm->fs.out = usb_find_endpoint(acm_fs_function, - f->descriptors, &acm_fs_out_desc); - acm->fs.notify = usb_find_endpoint(acm_fs_function, - f->descriptors, &acm_fs_notify_desc); - /* support all relevant hardware speeds... we expect that when * hardware is dual speed, all bulk-capable endpoints work at * both speeds @@ -652,15 +640,8 @@ acm_bind(struct usb_configuration *c, struct usb_function *f) acm_hs_notify_desc.bEndpointAddress = acm_fs_notify_desc.bEndpointAddress; - /* copy descriptors, and track endpoint copies */ + /* copy descriptors */ f->hs_descriptors = usb_copy_descriptors(acm_hs_function); - - acm->hs.in = usb_find_endpoint(acm_hs_function, - f->hs_descriptors, &acm_hs_in_desc); - acm->hs.out = usb_find_endpoint(acm_hs_function, - f->hs_descriptors, &acm_hs_out_desc); - acm->hs.notify = usb_find_endpoint(acm_hs_function, - f->hs_descriptors, &acm_hs_notify_desc); } DBG(cdev, "acm ttyGS%d: %s speed IN/%s OUT/%s NOTIFY/%s\n", diff --git a/drivers/usb/gadget/f_ecm.c b/drivers/usb/gadget/f_ecm.c index 7c996f271cc..ddedbc83bc3 100644 --- a/drivers/usb/gadget/f_ecm.c +++ b/drivers/usb/gadget/f_ecm.c @@ -46,11 +46,6 @@ * and also means that a get_alt() method is required. */ -struct ecm_ep_descs { - struct usb_endpoint_descriptor *in; - struct usb_endpoint_descriptor *out; - struct usb_endpoint_descriptor *notify; -}; enum ecm_notify_state { ECM_NOTIFY_NONE, /* don't notify */ @@ -64,9 +59,6 @@ struct f_ecm { char ethaddr[14]; - struct ecm_ep_descs fs; - struct ecm_ep_descs hs; - struct usb_ep *notify; struct usb_request *notify_req; u8 notify_state; @@ -463,11 +455,11 @@ static int ecm_set_alt(struct usb_function *f, unsigned intf, unsigned alt) if (ecm->notify->driver_data) { VDBG(cdev, "reset ecm control %d\n", intf); usb_ep_disable(ecm->notify); - } else { + } + if (!(ecm->notify->desc)) { VDBG(cdev, "init ecm ctrl %d\n", intf); - ecm->notify->desc = ep_choose(cdev->gadget, - ecm->hs.notify, - ecm->fs.notify); + if (config_ep_by_speed(cdev->gadget, f, ecm->notify)) + goto fail; } usb_ep_enable(ecm->notify); ecm->notify->driver_data = ecm; @@ -482,12 +474,17 @@ static int ecm_set_alt(struct usb_function *f, unsigned intf, unsigned alt) gether_disconnect(&ecm->port); } - if (!ecm->port.in_ep->desc) { + if (!ecm->port.in_ep->desc || + !ecm->port.out_ep->desc) { DBG(cdev, "init ecm\n"); - ecm->port.in_ep->desc = ep_choose(cdev->gadget, - ecm->hs.in, ecm->fs.in); - ecm->port.out_ep->desc = ep_choose(cdev->gadget, - ecm->hs.out, ecm->fs.out); + if (config_ep_by_speed(cdev->gadget, f, + ecm->port.in_ep) || + config_ep_by_speed(cdev->gadget, f, + ecm->port.out_ep)) { + ecm->port.in_ep->desc = NULL; + ecm->port.out_ep->desc = NULL; + goto fail; + } } /* CDC Ethernet only sends data in non-default altsettings. @@ -664,13 +661,6 @@ ecm_bind(struct usb_configuration *c, struct usb_function *f) if (!f->descriptors) goto fail; - ecm->fs.in = usb_find_endpoint(ecm_fs_function, - f->descriptors, &fs_ecm_in_desc); - ecm->fs.out = usb_find_endpoint(ecm_fs_function, - f->descriptors, &fs_ecm_out_desc); - ecm->fs.notify = usb_find_endpoint(ecm_fs_function, - f->descriptors, &fs_ecm_notify_desc); - /* support all relevant hardware speeds... we expect that when * hardware is dual speed, all bulk-capable endpoints work at * both speeds @@ -687,13 +677,6 @@ ecm_bind(struct usb_configuration *c, struct usb_function *f) f->hs_descriptors = usb_copy_descriptors(ecm_hs_function); if (!f->hs_descriptors) goto fail; - - ecm->hs.in = usb_find_endpoint(ecm_hs_function, - f->hs_descriptors, &hs_ecm_in_desc); - ecm->hs.out = usb_find_endpoint(ecm_hs_function, - f->hs_descriptors, &hs_ecm_out_desc); - ecm->hs.notify = usb_find_endpoint(ecm_hs_function, - f->hs_descriptors, &hs_ecm_notify_desc); } /* NOTE: all that is done without knowing or caring about diff --git a/drivers/usb/gadget/f_eem.c b/drivers/usb/gadget/f_eem.c index fea8e3b08b5..3e412740e2e 100644 --- a/drivers/usb/gadget/f_eem.c +++ b/drivers/usb/gadget/f_eem.c @@ -35,17 +35,9 @@ * Ethernet link. */ -struct eem_ep_descs { - struct usb_endpoint_descriptor *in; - struct usb_endpoint_descriptor *out; -}; - struct f_eem { struct gether port; u8 ctrl_id; - - struct eem_ep_descs fs; - struct eem_ep_descs hs; }; static inline struct f_eem *func_to_eem(struct usb_function *f) @@ -176,12 +168,16 @@ static int eem_set_alt(struct usb_function *f, unsigned intf, unsigned alt) gether_disconnect(&eem->port); } - if (!eem->port.in_ep->desc) { + if (!eem->port.in_ep->desc || !eem->port.out_ep->desc) { DBG(cdev, "init eem\n"); - eem->port.in_ep->desc = ep_choose(cdev->gadget, - eem->hs.in, eem->fs.in); - eem->port.out_ep->desc = ep_choose(cdev->gadget, - eem->hs.out, eem->fs.out); + if (config_ep_by_speed(cdev->gadget, f, + eem->port.in_ep) || + config_ep_by_speed(cdev->gadget, f, + eem->port.out_ep)) { + eem->port.in_ep->desc = NULL; + eem->port.out_ep->desc = NULL; + goto fail; + } } /* zlps should not occur because zero-length EEM packets @@ -253,11 +249,6 @@ eem_bind(struct usb_configuration *c, struct usb_function *f) if (!f->descriptors) goto fail; - eem->fs.in = usb_find_endpoint(eem_fs_function, - f->descriptors, &eem_fs_in_desc); - eem->fs.out = usb_find_endpoint(eem_fs_function, - f->descriptors, &eem_fs_out_desc); - /* support all relevant hardware speeds... we expect that when * hardware is dual speed, all bulk-capable endpoints work at * both speeds @@ -272,11 +263,6 @@ eem_bind(struct usb_configuration *c, struct usb_function *f) f->hs_descriptors = usb_copy_descriptors(eem_hs_function); if (!f->hs_descriptors) goto fail; - - eem->hs.in = usb_find_endpoint(eem_hs_function, - f->hs_descriptors, &eem_hs_in_desc); - eem->hs.out = usb_find_endpoint(eem_hs_function, - f->hs_descriptors, &eem_hs_out_desc); } DBG(cdev, "CDC Ethernet (EEM): %s speed IN/%s OUT/%s\n", diff --git a/drivers/usb/gadget/f_hid.c b/drivers/usb/gadget/f_hid.c index 12879b6f787..403a48bcf56 100644 --- a/drivers/usb/gadget/f_hid.c +++ b/drivers/usb/gadget/f_hid.c @@ -59,8 +59,6 @@ struct f_hidg { struct cdev cdev; struct usb_function func; struct usb_ep *in_ep; - struct usb_endpoint_descriptor *fs_in_ep_desc; - struct usb_endpoint_descriptor *hs_in_ep_desc; }; static inline struct f_hidg *func_to_hidg(struct usb_function *f) @@ -425,8 +423,12 @@ static int hidg_set_alt(struct usb_function *f, unsigned intf, unsigned alt) if (hidg->in_ep->driver_data != NULL) usb_ep_disable(hidg->in_ep); - hidg->in_ep->desc = ep_choose(f->config->cdev->gadget, - hidg->hs_in_ep_desc, hidg->fs_in_ep_desc); + status = config_ep_by_speed(f->config->cdev->gadget, f, + hidg->in_ep); + if (status) { + ERROR(cdev, "config_ep_by_speed FAILED!\n"); + goto fail; + } status = usb_ep_enable(hidg->in_ep); if (status < 0) { ERROR(cdev, "Enable endpoint FAILED!\n"); @@ -497,21 +499,12 @@ static int __init hidg_bind(struct usb_configuration *c, struct usb_function *f) if (!f->descriptors) goto fail; - hidg->fs_in_ep_desc = usb_find_endpoint(hidg_fs_descriptors, - f->descriptors, - &hidg_fs_in_ep_desc); - if (gadget_is_dualspeed(c->cdev->gadget)) { hidg_hs_in_ep_desc.bEndpointAddress = hidg_fs_in_ep_desc.bEndpointAddress; f->hs_descriptors = usb_copy_descriptors(hidg_hs_descriptors); if (!f->hs_descriptors) goto fail; - hidg->hs_in_ep_desc = usb_find_endpoint(hidg_hs_descriptors, - f->hs_descriptors, - &hidg_hs_in_ep_desc); - } else { - hidg->hs_in_ep_desc = NULL; } mutex_init(&hidg->lock); diff --git a/drivers/usb/gadget/f_loopback.c b/drivers/usb/gadget/f_loopback.c index 34e3ccaf088..375632659a0 100644 --- a/drivers/usb/gadget/f_loopback.c +++ b/drivers/usb/gadget/f_loopback.c @@ -256,8 +256,9 @@ enable_loopback(struct usb_composite_dev *cdev, struct f_loopback *loop) /* one endpoint writes data back IN to the host */ ep = loop->in_ep; - ep->desc = ep_choose(cdev->gadget, - &hs_loop_source_desc, &fs_loop_source_desc); + result = config_ep_by_speed(cdev->gadget, &(loop->function), ep); + if (result) + return result; result = usb_ep_enable(ep); if (result < 0) return result; @@ -265,8 +266,10 @@ enable_loopback(struct usb_composite_dev *cdev, struct f_loopback *loop) /* one endpoint just reads OUT packets */ ep = loop->out_ep; - ep->desc = ep_choose(cdev->gadget, - &hs_loop_sink_desc, &fs_loop_sink_desc); + result = config_ep_by_speed(cdev->gadget, &(loop->function), ep); + if (result) + goto fail0; + result = usb_ep_enable(ep); if (result < 0) { fail0: diff --git a/drivers/usb/gadget/f_mass_storage.c b/drivers/usb/gadget/f_mass_storage.c index 4eee4341212..5b933958200 100644 --- a/drivers/usb/gadget/f_mass_storage.c +++ b/drivers/usb/gadget/f_mass_storage.c @@ -2324,19 +2324,6 @@ static int get_next_command(struct fsg_common *common) /*-------------------------------------------------------------------------*/ -static int enable_endpoint(struct fsg_common *common, struct usb_ep *ep, - const struct usb_endpoint_descriptor *d) -{ - int rc; - - ep->driver_data = common; - ep->desc = (struct usb_endpoint_descriptor *)d; - rc = usb_ep_enable(ep); - if (rc) - ERROR(common, "can't enable %s, result %d\n", ep->name, rc); - return rc; -} - static int alloc_request(struct fsg_common *common, struct usb_ep *ep, struct usb_request **preq) { @@ -2350,7 +2337,6 @@ static int alloc_request(struct fsg_common *common, struct usb_ep *ep, /* Reset interface setting and re-init endpoint state (toggle etc). */ static int do_set_interface(struct fsg_common *common, struct fsg_dev *new_fsg) { - const struct usb_endpoint_descriptor *d; struct fsg_dev *fsg; int i, rc = 0; @@ -2397,20 +2383,26 @@ reset: fsg = common->fsg; /* Enable the endpoints */ - d = fsg_ep_desc(common->gadget, - &fsg_fs_bulk_in_desc, &fsg_hs_bulk_in_desc); - rc = enable_endpoint(common, fsg->bulk_in, d); + rc = config_ep_by_speed(common->gadget, &(fsg->function), fsg->bulk_in); + if (rc) + goto reset; + rc = usb_ep_enable(fsg->bulk_in); if (rc) goto reset; + fsg->bulk_in->driver_data = common; fsg->bulk_in_enabled = 1; - d = fsg_ep_desc(common->gadget, - &fsg_fs_bulk_out_desc, &fsg_hs_bulk_out_desc); - rc = enable_endpoint(common, fsg->bulk_out, d); + rc = config_ep_by_speed(common->gadget, &(fsg->function), + fsg->bulk_out); + if (rc) + goto reset; + rc = usb_ep_enable(fsg->bulk_out); if (rc) goto reset; + fsg->bulk_out->driver_data = common; fsg->bulk_out_enabled = 1; - common->bulk_out_maxpacket = le16_to_cpu(d->wMaxPacketSize); + common->bulk_out_maxpacket = + le16_to_cpu(fsg->bulk_out->desc->wMaxPacketSize); clear_bit(IGNORE_BULK_OUT, &fsg->atomic_bitflags); /* Allocate the requests */ diff --git a/drivers/usb/gadget/f_ncm.c b/drivers/usb/gadget/f_ncm.c index 06daa1bc9ff..ae69ed7e6b9 100644 --- a/drivers/usb/gadget/f_ncm.c +++ b/drivers/usb/gadget/f_ncm.c @@ -48,12 +48,6 @@ #define NCM_NDP_HDR_CRC 0x01000000 #define NCM_NDP_HDR_NOCRC 0x00000000 -struct ncm_ep_descs { - struct usb_endpoint_descriptor *in; - struct usb_endpoint_descriptor *out; - struct usb_endpoint_descriptor *notify; -}; - enum ncm_notify_state { NCM_NOTIFY_NONE, /* don't notify */ NCM_NOTIFY_CONNECT, /* issue CONNECT next */ @@ -66,9 +60,6 @@ struct f_ncm { char ethaddr[14]; - struct ncm_ep_descs fs; - struct ncm_ep_descs hs; - struct usb_ep *notify; struct usb_request *notify_req; u8 notify_state; @@ -801,11 +792,12 @@ static int ncm_set_alt(struct usb_function *f, unsigned intf, unsigned alt) if (ncm->notify->driver_data) { DBG(cdev, "reset ncm control %d\n", intf); usb_ep_disable(ncm->notify); - } else { + } + + if (!(ncm->notify->desc)) { DBG(cdev, "init ncm ctrl %d\n", intf); - ncm->notify->desc = ep_choose(cdev->gadget, - ncm->hs.notify, - ncm->fs.notify); + if (config_ep_by_speed(cdev->gadget, f, ncm->notify)) + goto fail; } usb_ep_enable(ncm->notify); ncm->notify->driver_data = ncm; @@ -828,14 +820,17 @@ static int ncm_set_alt(struct usb_function *f, unsigned intf, unsigned alt) if (alt == 1) { struct net_device *net; - if (!ncm->port.in_ep->desc) { + if (!ncm->port.in_ep->desc || + !ncm->port.out_ep->desc) { DBG(cdev, "init ncm\n"); - ncm->port.in_ep->desc = ep_choose(cdev->gadget, - ncm->hs.in, - ncm->fs.in); - ncm->port.out_ep->desc = ep_choose(cdev->gadget, - ncm->hs.out, - ncm->fs.out); + if (config_ep_by_speed(cdev->gadget, f, + ncm->port.in_ep) || + config_ep_by_speed(cdev->gadget, f, + ncm->port.out_ep)) { + ncm->port.in_ep->desc = NULL; + ncm->port.out_ep->desc = NULL; + goto fail; + } } /* TODO */ @@ -1227,13 +1222,6 @@ ncm_bind(struct usb_configuration *c, struct usb_function *f) if (!f->descriptors) goto fail; - ncm->fs.in = usb_find_endpoint(ncm_fs_function, - f->descriptors, &fs_ncm_in_desc); - ncm->fs.out = usb_find_endpoint(ncm_fs_function, - f->descriptors, &fs_ncm_out_desc); - ncm->fs.notify = usb_find_endpoint(ncm_fs_function, - f->descriptors, &fs_ncm_notify_desc); - /* * support all relevant hardware speeds... we expect that when * hardware is dual speed, all bulk-capable endpoints work at @@ -1251,13 +1239,6 @@ ncm_bind(struct usb_configuration *c, struct usb_function *f) f->hs_descriptors = usb_copy_descriptors(ncm_hs_function); if (!f->hs_descriptors) goto fail; - - ncm->hs.in = usb_find_endpoint(ncm_hs_function, - f->hs_descriptors, &hs_ncm_in_desc); - ncm->hs.out = usb_find_endpoint(ncm_hs_function, - f->hs_descriptors, &hs_ncm_out_desc); - ncm->hs.notify = usb_find_endpoint(ncm_hs_function, - f->hs_descriptors, &hs_ncm_notify_desc); } /* diff --git a/drivers/usb/gadget/f_obex.c b/drivers/usb/gadget/f_obex.c index a6dbda090ca..394502abeb9 100644 --- a/drivers/usb/gadget/f_obex.c +++ b/drivers/usb/gadget/f_obex.c @@ -39,20 +39,12 @@ * ready to handle the commands. */ -struct obex_ep_descs { - struct usb_endpoint_descriptor *obex_in; - struct usb_endpoint_descriptor *obex_out; -}; - struct f_obex { struct gserial port; u8 ctrl_id; u8 data_id; u8 port_num; u8 can_activate; - - struct obex_ep_descs fs; - struct obex_ep_descs hs; }; static inline struct f_obex *func_to_obex(struct usb_function *f) @@ -227,12 +219,16 @@ static int obex_set_alt(struct usb_function *f, unsigned intf, unsigned alt) gserial_disconnect(&obex->port); } - if (!obex->port.in->desc) { + if (!obex->port.in->desc || !obex->port.out->desc) { DBG(cdev, "init obex ttyGS%d\n", obex->port_num); - obex->port.in->desc = ep_choose(cdev->gadget, - obex->hs.obex_in, obex->fs.obex_in); - obex->port.out->desc = ep_choose(cdev->gadget, - obex->hs.obex_out, obex->fs.obex_out); + if (config_ep_by_speed(cdev->gadget, f, + obex->port.in) || + config_ep_by_speed(cdev->gadget, f, + obex->port.out)) { + obex->port.out->desc = NULL; + obex->port.in->desc = NULL; + goto fail; + } } if (alt == 1) { @@ -346,11 +342,6 @@ obex_bind(struct usb_configuration *c, struct usb_function *f) /* copy descriptors, and track endpoint copies */ f->descriptors = usb_copy_descriptors(fs_function); - obex->fs.obex_in = usb_find_endpoint(fs_function, - f->descriptors, &obex_fs_ep_in_desc); - obex->fs.obex_out = usb_find_endpoint(fs_function, - f->descriptors, &obex_fs_ep_out_desc); - /* support all relevant hardware speeds... we expect that when * hardware is dual speed, all bulk-capable endpoints work at * both speeds @@ -364,11 +355,6 @@ obex_bind(struct usb_configuration *c, struct usb_function *f) /* copy descriptors, and track endpoint copies */ f->hs_descriptors = usb_copy_descriptors(hs_function); - - obex->hs.obex_in = usb_find_endpoint(hs_function, - f->hs_descriptors, &obex_hs_ep_in_desc); - obex->hs.obex_out = usb_find_endpoint(hs_function, - f->hs_descriptors, &obex_hs_ep_out_desc); } /* Avoid letting this gadget enumerate until the userspace diff --git a/drivers/usb/gadget/f_phonet.c b/drivers/usb/gadget/f_phonet.c index dc63f161a10..0d6d26090da 100644 --- a/drivers/usb/gadget/f_phonet.c +++ b/drivers/usb/gadget/f_phonet.c @@ -429,12 +429,12 @@ static int pn_set_alt(struct usb_function *f, unsigned intf, unsigned alt) if (alt == 1) { int i; - fp->out_ep->desc = ep_choose(gadget, - &pn_hs_sink_desc, - &pn_fs_sink_desc); - fp->in_ep->desc = ep_choose(gadget, - &pn_hs_source_desc, - &pn_fs_source_desc); + if (config_ep_by_speed(gadget, f, fp->in_ep) || + config_ep_by_speed(gadget, f, fp->out_ep)) { + fp->in_ep->desc = NULL; + fp->out_ep->desc = NULL; + return -EINVAL; + } usb_ep_enable(fp->out_ep); usb_ep_enable(fp->in_ep); diff --git a/drivers/usb/gadget/f_rndis.c b/drivers/usb/gadget/f_rndis.c index 4646254a892..b324efa0773 100644 --- a/drivers/usb/gadget/f_rndis.c +++ b/drivers/usb/gadget/f_rndis.c @@ -76,21 +76,12 @@ * - MS-Windows drivers sometimes emit undocumented requests. */ -struct rndis_ep_descs { - struct usb_endpoint_descriptor *in; - struct usb_endpoint_descriptor *out; - struct usb_endpoint_descriptor *notify; -}; - struct f_rndis { struct gether port; u8 ctrl_id, data_id; u8 ethaddr[ETH_ALEN]; int config; - struct rndis_ep_descs fs; - struct rndis_ep_descs hs; - struct usb_ep *notify; struct usb_request *notify_req; atomic_t notify_count; @@ -483,11 +474,11 @@ static int rndis_set_alt(struct usb_function *f, unsigned intf, unsigned alt) if (rndis->notify->driver_data) { VDBG(cdev, "reset rndis control %d\n", intf); usb_ep_disable(rndis->notify); - } else { + } + if (!rndis->notify->desc) { VDBG(cdev, "init rndis ctrl %d\n", intf); - rndis->notify->desc = ep_choose(cdev->gadget, - rndis->hs.notify, - rndis->fs.notify); + if (config_ep_by_speed(cdev->gadget, f, rndis->notify)) + goto fail; } usb_ep_enable(rndis->notify); rndis->notify->driver_data = rndis; @@ -500,12 +491,16 @@ static int rndis_set_alt(struct usb_function *f, unsigned intf, unsigned alt) gether_disconnect(&rndis->port); } - if (!rndis->port.in_ep->desc) { + if (!rndis->port.in_ep->desc || !rndis->port.out_ep->desc) { DBG(cdev, "init rndis\n"); - rndis->port.in_ep->desc = ep_choose(cdev->gadget, - rndis->hs.in, rndis->fs.in); - rndis->port.out_ep->desc = ep_choose(cdev->gadget, - rndis->hs.out, rndis->fs.out); + if (config_ep_by_speed(cdev->gadget, f, + rndis->port.in_ep) || + config_ep_by_speed(cdev->gadget, f, + rndis->port.out_ep)) { + rndis->port.in_ep->desc = NULL; + rndis->port.out_ep->desc = NULL; + goto fail; + } } /* Avoid ZLPs; they can be troublesome. */ @@ -661,13 +656,6 @@ rndis_bind(struct usb_configuration *c, struct usb_function *f) if (!f->descriptors) goto fail; - rndis->fs.in = usb_find_endpoint(eth_fs_function, - f->descriptors, &fs_in_desc); - rndis->fs.out = usb_find_endpoint(eth_fs_function, - f->descriptors, &fs_out_desc); - rndis->fs.notify = usb_find_endpoint(eth_fs_function, - f->descriptors, &fs_notify_desc); - /* support all relevant hardware speeds... we expect that when * hardware is dual speed, all bulk-capable endpoints work at * both speeds @@ -685,13 +673,6 @@ rndis_bind(struct usb_configuration *c, struct usb_function *f) if (!f->hs_descriptors) goto fail; - - rndis->hs.in = usb_find_endpoint(eth_hs_function, - f->hs_descriptors, &hs_in_desc); - rndis->hs.out = usb_find_endpoint(eth_hs_function, - f->hs_descriptors, &hs_out_desc); - rndis->hs.notify = usb_find_endpoint(eth_hs_function, - f->hs_descriptors, &hs_notify_desc); } rndis->port.open = rndis_open; diff --git a/drivers/usb/gadget/f_serial.c b/drivers/usb/gadget/f_serial.c index a9ce6261d15..91fdf790ed2 100644 --- a/drivers/usb/gadget/f_serial.c +++ b/drivers/usb/gadget/f_serial.c @@ -27,18 +27,10 @@ * if you can arrange appropriate host side drivers. */ -struct gser_descs { - struct usb_endpoint_descriptor *in; - struct usb_endpoint_descriptor *out; -}; - struct f_gser { struct gserial port; u8 data_id; u8 port_num; - - struct gser_descs fs; - struct gser_descs hs; }; static inline struct f_gser *func_to_gser(struct usb_function *f) @@ -136,12 +128,15 @@ static int gser_set_alt(struct usb_function *f, unsigned intf, unsigned alt) if (gser->port.in->driver_data) { DBG(cdev, "reset generic ttyGS%d\n", gser->port_num); gserial_disconnect(&gser->port); - } else { + } + if (!gser->port.in->desc || !gser->port.out->desc) { DBG(cdev, "activate generic ttyGS%d\n", gser->port_num); - gser->port.in->desc = ep_choose(cdev->gadget, - gser->hs.in, gser->fs.in); - gser->port.out->desc = ep_choose(cdev->gadget, - gser->hs.out, gser->fs.out); + if (!config_ep_by_speed(cdev->gadget, f, gser->port.in) || + !config_ep_by_speed(cdev->gadget, f, gser->port.out)) { + gser->port.in->desc = NULL; + gser->port.out->desc = NULL; + return -EINVAL; + } } gserial_connect(&gser->port, gser->port_num); return 0; @@ -193,12 +188,6 @@ gser_bind(struct usb_configuration *c, struct usb_function *f) /* copy descriptors, and track endpoint copies */ f->descriptors = usb_copy_descriptors(gser_fs_function); - gser->fs.in = usb_find_endpoint(gser_fs_function, - f->descriptors, &gser_fs_in_desc); - gser->fs.out = usb_find_endpoint(gser_fs_function, - f->descriptors, &gser_fs_out_desc); - - /* support all relevant hardware speeds... we expect that when * hardware is dual speed, all bulk-capable endpoints work at * both speeds @@ -211,11 +200,6 @@ gser_bind(struct usb_configuration *c, struct usb_function *f) /* copy descriptors, and track endpoint copies */ f->hs_descriptors = usb_copy_descriptors(gser_hs_function); - - gser->hs.in = usb_find_endpoint(gser_hs_function, - f->hs_descriptors, &gser_hs_in_desc); - gser->hs.out = usb_find_endpoint(gser_hs_function, - f->hs_descriptors, &gser_hs_out_desc); } DBG(cdev, "generic ttyGS%d: %s speed IN/%s OUT/%s\n", diff --git a/drivers/usb/gadget/f_sourcesink.c b/drivers/usb/gadget/f_sourcesink.c index 0ffddd33a55..caf2f95e034 100644 --- a/drivers/usb/gadget/f_sourcesink.c +++ b/drivers/usb/gadget/f_sourcesink.c @@ -347,7 +347,9 @@ enable_source_sink(struct usb_composite_dev *cdev, struct f_sourcesink *ss) /* one endpoint writes (sources) zeroes IN (to the host) */ ep = ss->in_ep; - ep->desc = ep_choose(cdev->gadget, &hs_source_desc, &fs_source_desc); + result = config_ep_by_speed(cdev->gadget, &(ss->function), ep); + if (result) + return result; result = usb_ep_enable(ep); if (result < 0) return result; @@ -364,7 +366,9 @@ fail: /* one endpoint reads (sinks) anything OUT (from the host) */ ep = ss->out_ep; - ep->desc = ep_choose(cdev->gadget, &hs_sink_desc, &fs_sink_desc); + result = config_ep_by_speed(cdev->gadget, &(ss->function), ep); + if (result) + goto fail; result = usb_ep_enable(ep); if (result < 0) goto fail; diff --git a/drivers/usb/gadget/f_subset.c b/drivers/usb/gadget/f_subset.c index aecaed1724a..93bf676ef50 100644 --- a/drivers/usb/gadget/f_subset.c +++ b/drivers/usb/gadget/f_subset.c @@ -57,18 +57,10 @@ * caring about specific product and vendor IDs. */ -struct geth_descs { - struct usb_endpoint_descriptor *in; - struct usb_endpoint_descriptor *out; -}; - struct f_gether { struct gether port; char ethaddr[14]; - - struct geth_descs fs; - struct geth_descs hs; }; static inline struct f_gether *func_to_geth(struct usb_function *f) @@ -243,10 +235,12 @@ static int geth_set_alt(struct usb_function *f, unsigned intf, unsigned alt) } DBG(cdev, "init + activate cdc subset\n"); - geth->port.in_ep->desc = ep_choose(cdev->gadget, - geth->hs.in, geth->fs.in); - geth->port.out_ep->desc = ep_choose(cdev->gadget, - geth->hs.out, geth->fs.out); + if (config_ep_by_speed(cdev->gadget, f, geth->port.in_ep) || + config_ep_by_speed(cdev->gadget, f, geth->port.out_ep)) { + geth->port.in_ep->desc = NULL; + geth->port.out_ep->desc = NULL; + return -EINVAL; + } net = gether_connect(&geth->port); return IS_ERR(net) ? PTR_ERR(net) : 0; @@ -297,12 +291,6 @@ geth_bind(struct usb_configuration *c, struct usb_function *f) /* copy descriptors, and track endpoint copies */ f->descriptors = usb_copy_descriptors(fs_eth_function); - geth->fs.in = usb_find_endpoint(fs_eth_function, - f->descriptors, &fs_subset_in_desc); - geth->fs.out = usb_find_endpoint(fs_eth_function, - f->descriptors, &fs_subset_out_desc); - - /* support all relevant hardware speeds... we expect that when * hardware is dual speed, all bulk-capable endpoints work at * both speeds @@ -315,11 +303,6 @@ geth_bind(struct usb_configuration *c, struct usb_function *f) /* copy descriptors, and track endpoint copies */ f->hs_descriptors = usb_copy_descriptors(hs_eth_function); - - geth->hs.in = usb_find_endpoint(hs_eth_function, - f->hs_descriptors, &hs_subset_in_desc); - geth->hs.out = usb_find_endpoint(hs_eth_function, - f->hs_descriptors, &hs_subset_out_desc); } /* NOTE: all that is done without knowing or caring about diff --git a/include/linux/usb/composite.h b/include/linux/usb/composite.h index 2014d6b1bab..99830d63d8f 100644 --- a/include/linux/usb/composite.h +++ b/include/linux/usb/composite.h @@ -148,21 +148,6 @@ int usb_interface_id(struct usb_configuration *, struct usb_function *); int config_ep_by_speed(struct usb_gadget *g, struct usb_function *f, struct usb_ep *_ep); -/** - * ep_choose - select descriptor endpoint at current device speed - * @g: gadget, connected and running at some speed - * @hs: descriptor to use for high speed operation - * @fs: descriptor to use for full or low speed operation - */ -static inline struct usb_endpoint_descriptor * -ep_choose(struct usb_gadget *g, struct usb_endpoint_descriptor *hs, - struct usb_endpoint_descriptor *fs) -{ - if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH) - return hs; - return fs; -} - #define MAX_CONFIG_INTERFACES 16 /* arbitrary; max 255 */ /** diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h index 0bcc2b76bcd..d22b4a4936c 100644 --- a/include/linux/usb/gadget.h +++ b/include/linux/usb/gadget.h @@ -879,12 +879,6 @@ int usb_gadget_config_buf(const struct usb_config_descriptor *config, struct usb_descriptor_header **usb_copy_descriptors( struct usb_descriptor_header **); -/* return copy of endpoint descriptor given original descriptor set */ -struct usb_endpoint_descriptor *usb_find_endpoint( - struct usb_descriptor_header **src, - struct usb_descriptor_header **copy, - struct usb_endpoint_descriptor *match); - /** * usb_free_descriptors - free descriptors returned by usb_copy_descriptors() * @v: vector of descriptors -- cgit v1.2.3-70-g09d2 From 7c884fe4d74d17efc83b19f3dc898a75f03859e9 Mon Sep 17 00:00:00 2001 From: Tatyana Brokhman Date: Tue, 28 Jun 2011 16:33:52 +0300 Subject: usb: gadget: coding style fix fix the coding style of a few switches on the gadget framework. [ balbi@ti.com : add a commit log ] Signed-off-by: Tatyana Brokhman Signed-off-by: Felipe Balbi Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/composite.c | 16 ++++++++++---- drivers/usb/gadget/dummy_hcd.c | 48 +++++++++++++++++++++++++++++++----------- 2 files changed, 48 insertions(+), 16 deletions(-) (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c index 1c6bd666150..ed8a70f271f 100644 --- a/drivers/usb/gadget/composite.c +++ b/drivers/usb/gadget/composite.c @@ -495,10 +495,18 @@ static int set_config(struct usb_composite_dev *cdev, INFO(cdev, "%s speed config #%d: %s\n", ({ char *speed; switch (gadget->speed) { - case USB_SPEED_LOW: speed = "low"; break; - case USB_SPEED_FULL: speed = "full"; break; - case USB_SPEED_HIGH: speed = "high"; break; - default: speed = "?"; break; + case USB_SPEED_LOW: + speed = "low"; + break; + case USB_SPEED_FULL: + speed = "full"; + break; + case USB_SPEED_HIGH: + speed = "high"; + break; + default: + speed = "?"; + break; } ; speed; }), number, c ? c->label : "unconfigured"); if (!c) diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c index d47a565d085..cbcb4c7fd26 100644 --- a/drivers/usb/gadget/dummy_hcd.c +++ b/drivers/usb/gadget/dummy_hcd.c @@ -425,10 +425,18 @@ dummy_enable (struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc) (desc->bEndpointAddress & USB_DIR_IN) ? "in" : "out", ({ char *val; switch (desc->bmAttributes & 0x03) { - case USB_ENDPOINT_XFER_BULK: val = "bulk"; break; - case USB_ENDPOINT_XFER_ISOC: val = "iso"; break; - case USB_ENDPOINT_XFER_INT: val = "intr"; break; - default: val = "ctrl"; break; + case USB_ENDPOINT_XFER_BULK: + val = "bulk"; + break; + case USB_ENDPOINT_XFER_ISOC: + val = "iso"; + break; + case USB_ENDPOINT_XFER_INT: + val = "intr"; + break; + default: + val = "ctrl"; + break; }; val; }), max); @@ -1798,18 +1806,34 @@ show_urb (char *buf, size_t size, struct urb *urb) urb, ({ char *s; switch (urb->dev->speed) { - case USB_SPEED_LOW: s = "ls"; break; - case USB_SPEED_FULL: s = "fs"; break; - case USB_SPEED_HIGH: s = "hs"; break; - default: s = "?"; break; + case USB_SPEED_LOW: + s = "ls"; + break; + case USB_SPEED_FULL: + s = "fs"; + break; + case USB_SPEED_HIGH: + s = "hs"; + break; + default: + s = "?"; + break; }; s; }), ep, ep ? (usb_pipein (urb->pipe) ? "in" : "out") : "", ({ char *s; \ switch (usb_pipetype (urb->pipe)) { \ - case PIPE_CONTROL: s = ""; break; \ - case PIPE_BULK: s = "-bulk"; break; \ - case PIPE_INTERRUPT: s = "-int"; break; \ - default: s = "-iso"; break; \ + case PIPE_CONTROL: \ + s = ""; \ + break; \ + case PIPE_BULK: \ + s = "-bulk"; \ + break; \ + case PIPE_INTERRUPT: \ + s = "-int"; \ + break; \ + default: \ + s = "-iso"; \ + break; \ }; s;}), urb->actual_length, urb->transfer_buffer_length); } -- cgit v1.2.3-70-g09d2 From a59d6b91cbca52235e3ed9f7f9e34c4f2f3e1996 Mon Sep 17 00:00:00 2001 From: Tatyana Brokhman Date: Tue, 28 Jun 2011 16:33:53 +0300 Subject: usb: gadget: add streams support to the gadget framework This patch defines necessary fields to support streaming for USB3.0. It implements a new function, called usb_ep_autoconfig_ss(), to be used instead of the existing usb_ep_autoconfig() when working in SuperSpeed mode and there is a need to search for an endpoint according to the number of required streams. [ balbi@ti.com : slight changes to commit log ] Signed-off-by: Maya Erez Signed-off-by: Tatyana Brokhman Signed-off-by: Felipe Balbi Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/epautoconf.c | 125 ++++++++++++++++++++++++++++++++-------- include/linux/usb/gadget.h | 13 +++++ 2 files changed, 113 insertions(+), 25 deletions(-) (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/epautoconf.c b/drivers/usb/gadget/epautoconf.c index 0022d44060a..91c032fbdf1 100644 --- a/drivers/usb/gadget/epautoconf.c +++ b/drivers/usb/gadget/epautoconf.c @@ -63,13 +63,16 @@ static int ep_matches ( struct usb_gadget *gadget, struct usb_ep *ep, - struct usb_endpoint_descriptor *desc + struct usb_endpoint_descriptor *desc, + struct usb_ss_ep_comp_descriptor *ep_comp ) { u8 type; const char *tmp; u16 max; + int num_req_streams = 0; + /* endpoint already claimed? */ if (NULL != ep->driver_data) return 0; @@ -128,6 +131,22 @@ ep_matches ( } } + /* + * Get the number of required streams from the EP companion + * descriptor and see if the EP matches it + */ + if (usb_endpoint_xfer_bulk(desc)) { + if (ep_comp) { + num_req_streams = ep_comp->bmAttributes & 0x1f; + if (num_req_streams > ep->max_streams) + return 0; + /* Update the ep_comp descriptor if needed */ + if (num_req_streams != ep->max_streams) + ep_comp->bmAttributes = ep->max_streams; + } + + } + /* * If the protocol driver hasn't yet decided on wMaxPacketSize * and wants to know the maximum possible, provide the info. @@ -208,38 +227,53 @@ find_ep (struct usb_gadget *gadget, const char *name) } /** - * usb_ep_autoconfig - choose an endpoint matching the descriptor + * usb_ep_autoconfig_ss() - choose an endpoint matching the ep + * descriptor and ep companion descriptor * @gadget: The device to which the endpoint must belong. * @desc: Endpoint descriptor, with endpoint direction and transfer mode - * initialized. For periodic transfers, the maximum packet - * size must also be initialized. This is modified on success. + * initialized. For periodic transfers, the maximum packet + * size must also be initialized. This is modified on + * success. + * @ep_comp: Endpoint companion descriptor, with the required + * number of streams. Will be modified when the chosen EP + * supports a different number of streams. * - * By choosing an endpoint to use with the specified descriptor, this - * routine simplifies writing gadget drivers that work with multiple - * USB device controllers. The endpoint would be passed later to - * usb_ep_enable(), along with some descriptor. + * This routine replaces the usb_ep_autoconfig when needed + * superspeed enhancments. If such enhancemnets are required, + * the FD should call usb_ep_autoconfig_ss directly and provide + * the additional ep_comp parameter. + * + * By choosing an endpoint to use with the specified descriptor, + * this routine simplifies writing gadget drivers that work with + * multiple USB device controllers. The endpoint would be + * passed later to usb_ep_enable(), along with some descriptor. * * That second descriptor won't always be the same as the first one. * For example, isochronous endpoints can be autoconfigured for high * bandwidth, and then used in several lower bandwidth altsettings. * Also, high and full speed descriptors will be different. * - * Be sure to examine and test the results of autoconfiguration on your - * hardware. This code may not make the best choices about how to use the - * USB controller, and it can't know all the restrictions that may apply. - * Some combinations of driver and hardware won't be able to autoconfigure. + * Be sure to examine and test the results of autoconfiguration + * on your hardware. This code may not make the best choices + * about how to use the USB controller, and it can't know all + * the restrictions that may apply. Some combinations of driver + * and hardware won't be able to autoconfigure. * * On success, this returns an un-claimed usb_ep, and modifies the endpoint * descriptor bEndpointAddress. For bulk endpoints, the wMaxPacket value - * is initialized as if the endpoint were used at full speed. To prevent - * the endpoint from being returned by a later autoconfig call, claim it - * by assigning ep->driver_data to some non-null value. + * is initialized as if the endpoint were used at full speed and + * the bmAttribute field in the ep companion descriptor is + * updated with the assigned number of streams if it is + * different from the original value. To prevent the endpoint + * from being returned by a later autoconfig call, claim it by + * assigning ep->driver_data to some non-null value. * * On failure, this returns a null endpoint descriptor. */ -struct usb_ep *usb_ep_autoconfig ( +struct usb_ep *usb_ep_autoconfig_ss( struct usb_gadget *gadget, - struct usb_endpoint_descriptor *desc + struct usb_endpoint_descriptor *desc, + struct usb_ss_ep_comp_descriptor *ep_comp ) { struct usb_ep *ep; @@ -253,23 +287,24 @@ struct usb_ep *usb_ep_autoconfig ( if (gadget_is_net2280 (gadget) && type == USB_ENDPOINT_XFER_INT) { /* ep-e, ep-f are PIO with only 64 byte fifos */ ep = find_ep (gadget, "ep-e"); - if (ep && ep_matches (gadget, ep, desc)) + if (ep && ep_matches(gadget, ep, desc, ep_comp)) return ep; ep = find_ep (gadget, "ep-f"); - if (ep && ep_matches (gadget, ep, desc)) + if (ep && ep_matches(gadget, ep, desc, ep_comp)) return ep; } else if (gadget_is_goku (gadget)) { if (USB_ENDPOINT_XFER_INT == type) { /* single buffering is enough */ - ep = find_ep (gadget, "ep3-bulk"); - if (ep && ep_matches (gadget, ep, desc)) + ep = find_ep(gadget, "ep3-bulk"); + if (ep && ep_matches(gadget, ep, desc, ep_comp)) return ep; } else if (USB_ENDPOINT_XFER_BULK == type && (USB_DIR_IN & desc->bEndpointAddress)) { /* DMA may be available */ - ep = find_ep (gadget, "ep2-bulk"); - if (ep && ep_matches (gadget, ep, desc)) + ep = find_ep(gadget, "ep2-bulk"); + if (ep && ep_matches(gadget, ep, desc, + ep_comp)) return ep; } @@ -288,14 +323,14 @@ struct usb_ep *usb_ep_autoconfig ( ep = find_ep(gadget, "ep2out"); } else ep = NULL; - if (ep && ep_matches (gadget, ep, desc)) + if (ep && ep_matches(gadget, ep, desc, ep_comp)) return ep; #endif } /* Second, look at endpoints until an unclaimed one looks usable */ list_for_each_entry (ep, &gadget->ep_list, ep_list) { - if (ep_matches (gadget, ep, desc)) + if (ep_matches(gadget, ep, desc, ep_comp)) return ep; } @@ -303,6 +338,46 @@ struct usb_ep *usb_ep_autoconfig ( return NULL; } +/** + * usb_ep_autoconfig() - choose an endpoint matching the + * descriptor + * @gadget: The device to which the endpoint must belong. + * @desc: Endpoint descriptor, with endpoint direction and transfer mode + * initialized. For periodic transfers, the maximum packet + * size must also be initialized. This is modified on success. + * + * By choosing an endpoint to use with the specified descriptor, this + * routine simplifies writing gadget drivers that work with multiple + * USB device controllers. The endpoint would be passed later to + * usb_ep_enable(), along with some descriptor. + * + * That second descriptor won't always be the same as the first one. + * For example, isochronous endpoints can be autoconfigured for high + * bandwidth, and then used in several lower bandwidth altsettings. + * Also, high and full speed descriptors will be different. + * + * Be sure to examine and test the results of autoconfiguration on your + * hardware. This code may not make the best choices about how to use the + * USB controller, and it can't know all the restrictions that may apply. + * Some combinations of driver and hardware won't be able to autoconfigure. + * + * On success, this returns an un-claimed usb_ep, and modifies the endpoint + * descriptor bEndpointAddress. For bulk endpoints, the wMaxPacket value + * is initialized as if the endpoint were used at full speed. To prevent + * the endpoint from being returned by a later autoconfig call, claim it + * by assigning ep->driver_data to some non-null value. + * + * On failure, this returns a null endpoint descriptor. + */ +struct usb_ep *usb_ep_autoconfig( + struct usb_gadget *gadget, + struct usb_endpoint_descriptor *desc +) +{ + return usb_ep_autoconfig_ss(gadget, desc, NULL); +} + + /** * usb_ep_autoconfig_reset - reset endpoint autoconfig state * @gadget: device for which autoconfig state will be reset diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h index d22b4a4936c..625971292c2 100644 --- a/include/linux/usb/gadget.h +++ b/include/linux/usb/gadget.h @@ -28,6 +28,7 @@ struct usb_ep; * field, and the usb controller needs one, it is responsible * for mapping and unmapping the buffer. * @length: Length of that data + * @stream_id: The stream id, when USB3.0 bulk streams are being used * @no_interrupt: If true, hints that no completion irq is needed. * Helpful sometimes with deep request queues that are handled * directly by DMA controllers. @@ -82,6 +83,7 @@ struct usb_request { unsigned length; dma_addr_t dma; + unsigned stream_id:16; unsigned no_interrupt:1; unsigned zero:1; unsigned short_not_ok:1; @@ -132,11 +134,15 @@ struct usb_ep_ops { * @maxpacket:The maximum packet size used on this endpoint. The initial * value can sometimes be reduced (hardware allowing), according to * the endpoint descriptor used to configure the endpoint. + * @max_streams: The maximum number of streams supported + * by this EP (0 - 16, actual number is 2^n) * @driver_data:for use by the gadget driver. * @address: used to identify the endpoint when finding descriptor that * matches connection speed * @desc: endpoint descriptor. This pointer is set before the endpoint is * enabled and remains valid until the endpoint is disabled. + * @comp_desc: In case of SuperSpeed support, this is the endpoint companion + * descriptor that is used to configure the endpoint * * the bus controller driver lists all the general purpose endpoints in * gadget->ep_list. the control endpoint (gadget->ep0) is not in that list, @@ -149,8 +155,10 @@ struct usb_ep { const struct usb_ep_ops *ops; struct list_head ep_list; unsigned maxpacket:16; + unsigned max_streams:16; u8 address; const struct usb_endpoint_descriptor *desc; + const struct usb_ss_ep_comp_descriptor *comp_desc; }; /*-------------------------------------------------------------------------*/ @@ -895,6 +903,11 @@ static inline void usb_free_descriptors(struct usb_descriptor_header **v) extern struct usb_ep *usb_ep_autoconfig(struct usb_gadget *, struct usb_endpoint_descriptor *); + +extern struct usb_ep *usb_ep_autoconfig_ss(struct usb_gadget *, + struct usb_endpoint_descriptor *, + struct usb_ss_ep_comp_descriptor *); + extern void usb_ep_autoconfig_reset(struct usb_gadget *); #endif /* __LINUX_USB_GADGET_H */ -- cgit v1.2.3-70-g09d2 From 35a0e0bf6f6b2b900d461e9f35c286953b2b1afc Mon Sep 17 00:00:00 2001 From: Tatyana Brokhman Date: Wed, 29 Jun 2011 16:41:49 +0300 Subject: usb: gadget: add max_speed to usb_composite_driver This field is used by the Gadget drivers to specify the maximum speed they support, meaning: the maximum speed they can provide descriptors for. The driver speed will be set in consideration of this value. [ balbi@ti.com : dropped the ifdeffery ] Signed-off-by: Tatyana Brokhman Signed-off-by: Felipe Balbi Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/audio.c | 1 + drivers/usb/gadget/cdc2.c | 1 + drivers/usb/gadget/composite.c | 2 ++ drivers/usb/gadget/ether.c | 1 + drivers/usb/gadget/g_ffs.c | 1 + drivers/usb/gadget/hid.c | 1 + drivers/usb/gadget/mass_storage.c | 1 + drivers/usb/gadget/multi.c | 1 + drivers/usb/gadget/ncm.c | 1 + drivers/usb/gadget/nokia.c | 1 + drivers/usb/gadget/serial.c | 1 + drivers/usb/gadget/webcam.c | 1 + drivers/usb/gadget/zero.c | 1 + include/linux/usb/composite.h | 2 ++ 14 files changed, 16 insertions(+) (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/audio.c b/drivers/usb/gadget/audio.c index 93b999e49ef..9d89ae4765a 100644 --- a/drivers/usb/gadget/audio.c +++ b/drivers/usb/gadget/audio.c @@ -165,6 +165,7 @@ static struct usb_composite_driver audio_driver = { .name = "g_audio", .dev = &device_desc, .strings = audio_strings, + .max_speed = USB_SPEED_HIGH, .unbind = __exit_p(audio_unbind), }; diff --git a/drivers/usb/gadget/cdc2.c b/drivers/usb/gadget/cdc2.c index 2720ab07ef1..b1c1afbb875 100644 --- a/drivers/usb/gadget/cdc2.c +++ b/drivers/usb/gadget/cdc2.c @@ -244,6 +244,7 @@ static struct usb_composite_driver cdc_driver = { .name = "g_cdc", .dev = &device_desc, .strings = dev_strings, + .max_speed = USB_SPEED_HIGH, .unbind = __exit_p(cdc_unbind), }; diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c index ed8a70f271f..897e4f57422 100644 --- a/drivers/usb/gadget/composite.c +++ b/drivers/usb/gadget/composite.c @@ -1386,6 +1386,8 @@ int usb_composite_probe(struct usb_composite_driver *driver, driver->iProduct = driver->name; composite_driver.function = (char *) driver->name; composite_driver.driver.name = driver->name; + composite_driver.speed = min((u8)composite_driver.speed, + (u8)driver->max_speed); composite = driver; composite_gadget_bind = bind; diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c index 1690c9d6825..ac41858800a 100644 --- a/drivers/usb/gadget/ether.c +++ b/drivers/usb/gadget/ether.c @@ -401,6 +401,7 @@ static struct usb_composite_driver eth_driver = { .name = "g_ether", .dev = &device_desc, .strings = dev_strings, + .max_speed = USB_SPEED_HIGH, .unbind = __exit_p(eth_unbind), }; diff --git a/drivers/usb/gadget/g_ffs.c b/drivers/usb/gadget/g_ffs.c index ebf6970a10b..704c2800ac0 100644 --- a/drivers/usb/gadget/g_ffs.c +++ b/drivers/usb/gadget/g_ffs.c @@ -162,6 +162,7 @@ static struct usb_composite_driver gfs_driver = { .name = DRIVER_NAME, .dev = &gfs_dev_desc, .strings = gfs_dev_strings, + .max_speed = USB_SPEED_HIGH, .unbind = gfs_unbind, .iProduct = DRIVER_DESC, }; diff --git a/drivers/usb/gadget/hid.c b/drivers/usb/gadget/hid.c index 2523e54097b..9fb575034a0 100644 --- a/drivers/usb/gadget/hid.c +++ b/drivers/usb/gadget/hid.c @@ -255,6 +255,7 @@ static struct usb_composite_driver hidg_driver = { .name = "g_hid", .dev = &device_desc, .strings = dev_strings, + .max_speed = USB_SPEED_HIGH, .unbind = __exit_p(hid_unbind), }; diff --git a/drivers/usb/gadget/mass_storage.c b/drivers/usb/gadget/mass_storage.c index 01822422c3e..d3eb27427c5 100644 --- a/drivers/usb/gadget/mass_storage.c +++ b/drivers/usb/gadget/mass_storage.c @@ -169,6 +169,7 @@ static struct usb_composite_driver msg_driver = { .name = "g_mass_storage", .dev = &msg_device_desc, .iProduct = DRIVER_DESC, + .max_speed = USB_SPEED_HIGH, .needs_serial = 1, }; diff --git a/drivers/usb/gadget/multi.c b/drivers/usb/gadget/multi.c index d9feced348e..8c7b74717d8 100644 --- a/drivers/usb/gadget/multi.c +++ b/drivers/usb/gadget/multi.c @@ -351,6 +351,7 @@ static struct usb_composite_driver multi_driver = { .name = "g_multi", .dev = &device_desc, .strings = dev_strings, + .max_speed = USB_SPEED_HIGH, .unbind = __exit_p(multi_unbind), .iProduct = DRIVER_DESC, .needs_serial = 1, diff --git a/drivers/usb/gadget/ncm.c b/drivers/usb/gadget/ncm.c index 99c179ad729..62ee5087dca 100644 --- a/drivers/usb/gadget/ncm.c +++ b/drivers/usb/gadget/ncm.c @@ -228,6 +228,7 @@ static struct usb_composite_driver ncm_driver = { .name = "g_ncm", .dev = &device_desc, .strings = dev_strings, + .max_speed = USB_SPEED_HIGH, .unbind = __exit_p(gncm_unbind), }; diff --git a/drivers/usb/gadget/nokia.c b/drivers/usb/gadget/nokia.c index 55ca63ad350..c7fb7723c01 100644 --- a/drivers/usb/gadget/nokia.c +++ b/drivers/usb/gadget/nokia.c @@ -241,6 +241,7 @@ static struct usb_composite_driver nokia_driver = { .name = "g_nokia", .dev = &device_desc, .strings = dev_strings, + .max_speed = USB_SPEED_HIGH, .unbind = __exit_p(nokia_unbind), }; diff --git a/drivers/usb/gadget/serial.c b/drivers/usb/gadget/serial.c index 1ac57a973aa..ed1b816e58d 100644 --- a/drivers/usb/gadget/serial.c +++ b/drivers/usb/gadget/serial.c @@ -242,6 +242,7 @@ static struct usb_composite_driver gserial_driver = { .name = "g_serial", .dev = &device_desc, .strings = dev_strings, + .max_speed = USB_SPEED_HIGH, }; static int __init init(void) diff --git a/drivers/usb/gadget/webcam.c b/drivers/usb/gadget/webcam.c index a5a0fdb808c..df6882de50b 100644 --- a/drivers/usb/gadget/webcam.c +++ b/drivers/usb/gadget/webcam.c @@ -373,6 +373,7 @@ static struct usb_composite_driver webcam_driver = { .name = "g_webcam", .dev = &webcam_device_descriptor, .strings = webcam_device_strings, + .max_speed = USB_SPEED_HIGH, .unbind = webcam_unbind, }; diff --git a/drivers/usb/gadget/zero.c b/drivers/usb/gadget/zero.c index 6d16db9d9d2..af7e7c3818d 100644 --- a/drivers/usb/gadget/zero.c +++ b/drivers/usb/gadget/zero.c @@ -340,6 +340,7 @@ static struct usb_composite_driver zero_driver = { .name = "zero", .dev = &device_desc, .strings = dev_strings, + .max_speed = USB_SPEED_HIGH, .unbind = zero_unbind, .suspend = zero_suspend, .resume = zero_resume, diff --git a/include/linux/usb/composite.h b/include/linux/usb/composite.h index 99830d63d8f..a3e72dfa699 100644 --- a/include/linux/usb/composite.h +++ b/include/linux/usb/composite.h @@ -240,6 +240,7 @@ int usb_add_config(struct usb_composite_dev *, * identifiers. * @strings: tables of strings, keyed by identifiers assigned during bind() * and language IDs provided in control requests + * @max_speed: Highest speed the driver supports. * @needs_serial: set to 1 if the gadget needs userspace to provide * a serial number. If one is not provided, warning will be printed. * @unbind: Reverses bind; called as a side effect of unregistering @@ -267,6 +268,7 @@ struct usb_composite_driver { const char *iManufacturer; const struct usb_device_descriptor *dev; struct usb_gadget_strings **strings; + enum usb_device_speed max_speed; unsigned needs_serial:1; int (*unbind)(struct usb_composite_dev *); -- cgit v1.2.3-70-g09d2 From bdb64d727216b49a18c2b8337658adc6b2db82ea Mon Sep 17 00:00:00 2001 From: Tatyana Brokhman Date: Wed, 29 Jun 2011 16:41:50 +0300 Subject: usb: gadget: add SuperSpeed support to the Gadget Framework SuperSpeed USB has defined a new descriptor, called the Binary Device Object Store (BOS) Descriptor. It has also changed a bit the definition of SET_FEATURE and GET_STATUS requests to add USB3-specific details. This patch implements both changes to the Composite Gadget Framework. [ balbi@ti.com : slight changes to commit log fixed a compile error on ARM ] Signed-off-by: Tatyana Brokhman Signed-off-by: Felipe Balbi Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/Kconfig | 6 + drivers/usb/gadget/composite.c | 257 +++++++++++++++++++++++++++++++++++++--- drivers/usb/gadget/epautoconf.c | 6 +- include/linux/usb/composite.h | 14 +++ include/linux/usb/gadget.h | 31 +++++ 5 files changed, 293 insertions(+), 21 deletions(-) (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index 22e43fffbcc..a23e291f07c 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -666,6 +666,12 @@ config USB_GADGET_DUALSPEED bool depends on USB_GADGET +# Selected by UDC drivers that support super-speed opperation +config USB_GADGET_SUPERSPEED + bool + depends on USB_GADGET + depends on USB_GADGET_DUALSPEED + # # USB Gadget Drivers # diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c index 897e4f57422..c5abe270970 100644 --- a/drivers/usb/gadget/composite.c +++ b/drivers/usb/gadget/composite.c @@ -27,7 +27,7 @@ #include #include - +#include /* * The code in this file is utility code, used to build a gadget driver @@ -128,6 +128,9 @@ int config_ep_by_speed(struct usb_gadget *g, struct usb_endpoint_descriptor *chosen_desc = NULL; struct usb_descriptor_header **speed_desc = NULL; + struct usb_ss_ep_comp_descriptor *comp_desc = NULL; + int want_comp_desc = 0; + struct usb_descriptor_header **d_spd; /* cursor for speed desc */ if (!g || !f || !_ep) @@ -135,6 +138,13 @@ int config_ep_by_speed(struct usb_gadget *g, /* select desired speed */ switch (g->speed) { + case USB_SPEED_SUPER: + if (gadget_is_superspeed(g)) { + speed_desc = f->ss_descriptors; + want_comp_desc = 1; + break; + } + /* else: Fall trough */ case USB_SPEED_HIGH: if (gadget_is_dualspeed(g)) { speed_desc = f->hs_descriptors; @@ -156,7 +166,36 @@ ep_found: /* commit results */ _ep->maxpacket = le16_to_cpu(chosen_desc->wMaxPacketSize); _ep->desc = chosen_desc; + _ep->comp_desc = NULL; + _ep->maxburst = 0; + _ep->mult = 0; + if (!want_comp_desc) + return 0; + /* + * Companion descriptor should follow EP descriptor + * USB 3.0 spec, #9.6.7 + */ + comp_desc = (struct usb_ss_ep_comp_descriptor *)*(++d_spd); + if (!comp_desc || + (comp_desc->bDescriptorType != USB_DT_SS_ENDPOINT_COMP)) + return -EIO; + _ep->comp_desc = comp_desc; + if (g->speed == USB_SPEED_SUPER) { + switch (usb_endpoint_type(_ep->desc)) { + case USB_ENDPOINT_XFER_BULK: + case USB_ENDPOINT_XFER_INT: + _ep->maxburst = comp_desc->bMaxBurst; + break; + case USB_ENDPOINT_XFER_ISOC: + /* mult: bits 1:0 of bmAttributes */ + _ep->mult = comp_desc->bmAttributes & 0x3; + break; + default: + /* Do nothing for control endpoints */ + break; + } + } return 0; } @@ -208,6 +247,8 @@ int usb_add_function(struct usb_configuration *config, config->fullspeed = true; if (!config->highspeed && function->hs_descriptors) config->highspeed = true; + if (!config->superspeed && function->ss_descriptors) + config->superspeed = true; done: if (value) @@ -351,10 +392,17 @@ static int config_buf(struct usb_configuration *config, list_for_each_entry(f, &config->functions, list) { struct usb_descriptor_header **descriptors; - if (speed == USB_SPEED_HIGH) + switch (speed) { + case USB_SPEED_SUPER: + descriptors = f->ss_descriptors; + break; + case USB_SPEED_HIGH: descriptors = f->hs_descriptors; - else + break; + default: descriptors = f->descriptors; + } + if (!descriptors) continue; status = usb_descriptor_fillbuf(next, len, @@ -377,9 +425,10 @@ static int config_desc(struct usb_composite_dev *cdev, unsigned w_value) u8 type = w_value >> 8; enum usb_device_speed speed = USB_SPEED_UNKNOWN; - if (gadget_is_dualspeed(gadget)) { - int hs = 0; - + if (gadget->speed == USB_SPEED_SUPER) + speed = gadget->speed; + else if (gadget_is_dualspeed(gadget)) { + int hs = 0; if (gadget->speed == USB_SPEED_HIGH) hs = 1; if (type == USB_DT_OTHER_SPEED_CONFIG) @@ -393,13 +442,20 @@ static int config_desc(struct usb_composite_dev *cdev, unsigned w_value) w_value &= 0xff; list_for_each_entry(c, &cdev->configs, list) { /* ignore configs that won't work at this speed */ - if (speed == USB_SPEED_HIGH) { + switch (speed) { + case USB_SPEED_SUPER: + if (!c->superspeed) + continue; + break; + case USB_SPEED_HIGH: if (!c->highspeed) continue; - } else { + break; + default: if (!c->fullspeed) continue; } + if (w_value == 0) return config_buf(c, speed, cdev->req->buf, type); w_value--; @@ -413,16 +469,22 @@ static int count_configs(struct usb_composite_dev *cdev, unsigned type) struct usb_configuration *c; unsigned count = 0; int hs = 0; + int ss = 0; if (gadget_is_dualspeed(gadget)) { if (gadget->speed == USB_SPEED_HIGH) hs = 1; + if (gadget->speed == USB_SPEED_SUPER) + ss = 1; if (type == USB_DT_DEVICE_QUALIFIER) hs = !hs; } list_for_each_entry(c, &cdev->configs, list) { /* ignore configs that won't work at this speed */ - if (hs) { + if (ss) { + if (!c->superspeed) + continue; + } else if (hs) { if (!c->highspeed) continue; } else { @@ -434,6 +496,71 @@ static int count_configs(struct usb_composite_dev *cdev, unsigned type) return count; } +/** + * bos_desc() - prepares the BOS descriptor. + * @cdev: pointer to usb_composite device to generate the bos + * descriptor for + * + * This function generates the BOS (Binary Device Object) + * descriptor and its device capabilities descriptors. The BOS + * descriptor should be supported by a SuperSpeed device. + */ +static int bos_desc(struct usb_composite_dev *cdev) +{ + struct usb_ext_cap_descriptor *usb_ext; + struct usb_ss_cap_descriptor *ss_cap; + struct usb_dcd_config_params dcd_config_params; + struct usb_bos_descriptor *bos = cdev->req->buf; + + bos->bLength = USB_DT_BOS_SIZE; + bos->bDescriptorType = USB_DT_BOS; + + bos->wTotalLength = cpu_to_le16(USB_DT_BOS_SIZE); + bos->bNumDeviceCaps = 0; + + /* + * A SuperSpeed device shall include the USB2.0 extension descriptor + * and shall support LPM when operating in USB2.0 HS mode. + */ + usb_ext = cdev->req->buf + le16_to_cpu(bos->wTotalLength); + bos->bNumDeviceCaps++; + le16_add_cpu(&bos->wTotalLength, USB_DT_USB_EXT_CAP_SIZE); + usb_ext->bLength = USB_DT_USB_EXT_CAP_SIZE; + usb_ext->bDescriptorType = USB_DT_DEVICE_CAPABILITY; + usb_ext->bDevCapabilityType = USB_CAP_TYPE_EXT; + usb_ext->bmAttributes = cpu_to_le32(USB_LPM_SUPPORT); + + /* + * The Superspeed USB Capability descriptor shall be implemented by all + * SuperSpeed devices. + */ + ss_cap = cdev->req->buf + le16_to_cpu(bos->wTotalLength); + bos->bNumDeviceCaps++; + le16_add_cpu(&bos->wTotalLength, USB_DT_USB_SS_CAP_SIZE); + ss_cap->bLength = USB_DT_USB_SS_CAP_SIZE; + ss_cap->bDescriptorType = USB_DT_DEVICE_CAPABILITY; + ss_cap->bDevCapabilityType = USB_SS_CAP_TYPE; + ss_cap->bmAttributes = 0; /* LTM is not supported yet */ + ss_cap->wSpeedSupported = cpu_to_le16(USB_LOW_SPEED_OPERATION | + USB_FULL_SPEED_OPERATION | + USB_HIGH_SPEED_OPERATION | + USB_5GBPS_OPERATION); + ss_cap->bFunctionalitySupport = USB_LOW_SPEED_OPERATION; + + /* Get Controller configuration */ + if (cdev->gadget->ops->get_config_params) + cdev->gadget->ops->get_config_params(&dcd_config_params); + else { + dcd_config_params.bU1devExitLat = USB_DEFULT_U1_DEV_EXIT_LAT; + dcd_config_params.bU2DevExitLat = + cpu_to_le16(USB_DEFULT_U2_DEV_EXIT_LAT); + } + ss_cap->bU1devExitLat = dcd_config_params.bU1devExitLat; + ss_cap->bU2DevExitLat = dcd_config_params.bU2DevExitLat; + + return le16_to_cpu(bos->wTotalLength); +} + static void device_qual(struct usb_composite_dev *cdev) { struct usb_qualifier_descriptor *qual = cdev->req->buf; @@ -477,20 +604,27 @@ static int set_config(struct usb_composite_dev *cdev, unsigned power = gadget_is_otg(gadget) ? 8 : 100; int tmp; - if (cdev->config) - reset_config(cdev); - if (number) { list_for_each_entry(c, &cdev->configs, list) { if (c->bConfigurationValue == number) { + /* + * We disable the FDs of the previous + * configuration only if the new configuration + * is a valid one + */ + if (cdev->config) + reset_config(cdev); result = 0; break; } } if (result < 0) goto done; - } else + } else { /* Zero configuration value - need to reset the config */ + if (cdev->config) + reset_config(cdev); result = 0; + } INFO(cdev, "%s speed config #%d: %s\n", ({ char *speed; @@ -504,6 +638,9 @@ static int set_config(struct usb_composite_dev *cdev, case USB_SPEED_HIGH: speed = "high"; break; + case USB_SPEED_SUPER: + speed = "super"; + break; default: speed = "?"; break; @@ -528,10 +665,16 @@ static int set_config(struct usb_composite_dev *cdev, * function's setup callback instead of the current * configuration's setup callback. */ - if (gadget->speed == USB_SPEED_HIGH) + switch (gadget->speed) { + case USB_SPEED_SUPER: + descriptors = f->ss_descriptors; + break; + case USB_SPEED_HIGH: descriptors = f->hs_descriptors; - else + break; + default: descriptors = f->descriptors; + } for (; *descriptors; ++descriptors) { struct usb_endpoint_descriptor *ep; @@ -624,8 +767,9 @@ int usb_add_config(struct usb_composite_dev *cdev, } else { unsigned i; - DBG(cdev, "cfg %d/%p speeds:%s%s\n", + DBG(cdev, "cfg %d/%p speeds:%s%s%s\n", config->bConfigurationValue, config, + config->superspeed ? " super" : "", config->highspeed ? " high" : "", config->fullspeed ? (gadget_is_dualspeed(cdev->gadget) @@ -904,6 +1048,7 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) struct usb_composite_dev *cdev = get_gadget_data(gadget); struct usb_request *req = cdev->req; int value = -EOPNOTSUPP; + int status = 0; u16 w_index = le16_to_cpu(ctrl->wIndex); u8 intf = w_index & 0xFF; u16 w_value = le16_to_cpu(ctrl->wValue); @@ -931,18 +1076,29 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) case USB_DT_DEVICE: cdev->desc.bNumConfigurations = count_configs(cdev, USB_DT_DEVICE); + cdev->desc.bMaxPacketSize0 = + cdev->gadget->ep0->maxpacket; + if (gadget_is_superspeed(gadget)) { + if (gadget->speed >= USB_SPEED_SUPER) + cdev->desc.bcdUSB = cpu_to_le16(0x0300); + else + cdev->desc.bcdUSB = cpu_to_le16(0x0210); + } + value = min(w_length, (u16) sizeof cdev->desc); memcpy(req->buf, &cdev->desc, value); break; case USB_DT_DEVICE_QUALIFIER: - if (!gadget_is_dualspeed(gadget)) + if (!gadget_is_dualspeed(gadget) || + gadget->speed >= USB_SPEED_SUPER) break; device_qual(cdev); value = min_t(int, w_length, sizeof(struct usb_qualifier_descriptor)); break; case USB_DT_OTHER_SPEED_CONFIG: - if (!gadget_is_dualspeed(gadget)) + if (!gadget_is_dualspeed(gadget) || + gadget->speed >= USB_SPEED_SUPER) break; /* FALLTHROUGH */ case USB_DT_CONFIG: @@ -956,6 +1112,12 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) if (value >= 0) value = min(w_length, (u16) value); break; + case USB_DT_BOS: + if (gadget_is_superspeed(gadget)) { + value = bos_desc(cdev); + value = min(w_length, (u16) value); + } + break; } break; @@ -1023,6 +1185,61 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) *((u8 *)req->buf) = value; value = min(w_length, (u16) 1); break; + + /* + * USB 3.0 additions: + * Function driver should handle get_status request. If such cb + * wasn't supplied we respond with default value = 0 + * Note: function driver should supply such cb only for the first + * interface of the function + */ + case USB_REQ_GET_STATUS: + if (!gadget_is_superspeed(gadget)) + goto unknown; + if (ctrl->bRequestType != (USB_DIR_IN | USB_RECIP_INTERFACE)) + goto unknown; + value = 2; /* This is the length of the get_status reply */ + put_unaligned_le16(0, req->buf); + if (!cdev->config || intf >= MAX_CONFIG_INTERFACES) + break; + f = cdev->config->interface[intf]; + if (!f) + break; + status = f->get_status ? f->get_status(f) : 0; + if (status < 0) + break; + put_unaligned_le16(status & 0x0000ffff, req->buf); + break; + /* + * Function drivers should handle SetFeature/ClearFeature + * (FUNCTION_SUSPEND) request. function_suspend cb should be supplied + * only for the first interface of the function + */ + case USB_REQ_CLEAR_FEATURE: + case USB_REQ_SET_FEATURE: + if (!gadget_is_superspeed(gadget)) + goto unknown; + if (ctrl->bRequestType != (USB_DIR_OUT | USB_RECIP_INTERFACE)) + goto unknown; + switch (w_value) { + case USB_INTRF_FUNC_SUSPEND: + if (!cdev->config || intf >= MAX_CONFIG_INTERFACES) + break; + f = cdev->config->interface[intf]; + if (!f) + break; + value = 0; + if (f->func_suspend) + value = f->func_suspend(f, w_index >> 8); + if (value < 0) { + ERROR(cdev, + "func_suspend() returned error %d\n", + value); + value = 0; + } + break; + } + break; default: unknown: VDBG(cdev, @@ -1340,7 +1557,11 @@ composite_resume(struct usb_gadget *gadget) /*-------------------------------------------------------------------------*/ static struct usb_gadget_driver composite_driver = { +#ifdef CONFIG_USB_GADGET_SUPERSPEED + .speed = USB_SPEED_SUPER, +#else .speed = USB_SPEED_HIGH, +#endif .unbind = composite_unbind, diff --git a/drivers/usb/gadget/epautoconf.c b/drivers/usb/gadget/epautoconf.c index 91c032fbdf1..7a7e6b7e1fd 100644 --- a/drivers/usb/gadget/epautoconf.c +++ b/drivers/usb/gadget/epautoconf.c @@ -161,13 +161,13 @@ ep_matches ( max = 0x7ff & le16_to_cpu(desc->wMaxPacketSize); switch (type) { case USB_ENDPOINT_XFER_INT: - /* INT: limit 64 bytes full speed, 1024 high speed */ + /* INT: limit 64 bytes full speed, 1024 high/super speed */ if (!gadget->is_dualspeed && max > 64) return 0; /* FALLTHROUGH */ case USB_ENDPOINT_XFER_ISOC: - /* ISO: limit 1023 bytes full speed, 1024 high speed */ + /* ISO: limit 1023 bytes full speed, 1024 high/super speed */ if (ep->maxpacket < max) return 0; if (!gadget->is_dualspeed && max > 1023) @@ -202,7 +202,7 @@ ep_matches ( } /* report (variable) full speed bulk maxpacket */ - if (USB_ENDPOINT_XFER_BULK == type) { + if ((USB_ENDPOINT_XFER_BULK == type) && !ep_comp) { int size = ep->maxpacket; /* min() doesn't work on bitfields with gcc-3.5 */ diff --git a/include/linux/usb/composite.h b/include/linux/usb/composite.h index a3e72dfa699..a316fba7351 100644 --- a/include/linux/usb/composite.h +++ b/include/linux/usb/composite.h @@ -59,6 +59,10 @@ struct usb_configuration; * @hs_descriptors: Table of high speed descriptors, using interface and * string identifiers assigned during @bind(). If this pointer is null, * the function will not be available at high speed. + * @ss_descriptors: Table of super speed descriptors, using interface and + * string identifiers assigned during @bind(). If this + * pointer is null after initiation, the function will not + * be available at super speed. * @config: assigned when @usb_add_function() is called; this is the * configuration with which this function is associated. * @bind: Before the gadget can register, all of its functions bind() to the @@ -77,6 +81,10 @@ struct usb_configuration; * @setup: Used for interface-specific control requests. * @suspend: Notifies functions when the host stops sending USB traffic. * @resume: Notifies functions when the host restarts USB traffic. + * @get_status: Returns function status as a reply to + * GetStatus() request when the recepient is Interface. + * @func_suspend: callback to be called when + * SetFeature(FUNCTION_SUSPEND) is reseived * * A single USB function uses one or more interfaces, and should in most * cases support operation at both full and high speeds. Each function is @@ -106,6 +114,7 @@ struct usb_function { struct usb_gadget_strings **strings; struct usb_descriptor_header **descriptors; struct usb_descriptor_header **hs_descriptors; + struct usb_descriptor_header **ss_descriptors; struct usb_configuration *config; @@ -132,6 +141,10 @@ struct usb_function { void (*suspend)(struct usb_function *); void (*resume)(struct usb_function *); + /* USB 3.0 additions */ + int (*get_status)(struct usb_function *); + int (*func_suspend)(struct usb_function *, + u8 suspend_opt); /* private: */ /* internals */ struct list_head list; @@ -219,6 +232,7 @@ struct usb_configuration { struct list_head list; struct list_head functions; u8 next_interface_id; + unsigned superspeed:1; unsigned highspeed:1; unsigned fullspeed:1; struct usb_function *interface[MAX_CONFIG_INTERFACES]; diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h index 625971292c2..e22ce7e5a44 100644 --- a/include/linux/usb/gadget.h +++ b/include/linux/usb/gadget.h @@ -136,6 +136,8 @@ struct usb_ep_ops { * the endpoint descriptor used to configure the endpoint. * @max_streams: The maximum number of streams supported * by this EP (0 - 16, actual number is 2^n) + * @mult: multiplier, 'mult' value for SS Isoc EPs + * @maxburst: the maximum number of bursts supported by this EP (for usb3) * @driver_data:for use by the gadget driver. * @address: used to identify the endpoint when finding descriptor that * matches connection speed @@ -156,6 +158,8 @@ struct usb_ep { struct list_head ep_list; unsigned maxpacket:16; unsigned max_streams:16; + unsigned mult:2; + unsigned maxburst:4; u8 address; const struct usb_endpoint_descriptor *desc; const struct usb_ss_ep_comp_descriptor *comp_desc; @@ -426,6 +430,14 @@ static inline void usb_ep_fifo_flush(struct usb_ep *ep) /*-------------------------------------------------------------------------*/ +struct usb_dcd_config_params { + __u8 bU1devExitLat; /* U1 Device exit Latency */ +#define USB_DEFULT_U1_DEV_EXIT_LAT 0x01 /* Less then 1 microsec */ + __le16 bU2DevExitLat; /* U2 Device exit Latency */ +#define USB_DEFULT_U2_DEV_EXIT_LAT 0x1F4 /* Less then 500 microsec */ +}; + + struct usb_gadget; struct usb_gadget_driver; @@ -441,6 +453,7 @@ struct usb_gadget_ops { int (*pullup) (struct usb_gadget *, int is_on); int (*ioctl)(struct usb_gadget *, unsigned code, unsigned long param); + void (*get_config_params)(struct usb_dcd_config_params *); int (*start)(struct usb_gadget_driver *, int (*bind)(struct usb_gadget *)); int (*stop)(struct usb_gadget_driver *); @@ -534,6 +547,24 @@ static inline int gadget_is_dualspeed(struct usb_gadget *g) #endif } +/** + * gadget_is_superspeed() - return true if the hardware handles + * supperspeed + * @g: controller that might support supper speed + */ +static inline int gadget_is_superspeed(struct usb_gadget *g) +{ +#ifdef CONFIG_USB_GADGET_SUPERSPEED + /* + * runtime test would check "g->is_superspeed" ... that might be + * useful to work around hardware bugs, but is mostly pointless + */ + return 1; +#else + return 0; +#endif +} + /** * gadget_is_otg - return true iff the hardware is OTG-ready * @g: controller that might have a Mini-AB connector -- cgit v1.2.3-70-g09d2 From cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32a Mon Sep 17 00:00:00 2001 From: Tatyana Brokhman Date: Wed, 29 Jun 2011 16:41:51 +0300 Subject: usb: gadget: dummy_hcd: use the shared_hcd infrastructure This patch is a preparation for adding SuperSpeed support to dummy hcd. It takes the master side fields out of the struct dummy to a separate structure. The init process was also modified to resemble the way it is done by xHCI. Signed-off-by: Tatyana Brokhman Signed-off-by: Felipe Balbi Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/dummy_hcd.c | 507 ++++++++++++++++++++++------------------- 1 file changed, 270 insertions(+), 237 deletions(-) (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c index cbcb4c7fd26..fcbff1cd180 100644 --- a/drivers/usb/gadget/dummy_hcd.c +++ b/drivers/usb/gadget/dummy_hcd.c @@ -152,6 +152,22 @@ enum dummy_rh_state { DUMMY_RH_RUNNING }; +struct dummy_hcd { + struct dummy *dum; + enum dummy_rh_state rh_state; + struct timer_list timer; + u32 port_status; + u32 old_status; + unsigned long re_timeout; + + struct usb_device *udev; + struct list_head urbp_list; + + unsigned active:1; + unsigned old_active:1; + unsigned resuming:1; +}; + struct dummy { spinlock_t lock; @@ -167,36 +183,26 @@ struct dummy { u16 devstatus; unsigned udc_suspended:1; unsigned pullup:1; - unsigned active:1; - unsigned old_active:1; /* * MASTER/HOST side support */ - enum dummy_rh_state rh_state; - struct timer_list timer; - u32 port_status; - u32 old_status; - unsigned resuming:1; - unsigned long re_timeout; - - struct usb_device *udev; - struct list_head urbp_list; + struct dummy_hcd *hs_hcd; }; -static inline struct dummy *hcd_to_dummy (struct usb_hcd *hcd) +static inline struct dummy_hcd *hcd_to_dummy_hcd(struct usb_hcd *hcd) { - return (struct dummy *) (hcd->hcd_priv); + return (struct dummy_hcd *) (hcd->hcd_priv); } -static inline struct usb_hcd *dummy_to_hcd (struct dummy *dum) +static inline struct usb_hcd *dummy_hcd_to_hcd(struct dummy_hcd *dum) { return container_of((void *) dum, struct usb_hcd, hcd_priv); } -static inline struct device *dummy_dev (struct dummy *dum) +static inline struct device *dummy_dev(struct dummy_hcd *dum) { - return dummy_to_hcd(dum)->self.controller; + return dummy_hcd_to_hcd(dum)->self.controller; } static inline struct device *udc_dev (struct dummy *dum) @@ -209,9 +215,10 @@ static inline struct dummy *ep_to_dummy (struct dummy_ep *ep) return container_of (ep->gadget, struct dummy, gadget); } -static inline struct dummy *gadget_to_dummy (struct usb_gadget *gadget) +static inline struct dummy_hcd *gadget_to_dummy_hcd(struct usb_gadget *gadget) { - return container_of (gadget, struct dummy, gadget); + struct dummy *dum = container_of(gadget, struct dummy, gadget); + return dum->hs_hcd; } static inline struct dummy *gadget_dev_to_dummy (struct device *dev) @@ -219,7 +226,7 @@ static inline struct dummy *gadget_dev_to_dummy (struct device *dev) return container_of (dev, struct dummy, gadget.dev); } -static struct dummy *the_controller; +static struct dummy the_controller; /*-------------------------------------------------------------------------*/ @@ -260,60 +267,64 @@ stop_activity (struct dummy *dum) } /* caller must hold lock */ -static void -set_link_state (struct dummy *dum) +static void set_link_state(struct dummy_hcd *dum_hcd) { - dum->active = 0; - if ((dum->port_status & USB_PORT_STAT_POWER) == 0) - dum->port_status = 0; + struct dummy *dum = dum_hcd->dum; + + dum_hcd->active = 0; + if ((dum_hcd->port_status & USB_PORT_STAT_POWER) == 0) + dum_hcd->port_status = 0; /* UDC suspend must cause a disconnect */ else if (!dum->pullup || dum->udc_suspended) { - dum->port_status &= ~(USB_PORT_STAT_CONNECTION | + dum_hcd->port_status &= ~(USB_PORT_STAT_CONNECTION | USB_PORT_STAT_ENABLE | USB_PORT_STAT_LOW_SPEED | USB_PORT_STAT_HIGH_SPEED | USB_PORT_STAT_SUSPEND); - if ((dum->old_status & USB_PORT_STAT_CONNECTION) != 0) - dum->port_status |= (USB_PORT_STAT_C_CONNECTION << 16); + if ((dum_hcd->old_status & USB_PORT_STAT_CONNECTION) != 0) + dum_hcd->port_status |= + (USB_PORT_STAT_C_CONNECTION << 16); } else { - dum->port_status |= USB_PORT_STAT_CONNECTION; - if ((dum->old_status & USB_PORT_STAT_CONNECTION) == 0) - dum->port_status |= (USB_PORT_STAT_C_CONNECTION << 16); - if ((dum->port_status & USB_PORT_STAT_ENABLE) == 0) - dum->port_status &= ~USB_PORT_STAT_SUSPEND; - else if ((dum->port_status & USB_PORT_STAT_SUSPEND) == 0 && - dum->rh_state != DUMMY_RH_SUSPENDED) - dum->active = 1; + dum_hcd->port_status |= USB_PORT_STAT_CONNECTION; + if ((dum_hcd->old_status & USB_PORT_STAT_CONNECTION) == 0) + dum_hcd->port_status |= + (USB_PORT_STAT_C_CONNECTION << 16); + if ((dum_hcd->port_status & USB_PORT_STAT_ENABLE) == 0) + dum_hcd->port_status &= ~USB_PORT_STAT_SUSPEND; + else if ((dum_hcd->port_status & USB_PORT_STAT_SUSPEND) == 0 && + dum_hcd->rh_state != DUMMY_RH_SUSPENDED) + dum_hcd->active = 1; } - if ((dum->port_status & USB_PORT_STAT_ENABLE) == 0 || dum->active) - dum->resuming = 0; + if ((dum_hcd->port_status & USB_PORT_STAT_ENABLE) == 0 || + dum_hcd->active) + dum_hcd->resuming = 0; - if ((dum->port_status & USB_PORT_STAT_CONNECTION) == 0 || - (dum->port_status & USB_PORT_STAT_RESET) != 0) { - if ((dum->old_status & USB_PORT_STAT_CONNECTION) != 0 && - (dum->old_status & USB_PORT_STAT_RESET) == 0 && + if ((dum_hcd->port_status & USB_PORT_STAT_CONNECTION) == 0 || + (dum_hcd->port_status & USB_PORT_STAT_RESET) != 0) { + if ((dum_hcd->old_status & USB_PORT_STAT_CONNECTION) != 0 && + (dum_hcd->old_status & USB_PORT_STAT_RESET) == 0 && dum->driver) { stop_activity (dum); spin_unlock (&dum->lock); dum->driver->disconnect (&dum->gadget); spin_lock (&dum->lock); } - } else if (dum->active != dum->old_active) { - if (dum->old_active && dum->driver->suspend) { + } else if (dum_hcd->active != dum_hcd->old_active) { + if (dum_hcd->old_active && dum->driver->suspend) { spin_unlock (&dum->lock); dum->driver->suspend (&dum->gadget); spin_lock (&dum->lock); - } else if (!dum->old_active && dum->driver->resume) { + } else if (!dum_hcd->old_active && dum->driver->resume) { spin_unlock (&dum->lock); dum->driver->resume (&dum->gadget); spin_lock (&dum->lock); } } - dum->old_status = dum->port_status; - dum->old_active = dum->active; + dum_hcd->old_status = dum_hcd->port_status; + dum_hcd->old_active = dum_hcd->active; } /*-------------------------------------------------------------------------*/ @@ -332,6 +343,7 @@ static int dummy_enable (struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc) { struct dummy *dum; + struct dummy_hcd *dum_hcd; struct dummy_ep *ep; unsigned max; int retval; @@ -341,9 +353,17 @@ dummy_enable (struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc) || desc->bDescriptorType != USB_DT_ENDPOINT) return -EINVAL; dum = ep_to_dummy (ep); - if (!dum->driver || !is_enabled (dum)) + if (!dum->driver) + return -ESHUTDOWN; + dum_hcd = dum->hs_hcd; + if (!is_enabled(dum_hcd)) return -ESHUTDOWN; - max = le16_to_cpu(desc->wMaxPacketSize) & 0x3ff; + + /* + * For HS/FS devices only bits 0..10 of the wMaxPacketSize represent the + * maximum packet size. + */ + max = le16_to_cpu(desc->wMaxPacketSize) & 0x7ff; /* drivers must not request bad settings, since lower levels * (hardware or its drivers) may not check. some endpoints @@ -515,6 +535,7 @@ dummy_queue (struct usb_ep *_ep, struct usb_request *_req, struct dummy_ep *ep; struct dummy_request *req; struct dummy *dum; + struct dummy_hcd *dum_hcd; unsigned long flags; req = usb_request_to_dummy_request (_req); @@ -526,7 +547,8 @@ dummy_queue (struct usb_ep *_ep, struct usb_request *_req, return -EINVAL; dum = ep_to_dummy (ep); - if (!dum->driver || !is_enabled (dum)) + dum_hcd = dum->hs_hcd; + if (!dum->driver || !is_enabled(dum_hcd)) return -ESHUTDOWN; #if 0 @@ -670,24 +692,24 @@ static int dummy_g_get_frame (struct usb_gadget *_gadget) static int dummy_wakeup (struct usb_gadget *_gadget) { - struct dummy *dum; + struct dummy_hcd *dum_hcd; - dum = gadget_to_dummy (_gadget); - if (!(dum->devstatus & ( (1 << USB_DEVICE_B_HNP_ENABLE) + dum_hcd = gadget_to_dummy_hcd(_gadget); + if (!(dum_hcd->dum->devstatus & ((1 << USB_DEVICE_B_HNP_ENABLE) | (1 << USB_DEVICE_REMOTE_WAKEUP)))) return -EINVAL; - if ((dum->port_status & USB_PORT_STAT_CONNECTION) == 0) + if ((dum_hcd->port_status & USB_PORT_STAT_CONNECTION) == 0) return -ENOLINK; - if ((dum->port_status & USB_PORT_STAT_SUSPEND) == 0 && - dum->rh_state != DUMMY_RH_SUSPENDED) + if ((dum_hcd->port_status & USB_PORT_STAT_SUSPEND) == 0 && + dum_hcd->rh_state != DUMMY_RH_SUSPENDED) return -EIO; /* FIXME: What if the root hub is suspended but the port isn't? */ /* hub notices our request, issues downstream resume, etc */ - dum->resuming = 1; - dum->re_timeout = jiffies + msecs_to_jiffies(20); - mod_timer (&dummy_to_hcd (dum)->rh_timer, dum->re_timeout); + dum_hcd->resuming = 1; + dum_hcd->re_timeout = jiffies + msecs_to_jiffies(20); + mod_timer(&dummy_hcd_to_hcd(dum_hcd)->rh_timer, dum_hcd->re_timeout); return 0; } @@ -695,7 +717,7 @@ static int dummy_set_selfpowered (struct usb_gadget *_gadget, int value) { struct dummy *dum; - dum = gadget_to_dummy (_gadget); + dum = (gadget_to_dummy_hcd(_gadget))->dum; if (value) dum->devstatus |= (1 << USB_DEVICE_SELF_POWERED); else @@ -708,13 +730,12 @@ static int dummy_pullup (struct usb_gadget *_gadget, int value) struct dummy *dum; unsigned long flags; - dum = gadget_to_dummy (_gadget); + dum = gadget_to_dummy_hcd(_gadget)->dum; spin_lock_irqsave (&dum->lock, flags); dum->pullup = (value != 0); - set_link_state (dum); + set_link_state(dum->hs_hcd); spin_unlock_irqrestore (&dum->lock, flags); - - usb_hcd_poll_rh_status (dummy_to_hcd (dum)); + usb_hcd_poll_rh_status(dummy_hcd_to_hcd(dum->hs_hcd)); return 0; } @@ -764,7 +785,7 @@ static DEVICE_ATTR (function, S_IRUGO, show_function, NULL); static int dummy_udc_start(struct usb_gadget_driver *driver, int (*bind)(struct usb_gadget *)) { - struct dummy *dum = the_controller; + struct dummy *dum = &the_controller; int retval, i; if (!dum) @@ -800,7 +821,8 @@ static int dummy_udc_start(struct usb_gadget_driver *driver, } dum->gadget.ep0 = &dum->ep [0].ep; - dum->ep [0].ep.maxpacket = 64; + dum->gadget.speed = min((u8)driver->speed, (u8)USB_SPEED_HIGH) ; + dum->ep[0].ep.maxpacket = 64; list_del_init (&dum->ep [0].ep.ep_list); INIT_LIST_HEAD(&dum->fifo_req.queue); @@ -819,16 +841,18 @@ static int dummy_udc_start(struct usb_gadget_driver *driver, /* khubd will enumerate this in a while */ spin_lock_irq (&dum->lock); dum->pullup = 1; - set_link_state (dum); + dum->gadget.is_otg = + (dummy_hcd_to_hcd(dum->hs_hcd)->self.otg_port != 0); + set_link_state(dum->hs_hcd); spin_unlock_irq (&dum->lock); - usb_hcd_poll_rh_status (dummy_to_hcd (dum)); + usb_hcd_poll_rh_status(dummy_hcd_to_hcd(dum->hs_hcd)); return 0; } static int dummy_udc_stop(struct usb_gadget_driver *driver) { - struct dummy *dum = the_controller; + struct dummy *dum = &the_controller; unsigned long flags; if (!dum) @@ -841,7 +865,7 @@ static int dummy_udc_stop(struct usb_gadget_driver *driver) spin_lock_irqsave (&dum->lock, flags); dum->pullup = 0; - set_link_state (dum); + set_link_state(dum->hs_hcd); spin_unlock_irqrestore (&dum->lock, flags); driver->unbind (&dum->gadget); @@ -850,10 +874,9 @@ static int dummy_udc_stop(struct usb_gadget_driver *driver) spin_lock_irqsave (&dum->lock, flags); dum->pullup = 0; - set_link_state (dum); + set_link_state(dum->hs_hcd); spin_unlock_irqrestore (&dum->lock, flags); - - usb_hcd_poll_rh_status (dummy_to_hcd (dum)); + usb_hcd_poll_rh_status(dummy_hcd_to_hcd(dum->hs_hcd)); return 0; } @@ -874,25 +897,18 @@ EXPORT_SYMBOL (net2280_set_fifo_mode); static void dummy_gadget_release (struct device *dev) { - struct dummy *dum = gadget_dev_to_dummy (dev); - - usb_put_hcd (dummy_to_hcd (dum)); + return; } static int dummy_udc_probe (struct platform_device *pdev) { - struct dummy *dum = the_controller; + struct dummy *dum = &the_controller; int rc; - usb_get_hcd(dummy_to_hcd(dum)); - dum->gadget.name = gadget_name; dum->gadget.ops = &dummy_ops; dum->gadget.is_dualspeed = 1; - /* maybe claim OTG support, though we won't complete HNP */ - dum->gadget.is_otg = (dummy_to_hcd(dum)->self.otg_port != 0); - dev_set_name(&dum->gadget.dev, "gadget"); dum->gadget.dev.parent = &pdev->dev; dum->gadget.dev.release = dummy_gadget_release; @@ -937,10 +953,10 @@ static int dummy_udc_suspend (struct platform_device *pdev, pm_message_t state) dev_dbg (&pdev->dev, "%s\n", __func__); spin_lock_irq (&dum->lock); dum->udc_suspended = 1; - set_link_state (dum); + set_link_state(dum->hs_hcd); spin_unlock_irq (&dum->lock); - usb_hcd_poll_rh_status (dummy_to_hcd (dum)); + usb_hcd_poll_rh_status(dummy_hcd_to_hcd(dum->hs_hcd)); return 0; } @@ -951,10 +967,10 @@ static int dummy_udc_resume (struct platform_device *pdev) dev_dbg (&pdev->dev, "%s\n", __func__); spin_lock_irq (&dum->lock); dum->udc_suspended = 0; - set_link_state (dum); + set_link_state(dum->hs_hcd); spin_unlock_irq (&dum->lock); - usb_hcd_poll_rh_status (dummy_to_hcd (dum)); + usb_hcd_poll_rh_status(dummy_hcd_to_hcd(dum->hs_hcd)); return 0; } @@ -988,7 +1004,7 @@ static int dummy_urb_enqueue ( struct urb *urb, gfp_t mem_flags ) { - struct dummy *dum; + struct dummy_hcd *dum_hcd; struct urbp *urbp; unsigned long flags; int rc; @@ -1001,51 +1017,51 @@ static int dummy_urb_enqueue ( return -ENOMEM; urbp->urb = urb; - dum = hcd_to_dummy (hcd); - spin_lock_irqsave (&dum->lock, flags); + dum_hcd = hcd_to_dummy_hcd(hcd); + spin_lock_irqsave(&dum_hcd->dum->lock, flags); rc = usb_hcd_link_urb_to_ep(hcd, urb); if (rc) { kfree(urbp); goto done; } - if (!dum->udev) { - dum->udev = urb->dev; - usb_get_dev (dum->udev); - } else if (unlikely (dum->udev != urb->dev)) - dev_err (dummy_dev(dum), "usb_device address has changed!\n"); + if (!dum_hcd->udev) { + dum_hcd->udev = urb->dev; + usb_get_dev(dum_hcd->udev); + } else if (unlikely(dum_hcd->udev != urb->dev)) + dev_err(dummy_dev(dum_hcd), "usb_device address has changed!\n"); - list_add_tail (&urbp->urbp_list, &dum->urbp_list); + list_add_tail(&urbp->urbp_list, &dum_hcd->urbp_list); urb->hcpriv = urbp; if (usb_pipetype (urb->pipe) == PIPE_CONTROL) urb->error_count = 1; /* mark as a new urb */ /* kick the scheduler, it'll do the rest */ - if (!timer_pending (&dum->timer)) - mod_timer (&dum->timer, jiffies + 1); + if (!timer_pending(&dum_hcd->timer)) + mod_timer(&dum_hcd->timer, jiffies + 1); done: - spin_unlock_irqrestore(&dum->lock, flags); + spin_unlock_irqrestore(&dum_hcd->dum->lock, flags); return rc; } static int dummy_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) { - struct dummy *dum; + struct dummy_hcd *dum_hcd; unsigned long flags; int rc; /* giveback happens automatically in timer callback, * so make sure the callback happens */ - dum = hcd_to_dummy (hcd); - spin_lock_irqsave (&dum->lock, flags); + dum_hcd = hcd_to_dummy_hcd(hcd); + spin_lock_irqsave(&dum_hcd->dum->lock, flags); rc = usb_hcd_check_unlink_urb(hcd, urb, status); - if (!rc && dum->rh_state != DUMMY_RH_RUNNING && - !list_empty(&dum->urbp_list)) - mod_timer (&dum->timer, jiffies); + if (!rc && dum_hcd->rh_state != DUMMY_RH_RUNNING && + !list_empty(&dum_hcd->urbp_list)) + mod_timer(&dum_hcd->timer, jiffies); - spin_unlock_irqrestore (&dum->lock, flags); + spin_unlock_irqrestore(&dum_hcd->dum->lock, flags); return rc; } @@ -1185,7 +1201,7 @@ static int periodic_bytes (struct dummy *dum, struct dummy_ep *ep) return limit; } -#define is_active(dum) ((dum->port_status & \ +#define is_active(dum_hcd) ((dum_hcd->port_status & \ (USB_PORT_STAT_CONNECTION | USB_PORT_STAT_ENABLE | \ USB_PORT_STAT_SUSPEND)) \ == (USB_PORT_STAT_CONNECTION | USB_PORT_STAT_ENABLE)) @@ -1194,7 +1210,7 @@ static struct dummy_ep *find_endpoint (struct dummy *dum, u8 address) { int i; - if (!is_active (dum)) + if (!is_active(dum->hs_hcd)) return NULL; if ((address & ~USB_DIR_IN) == 0) return &dum->ep [0]; @@ -1231,11 +1247,12 @@ static struct dummy_ep *find_endpoint (struct dummy *dum, u8 address) * 1 - if the request wasn't handles * error code on error */ -static int handle_control_request(struct dummy *dum, struct urb *urb, +static int handle_control_request(struct dummy_hcd *dum_hcd, struct urb *urb, struct usb_ctrlrequest *setup, int *status) { struct dummy_ep *ep2; + struct dummy *dum = dum_hcd->dum; int ret_val = 1; unsigned w_index; unsigned w_value; @@ -1354,9 +1371,10 @@ static int handle_control_request(struct dummy *dum, struct urb *urb, /* drive both sides of the transfers; looks like irq handlers to * both drivers except the callbacks aren't in_irq(). */ -static void dummy_timer (unsigned long _dum) +static void dummy_timer(unsigned long _dum_hcd) { - struct dummy *dum = (struct dummy *) _dum; + struct dummy_hcd *dum_hcd = (struct dummy_hcd *) _dum_hcd; + struct dummy *dum = dum_hcd->dum; struct urbp *urbp, *tmp; unsigned long flags; int limit, total; @@ -1374,7 +1392,7 @@ static void dummy_timer (unsigned long _dum) total = 512/*bytes*/ * 13/*packets*/ * 8/*uframes*/; break; default: - dev_err (dummy_dev(dum), "bogus device speed\n"); + dev_err(dummy_dev(dum_hcd), "bogus device speed\n"); return; } @@ -1383,8 +1401,8 @@ static void dummy_timer (unsigned long _dum) /* look at each urb queued by the host side driver */ spin_lock_irqsave (&dum->lock, flags); - if (!dum->udev) { - dev_err (dummy_dev(dum), + if (!dum_hcd->udev) { + dev_err(dummy_dev(dum_hcd), "timer fired with no URBs pending?\n"); spin_unlock_irqrestore (&dum->lock, flags); return; @@ -1397,7 +1415,7 @@ static void dummy_timer (unsigned long _dum) } restart: - list_for_each_entry_safe (urbp, tmp, &dum->urbp_list, urbp_list) { + list_for_each_entry_safe(urbp, tmp, &dum_hcd->urbp_list, urbp_list) { struct urb *urb; struct dummy_request *req; u8 address; @@ -1408,7 +1426,7 @@ restart: urb = urbp->urb; if (urb->unlinked) goto return_urb; - else if (dum->rh_state != DUMMY_RH_RUNNING) + else if (dum_hcd->rh_state != DUMMY_RH_RUNNING) continue; type = usb_pipetype (urb->pipe); @@ -1426,7 +1444,7 @@ restart: ep = find_endpoint(dum, address); if (!ep) { /* set_configuration() disagreement */ - dev_dbg (dummy_dev(dum), + dev_dbg(dummy_dev(dum_hcd), "no ep configured for urb %p\n", urb); status = -EPROTO; @@ -1442,7 +1460,7 @@ restart: } if (ep->halted && !ep->setup_stage) { /* NOTE: must not be iso! */ - dev_dbg (dummy_dev(dum), "ep %s halted, urb %p\n", + dev_dbg(dummy_dev(dum_hcd), "ep %s halted, urb %p\n", ep->ep.name, urb); status = -EPIPE; goto return_urb; @@ -1477,7 +1495,7 @@ restart: ep->setup_stage = 0; ep->halted = 0; - value = handle_control_request(dum, urb, &setup, + value = handle_control_request(dum_hcd, urb, &setup, &status); /* gadget driver handles all other requests. block @@ -1547,20 +1565,20 @@ return_urb: if (ep) ep->already_seen = ep->setup_stage = 0; - usb_hcd_unlink_urb_from_ep(dummy_to_hcd(dum), urb); + usb_hcd_unlink_urb_from_ep(dummy_hcd_to_hcd(dum_hcd), urb); spin_unlock (&dum->lock); - usb_hcd_giveback_urb(dummy_to_hcd(dum), urb, status); + usb_hcd_giveback_urb(dummy_hcd_to_hcd(dum_hcd), urb, status); spin_lock (&dum->lock); goto restart; } - if (list_empty (&dum->urbp_list)) { - usb_put_dev (dum->udev); - dum->udev = NULL; - } else if (dum->rh_state == DUMMY_RH_RUNNING) { + if (list_empty(&dum_hcd->urbp_list)) { + usb_put_dev(dum_hcd->udev); + dum_hcd->udev = NULL; + } else if (dum_hcd->rh_state == DUMMY_RH_RUNNING) { /* want a 1 msec delay here */ - mod_timer (&dum->timer, jiffies + msecs_to_jiffies(1)); + mod_timer(&dum_hcd->timer, jiffies + msecs_to_jiffies(1)); } spin_unlock_irqrestore (&dum->lock, flags); @@ -1577,32 +1595,32 @@ return_urb: static int dummy_hub_status (struct usb_hcd *hcd, char *buf) { - struct dummy *dum; + struct dummy_hcd *dum_hcd; unsigned long flags; int retval = 0; - dum = hcd_to_dummy (hcd); + dum_hcd = hcd_to_dummy_hcd(hcd); - spin_lock_irqsave (&dum->lock, flags); + spin_lock_irqsave(&dum_hcd->dum->lock, flags); if (!HCD_HW_ACCESSIBLE(hcd)) goto done; - if (dum->resuming && time_after_eq (jiffies, dum->re_timeout)) { - dum->port_status |= (USB_PORT_STAT_C_SUSPEND << 16); - dum->port_status &= ~USB_PORT_STAT_SUSPEND; - set_link_state (dum); + if (dum_hcd->resuming && time_after_eq(jiffies, dum_hcd->re_timeout)) { + dum_hcd->port_status |= (USB_PORT_STAT_C_SUSPEND << 16); + dum_hcd->port_status &= ~USB_PORT_STAT_SUSPEND; + set_link_state(dum_hcd); } - if ((dum->port_status & PORT_C_MASK) != 0) { + if ((dum_hcd->port_status & PORT_C_MASK) != 0) { *buf = (1 << 1); - dev_dbg (dummy_dev(dum), "port status 0x%08x has changes\n", - dum->port_status); + dev_dbg(dummy_dev(dum_hcd), "port status 0x%08x has changes\n", + dum_hcd->port_status); retval = 1; - if (dum->rh_state == DUMMY_RH_SUSPENDED) + if (dum_hcd->rh_state == DUMMY_RH_SUSPENDED) usb_hcd_resume_root_hub (hcd); } done: - spin_unlock_irqrestore (&dum->lock, flags); + spin_unlock_irqrestore(&dum_hcd->dum->lock, flags); return retval; } @@ -1626,39 +1644,40 @@ static int dummy_hub_control ( char *buf, u16 wLength ) { - struct dummy *dum; + struct dummy_hcd *dum_hcd; int retval = 0; unsigned long flags; if (!HCD_HW_ACCESSIBLE(hcd)) return -ETIMEDOUT; - dum = hcd_to_dummy (hcd); - spin_lock_irqsave (&dum->lock, flags); + dum_hcd = hcd_to_dummy_hcd(hcd); + + spin_lock_irqsave(&dum_hcd->dum->lock, flags); switch (typeReq) { case ClearHubFeature: break; case ClearPortFeature: switch (wValue) { case USB_PORT_FEAT_SUSPEND: - if (dum->port_status & USB_PORT_STAT_SUSPEND) { + if (dum_hcd->port_status & USB_PORT_STAT_SUSPEND) { /* 20msec resume signaling */ - dum->resuming = 1; - dum->re_timeout = jiffies + + dum_hcd->resuming = 1; + dum_hcd->re_timeout = jiffies + msecs_to_jiffies(20); } break; case USB_PORT_FEAT_POWER: - if (dum->port_status & USB_PORT_STAT_POWER) - dev_dbg (dummy_dev(dum), "power-off\n"); + if (dum_hcd->port_status & USB_PORT_STAT_POWER) + dev_dbg(dummy_dev(dum_hcd), "power-off\n"); /* FALLS THROUGH */ default: - dum->port_status &= ~(1 << wValue); - set_link_state (dum); + dum_hcd->port_status &= ~(1 << wValue); + set_link_state(dum_hcd); } break; case GetHubDescriptor: - hub_descriptor ((struct usb_hub_descriptor *) buf); + hub_descriptor((struct usb_hub_descriptor *) buf); break; case GetHubStatus: *(__le32 *) buf = cpu_to_le32 (0); @@ -1670,39 +1689,38 @@ static int dummy_hub_control ( /* whoever resets or resumes must GetPortStatus to * complete it!! */ - if (dum->resuming && - time_after_eq (jiffies, dum->re_timeout)) { - dum->port_status |= (USB_PORT_STAT_C_SUSPEND << 16); - dum->port_status &= ~USB_PORT_STAT_SUSPEND; + if (dum_hcd->resuming && + time_after_eq(jiffies, dum_hcd->re_timeout)) { + dum_hcd->port_status |= (USB_PORT_STAT_C_SUSPEND << 16); + dum_hcd->port_status &= ~USB_PORT_STAT_SUSPEND; } - if ((dum->port_status & USB_PORT_STAT_RESET) != 0 && - time_after_eq (jiffies, dum->re_timeout)) { - dum->port_status |= (USB_PORT_STAT_C_RESET << 16); - dum->port_status &= ~USB_PORT_STAT_RESET; - if (dum->pullup) { - dum->port_status |= USB_PORT_STAT_ENABLE; - /* give it the best speed we agree on */ - dum->gadget.speed = dum->driver->speed; - dum->gadget.ep0->maxpacket = 64; - switch (dum->gadget.speed) { + if ((dum_hcd->port_status & USB_PORT_STAT_RESET) != 0 && + time_after_eq(jiffies, dum_hcd->re_timeout)) { + dum_hcd->port_status |= (USB_PORT_STAT_C_RESET << 16); + dum_hcd->port_status &= ~USB_PORT_STAT_RESET; + if (dum_hcd->dum->pullup) { + dum_hcd->port_status |= USB_PORT_STAT_ENABLE; + switch (dum_hcd->dum->gadget.speed) { case USB_SPEED_HIGH: - dum->port_status |= - USB_PORT_STAT_HIGH_SPEED; + dum_hcd->port_status |= + USB_PORT_STAT_HIGH_SPEED; break; case USB_SPEED_LOW: - dum->gadget.ep0->maxpacket = 8; - dum->port_status |= + dum_hcd->dum->gadget.ep0-> + maxpacket = 8; + dum_hcd->port_status |= USB_PORT_STAT_LOW_SPEED; break; default: - dum->gadget.speed = USB_SPEED_FULL; + dum_hcd->dum->gadget.speed = + USB_SPEED_FULL; break; } } } - set_link_state (dum); - ((__le16 *) buf)[0] = cpu_to_le16 (dum->port_status); - ((__le16 *) buf)[1] = cpu_to_le16 (dum->port_status >> 16); + set_link_state(dum_hcd); + ((__le16 *) buf)[0] = cpu_to_le16 (dum_hcd->port_status); + ((__le16 *) buf)[1] = cpu_to_le16 (dum_hcd->port_status >> 16); break; case SetHubFeature: retval = -EPIPE; @@ -1710,87 +1728,91 @@ static int dummy_hub_control ( case SetPortFeature: switch (wValue) { case USB_PORT_FEAT_SUSPEND: - if (dum->active) { - dum->port_status |= USB_PORT_STAT_SUSPEND; + if (dum_hcd->active) { + dum_hcd->port_status |= USB_PORT_STAT_SUSPEND; /* HNP would happen here; for now we * assume b_bus_req is always true. */ - set_link_state (dum); + set_link_state(dum_hcd); if (((1 << USB_DEVICE_B_HNP_ENABLE) - & dum->devstatus) != 0) - dev_dbg (dummy_dev(dum), + & dum_hcd->dum->devstatus) != 0) + dev_dbg(dummy_dev(dum_hcd), "no HNP yet!\n"); } break; case USB_PORT_FEAT_POWER: - dum->port_status |= USB_PORT_STAT_POWER; - set_link_state (dum); + dum_hcd->port_status |= USB_PORT_STAT_POWER; + set_link_state(dum_hcd); break; case USB_PORT_FEAT_RESET: /* if it's already enabled, disable */ - dum->port_status &= ~(USB_PORT_STAT_ENABLE + dum_hcd->port_status &= ~(USB_PORT_STAT_ENABLE | USB_PORT_STAT_LOW_SPEED | USB_PORT_STAT_HIGH_SPEED); - dum->devstatus = 0; - /* 50msec reset signaling */ - dum->re_timeout = jiffies + msecs_to_jiffies(50); + /* + * We want to reset device status. All but the + * Self powered feature + */ + dum_hcd->dum->devstatus &= + (1 << USB_DEVICE_SELF_POWERED); + dum_hcd->re_timeout = jiffies + msecs_to_jiffies(50); /* FALLS THROUGH */ default: - if ((dum->port_status & USB_PORT_STAT_POWER) != 0) { - dum->port_status |= (1 << wValue); - set_link_state (dum); + if ((dum_hcd->port_status & + USB_PORT_STAT_POWER) != 0) { + dum_hcd->port_status |= (1 << wValue); + set_link_state(dum_hcd); } } break; default: - dev_dbg (dummy_dev(dum), + dev_dbg(dummy_dev(dum_hcd), "hub control req%04x v%04x i%04x l%d\n", typeReq, wValue, wIndex, wLength); - /* "protocol stall" on error */ retval = -EPIPE; } - spin_unlock_irqrestore (&dum->lock, flags); + spin_unlock_irqrestore(&dum_hcd->dum->lock, flags); - if ((dum->port_status & PORT_C_MASK) != 0) + if ((dum_hcd->port_status & PORT_C_MASK) != 0) usb_hcd_poll_rh_status (hcd); return retval; } static int dummy_bus_suspend (struct usb_hcd *hcd) { - struct dummy *dum = hcd_to_dummy (hcd); + struct dummy_hcd *dum_hcd = hcd_to_dummy_hcd(hcd); dev_dbg (&hcd->self.root_hub->dev, "%s\n", __func__); - spin_lock_irq (&dum->lock); - dum->rh_state = DUMMY_RH_SUSPENDED; - set_link_state (dum); + spin_lock_irq(&dum_hcd->dum->lock); + dum_hcd->rh_state = DUMMY_RH_SUSPENDED; + set_link_state(dum_hcd); hcd->state = HC_STATE_SUSPENDED; - spin_unlock_irq (&dum->lock); + spin_unlock_irq(&dum_hcd->dum->lock); return 0; } static int dummy_bus_resume (struct usb_hcd *hcd) { - struct dummy *dum = hcd_to_dummy (hcd); + struct dummy_hcd *dum_hcd = hcd_to_dummy_hcd(hcd); int rc = 0; dev_dbg (&hcd->self.root_hub->dev, "%s\n", __func__); - spin_lock_irq (&dum->lock); + spin_lock_irq(&dum_hcd->dum->lock); if (!HCD_HW_ACCESSIBLE(hcd)) { rc = -ESHUTDOWN; } else { - dum->rh_state = DUMMY_RH_RUNNING; - set_link_state (dum); - if (!list_empty(&dum->urbp_list)) - mod_timer (&dum->timer, jiffies); + dum_hcd->rh_state = DUMMY_RH_RUNNING; + set_link_state(dum_hcd); + if (!list_empty(&dum_hcd->urbp_list)) + mod_timer(&dum_hcd->timer, jiffies); hcd->state = HC_STATE_RUNNING; } - spin_unlock_irq (&dum->lock); + spin_unlock_irq(&dum_hcd->dum->lock); return rc; } @@ -1842,43 +1864,41 @@ static ssize_t show_urbs (struct device *dev, struct device_attribute *attr, char *buf) { struct usb_hcd *hcd = dev_get_drvdata (dev); - struct dummy *dum = hcd_to_dummy (hcd); + struct dummy_hcd *dum_hcd = hcd_to_dummy_hcd(hcd); struct urbp *urbp; size_t size = 0; unsigned long flags; - spin_lock_irqsave (&dum->lock, flags); - list_for_each_entry (urbp, &dum->urbp_list, urbp_list) { + spin_lock_irqsave(&dum_hcd->dum->lock, flags); + list_for_each_entry(urbp, &dum_hcd->urbp_list, urbp_list) { size_t temp; temp = show_urb (buf, PAGE_SIZE - size, urbp->urb); buf += temp; size += temp; } - spin_unlock_irqrestore (&dum->lock, flags); + spin_unlock_irqrestore(&dum_hcd->dum->lock, flags); return size; } static DEVICE_ATTR (urbs, S_IRUGO, show_urbs, NULL); -static int dummy_start (struct usb_hcd *hcd) +static int dummy_start(struct usb_hcd *hcd) { - struct dummy *dum; - - dum = hcd_to_dummy (hcd); + struct dummy_hcd *dum_hcd = hcd_to_dummy_hcd(hcd); /* * MASTER side init ... we emulate a root hub that'll only ever * talk to one device (the slave side). Also appears in sysfs, * just like more familiar pci-based HCDs. */ - spin_lock_init (&dum->lock); - init_timer (&dum->timer); - dum->timer.function = dummy_timer; - dum->timer.data = (unsigned long) dum; - dum->rh_state = DUMMY_RH_RUNNING; + spin_lock_init(&dum_hcd->dum->lock); + init_timer(&dum_hcd->timer); + dum_hcd->timer.function = dummy_timer; + dum_hcd->timer.data = (unsigned long)dum_hcd; + dum_hcd->rh_state = DUMMY_RH_RUNNING; - INIT_LIST_HEAD (&dum->urbp_list); + INIT_LIST_HEAD(&dum_hcd->urbp_list); hcd->power_budget = POWER_BUDGET; hcd->state = HC_STATE_RUNNING; @@ -1889,17 +1909,17 @@ static int dummy_start (struct usb_hcd *hcd) #endif /* FIXME 'urbs' should be a per-device thing, maybe in usbcore */ - return device_create_file (dummy_dev(dum), &dev_attr_urbs); + return device_create_file(dummy_dev(dum_hcd), &dev_attr_urbs); } static void dummy_stop (struct usb_hcd *hcd) { struct dummy *dum; - dum = hcd_to_dummy (hcd); - - device_remove_file (dummy_dev(dum), &dev_attr_urbs); - dev_info (dummy_dev(dum), "stopped\n"); + dum = (hcd_to_dummy_hcd(hcd))->dum; + device_remove_file(dummy_dev(hcd_to_dummy_hcd(hcd)), &dev_attr_urbs); + usb_gadget_unregister_driver(dum->driver); + dev_info(dummy_dev(hcd_to_dummy_hcd(hcd)), "stopped\n"); } /*-------------------------------------------------------------------------*/ @@ -1909,13 +1929,26 @@ static int dummy_h_get_frame (struct usb_hcd *hcd) return dummy_g_get_frame (NULL); } +static int dummy_setup(struct usb_hcd *hcd) +{ + if (usb_hcd_is_primary_hcd(hcd)) { + the_controller.hs_hcd = hcd_to_dummy_hcd(hcd); + the_controller.hs_hcd->dum = &the_controller; + /* Mark the first roothub as being USB 2.0. */ + hcd->speed = HCD_USB2; + hcd->self.root_hub->speed = USB_SPEED_HIGH; + } + return 0; +} + static const struct hc_driver dummy_hcd = { .description = (char *) driver_name, .product_desc = "Dummy host controller", - .hcd_priv_size = sizeof(struct dummy), + .hcd_priv_size = sizeof(struct dummy_hcd), .flags = HCD_USB2, + .reset = dummy_setup, .start = dummy_start, .stop = dummy_stop, @@ -1932,47 +1965,47 @@ static const struct hc_driver dummy_hcd = { static int dummy_hcd_probe(struct platform_device *pdev) { - struct usb_hcd *hcd; + struct usb_hcd *hs_hcd; int retval; dev_info(&pdev->dev, "%s, driver " DRIVER_VERSION "\n", driver_desc); - hcd = usb_create_hcd(&dummy_hcd, &pdev->dev, dev_name(&pdev->dev)); - if (!hcd) + hs_hcd = usb_create_hcd(&dummy_hcd, &pdev->dev, dev_name(&pdev->dev)); + if (!hs_hcd) return -ENOMEM; - the_controller = hcd_to_dummy (hcd); - hcd->has_tt = 1; + hs_hcd->has_tt = 1; - retval = usb_add_hcd(hcd, 0, 0); + retval = usb_add_hcd(hs_hcd, 0, 0); if (retval != 0) { - usb_put_hcd (hcd); - the_controller = NULL; + usb_put_hcd(hs_hcd); + the_controller.hs_hcd = NULL; } return retval; } -static int dummy_hcd_remove (struct platform_device *pdev) +static int dummy_hcd_remove(struct platform_device *pdev) { - struct usb_hcd *hcd; + struct dummy *dum; + + dum = (hcd_to_dummy_hcd(platform_get_drvdata(pdev)))->dum; + usb_remove_hcd(dummy_hcd_to_hcd(dum->hs_hcd)); + usb_put_hcd(dummy_hcd_to_hcd(dum->hs_hcd)); + the_controller.hs_hcd = NULL; - hcd = platform_get_drvdata (pdev); - usb_remove_hcd (hcd); - usb_put_hcd (hcd); - the_controller = NULL; return 0; } static int dummy_hcd_suspend (struct platform_device *pdev, pm_message_t state) { struct usb_hcd *hcd; - struct dummy *dum; + struct dummy_hcd *dum_hcd; int rc = 0; dev_dbg (&pdev->dev, "%s\n", __func__); hcd = platform_get_drvdata (pdev); - dum = hcd_to_dummy (hcd); - if (dum->rh_state == DUMMY_RH_RUNNING) { + dum_hcd = hcd_to_dummy_hcd(hcd); + if (dum_hcd->rh_state == DUMMY_RH_RUNNING) { dev_warn(&pdev->dev, "Root hub isn't suspended!\n"); rc = -EBUSY; } else @@ -2032,7 +2065,7 @@ static int __init init (void) retval = platform_device_add(the_hcd_pdev); if (retval < 0) goto err_add_hcd; - if (!the_controller) { + if (!the_controller.hs_hcd) { /* * The hcd was added successfully but its probe function failed * for some reason. -- cgit v1.2.3-70-g09d2 From 1cd8fd2887e162ad3d067150962cc3d32dcf3150 Mon Sep 17 00:00:00 2001 From: Tatyana Brokhman Date: Wed, 29 Jun 2011 16:41:52 +0300 Subject: usb: gadget: dummy_hcd: add SuperSpeed support This patch adds SS support to the dummy hcd module. It may be used to test SS device when no (SS) HW is available. USB 3.0 hub includes 2 hubs - one HS and one SS. This patch adds support for a SS root hub in the dummy_hcd module. A new module parameter was added: is_super_speed. When set to true, a SS root hub will also be registered and the connected device will be enumerated over the SS root hub. The default of this parameter is false. Signed-off-by: Tatyana Brokhman [ balbi@ti.com : slight change to commit log fixed one coding style issue ] Signed-off-by: Felipe Balbi Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/Kconfig | 1 + drivers/usb/gadget/dummy_hcd.c | 564 ++++++++++++++++++++++++++++++++++------- 2 files changed, 477 insertions(+), 88 deletions(-) (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index a23e291f07c..86f64caeafc 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -631,6 +631,7 @@ config USB_GADGET_DUMMY_HCD boolean "Dummy HCD (DEVELOPMENT)" depends on USB=y || (USB=m && USB_GADGET=m) select USB_GADGET_DUALSPEED + select USB_GADGET_SUPERSPEED help This host controller driver emulates USB, looping all data transfer requests back to a USB "gadget driver" in the same host. The host diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c index fcbff1cd180..a4896df3296 100644 --- a/drivers/usb/gadget/dummy_hcd.c +++ b/drivers/usb/gadget/dummy_hcd.c @@ -70,6 +70,15 @@ MODULE_DESCRIPTION (DRIVER_DESC); MODULE_AUTHOR ("David Brownell"); MODULE_LICENSE ("GPL"); +struct dummy_hcd_module_parameters { + bool is_super_speed; +}; + +static struct dummy_hcd_module_parameters mod_data = { + .is_super_speed = false +}; +module_param_named(is_super_speed, mod_data.is_super_speed, bool, S_IRUGO); +MODULE_PARM_DESC(is_super_speed, "true to simulate SuperSpeed connection"); /*-------------------------------------------------------------------------*/ /* gadget side driver data structres */ @@ -188,6 +197,7 @@ struct dummy { * MASTER/HOST side support */ struct dummy_hcd *hs_hcd; + struct dummy_hcd *ss_hcd; }; static inline struct dummy_hcd *hcd_to_dummy_hcd(struct usb_hcd *hcd) @@ -218,7 +228,10 @@ static inline struct dummy *ep_to_dummy (struct dummy_ep *ep) static inline struct dummy_hcd *gadget_to_dummy_hcd(struct usb_gadget *gadget) { struct dummy *dum = container_of(gadget, struct dummy, gadget); - return dum->hs_hcd; + if (dum->gadget.speed == USB_SPEED_SUPER) + return dum->ss_hcd; + else + return dum->hs_hcd; } static inline struct dummy *gadget_dev_to_dummy (struct device *dev) @@ -266,60 +279,117 @@ stop_activity (struct dummy *dum) /* driver now does any non-usb quiescing necessary */ } +/** + * set_link_state_by_speed() - Sets the current state of the link according to + * the hcd speed + * @dum_hcd: pointer to the dummy_hcd structure to update the link state for + * + * This function updates the port_status according to the link state and the + * speed of the hcd. + */ +static void set_link_state_by_speed(struct dummy_hcd *dum_hcd) +{ + struct dummy *dum = dum_hcd->dum; + + if (dummy_hcd_to_hcd(dum_hcd)->speed == HCD_USB3) { + if ((dum_hcd->port_status & USB_SS_PORT_STAT_POWER) == 0) { + dum_hcd->port_status = 0; + } else if (!dum->pullup || dum->udc_suspended) { + /* UDC suspend must cause a disconnect */ + dum_hcd->port_status &= ~(USB_PORT_STAT_CONNECTION | + USB_PORT_STAT_ENABLE); + if ((dum_hcd->old_status & + USB_PORT_STAT_CONNECTION) != 0) + dum_hcd->port_status |= + (USB_PORT_STAT_C_CONNECTION << 16); + } else { + /* device is connected and not suspended */ + dum_hcd->port_status |= (USB_PORT_STAT_CONNECTION | + USB_PORT_STAT_SPEED_5GBPS) ; + if ((dum_hcd->old_status & + USB_PORT_STAT_CONNECTION) == 0) + dum_hcd->port_status |= + (USB_PORT_STAT_C_CONNECTION << 16); + if ((dum_hcd->port_status & + USB_PORT_STAT_ENABLE) == 1 && + (dum_hcd->port_status & + USB_SS_PORT_LS_U0) == 1 && + dum_hcd->rh_state != DUMMY_RH_SUSPENDED) + dum_hcd->active = 1; + } + } else { + if ((dum_hcd->port_status & USB_PORT_STAT_POWER) == 0) { + dum_hcd->port_status = 0; + } else if (!dum->pullup || dum->udc_suspended) { + /* UDC suspend must cause a disconnect */ + dum_hcd->port_status &= ~(USB_PORT_STAT_CONNECTION | + USB_PORT_STAT_ENABLE | + USB_PORT_STAT_LOW_SPEED | + USB_PORT_STAT_HIGH_SPEED | + USB_PORT_STAT_SUSPEND); + if ((dum_hcd->old_status & + USB_PORT_STAT_CONNECTION) != 0) + dum_hcd->port_status |= + (USB_PORT_STAT_C_CONNECTION << 16); + } else { + dum_hcd->port_status |= USB_PORT_STAT_CONNECTION; + if ((dum_hcd->old_status & + USB_PORT_STAT_CONNECTION) == 0) + dum_hcd->port_status |= + (USB_PORT_STAT_C_CONNECTION << 16); + if ((dum_hcd->port_status & USB_PORT_STAT_ENABLE) == 0) + dum_hcd->port_status &= ~USB_PORT_STAT_SUSPEND; + else if ((dum_hcd->port_status & + USB_PORT_STAT_SUSPEND) == 0 && + dum_hcd->rh_state != DUMMY_RH_SUSPENDED) + dum_hcd->active = 1; + } + } +} + /* caller must hold lock */ static void set_link_state(struct dummy_hcd *dum_hcd) { struct dummy *dum = dum_hcd->dum; dum_hcd->active = 0; - if ((dum_hcd->port_status & USB_PORT_STAT_POWER) == 0) - dum_hcd->port_status = 0; - - /* UDC suspend must cause a disconnect */ - else if (!dum->pullup || dum->udc_suspended) { - dum_hcd->port_status &= ~(USB_PORT_STAT_CONNECTION | - USB_PORT_STAT_ENABLE | - USB_PORT_STAT_LOW_SPEED | - USB_PORT_STAT_HIGH_SPEED | - USB_PORT_STAT_SUSPEND); - if ((dum_hcd->old_status & USB_PORT_STAT_CONNECTION) != 0) - dum_hcd->port_status |= - (USB_PORT_STAT_C_CONNECTION << 16); - } else { - dum_hcd->port_status |= USB_PORT_STAT_CONNECTION; - if ((dum_hcd->old_status & USB_PORT_STAT_CONNECTION) == 0) - dum_hcd->port_status |= - (USB_PORT_STAT_C_CONNECTION << 16); - if ((dum_hcd->port_status & USB_PORT_STAT_ENABLE) == 0) - dum_hcd->port_status &= ~USB_PORT_STAT_SUSPEND; - else if ((dum_hcd->port_status & USB_PORT_STAT_SUSPEND) == 0 && - dum_hcd->rh_state != DUMMY_RH_SUSPENDED) - dum_hcd->active = 1; - } + if (dum->pullup) + if ((dummy_hcd_to_hcd(dum_hcd)->speed == HCD_USB3 && + dum->gadget.speed != USB_SPEED_SUPER) || + (dummy_hcd_to_hcd(dum_hcd)->speed != HCD_USB3 && + dum->gadget.speed == USB_SPEED_SUPER)) + return; + + set_link_state_by_speed(dum_hcd); if ((dum_hcd->port_status & USB_PORT_STAT_ENABLE) == 0 || dum_hcd->active) dum_hcd->resuming = 0; + /* if !connected or reset */ if ((dum_hcd->port_status & USB_PORT_STAT_CONNECTION) == 0 || (dum_hcd->port_status & USB_PORT_STAT_RESET) != 0) { + /* + * We're connected and not reset (reset occurred now), + * and driver attached - disconnect! + */ if ((dum_hcd->old_status & USB_PORT_STAT_CONNECTION) != 0 && - (dum_hcd->old_status & USB_PORT_STAT_RESET) == 0 && - dum->driver) { - stop_activity (dum); - spin_unlock (&dum->lock); - dum->driver->disconnect (&dum->gadget); - spin_lock (&dum->lock); + (dum_hcd->old_status & USB_PORT_STAT_RESET) == 0 && + dum->driver) { + stop_activity(dum); + spin_unlock(&dum->lock); + dum->driver->disconnect(&dum->gadget); + spin_lock(&dum->lock); } } else if (dum_hcd->active != dum_hcd->old_active) { if (dum_hcd->old_active && dum->driver->suspend) { - spin_unlock (&dum->lock); - dum->driver->suspend (&dum->gadget); - spin_lock (&dum->lock); - } else if (!dum_hcd->old_active && dum->driver->resume) { - spin_unlock (&dum->lock); - dum->driver->resume (&dum->gadget); - spin_lock (&dum->lock); + spin_unlock(&dum->lock); + dum->driver->suspend(&dum->gadget); + spin_lock(&dum->lock); + } else if (!dum_hcd->old_active && dum->driver->resume) { + spin_unlock(&dum->lock); + dum->driver->resume(&dum->gadget); + spin_lock(&dum->lock); } } @@ -355,13 +425,17 @@ dummy_enable (struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc) dum = ep_to_dummy (ep); if (!dum->driver) return -ESHUTDOWN; - dum_hcd = dum->hs_hcd; + if (dum->gadget.speed == USB_SPEED_SUPER) + dum_hcd = dum->ss_hcd; + else + dum_hcd = dum->hs_hcd; if (!is_enabled(dum_hcd)) return -ESHUTDOWN; /* * For HS/FS devices only bits 0..10 of the wMaxPacketSize represent the * maximum packet size. + * For SS devices the wMaxPacketSize is limited by 1024. */ max = le16_to_cpu(desc->wMaxPacketSize) & 0x7ff; @@ -381,6 +455,10 @@ dummy_enable (struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc) goto done; } switch (dum->gadget.speed) { + case USB_SPEED_SUPER: + if (max == 1024) + break; + goto done; case USB_SPEED_HIGH: if (max == 512) break; @@ -399,6 +477,7 @@ dummy_enable (struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc) goto done; /* real hardware might not handle all packet sizes */ switch (dum->gadget.speed) { + case USB_SPEED_SUPER: case USB_SPEED_HIGH: if (max <= 1024) break; @@ -419,6 +498,7 @@ dummy_enable (struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc) goto done; /* real hardware might not handle all packet sizes */ switch (dum->gadget.speed) { + case USB_SPEED_SUPER: case USB_SPEED_HIGH: if (max <= 1024) break; @@ -547,7 +627,10 @@ dummy_queue (struct usb_ep *_ep, struct usb_request *_req, return -EINVAL; dum = ep_to_dummy (ep); - dum_hcd = dum->hs_hcd; + if (dum->gadget.speed == USB_SPEED_SUPER) + dum_hcd = dum->ss_hcd; + else + dum_hcd = dum->hs_hcd; if (!dum->driver || !is_enabled(dum_hcd)) return -ESHUTDOWN; @@ -733,9 +816,12 @@ static int dummy_pullup (struct usb_gadget *_gadget, int value) dum = gadget_to_dummy_hcd(_gadget)->dum; spin_lock_irqsave (&dum->lock, flags); dum->pullup = (value != 0); - set_link_state(dum->hs_hcd); + set_link_state((dum->gadget.speed == USB_SPEED_SUPER ? + dum->ss_hcd : dum->hs_hcd)); spin_unlock_irqrestore (&dum->lock, flags); - usb_hcd_poll_rh_status(dummy_hcd_to_hcd(dum->hs_hcd)); + usb_hcd_poll_rh_status((dum->gadget.speed == USB_SPEED_SUPER ? + dummy_hcd_to_hcd(dum->ss_hcd) : + dummy_hcd_to_hcd(dum->hs_hcd))); return 0; } @@ -821,8 +907,21 @@ static int dummy_udc_start(struct usb_gadget_driver *driver, } dum->gadget.ep0 = &dum->ep [0].ep; - dum->gadget.speed = min((u8)driver->speed, (u8)USB_SPEED_HIGH) ; - dum->ep[0].ep.maxpacket = 64; + if (mod_data.is_super_speed) + dum->gadget.speed = driver->speed; + else + dum->gadget.speed = min((u8)USB_SPEED_HIGH, (u8)driver->speed); + if (dum->gadget.speed < driver->speed) + dev_dbg(udc_dev(dum), "This device can perform faster if" + " you connect it to a " + "SupeSpeed port...\n"); + + if (dum->gadget.speed == USB_SPEED_SUPER) { + for (i = 0; i < DUMMY_ENDPOINTS; i++) + dum->ep[i].ep.max_streams = 0x10; + dum->ep[0].ep.maxpacket = 9; + } else + dum->ep[0].ep.maxpacket = 64; list_del_init (&dum->ep [0].ep.ep_list); INIT_LIST_HEAD(&dum->fifo_req.queue); @@ -841,12 +940,21 @@ static int dummy_udc_start(struct usb_gadget_driver *driver, /* khubd will enumerate this in a while */ spin_lock_irq (&dum->lock); dum->pullup = 1; - dum->gadget.is_otg = - (dummy_hcd_to_hcd(dum->hs_hcd)->self.otg_port != 0); - set_link_state(dum->hs_hcd); + if (dum->gadget.speed == USB_SPEED_SUPER) { + dum->gadget.is_otg = + (dummy_hcd_to_hcd(dum->ss_hcd)->self.otg_port != 0); + set_link_state(dum->ss_hcd); + } else { + dum->gadget.is_otg = + (dummy_hcd_to_hcd(dum->hs_hcd)->self.otg_port != 0); + set_link_state(dum->hs_hcd); + } + spin_unlock_irq (&dum->lock); - usb_hcd_poll_rh_status(dummy_hcd_to_hcd(dum->hs_hcd)); + usb_hcd_poll_rh_status((dum->gadget.speed == USB_SPEED_SUPER ? + dummy_hcd_to_hcd(dum->ss_hcd) : + dummy_hcd_to_hcd(dum->hs_hcd))); return 0; } @@ -865,18 +973,21 @@ static int dummy_udc_stop(struct usb_gadget_driver *driver) spin_lock_irqsave (&dum->lock, flags); dum->pullup = 0; - set_link_state(dum->hs_hcd); + set_link_state((dum->gadget.speed == USB_SPEED_SUPER ? + dum->ss_hcd : dum->hs_hcd)); spin_unlock_irqrestore (&dum->lock, flags); driver->unbind (&dum->gadget); dum->gadget.dev.driver = NULL; dum->driver = NULL; - spin_lock_irqsave (&dum->lock, flags); dum->pullup = 0; - set_link_state(dum->hs_hcd); + set_link_state((dum->gadget.speed == USB_SPEED_SUPER ? + dum->ss_hcd : dum->hs_hcd)); spin_unlock_irqrestore (&dum->lock, flags); - usb_hcd_poll_rh_status(dummy_hcd_to_hcd(dum->hs_hcd)); + usb_hcd_poll_rh_status((dum->gadget.speed == USB_SPEED_SUPER ? + dummy_hcd_to_hcd(dum->ss_hcd) : + dummy_hcd_to_hcd(dum->hs_hcd))); return 0; } @@ -953,10 +1064,13 @@ static int dummy_udc_suspend (struct platform_device *pdev, pm_message_t state) dev_dbg (&pdev->dev, "%s\n", __func__); spin_lock_irq (&dum->lock); dum->udc_suspended = 1; - set_link_state(dum->hs_hcd); + set_link_state((dum->gadget.speed == USB_SPEED_SUPER ? + dum->ss_hcd : dum->hs_hcd)); spin_unlock_irq (&dum->lock); - usb_hcd_poll_rh_status(dummy_hcd_to_hcd(dum->hs_hcd)); + usb_hcd_poll_rh_status((dum->gadget.speed == USB_SPEED_SUPER ? + dummy_hcd_to_hcd(dum->ss_hcd) : + dummy_hcd_to_hcd(dum->hs_hcd))); return 0; } @@ -967,10 +1081,13 @@ static int dummy_udc_resume (struct platform_device *pdev) dev_dbg (&pdev->dev, "%s\n", __func__); spin_lock_irq (&dum->lock); dum->udc_suspended = 0; - set_link_state(dum->hs_hcd); + set_link_state((dum->gadget.speed == USB_SPEED_SUPER ? + dum->ss_hcd : dum->hs_hcd)); spin_unlock_irq (&dum->lock); - usb_hcd_poll_rh_status(dummy_hcd_to_hcd(dum->hs_hcd)); + usb_hcd_poll_rh_status((dum->gadget.speed == USB_SPEED_SUPER ? + dummy_hcd_to_hcd(dum->ss_hcd) : + dummy_hcd_to_hcd(dum->hs_hcd))); return 0; } @@ -1198,6 +1315,21 @@ static int periodic_bytes (struct dummy *dum, struct dummy_ep *ep) tmp *= 8 /* applies to entire frame */; limit += limit * tmp; } + if (dum->gadget.speed == USB_SPEED_SUPER) { + switch (ep->desc->bmAttributes & 0x03) { + case USB_ENDPOINT_XFER_ISOC: + /* Sec. 4.4.8.2 USB3.0 Spec */ + limit = 3 * 16 * 1024 * 8; + break; + case USB_ENDPOINT_XFER_INT: + /* Sec. 4.4.7.2 USB3.0 Spec */ + limit = 3 * 1024 * 8; + break; + case USB_ENDPOINT_XFER_BULK: + default: + break; + } + } return limit; } @@ -1210,7 +1342,8 @@ static struct dummy_ep *find_endpoint (struct dummy *dum, u8 address) { int i; - if (!is_active(dum->hs_hcd)) + if (!is_active((dum->gadget.speed == USB_SPEED_SUPER ? + dum->ss_hcd : dum->hs_hcd))) return NULL; if ((address & ~USB_DIR_IN) == 0) return &dum->ep [0]; @@ -1284,6 +1417,27 @@ static int handle_control_request(struct dummy_hcd *dum_hcd, struct urb *urb, case USB_DEVICE_A_ALT_HNP_SUPPORT: dum->gadget.a_alt_hnp_support = 1; break; + case USB_DEVICE_U1_ENABLE: + if (dummy_hcd_to_hcd(dum_hcd)->speed == + HCD_USB3) + w_value = USB_DEV_STAT_U1_ENABLED; + else + ret_val = -EOPNOTSUPP; + break; + case USB_DEVICE_U2_ENABLE: + if (dummy_hcd_to_hcd(dum_hcd)->speed == + HCD_USB3) + w_value = USB_DEV_STAT_U2_ENABLED; + else + ret_val = -EOPNOTSUPP; + break; + case USB_DEVICE_LTM_ENABLE: + if (dummy_hcd_to_hcd(dum_hcd)->speed == + HCD_USB3) + w_value = USB_DEV_STAT_LTM_ENABLED; + else + ret_val = -EOPNOTSUPP; + break; default: ret_val = -EOPNOTSUPP; } @@ -1310,6 +1464,27 @@ static int handle_control_request(struct dummy_hcd *dum_hcd, struct urb *urb, case USB_DEVICE_REMOTE_WAKEUP: w_value = USB_DEVICE_REMOTE_WAKEUP; break; + case USB_DEVICE_U1_ENABLE: + if (dummy_hcd_to_hcd(dum_hcd)->speed == + HCD_USB3) + w_value = USB_DEV_STAT_U1_ENABLED; + else + ret_val = -EOPNOTSUPP; + break; + case USB_DEVICE_U2_ENABLE: + if (dummy_hcd_to_hcd(dum_hcd)->speed == + HCD_USB3) + w_value = USB_DEV_STAT_U2_ENABLED; + else + ret_val = -EOPNOTSUPP; + break; + case USB_DEVICE_LTM_ENABLE: + if (dummy_hcd_to_hcd(dum_hcd)->speed == + HCD_USB3) + w_value = USB_DEV_STAT_LTM_ENABLED; + else + ret_val = -EOPNOTSUPP; + break; default: ret_val = -EOPNOTSUPP; break; @@ -1391,6 +1566,10 @@ static void dummy_timer(unsigned long _dum_hcd) case USB_SPEED_HIGH: total = 512/*bytes*/ * 13/*packets*/ * 8/*uframes*/; break; + case USB_SPEED_SUPER: + /* Bus speed is 500000 bytes/ms, so use a little less */ + total = 490000; + break; default: dev_err(dummy_dev(dum_hcd), "bogus device speed\n"); return; @@ -1624,6 +1803,18 @@ done: return retval; } +static inline void +ss_hub_descriptor(struct usb_hub_descriptor *desc) +{ + memset(desc, 0, sizeof *desc); + desc->bDescriptorType = 0x2a; + desc->bDescLength = 12; + desc->wHubCharacteristics = cpu_to_le16(0x0001); + desc->bNbrPorts = 1; + desc->u.ss.bHubHdrDecLat = 0x04; /* Worst case: 0.4 micro sec*/ + desc->u.ss.DeviceRemovable = 0xffff; +} + static inline void hub_descriptor (struct usb_hub_descriptor *desc) { @@ -1660,6 +1851,12 @@ static int dummy_hub_control ( case ClearPortFeature: switch (wValue) { case USB_PORT_FEAT_SUSPEND: + if (hcd->speed == HCD_USB3) { + dev_dbg(dummy_dev(dum_hcd), + "USB_PORT_FEAT_SUSPEND req not " + "supported for USB 3.0 roothub\n"); + goto error; + } if (dum_hcd->port_status & USB_PORT_STAT_SUSPEND) { /* 20msec resume signaling */ dum_hcd->resuming = 1; @@ -1668,8 +1865,15 @@ static int dummy_hub_control ( } break; case USB_PORT_FEAT_POWER: - if (dum_hcd->port_status & USB_PORT_STAT_POWER) - dev_dbg(dummy_dev(dum_hcd), "power-off\n"); + if (hcd->speed == HCD_USB3) { + if (dum_hcd->port_status & USB_PORT_STAT_POWER) + dev_dbg(dummy_dev(dum_hcd), + "power-off\n"); + } else + if (dum_hcd->port_status & + USB_SS_PORT_STAT_POWER) + dev_dbg(dummy_dev(dum_hcd), + "power-off\n"); /* FALLS THROUGH */ default: dum_hcd->port_status &= ~(1 << wValue); @@ -1677,7 +1881,18 @@ static int dummy_hub_control ( } break; case GetHubDescriptor: - hub_descriptor((struct usb_hub_descriptor *) buf); + if (hcd->speed == HCD_USB3 && + (wLength < USB_DT_SS_HUB_SIZE || + wValue != (USB_DT_SS_HUB << 8))) { + dev_dbg(dummy_dev(dum_hcd), + "Wrong hub descriptor type for " + "USB 3.0 roothub.\n"); + goto error; + } + if (hcd->speed == HCD_USB3) + ss_hub_descriptor((struct usb_hub_descriptor *) buf); + else + hub_descriptor((struct usb_hub_descriptor *) buf); break; case GetHubStatus: *(__le32 *) buf = cpu_to_le32 (0); @@ -1700,21 +1915,24 @@ static int dummy_hub_control ( dum_hcd->port_status &= ~USB_PORT_STAT_RESET; if (dum_hcd->dum->pullup) { dum_hcd->port_status |= USB_PORT_STAT_ENABLE; - switch (dum_hcd->dum->gadget.speed) { - case USB_SPEED_HIGH: - dum_hcd->port_status |= - USB_PORT_STAT_HIGH_SPEED; - break; - case USB_SPEED_LOW: - dum_hcd->dum->gadget.ep0-> - maxpacket = 8; - dum_hcd->port_status |= - USB_PORT_STAT_LOW_SPEED; - break; - default: - dum_hcd->dum->gadget.speed = - USB_SPEED_FULL; - break; + + if (hcd->speed < HCD_USB3) { + switch (dum_hcd->dum->gadget.speed) { + case USB_SPEED_HIGH: + dum_hcd->port_status |= + USB_PORT_STAT_HIGH_SPEED; + break; + case USB_SPEED_LOW: + dum_hcd->dum->gadget.ep0-> + maxpacket = 8; + dum_hcd->port_status |= + USB_PORT_STAT_LOW_SPEED; + break; + default: + dum_hcd->dum->gadget.speed = + USB_SPEED_FULL; + break; + } } } } @@ -1727,7 +1945,36 @@ static int dummy_hub_control ( break; case SetPortFeature: switch (wValue) { + case USB_PORT_FEAT_LINK_STATE: + if (hcd->speed != HCD_USB3) { + dev_dbg(dummy_dev(dum_hcd), + "USB_PORT_FEAT_LINK_STATE req not " + "supported for USB 2.0 roothub\n"); + goto error; + } + /* + * Since this is dummy we don't have an actual link so + * there is nothing to do for the SET_LINK_STATE cmd + */ + break; + case USB_PORT_FEAT_U1_TIMEOUT: + case USB_PORT_FEAT_U2_TIMEOUT: + /* TODO: add suspend/resume support! */ + if (hcd->speed != HCD_USB3) { + dev_dbg(dummy_dev(dum_hcd), + "USB_PORT_FEAT_U1/2_TIMEOUT req not " + "supported for USB 2.0 roothub\n"); + goto error; + } + break; case USB_PORT_FEAT_SUSPEND: + /* Applicable only for USB2.0 hub */ + if (hcd->speed == HCD_USB3) { + dev_dbg(dummy_dev(dum_hcd), + "USB_PORT_FEAT_SUSPEND req not " + "supported for USB 3.0 roothub\n"); + goto error; + } if (dum_hcd->active) { dum_hcd->port_status |= USB_PORT_STAT_SUSPEND; @@ -1742,12 +1989,31 @@ static int dummy_hub_control ( } break; case USB_PORT_FEAT_POWER: - dum_hcd->port_status |= USB_PORT_STAT_POWER; + if (hcd->speed == HCD_USB3) + dum_hcd->port_status |= USB_SS_PORT_STAT_POWER; + else + dum_hcd->port_status |= USB_PORT_STAT_POWER; set_link_state(dum_hcd); break; + case USB_PORT_FEAT_BH_PORT_RESET: + /* Applicable only for USB3.0 hub */ + if (hcd->speed != HCD_USB3) { + dev_dbg(dummy_dev(dum_hcd), + "USB_PORT_FEAT_BH_PORT_RESET req not " + "supported for USB 2.0 roothub\n"); + goto error; + } + /* FALLS THROUGH */ case USB_PORT_FEAT_RESET: /* if it's already enabled, disable */ - dum_hcd->port_status &= ~(USB_PORT_STAT_ENABLE + if (hcd->speed == HCD_USB3) { + dum_hcd->port_status = 0; + dum_hcd->port_status = + (USB_SS_PORT_STAT_POWER | + USB_PORT_STAT_CONNECTION | + USB_PORT_STAT_RESET); + } else + dum_hcd->port_status &= ~(USB_PORT_STAT_ENABLE | USB_PORT_STAT_LOW_SPEED | USB_PORT_STAT_HIGH_SPEED); /* @@ -1756,21 +2022,50 @@ static int dummy_hub_control ( */ dum_hcd->dum->devstatus &= (1 << USB_DEVICE_SELF_POWERED); + /* + * FIXME USB3.0: what is the correct reset signaling + * interval? Is it still 50msec as for HS? + */ dum_hcd->re_timeout = jiffies + msecs_to_jiffies(50); /* FALLS THROUGH */ default: - if ((dum_hcd->port_status & - USB_PORT_STAT_POWER) != 0) { - dum_hcd->port_status |= (1 << wValue); - set_link_state(dum_hcd); - } + if (hcd->speed == HCD_USB3) { + if ((dum_hcd->port_status & + USB_SS_PORT_STAT_POWER) != 0) { + dum_hcd->port_status |= (1 << wValue); + set_link_state(dum_hcd); + } + } else + if ((dum_hcd->port_status & + USB_PORT_STAT_POWER) != 0) { + dum_hcd->port_status |= (1 << wValue); + set_link_state(dum_hcd); + } + } + break; + case GetPortErrorCount: + if (hcd->speed != HCD_USB3) { + dev_dbg(dummy_dev(dum_hcd), + "GetPortErrorCount req not " + "supported for USB 2.0 roothub\n"); + goto error; + } + /* We'll always return 0 since this is a dummy hub */ + *(__le32 *) buf = cpu_to_le32(0); + break; + case SetHubDepth: + if (hcd->speed != HCD_USB3) { + dev_dbg(dummy_dev(dum_hcd), + "SetHubDepth req not supported for " + "USB 2.0 roothub\n"); + goto error; } break; - default: dev_dbg(dummy_dev(dum_hcd), "hub control req%04x v%04x i%04x l%d\n", typeReq, wValue, wIndex, wLength); +error: /* "protocol stall" on error */ retval = -EPIPE; } @@ -1837,6 +2132,9 @@ show_urb (char *buf, size_t size, struct urb *urb) case USB_SPEED_HIGH: s = "hs"; break; + case USB_SPEED_SUPER: + s = "ss"; + break; default: s = "?"; break; @@ -1883,6 +2181,25 @@ show_urbs (struct device *dev, struct device_attribute *attr, char *buf) } static DEVICE_ATTR (urbs, S_IRUGO, show_urbs, NULL); +static int dummy_start_ss(struct dummy_hcd *dum_hcd) +{ + init_timer(&dum_hcd->timer); + dum_hcd->timer.function = dummy_timer; + dum_hcd->timer.data = (unsigned long)dum_hcd; + dum_hcd->rh_state = DUMMY_RH_RUNNING; + INIT_LIST_HEAD(&dum_hcd->urbp_list); + dummy_hcd_to_hcd(dum_hcd)->power_budget = POWER_BUDGET; + dummy_hcd_to_hcd(dum_hcd)->state = HC_STATE_RUNNING; + dummy_hcd_to_hcd(dum_hcd)->uses_new_polling = 1; +#ifdef CONFIG_USB_OTG + dummy_hcd_to_hcd(dum_hcd)->self.otg_port = 1; +#endif + return 0; + + /* FIXME 'urbs' should be a per-device thing, maybe in usbcore */ + return device_create_file(dummy_dev(dum_hcd), &dev_attr_urbs); +} + static int dummy_start(struct usb_hcd *hcd) { struct dummy_hcd *dum_hcd = hcd_to_dummy_hcd(hcd); @@ -1892,6 +2209,9 @@ static int dummy_start(struct usb_hcd *hcd) * talk to one device (the slave side). Also appears in sysfs, * just like more familiar pci-based HCDs. */ + if (!usb_hcd_is_primary_hcd(hcd)) + return dummy_start_ss(dum_hcd); + spin_lock_init(&dum_hcd->dum->lock); init_timer(&dum_hcd->timer); dum_hcd->timer.function = dummy_timer; @@ -1934,19 +2254,52 @@ static int dummy_setup(struct usb_hcd *hcd) if (usb_hcd_is_primary_hcd(hcd)) { the_controller.hs_hcd = hcd_to_dummy_hcd(hcd); the_controller.hs_hcd->dum = &the_controller; - /* Mark the first roothub as being USB 2.0. */ + /* + * Mark the first roothub as being USB 2.0. + * The USB 3.0 roothub will be registered later by + * dummy_hcd_probe() + */ hcd->speed = HCD_USB2; hcd->self.root_hub->speed = USB_SPEED_HIGH; + } else { + the_controller.ss_hcd = hcd_to_dummy_hcd(hcd); + the_controller.ss_hcd->dum = &the_controller; + hcd->speed = HCD_USB3; + hcd->self.root_hub->speed = USB_SPEED_SUPER; } return 0; } -static const struct hc_driver dummy_hcd = { +/* Change a group of bulk endpoints to support multiple stream IDs */ +int dummy_alloc_streams(struct usb_hcd *hcd, struct usb_device *udev, + struct usb_host_endpoint **eps, unsigned int num_eps, + unsigned int num_streams, gfp_t mem_flags) +{ + if (hcd->speed != HCD_USB3) + dev_dbg(dummy_dev(hcd_to_dummy_hcd(hcd)), + "%s() - ERROR! Not supported for USB2.0 roothub\n", + __func__); + return 0; +} + +/* Reverts a group of bulk endpoints back to not using stream IDs. */ +int dummy_free_streams(struct usb_hcd *hcd, struct usb_device *udev, + struct usb_host_endpoint **eps, unsigned int num_eps, + gfp_t mem_flags) +{ + if (hcd->speed != HCD_USB3) + dev_dbg(dummy_dev(hcd_to_dummy_hcd(hcd)), + "%s() - ERROR! Not supported for USB2.0 roothub\n", + __func__); + return 0; +} + +static struct hc_driver dummy_hcd = { .description = (char *) driver_name, .product_desc = "Dummy host controller", .hcd_priv_size = sizeof(struct dummy_hcd), - .flags = HCD_USB2, + .flags = HCD_USB3 | HCD_SHARED, .reset = dummy_setup, .start = dummy_start, @@ -1961,15 +2314,21 @@ static const struct hc_driver dummy_hcd = { .hub_control = dummy_hub_control, .bus_suspend = dummy_bus_suspend, .bus_resume = dummy_bus_resume, + + .alloc_streams = dummy_alloc_streams, + .free_streams = dummy_free_streams, }; static int dummy_hcd_probe(struct platform_device *pdev) { struct usb_hcd *hs_hcd; + struct usb_hcd *ss_hcd; int retval; dev_info(&pdev->dev, "%s, driver " DRIVER_VERSION "\n", driver_desc); + if (!mod_data.is_super_speed) + dummy_hcd.flags = HCD_USB2; hs_hcd = usb_create_hcd(&dummy_hcd, &pdev->dev, dev_name(&pdev->dev)); if (!hs_hcd) return -ENOMEM; @@ -1978,8 +2337,28 @@ static int dummy_hcd_probe(struct platform_device *pdev) retval = usb_add_hcd(hs_hcd, 0, 0); if (retval != 0) { usb_put_hcd(hs_hcd); - the_controller.hs_hcd = NULL; + return retval; } + + if (mod_data.is_super_speed) { + ss_hcd = usb_create_shared_hcd(&dummy_hcd, &pdev->dev, + dev_name(&pdev->dev), hs_hcd); + if (!ss_hcd) { + retval = -ENOMEM; + goto dealloc_usb2_hcd; + } + + retval = usb_add_hcd(ss_hcd, 0, 0); + if (retval) + goto put_usb3_hcd; + } + return 0; + +put_usb3_hcd: + usb_put_hcd(ss_hcd); +dealloc_usb2_hcd: + usb_put_hcd(hs_hcd); + the_controller.hs_hcd = the_controller.ss_hcd = NULL; return retval; } @@ -1988,9 +2367,17 @@ static int dummy_hcd_remove(struct platform_device *pdev) struct dummy *dum; dum = (hcd_to_dummy_hcd(platform_get_drvdata(pdev)))->dum; + + if (dum->ss_hcd) { + usb_remove_hcd(dummy_hcd_to_hcd(dum->ss_hcd)); + usb_put_hcd(dummy_hcd_to_hcd(dum->ss_hcd)); + } + usb_remove_hcd(dummy_hcd_to_hcd(dum->hs_hcd)); usb_put_hcd(dummy_hcd_to_hcd(dum->hs_hcd)); + the_controller.hs_hcd = NULL; + the_controller.ss_hcd = NULL; return 0; } @@ -2065,7 +2452,8 @@ static int __init init (void) retval = platform_device_add(the_hcd_pdev); if (retval < 0) goto err_add_hcd; - if (!the_controller.hs_hcd) { + if (!the_controller.hs_hcd || + (!the_controller.ss_hcd && mod_data.is_super_speed)) { /* * The hcd was added successfully but its probe function failed * for some reason. -- cgit v1.2.3-70-g09d2 From 7eca4c5a8b73f22ad16ad6e76b901351732355da Mon Sep 17 00:00:00 2001 From: Tatyana Brokhman Date: Wed, 29 Jun 2011 16:41:53 +0300 Subject: usb: gadget: dummy_hcd: add 'is_high_speed' parameter This patch adds a new module parameter to dummy_hcd called is_high_speed. When set to false the connected device will be forced to operate in full-speed mode. By default, this parameter is set to 'true'. Acked-by: Alan Stern Signed-off-by: Tatyana Brokhman Signed-off-by: Felipe Balbi Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/dummy_hcd.c | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c index a4896df3296..d040dc406b1 100644 --- a/drivers/usb/gadget/dummy_hcd.c +++ b/drivers/usb/gadget/dummy_hcd.c @@ -72,13 +72,17 @@ MODULE_LICENSE ("GPL"); struct dummy_hcd_module_parameters { bool is_super_speed; + bool is_high_speed; }; static struct dummy_hcd_module_parameters mod_data = { - .is_super_speed = false + .is_super_speed = false, + .is_high_speed = true, }; module_param_named(is_super_speed, mod_data.is_super_speed, bool, S_IRUGO); MODULE_PARM_DESC(is_super_speed, "true to simulate SuperSpeed connection"); +module_param_named(is_high_speed, mod_data.is_high_speed, bool, S_IRUGO); +MODULE_PARM_DESC(is_high_speed, "true to simulate HighSpeed connection"); /*-------------------------------------------------------------------------*/ /* gadget side driver data structres */ @@ -909,12 +913,15 @@ static int dummy_udc_start(struct usb_gadget_driver *driver, dum->gadget.ep0 = &dum->ep [0].ep; if (mod_data.is_super_speed) dum->gadget.speed = driver->speed; + else if (mod_data.is_high_speed) + dum->gadget.speed = min_t(u8, USB_SPEED_HIGH, driver->speed); else - dum->gadget.speed = min((u8)USB_SPEED_HIGH, (u8)driver->speed); + dum->gadget.speed = USB_SPEED_FULL; if (dum->gadget.speed < driver->speed) - dev_dbg(udc_dev(dum), "This device can perform faster if" - " you connect it to a " - "SupeSpeed port...\n"); + dev_dbg(udc_dev(dum), "This device can perform faster" + " if you connect it to a %s port...\n", + (driver->speed == USB_SPEED_SUPER ? + "SuperSpeed" : "HighSpeed")); if (dum->gadget.speed == USB_SPEED_SUPER) { for (i = 0; i < DUMMY_ENDPOINTS; i++) @@ -2435,6 +2442,9 @@ static int __init init (void) if (usb_disabled ()) return -ENODEV; + if (!mod_data.is_high_speed && mod_data.is_super_speed) + return -EINVAL; + the_hcd_pdev = platform_device_alloc(driver_name, -1); if (!the_hcd_pdev) return retval; -- cgit v1.2.3-70-g09d2 From e4fe056ed3a350ec569aa25014a0982883bc03c1 Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Wed, 29 Jun 2011 16:41:54 +0300 Subject: usb: gadget: net2272: cleanup pci_register_driver() error path In case pci_register_driver() fails it error will be 0 in case platform_driver_register() was fine. Also without PCI pci_register_driver() evaluates to 1 which is well, special. If platform_driver_register() returns EINVAL or EBUSY we end up with 0. Acked-by: Mike Frysinger Signed-off-by: Sebastian Andrzej Siewior Signed-off-by: Felipe Balbi Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/net2272.c | 31 ++++++++++++++++++++++++++----- 1 file changed, 26 insertions(+), 5 deletions(-) (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/net2272.c b/drivers/usb/gadget/net2272.c index 7f1219e239a..739f564f252 100644 --- a/drivers/usb/gadget/net2272.c +++ b/drivers/usb/gadget/net2272.c @@ -2611,9 +2611,19 @@ static struct pci_driver net2272_pci_driver = { .remove = __devexit_p(net2272_pci_remove), }; +static int net2272_pci_register(void) +{ + return pci_register_driver(&net2272_pci_driver); +} + +static void net2272_pci_unregister(void) +{ + pci_unregister_driver(&net2272_pci_driver); +} + #else -# define pci_register_driver(x) 1 -# define pci_unregister_driver(x) 1 +static inline int net2272_pci_register(void) { return 0; } +static inline void net2272_pci_unregister(void) { } #endif /*---------------------------------------------------------------------------*/ @@ -2713,14 +2723,25 @@ static struct platform_driver net2272_plat_driver = { static int __init net2272_init(void) { - return pci_register_driver(&net2272_pci_driver) & - platform_driver_register(&net2272_plat_driver); + int ret; + + ret = net2272_pci_register(); + if (ret) + return ret; + ret = platform_driver_register(&net2272_plat_driver); + if (ret) + goto err_pci; + return ret; + +err_pci: + net2272_pci_unregister(); + return ret; } module_init(net2272_init); static void __exit net2272_cleanup(void) { - pci_unregister_driver(&net2272_pci_driver); + net2272_pci_unregister(); platform_driver_unregister(&net2272_plat_driver); } module_exit(net2272_cleanup); -- cgit v1.2.3-70-g09d2 From 86081d7be34e0f80dc5c46391ec927fc4f350462 Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Wed, 29 Jun 2011 16:41:55 +0300 Subject: usb: gadget: add platform module alias where it is missing Without it udev won't be able to load the driver once it notices the device unbound. Signed-off-by: Sebastian Andrzej Siewior Signed-off-by: Felipe Balbi Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/ci13xxx_msm.c | 1 + drivers/usb/gadget/mv_udc_core.c | 2 +- drivers/usb/gadget/net2272.c | 1 + drivers/usb/gadget/r8a66597-udc.c | 1 + drivers/usb/gadget/s3c-hsudc.c | 1 + 5 files changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/ci13xxx_msm.c b/drivers/usb/gadget/ci13xxx_msm.c index 139ac941959..470981ad6f7 100644 --- a/drivers/usb/gadget/ci13xxx_msm.c +++ b/drivers/usb/gadget/ci13xxx_msm.c @@ -126,6 +126,7 @@ static struct platform_driver ci13xxx_msm_driver = { .probe = ci13xxx_msm_probe, .driver = { .name = "msm_hsusb", }, }; +MODULE_ALIAS("platform:msm_hsusb"); static int __init ci13xxx_msm_init(void) { diff --git a/drivers/usb/gadget/mv_udc_core.c b/drivers/usb/gadget/mv_udc_core.c index 6adf38c5353..ce1ac2bcb31 100644 --- a/drivers/usb/gadget/mv_udc_core.c +++ b/drivers/usb/gadget/mv_udc_core.c @@ -2131,7 +2131,7 @@ static struct platform_driver udc_driver = { #endif }, }; - +MODULE_ALIAS("platform:pxa-u2o"); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_AUTHOR("Chao Xie "); diff --git a/drivers/usb/gadget/net2272.c b/drivers/usb/gadget/net2272.c index 739f564f252..6065bdfd83b 100644 --- a/drivers/usb/gadget/net2272.c +++ b/drivers/usb/gadget/net2272.c @@ -2720,6 +2720,7 @@ static struct platform_driver net2272_plat_driver = { }, /* FIXME .suspend, .resume */ }; +MODULE_ALIAS("platform:net2272"); static int __init net2272_init(void) { diff --git a/drivers/usb/gadget/r8a66597-udc.c b/drivers/usb/gadget/r8a66597-udc.c index 51b655f3b47..db7a6de8583 100644 --- a/drivers/usb/gadget/r8a66597-udc.c +++ b/drivers/usb/gadget/r8a66597-udc.c @@ -1686,6 +1686,7 @@ static struct platform_driver r8a66597_driver = { .name = (char *) udc_name, }, }; +MODULE_ALIAS("platform:r8a66597_udc"); static int __init r8a66597_udc_init(void) { diff --git a/drivers/usb/gadget/s3c-hsudc.c b/drivers/usb/gadget/s3c-hsudc.c index dc9f42823a4..3fa717c5f4b 100644 --- a/drivers/usb/gadget/s3c-hsudc.c +++ b/drivers/usb/gadget/s3c-hsudc.c @@ -1341,6 +1341,7 @@ static struct platform_driver s3c_hsudc_driver = { }, .probe = s3c_hsudc_probe, }; +MODULE_ALIAS("platform:s3c-hsudc"); static int __init s3c_hsudc_modinit(void) { -- cgit v1.2.3-70-g09d2 From 513385a3cf97e9fb7e982afffeb013a12a7ccbd2 Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Wed, 29 Jun 2011 16:41:56 +0300 Subject: usb: gadget: s3c2410_udc: use platform ids instead This also fixes the error path: If the second device fails to register we never remove the first one. This is compile-tested only. I don't see any difference between those two. Maybe we should just use one name instead? Cc: Ben Dooks Cc: Kukjin Kim Signed-off-by: Sebastian Andrzej Siewior Signed-off-by: Felipe Balbi Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/s3c2410_udc.c | 29 +++++++++-------------------- 1 file changed, 9 insertions(+), 20 deletions(-) (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/s3c2410_udc.c b/drivers/usb/gadget/s3c2410_udc.c index 1c19cd3f6a5..394c1a3bbe8 100644 --- a/drivers/usb/gadget/s3c2410_udc.c +++ b/drivers/usb/gadget/s3c2410_udc.c @@ -2057,26 +2057,22 @@ static int s3c2410_udc_resume(struct platform_device *pdev) #define s3c2410_udc_resume NULL #endif -static struct platform_driver udc_driver_2410 = { - .driver = { - .name = "s3c2410-usbgadget", - .owner = THIS_MODULE, - }, - .probe = s3c2410_udc_probe, - .remove = s3c2410_udc_remove, - .suspend = s3c2410_udc_suspend, - .resume = s3c2410_udc_resume, +static const struct platform_device_id s3c_udc_ids[] = { + { "s3c2410-usbgadget", }, + { "s3c2440-usbgadget", }, }; +MODULE_DEVICE_TABLE(platform, s3c_udc_ids); -static struct platform_driver udc_driver_2440 = { +static struct platform_driver udc_driver_24x0 = { .driver = { - .name = "s3c2440-usbgadget", + .name = "s3c24x0-usbgadget", .owner = THIS_MODULE, }, .probe = s3c2410_udc_probe, .remove = s3c2410_udc_remove, .suspend = s3c2410_udc_suspend, .resume = s3c2410_udc_resume, + .id_table = s3c_udc_ids, }; static int __init udc_init(void) @@ -2092,11 +2088,7 @@ static int __init udc_init(void) s3c2410_udc_debugfs_root = NULL; } - retval = platform_driver_register(&udc_driver_2410); - if (retval) - goto err; - - retval = platform_driver_register(&udc_driver_2440); + retval = platform_driver_register(&udc_driver_24x0); if (retval) goto err; @@ -2109,8 +2101,7 @@ err: static void __exit udc_exit(void) { - platform_driver_unregister(&udc_driver_2410); - platform_driver_unregister(&udc_driver_2440); + platform_driver_unregister(&udc_driver_24x0); debugfs_remove(s3c2410_udc_debugfs_root); } @@ -2121,5 +2112,3 @@ MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_VERSION(DRIVER_VERSION); MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:s3c2410-usbgadget"); -MODULE_ALIAS("platform:s3c2440-usbgadget"); -- cgit v1.2.3-70-g09d2 From 877c1f5408a94cd8a0fa1de4e4806830c1839e8d Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Wed, 29 Jun 2011 16:41:57 +0300 Subject: usb: gadget: ci13xx_udc: fix usb_ep_enable() call commit 72c973d (usb: gadget: add usb_endpoint_descriptor to struct usb_ep) has introduced a compile error to ci13xxx_udc. Fix it. Signed-off-by: Felipe Balbi Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/ci13xxx_udc.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/ci13xxx_udc.c b/drivers/usb/gadget/ci13xxx_udc.c index 909bc45c0be..082471650fb 100644 --- a/drivers/usb/gadget/ci13xxx_udc.c +++ b/drivers/usb/gadget/ci13xxx_udc.c @@ -2620,10 +2620,13 @@ static int ci13xxx_start(struct usb_gadget_driver *driver, if (retval) goto done; spin_unlock_irqrestore(udc->lock, flags); - retval = usb_ep_enable(&udc->ep0out.ep, &ctrl_endpt_out_desc); + udc->ep0out.ep.desc = &ctrl_endpt_out_desc; + retval = usb_ep_enable(&udc->ep0out.ep); if (retval) return retval; - retval = usb_ep_enable(&udc->ep0in.ep, &ctrl_endpt_in_desc); + + udc->ep0in.ep.desc = &ctrl_endpt_in_desc; + retval = usb_ep_enable(&udc->ep0in.ep); if (retval) return retval; spin_lock_irqsave(udc->lock, flags); -- cgit v1.2.3-70-g09d2 From 199e7edbb1b32d237ade354fee24eef5e2cbeb18 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Mon, 13 Jun 2011 18:43:59 +0300 Subject: usb: gadget: chips: remove ifdef trickery the gadget controller number is only used during bind() to update descriptors and/or check that a particular controller can support a particular gadget driver. Because of that, we can remove the ifdef trickery as it's a rather small optimization anyway. While at that, also sort the entries alphabetically and add a comment stating we want to keep the list ordered alphabetically. Signed-off-by: Felipe Balbi Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/gadget_chips.h | 182 +++++++------------------------------- 1 file changed, 33 insertions(+), 149 deletions(-) (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/gadget_chips.h b/drivers/usb/gadget/gadget_chips.h index 13c2f9e9440..f3a83cd0ef5 100644 --- a/drivers/usb/gadget/gadget_chips.h +++ b/drivers/usb/gadget/gadget_chips.h @@ -15,156 +15,40 @@ #ifndef __GADGET_CHIPS_H #define __GADGET_CHIPS_H -#ifdef CONFIG_USB_GADGET_NET2272 -#define gadget_is_net2272(g) !strcmp("net2272", (g)->name) -#else -#define gadget_is_net2272(g) 0 -#endif - -#ifdef CONFIG_USB_GADGET_NET2280 -#define gadget_is_net2280(g) !strcmp("net2280", (g)->name) -#else -#define gadget_is_net2280(g) 0 -#endif - -#ifdef CONFIG_USB_GADGET_AMD5536UDC -#define gadget_is_amd5536udc(g) !strcmp("amd5536udc", (g)->name) -#else -#define gadget_is_amd5536udc(g) 0 -#endif - -#ifdef CONFIG_USB_GADGET_DUMMY_HCD -#define gadget_is_dummy(g) !strcmp("dummy_udc", (g)->name) -#else -#define gadget_is_dummy(g) 0 -#endif - -#ifdef CONFIG_USB_GADGET_PXA25X -#define gadget_is_pxa(g) !strcmp("pxa25x_udc", (g)->name) -#else -#define gadget_is_pxa(g) 0 -#endif - -#ifdef CONFIG_USB_GADGET_GOKU -#define gadget_is_goku(g) !strcmp("goku_udc", (g)->name) -#else -#define gadget_is_goku(g) 0 -#endif - -#ifdef CONFIG_USB_GADGET_OMAP -#define gadget_is_omap(g) !strcmp("omap_udc", (g)->name) -#else -#define gadget_is_omap(g) 0 -#endif - -/* various unstable versions available */ -#ifdef CONFIG_USB_GADGET_PXA27X -#define gadget_is_pxa27x(g) !strcmp("pxa27x_udc", (g)->name) -#else -#define gadget_is_pxa27x(g) 0 -#endif - -#ifdef CONFIG_USB_GADGET_ATMEL_USBA -#define gadget_is_atmel_usba(g) !strcmp("atmel_usba_udc", (g)->name) -#else -#define gadget_is_atmel_usba(g) 0 -#endif - -#ifdef CONFIG_USB_GADGET_S3C2410 -#define gadget_is_s3c2410(g) !strcmp("s3c2410_udc", (g)->name) -#else -#define gadget_is_s3c2410(g) 0 -#endif - -#ifdef CONFIG_USB_GADGET_AT91 -#define gadget_is_at91(g) !strcmp("at91_udc", (g)->name) -#else -#define gadget_is_at91(g) 0 -#endif - -#ifdef CONFIG_USB_GADGET_IMX -#define gadget_is_imx(g) !strcmp("imx_udc", (g)->name) -#else -#define gadget_is_imx(g) 0 -#endif - -#ifdef CONFIG_USB_GADGET_FSL_USB2 -#define gadget_is_fsl_usb2(g) !strcmp("fsl-usb2-udc", (g)->name) -#else -#define gadget_is_fsl_usb2(g) 0 -#endif - -/* Mentor high speed "dual role" controller, in peripheral role */ -#ifdef CONFIG_USB_GADGET_MUSB_HDRC -#define gadget_is_musbhdrc(g) !strcmp("musb-hdrc", (g)->name) -#else -#define gadget_is_musbhdrc(g) 0 -#endif - -#ifdef CONFIG_USB_GADGET_LANGWELL -#define gadget_is_langwell(g) (!strcmp("langwell_udc", (g)->name)) -#else -#define gadget_is_langwell(g) 0 -#endif - -#ifdef CONFIG_USB_GADGET_M66592 -#define gadget_is_m66592(g) !strcmp("m66592_udc", (g)->name) -#else -#define gadget_is_m66592(g) 0 -#endif - -/* Freescale CPM/QE UDC SUPPORT */ -#ifdef CONFIG_USB_GADGET_FSL_QE -#define gadget_is_fsl_qe(g) !strcmp("fsl_qe_udc", (g)->name) -#else -#define gadget_is_fsl_qe(g) 0 -#endif - -#ifdef CONFIG_USB_GADGET_CI13XXX_PCI -#define gadget_is_ci13xxx_pci(g) (!strcmp("ci13xxx_pci", (g)->name)) -#else -#define gadget_is_ci13xxx_pci(g) 0 -#endif - -// CONFIG_USB_GADGET_SX2 -// CONFIG_USB_GADGET_AU1X00 -// ... - -#ifdef CONFIG_USB_GADGET_R8A66597 -#define gadget_is_r8a66597(g) !strcmp("r8a66597_udc", (g)->name) -#else -#define gadget_is_r8a66597(g) 0 -#endif - -#ifdef CONFIG_USB_S3C_HSOTG -#define gadget_is_s3c_hsotg(g) (!strcmp("s3c-hsotg", (g)->name)) -#else -#define gadget_is_s3c_hsotg(g) 0 -#endif - -#ifdef CONFIG_USB_S3C_HSUDC -#define gadget_is_s3c_hsudc(g) (!strcmp("s3c-hsudc", (g)->name)) -#else -#define gadget_is_s3c_hsudc(g) 0 -#endif - -#ifdef CONFIG_USB_GADGET_EG20T -#define gadget_is_pch(g) (!strcmp("pch_udc", (g)->name)) -#else -#define gadget_is_pch(g) 0 -#endif - -#ifdef CONFIG_USB_GADGET_CI13XXX_MSM +/* + * NOTICE: the entries below are alphabetical and should be kept + * that way. + * + * Always be sure to add new entries to the correct position or + * accept the bashing later. + * + * If you have forgotten the alphabetical order let VIM/EMACS + * do that for you. + */ +#define gadget_is_amd5536udc(g) (!strcmp("amd5536udc", (g)->name)) +#define gadget_is_at91(g) (!strcmp("at91_udc", (g)->name)) +#define gadget_is_atmel_usba(g) (!strcmp("atmel_usba_udc", (g)->name)) #define gadget_is_ci13xxx_msm(g) (!strcmp("ci13xxx_msm", (g)->name)) -#else -#define gadget_is_ci13xxx_msm(g) 0 -#endif - -#ifdef CONFIG_USB_GADGET_RENESAS_USBHS -#define gadget_is_renesas_usbhs(g) (!strcmp("renesas_usbhs_udc", (g)->name)) -#else -#define gadget_is_renesas_usbhs(g) 0 -#endif +#define gadget_is_ci13xxx_pci(g) (!strcmp("ci13xxx_pci", (g)->name)) +#define gadget_is_dummy(g) (!strcmp("dummy_udc", (g)->name)) +#define gadget_is_fsl_qe(g) (!strcmp("fsl_qe_udc", (g)->name)) +#define gadget_is_fsl_usb2(g) (!strcmp("fsl-usb2-udc", (g)->name)) +#define gadget_is_goku(g) (!strcmp("goku_udc", (g)->name)) +#define gadget_is_imx(g) (!strcmp("imx_udc", (g)->name)) +#define gadget_is_langwell(g) (!strcmp("langwell_udc", (g)->name)) +#define gadget_is_m66592(g) (!strcmp("m66592_udc", (g)->name)) +#define gadget_is_musbhdrc(g) (!strcmp("musb-hdrc", (g)->name)) +#define gadget_is_net2272(g) (!strcmp("net2272", (g)->name)) +#define gadget_is_net2280(g) (!strcmp("net2280", (g)->name)) +#define gadget_is_omap(g) (!strcmp("omap_udc", (g)->name)) +#define gadget_is_pch(g) (!strcmp("pch_udc", (g)->name)) +#define gadget_is_pxa(g) (!strcmp("pxa25x_udc", (g)->name)) +#define gadget_is_pxa27x(g) (!strcmp("pxa27x_udc", (g)->name)) +#define gadget_is_r8a66597(g) (!strcmp("r8a66597_udc", (g)->name)) +#define gadget_is_renesas_usbhs(g) (!strcmp("renesas_usbhs_udc", (g)->name)) +#define gadget_is_s3c2410(g) (!strcmp("s3c2410_udc", (g)->name)) +#define gadget_is_s3c_hsotg(g) (!strcmp("s3c-hsotg", (g)->name)) +#define gadget_is_s3c_hsudc(g) (!strcmp("s3c-hsudc", (g)->name)) /** * usb_gadget_controller_number - support bcdDevice id convention -- cgit v1.2.3-70-g09d2 From 2542787430fc46b4e07e0da4c6ec80ed230032e5 Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Thu, 16 Jun 2011 20:36:55 +0200 Subject: usb: gadget: dummy_hcd: use dummy_pullup() instead of open coding The removed code does the same thing as dummy_pullup(). The only difference is that in dummy_udc_stop() the first dummy_pullup() did not call usb_hcd_poll_rh_status(). Signed-off-by: Sebastian Andrzej Siewior Signed-off-by: Felipe Balbi Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/dummy_hcd.c | 34 +++++++--------------------------- 1 file changed, 7 insertions(+), 27 deletions(-) (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c index d040dc406b1..cecc25ad458 100644 --- a/drivers/usb/gadget/dummy_hcd.c +++ b/drivers/usb/gadget/dummy_hcd.c @@ -944,31 +944,21 @@ static int dummy_udc_start(struct usb_gadget_driver *driver, return retval; } - /* khubd will enumerate this in a while */ - spin_lock_irq (&dum->lock); - dum->pullup = 1; - if (dum->gadget.speed == USB_SPEED_SUPER) { + if (dum->gadget.speed == USB_SPEED_SUPER) dum->gadget.is_otg = (dummy_hcd_to_hcd(dum->ss_hcd)->self.otg_port != 0); - set_link_state(dum->ss_hcd); - } else { + else dum->gadget.is_otg = (dummy_hcd_to_hcd(dum->hs_hcd)->self.otg_port != 0); - set_link_state(dum->hs_hcd); - } - spin_unlock_irq (&dum->lock); - - usb_hcd_poll_rh_status((dum->gadget.speed == USB_SPEED_SUPER ? - dummy_hcd_to_hcd(dum->ss_hcd) : - dummy_hcd_to_hcd(dum->hs_hcd))); + /* khubd will enumerate this in a while */ + dummy_pullup(&dum->gadget, 1); return 0; } static int dummy_udc_stop(struct usb_gadget_driver *driver) { struct dummy *dum = &the_controller; - unsigned long flags; if (!dum) return -ENODEV; @@ -978,23 +968,13 @@ static int dummy_udc_stop(struct usb_gadget_driver *driver) dev_dbg (udc_dev(dum), "unregister gadget driver '%s'\n", driver->driver.name); - spin_lock_irqsave (&dum->lock, flags); - dum->pullup = 0; - set_link_state((dum->gadget.speed == USB_SPEED_SUPER ? - dum->ss_hcd : dum->hs_hcd)); - spin_unlock_irqrestore (&dum->lock, flags); + dummy_pullup(&dum->gadget, 0); driver->unbind (&dum->gadget); dum->gadget.dev.driver = NULL; dum->driver = NULL; - spin_lock_irqsave (&dum->lock, flags); - dum->pullup = 0; - set_link_state((dum->gadget.speed == USB_SPEED_SUPER ? - dum->ss_hcd : dum->hs_hcd)); - spin_unlock_irqrestore (&dum->lock, flags); - usb_hcd_poll_rh_status((dum->gadget.speed == USB_SPEED_SUPER ? - dummy_hcd_to_hcd(dum->ss_hcd) : - dummy_hcd_to_hcd(dum->hs_hcd))); + + dummy_pullup(&dum->gadget, 0); return 0; } -- cgit v1.2.3-70-g09d2 From 99fd14080e7f0a65b87830bf5062b09f6e80dd13 Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Thu, 16 Jun 2011 20:36:56 +0200 Subject: usb: gadget: dummy_hcd: set gadget.is_otg before calling bind() Before commit 53832daea ("usb: gadget: dummy_hcd: use the shared_hcd infrastructure") the is_otg field was set in dummy_udc_probe(). It seems to me that this field is used in gadget's bind function. Therefore I'm moving it before the bind() callback is called. Cc: Tatyana Brokhman Signed-off-by: Felipe Balbi Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/dummy_hcd.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c index cecc25ad458..834fb923a06 100644 --- a/drivers/usb/gadget/dummy_hcd.c +++ b/drivers/usb/gadget/dummy_hcd.c @@ -929,6 +929,14 @@ static int dummy_udc_start(struct usb_gadget_driver *driver, dum->ep[0].ep.maxpacket = 9; } else dum->ep[0].ep.maxpacket = 64; + + if (dum->gadget.speed == USB_SPEED_SUPER) + dum->gadget.is_otg = + (dummy_hcd_to_hcd(dum->ss_hcd)->self.otg_port != 0); + else + dum->gadget.is_otg = + (dummy_hcd_to_hcd(dum->hs_hcd)->self.otg_port != 0); + list_del_init (&dum->ep [0].ep.ep_list); INIT_LIST_HEAD(&dum->fifo_req.queue); @@ -944,13 +952,6 @@ static int dummy_udc_start(struct usb_gadget_driver *driver, return retval; } - if (dum->gadget.speed == USB_SPEED_SUPER) - dum->gadget.is_otg = - (dummy_hcd_to_hcd(dum->ss_hcd)->self.otg_port != 0); - else - dum->gadget.is_otg = - (dummy_hcd_to_hcd(dum->hs_hcd)->self.otg_port != 0); - /* khubd will enumerate this in a while */ dummy_pullup(&dum->gadget, 1); return 0; -- cgit v1.2.3-70-g09d2 From 719e52cbc7b826fae9501f3b86b8cbc25a4c5268 Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Thu, 16 Jun 2011 20:36:57 +0200 Subject: usb: gadget: dummy_hcd: use gadget_to_dummy_hcd() where possible gadget_to_dummy_hcd() already does the speed check, so it's unnecessary to unroll that all the time. Signed-off-by: Sebastian Andrzej Siewior Signed-off-by: Felipe Balbi Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/dummy_hcd.c | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c index 834fb923a06..1fc80bb8ca3 100644 --- a/drivers/usb/gadget/dummy_hcd.c +++ b/drivers/usb/gadget/dummy_hcd.c @@ -429,10 +429,8 @@ dummy_enable (struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc) dum = ep_to_dummy (ep); if (!dum->driver) return -ESHUTDOWN; - if (dum->gadget.speed == USB_SPEED_SUPER) - dum_hcd = dum->ss_hcd; - else - dum_hcd = dum->hs_hcd; + + dum_hcd = gadget_to_dummy_hcd(&dum->gadget); if (!is_enabled(dum_hcd)) return -ESHUTDOWN; @@ -631,10 +629,7 @@ dummy_queue (struct usb_ep *_ep, struct usb_request *_req, return -EINVAL; dum = ep_to_dummy (ep); - if (dum->gadget.speed == USB_SPEED_SUPER) - dum_hcd = dum->ss_hcd; - else - dum_hcd = dum->hs_hcd; + dum_hcd = gadget_to_dummy_hcd(&dum->gadget); if (!dum->driver || !is_enabled(dum_hcd)) return -ESHUTDOWN; -- cgit v1.2.3-70-g09d2 From d8a14a85c72faf1bdcbbc12255361aaa9cb79ff5 Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Fri, 17 Jun 2011 10:11:41 +0200 Subject: usb: gadget: dummy_hcd: use less checks for USB_SPEED_SUPER Taking the correct struct once avoids doing the speed dance. Signed-off-by: Sebastian Andrzej Siewior Signed-off-by: Felipe Balbi Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/dummy_hcd.c | 30 ++++++++++++++---------------- 1 file changed, 14 insertions(+), 16 deletions(-) (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c index 1fc80bb8ca3..865faf0932a 100644 --- a/drivers/usb/gadget/dummy_hcd.c +++ b/drivers/usb/gadget/dummy_hcd.c @@ -809,18 +809,18 @@ static int dummy_set_selfpowered (struct usb_gadget *_gadget, int value) static int dummy_pullup (struct usb_gadget *_gadget, int value) { + struct dummy_hcd *dum_hcd; struct dummy *dum; unsigned long flags; - dum = gadget_to_dummy_hcd(_gadget)->dum; + dum_hcd = gadget_to_dummy_hcd(_gadget); + dum = dum_hcd->dum; + spin_lock_irqsave (&dum->lock, flags); dum->pullup = (value != 0); - set_link_state((dum->gadget.speed == USB_SPEED_SUPER ? - dum->ss_hcd : dum->hs_hcd)); + set_link_state(dum_hcd); spin_unlock_irqrestore (&dum->lock, flags); - usb_hcd_poll_rh_status((dum->gadget.speed == USB_SPEED_SUPER ? - dummy_hcd_to_hcd(dum->ss_hcd) : - dummy_hcd_to_hcd(dum->hs_hcd))); + usb_hcd_poll_rh_status(dummy_hcd_to_hcd(dum_hcd)); return 0; } @@ -1043,34 +1043,32 @@ static int dummy_udc_remove (struct platform_device *pdev) static int dummy_udc_suspend (struct platform_device *pdev, pm_message_t state) { struct dummy *dum = platform_get_drvdata(pdev); + struct dummy_hcd *dum_hcd; dev_dbg (&pdev->dev, "%s\n", __func__); + dum_hcd = gadget_to_dummy_hcd(&dum->gadget); spin_lock_irq (&dum->lock); dum->udc_suspended = 1; - set_link_state((dum->gadget.speed == USB_SPEED_SUPER ? - dum->ss_hcd : dum->hs_hcd)); + set_link_state(dum_hcd); spin_unlock_irq (&dum->lock); - usb_hcd_poll_rh_status((dum->gadget.speed == USB_SPEED_SUPER ? - dummy_hcd_to_hcd(dum->ss_hcd) : - dummy_hcd_to_hcd(dum->hs_hcd))); + usb_hcd_poll_rh_status(dummy_hcd_to_hcd(dum_hcd)); return 0; } static int dummy_udc_resume (struct platform_device *pdev) { struct dummy *dum = platform_get_drvdata(pdev); + struct dummy_hcd *dum_hcd; dev_dbg (&pdev->dev, "%s\n", __func__); + dum_hcd = gadget_to_dummy_hcd(&dum->gadget); spin_lock_irq (&dum->lock); dum->udc_suspended = 0; - set_link_state((dum->gadget.speed == USB_SPEED_SUPER ? - dum->ss_hcd : dum->hs_hcd)); + set_link_state(dum_hcd); spin_unlock_irq (&dum->lock); - usb_hcd_poll_rh_status((dum->gadget.speed == USB_SPEED_SUPER ? - dummy_hcd_to_hcd(dum->ss_hcd) : - dummy_hcd_to_hcd(dum->hs_hcd))); + usb_hcd_poll_rh_status(dummy_hcd_to_hcd(dum_hcd)); return 0; } -- cgit v1.2.3-70-g09d2 From 4baa74fe32f330d464d59a00d01980fd16a15ecc Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Thu, 16 Jun 2011 20:37:00 +0200 Subject: usb: gadget: remove net2280_set_fifo_mode() This function has no user in my tree. It looks like it belongs to net2280 but it somehow morphed into the dummy_hcd. So I remove it before it spreads into more drivers. After some digging I figured out that the only user was removed in |commit 9079e91b5b5a84836e65cdc9128d2602e3beaef2 |Author: David Brownell |Date: Wed May 7 16:00:36 2008 -0700 | | USB: serial gadget: cleanup/reorg Signed-off-by: Sebastian Andrzej Siewior Signed-off-by: Felipe Balbi Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/dummy_hcd.c | 10 -------- drivers/usb/gadget/net2280.c | 56 ------------------------------------------ 2 files changed, 66 deletions(-) (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c index 865faf0932a..6d189e1b571 100644 --- a/drivers/usb/gadget/dummy_hcd.c +++ b/drivers/usb/gadget/dummy_hcd.c @@ -976,16 +976,6 @@ static int dummy_udc_stop(struct usb_gadget_driver *driver) #undef is_enabled -/* just declare this in any driver that really need it */ -extern int net2280_set_fifo_mode (struct usb_gadget *gadget, int mode); - -int net2280_set_fifo_mode (struct usb_gadget *gadget, int mode) -{ - return -ENOSYS; -} -EXPORT_SYMBOL (net2280_set_fifo_mode); - - /* The gadget structure is stored inside the hcd structure and will be * released along with it. */ static void diff --git a/drivers/usb/gadget/net2280.c b/drivers/usb/gadget/net2280.c index 1e6ea6f2650..3dd40b4e675 100644 --- a/drivers/usb/gadget/net2280.c +++ b/drivers/usb/gadget/net2280.c @@ -1744,62 +1744,6 @@ static void set_fifo_mode (struct net2280 *dev, int mode) list_add_tail (&dev->ep [6].ep.ep_list, &dev->gadget.ep_list); } -/* just declare this in any driver that really need it */ -extern int net2280_set_fifo_mode (struct usb_gadget *gadget, int mode); - -/** - * net2280_set_fifo_mode - change allocation of fifo buffers - * @gadget: access to the net2280 device that will be updated - * @mode: 0 for default, four 1kB buffers (ep-a through ep-d); - * 1 for two 2kB buffers (ep-a and ep-b only); - * 2 for one 2kB buffer (ep-a) and two 1kB ones (ep-b, ep-c). - * - * returns zero on success, else negative errno. when this succeeds, - * the contents of gadget->ep_list may have changed. - * - * you may only call this function when endpoints a-d are all disabled. - * use it whenever extra hardware buffering can help performance, such - * as before enabling "high bandwidth" interrupt endpoints that use - * maxpacket bigger than 512 (when double buffering would otherwise - * be unavailable). - */ -int net2280_set_fifo_mode (struct usb_gadget *gadget, int mode) -{ - int i; - struct net2280 *dev; - int status = 0; - unsigned long flags; - - if (!gadget) - return -ENODEV; - dev = container_of (gadget, struct net2280, gadget); - - spin_lock_irqsave (&dev->lock, flags); - - for (i = 1; i <= 4; i++) - if (dev->ep [i].desc) { - status = -EINVAL; - break; - } - if (mode < 0 || mode > 2) - status = -EINVAL; - if (status == 0) - set_fifo_mode (dev, mode); - spin_unlock_irqrestore (&dev->lock, flags); - - if (status == 0) { - if (mode == 1) - DEBUG (dev, "fifo: ep-a 2K, ep-b 2K\n"); - else if (mode == 2) - DEBUG (dev, "fifo: ep-a 2K, ep-b 1K, ep-c 1K\n"); - /* else all are 1K */ - } - return status; -} -EXPORT_SYMBOL (net2280_set_fifo_mode); - -/*-------------------------------------------------------------------------*/ - /* keeping it simple: * - one bus driver, initted first; * - one function driver, initted second -- cgit v1.2.3-70-g09d2 From fc0b721f27beb5464d9fb5e521f5cd68127dd14e Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Fri, 17 Jun 2011 19:43:13 +0200 Subject: usb: gadget: dummy_hcd: move common bits of suspend/resume into one function Signed-off-by: Sebastian Andrzej Siewior Signed-off-by: Felipe Balbi Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/dummy_hcd.c | 37 ++++++++++++++++++------------------- 1 file changed, 18 insertions(+), 19 deletions(-) (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c index 6d189e1b571..1916360072a 100644 --- a/drivers/usb/gadget/dummy_hcd.c +++ b/drivers/usb/gadget/dummy_hcd.c @@ -1030,34 +1030,33 @@ static int dummy_udc_remove (struct platform_device *pdev) return 0; } -static int dummy_udc_suspend (struct platform_device *pdev, pm_message_t state) +static void dummy_udc_pm(struct dummy *dum, struct dummy_hcd *dum_hcd, + int suspend) { - struct dummy *dum = platform_get_drvdata(pdev); - struct dummy_hcd *dum_hcd; - - dev_dbg (&pdev->dev, "%s\n", __func__); - dum_hcd = gadget_to_dummy_hcd(&dum->gadget); - spin_lock_irq (&dum->lock); - dum->udc_suspended = 1; + spin_lock_irq(&dum->lock); + dum->udc_suspended = suspend; set_link_state(dum_hcd); - spin_unlock_irq (&dum->lock); + spin_unlock_irq(&dum->lock); +} + +static int dummy_udc_suspend(struct platform_device *pdev, pm_message_t state) +{ + struct dummy *dum = platform_get_drvdata(pdev); + struct dummy_hcd *dum_hcd = gadget_to_dummy_hcd(&dum->gadget); + dev_dbg(&pdev->dev, "%s\n", __func__); + dummy_udc_pm(dum, dum_hcd, 1); usb_hcd_poll_rh_status(dummy_hcd_to_hcd(dum_hcd)); return 0; } -static int dummy_udc_resume (struct platform_device *pdev) +static int dummy_udc_resume(struct platform_device *pdev) { - struct dummy *dum = platform_get_drvdata(pdev); - struct dummy_hcd *dum_hcd; - - dev_dbg (&pdev->dev, "%s\n", __func__); - dum_hcd = gadget_to_dummy_hcd(&dum->gadget); - spin_lock_irq (&dum->lock); - dum->udc_suspended = 0; - set_link_state(dum_hcd); - spin_unlock_irq (&dum->lock); + struct dummy *dum = platform_get_drvdata(pdev); + struct dummy_hcd *dum_hcd = gadget_to_dummy_hcd(&dum->gadget); + dev_dbg(&pdev->dev, "%s\n", __func__); + dummy_udc_pm(dum, dum_hcd, 0); usb_hcd_poll_rh_status(dummy_hcd_to_hcd(dum_hcd)); return 0; } -- cgit v1.2.3-70-g09d2 From 193ab2a6070039e7ee2b9b9bebea754a7c52fd1b Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Wed, 22 Jun 2011 17:28:10 +0300 Subject: usb: gadget: allow multiple gadgets to be built now that we have the udc class, we can allow multiple gadget controller drivers to be compiled as modules. This will allow for distro-like kernels for embedded devices. With this patch, I managed to build an x86 kernel with support for many of the controllers enabled: CONFIG_USB_FUSB300=m CONFIG_USB_R8A66597=m CONFIG_USB_M66592=m CONFIG_USB_AMD5536UDC=m CONFIG_USB_CI13XXX_PCI=m CONFIG_USB_NET2272=m CONFIG_USB_NET2280=m CONFIG_USB_GOKU=m CONFIG_USB_LANGWELL=m CONFIG_USB_EG20T=m Also an ARM kernel with support for many controllers: CONFIG_USB_FUSB300=m CONFIG_USB_OMAP=m CONFIG_USB_R8A66597=m CONFIG_USB_GADGET_MUSB_HDRC=m CONFIG_USB_M66592=m CONFIG_USB_NET2272=m CONFIG_USB_DUMMY_HCD=m The next step would be to get rid of the direct access to arch/ and mach/ directories on some gadget controllers so that we can build all of them without depending on their respective ARCH_* symbols. Signed-off-by: Felipe Balbi Signed-off-by: Greg Kroah-Hartman --- drivers/usb/Kconfig | 2 - drivers/usb/gadget/Kconfig | 285 +++++++++----------------------------- drivers/usb/renesas_usbhs/Kconfig | 16 --- 3 files changed, 66 insertions(+), 237 deletions(-) delete mode 100644 drivers/usb/renesas_usbhs/Kconfig (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig index 48f1781352f..8cd999a217b 100644 --- a/drivers/usb/Kconfig +++ b/drivers/usb/Kconfig @@ -118,8 +118,6 @@ source "drivers/usb/host/Kconfig" source "drivers/usb/musb/Kconfig" -source "drivers/usb/renesas_usbhs/Kconfig" - source "drivers/usb/class/Kconfig" source "drivers/usb/storage/Kconfig" diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index 86f64caeafc..46a253adde3 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -96,9 +96,6 @@ config USB_GADGET_VBUS_DRAW This value will be used except for system-specific gadget drivers that have more specific information. -config USB_GADGET_SELECTED - boolean - # # USB Peripheral Controller Support # @@ -122,10 +119,9 @@ choice # Integrated controllers # -config USB_GADGET_AT91 - boolean "Atmel AT91 USB Device Port" +config USB_AT91 + tristate "Atmel AT91 USB Device Port" depends on ARCH_AT91 && !ARCH_AT91SAM9RL && !ARCH_AT91CAP9 && !ARCH_AT91SAM9G45 - select USB_GADGET_SELECTED help Many Atmel AT91 processors (such as the AT91RM2000) have a full speed USB Device Port with support for five configurable @@ -135,27 +131,16 @@ config USB_GADGET_AT91 dynamically linked module called "at91_udc" and force all gadget drivers to also be dynamically linked. -config USB_AT91 - tristate - depends on USB_GADGET_AT91 - default USB_GADGET - -config USB_GADGET_ATMEL_USBA - boolean "Atmel USBA" +config USB_ATMEL_USBA + tristate "Atmel USBA" select USB_GADGET_DUALSPEED depends on AVR32 || ARCH_AT91CAP9 || ARCH_AT91SAM9RL || ARCH_AT91SAM9G45 help USBA is the integrated high-speed USB Device controller on the AT32AP700x, some AT91SAM9 and AT91CAP9 processors from Atmel. -config USB_ATMEL_USBA - tristate - depends on USB_GADGET_ATMEL_USBA - default USB_GADGET - select USB_GADGET_SELECTED - -config USB_GADGET_FSL_USB2 - boolean "Freescale Highspeed USB DR Peripheral Controller" +config USB_FSL_USB2 + tristate "Freescale Highspeed USB DR Peripheral Controller" depends on FSL_SOC || ARCH_MXC select USB_GADGET_DUALSPEED select USB_FSL_MPH_DR_OF if OF @@ -170,26 +155,14 @@ config USB_GADGET_FSL_USB2 dynamically linked module called "fsl_usb2_udc" and force all gadget drivers to also be dynamically linked. -config USB_FSL_USB2 - tristate - depends on USB_GADGET_FSL_USB2 - default USB_GADGET - select USB_GADGET_SELECTED - -config USB_GADGET_FUSB300 - boolean "Faraday FUSB300 USB Peripheral Controller" +config USB_FUSB300 + tristate "Faraday FUSB300 USB Peripheral Controller" select USB_GADGET_DUALSPEED help Faraday usb device controller FUSB300 driver -config USB_FUSB300 - tristate - depends on USB_GADGET_FUSB300 - default USB_GADGET - select USB_GADGET_SELECTED - -config USB_GADGET_OMAP - boolean "OMAP USB Device Controller" +config USB_OMAP + tristate "OMAP USB Device Controller" depends on ARCH_OMAP select ISP1301_OMAP if MACH_OMAP_H2 || MACH_OMAP_H3 || MACH_OMAP_H4_OTG select USB_OTG_UTILS if ARCH_OMAP @@ -204,14 +177,8 @@ config USB_GADGET_OMAP dynamically linked module called "omap_udc" and force all gadget drivers to also be dynamically linked. -config USB_OMAP - tristate - depends on USB_GADGET_OMAP - default USB_GADGET - select USB_GADGET_SELECTED - -config USB_GADGET_PXA25X - boolean "PXA 25x or IXP 4xx" +config USB_PXA25X + tristate "PXA 25x or IXP 4xx" depends on (ARCH_PXA && PXA25x) || ARCH_IXP4XX select USB_OTG_UTILS help @@ -226,24 +193,18 @@ config USB_GADGET_PXA25X dynamically linked module called "pxa25x_udc" and force all gadget drivers to also be dynamically linked. -config USB_PXA25X - tristate - depends on USB_GADGET_PXA25X - default USB_GADGET - select USB_GADGET_SELECTED - # if there's only one gadget driver, using only two bulk endpoints, # don't waste memory for the other endpoints config USB_PXA25X_SMALL - depends on USB_GADGET_PXA25X + depends on USB_PXA25X bool default n if USB_ETH_RNDIS default y if USB_ZERO default y if USB_ETH default y if USB_G_SERIAL -config USB_GADGET_R8A66597 - boolean "Renesas R8A66597 USB Peripheral Controller" +config USB_R8A66597 + tristate "Renesas R8A66597 USB Peripheral Controller" select USB_GADGET_DUALSPEED help R8A66597 is a discrete USB host and peripheral controller chip that @@ -254,32 +215,20 @@ config USB_GADGET_R8A66597 dynamically linked module called "r8a66597_udc" and force all gadget drivers to also be dynamically linked. -config USB_R8A66597 - tristate - depends on USB_GADGET_R8A66597 - default USB_GADGET - select USB_GADGET_SELECTED - -config USB_GADGET_RENESAS_USBHS - boolean "Renesas USBHS" - depends on USB_RENESAS_USBHS - select USB_GADGET_DUALSPEED +config USB_RENESAS_USBHS + tristate 'Renesas USBHS controller' + depends on SUPERH || ARCH_SHMOBILE help - Renesas USBHS is a discrete USB host and peripheral controller - chip that supports both full and high speed USB 2.0 data transfers. - platform is able to configure endpoint (pipe) style - - Say "y" to enable the gadget specific portion of the USBHS driver. - + Renesas USBHS is a discrete USB host and peripheral controller chip + that supports both full and high speed USB 2.0 data transfers. + It has nine or more configurable endpoints, and endpoint zero. -config USB_RENESAS_USBHS_UDC - tristate - depends on USB_GADGET_RENESAS_USBHS - default USB_GADGET - select USB_GADGET_SELECTED + Say "y" to link the driver statically, or "m" to build a + dynamically linked module called "renesas_usbhs" and force all + gadget drivers to also be dynamically linked. -config USB_GADGET_PXA27X - boolean "PXA 27x" +config USB_PXA27X + tristate "PXA 27x" depends on ARCH_PXA && (PXA27x || PXA3xx) select USB_OTG_UTILS help @@ -293,14 +242,8 @@ config USB_GADGET_PXA27X dynamically linked module called "pxa27x_udc" and force all gadget drivers to also be dynamically linked. -config USB_PXA27X - tristate - depends on USB_GADGET_PXA27X - default USB_GADGET - select USB_GADGET_SELECTED - -config USB_GADGET_S3C_HSOTG - boolean "S3C HS/OtG USB Device controller" +config USB_S3C_HSOTG + tristate "S3C HS/OtG USB Device controller" depends on S3C_DEV_USB_HSOTG select USB_GADGET_S3C_HSOTG_PIO select USB_GADGET_DUALSPEED @@ -308,14 +251,8 @@ config USB_GADGET_S3C_HSOTG The Samsung S3C64XX USB2.0 high-speed gadget controller integrated into the S3C64XX series SoC. -config USB_S3C_HSOTG - tristate - depends on USB_GADGET_S3C_HSOTG - default USB_GADGET - select USB_GADGET_SELECTED - -config USB_GADGET_IMX - boolean "Freescale IMX USB Peripheral Controller" +config USB_IMX + tristate "Freescale IMX USB Peripheral Controller" depends on ARCH_MX1 help Freescale's IMX series include an integrated full speed @@ -329,14 +266,8 @@ config USB_GADGET_IMX dynamically linked module called "imx_udc" and force all gadget drivers to also be dynamically linked. -config USB_IMX - tristate - depends on USB_GADGET_IMX - default USB_GADGET - select USB_GADGET_SELECTED - -config USB_GADGET_S3C2410 - boolean "S3C2410 USB Device Controller" +config USB_S3C2410 + tristate "S3C2410 USB Device Controller" depends on ARCH_S3C2410 help Samsung's S3C2410 is an ARM-4 processor with an integrated @@ -346,18 +277,12 @@ config USB_GADGET_S3C2410 This driver has been tested on the S3C2410, S3C2412, and S3C2440 processors. -config USB_S3C2410 - tristate - depends on USB_GADGET_S3C2410 - default USB_GADGET - select USB_GADGET_SELECTED - config USB_S3C2410_DEBUG boolean "S3C2410 udc debug messages" - depends on USB_GADGET_S3C2410 + depends on USB_S3C2410 -config USB_GADGET_S3C_HSUDC - boolean "S3C2416, S3C2443 and S3C2450 USB Device Controller" +config USB_S3C_HSUDC + tristate "S3C2416, S3C2443 and S3C2450 USB Device Controller" depends on ARCH_S3C2410 select USB_GADGET_DUALSPEED help @@ -367,41 +292,29 @@ config USB_GADGET_S3C_HSUDC This driver has been tested on S3C2416 and S3C2450 processors. -config USB_S3C_HSUDC - tristate - depends on USB_GADGET_S3C_HSUDC - default USB_GADGET - select USB_GADGET_SELECTED - -config USB_GADGET_PXA_U2O - boolean "PXA9xx Processor USB2.0 controller" +config USB_PXA_U2O + tristate "PXA9xx Processor USB2.0 controller" + depends on ARCH_MMP select USB_GADGET_DUALSPEED help PXA9xx Processor series include a high speed USB2.0 device controller, which support high speed and full speed USB peripheral. -config USB_PXA_U2O - tristate - depends on USB_GADGET_PXA_U2O - default USB_GADGET - select USB_GADGET_SELECTED - # # Controllers available in both integrated and discrete versions # # musb builds in ../musb along with host support config USB_GADGET_MUSB_HDRC - boolean "Inventra HDRC USB Peripheral (TI, ADI, ...)" + tristate "Inventra HDRC USB Peripheral (TI, ADI, ...)" depends on USB_MUSB_HDRC && (USB_MUSB_PERIPHERAL || USB_MUSB_OTG) select USB_GADGET_DUALSPEED - select USB_GADGET_SELECTED help This OTG-capable silicon IP is used in dual designs including the TI DaVinci, OMAP 243x, OMAP 343x, TUSB 6010, and ADI Blackfin -config USB_GADGET_M66592 - boolean "Renesas M66592 USB Peripheral Controller" +config USB_M66592 + tristate "Renesas M66592 USB Peripheral Controller" select USB_GADGET_DUALSPEED help M66592 is a discrete USB peripheral controller chip that @@ -412,18 +325,12 @@ config USB_GADGET_M66592 dynamically linked module called "m66592_udc" and force all gadget drivers to also be dynamically linked. -config USB_M66592 - tristate - depends on USB_GADGET_M66592 - default USB_GADGET - select USB_GADGET_SELECTED - # # Controllers available only in discrete form (and all PCI controllers) # -config USB_GADGET_AMD5536UDC - boolean "AMD5536 UDC" +config USB_AMD5536UDC + tristate "AMD5536 UDC" depends on PCI select USB_GADGET_DUALSPEED help @@ -437,14 +344,8 @@ config USB_GADGET_AMD5536UDC dynamically linked module called "amd5536udc" and force all gadget drivers to also be dynamically linked. -config USB_AMD5536UDC - tristate - depends on USB_GADGET_AMD5536UDC - default USB_GADGET - select USB_GADGET_SELECTED - -config USB_GADGET_FSL_QE - boolean "Freescale QE/CPM USB Device Controller" +config USB_FSL_QE + tristate "Freescale QE/CPM USB Device Controller" depends on FSL_SOC && (QUICC_ENGINE || CPM) help Some of Freescale PowerPC processors have a Full Speed @@ -456,14 +357,8 @@ config USB_GADGET_FSL_QE Set CONFIG_USB_GADGET to "m" to build this driver as a dynamically linked module called "fsl_qe_udc". -config USB_FSL_QE - tristate - depends on USB_GADGET_FSL_QE - default USB_GADGET - select USB_GADGET_SELECTED - -config USB_GADGET_CI13XXX_PCI - boolean "MIPS USB CI13xxx PCI UDC" +config USB_CI13XXX_PCI + tristate "MIPS USB CI13xxx PCI UDC" depends on PCI select USB_GADGET_DUALSPEED help @@ -474,14 +369,8 @@ config USB_GADGET_CI13XXX_PCI dynamically linked module called "ci13xxx_udc" and force all gadget drivers to also be dynamically linked. -config USB_CI13XXX_PCI - tristate - depends on USB_GADGET_CI13XXX_PCI - default USB_GADGET - select USB_GADGET_SELECTED - -config USB_GADGET_NET2272 - boolean "PLX NET2272" +config USB_NET2272 + tristate "PLX NET2272" select USB_GADGET_DUALSPEED help PLX NET2272 is a USB peripheral controller which supports @@ -493,9 +382,9 @@ config USB_GADGET_NET2272 dynamically linked module called "net2272" and force all gadget drivers to also be dynamically linked. -config USB_GADGET_NET2272_DMA +config USB_NET2272_DMA boolean "Support external DMA controller" - depends on USB_GADGET_NET2272 + depends on USB_NET2272 help The NET2272 part can optionally support an external DMA controller, but your board has to have support in the @@ -503,14 +392,8 @@ config USB_GADGET_NET2272_DMA If unsure, say "N" here. The driver works fine in PIO mode. -config USB_NET2272 - tristate - depends on USB_GADGET_NET2272 - default USB_GADGET - select USB_GADGET_SELECTED - -config USB_GADGET_NET2280 - boolean "NetChip 228x" +config USB_NET2280 + tristate "NetChip 228x" depends on PCI select USB_GADGET_DUALSPEED help @@ -525,14 +408,8 @@ config USB_GADGET_NET2280 dynamically linked module called "net2280" and force all gadget drivers to also be dynamically linked. -config USB_NET2280 - tristate - depends on USB_GADGET_NET2280 - default USB_GADGET - select USB_GADGET_SELECTED - -config USB_GADGET_GOKU - boolean "Toshiba TC86C001 'Goku-S'" +config USB_GOKU + tristate "Toshiba TC86C001 'Goku-S'" depends on PCI help The Toshiba TC86C001 is a PCI device which includes controllers @@ -545,14 +422,8 @@ config USB_GADGET_GOKU dynamically linked module called "goku_udc" and to force all gadget drivers to also be dynamically linked. -config USB_GOKU - tristate - depends on USB_GADGET_GOKU - default USB_GADGET - select USB_GADGET_SELECTED - -config USB_GADGET_LANGWELL - boolean "Intel Langwell USB Device Controller" +config USB_LANGWELL + tristate "Intel Langwell USB Device Controller" depends on PCI select USB_GADGET_DUALSPEED help @@ -566,14 +437,8 @@ config USB_GADGET_LANGWELL dynamically linked module called "langwell_udc" and force all gadget drivers to also be dynamically linked. -config USB_LANGWELL - tristate - depends on USB_GADGET_LANGWELL - default USB_GADGET - select USB_GADGET_SELECTED - -config USB_GADGET_EG20T - boolean "Intel EG20T PCH/OKI SEMICONDUCTOR ML7213 IOH UDC" +config USB_EG20T + tristate "Intel EG20T PCH/OKI SEMICONDUCTOR ML7213 IOH UDC" depends on PCI select USB_GADGET_DUALSPEED help @@ -594,14 +459,8 @@ config USB_GADGET_EG20T ML7213 is companion chip for Intel Atom E6xx series. ML7213 is completely compatible for Intel EG20T PCH. -config USB_EG20T - tristate - depends on USB_GADGET_EG20T - default USB_GADGET - select USB_GADGET_SELECTED - -config USB_GADGET_CI13XXX_MSM - boolean "MIPS USB CI13xxx for MSM" +config USB_CI13XXX_MSM + tristate "MIPS USB CI13xxx for MSM" depends on ARCH_MSM select USB_GADGET_DUALSPEED select USB_MSM_OTG @@ -617,18 +476,12 @@ config USB_GADGET_CI13XXX_MSM dynamically linked module called "ci13xxx_msm" and force all gadget drivers to also be dynamically linked. -config USB_CI13XXX_MSM - tristate - depends on USB_GADGET_CI13XXX_MSM - default USB_GADGET - select USB_GADGET_SELECTED - # # LAST -- dummy/emulated controller # -config USB_GADGET_DUMMY_HCD - boolean "Dummy HCD (DEVELOPMENT)" +config USB_DUMMY_HCD + tristate "Dummy HCD (DEVELOPMENT)" depends on USB=y || (USB=m && USB_GADGET=m) select USB_GADGET_DUALSPEED select USB_GADGET_SUPERSPEED @@ -638,11 +491,11 @@ config USB_GADGET_DUMMY_HCD side is the master; the gadget side is the slave. Gadget drivers can be high, full, or low speed; and they have access to endpoints like those from NET2280, PXA2xx, or SA1100 hardware. - + This may help in some stages of creating a driver to embed in a Linux device, since it lets you debug several parts of the gadget driver without its hardware or drivers being involved. - + Since such a gadget side driver needs to interoperate with a host side Linux-USB device driver, this may help to debug both sides of a USB protocol stack. @@ -651,12 +504,6 @@ config USB_GADGET_DUMMY_HCD dynamically linked module called "dummy_hcd" and force all gadget drivers to also be dynamically linked. -config USB_DUMMY_HCD - tristate - depends on USB_GADGET_DUMMY_HCD - default USB_GADGET - select USB_GADGET_SELECTED - # NOTE: Please keep dummy_hcd LAST so that "real hardware" appears # first and will be selected by default. @@ -678,7 +525,7 @@ config USB_GADGET_SUPERSPEED # choice tristate "USB Gadget Drivers" - depends on USB_GADGET && USB_GADGET_SELECTED + depends on USB_GADGET default USB_ETH help A Linux "Gadget Driver" talks to the USB Peripheral Controller diff --git a/drivers/usb/renesas_usbhs/Kconfig b/drivers/usb/renesas_usbhs/Kconfig deleted file mode 100644 index b2e64918884..00000000000 --- a/drivers/usb/renesas_usbhs/Kconfig +++ /dev/null @@ -1,16 +0,0 @@ -# -# Renesas USB Controller Drivers -# - -config USB_RENESAS_USBHS - tristate 'Renesas USBHS controller' - depends on SUPERH || ARCH_SHMOBILE - default n - help - Renesas USBHS is a discrete USB host and peripheral controller chip - that supports both full and high speed USB 2.0 data transfers. - It has nine or more configurable endpoints, and endpoint zero. - - Say "y" to link the driver statically, or "m" to build a - dynamically linked module called "renesas_usbhs" and force all - gadget drivers to also be dynamically linked. -- cgit v1.2.3-70-g09d2 From 765f5b830e547229bb752e7b232ee83e2b3d49d5 Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Thu, 23 Jun 2011 14:26:11 +0200 Subject: usb: gadget: defer setting maxpacket till ->setup() maxpacket is set by the udc driver for ep0 very early. This value is copied by the function gadget used later for the USB_DT_DEVICE and USB_DT_DEVICE_QUALIFIER query. This seems to work fine so far. For USB3 we need set a different value here. In SS speed it is 2^x with x=9 and in HS we set something <= 64. If the UDC starts in SS and continues in HS after the cable has been plugged it will report a too small value. There setting of this value is defered and taken automaticly from the ep0 pointer where the UDC driver can update it according to the speed it detected _after_ a cable has been plugged. Signed-off-by: Sebastian Andrzej Siewior Signed-off-by: Felipe Balbi Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/composite.c | 3 +-- drivers/usb/gadget/dbgp.c | 2 +- drivers/usb/gadget/file_storage.c | 10 ++++++---- drivers/usb/gadget/gmidi.c | 3 +-- drivers/usb/gadget/inode.c | 5 ++--- drivers/usb/gadget/printer.c | 14 +++++++++----- 6 files changed, 20 insertions(+), 17 deletions(-) (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c index c5abe270970..5ef87794fd3 100644 --- a/drivers/usb/gadget/composite.c +++ b/drivers/usb/gadget/composite.c @@ -573,7 +573,7 @@ static void device_qual(struct usb_composite_dev *cdev) qual->bDeviceSubClass = cdev->desc.bDeviceSubClass; qual->bDeviceProtocol = cdev->desc.bDeviceProtocol; /* ASSUME same EP0 fifo size at both speeds */ - qual->bMaxPacketSize0 = cdev->desc.bMaxPacketSize0; + qual->bMaxPacketSize0 = cdev->gadget->ep0->maxpacket; qual->bNumConfigurations = count_configs(cdev, USB_DT_DEVICE_QUALIFIER); qual->bRESERVED = 0; } @@ -1450,7 +1450,6 @@ static int composite_bind(struct usb_gadget *gadget) goto fail; cdev->desc = *composite->dev; - cdev->desc.bMaxPacketSize0 = gadget->ep0->maxpacket; /* standardized runtime overrides for device ID data */ if (idVendor) diff --git a/drivers/usb/gadget/dbgp.c b/drivers/usb/gadget/dbgp.c index 052209e8927..8beefdd3678 100644 --- a/drivers/usb/gadget/dbgp.c +++ b/drivers/usb/gadget/dbgp.c @@ -314,7 +314,6 @@ static int __init dbgp_bind(struct usb_gadget *gadget) dbgp.req->length = DBGP_REQ_EP0_LEN; gadget->ep0->driver_data = gadget; - device_desc.bMaxPacketSize0 = gadget->ep0->maxpacket; #ifdef CONFIG_USB_G_DBGP_SERIAL dbgp.serial = kzalloc(sizeof(struct gserial), GFP_KERNEL); @@ -365,6 +364,7 @@ static int dbgp_setup(struct usb_gadget *gadget, dev_dbg(&dbgp.gadget->dev, "setup: desc device\n"); len = sizeof device_desc; data = &device_desc; + device_desc.bMaxPacketSize0 = gadget->ep0->maxpacket; break; case USB_DT_DEBUG: dev_dbg(&dbgp.gadget->dev, "setup: desc debug\n"); diff --git a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c index 738591a64bb..639e14a2fd1 100644 --- a/drivers/usb/gadget/file_storage.c +++ b/drivers/usb/gadget/file_storage.c @@ -929,6 +929,7 @@ static int standard_setup_req(struct fsg_dev *fsg, case USB_DT_DEVICE: VDBG(fsg, "get device descriptor\n"); + device_desc.bMaxPacketSize0 = fsg->ep0->maxpacket; value = sizeof device_desc; memcpy(req->buf, &device_desc, value); break; @@ -936,6 +937,11 @@ static int standard_setup_req(struct fsg_dev *fsg, VDBG(fsg, "get device qualifier\n"); if (!gadget_is_dualspeed(fsg->gadget)) break; + /* + * Assume ep0 uses the same maxpacket value for both + * speeds + */ + dev_qualifier.bMaxPacketSize0 = fsg->ep0->maxpacket; value = sizeof dev_qualifier; memcpy(req->buf, &dev_qualifier, value); break; @@ -3417,7 +3423,6 @@ static int __init fsg_bind(struct usb_gadget *gadget) } /* Fix up the descriptors */ - device_desc.bMaxPacketSize0 = fsg->ep0->maxpacket; device_desc.idVendor = cpu_to_le16(mod_data.vendor); device_desc.idProduct = cpu_to_le16(mod_data.product); device_desc.bcdDevice = cpu_to_le16(mod_data.release); @@ -3431,9 +3436,6 @@ static int __init fsg_bind(struct usb_gadget *gadget) if (gadget_is_dualspeed(gadget)) { fsg_hs_function[i + FSG_HS_FUNCTION_PRE_EP_ENTRIES] = NULL; - /* Assume ep0 uses the same maxpacket value for both speeds */ - dev_qualifier.bMaxPacketSize0 = fsg->ep0->maxpacket; - /* Assume endpoint addresses are the same for both speeds */ fsg_hs_bulk_in_desc.bEndpointAddress = fsg_fs_bulk_in_desc.bEndpointAddress; diff --git a/drivers/usb/gadget/gmidi.c b/drivers/usb/gadget/gmidi.c index 4f40f146743..8b9220e128a 100644 --- a/drivers/usb/gadget/gmidi.c +++ b/drivers/usb/gadget/gmidi.c @@ -695,6 +695,7 @@ static int gmidi_setup(struct usb_gadget *gadget, switch (w_value >> 8) { case USB_DT_DEVICE: + device_desc.bMaxPacketSize0 = gadget->ep0->maxpacket; value = min(w_length, (u16) sizeof(device_desc)); memcpy(req->buf, &device_desc, value); break; @@ -1249,8 +1250,6 @@ autoconf_fail: dev->req->complete = gmidi_setup_complete; - device_desc.bMaxPacketSize0 = gadget->ep0->maxpacket; - gadget->ep0->driver_data = dev; INFO(dev, "%s, version: " DRIVER_VERSION "\n", longname); diff --git a/drivers/usb/gadget/inode.c b/drivers/usb/gadget/inode.c index a9a45569239..1b240990448 100644 --- a/drivers/usb/gadget/inode.c +++ b/drivers/usb/gadget/inode.c @@ -1347,7 +1347,7 @@ static void make_qualifier (struct dev_data *dev) qual.bDeviceProtocol = desc->bDeviceProtocol; /* assumes ep0 uses the same value for both speeds ... */ - qual.bMaxPacketSize0 = desc->bMaxPacketSize0; + qual.bMaxPacketSize0 = dev->gadget->ep0->maxpacket; qual.bNumConfigurations = 1; qual.bRESERVED = 0; @@ -1404,7 +1404,6 @@ gadgetfs_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) } dev->state = STATE_DEV_CONNECTED; - dev->dev->bMaxPacketSize0 = gadget->ep0->maxpacket; INFO (dev, "connected\n"); event = next_event (dev, GADGETFS_CONNECT); @@ -1432,6 +1431,7 @@ gadgetfs_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) case USB_DT_DEVICE: value = min (w_length, (u16) sizeof *dev->dev); + dev->dev->bMaxPacketSize0 = dev->gadget->ep0->maxpacket; req->buf = dev->dev; break; #ifdef CONFIG_USB_GADGET_DUALSPEED @@ -1712,7 +1712,6 @@ gadgetfs_bind (struct usb_gadget *gadget) set_gadget_data (gadget, dev); dev->gadget = gadget; gadget->ep0->driver_data = dev; - dev->dev->bMaxPacketSize0 = gadget->ep0->maxpacket; /* preallocate control response and buffer */ dev->req = usb_ep_alloc_request (gadget->ep0, GFP_KERNEL); diff --git a/drivers/usb/gadget/printer.c b/drivers/usb/gadget/printer.c index 00e5f19c75b..d5df8dd9d58 100644 --- a/drivers/usb/gadget/printer.c +++ b/drivers/usb/gadget/printer.c @@ -1148,6 +1148,8 @@ printer_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) switch (wValue >> 8) { case USB_DT_DEVICE: + device_desc.bMaxPacketSize0 = + gadget->ep0->maxpacket; value = min(wLength, (u16) sizeof device_desc); memcpy(req->buf, &device_desc, value); break; @@ -1155,6 +1157,12 @@ printer_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) case USB_DT_DEVICE_QUALIFIER: if (!gadget->is_dualspeed) break; + /* + * assumes ep0 uses the same value for both + * speeds + */ + dev_qualifier.bMaxPacketSize0 = + gadget->ep0->maxpacket; value = min(wLength, (u16) sizeof dev_qualifier); memcpy(req->buf, &dev_qualifier, value); @@ -1450,15 +1458,11 @@ autoconf_fail: out_ep->driver_data = out_ep; /* claim */ #ifdef CONFIG_USB_GADGET_DUALSPEED - /* assumes ep0 uses the same value for both speeds ... */ - dev_qualifier.bMaxPacketSize0 = device_desc.bMaxPacketSize0; - - /* and that all endpoints are dual-speed */ + /* assumes that all endpoints are dual-speed */ hs_ep_in_desc.bEndpointAddress = fs_ep_in_desc.bEndpointAddress; hs_ep_out_desc.bEndpointAddress = fs_ep_out_desc.bEndpointAddress; #endif /* DUALSPEED */ - device_desc.bMaxPacketSize0 = gadget->ep0->maxpacket; usb_gadget_set_selfpowered(gadget); if (gadget->is_otg) { -- cgit v1.2.3-70-g09d2 From 0fb5759952e934dd5ff25fd79f45cb5d69c8d2d1 Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Thu, 23 Jun 2011 14:26:12 +0200 Subject: usb: gadget: dummy_hcd: move ep initialisation HW setup This is only required to be done once. There is no counter part to this in ->stop() so there is no need to re-do it next time. While here also init the max_stream size to 0 on SS speed. Signed-off-by: Sebastian Andrzej Siewior Signed-off-by: Felipe Balbi Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/dummy_hcd.c | 56 +++++++++++++++++++++++++----------------- 1 file changed, 33 insertions(+), 23 deletions(-) (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c index 1916360072a..3144092d828 100644 --- a/drivers/usb/gadget/dummy_hcd.c +++ b/drivers/usb/gadget/dummy_hcd.c @@ -887,25 +887,6 @@ static int dummy_udc_start(struct usb_gadget_driver *driver, dum->devstatus = 0; - INIT_LIST_HEAD (&dum->gadget.ep_list); - for (i = 0; i < DUMMY_ENDPOINTS; i++) { - struct dummy_ep *ep = &dum->ep [i]; - - if (!ep_name [i]) - break; - ep->ep.name = ep_name [i]; - ep->ep.ops = &dummy_ep_ops; - list_add_tail (&ep->ep.ep_list, &dum->gadget.ep_list); - ep->halted = ep->wedged = ep->already_seen = - ep->setup_stage = 0; - ep->ep.maxpacket = ~0; - ep->last_io = jiffies; - ep->gadget = &dum->gadget; - ep->desc = NULL; - INIT_LIST_HEAD (&ep->queue); - } - - dum->gadget.ep0 = &dum->ep [0].ep; if (mod_data.is_super_speed) dum->gadget.speed = driver->speed; else if (mod_data.is_high_speed) @@ -922,8 +903,11 @@ static int dummy_udc_start(struct usb_gadget_driver *driver, for (i = 0; i < DUMMY_ENDPOINTS; i++) dum->ep[i].ep.max_streams = 0x10; dum->ep[0].ep.maxpacket = 9; - } else + } else { + for (i = 0; i < DUMMY_ENDPOINTS; i++) + dum->ep[i].ep.max_streams = 0; dum->ep[0].ep.maxpacket = 64; + } if (dum->gadget.speed == USB_SPEED_SUPER) dum->gadget.is_otg = @@ -932,9 +916,6 @@ static int dummy_udc_start(struct usb_gadget_driver *driver, dum->gadget.is_otg = (dummy_hcd_to_hcd(dum->hs_hcd)->self.otg_port != 0); - list_del_init (&dum->ep [0].ep.ep_list); - INIT_LIST_HEAD(&dum->fifo_req.queue); - driver->driver.bus = NULL; dum->driver = driver; dum->gadget.dev.driver = &driver->driver; @@ -984,6 +965,33 @@ dummy_gadget_release (struct device *dev) return; } +static void init_dummy_udc_hw(struct dummy *dum) +{ + int i; + + INIT_LIST_HEAD(&dum->gadget.ep_list); + for (i = 0; i < DUMMY_ENDPOINTS; i++) { + struct dummy_ep *ep = &dum->ep[i]; + + if (!ep_name[i]) + break; + ep->ep.name = ep_name[i]; + ep->ep.ops = &dummy_ep_ops; + list_add_tail(&ep->ep.ep_list, &dum->gadget.ep_list); + ep->halted = ep->wedged = ep->already_seen = + ep->setup_stage = 0; + ep->ep.maxpacket = ~0; + ep->last_io = jiffies; + ep->gadget = &dum->gadget; + ep->desc = NULL; + INIT_LIST_HEAD(&ep->queue); + } + + dum->gadget.ep0 = &dum->ep[0].ep; + list_del_init(&dum->ep[0].ep.ep_list); + INIT_LIST_HEAD(&dum->fifo_req.queue); +} + static int dummy_udc_probe (struct platform_device *pdev) { struct dummy *dum = &the_controller; @@ -1002,6 +1010,8 @@ static int dummy_udc_probe (struct platform_device *pdev) return rc; } + init_dummy_udc_hw(dum); + rc = usb_add_gadget_udc(&pdev->dev, &dum->gadget); if (rc < 0) goto err_udc; -- cgit v1.2.3-70-g09d2 From f8744d40ca12d54f35c56831040683d52e765bf8 Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Thu, 23 Jun 2011 14:26:13 +0200 Subject: usb: gadget: dummy_hcd: init is_otg in init_dummy_udc_hw() This value is now assigned during bind(). The configuration depends on static values assigned by dummy driver itself. So there is no need to defer this assigment until one know the actuall speed since the configuration is static and known early. Signed-off-by: Sebastian Andrzej Siewior Signed-off-by: Felipe Balbi Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/dummy_hcd.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c index 3144092d828..0ab2f565c12 100644 --- a/drivers/usb/gadget/dummy_hcd.c +++ b/drivers/usb/gadget/dummy_hcd.c @@ -909,13 +909,6 @@ static int dummy_udc_start(struct usb_gadget_driver *driver, dum->ep[0].ep.maxpacket = 64; } - if (dum->gadget.speed == USB_SPEED_SUPER) - dum->gadget.is_otg = - (dummy_hcd_to_hcd(dum->ss_hcd)->self.otg_port != 0); - else - dum->gadget.is_otg = - (dummy_hcd_to_hcd(dum->hs_hcd)->self.otg_port != 0); - driver->driver.bus = NULL; dum->driver = driver; dum->gadget.dev.driver = &driver->driver; @@ -990,6 +983,10 @@ static void init_dummy_udc_hw(struct dummy *dum) dum->gadget.ep0 = &dum->ep[0].ep; list_del_init(&dum->ep[0].ep.ep_list); INIT_LIST_HEAD(&dum->fifo_req.queue); + +#ifdef CONFIG_USB_OTG + dum->gadget.is_otg = 1; +#endif } static int dummy_udc_probe (struct platform_device *pdev) -- cgit v1.2.3-70-g09d2 From b5738413c96126e8191bc506b403cd55950b8f9a Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Thu, 23 Jun 2011 14:26:14 +0200 Subject: usb: gadget: dummy_hcd: move selection of speed into ->pullup() The configuration is static however we only know the speed after we have connected with the other side. Signed-off-by: Sebastian Andrzej Siewior Signed-off-by: Felipe Balbi Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/dummy_hcd.c | 60 ++++++++++++++++++++++++------------------ 1 file changed, 35 insertions(+), 25 deletions(-) (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c index 0ab2f565c12..f5c0d8f2859 100644 --- a/drivers/usb/gadget/dummy_hcd.c +++ b/drivers/usb/gadget/dummy_hcd.c @@ -807,19 +807,52 @@ static int dummy_set_selfpowered (struct usb_gadget *_gadget, int value) return 0; } +static void dummy_udc_udpate_ep0(struct dummy *dum) +{ + u32 i; + + if (dum->gadget.speed == USB_SPEED_SUPER) { + for (i = 0; i < DUMMY_ENDPOINTS; i++) + dum->ep[i].ep.max_streams = 0x10; + dum->ep[0].ep.maxpacket = 9; + } else { + for (i = 0; i < DUMMY_ENDPOINTS; i++) + dum->ep[i].ep.max_streams = 0; + dum->ep[0].ep.maxpacket = 64; + } +} + static int dummy_pullup (struct usb_gadget *_gadget, int value) { struct dummy_hcd *dum_hcd; struct dummy *dum; unsigned long flags; + dum = gadget_dev_to_dummy(&_gadget->dev); + + if (value && dum->driver) { + if (mod_data.is_super_speed) + dum->gadget.speed = dum->driver->speed; + else if (mod_data.is_high_speed) + dum->gadget.speed = min_t(u8, USB_SPEED_HIGH, + dum->driver->speed); + else + dum->gadget.speed = USB_SPEED_FULL; + dummy_udc_udpate_ep0(dum); + + if (dum->gadget.speed < dum->driver->speed) + dev_dbg(udc_dev(dum), "This device can perform faster" + " if you connect it to a %s port...\n", + (dum->driver->speed == USB_SPEED_SUPER ? + "SuperSpeed" : "HighSpeed")); + } dum_hcd = gadget_to_dummy_hcd(_gadget); - dum = dum_hcd->dum; spin_lock_irqsave (&dum->lock, flags); dum->pullup = (value != 0); set_link_state(dum_hcd); spin_unlock_irqrestore (&dum->lock, flags); + usb_hcd_poll_rh_status(dummy_hcd_to_hcd(dum_hcd)); return 0; } @@ -871,7 +904,7 @@ static int dummy_udc_start(struct usb_gadget_driver *driver, int (*bind)(struct usb_gadget *)) { struct dummy *dum = &the_controller; - int retval, i; + int retval; if (!dum) return -EINVAL; @@ -887,29 +920,6 @@ static int dummy_udc_start(struct usb_gadget_driver *driver, dum->devstatus = 0; - if (mod_data.is_super_speed) - dum->gadget.speed = driver->speed; - else if (mod_data.is_high_speed) - dum->gadget.speed = min_t(u8, USB_SPEED_HIGH, driver->speed); - else - dum->gadget.speed = USB_SPEED_FULL; - if (dum->gadget.speed < driver->speed) - dev_dbg(udc_dev(dum), "This device can perform faster" - " if you connect it to a %s port...\n", - (driver->speed == USB_SPEED_SUPER ? - "SuperSpeed" : "HighSpeed")); - - if (dum->gadget.speed == USB_SPEED_SUPER) { - for (i = 0; i < DUMMY_ENDPOINTS; i++) - dum->ep[i].ep.max_streams = 0x10; - dum->ep[0].ep.maxpacket = 9; - } else { - for (i = 0; i < DUMMY_ENDPOINTS; i++) - dum->ep[i].ep.max_streams = 0; - dum->ep[0].ep.maxpacket = 64; - } - - driver->driver.bus = NULL; dum->driver = driver; dum->gadget.dev.driver = &driver->driver; dev_dbg (udc_dev(dum), "binding gadget driver '%s'\n", -- cgit v1.2.3-70-g09d2 From 352c2dc8b07491bbab77ddf86c20c16a97326ee7 Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Thu, 23 Jun 2011 14:26:15 +0200 Subject: usb: gadget: udc-core: add "new-style" registration interface udc_start() should only trigger the internal state machine and make minimal house keeping. Before that call udc-core calls the bind() callback and after the callback the pullup(). udc_stop() is simillar, udc-core calls pullup(), unbind() and finally udc_stop(). Signed-off-by: Sebastian Andrzej Siewior Signed-off-by: Felipe Balbi Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/udc-core.c | 75 ++++++++++++++++++++++++++++++++++++++++--- include/linux/usb/gadget.h | 6 ++++ 2 files changed, 77 insertions(+), 4 deletions(-) (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/udc-core.c b/drivers/usb/gadget/udc-core.c index 83e9e5f99b4..2ddb7c8b5b3 100644 --- a/drivers/usb/gadget/udc-core.c +++ b/drivers/usb/gadget/udc-core.c @@ -72,6 +72,26 @@ static inline int usb_gadget_start(struct usb_gadget *gadget, return gadget->ops->start(driver, bind); } +/** + * usb_gadget_udc_start - tells usb device controller to start up + * @gadget: The gadget we want to get started + * @driver: The driver we want to bind to @gadget + * + * This call is issued by the UDC Class driver when it's about + * to register a gadget driver to the device controller, before + * calling gadget driver's bind() method. + * + * It allows the controller to be powered off until strictly + * necessary to have it powered on. + * + * Returns zero on success, else negative errno. + */ +static inline int usb_gadget_udc_start(struct usb_gadget *gadget, + struct usb_gadget_driver *driver) +{ + return gadget->ops->udc_start(gadget, driver); +} + /** * usb_gadget_stop - tells usb device controller we don't need it anymore * @gadget: The device we want to stop activity @@ -90,6 +110,24 @@ static inline void usb_gadget_stop(struct usb_gadget *gadget, gadget->ops->stop(driver); } +/** + * usb_gadget_udc_stop - tells usb device controller we don't need it anymore + * @gadget: The device we want to stop activity + * @driver: The driver to unbind from @gadget + * + * This call is issued by the UDC Class driver after calling + * gadget driver's unbind() method. + * + * The details are implementation specific, but it can go as + * far as powering off UDC completely and disable its data + * line pullups. + */ +static inline void usb_gadget_udc_stop(struct usb_gadget *gadget, + struct usb_gadget_driver *driver) +{ + gadget->ops->udc_stop(gadget, driver); +} + /** * usb_udc_release - release the usb_udc struct * @dev: the dev member within usb_udc @@ -155,6 +193,14 @@ err1: } EXPORT_SYMBOL_GPL(usb_add_gadget_udc); +static int udc_is_newstyle(struct usb_udc *udc) +{ + if (udc->gadget->ops->udc_start && udc->gadget->ops->udc_stop) + return 1; + return 0; +} + + static void usb_gadget_remove_driver(struct usb_udc *udc) { dev_dbg(&udc->dev, "unregistering UDC driver [%s]\n", @@ -162,7 +208,14 @@ static void usb_gadget_remove_driver(struct usb_udc *udc) kobject_uevent(&udc->dev.kobj, KOBJ_CHANGE); - usb_gadget_stop(udc->gadget, udc->driver); + if (udc_is_newstyle(udc)) { + usb_gadget_disconnect(udc->gadget); + udc->driver->unbind(udc->gadget); + usb_gadget_udc_stop(udc->gadget, udc->driver); + + } else { + usb_gadget_stop(udc->gadget, udc->driver); + } udc->driver = NULL; udc->dev.driver = NULL; @@ -232,9 +285,23 @@ found: udc->driver = driver; udc->dev.driver = &driver->driver; - ret = usb_gadget_start(udc->gadget, driver, bind); - if (ret) - goto err1; + if (udc_is_newstyle(udc)) { + ret = bind(udc->gadget); + if (ret) + goto err1; + ret = usb_gadget_udc_start(udc->gadget, driver); + if (ret) { + driver->unbind(udc->gadget); + goto err1; + } + usb_gadget_connect(udc->gadget); + } else { + + ret = usb_gadget_start(udc->gadget, driver, bind); + if (ret) + goto err1; + + } kobject_uevent(&udc->dev.kobj, KOBJ_CHANGE); mutex_unlock(&udc_lock); diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h index afb67d997f0..087f4b93183 100644 --- a/include/linux/usb/gadget.h +++ b/include/linux/usb/gadget.h @@ -459,6 +459,12 @@ struct usb_gadget_ops { int (*ioctl)(struct usb_gadget *, unsigned code, unsigned long param); void (*get_config_params)(struct usb_dcd_config_params *); + int (*udc_start)(struct usb_gadget *, + struct usb_gadget_driver *); + int (*udc_stop)(struct usb_gadget *, + struct usb_gadget_driver *); + + /* Those two are deprecated */ int (*start)(struct usb_gadget_driver *, int (*bind)(struct usb_gadget *)); int (*stop)(struct usb_gadget_driver *); -- cgit v1.2.3-70-g09d2 From aa0747394337e50533badd46e8fb7106bad3311e Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Thu, 23 Jun 2011 14:26:17 +0200 Subject: usb: gadget: dummy_hcd: convert to new-style udc-probe bind() and pull is moved to udc core, call callbacks are verified by the upper layer. Signed-off-by: Sebastian Andrzej Siewior Signed-off-by: Felipe Balbi Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/dummy_hcd.c | 50 +++++++++++++----------------------------- 1 file changed, 15 insertions(+), 35 deletions(-) (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c index f5c0d8f2859..e755a9d267f 100644 --- a/drivers/usb/gadget/dummy_hcd.c +++ b/drivers/usb/gadget/dummy_hcd.c @@ -857,17 +857,18 @@ static int dummy_pullup (struct usb_gadget *_gadget, int value) return 0; } -static int dummy_udc_start(struct usb_gadget_driver *driver, - int (*bind)(struct usb_gadget *)); -static int dummy_udc_stop(struct usb_gadget_driver *driver); +static int dummy_udc_start(struct usb_gadget *g, + struct usb_gadget_driver *driver); +static int dummy_udc_stop(struct usb_gadget *g, + struct usb_gadget_driver *driver); static const struct usb_gadget_ops dummy_ops = { .get_frame = dummy_g_get_frame, .wakeup = dummy_wakeup, .set_selfpowered = dummy_set_selfpowered, .pullup = dummy_pullup, - .start = dummy_udc_start, - .stop = dummy_udc_stop, + .udc_start = dummy_udc_start, + .udc_stop = dummy_udc_stop, }; /*-------------------------------------------------------------------------*/ @@ -900,17 +901,13 @@ static DEVICE_ATTR (function, S_IRUGO, show_function, NULL); * for each driver that registers: just add to a big root hub. */ -static int dummy_udc_start(struct usb_gadget_driver *driver, - int (*bind)(struct usb_gadget *)) +static int dummy_udc_start(struct usb_gadget *g, + struct usb_gadget_driver *driver) { - struct dummy *dum = &the_controller; - int retval; + struct dummy_hcd *dum_hcd = gadget_to_dummy_hcd(g); + struct dummy *dum = dum_hcd->dum; - if (!dum) - return -EINVAL; - if (dum->driver) - return -EBUSY; - if (!bind || !driver->setup || driver->speed == USB_SPEED_UNKNOWN) + if (driver->speed == USB_SPEED_UNKNOWN) return -EINVAL; /* @@ -921,37 +918,20 @@ static int dummy_udc_start(struct usb_gadget_driver *driver, dum->devstatus = 0; dum->driver = driver; - dum->gadget.dev.driver = &driver->driver; dev_dbg (udc_dev(dum), "binding gadget driver '%s'\n", driver->driver.name); - retval = bind(&dum->gadget); - if (retval) { - dum->driver = NULL; - dum->gadget.dev.driver = NULL; - return retval; - } - - /* khubd will enumerate this in a while */ - dummy_pullup(&dum->gadget, 1); return 0; } -static int dummy_udc_stop(struct usb_gadget_driver *driver) +static int dummy_udc_stop(struct usb_gadget *g, + struct usb_gadget_driver *driver) { - struct dummy *dum = &the_controller; - - if (!dum) - return -ENODEV; - if (!driver || driver != dum->driver || !driver->unbind) - return -EINVAL; + struct dummy_hcd *dum_hcd = gadget_to_dummy_hcd(g); + struct dummy *dum = dum_hcd->dum; dev_dbg (udc_dev(dum), "unregister gadget driver '%s'\n", driver->driver.name); - dummy_pullup(&dum->gadget, 0); - - driver->unbind (&dum->gadget); - dum->gadget.dev.driver = NULL; dum->driver = NULL; dummy_pullup(&dum->gadget, 0); -- cgit v1.2.3-70-g09d2 From 019f976e8f268a63b2fcbb662aa2f77f6b07bac6 Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Thu, 23 Jun 2011 14:28:38 +0200 Subject: usb: gadget: udc-core: wire up sysfs files This was somehow forgotten. Signed-off-by: Sebastian Andrzej Siewior Signed-off-by: Felipe Balbi Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/udc-core.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/udc-core.c b/drivers/usb/gadget/udc-core.c index 2ddb7c8b5b3..05ba4721436 100644 --- a/drivers/usb/gadget/udc-core.c +++ b/drivers/usb/gadget/udc-core.c @@ -44,7 +44,6 @@ struct usb_udc { }; static struct class *udc_class; -static struct device_type udc_device_type; static LIST_HEAD(udc_list); static DEFINE_MUTEX(udc_lock); @@ -144,6 +143,7 @@ static void usb_udc_release(struct device *dev) kfree(udc); } +static const struct attribute_group *usb_udc_attr_groups[]; /** * usb_add_gadget_udc - adds a new gadget to the udc class driver list * @parent: the parent device to this udc. Usually the controller @@ -164,6 +164,7 @@ int usb_add_gadget_udc(struct device *parent, struct usb_gadget *gadget) device_initialize(&udc->dev); udc->dev.release = usb_udc_release; udc->dev.class = udc_class; + udc->dev.groups = usb_udc_attr_groups; udc->dev.parent = parent; ret = dev_set_name(&udc->dev, "%s", kobject_name(&parent->kobj)); if (ret) @@ -373,7 +374,7 @@ static DEVICE_ATTR(soft_connect, S_IWUSR, NULL, usb_udc_softconn_store); static ssize_t usb_udc_speed_show(struct device *dev, struct device_attribute *attr, char *buf) { - struct usb_udc *udc = dev_get_drvdata(dev); + struct usb_udc *udc = container_of(dev, struct usb_udc, dev); struct usb_gadget *gadget = udc->gadget; switch (gadget->speed) { @@ -398,7 +399,7 @@ static DEVICE_ATTR(speed, S_IRUSR, usb_udc_speed_show, NULL); ssize_t usb_udc_##name##_show(struct device *dev, \ struct device_attribute *attr, char *buf) \ { \ - struct usb_udc *udc = dev_get_drvdata(dev); \ + struct usb_udc *udc = container_of(dev, struct usb_udc, dev); \ struct usb_gadget *gadget = udc->gadget; \ \ return snprintf(buf, PAGE_SIZE, "%d\n", gadget->name); \ @@ -468,8 +469,6 @@ static int __init usb_udc_init(void) } udc_class->dev_uevent = usb_udc_uevent; - udc_device_type.groups = usb_udc_attr_groups; - return 0; } subsys_initcall(usb_udc_init); -- cgit v1.2.3-70-g09d2 From 5030ec730279eabafccf862f3c8393af90c258a5 Mon Sep 17 00:00:00 2001 From: Bob Liu Date: Thu, 23 Jun 2011 17:09:49 -0400 Subject: USB: gadget: fix req length in sourcesink_setup() The recent commit 2edb11cbac fixed req->length in the composite_setup() function, but that will cause all g_zero tests to fail like: root#> ./testusb -D /proc/bus/usb/002/021 -t14 -c 15000 -s 256 -v 1 unknown speed /proc/bus/usb/002/021 /proc/bus/usb/002/021 test 14 --> 32 (Broken pipe) We need to fix req->length in sourcesink_setup() as well to avoid this. Signed-off-by: Bob Liu Signed-off-by: Mike Frysinger Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/f_sourcesink.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/f_sourcesink.c b/drivers/usb/gadget/f_sourcesink.c index caf2f95e034..5a92883f4c8 100644 --- a/drivers/usb/gadget/f_sourcesink.c +++ b/drivers/usb/gadget/f_sourcesink.c @@ -437,6 +437,8 @@ static int sourcesink_setup(struct usb_configuration *c, u16 w_value = le16_to_cpu(ctrl->wValue); u16 w_length = le16_to_cpu(ctrl->wLength); + req->length = USB_BUFSIZ; + /* composite driver infrastructure handles everything except * the two control test requests. */ -- cgit v1.2.3-70-g09d2 From 28f75f4db1e5ea1366375b2a6c40d66659e0e7ec Mon Sep 17 00:00:00 2001 From: Jassi Brar Date: Sat, 25 Jun 2011 00:17:26 +0530 Subject: USB: Gadget: Webcam: Return correct result of bind The config bind was reported success even if usb_add_function failed. Fix the return value. Signed-off-by: Jassi Brar Acked-by: Laurent Pinchart Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/f_uvc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/f_uvc.c b/drivers/usb/gadget/f_uvc.c index df74d031191..7a8b9aa4aea 100644 --- a/drivers/usb/gadget/f_uvc.c +++ b/drivers/usb/gadget/f_uvc.c @@ -651,7 +651,7 @@ uvc_bind_config(struct usb_configuration *c, if (ret) kfree(uvc); - return 0; + return ret; error: kfree(uvc); -- cgit v1.2.3-70-g09d2 From bc8687db894d537283b9e1e37806cca101185e56 Mon Sep 17 00:00:00 2001 From: Tatyana Brokhman Date: Thu, 30 Jun 2011 08:44:42 +0300 Subject: usb: gadget: Compilation warning fix A compilation warning was added by the patch "usb: gadget: use config_ep_by_speed() instead of ep_choose()". This patch fixed it. Signed-off-by: Tatyana Brokhman Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/storage_common.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/storage_common.c b/drivers/usb/gadget/storage_common.c index 1fa4f705b0b..d3dd227a2bf 100644 --- a/drivers/usb/gadget/storage_common.c +++ b/drivers/usb/gadget/storage_common.c @@ -494,7 +494,7 @@ static struct usb_descriptor_header *fsg_hs_function[] = { }; /* Maxpacket and other transfer characteristics vary by speed. */ -static struct usb_endpoint_descriptor * +static __maybe_unused struct usb_endpoint_descriptor * fsg_ep_desc(struct usb_gadget *g, struct usb_endpoint_descriptor *fs, struct usb_endpoint_descriptor *hs) { -- cgit v1.2.3-70-g09d2 From 5b8261385c5c3e5cf70a95c36cce71939b844a16 Mon Sep 17 00:00:00 2001 From: Viliam Mateicka Date: Thu, 16 Jun 2011 10:04:36 +0200 Subject: USB: s3c2410_udc: fix custom UDC command handling There is a bug in Samsung's UDC driver, which is completely disabling the USB device when a custom UDC command is used. Following patch seems to get the right behavior (e.g. enabling pull-up instead of disabling then Vcc is applied). Signed-off-by: Viliam Mateicka Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/s3c2410_udc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/s3c2410_udc.c b/drivers/usb/gadget/s3c2410_udc.c index 394c1a3bbe8..85c1b0d6629 100644 --- a/drivers/usb/gadget/s3c2410_udc.c +++ b/drivers/usb/gadget/s3c2410_udc.c @@ -1573,7 +1573,7 @@ static void s3c2410_udc_command(enum s3c2410_udc_cmd_e cmd) return; if (udc_info->udc_command) { - udc_info->udc_command(S3C2410_UDC_P_DISABLE); + udc_info->udc_command(cmd); } else if (gpio_is_valid(udc_info->pullup_pin)) { int value; -- cgit v1.2.3-70-g09d2 From 4dbafd3dce8593c8ec1a6b78239f59645b4dde8f Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Mon, 4 Jul 2011 11:09:15 +0300 Subject: usb: gadget: fusb300_udc: drop dead code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit that code has been dead forever. Since the first commit (0fe6f1d1) the use of that code has been commented out. Let's drop the dead code already and fix the following compile warning: | drivers/usb/gadget/fusb300_udc.c: At top level: | drivers/usb/gadget/fusb300_udc.c:771:13: warning: ‘fusb300_wrfifo’ defined but not used [-Wunused-function] | drivers/usb/gadget/fusb300_udc.c:1027:13: warning: ‘fusb300_set_ep_bycnt’ defined but not used [-Wunused-function] Signed-off-by: Felipe Balbi --- drivers/usb/gadget/fusb300_udc.c | 69 +--------------------------------------- 1 file changed, 1 insertion(+), 68 deletions(-) (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/fusb300_udc.c b/drivers/usb/gadget/fusb300_udc.c index 06353e7ba1f..4739f5baa36 100644 --- a/drivers/usb/gadget/fusb300_udc.c +++ b/drivers/usb/gadget/fusb300_udc.c @@ -767,56 +767,6 @@ static void fusb300_rdfifo(struct fusb300_ep *ep, } while (!reg); } -/* write data to fifo */ -static void fusb300_wrfifo(struct fusb300_ep *ep, - struct fusb300_request *req) -{ - int i = 0; - u8 *tmp; - u32 data, reg; - struct fusb300 *fusb300 = ep->fusb300; - - tmp = req->req.buf; - req->req.actual = req->req.length; - - for (i = (req->req.length >> 2); i > 0; i--) { - data = *tmp | *(tmp + 1) << 8 | - *(tmp + 2) << 16 | *(tmp + 3) << 24; - - iowrite32(data, fusb300->reg + - FUSB300_OFFSET_EPPORT(ep->epnum)); - tmp += 4; - } - - switch (req->req.length % 4) { - case 1: - data = *tmp; - iowrite32(data, fusb300->reg + - FUSB300_OFFSET_EPPORT(ep->epnum)); - break; - case 2: - data = *tmp | *(tmp + 1) << 8; - iowrite32(data, fusb300->reg + - FUSB300_OFFSET_EPPORT(ep->epnum)); - break; - case 3: - data = *tmp | *(tmp + 1) << 8 | *(tmp + 2) << 16; - iowrite32(data, fusb300->reg + - FUSB300_OFFSET_EPPORT(ep->epnum)); - break; - default: - break; - } - - do { - reg = ioread32(fusb300->reg + FUSB300_OFFSET_IGR1); - reg &= FUSB300_IGR1_SYNF0_EMPTY_INT; - if (i) - printk(KERN_INFO"sync fifo is not empty!\n"); - i++; - } while (!reg); -} - static u8 fusb300_get_epnstall(struct fusb300 *fusb300, u8 ep) { u8 value; @@ -1024,17 +974,6 @@ static int setup_packet(struct fusb300 *fusb300, struct usb_ctrlrequest *ctrl) return ret; } -static void fusb300_set_ep_bycnt(struct fusb300_ep *ep, u32 bycnt) -{ - struct fusb300 *fusb300 = ep->fusb300; - u32 reg = ioread32(fusb300->reg + FUSB300_OFFSET_EPFFR(ep->epnum)); - - reg &= ~FUSB300_FFR_BYCNT; - reg |= bycnt & FUSB300_FFR_BYCNT; - - iowrite32(reg, fusb300->reg + FUSB300_OFFSET_EPFFR(ep->epnum)); -} - static void done(struct fusb300_ep *ep, struct fusb300_request *req, int status) { @@ -1143,14 +1082,8 @@ static void in_ep_fifo_handler(struct fusb300_ep *ep) struct fusb300_request *req = list_entry(ep->queue.next, struct fusb300_request, queue); - if (req->req.length) { -#if 0 - fusb300_set_ep_bycnt(ep, req->req.length); - fusb300_wrfifo(ep, req); -#else + if (req->req.length) fusb300_set_idma(ep, req); -#endif - } done(ep, req, 0); } -- cgit v1.2.3-70-g09d2 From b9af9ea45a8dc1c3e7a98319bac90199807cc258 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Mon, 4 Jul 2011 11:12:32 +0300 Subject: usb: gadget: langwell_udc: fix compile warnings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch fixes the following compile warnings: drivers/usb/gadget/langwell_udc.c: In function ‘queue_dtd’: drivers/usb/gadget/langwell_udc.c:596:2: warning: cast from pointer to integer of different size [-Wpointer-to-int-cast] drivers/usb/gadget/langwell_udc.c: In function ‘langwell_udc_probe’: drivers/usb/gadget/langwell_udc.c:3274:2: warning: format ‘%d’ expects argument of type ‘int’, but argument 4 has type ‘size_t’ [-Wformat] drivers/usb/gadget/langwell_udc.c:3289:2: warning: format ‘%d’ expects argument of type ‘int’, but argument 4 has type ‘size_t’ [-Wformat] drivers/usb/gadget/langwell_udc.c: In function ‘langwell_udc_resume’: drivers/usb/gadget/langwell_udc.c:3473:2: warning: format ‘%d’ expects argument of type ‘int’, but argument 4 has type ‘size_t’ [-Wformat] drivers/usb/gadget/langwell_udc.c:3487:2: warning: format ‘%d’ expects argument of type ‘int’, but argument 4 has type ‘size_t’ [-Wformat] Signed-off-by: Felipe Balbi --- drivers/usb/gadget/langwell_udc.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/langwell_udc.c b/drivers/usb/gadget/langwell_udc.c index d8403ae3c2b..a06e2c27b43 100644 --- a/drivers/usb/gadget/langwell_udc.c +++ b/drivers/usb/gadget/langwell_udc.c @@ -593,8 +593,8 @@ static int queue_dtd(struct langwell_ep *ep, struct langwell_request *req) /* ep0 */ dev_vdbg(&dev->pdev->dev, "%s-%s\n", ep->name, DIR_STRING(ep)); - dev_vdbg(&dev->pdev->dev, "ep_dqh[%d] addr: 0x%08x\n", - i, (u32)&(dev->ep_dqh[i])); + dev_vdbg(&dev->pdev->dev, "ep_dqh[%d] addr: 0x%p\n", + i, &(dev->ep_dqh[i])); bit_mask = is_in(ep) ? (1 << (ep->ep_num + 16)) : (1 << (ep->ep_num)); @@ -3271,7 +3271,7 @@ static int langwell_udc_probe(struct pci_dev *pdev, /* allocate device dQH memory */ size = dev->ep_max * sizeof(struct langwell_dqh); - dev_vdbg(&dev->pdev->dev, "orig size = %d\n", size); + dev_vdbg(&dev->pdev->dev, "orig size = %zd\n", size); if (size < DQH_ALIGNMENT) size = DQH_ALIGNMENT; else if ((size % DQH_ALIGNMENT) != 0) { @@ -3286,7 +3286,7 @@ static int langwell_udc_probe(struct pci_dev *pdev, goto error; } dev->ep_dqh_size = size; - dev_vdbg(&dev->pdev->dev, "ep_dqh_size = %d\n", dev->ep_dqh_size); + dev_vdbg(&dev->pdev->dev, "ep_dqh_size = %zd\n", dev->ep_dqh_size); /* initialize ep0 status request structure */ dev->status_req = kzalloc(sizeof(struct langwell_request), GFP_KERNEL); @@ -3470,7 +3470,7 @@ static int langwell_udc_resume(struct pci_dev *pdev) /* allocate device dQH memory */ size = dev->ep_max * sizeof(struct langwell_dqh); - dev_vdbg(&dev->pdev->dev, "orig size = %d\n", size); + dev_vdbg(&dev->pdev->dev, "orig size = %zd\n", size); if (size < DQH_ALIGNMENT) size = DQH_ALIGNMENT; else if ((size % DQH_ALIGNMENT) != 0) { @@ -3484,7 +3484,7 @@ static int langwell_udc_resume(struct pci_dev *pdev) return -ENOMEM; } dev->ep_dqh_size = size; - dev_vdbg(&dev->pdev->dev, "ep_dqh_size = %d\n", dev->ep_dqh_size); + dev_vdbg(&dev->pdev->dev, "ep_dqh_size = %zd\n", dev->ep_dqh_size); /* create dTD dma_pool resource */ dev->dtd_pool = dma_pool_create("langwell_dtd", -- cgit v1.2.3-70-g09d2 From 7b30d19a5736b930c39cd7212ae9409ac0df525d Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Mon, 4 Jul 2011 11:16:06 +0300 Subject: usb: gadget: net2272: fix compile warnings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch fixes the following compile warnings: drivers/usb/gadget/net2272.c: In function ‘net2272_kick_dma’: drivers/usb/gadget/net2272.c:740:2: warning: format ‘%x’ expects argument of type ‘unsigned int’, but argument 6 has type ‘dma_addr_t’ [-Wformat] drivers/usb/gadget/net2272.c: In function ‘net2272_queue’: drivers/usb/gadget/net2272.c:859:2: warning: format ‘%x’ expects argument of type ‘unsigned int’, but argument 8 has type ‘dma_addr_t’ [-Wformat] Signed-off-by: Felipe Balbi --- drivers/usb/gadget/net2272.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/net2272.c b/drivers/usb/gadget/net2272.c index 6065bdfd83b..7c7b0e120d8 100644 --- a/drivers/usb/gadget/net2272.c +++ b/drivers/usb/gadget/net2272.c @@ -737,8 +737,8 @@ net2272_kick_dma(struct net2272_ep *ep, struct net2272_request *req) if (req->req.length & 1) return -EINVAL; - dev_vdbg(ep->dev->dev, "kick_dma %s req %p dma %08x\n", - ep->ep.name, req, req->req.dma); + dev_vdbg(ep->dev->dev, "kick_dma %s req %p dma %08llx\n", + ep->ep.name, req, (unsigned long long) req->req.dma); net2272_ep_write(ep, EP_RSPSET, 1 << ALT_NAK_OUT_PACKETS); @@ -856,9 +856,9 @@ net2272_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags) req->mapped = 1; } - dev_vdbg(dev->dev, "%s queue req %p, len %d buf %p dma %08x %s\n", + dev_vdbg(dev->dev, "%s queue req %p, len %d buf %p dma %08llx %s\n", _ep->name, _req, _req->length, _req->buf, - _req->dma, _req->zero ? "zero" : "!zero"); + (unsigned long long) _req->dma, _req->zero ? "zero" : "!zero"); spin_lock_irqsave(&dev->lock, flags); -- cgit v1.2.3-70-g09d2 From c2b65f8422a3f51435c9f60f9752a6ed82d47e13 Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Tue, 5 Jul 2011 15:57:52 +0300 Subject: usb: gadget: ci13xx_udc.c: fix compile warning Fix the following compile warning: | usb/gadget/ci13xxx_udc.c: In function 'show_registers': | usb/gadget/ci13xxx_udc.c:1242:1: warning: the frame size of 2064 bytes is larger than 1024 bytes Signed-off-by: Sebastian Andrzej Siewior Signed-off-by: Felipe Balbi --- drivers/usb/gadget/ci13xxx_udc.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/ci13xxx_udc.c b/drivers/usb/gadget/ci13xxx_udc.c index 082471650fb..1265a8502ea 100644 --- a/drivers/usb/gadget/ci13xxx_udc.c +++ b/drivers/usb/gadget/ci13xxx_udc.c @@ -1214,12 +1214,13 @@ static DEVICE_ATTR(qheads, S_IRUSR, show_qheads, NULL); * * Check "device.h" for details */ +#define DUMP_ENTRIES 512 static ssize_t show_registers(struct device *dev, struct device_attribute *attr, char *buf) { struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev); unsigned long flags; - u32 dump[512]; + u32 *dump; unsigned i, k, n = 0; dbg_trace("[%s] %p\n", __func__, buf); @@ -1228,8 +1229,14 @@ static ssize_t show_registers(struct device *dev, return 0; } + dump = kmalloc(sizeof(u32) * DUMP_ENTRIES, GFP_KERNEL); + if (!dump) { + dev_err(dev, "%s: out of memory\n", __func__); + return 0; + } + spin_lock_irqsave(udc->lock, flags); - k = hw_register_read(dump, sizeof(dump)/sizeof(u32)); + k = hw_register_read(dump, DUMP_ENTRIES); spin_unlock_irqrestore(udc->lock, flags); for (i = 0; i < k; i++) { @@ -1237,6 +1244,7 @@ static ssize_t show_registers(struct device *dev, "reg[0x%04X] = 0x%08X\n", i * (unsigned)sizeof(u32), dump[i]); } + kfree(dump); return n; } -- cgit v1.2.3-70-g09d2 From 1425b80e0dc0d4b002aee0705dd78c2efc913fee Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Tue, 5 Jul 2011 15:59:05 +0300 Subject: usb: gadget: fusb300_udc: fix compile warnings - remove pointer u32 abuse in fusb300_fill_idma_prdtbl(). It is assigned the dma_addr to a pointer and then back. Poor families may have to recycle variables but we don't - don't free req.buf in error case. We don't do it in the ok case so it is probably wrong to do it in error case. - return in error case. There is no reason to continue without data and performing ops on an invalid pointer. - The if (d) statement is bogus since an invalid DMA pointer is ~0 on some architecutres. And since we return for the invalid case we don't need it. Signed-off-by: Sebastian Andrzej Siewior Signed-off-by: Felipe Balbi --- drivers/usb/gadget/fusb300_udc.c | 22 +++++++--------------- 1 file changed, 7 insertions(+), 15 deletions(-) (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/fusb300_udc.c b/drivers/usb/gadget/fusb300_udc.c index 4739f5baa36..24a924330c8 100644 --- a/drivers/usb/gadget/fusb300_udc.c +++ b/drivers/usb/gadget/fusb300_udc.c @@ -997,8 +997,8 @@ static void done(struct fusb300_ep *ep, struct fusb300_request *req, fusb300_set_cxdone(ep->fusb300); } -void fusb300_fill_idma_prdtbl(struct fusb300_ep *ep, - struct fusb300_request *req) +static void fusb300_fill_idma_prdtbl(struct fusb300_ep *ep, dma_addr_t d, + u32 len) { u32 value; u32 reg; @@ -1010,10 +1010,9 @@ void fusb300_fill_idma_prdtbl(struct fusb300_ep *ep, reg &= FUSB300_EPPRD0_H; } while (reg); - iowrite32((u32) req->req.buf, ep->fusb300->reg + - FUSB300_OFFSET_EPPRD_W1(ep->epnum)); + iowrite32(d, ep->fusb300->reg + FUSB300_OFFSET_EPPRD_W1(ep->epnum)); - value = FUSB300_EPPRD0_BTC(req->req.length) | FUSB300_EPPRD0_H | + value = FUSB300_EPPRD0_BTC(len) | FUSB300_EPPRD0_H | FUSB300_EPPRD0_F | FUSB300_EPPRD0_L | FUSB300_EPPRD0_I; iowrite32(value, ep->fusb300->reg + FUSB300_OFFSET_EPPRD_W0(ep->epnum)); @@ -1050,13 +1049,12 @@ static void fusb300_set_idma(struct fusb300_ep *ep, struct fusb300_request *req) { dma_addr_t d; - u8 *tmp = NULL; d = dma_map_single(NULL, req->req.buf, req->req.length, DMA_TO_DEVICE); if (dma_mapping_error(NULL, d)) { - kfree(req->req.buf); printk(KERN_DEBUG "dma_mapping_error\n"); + return; } dma_sync_single_for_device(NULL, d, req->req.length, DMA_TO_DEVICE); @@ -1064,17 +1062,11 @@ static void fusb300_set_idma(struct fusb300_ep *ep, fusb300_enable_bit(ep->fusb300, FUSB300_OFFSET_IGER0, FUSB300_IGER0_EEPn_PRD_INT(ep->epnum)); - tmp = req->req.buf; - req->req.buf = (u8 *)d; - - fusb300_fill_idma_prdtbl(ep, req); + fusb300_fill_idma_prdtbl(ep, d, req->req.length); /* check idma is done */ fusb300_wait_idma_finished(ep); - req->req.buf = tmp; - - if (d) - dma_unmap_single(NULL, d, req->req.length, DMA_TO_DEVICE); + dma_unmap_single(NULL, d, req->req.length, DMA_TO_DEVICE); } static void in_ep_fifo_handler(struct fusb300_ep *ep) -- cgit v1.2.3-70-g09d2 From ac17317d209a488059003de00f7cb0e5373a7c6e Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Tue, 5 Jul 2011 16:39:48 +0300 Subject: usb: gadget: fix up depencies Both fusb300 and langwell udcs seem to only work with 32-bit address space. Signed-off-by: Sebastian Andrzej Siewior Signed-off-by: Felipe Balbi --- drivers/usb/gadget/Kconfig | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index 46a253adde3..b0594d90754 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -157,6 +157,7 @@ config USB_FSL_USB2 config USB_FUSB300 tristate "Faraday FUSB300 USB Peripheral Controller" + depends on !PHYS_ADDR_T_64BIT select USB_GADGET_DUALSPEED help Faraday usb device controller FUSB300 driver @@ -425,6 +426,7 @@ config USB_GOKU config USB_LANGWELL tristate "Intel Langwell USB Device Controller" depends on PCI + depends on !PHYS_ADDR_T_64BIT select USB_GADGET_DUALSPEED help Intel Langwell USB Device Controller is a High-Speed USB -- cgit v1.2.3-70-g09d2 From 5db05c09ac107ef957b7a052d7bba8190c93b460 Mon Sep 17 00:00:00 2001 From: Yoshihiro Shimoda Date: Thu, 7 Jul 2011 09:59:07 +0900 Subject: usb: update email address in r8a66597-udc and m66592-udc Signed-off-by: Yoshihiro Shimoda Signed-off-by: Felipe Balbi --- drivers/usb/gadget/m66592-udc.c | 2 +- drivers/usb/gadget/m66592-udc.h | 2 +- drivers/usb/gadget/r8a66597-udc.c | 2 +- drivers/usb/gadget/r8a66597-udc.h | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/m66592-udc.c b/drivers/usb/gadget/m66592-udc.c index 11d37821ce7..dd9f460a7ef 100644 --- a/drivers/usb/gadget/m66592-udc.c +++ b/drivers/usb/gadget/m66592-udc.c @@ -3,7 +3,7 @@ * * Copyright (C) 2006-2007 Renesas Solutions Corp. * - * Author : Yoshihiro Shimoda + * Author : Yoshihiro Shimoda * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/drivers/usb/gadget/m66592-udc.h b/drivers/usb/gadget/m66592-udc.h index c3caf1ac73c..b85e05b2e97 100644 --- a/drivers/usb/gadget/m66592-udc.h +++ b/drivers/usb/gadget/m66592-udc.h @@ -3,7 +3,7 @@ * * Copyright (C) 2006-2007 Renesas Solutions Corp. * - * Author : Yoshihiro Shimoda + * Author : Yoshihiro Shimoda * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/drivers/usb/gadget/r8a66597-udc.c b/drivers/usb/gadget/r8a66597-udc.c index db7a6de8583..7ee69152ec9 100644 --- a/drivers/usb/gadget/r8a66597-udc.c +++ b/drivers/usb/gadget/r8a66597-udc.c @@ -3,7 +3,7 @@ * * Copyright (C) 2006-2009 Renesas Solutions Corp. * - * Author : Yoshihiro Shimoda + * Author : Yoshihiro Shimoda * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/drivers/usb/gadget/r8a66597-udc.h b/drivers/usb/gadget/r8a66597-udc.h index 5fc22e09a0f..503f766c23a 100644 --- a/drivers/usb/gadget/r8a66597-udc.h +++ b/drivers/usb/gadget/r8a66597-udc.h @@ -3,7 +3,7 @@ * * Copyright (C) 2007-2009 Renesas Solutions Corp. * - * Author : Yoshihiro Shimoda + * Author : Yoshihiro Shimoda * * 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 -- cgit v1.2.3-70-g09d2 From deafeb24e8a846da8555e68f4bcf651daa8a4ed1 Mon Sep 17 00:00:00 2001 From: Yoshihiro Shimoda Date: Fri, 8 Jul 2011 14:51:21 +0900 Subject: usb: gadget: r8a66597-udc: fix cannot connect after rmmod gadget driver When we run rmmod a gadget driver, the driver will call disable_controller(). Then, because the bit of USBE in SYSCFG0 was cleared in on_chip=1 mode, we could not connect the usb when we run insmod a gadget driver next time. This patch also cleans up probe() and ->stop() about unnecessary init_controller(). Signed-off-by: Yoshihiro Shimoda Signed-off-by: Felipe Balbi --- drivers/usb/gadget/r8a66597-udc.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/r8a66597-udc.c b/drivers/usb/gadget/r8a66597-udc.c index 7ee69152ec9..4f3f1ce0424 100644 --- a/drivers/usb/gadget/r8a66597-udc.c +++ b/drivers/usb/gadget/r8a66597-udc.c @@ -1444,6 +1444,7 @@ static int r8a66597_start(struct usb_gadget_driver *driver, goto error; } + init_controller(r8a66597); r8a66597_bset(r8a66597, VBSE, INTENB0); if (r8a66597_read(r8a66597, INTSTS0) & VBSTS) { r8a66597_start_xclock(r8a66597); @@ -1474,15 +1475,12 @@ static int r8a66597_stop(struct usb_gadget_driver *driver) spin_lock_irqsave(&r8a66597->lock, flags); if (r8a66597->gadget.speed != USB_SPEED_UNKNOWN) r8a66597_usb_disconnect(r8a66597); - spin_unlock_irqrestore(&r8a66597->lock, flags); - r8a66597_bclr(r8a66597, VBSE, INTENB0); + disable_controller(r8a66597); + spin_unlock_irqrestore(&r8a66597->lock, flags); driver->unbind(&r8a66597->gadget); - init_controller(r8a66597); - disable_controller(r8a66597); - device_del(&r8a66597->gadget.dev); r8a66597->driver = NULL; return 0; @@ -1646,8 +1644,6 @@ static int __init r8a66597_probe(struct platform_device *pdev) goto clean_up3; r8a66597->ep0_req->complete = nop_completion; - init_controller(r8a66597); - ret = usb_add_gadget_udc(&pdev->dev, &r8a66597->gadget); if (ret) goto err_add_udc; -- cgit v1.2.3-70-g09d2 From 5154e9f126c1d2ee8f5f93d9954f83d82b2d5e64 Mon Sep 17 00:00:00 2001 From: Yoshihiro Shimoda Date: Fri, 8 Jul 2011 14:51:27 +0900 Subject: usb: gadget: r8a66597-udc: Make BUSWAIT configurable through platform data BUSWAIT is a 4-bit-wide value that controls the number of access waits from the CPU to on-chip USB module. b'0000 inserts 0 wait (2 access cycles) and b'1111 inserts 15 waits (17 access cycles, hardware initial value), respectively. BUSWAIT value depends on peripheral clock frequency supplied to on-chip of each CPU, hence should be configurable through platform data. Note that this patch assumes that b'0000 (0 wait, 2 access cycles) is rerely used and considered as invalid. If valid 'buswait' data is not provided by platform, initial b'1111 (15 waits, 17 access cycles) will be applied as a safe default. Signed-off-by: Yoshihiro Shimoda Signed-off-by: Felipe Balbi --- drivers/usb/gadget/r8a66597-udc.c | 6 +++++- include/linux/usb/r8a66597.h | 3 +++ 2 files changed, 8 insertions(+), 1 deletion(-) (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/r8a66597-udc.c b/drivers/usb/gadget/r8a66597-udc.c index 4f3f1ce0424..834a0202ae3 100644 --- a/drivers/usb/gadget/r8a66597-udc.c +++ b/drivers/usb/gadget/r8a66597-udc.c @@ -576,7 +576,11 @@ static void init_controller(struct r8a66597 *r8a66597) u16 endian = r8a66597->pdata->endian ? BIGEND : 0; if (r8a66597->pdata->on_chip) { - r8a66597_bset(r8a66597, 0x04, SYSCFG1); + if (r8a66597->pdata->buswait) + r8a66597_write(r8a66597, r8a66597->pdata->buswait, + SYSCFG1); + else + r8a66597_write(r8a66597, 0x0f, SYSCFG1); r8a66597_bset(r8a66597, HSE, SYSCFG0); r8a66597_bclr(r8a66597, USBE, SYSCFG0); diff --git a/include/linux/usb/r8a66597.h b/include/linux/usb/r8a66597.h index 26d21673405..6e1bfaedb6c 100644 --- a/include/linux/usb/r8a66597.h +++ b/include/linux/usb/r8a66597.h @@ -31,6 +31,9 @@ struct r8a66597_platdata { /* This callback can control port power instead of DVSTCTR register. */ void (*port_power)(int port, int power); + /* This parameter is for BUSWAIT */ + u16 buswait; + /* set one = on chip controller, set zero = external controller */ unsigned on_chip:1; -- cgit v1.2.3-70-g09d2 From ceaa0a6eeadfd2f53df121210d99a1f80ee7645e Mon Sep 17 00:00:00 2001 From: Yoshihiro Shimoda Date: Fri, 8 Jul 2011 14:51:33 +0900 Subject: usb: gadget: m66592-udc: add support for TEST_MODE The USB high speed device must support the TEST_MODE, but the driver didn't support it. When we sent the SET_FEATURE for TEST_MODE to the driver, the request was successful, but the module didn't enter the TEST_MODE. Signed-off-by: Yoshihiro Shimoda Signed-off-by: Felipe Balbi --- drivers/usb/gadget/m66592-udc.c | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/m66592-udc.c b/drivers/usb/gadget/m66592-udc.c index dd9f460a7ef..40c2f7a4f8f 100644 --- a/drivers/usb/gadget/m66592-udc.c +++ b/drivers/usb/gadget/m66592-udc.c @@ -691,6 +691,7 @@ static void init_controller(struct m66592 *m66592) static void disable_controller(struct m66592 *m66592) { + m66592_bclr(m66592, M66592_UTST, M66592_TESTMODE); if (!m66592->pdata->on_chip) { m66592_bclr(m66592, M66592_SCKE, M66592_SYSCFG); udelay(1); @@ -1048,10 +1049,30 @@ static void clear_feature(struct m66592 *m66592, struct usb_ctrlrequest *ctrl) static void set_feature(struct m66592 *m66592, struct usb_ctrlrequest *ctrl) { + u16 tmp; + int timeout = 3000; switch (ctrl->bRequestType & USB_RECIP_MASK) { case USB_RECIP_DEVICE: - control_end(m66592, 1); + switch (le16_to_cpu(ctrl->wValue)) { + case USB_DEVICE_TEST_MODE: + control_end(m66592, 1); + /* Wait for the completion of status stage */ + do { + tmp = m66592_read(m66592, M66592_INTSTS0) & + M66592_CTSQ; + udelay(1); + } while (tmp != M66592_CS_IDST || timeout-- > 0); + + if (tmp == M66592_CS_IDST) + m66592_bset(m66592, + le16_to_cpu(ctrl->wIndex >> 8), + M66592_TESTMODE); + break; + default: + pipe_stall(m66592, 0); + break; + } break; case USB_RECIP_INTERFACE: control_end(m66592, 1); -- cgit v1.2.3-70-g09d2 From 96fe53ef5498ba130b2f054f2de38e090ddaa55f Mon Sep 17 00:00:00 2001 From: Yoshihiro Shimoda Date: Fri, 8 Jul 2011 14:51:14 +0900 Subject: usb: gadget: r8a66597-udc: add support for TEST_MODE The USB high speed device must support the TEST_MODE, but the driver didn't support it. When we sent the SET_FEATURE for TEST_MODE to the driver, the request was successful, but the module didn't enter the TEST_MODE. Signed-off-by: Yoshihiro Shimoda Signed-off-by: Felipe Balbi --- drivers/usb/gadget/r8a66597-udc.c | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/r8a66597-udc.c b/drivers/usb/gadget/r8a66597-udc.c index 834a0202ae3..b8b30059f8a 100644 --- a/drivers/usb/gadget/r8a66597-udc.c +++ b/drivers/usb/gadget/r8a66597-udc.c @@ -622,6 +622,7 @@ static void disable_controller(struct r8a66597 *r8a66597) { if (r8a66597->pdata->on_chip) { r8a66597_bset(r8a66597, SCKE, SYSCFG0); + r8a66597_bclr(r8a66597, UTST, TESTMODE); /* disable interrupts */ r8a66597_write(r8a66597, 0, INTENB0); @@ -639,6 +640,7 @@ static void disable_controller(struct r8a66597 *r8a66597) r8a66597_bclr(r8a66597, SCKE, SYSCFG0); } else { + r8a66597_bclr(r8a66597, UTST, TESTMODE); r8a66597_bclr(r8a66597, SCKE, SYSCFG0); udelay(1); r8a66597_bclr(r8a66597, PLLC, SYSCFG0); @@ -1003,10 +1005,29 @@ static void clear_feature(struct r8a66597 *r8a66597, static void set_feature(struct r8a66597 *r8a66597, struct usb_ctrlrequest *ctrl) { + u16 tmp; + int timeout = 3000; switch (ctrl->bRequestType & USB_RECIP_MASK) { case USB_RECIP_DEVICE: - control_end(r8a66597, 1); + switch (le16_to_cpu(ctrl->wValue)) { + case USB_DEVICE_TEST_MODE: + control_end(r8a66597, 1); + /* Wait for the completion of status stage */ + do { + tmp = r8a66597_read(r8a66597, INTSTS0) & CTSQ; + udelay(1); + } while (tmp != CS_IDST || timeout-- > 0); + + if (tmp == CS_IDST) + r8a66597_bset(r8a66597, + le16_to_cpu(ctrl->wIndex >> 8), + TESTMODE); + break; + default: + pipe_stall(r8a66597, 0); + break; + } break; case USB_RECIP_INTERFACE: control_end(r8a66597, 1); -- cgit v1.2.3-70-g09d2 From 04617db7aa688598ebd3fce20691d31a5e778b45 Mon Sep 17 00:00:00 2001 From: Paul Zimmerman Date: Mon, 27 Jun 2011 14:13:18 -0700 Subject: usb: gadget: add SS descriptors to Ethernet gadget Add SuperSpeed descriptors to the Network USB function drivers. This has been lightly tested using a Linux host. I was able to ssh from device to host and host to device, no obvious problems seen. Signed-off-by: Paul Zimmerman Signed-off-by: Felipe Balbi --- drivers/usb/gadget/ether.c | 2 +- drivers/usb/gadget/f_ecm.c | 100 ++++++++++++++++++++++++++++++++++++++++- drivers/usb/gadget/f_eem.c | 56 +++++++++++++++++++++++ drivers/usb/gadget/f_rndis.c | 101 ++++++++++++++++++++++++++++++++++++++++-- drivers/usb/gadget/f_subset.c | 64 ++++++++++++++++++++++++++ drivers/usb/gadget/u_ether.c | 12 ++--- 6 files changed, 324 insertions(+), 11 deletions(-) (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c index ac41858800a..aafc84f33e2 100644 --- a/drivers/usb/gadget/ether.c +++ b/drivers/usb/gadget/ether.c @@ -401,7 +401,7 @@ static struct usb_composite_driver eth_driver = { .name = "g_ether", .dev = &device_desc, .strings = dev_strings, - .max_speed = USB_SPEED_HIGH, + .max_speed = USB_SPEED_SUPER, .unbind = __exit_p(eth_unbind), }; diff --git a/drivers/usb/gadget/f_ecm.c b/drivers/usb/gadget/f_ecm.c index ddedbc83bc3..3691a0cb946 100644 --- a/drivers/usb/gadget/f_ecm.c +++ b/drivers/usb/gadget/f_ecm.c @@ -77,10 +77,12 @@ static inline struct f_ecm *func_to_ecm(struct usb_function *f) /* peak (theoretical) bulk transfer rate in bits-per-second */ static inline unsigned ecm_bitrate(struct usb_gadget *g) { - if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH) + if (gadget_is_superspeed(g) && g->speed == USB_SPEED_SUPER) + return 13 * 1024 * 8 * 1000 * 8; + else if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH) return 13 * 512 * 8 * 1000 * 8; else - return 19 * 64 * 1 * 1000 * 8; + return 19 * 64 * 1 * 1000 * 8; } /*-------------------------------------------------------------------------*/ @@ -210,8 +212,10 @@ static struct usb_descriptor_header *ecm_fs_function[] = { (struct usb_descriptor_header *) &ecm_header_desc, (struct usb_descriptor_header *) &ecm_union_desc, (struct usb_descriptor_header *) &ecm_desc, + /* NOTE: status endpoint might need to be removed */ (struct usb_descriptor_header *) &fs_ecm_notify_desc, + /* data interface, altsettings 0 and 1 */ (struct usb_descriptor_header *) &ecm_data_nop_intf, (struct usb_descriptor_header *) &ecm_data_intf, @@ -231,6 +235,7 @@ static struct usb_endpoint_descriptor hs_ecm_notify_desc = { .wMaxPacketSize = cpu_to_le16(ECM_STATUS_BYTECOUNT), .bInterval = LOG2_STATUS_INTERVAL_MSEC + 4, }; + static struct usb_endpoint_descriptor hs_ecm_in_desc = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, @@ -255,8 +260,10 @@ static struct usb_descriptor_header *ecm_hs_function[] = { (struct usb_descriptor_header *) &ecm_header_desc, (struct usb_descriptor_header *) &ecm_union_desc, (struct usb_descriptor_header *) &ecm_desc, + /* NOTE: status endpoint might need to be removed */ (struct usb_descriptor_header *) &hs_ecm_notify_desc, + /* data interface, altsettings 0 and 1 */ (struct usb_descriptor_header *) &ecm_data_nop_intf, (struct usb_descriptor_header *) &ecm_data_intf, @@ -265,6 +272,76 @@ static struct usb_descriptor_header *ecm_hs_function[] = { NULL, }; +/* super speed support: */ + +static struct usb_endpoint_descriptor ss_ecm_notify_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + + .bEndpointAddress = USB_DIR_IN, + .bmAttributes = USB_ENDPOINT_XFER_INT, + .wMaxPacketSize = cpu_to_le16(ECM_STATUS_BYTECOUNT), + .bInterval = LOG2_STATUS_INTERVAL_MSEC + 4, +}; + +static struct usb_ss_ep_comp_descriptor ss_ecm_intr_comp_desc = { + .bLength = sizeof ss_ecm_intr_comp_desc, + .bDescriptorType = USB_DT_SS_ENDPOINT_COMP, + + /* the following 3 values can be tweaked if necessary */ + /* .bMaxBurst = 0, */ + /* .bmAttributes = 0, */ + .wBytesPerInterval = cpu_to_le16(ECM_STATUS_BYTECOUNT), +}; + +static struct usb_endpoint_descriptor ss_ecm_in_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + + .bEndpointAddress = USB_DIR_IN, + .bmAttributes = USB_ENDPOINT_XFER_BULK, + .wMaxPacketSize = cpu_to_le16(1024), +}; + +static struct usb_endpoint_descriptor ss_ecm_out_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + + .bEndpointAddress = USB_DIR_OUT, + .bmAttributes = USB_ENDPOINT_XFER_BULK, + .wMaxPacketSize = cpu_to_le16(1024), +}; + +static struct usb_ss_ep_comp_descriptor ss_ecm_bulk_comp_desc = { + .bLength = sizeof ss_ecm_bulk_comp_desc, + .bDescriptorType = USB_DT_SS_ENDPOINT_COMP, + + /* the following 2 values can be tweaked if necessary */ + /* .bMaxBurst = 0, */ + /* .bmAttributes = 0, */ +}; + +static struct usb_descriptor_header *ecm_ss_function[] = { + /* CDC ECM control descriptors */ + (struct usb_descriptor_header *) &ecm_control_intf, + (struct usb_descriptor_header *) &ecm_header_desc, + (struct usb_descriptor_header *) &ecm_union_desc, + (struct usb_descriptor_header *) &ecm_desc, + + /* NOTE: status endpoint might need to be removed */ + (struct usb_descriptor_header *) &ss_ecm_notify_desc, + (struct usb_descriptor_header *) &ss_ecm_intr_comp_desc, + + /* data interface, altsettings 0 and 1 */ + (struct usb_descriptor_header *) &ecm_data_nop_intf, + (struct usb_descriptor_header *) &ecm_data_intf, + (struct usb_descriptor_header *) &ss_ecm_in_desc, + (struct usb_descriptor_header *) &ss_ecm_bulk_comp_desc, + (struct usb_descriptor_header *) &ss_ecm_out_desc, + (struct usb_descriptor_header *) &ss_ecm_bulk_comp_desc, + NULL, +}; + /* string descriptors: */ static struct usb_string ecm_string_defs[] = { @@ -679,6 +756,20 @@ ecm_bind(struct usb_configuration *c, struct usb_function *f) goto fail; } + if (gadget_is_superspeed(c->cdev->gadget)) { + ss_ecm_in_desc.bEndpointAddress = + fs_ecm_in_desc.bEndpointAddress; + ss_ecm_out_desc.bEndpointAddress = + fs_ecm_out_desc.bEndpointAddress; + ss_ecm_notify_desc.bEndpointAddress = + fs_ecm_notify_desc.bEndpointAddress; + + /* copy descriptors, and track endpoint copies */ + f->ss_descriptors = usb_copy_descriptors(ecm_ss_function); + if (!f->ss_descriptors) + goto fail; + } + /* NOTE: all that is done without knowing or caring about * the network link ... which is unavailable to this code * until we're activated via set_alt(). @@ -688,6 +779,7 @@ ecm_bind(struct usb_configuration *c, struct usb_function *f) ecm->port.close = ecm_close; DBG(cdev, "CDC Ethernet: %s speed IN/%s OUT/%s NOTIFY/%s\n", + gadget_is_superspeed(c->cdev->gadget) ? "super" : gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full", ecm->port.in_ep->name, ecm->port.out_ep->name, ecm->notify->name); @@ -696,6 +788,8 @@ ecm_bind(struct usb_configuration *c, struct usb_function *f) fail: if (f->descriptors) usb_free_descriptors(f->descriptors); + if (f->hs_descriptors) + usb_free_descriptors(f->hs_descriptors); if (ecm->notify_req) { kfree(ecm->notify_req->buf); @@ -722,6 +816,8 @@ ecm_unbind(struct usb_configuration *c, struct usb_function *f) DBG(c->cdev, "ecm unbind\n"); + if (gadget_is_superspeed(c->cdev->gadget)) + usb_free_descriptors(f->ss_descriptors); if (gadget_is_dualspeed(c->cdev->gadget)) usb_free_descriptors(f->hs_descriptors); usb_free_descriptors(f->descriptors); diff --git a/drivers/usb/gadget/f_eem.c b/drivers/usb/gadget/f_eem.c index 3e412740e2e..046c6d0e696 100644 --- a/drivers/usb/gadget/f_eem.c +++ b/drivers/usb/gadget/f_eem.c @@ -115,6 +115,45 @@ static struct usb_descriptor_header *eem_hs_function[] __initdata = { NULL, }; +/* super speed support: */ + +static struct usb_endpoint_descriptor eem_ss_in_desc __initdata = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + + .bEndpointAddress = USB_DIR_IN, + .bmAttributes = USB_ENDPOINT_XFER_BULK, + .wMaxPacketSize = cpu_to_le16(1024), +}; + +static struct usb_endpoint_descriptor eem_ss_out_desc __initdata = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + + .bEndpointAddress = USB_DIR_OUT, + .bmAttributes = USB_ENDPOINT_XFER_BULK, + .wMaxPacketSize = cpu_to_le16(1024), +}; + +static struct usb_ss_ep_comp_descriptor eem_ss_bulk_comp_desc __initdata = { + .bLength = sizeof eem_ss_bulk_comp_desc, + .bDescriptorType = USB_DT_SS_ENDPOINT_COMP, + + /* the following 2 values can be tweaked if necessary */ + /* .bMaxBurst = 0, */ + /* .bmAttributes = 0, */ +}; + +static struct usb_descriptor_header *eem_ss_function[] __initdata = { + /* CDC EEM control descriptors */ + (struct usb_descriptor_header *) &eem_intf, + (struct usb_descriptor_header *) &eem_ss_in_desc, + (struct usb_descriptor_header *) &eem_ss_bulk_comp_desc, + (struct usb_descriptor_header *) &eem_ss_out_desc, + (struct usb_descriptor_header *) &eem_ss_bulk_comp_desc, + NULL, +}; + /* string descriptors: */ static struct usb_string eem_string_defs[] = { @@ -265,7 +304,20 @@ eem_bind(struct usb_configuration *c, struct usb_function *f) goto fail; } + if (gadget_is_superspeed(c->cdev->gadget)) { + eem_ss_in_desc.bEndpointAddress = + eem_fs_in_desc.bEndpointAddress; + eem_ss_out_desc.bEndpointAddress = + eem_fs_out_desc.bEndpointAddress; + + /* copy descriptors, and track endpoint copies */ + f->ss_descriptors = usb_copy_descriptors(eem_ss_function); + if (!f->ss_descriptors) + goto fail; + } + DBG(cdev, "CDC Ethernet (EEM): %s speed IN/%s OUT/%s\n", + gadget_is_superspeed(c->cdev->gadget) ? "super" : gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full", eem->port.in_ep->name, eem->port.out_ep->name); return 0; @@ -273,6 +325,8 @@ eem_bind(struct usb_configuration *c, struct usb_function *f) fail: if (f->descriptors) usb_free_descriptors(f->descriptors); + if (f->hs_descriptors) + usb_free_descriptors(f->hs_descriptors); /* we might as well release our claims on endpoints */ if (eem->port.out_ep->desc) @@ -292,6 +346,8 @@ eem_unbind(struct usb_configuration *c, struct usb_function *f) DBG(c->cdev, "eem unbind\n"); + if (gadget_is_superspeed(c->cdev->gadget)) + usb_free_descriptors(f->ss_descriptors); if (gadget_is_dualspeed(c->cdev->gadget)) usb_free_descriptors(f->hs_descriptors); usb_free_descriptors(f->descriptors); diff --git a/drivers/usb/gadget/f_rndis.c b/drivers/usb/gadget/f_rndis.c index b324efa0773..8f3eae90919 100644 --- a/drivers/usb/gadget/f_rndis.c +++ b/drivers/usb/gadget/f_rndis.c @@ -95,10 +95,12 @@ static inline struct f_rndis *func_to_rndis(struct usb_function *f) /* peak (theoretical) bulk transfer rate in bits-per-second */ static unsigned int bitrate(struct usb_gadget *g) { - if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH) + if (gadget_is_superspeed(g) && g->speed == USB_SPEED_SUPER) + return 13 * 1024 * 8 * 1000 * 8; + else if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH) return 13 * 512 * 8 * 1000 * 8; else - return 19 * 64 * 1 * 1000 * 8; + return 19 * 64 * 1 * 1000 * 8; } /*-------------------------------------------------------------------------*/ @@ -216,6 +218,7 @@ static struct usb_endpoint_descriptor fs_out_desc = { static struct usb_descriptor_header *eth_fs_function[] = { (struct usb_descriptor_header *) &rndis_iad_descriptor, + /* control interface matches ACM, not Ethernet */ (struct usb_descriptor_header *) &rndis_control_intf, (struct usb_descriptor_header *) &header_desc, @@ -223,6 +226,7 @@ static struct usb_descriptor_header *eth_fs_function[] = { (struct usb_descriptor_header *) &rndis_acm_descriptor, (struct usb_descriptor_header *) &rndis_union_desc, (struct usb_descriptor_header *) &fs_notify_desc, + /* data interface has no altsetting */ (struct usb_descriptor_header *) &rndis_data_intf, (struct usb_descriptor_header *) &fs_in_desc, @@ -241,6 +245,7 @@ static struct usb_endpoint_descriptor hs_notify_desc = { .wMaxPacketSize = cpu_to_le16(STATUS_BYTECOUNT), .bInterval = LOG2_STATUS_INTERVAL_MSEC + 4, }; + static struct usb_endpoint_descriptor hs_in_desc = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, @@ -261,6 +266,7 @@ static struct usb_endpoint_descriptor hs_out_desc = { static struct usb_descriptor_header *eth_hs_function[] = { (struct usb_descriptor_header *) &rndis_iad_descriptor, + /* control interface matches ACM, not Ethernet */ (struct usb_descriptor_header *) &rndis_control_intf, (struct usb_descriptor_header *) &header_desc, @@ -268,6 +274,7 @@ static struct usb_descriptor_header *eth_hs_function[] = { (struct usb_descriptor_header *) &rndis_acm_descriptor, (struct usb_descriptor_header *) &rndis_union_desc, (struct usb_descriptor_header *) &hs_notify_desc, + /* data interface has no altsetting */ (struct usb_descriptor_header *) &rndis_data_intf, (struct usb_descriptor_header *) &hs_in_desc, @@ -275,6 +282,76 @@ static struct usb_descriptor_header *eth_hs_function[] = { NULL, }; +/* super speed support: */ + +static struct usb_endpoint_descriptor ss_notify_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + + .bEndpointAddress = USB_DIR_IN, + .bmAttributes = USB_ENDPOINT_XFER_INT, + .wMaxPacketSize = cpu_to_le16(STATUS_BYTECOUNT), + .bInterval = LOG2_STATUS_INTERVAL_MSEC + 4, +}; + +static struct usb_ss_ep_comp_descriptor ss_intr_comp_desc = { + .bLength = sizeof ss_intr_comp_desc, + .bDescriptorType = USB_DT_SS_ENDPOINT_COMP, + + /* the following 3 values can be tweaked if necessary */ + /* .bMaxBurst = 0, */ + /* .bmAttributes = 0, */ + .wBytesPerInterval = cpu_to_le16(STATUS_BYTECOUNT), +}; + +static struct usb_endpoint_descriptor ss_in_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + + .bEndpointAddress = USB_DIR_IN, + .bmAttributes = USB_ENDPOINT_XFER_BULK, + .wMaxPacketSize = cpu_to_le16(1024), +}; + +static struct usb_endpoint_descriptor ss_out_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + + .bEndpointAddress = USB_DIR_OUT, + .bmAttributes = USB_ENDPOINT_XFER_BULK, + .wMaxPacketSize = cpu_to_le16(1024), +}; + +static struct usb_ss_ep_comp_descriptor ss_bulk_comp_desc = { + .bLength = sizeof ss_bulk_comp_desc, + .bDescriptorType = USB_DT_SS_ENDPOINT_COMP, + + /* the following 2 values can be tweaked if necessary */ + /* .bMaxBurst = 0, */ + /* .bmAttributes = 0, */ +}; + +static struct usb_descriptor_header *eth_ss_function[] = { + (struct usb_descriptor_header *) &rndis_iad_descriptor, + + /* control interface matches ACM, not Ethernet */ + (struct usb_descriptor_header *) &rndis_control_intf, + (struct usb_descriptor_header *) &header_desc, + (struct usb_descriptor_header *) &call_mgmt_descriptor, + (struct usb_descriptor_header *) &rndis_acm_descriptor, + (struct usb_descriptor_header *) &rndis_union_desc, + (struct usb_descriptor_header *) &ss_notify_desc, + (struct usb_descriptor_header *) &ss_intr_comp_desc, + + /* data interface has no altsetting */ + (struct usb_descriptor_header *) &rndis_data_intf, + (struct usb_descriptor_header *) &ss_in_desc, + (struct usb_descriptor_header *) &ss_bulk_comp_desc, + (struct usb_descriptor_header *) &ss_out_desc, + (struct usb_descriptor_header *) &ss_bulk_comp_desc, + NULL, +}; + /* string descriptors: */ static struct usb_string rndis_string_defs[] = { @@ -670,11 +747,24 @@ rndis_bind(struct usb_configuration *c, struct usb_function *f) /* copy descriptors, and track endpoint copies */ f->hs_descriptors = usb_copy_descriptors(eth_hs_function); - if (!f->hs_descriptors) goto fail; } + if (gadget_is_superspeed(c->cdev->gadget)) { + ss_in_desc.bEndpointAddress = + fs_in_desc.bEndpointAddress; + ss_out_desc.bEndpointAddress = + fs_out_desc.bEndpointAddress; + ss_notify_desc.bEndpointAddress = + fs_notify_desc.bEndpointAddress; + + /* copy descriptors, and track endpoint copies */ + f->ss_descriptors = usb_copy_descriptors(eth_ss_function); + if (!f->ss_descriptors) + goto fail; + } + rndis->port.open = rndis_open; rndis->port.close = rndis_close; @@ -699,12 +789,15 @@ rndis_bind(struct usb_configuration *c, struct usb_function *f) */ DBG(cdev, "RNDIS: %s speed IN/%s OUT/%s NOTIFY/%s\n", + gadget_is_superspeed(c->cdev->gadget) ? "super" : gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full", rndis->port.in_ep->name, rndis->port.out_ep->name, rndis->notify->name); return 0; fail: + if (gadget_is_superspeed(c->cdev->gadget) && f->ss_descriptors) + usb_free_descriptors(f->ss_descriptors); if (gadget_is_dualspeed(c->cdev->gadget) && f->hs_descriptors) usb_free_descriptors(f->hs_descriptors); if (f->descriptors) @@ -736,6 +829,8 @@ rndis_unbind(struct usb_configuration *c, struct usb_function *f) rndis_deregister(rndis->config); rndis_exit(); + if (gadget_is_superspeed(c->cdev->gadget)) + usb_free_descriptors(f->ss_descriptors); if (gadget_is_dualspeed(c->cdev->gadget)) usb_free_descriptors(f->hs_descriptors); usb_free_descriptors(f->descriptors); diff --git a/drivers/usb/gadget/f_subset.c b/drivers/usb/gadget/f_subset.c index 93bf676ef50..3dc53754ab6 100644 --- a/drivers/usb/gadget/f_subset.c +++ b/drivers/usb/gadget/f_subset.c @@ -201,6 +201,46 @@ static struct usb_descriptor_header *hs_eth_function[] __initdata = { NULL, }; +/* super speed support: */ + +static struct usb_endpoint_descriptor ss_subset_in_desc __initdata = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + + .bmAttributes = USB_ENDPOINT_XFER_BULK, + .wMaxPacketSize = cpu_to_le16(1024), +}; + +static struct usb_endpoint_descriptor ss_subset_out_desc __initdata = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + + .bmAttributes = USB_ENDPOINT_XFER_BULK, + .wMaxPacketSize = cpu_to_le16(1024), +}; + +static struct usb_ss_ep_comp_descriptor ss_subset_bulk_comp_desc __initdata = { + .bLength = sizeof ss_subset_bulk_comp_desc, + .bDescriptorType = USB_DT_SS_ENDPOINT_COMP, + + /* the following 2 values can be tweaked if necessary */ + /* .bMaxBurst = 0, */ + /* .bmAttributes = 0, */ +}; + +static struct usb_descriptor_header *ss_eth_function[] __initdata = { + (struct usb_descriptor_header *) &subset_data_intf, + (struct usb_descriptor_header *) &mdlm_header_desc, + (struct usb_descriptor_header *) &mdlm_desc, + (struct usb_descriptor_header *) &mdlm_detail_desc, + (struct usb_descriptor_header *) ðer_desc, + (struct usb_descriptor_header *) &ss_subset_in_desc, + (struct usb_descriptor_header *) &ss_subset_bulk_comp_desc, + (struct usb_descriptor_header *) &ss_subset_out_desc, + (struct usb_descriptor_header *) &ss_subset_bulk_comp_desc, + NULL, +}; + /* string descriptors: */ static struct usb_string geth_string_defs[] = { @@ -290,6 +330,8 @@ geth_bind(struct usb_configuration *c, struct usb_function *f) /* copy descriptors, and track endpoint copies */ f->descriptors = usb_copy_descriptors(fs_eth_function); + if (!f->descriptors) + goto fail; /* support all relevant hardware speeds... we expect that when * hardware is dual speed, all bulk-capable endpoints work at @@ -303,6 +345,20 @@ geth_bind(struct usb_configuration *c, struct usb_function *f) /* copy descriptors, and track endpoint copies */ f->hs_descriptors = usb_copy_descriptors(hs_eth_function); + if (!f->hs_descriptors) + goto fail; + } + + if (gadget_is_superspeed(c->cdev->gadget)) { + ss_subset_in_desc.bEndpointAddress = + fs_subset_in_desc.bEndpointAddress; + ss_subset_out_desc.bEndpointAddress = + fs_subset_out_desc.bEndpointAddress; + + /* copy descriptors, and track endpoint copies */ + f->ss_descriptors = usb_copy_descriptors(ss_eth_function); + if (!f->ss_descriptors) + goto fail; } /* NOTE: all that is done without knowing or caring about @@ -311,11 +367,17 @@ geth_bind(struct usb_configuration *c, struct usb_function *f) */ DBG(cdev, "CDC Subset: %s speed IN/%s OUT/%s\n", + gadget_is_superspeed(c->cdev->gadget) ? "super" : gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full", geth->port.in_ep->name, geth->port.out_ep->name); return 0; fail: + if (f->descriptors) + usb_free_descriptors(f->descriptors); + if (f->hs_descriptors) + usb_free_descriptors(f->hs_descriptors); + /* we might as well release our claims on endpoints */ if (geth->port.out_ep->desc) geth->port.out_ep->driver_data = NULL; @@ -330,6 +392,8 @@ fail: static void geth_unbind(struct usb_configuration *c, struct usb_function *f) { + if (gadget_is_superspeed(c->cdev->gadget)) + usb_free_descriptors(f->ss_descriptors); if (gadget_is_dualspeed(c->cdev->gadget)) usb_free_descriptors(f->hs_descriptors); usb_free_descriptors(f->descriptors); diff --git a/drivers/usb/gadget/u_ether.c b/drivers/usb/gadget/u_ether.c index b91363e88db..dfed4c1d96c 100644 --- a/drivers/usb/gadget/u_ether.c +++ b/drivers/usb/gadget/u_ether.c @@ -97,16 +97,17 @@ struct eth_dev { static unsigned qmult = 5; module_param(qmult, uint, S_IRUGO|S_IWUSR); -MODULE_PARM_DESC(qmult, "queue length multiplier at high speed"); +MODULE_PARM_DESC(qmult, "queue length multiplier at high/super speed"); #else /* full speed (low speed doesn't do bulk) */ #define qmult 1 #endif -/* for dual-speed hardware, use deeper queues at highspeed */ +/* for dual-speed hardware, use deeper queues at high/super speed */ static inline int qlen(struct usb_gadget *gadget) { - if (gadget_is_dualspeed(gadget) && gadget->speed == USB_SPEED_HIGH) + if (gadget_is_dualspeed(gadget) && (gadget->speed == USB_SPEED_HIGH || + gadget->speed == USB_SPEED_SUPER)) return qmult * DEFAULT_QLEN; else return DEFAULT_QLEN; @@ -598,9 +599,10 @@ static netdev_tx_t eth_start_xmit(struct sk_buff *skb, req->length = length; - /* throttle highspeed IRQ rate back slightly */ + /* throttle high/super speed IRQ rate back slightly */ if (gadget_is_dualspeed(dev->gadget)) - req->no_interrupt = (dev->gadget->speed == USB_SPEED_HIGH) + req->no_interrupt = (dev->gadget->speed == USB_SPEED_HIGH || + dev->gadget->speed == USB_SPEED_SUPER) ? ((atomic_read(&dev->tx_qlen) % qmult) != 0) : 0; -- cgit v1.2.3-70-g09d2 From 57c97c02de0e7a59cb48d3d7666f4afaf9968e84 Mon Sep 17 00:00:00 2001 From: Amit Blay Date: Sun, 3 Jul 2011 17:29:31 +0300 Subject: usb: gadget: zero: add superspeed support This patch adds SuperSpeed descriptors to the g_zero gadget. The SuperSpeed descriptors were added both for f_soursesink and f_loopback function drivers. Signed-off-by: Tatyana Brokhman Signed-off-by: Amit Blay Signed-off-by: Felipe Balbi --- drivers/usb/gadget/f_loopback.c | 55 ++++++++++++++++++++++++++++++++++++++- drivers/usb/gadget/f_sourcesink.c | 55 ++++++++++++++++++++++++++++++++++++++- drivers/usb/gadget/zero.c | 2 +- 3 files changed, 109 insertions(+), 3 deletions(-) (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/f_loopback.c b/drivers/usb/gadget/f_loopback.c index 375632659a0..ca660d40b11 100644 --- a/drivers/usb/gadget/f_loopback.c +++ b/drivers/usb/gadget/f_loopback.c @@ -118,6 +118,49 @@ static struct usb_descriptor_header *hs_loopback_descs[] = { NULL, }; +/* super speed support: */ + +static struct usb_endpoint_descriptor ss_loop_source_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + + .bmAttributes = USB_ENDPOINT_XFER_BULK, + .wMaxPacketSize = cpu_to_le16(1024), +}; + +struct usb_ss_ep_comp_descriptor ss_loop_source_comp_desc = { + .bLength = USB_DT_SS_EP_COMP_SIZE, + .bDescriptorType = USB_DT_SS_ENDPOINT_COMP, + .bMaxBurst = 0, + .bmAttributes = 0, + .wBytesPerInterval = 0, +}; + +static struct usb_endpoint_descriptor ss_loop_sink_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + + .bmAttributes = USB_ENDPOINT_XFER_BULK, + .wMaxPacketSize = cpu_to_le16(1024), +}; + +struct usb_ss_ep_comp_descriptor ss_loop_sink_comp_desc = { + .bLength = USB_DT_SS_EP_COMP_SIZE, + .bDescriptorType = USB_DT_SS_ENDPOINT_COMP, + .bMaxBurst = 0, + .bmAttributes = 0, + .wBytesPerInterval = 0, +}; + +static struct usb_descriptor_header *ss_loopback_descs[] = { + (struct usb_descriptor_header *) &loopback_intf, + (struct usb_descriptor_header *) &ss_loop_source_desc, + (struct usb_descriptor_header *) &ss_loop_source_comp_desc, + (struct usb_descriptor_header *) &ss_loop_sink_desc, + (struct usb_descriptor_header *) &ss_loop_sink_comp_desc, + NULL, +}; + /* function-specific strings: */ static struct usb_string strings_loopback[] = { @@ -175,8 +218,18 @@ autoconf_fail: f->hs_descriptors = hs_loopback_descs; } + /* support super speed hardware */ + if (gadget_is_superspeed(c->cdev->gadget)) { + ss_loop_source_desc.bEndpointAddress = + fs_loop_source_desc.bEndpointAddress; + ss_loop_sink_desc.bEndpointAddress = + fs_loop_sink_desc.bEndpointAddress; + f->ss_descriptors = ss_loopback_descs; + } + DBG(cdev, "%s speed %s: IN/%s, OUT/%s\n", - gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full", + (gadget_is_superspeed(c->cdev->gadget) ? "super" : + (gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full")), f->name, loop->in_ep->name, loop->out_ep->name); return 0; } diff --git a/drivers/usb/gadget/f_sourcesink.c b/drivers/usb/gadget/f_sourcesink.c index 5a92883f4c8..e18b4f52095 100644 --- a/drivers/usb/gadget/f_sourcesink.c +++ b/drivers/usb/gadget/f_sourcesink.c @@ -131,6 +131,49 @@ static struct usb_descriptor_header *hs_source_sink_descs[] = { NULL, }; +/* super speed support: */ + +static struct usb_endpoint_descriptor ss_source_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + + .bmAttributes = USB_ENDPOINT_XFER_BULK, + .wMaxPacketSize = cpu_to_le16(1024), +}; + +struct usb_ss_ep_comp_descriptor ss_source_comp_desc = { + .bLength = USB_DT_SS_EP_COMP_SIZE, + .bDescriptorType = USB_DT_SS_ENDPOINT_COMP, + .bMaxBurst = 0, + .bmAttributes = 0, + .wBytesPerInterval = 0, +}; + +static struct usb_endpoint_descriptor ss_sink_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + + .bmAttributes = USB_ENDPOINT_XFER_BULK, + .wMaxPacketSize = cpu_to_le16(1024), +}; + +struct usb_ss_ep_comp_descriptor ss_sink_comp_desc = { + .bLength = USB_DT_SS_EP_COMP_SIZE, + .bDescriptorType = USB_DT_SS_ENDPOINT_COMP, + .bMaxBurst = 0, + .bmAttributes = 0, + .wBytesPerInterval = 0, +}; + +static struct usb_descriptor_header *ss_source_sink_descs[] = { + (struct usb_descriptor_header *) &source_sink_intf, + (struct usb_descriptor_header *) &ss_source_desc, + (struct usb_descriptor_header *) &ss_source_comp_desc, + (struct usb_descriptor_header *) &ss_sink_desc, + (struct usb_descriptor_header *) &ss_sink_comp_desc, + NULL, +}; + /* function-specific strings: */ static struct usb_string strings_sourcesink[] = { @@ -187,8 +230,18 @@ autoconf_fail: f->hs_descriptors = hs_source_sink_descs; } + /* support super speed hardware */ + if (gadget_is_superspeed(c->cdev->gadget)) { + ss_source_desc.bEndpointAddress = + fs_source_desc.bEndpointAddress; + ss_sink_desc.bEndpointAddress = + fs_sink_desc.bEndpointAddress; + f->ss_descriptors = ss_source_sink_descs; + } + DBG(cdev, "%s speed %s: IN/%s, OUT/%s\n", - gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full", + (gadget_is_superspeed(c->cdev->gadget) ? "super" : + (gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full")), f->name, ss->in_ep->name, ss->out_ep->name); return 0; } diff --git a/drivers/usb/gadget/zero.c b/drivers/usb/gadget/zero.c index af7e7c3818d..00e2fd2d479 100644 --- a/drivers/usb/gadget/zero.c +++ b/drivers/usb/gadget/zero.c @@ -340,7 +340,7 @@ static struct usb_composite_driver zero_driver = { .name = "zero", .dev = &device_desc, .strings = dev_strings, - .max_speed = USB_SPEED_HIGH, + .max_speed = USB_SPEED_SUPER, .unbind = zero_unbind, .suspend = zero_suspend, .resume = zero_resume, -- cgit v1.2.3-70-g09d2 From 030ed1fcb0279953d142665e89bb89ecfb0960f6 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 7 Jul 2011 02:17:37 -0700 Subject: usb: renesas_usbhs: compile/config are rescued This patch rescues renesas_usbhs compile from commit 193ab2a (usb: gadget: allow multiple gadgets to be built) CONFIG_USB_RENESAS_USBHS compile renesas_usbhs main code which is shared between Host/Gadget. CONFIG_USB_RENESAS_USBHS_UDC add mod_gadget to it. It had lost USB_GADGET_DUALSPEED Signed-off-by: Kuninori Morimoto Signed-off-by: Felipe Balbi Signed-off-by: Greg Kroah-Hartman --- drivers/usb/Kconfig | 2 ++ drivers/usb/gadget/Kconfig | 4 +++- drivers/usb/renesas_usbhs/Kconfig | 15 +++++++++++++++ 3 files changed, 20 insertions(+), 1 deletion(-) create mode 100644 drivers/usb/renesas_usbhs/Kconfig (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig index 8cd999a217b..48f1781352f 100644 --- a/drivers/usb/Kconfig +++ b/drivers/usb/Kconfig @@ -118,6 +118,8 @@ source "drivers/usb/host/Kconfig" source "drivers/usb/musb/Kconfig" +source "drivers/usb/renesas_usbhs/Kconfig" + source "drivers/usb/class/Kconfig" source "drivers/usb/storage/Kconfig" diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index 46a253adde3..b5b8d67f656 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -215,9 +215,11 @@ config USB_R8A66597 dynamically linked module called "r8a66597_udc" and force all gadget drivers to also be dynamically linked. -config USB_RENESAS_USBHS +config USB_RENESAS_USBHS_UDC tristate 'Renesas USBHS controller' depends on SUPERH || ARCH_SHMOBILE + depends on USB_RENESAS_USBHS + select USB_GADGET_DUALSPEED help Renesas USBHS is a discrete USB host and peripheral controller chip that supports both full and high speed USB 2.0 data transfers. diff --git a/drivers/usb/renesas_usbhs/Kconfig b/drivers/usb/renesas_usbhs/Kconfig new file mode 100644 index 00000000000..286cbf1ca7d --- /dev/null +++ b/drivers/usb/renesas_usbhs/Kconfig @@ -0,0 +1,15 @@ +# +# Renesas USBHS Controller Drivers +# + +config USB_RENESAS_USBHS + tristate 'Renesas USBHS controller' + depends on SUPERH || ARCH_SHMOBILE + default n + help + Renesas USBHS is a discrete USB host and peripheral controller chip + that supports both full and high speed USB 2.0 data transfers. + It has nine or more configurable endpoints, and endpoint zero. + + Say "y" to link the driver statically, or "m" to build a + dynamically linked module called "renesas_usbhs" -- cgit v1.2.3-70-g09d2 From 8ca137562a79f573f822f5a84a4e56a0d8cc6792 Mon Sep 17 00:00:00 2001 From: Yoshihiro Shimoda Date: Thu, 7 Jul 2011 09:58:20 +0900 Subject: usb: gadget: r8a66597-udc: add pullup function Signed-off-by: Yoshihiro Shimoda Signed-off-by: Felipe Balbi --- drivers/usb/gadget/r8a66597-udc.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/r8a66597-udc.c b/drivers/usb/gadget/r8a66597-udc.c index b8b30059f8a..50991e5bd5e 100644 --- a/drivers/usb/gadget/r8a66597-udc.c +++ b/drivers/usb/gadget/r8a66597-udc.c @@ -1518,10 +1518,26 @@ static int r8a66597_get_frame(struct usb_gadget *_gadget) return r8a66597_read(r8a66597, FRMNUM) & 0x03FF; } +static int r8a66597_pullup(struct usb_gadget *gadget, int is_on) +{ + struct r8a66597 *r8a66597 = gadget_to_r8a66597(gadget); + unsigned long flags; + + spin_lock_irqsave(&r8a66597->lock, flags); + if (is_on) + r8a66597_bset(r8a66597, DPRPU, SYSCFG0); + else + r8a66597_bclr(r8a66597, DPRPU, SYSCFG0); + spin_unlock_irqrestore(&r8a66597->lock, flags); + + return 0; +} + static struct usb_gadget_ops r8a66597_gadget_ops = { .get_frame = r8a66597_get_frame, .start = r8a66597_start, .stop = r8a66597_stop, + .pullup = r8a66597_pullup, }; static int __exit r8a66597_remove(struct platform_device *pdev) -- cgit v1.2.3-70-g09d2 From bb59dbff4e5fb0ac14e3ee47d3f688490f128155 Mon Sep 17 00:00:00 2001 From: Yoshihiro Shimoda Date: Thu, 7 Jul 2011 09:58:43 +0900 Subject: usb: gadget: m66592-udc: add function for external controller M66592 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/m66592-udc.c | 4 ++-- drivers/usb/gadget/m66592-udc.h | 38 +++++++++++++++++++++----------------- include/linux/usb/m66592.h | 2 ++ 3 files changed, 25 insertions(+), 19 deletions(-) (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/m66592-udc.c b/drivers/usb/gadget/m66592-udc.c index 40c2f7a4f8f..5c9c04d7aa7 100644 --- a/drivers/usb/gadget/m66592-udc.c +++ b/drivers/usb/gadget/m66592-udc.c @@ -781,7 +781,7 @@ static void irq_ep0_write(struct m66592_ep *ep, struct m66592_request *req) /* write fifo */ if (req->req.buf) { if (size > 0) - m66592_write_fifo(m66592, ep->fifoaddr, buf, size); + m66592_write_fifo(m66592, ep, buf, size); if ((size == 0) || ((size % ep->ep.maxpacket) != 0)) m66592_bset(m66592, M66592_BVAL, ep->fifoctr); } @@ -827,7 +827,7 @@ static void irq_packet_write(struct m66592_ep *ep, struct m66592_request *req) /* write fifo */ if (req->req.buf) { - m66592_write_fifo(m66592, ep->fifoaddr, buf, size); + m66592_write_fifo(m66592, ep, buf, size); if ((size == 0) || ((size % ep->ep.maxpacket) != 0) || ((bufsize != ep->ep.maxpacket) diff --git a/drivers/usb/gadget/m66592-udc.h b/drivers/usb/gadget/m66592-udc.h index b85e05b2e97..7b93d579af3 100644 --- a/drivers/usb/gadget/m66592-udc.h +++ b/drivers/usb/gadget/m66592-udc.h @@ -561,11 +561,26 @@ static inline void m66592_write(struct m66592 *m66592, u16 val, iowrite16(val, m66592->reg + offset); } +static inline void m66592_mdfy(struct m66592 *m66592, u16 val, u16 pat, + unsigned long offset) +{ + u16 tmp; + tmp = m66592_read(m66592, offset); + tmp = tmp & (~pat); + tmp = tmp | val; + m66592_write(m66592, tmp, offset); +} + +#define m66592_bclr(m66592, val, offset) \ + m66592_mdfy(m66592, 0, val, offset) +#define m66592_bset(m66592, val, offset) \ + m66592_mdfy(m66592, val, 0, offset) + static inline void m66592_write_fifo(struct m66592 *m66592, - unsigned long offset, + struct m66592_ep *ep, void *buf, unsigned long len) { - void __iomem *fifoaddr = m66592->reg + offset; + void __iomem *fifoaddr = m66592->reg + ep->fifoaddr; if (m66592->pdata->on_chip) { unsigned long count; @@ -591,26 +606,15 @@ static inline void m66592_write_fifo(struct m66592 *m66592, iowrite16_rep(fifoaddr, buf, len); if (odd) { unsigned char *p = buf + len*2; + if (m66592->pdata->wr0_shorted_to_wr1) + m66592_bclr(m66592, M66592_MBW_16, ep->fifosel); iowrite8(*p, fifoaddr); + if (m66592->pdata->wr0_shorted_to_wr1) + m66592_bset(m66592, M66592_MBW_16, ep->fifosel); } } } -static inline void m66592_mdfy(struct m66592 *m66592, u16 val, u16 pat, - unsigned long offset) -{ - u16 tmp; - tmp = m66592_read(m66592, offset); - tmp = tmp & (~pat); - tmp = tmp | val; - m66592_write(m66592, tmp, offset); -} - -#define m66592_bclr(m66592, val, offset) \ - m66592_mdfy(m66592, 0, val, offset) -#define m66592_bset(m66592, val, offset) \ - m66592_mdfy(m66592, val, 0, offset) - #endif /* ifndef __M66592_UDC_H__ */ diff --git a/include/linux/usb/m66592.h b/include/linux/usb/m66592.h index cda9625e7df..a4ba31ab2fe 100644 --- a/include/linux/usb/m66592.h +++ b/include/linux/usb/m66592.h @@ -38,6 +38,8 @@ struct m66592_platdata { /* (external controller only) one = 3.3V, zero = 1.5V */ unsigned vif:1; + /* (external controller only) set one = WR0_N shorted to WR1_N */ + unsigned wr0_shorted_to_wr1:1; }; #endif /* __LINUX_USB_M66592_H */ -- cgit v1.2.3-70-g09d2 From 7eff1d83a3b846d16a4cd706d06b5827a07c08a3 Mon Sep 17 00:00:00 2001 From: Yoshihiro Shimoda Date: Thu, 7 Jul 2011 09:58:50 +0900 Subject: usb: gadget: m66592-udc: add pullup function Signed-off-by: Yoshihiro Shimoda Signed-off-by: Felipe Balbi --- drivers/usb/gadget/m66592-udc.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/m66592-udc.c b/drivers/usb/gadget/m66592-udc.c index 5c9c04d7aa7..491f825ed5c 100644 --- a/drivers/usb/gadget/m66592-udc.c +++ b/drivers/usb/gadget/m66592-udc.c @@ -1561,10 +1561,26 @@ static int m66592_get_frame(struct usb_gadget *_gadget) return m66592_read(m66592, M66592_FRMNUM) & 0x03FF; } +static int m66592_pullup(struct usb_gadget *gadget, int is_on) +{ + struct m66592 *m66592 = gadget_to_m66592(gadget); + unsigned long flags; + + spin_lock_irqsave(&m66592->lock, flags); + if (is_on) + m66592_bset(m66592, M66592_DPRPU, M66592_SYSCFG); + else + m66592_bclr(m66592, M66592_DPRPU, M66592_SYSCFG); + spin_unlock_irqrestore(&m66592->lock, flags); + + return 0; +} + static struct usb_gadget_ops m66592_gadget_ops = { .get_frame = m66592_get_frame, .start = m66592_start, .stop = m66592_stop, + .pullup = m66592_pullup, }; static int __exit m66592_remove(struct platform_device *pdev) -- cgit v1.2.3-70-g09d2