📄 pxa2xx_udc.c
字号:
*/ stop_activity (dev, dev->driver); } else { INFO("USB reset\n"); dev->gadget.speed = USB_SPEED_FULL; LED_CONNECTED_ON; memset(&dev->stats, 0, sizeof dev->stats); /* driver and endpoints are still reset */ enable_disconnect_irq(); } } 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 */ /* FIXME: the system freeze when build as non module without CONFIG_USB_ETH_RNDIS on Lubbock */#if defined(CONFIG_USB_ETH_RNDIS) asm("mrc%? p15, 0, %0, c0, c0" : "=r" (chiprev));#else chiprev=0x69052D05; /* Captured value on my Lubbock Board */#endif 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 */ dev->dev = _dev; dev->mach = _dev->platform_data; init_timer(&dev->timer); dev->timer.function = udc_watchdog; dev->timer.data = (unsigned long) dev; device_initialize(&dev->gadget.dev); dev->gadget.dev.parent = _dev; dev->gadget.dev.dma_mask = _dev->dma_mask; the_controller = dev; dev_set_drvdata(_dev, dev); udc_disable(dev); udc_reinit(dev); /* irq setup after old hardware state is cleaned up */ retval = request_irq(IRQ_USB, pxa2xx_udc_irq, SA_INTERRUPT, driver_name, dev); if (retval != 0) { printk(KERN_ERR "%s: can't get irq %i, err %d\n", driver_name, IRQ_USB, retval); return -EBUSY; } dev->got_irq = 1;#ifdef CONFIG_ARCH_LUBBOCK#ifndef CONFIG_ARCH_FS_PXA255 if (machine_is_lubbock()) { disable_irq(LUBBOCK_USB_DISC_IRQ); retval = request_irq(LUBBOCK_USB_DISC_IRQ, usb_connection_irq, SA_INTERRUPT /* OOPSING | SA_SAMPLE_RANDOM */, driver_name, dev); if (retval != 0) { enable_irq(LUBBOCK_USB_DISC_IRQ); printk(KERN_ERR "%s: can't get irq %i, err %d\n", driver_name, LUBBOCK_USB_DISC_IRQ, retval); return -EBUSY; } dev->got_disc = 1; }#endif#endif create_proc_files(); return 0;}static int __exit pxa2xx_udc_remove(struct device *_dev){ struct pxa2xx_udc *dev = _dev->driver_data; udc_disable(dev); remove_proc_files(); usb_gadget_unregister_driver(dev->driver); if (dev->got_irq) { free_irq(IRQ_USB, dev); dev->got_irq = 0; } if (machine_is_lubbock() && dev->got_disc) { free_irq(LUBBOCK_USB_DISC_IRQ, dev); dev->got_disc = 0; } dev_set_drvdata(_dev, 0); the_controller = 0; return 0;}/*-------------------------------------------------------------------------*/static struct device_driver udc_driver = { .name = (char *) driver_name, .bus = &platform_bus_type, .probe = pxa2xx_udc_probe, .remove = __exit_p(pxa2xx_udc_remove), // FIXME power management support // .suspend = ... disable UDC // .resume = ... re-enable UDC};static int __init udc_init(void){ printk(KERN_INFO "%s: version %s\n", driver_name, DRIVER_VERSION); return driver_register(&udc_driver);}module_init(udc_init);static void __exit udc_exit(void){ driver_unregister(&udc_driver);}module_exit(udc_exit);MODULE_DESCRIPTION(DRIVER_DESC);MODULE_AUTHOR("Frank Becker, Robert Schwebel, David Brownell");MODULE_LICENSE("GPL");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -