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/net2272.c | 2718 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 2718 insertions(+) create mode 100644 drivers/usb/gadget/net2272.c (limited to 'drivers/usb/gadget/net2272.c') 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"); -- 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/net2272.c') 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 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/net2272.c') 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/net2272.c') 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 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/net2272.c') 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