📄 pxa2xx_udc.c
字号:
if (req && likely ((udccs & UDCCS_BI_TFS) != 0))
completed = write_fifo(ep, req);
} else { /* irq from RPC (or for ISO, ROF) */
if (likely(ep->bmAttributes == USB_ENDPOINT_XFER_BULK))
tmp = UDCCS_BO_SST | UDCCS_BO_DME;
else
tmp = UDCCS_IO_ROF | UDCCS_IO_DME;
tmp &= udccs;
if (likely(tmp))
*ep->reg_udccs = tmp;
/* fifos can hold packets, ready for reading... */
if (likely(req)) {
#ifdef USE_OUT_DMA
// TODO didn't yet debug out-dma. this approach assumes
// the worst about short packets and RPC; it might be better.
if (likely(ep->dma >= 0)) {
if (!(udccs & UDCCS_BO_RSP)) {
*ep->reg_udccs = UDCCS_BO_RPC;
ep->dma_irqs++;
return;
}
}
#endif
completed = read_fifo(ep, req);
} else
pio_irq_disable (ep->bEndpointAddress);
}
ep->pio_irqs++;
} while (completed);
}
/*
* pxa2xx_udc_irq - interrupt handler
*
* avoid delays in ep0 processing. the control handshaking isn't always
* under software control (pxa250c0 and the pxa255 are better), and delays
* could cause usb protocol errors.
*/
static irqreturn_t
pxa2xx_udc_irq(int irq, void *_dev, struct pt_regs *r)
{
struct pxa2xx_udc *dev = _dev;
int handled;
dev->stats.irqs++;
HEX_DISPLAY(dev->stats.irqs);
do {
u32 udccr = UDCCR;
handled = 0;
/* SUSpend Interrupt Request */
if (unlikely(udccr & UDCCR_SUSIR)) {
udc_ack_int_UDCCR(UDCCR_SUSIR);
handled = 1;
DBG(DBG_VERBOSE, "USB suspend%s\n", is_vbus_present()
? "" : "+disconnect");
if (!is_vbus_present())
stop_activity(dev, dev->driver);
else if (dev->gadget.speed != USB_SPEED_UNKNOWN
&& dev->driver
&& dev->driver->suspend)
dev->driver->suspend(&dev->gadget);
ep0_idle (dev);
}
/* RESume Interrupt Request */
if (unlikely(udccr & UDCCR_RESIR)) {
udc_ack_int_UDCCR(UDCCR_RESIR);
handled = 1;
DBG(DBG_VERBOSE, "USB resume\n");
if (dev->gadget.speed != USB_SPEED_UNKNOWN
&& dev->driver
&& dev->driver->resume
&& is_vbus_present())
dev->driver->resume(&dev->gadget);
}
/* ReSeT Interrupt Request - USB reset */
if (unlikely(udccr & UDCCR_RSTIR)) {
udc_ack_int_UDCCR(UDCCR_RSTIR);
handled = 1;
if ((UDCCR & UDCCR_UDA) == 0) {
DBG(DBG_VERBOSE, "USB reset start\n");
/* reset driver and endpoints,
* in case that's not yet done
*/
stop_activity (dev, dev->driver);
} else {
DBG(DBG_VERBOSE, "USB reset end\n");
dev->gadget.speed = USB_SPEED_FULL;
LED_CONNECTED_ON;
memset(&dev->stats, 0, sizeof dev->stats);
/* driver and endpoints are still reset */
}
} else {
u32 usir0 = USIR0 & ~UICR0;
u32 usir1 = USIR1 & ~UICR1;
int i;
if (unlikely (!usir0 && !usir1))
continue;
DBG(DBG_VERY_NOISY, "irq %02x.%02x\n", usir1, usir0);
/* control traffic */
if (usir0 & USIR0_IR0) {
dev->ep[0].pio_irqs++;
handle_ep0(dev);
handled = 1;
}
/* endpoint data transfers */
for (i = 0; i < 8; i++) {
u32 tmp = 1 << i;
if (i && (usir0 & tmp)) {
handle_ep(&dev->ep[i]);
USIR0 |= tmp;
handled = 1;
}
if (usir1 & tmp) {
handle_ep(&dev->ep[i+8]);
USIR1 |= tmp;
handled = 1;
}
}
}
/* we could also ask for 1 msec SOF (SIR) interrupts */
} while (handled);
return IRQ_HANDLED;
}
/*-------------------------------------------------------------------------*/
static void nop_release (struct device *dev)
{
DMSG("%s %s\n", __FUNCTION__, dev->bus_id);
}
/* this uses load-time allocation and initialization (instead of
* doing it at run-time) to save code, eliminate fault paths, and
* be more obviously correct.
*/
static struct pxa2xx_udc memory = {
.gadget = {
.ops = &pxa2xx_udc_ops,
.ep0 = &memory.ep[0].ep,
.name = driver_name,
.dev = {
.bus_id = "gadget",
.release = nop_release,
},
},
/* control endpoint */
.ep[0] = {
.ep = {
.name = ep0name,
.ops = &pxa2xx_ep_ops,
.maxpacket = EP0_FIFO_SIZE,
},
.dev = &memory,
.reg_udccs = &UDCCS0,
.reg_uddr = &UDDR0,
},
/* first group of endpoints */
.ep[1] = {
.ep = {
.name = "ep1in-bulk",
.ops = &pxa2xx_ep_ops,
.maxpacket = BULK_FIFO_SIZE,
},
.dev = &memory,
.fifo_size = BULK_FIFO_SIZE,
.bEndpointAddress = USB_DIR_IN | 1,
.bmAttributes = USB_ENDPOINT_XFER_BULK,
.reg_udccs = &UDCCS1,
.reg_uddr = &UDDR1,
drcmr (25)
},
.ep[2] = {
.ep = {
.name = "ep2out-bulk",
.ops = &pxa2xx_ep_ops,
.maxpacket = BULK_FIFO_SIZE,
},
.dev = &memory,
.fifo_size = BULK_FIFO_SIZE,
.bEndpointAddress = 2,
.bmAttributes = USB_ENDPOINT_XFER_BULK,
.reg_udccs = &UDCCS2,
.reg_ubcr = &UBCR2,
.reg_uddr = &UDDR2,
drcmr (26)
},
#ifndef CONFIG_USB_PXA2XX_SMALL
.ep[3] = {
.ep = {
.name = "ep3in-iso",
.ops = &pxa2xx_ep_ops,
.maxpacket = ISO_FIFO_SIZE,
},
.dev = &memory,
.fifo_size = ISO_FIFO_SIZE,
.bEndpointAddress = USB_DIR_IN | 3,
.bmAttributes = USB_ENDPOINT_XFER_ISOC,
.reg_udccs = &UDCCS3,
.reg_uddr = &UDDR3,
drcmr (27)
},
.ep[4] = {
.ep = {
.name = "ep4out-iso",
.ops = &pxa2xx_ep_ops,
.maxpacket = ISO_FIFO_SIZE,
},
.dev = &memory,
.fifo_size = ISO_FIFO_SIZE,
.bEndpointAddress = 4,
.bmAttributes = USB_ENDPOINT_XFER_ISOC,
.reg_udccs = &UDCCS4,
.reg_ubcr = &UBCR4,
.reg_uddr = &UDDR4,
drcmr (28)
},
.ep[5] = {
.ep = {
.name = "ep5in-int",
.ops = &pxa2xx_ep_ops,
.maxpacket = INT_FIFO_SIZE,
},
.dev = &memory,
.fifo_size = INT_FIFO_SIZE,
.bEndpointAddress = USB_DIR_IN | 5,
.bmAttributes = USB_ENDPOINT_XFER_INT,
.reg_udccs = &UDCCS5,
.reg_uddr = &UDDR5,
},
/* second group of endpoints */
.ep[6] = {
.ep = {
.name = "ep6in-bulk",
.ops = &pxa2xx_ep_ops,
.maxpacket = BULK_FIFO_SIZE,
},
.dev = &memory,
.fifo_size = BULK_FIFO_SIZE,
.bEndpointAddress = USB_DIR_IN | 6,
.bmAttributes = USB_ENDPOINT_XFER_BULK,
.reg_udccs = &UDCCS6,
.reg_uddr = &UDDR6,
drcmr (30)
},
.ep[7] = {
.ep = {
.name = "ep7out-bulk",
.ops = &pxa2xx_ep_ops,
.maxpacket = BULK_FIFO_SIZE,
},
.dev = &memory,
.fifo_size = BULK_FIFO_SIZE,
.bEndpointAddress = 7,
.bmAttributes = USB_ENDPOINT_XFER_BULK,
.reg_udccs = &UDCCS7,
.reg_ubcr = &UBCR7,
.reg_uddr = &UDDR7,
drcmr (31)
},
.ep[8] = {
.ep = {
.name = "ep8in-iso",
.ops = &pxa2xx_ep_ops,
.maxpacket = ISO_FIFO_SIZE,
},
.dev = &memory,
.fifo_size = ISO_FIFO_SIZE,
.bEndpointAddress = USB_DIR_IN | 8,
.bmAttributes = USB_ENDPOINT_XFER_ISOC,
.reg_udccs = &UDCCS8,
.reg_uddr = &UDDR8,
drcmr (32)
},
.ep[9] = {
.ep = {
.name = "ep9out-iso",
.ops = &pxa2xx_ep_ops,
.maxpacket = ISO_FIFO_SIZE,
},
.dev = &memory,
.fifo_size = ISO_FIFO_SIZE,
.bEndpointAddress = 9,
.bmAttributes = USB_ENDPOINT_XFER_ISOC,
.reg_udccs = &UDCCS9,
.reg_ubcr = &UBCR9,
.reg_uddr = &UDDR9,
drcmr (33)
},
.ep[10] = {
.ep = {
.name = "ep10in-int",
.ops = &pxa2xx_ep_ops,
.maxpacket = INT_FIFO_SIZE,
},
.dev = &memory,
.fifo_size = INT_FIFO_SIZE,
.bEndpointAddress = USB_DIR_IN | 10,
.bmAttributes = USB_ENDPOINT_XFER_INT,
.reg_udccs = &UDCCS10,
.reg_uddr = &UDDR10,
},
/* third group of endpoints */
.ep[11] = {
.ep = {
.name = "ep11in-bulk",
.ops = &pxa2xx_ep_ops,
.maxpacket = BULK_FIFO_SIZE,
},
.dev = &memory,
.fifo_size = BULK_FIFO_SIZE,
.bEndpointAddress = USB_DIR_IN | 11,
.bmAttributes = USB_ENDPOINT_XFER_BULK,
.reg_udccs = &UDCCS11,
.reg_uddr = &UDDR11,
drcmr (35)
},
.ep[12] = {
.ep = {
.name = "ep12out-bulk",
.ops = &pxa2xx_ep_ops,
.maxpacket = BULK_FIFO_SIZE,
},
.dev = &memory,
.fifo_size = BULK_FIFO_SIZE,
.bEndpointAddress = 12,
.bmAttributes = USB_ENDPOINT_XFER_BULK,
.reg_udccs = &UDCCS12,
.reg_ubcr = &UBCR12,
.reg_uddr = &UDDR12,
drcmr (36)
},
.ep[13] = {
.ep = {
.name = "ep13in-iso",
.ops = &pxa2xx_ep_ops,
.maxpacket = ISO_FIFO_SIZE,
},
.dev = &memory,
.fifo_size = ISO_FIFO_SIZE,
.bEndpointAddress = USB_DIR_IN | 13,
.bmAttributes = USB_ENDPOINT_XFER_ISOC,
.reg_udccs = &UDCCS13,
.reg_uddr = &UDDR13,
drcmr (37)
},
.ep[14] = {
.ep = {
.name = "ep14out-iso",
.ops = &pxa2xx_ep_ops,
.maxpacket = ISO_FIFO_SIZE,
},
.dev = &memory,
.fifo_size = ISO_FIFO_SIZE,
.bEndpointAddress = 14,
.bmAttributes = USB_ENDPOINT_XFER_ISOC,
.reg_udccs = &UDCCS14,
.reg_ubcr = &UBCR14,
.reg_uddr = &UDDR14,
drcmr (38)
},
.ep[15] = {
.ep = {
.name = "ep15in-int",
.ops = &pxa2xx_ep_ops,
.maxpacket = INT_FIFO_SIZE,
},
.dev = &memory,
.fifo_size = INT_FIFO_SIZE,
.bEndpointAddress = USB_DIR_IN | 15,
.bmAttributes = USB_ENDPOINT_XFER_INT,
.reg_udccs = &UDCCS15,
.reg_uddr = &UDDR15,
},
#endif /* !CONFIG_USB_PXA2XX_SMALL */
};
#define CP15R0_VENDOR_MASK 0xffffe000
#if defined(CONFIG_ARCH_PXA)
#define CP15R0_XSCALE_VALUE 0x69052000 /* intel/arm/xscale */
#elif defined(CONFIG_ARCH_IXP4XX)
#define CP15R0_XSCALE_VALUE 0x69054000 /* intel/arm/ixp4xx */
#endif
#define CP15R0_PROD_MASK 0x000003f0
#define PXA25x 0x00000100 /* and PXA26x */
#define PXA210 0x00000120
#define CP15R0_REV_MASK 0x0000000f
#define CP15R0_PRODREV_MASK (CP15R0_PROD_MASK | CP15R0_REV_MASK)
#define PXA255_A0 0x00000106 /* or PXA260_B1 */
#define PXA250_C0 0x00000105 /* or PXA26x_B0 */
#define PXA250_B2 0x00000104
#define PXA250_B1 0x00000103 /* or PXA260_A0 */
#define PXA250_B0 0x00000102
#define PXA250_A1 0x00000101
#define PXA250_A0 0x00000100
#define PXA210_C0 0x00000125
#define PXA210_B2 0x00000124
#define PXA210_B1 0x00000123
#define PXA210_B0 0x00000122
#define IXP425_A0 0x000001c1
/*
* probe - binds to the platform device
*/
static int __init pxa2xx_udc_probe(struct device *_dev)
{
struct pxa2xx_udc *dev = &memory;
int retval, out_dma = 1;
u32 chiprev;
/* insist on Intel/ARM/XScale */
asm("mrc%? p15, 0, %0, c0, c0" : "=r" (chiprev));
if ((chiprev & CP15R0_VENDOR_MASK) != CP15R0_XSCALE_VALUE) {
printk(KERN_ERR "%s: not XScale!\n", driver_name);
return -ENODEV;
}
/* trigger chiprev-specific logic */
switch (chiprev & CP15R0_PRODREV_MASK) {
#if defined(CONFIG_ARCH_PXA)
case PXA255_A0:
dev->has_cfr = 1;
break;
case PXA250_A0:
case PXA250_A1:
/* A0/A1 "not released"; ep 13, 15 unusable */
/* fall through */
case PXA250_B2: case PXA210_B2:
case PXA250_B1: case PXA210_B1:
case PXA250_B0: case PXA210_B0:
out_dma = 0;
/* fall through */
case PXA250_C0: case PXA210_C0:
break;
#elif defined(CONFIG_ARCH_IXP4XX)
case IXP425_A0:
out_dma = 0;
break;
#endif
default:
out_dma = 0;
printk(KERN_ERR "%s: unrecognized processor: %08x\n",
driver_name, chiprev);
/* iop3xx, ixp4xx, ... */
return -ENODEV;
}
pr_debug("%s: IRQ %d%s%s%s\n", driver_name, IRQ_USB,
dev->has_cfr ? "" : " (!cfr)",
out_dma ? "" : " (broken dma-out)",
SIZE_STR DMASTR
);
#ifdef USE_DMA
#ifndef USE_OUT_DMA
out_dma = 0;
#endif
/* pxa 250 erratum 130 prevents using OUT dma (fixed C0) */
if (!out_dma) {
DMSG("disabled OUT dma\n");
dev->ep[ 2].reg_drcmr = dev->ep[ 4].reg_drcmr = 0;
dev->ep[ 7].reg_drcmr = dev->ep[ 9].reg_drcmr = 0;
dev->ep[12].reg_drcmr = dev->ep[14].reg_drcmr = 0;
}
#endif
/* other non-static parts of init */
d
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -