📄 pxa2xx_udc.c
字号:
/* * linux/drivers/usb/gadget/pxa2xx_udc.c * Intel PXA25x and IXP4xx on-chip full speed USB device controllers * * Copyright (C) 2002 Intrinsyc, Inc. (Frank Becker) * Copyright (C) 2003 Robert Schwebel, Pengutronix * Copyright (C) 2003 Benedikt Spranger, Pengutronix * Copyright (C) 2003 David Brownell * Copyright (C) 2003 Joshua Wise * * 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 * */// #define VERBOSE DBG_VERBOSE#include <linux/device.h>#include <linux/module.h>#include <linux/kernel.h>#include <linux/ioport.h>#include <linux/types.h>#include <linux/errno.h>#include <linux/delay.h>#include <linux/slab.h>#include <linux/init.h>#include <linux/timer.h>#include <linux/list.h>#include <linux/interrupt.h>#include <linux/proc_fs.h>#include <linux/mm.h>#include <linux/platform_device.h>#include <linux/dma-mapping.h>#include <linux/irq.h>#include <linux/clk.h>#include <linux/err.h>#include <asm/byteorder.h>#include <asm/dma.h>#include <asm/gpio.h>#include <asm/io.h>#include <asm/system.h>#include <asm/mach-types.h>#include <asm/unaligned.h>#include <asm/hardware.h>#include <linux/usb/ch9.h>#include <linux/usb/gadget.h>#include <asm/mach/udc_pxa2xx.h>/* * This driver handles the USB Device Controller (UDC) in Intel's PXA 25x * series processors. The UDC for the IXP 4xx series is very similar. * There are fifteen endpoints, in addition to ep0. * * Such controller drivers work with a gadget driver. The gadget driver * returns descriptors, implements configuration and data protocols used * by the host to interact with this device, and allocates endpoints to * the different protocol interfaces. The controller driver virtualizes * usb hardware so that the gadget drivers will be more portable. * * This UDC hardware wants to implement a bit too much USB protocol, so * it constrains the sorts of USB configuration change events that work. * The errata for these chips are misleading; some "fixed" bugs from * pxa250 a0/a1 b0/b1/b2 sure act like they're still there. * * Note that the UDC hardware supports DMA (except on IXP) but that's * not used here. IN-DMA (to host) is simple enough, when the data is * suitably aligned (16 bytes) ... the network stack doesn't do that, * other software can. OUT-DMA is buggy in most chip versions, as well * as poorly designed (data toggle not automatic). So this driver won't * bother using DMA. (Mostly-working IN-DMA support was available in * kernels before 2.6.23, but was never enabled or well tested.) */#define DRIVER_VERSION "30-June-2007"#define DRIVER_DESC "PXA 25x USB Device Controller driver"static const char driver_name [] = "pxa2xx_udc";static const char ep0name [] = "ep0";#ifdef CONFIG_ARCH_IXP4XX/* cpu-specific register addresses are compiled in to this code */#ifdef CONFIG_ARCH_PXA#error "Can't configure both IXP and PXA"#endif#endif#include "pxa2xx_udc.h"#ifdef CONFIG_USB_PXA2XX_SMALL#define SIZE_STR " (small)"#else#define SIZE_STR ""#endif/* --------------------------------------------------------------------------- * endpoint related parts of the api to the usb controller hardware, * used by gadget driver; and the inner talker-to-hardware core. * --------------------------------------------------------------------------- */static void pxa2xx_ep_fifo_flush (struct usb_ep *ep);static void nuke (struct pxa2xx_ep *, int status);/* one GPIO should be used to detect VBUS from the host */static int is_vbus_present(void){ struct pxa2xx_udc_mach_info *mach = the_controller->mach; if (mach->gpio_vbus) return gpio_get_value(mach->gpio_vbus); if (mach->udc_is_connected) return mach->udc_is_connected(); return 1;}/* one GPIO should control a D+ pullup, so host sees this device (or not) */static void pullup_off(void){ struct pxa2xx_udc_mach_info *mach = the_controller->mach; if (mach->gpio_pullup) gpio_set_value(mach->gpio_pullup, 0); else if (mach->udc_command) mach->udc_command(PXA2XX_UDC_CMD_DISCONNECT);}static void pullup_on(void){ struct pxa2xx_udc_mach_info *mach = the_controller->mach; if (mach->gpio_pullup) gpio_set_value(mach->gpio_pullup, 1); else if (mach->udc_command) mach->udc_command(PXA2XX_UDC_CMD_CONNECT);}static void pio_irq_enable(int bEndpointAddress){ bEndpointAddress &= 0xf; if (bEndpointAddress < 8) UICR0 &= ~(1 << bEndpointAddress); else { bEndpointAddress -= 8; UICR1 &= ~(1 << bEndpointAddress); }}static void pio_irq_disable(int bEndpointAddress){ bEndpointAddress &= 0xf; if (bEndpointAddress < 8) UICR0 |= 1 << bEndpointAddress; else { bEndpointAddress -= 8; UICR1 |= 1 << bEndpointAddress; }}/* The UDCCR reg contains mask and interrupt status bits, * so using '|=' isn't safe as it may ack an interrupt. */#define UDCCR_MASK_BITS (UDCCR_REM | UDCCR_SRM | UDCCR_UDE)static inline void udc_set_mask_UDCCR(int mask){ UDCCR = (UDCCR & UDCCR_MASK_BITS) | (mask & UDCCR_MASK_BITS);}static inline void udc_clear_mask_UDCCR(int mask){ UDCCR = (UDCCR & UDCCR_MASK_BITS) & ~(mask & UDCCR_MASK_BITS);}static inline void udc_ack_int_UDCCR(int mask){ /* udccr contains the bits we dont want to change */ __u32 udccr = UDCCR & UDCCR_MASK_BITS; UDCCR = udccr | (mask & ~UDCCR_MASK_BITS);}/* * endpoint enable/disable * * we need to verify the descriptors used to enable endpoints. since pxa2xx * endpoint configurations are fixed, and are pretty much always enabled, * there's not a lot to manage here. * * because pxa2xx can't selectively initialize bulk (or interrupt) endpoints, * (resetting endpoint halt and toggle), SET_INTERFACE is unusable except * for a single interface (with only the default altsetting) and for gadget * drivers that don't halt endpoints (not reset by set_interface). that also * means that if you use ISO, you must violate the USB spec rule that all * iso endpoints must be in non-default altsettings. */static int pxa2xx_ep_enable (struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc){ struct pxa2xx_ep *ep; struct pxa2xx_udc *dev; ep = container_of (_ep, struct pxa2xx_ep, ep); if (!_ep || !desc || ep->desc || _ep->name == ep0name || desc->bDescriptorType != USB_DT_ENDPOINT || ep->bEndpointAddress != desc->bEndpointAddress || ep->fifo_size < le16_to_cpu (desc->wMaxPacketSize)) { DMSG("%s, bad ep or descriptor\n", __FUNCTION__); return -EINVAL; } /* xfer types must match, except that interrupt ~= bulk */ if (ep->bmAttributes != desc->bmAttributes && ep->bmAttributes != USB_ENDPOINT_XFER_BULK && desc->bmAttributes != USB_ENDPOINT_XFER_INT) { DMSG("%s, %s type mismatch\n", __FUNCTION__, _ep->name); return -EINVAL; } /* hardware _could_ do smaller, but driver doesn't */ if ((desc->bmAttributes == USB_ENDPOINT_XFER_BULK && le16_to_cpu (desc->wMaxPacketSize) != BULK_FIFO_SIZE) || !desc->wMaxPacketSize) { DMSG("%s, bad %s maxpacket\n", __FUNCTION__, _ep->name); return -ERANGE; } dev = ep->dev; if (!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN) { DMSG("%s, bogus device state\n", __FUNCTION__); return -ESHUTDOWN; } ep->desc = desc; ep->stopped = 0; ep->pio_irqs = 0; ep->ep.maxpacket = le16_to_cpu (desc->wMaxPacketSize); /* flush fifo (mostly for OUT buffers) */ pxa2xx_ep_fifo_flush (_ep); /* ... reset halt state too, if we could ... */ DBG(DBG_VERBOSE, "enabled %s\n", _ep->name); return 0;}static int pxa2xx_ep_disable (struct usb_ep *_ep){ struct pxa2xx_ep *ep; unsigned long flags; ep = container_of (_ep, struct pxa2xx_ep, ep); if (!_ep || !ep->desc) { DMSG("%s, %s not enabled\n", __FUNCTION__, _ep ? ep->ep.name : NULL); return -EINVAL; } local_irq_save(flags); nuke (ep, -ESHUTDOWN); /* flush fifo (mostly for IN buffers) */ pxa2xx_ep_fifo_flush (_ep); ep->desc = NULL; ep->stopped = 1; local_irq_restore(flags); DBG(DBG_VERBOSE, "%s disabled\n", _ep->name); return 0;}/*-------------------------------------------------------------------------*//* for the pxa2xx, these can just wrap kmalloc/kfree. gadget drivers * must still pass correctly initialized endpoints, since other controller * drivers may care about how it's currently set up (dma issues etc). *//* * pxa2xx_ep_alloc_request - allocate a request data structure */static struct usb_request *pxa2xx_ep_alloc_request (struct usb_ep *_ep, gfp_t gfp_flags){ struct pxa2xx_request *req; req = kzalloc(sizeof(*req), gfp_flags); if (!req) return NULL; INIT_LIST_HEAD (&req->queue); return &req->req;}/* * pxa2xx_ep_free_request - deallocate a request data structure */static voidpxa2xx_ep_free_request (struct usb_ep *_ep, struct usb_request *_req){ struct pxa2xx_request *req; req = container_of (_req, struct pxa2xx_request, req); WARN_ON (!list_empty (&req->queue)); kfree(req);}/*-------------------------------------------------------------------------*//* * done - retire a request; caller blocked irqs */static void done(struct pxa2xx_ep *ep, struct pxa2xx_request *req, int status){ unsigned stopped = ep->stopped; list_del_init(&req->queue); if (likely (req->req.status == -EINPROGRESS)) req->req.status = status; else status = req->req.status; if (status && status != -ESHUTDOWN) DBG(DBG_VERBOSE, "complete %s req %p stat %d len %u/%u\n", ep->ep.name, &req->req, status, req->req.actual, req->req.length); /* don't modify queue heads during completion callback */ ep->stopped = 1; req->req.complete(&ep->ep, &req->req); ep->stopped = stopped;}static inline void ep0_idle (struct pxa2xx_udc *dev){ dev->ep0state = EP0_IDLE;}static intwrite_packet(volatile u32 *uddr, struct pxa2xx_request *req, unsigned max){ u8 *buf; unsigned length, count; buf = req->req.buf + req->req.actual; prefetch(buf); /* how big will this packet be? */ length = min(req->req.length - req->req.actual, max); req->req.actual += length; count = length; while (likely(count--)) *uddr = *buf++; return length;}/* * write to an IN endpoint fifo, as many packets as possible. * irqs will use this to write the rest later. * caller guarantees at least one packet buffer is ready (or a zlp). */static intwrite_fifo (struct pxa2xx_ep *ep, struct pxa2xx_request *req){ unsigned max; max = le16_to_cpu(ep->desc->wMaxPacketSize); do { unsigned count; int is_last, is_short; count = write_packet(ep->reg_uddr, req, max); /* last packet is usually short (or a zlp) */ if (unlikely (count != max)) is_last = is_short = 1; else { if (likely(req->req.length != req->req.actual) || req->req.zero) is_last = 0; else is_last = 1; /* interrupt/iso maxpacket may not fill the fifo */ is_short = unlikely (max < ep->fifo_size); } DBG(DBG_VERY_NOISY, "wrote %s %d bytes%s%s %d left %p\n", ep->ep.name, count, is_last ? "/L" : "", is_short ? "/S" : "", req->req.length - req->req.actual, req); /* let loose that packet. maybe try writing another one, * double buffering might work. TSP, TPC, and TFS * bit values are the same for all normal IN endpoints. */ *ep->reg_udccs = UDCCS_BI_TPC; if (is_short) *ep->reg_udccs = UDCCS_BI_TSP; /* requests complete when all IN data is in the FIFO */ if (is_last) { done (ep, req, 0); if (list_empty(&ep->queue)) pio_irq_disable (ep->bEndpointAddress); return 1; } // TODO experiment: how robust can fifo mode tweaking be? // double buffering is off in the default fifo mode, which // prevents TFS from being set here. } while (*ep->reg_udccs & UDCCS_BI_TFS); return 0;}/* caller asserts req->pending (ep0 irq status nyet cleared); starts * ep0 data stage. these chips want very simple state transitions. */static inlinevoid ep0start(struct pxa2xx_udc *dev, u32 flags, const char *tag){ UDCCS0 = flags|UDCCS0_SA|UDCCS0_OPR; USIR0 = USIR0_IR0; dev->req_pending = 0; DBG(DBG_VERY_NOISY, "%s %s, %02x/%02x\n", __FUNCTION__, tag, UDCCS0, flags);}static intwrite_ep0_fifo (struct pxa2xx_ep *ep, struct pxa2xx_request *req){ unsigned count; int is_short; count = write_packet(&UDDR0, req, EP0_FIFO_SIZE); ep->dev->stats.write.bytes += count; /* last packet "must be" short (or a zlp) */ is_short = (count != EP0_FIFO_SIZE); DBG(DBG_VERY_NOISY, "ep0in %d bytes %d left %p\n", count, req->req.length - req->req.actual, req); if (unlikely (is_short)) { if (ep->dev->req_pending) ep0start(ep->dev, UDCCS0_IPR, "short IN"); else UDCCS0 = UDCCS0_IPR; count = req->req.length; done (ep, req, 0); ep0_idle(ep->dev);#ifndef CONFIG_ARCH_IXP4XX#if 1 /* This seems to get rid of lost status irqs in some cases: * host responds quickly, or next request involves config * change automagic, or should have been hidden, or ... * * FIXME get rid of all udelays possible... */ if (count >= EP0_FIFO_SIZE) { count = 100; do { if ((UDCCS0 & UDCCS0_OPR) != 0) { /* clear OPR, generate ack */ UDCCS0 = UDCCS0_OPR; break; } count--; udelay(1); } while (count); }#endif#endif } else if (ep->dev->req_pending) ep0start(ep->dev, 0, "IN"); return is_short;}/* * read_fifo - unload packet(s) from the fifo we use for usb OUT * transfers and put them into the request. caller should have made * sure there's at least one packet ready. * * returns true if the request completed because of short packet or the * request buffer having filled (and maybe overran till end-of-packet). */static intread_fifo (struct pxa2xx_ep *ep, struct pxa2xx_request *req){ for (;;) { u32 udccs; u8 *buf; unsigned bufferspace, count, is_short; /* make sure there's a packet in the FIFO. * UDCCS_{BO,IO}_RPC are all the same bit value. * UDCCS_{BO,IO}_RNE are all the same bit value. */ udccs = *ep->reg_udccs; if (unlikely ((udccs & UDCCS_BO_RPC) == 0)) break; buf = req->req.buf + req->req.actual; prefetchw(buf); bufferspace = req->req.length - req->req.actual; /* read all bytes from this packet */ if (likely (udccs & UDCCS_BO_RNE)) { count = 1 + (0x0ff & *ep->reg_ubcr); req->req.actual += min (count, bufferspace); } else /* zlp */ count = 0; is_short = (count < ep->ep.maxpacket); DBG(DBG_VERY_NOISY, "read %s %02x, %d bytes%s req %p %d/%d\n", ep->ep.name, udccs, count, is_short ? "/S" : "", req, req->req.actual, req->req.length); while (likely (count-- != 0)) { u8 byte = (u8) *ep->reg_uddr; if (unlikely (bufferspace == 0)) { /* this happens when the driver's buffer * is smaller than what the host sent. * discard the extra data. */ if (req->req.status != -EOVERFLOW) DMSG("%s overflow %d\n", ep->ep.name, count); req->req.status = -EOVERFLOW; } else { *buf++ = byte; bufferspace--; } } *ep->reg_udccs = UDCCS_BO_RPC; /* RPC/RSP/RNE could now reflect the other packet buffer */ /* iso is one request per packet */ if (ep->bmAttributes == USB_ENDPOINT_XFER_ISOC) { if (udccs & UDCCS_IO_ROF) req->req.status = -EHOSTUNREACH; /* more like "is_done" */ is_short = 1; } /* completion */ if (is_short || req->req.actual == req->req.length) { done (ep, req, 0); if (list_empty(&ep->queue)) pio_irq_disable (ep->bEndpointAddress); return 1; } /* finished that packet. the next one may be waiting... */ } return 0;}/* * special ep0 version of the above. no UBCR0 or double buffering; status * handshaking is magic. most device protocols don't need control-OUT. * CDC vendor commands (and RNDIS), mass storage CB/CBI, and some other * protocols do use them. */static int
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -