plat_uds.c
来自「omap3 linux 2.6 用nocc去除了冗余代码」· C语言 代码 · 共 2,070 行 · 第 1/4 页
C
2,070 行
musb_writew(mbase, MGC_O_HDRC_RXFIFOADD, c_off); hw_ep->rx_double_buffered = !!(c_size & MGC_M_FIFOSZ_DPB); hw_ep->wMaxPacketSizeRx = maxpacket; break; case FIFO_RXTX: musb_writeb(mbase, MGC_O_HDRC_TXFIFOSZ, c_size); musb_writew(mbase, MGC_O_HDRC_TXFIFOADD, c_off); hw_ep->rx_double_buffered = !!(c_size & MGC_M_FIFOSZ_DPB); hw_ep->wMaxPacketSizeRx = maxpacket; musb_writeb(mbase, MGC_O_HDRC_RXFIFOSZ, c_size); musb_writew(mbase, MGC_O_HDRC_RXFIFOADD, c_off); hw_ep->tx_double_buffered = hw_ep->rx_double_buffered; hw_ep->wMaxPacketSizeTx = maxpacket; hw_ep->bIsSharedFifo = TRUE; break; } /* NOTE rx and tx endpoint irqs aren't managed separately, * which happens to be ok */ musb->wEndMask |= (1 << hw_ep->bLocalEnd); return offset + (maxpacket << ((c_size & MGC_M_FIFOSZ_DPB) ? 1 : 0));}static struct fifo_cfg __initdata ep0_cfg = { .style = FIFO_RXTX, .maxpacket = 64,};static int __init ep_config_from_table(struct musb *musb){ const struct fifo_cfg *cfg; unsigned i, n; int offset; struct musb_hw_ep *hw_ep = musb->aLocalEnd; switch (fifo_mode) { default: fifo_mode = 0; /* FALLTHROUGH */ case 0: cfg = mode_0_cfg; n = ARRAY_SIZE(mode_0_cfg); break; case 1: cfg = mode_1_cfg; n = ARRAY_SIZE(mode_1_cfg); break; case 2: cfg = mode_2_cfg; n = ARRAY_SIZE(mode_2_cfg); break; case 3: cfg = mode_3_cfg; n = ARRAY_SIZE(mode_3_cfg); break; case 4: cfg = mode_4_cfg; n = ARRAY_SIZE(mode_4_cfg); break; } printk(KERN_DEBUG "%s: setup fifo_mode %d\n", musb_driver_name, fifo_mode); offset = fifo_setup(musb, hw_ep, &ep0_cfg, 0); // assert(offset > 0) /* NOTE: for RTL versions >= 1.400 EPINFO and RAMINFO would * be better than static MUSB_C_NUM_EPS and DYN_FIFO_SIZE... */ for (i = 0; i < n; i++) { u8 epn = cfg->hw_ep_num; if (epn >= MUSB_C_NUM_EPS) { pr_debug( "%s: invalid ep %d\n", musb_driver_name, epn); continue; } offset = fifo_setup(musb, hw_ep + epn, cfg++, offset); if (offset < 0) { pr_debug( "%s: mem overrun, ep %d\n", musb_driver_name, epn); return -EINVAL; } epn++; musb->bEndCount = max(epn, musb->bEndCount); } printk(KERN_DEBUG "%s: %d/%d max ep, %d/%d memory\n", musb_driver_name, n + 1, MUSB_C_NUM_EPS * 2 - 1, offset, DYN_FIFO_SIZE); if (!musb->bulk_ep) { pr_debug( "%s: missing bulk\n", musb_driver_name); return -EINVAL; } return 0;}/* * ep_config_from_hw - when MUSB_C_DYNFIFO_DEF is false * @param pThis the controller */static int __init ep_config_from_hw(struct musb *musb){ u8 bEnd = 0, reg; struct musb_hw_ep *pEnd; void *pBase = musb->pRegs; DBG(2, "<== static silicon ep config\n"); /* FIXME pick up ep0 maxpacket size */ for (bEnd = 1; bEnd < MUSB_C_NUM_EPS; bEnd++) { MGC_SelectEnd(pBase, bEnd); pEnd = musb->aLocalEnd + bEnd; /* read from core using indexed model */ reg = musb_readb(pEnd->regs, 0x10 + MGC_O_HDRC_FIFOSIZE); if (!reg) { /* 0's returned when no more endpoints */ break; } musb->bEndCount++; musb->wEndMask |= (1 << bEnd); pEnd->wMaxPacketSizeTx = 1 << (reg & 0x0f); /* shared TX/RX FIFO? */ if ((reg & 0xf0) == 0xf0) { pEnd->wMaxPacketSizeRx = pEnd->wMaxPacketSizeTx; pEnd->bIsSharedFifo = TRUE; continue; } else { pEnd->wMaxPacketSizeRx = 1 << ((reg & 0xf0) >> 4); pEnd->bIsSharedFifo = FALSE; } /* FIXME set up pEnd->{rx,tx}_double_buffered */ /* pick an RX/TX endpoint for bulk */ if (pEnd->wMaxPacketSizeTx < 512 || pEnd->wMaxPacketSizeRx < 512) continue; /* REVISIT: this algorithm is lazy, we should at least * try to pick a double buffered endpoint. */ if (musb->bulk_ep) continue; musb->bulk_ep = pEnd; } if (!musb->bulk_ep) { pr_debug( "%s: missing bulk\n", musb_driver_name); return -EINVAL; } return 0;}enum { MUSB_CONTROLLER_MHDRC, MUSB_CONTROLLER_HDRC, };/* Initialize MUSB (M)HDRC part of the USB hardware subsystem; * configure endpoints, or take their config from silicon */static int __init musb_core_init(u16 wType, struct musb *pThis){ u8 reg; char *type; u16 wRelease, wRelMajor, wRelMinor; char aInfo[100], aRevision[32], aDate[12]; void __iomem *pBase = pThis->pRegs; int status = 0; int i; /* log core options (read using indexed model) */ //MGC_SelectEnd(pBase, 0); musb_writeb(pBase, MGC_O_HDRC_INDEX, 0); reg = musb_readb(pBase, 0x10 + MGC_O_HDRC_CONFIGDATA); strcpy(aInfo, (reg & MGC_M_CONFIGDATA_UTMIDW) ? "UTMI-16" : "UTMI-8"); if (reg & MGC_M_CONFIGDATA_DYNFIFO) { strcat(aInfo, ", dyn FIFOs"); } if (reg & MGC_M_CONFIGDATA_MPRXE) { strcat(aInfo, ", bulk combine"); strcat(aInfo, " (X)"); /* no driver support */ } if (reg & MGC_M_CONFIGDATA_MPTXE) { strcat(aInfo, ", bulk split"); strcat(aInfo, " (X)"); /* no driver support */ } if (reg & MGC_M_CONFIGDATA_HBRXE) { strcat(aInfo, ", HB-ISO Rx"); strcat(aInfo, " (X)"); /* no driver support */ } if (reg & MGC_M_CONFIGDATA_HBTXE) { strcat(aInfo, ", HB-ISO Tx"); strcat(aInfo, " (X)"); /* no driver support */ } if (reg & MGC_M_CONFIGDATA_SOFTCONE) { strcat(aInfo, ", SoftConn"); } printk(KERN_DEBUG "%s: ConfigData=0x%02x (%s)\n", musb_driver_name, reg, aInfo); aDate[0] = 0; if (MUSB_CONTROLLER_MHDRC == wType) { pThis->bIsMultipoint = 1; type = "M"; } else { pThis->bIsMultipoint = 0; type = ""; printk(KERN_ERR "%s: kernel must blacklist external hubs\n", musb_driver_name); } /* log release info */ wRelease = musb_readw(pBase, MGC_O_HDRC_HWVERS); wRelMajor = (wRelease >> 10) & 0x1f; wRelMinor = wRelease & 0x3ff; snprintf(aRevision, 32, "%d.%d%s", wRelMajor, wRelMinor, (wRelease & 0x8000) ? "RC" : ""); printk(KERN_DEBUG "%s: %sHDRC RTL version %s %s\n", musb_driver_name, type, aRevision, aDate); /* configure ep0 */ pThis->aLocalEnd[0].wMaxPacketSizeTx = MGC_END0_FIFOSIZE; pThis->aLocalEnd[0].wMaxPacketSizeRx = MGC_END0_FIFOSIZE; /* discover endpoint configuration */ pThis->bEndCount = 1; pThis->wEndMask = 1; if (reg & MGC_M_CONFIGDATA_DYNFIFO) { if (can_dynfifo()) status = ep_config_from_table(pThis); else { ERR("reconfigure software for Dynamic FIFOs\n"); status = -ENODEV; } } else { if (!can_dynfifo()) status = ep_config_from_hw(pThis); else { ERR("reconfigure software for static FIFOs\n"); return -ENODEV; } } if (status < 0) return status; /* finish init, and print endpoint config */ for (i = 0; i < pThis->bEndCount; i++) { struct musb_hw_ep *hw_ep = pThis->aLocalEnd + i; hw_ep->fifo = MUSB_FIFO_OFFSET(i) + pBase; hw_ep->regs = MGC_END_OFFSET(i, 0) + pBase; hw_ep->target_regs = MGC_BUSCTL_OFFSET(i, 0) + pBase; hw_ep->rx_reinit = 1; hw_ep->tx_reinit = 1; if (hw_ep->wMaxPacketSizeTx) { printk(KERN_DEBUG "%s: hw_ep %d%s, %smax %d\n", musb_driver_name, i, hw_ep->bIsSharedFifo ? "shared" : "tx", hw_ep->tx_double_buffered ? "doublebuffer, " : "", hw_ep->wMaxPacketSizeTx); } if (hw_ep->wMaxPacketSizeRx && !hw_ep->bIsSharedFifo) { printk(KERN_DEBUG "%s: hw_ep %d%s, %smax %d\n", musb_driver_name, i, "rx", hw_ep->rx_double_buffered ? "doublebuffer, " : "", hw_ep->wMaxPacketSizeRx); } if (!(hw_ep->wMaxPacketSizeTx || hw_ep->wMaxPacketSizeRx)) DBG(1, "hw_ep %d not configured\n", i); } return 0;}/*-------------------------------------------------------------------------*/static irqreturn_t generic_interrupt(int irq, void *__hci){ unsigned long flags; irqreturn_t retval = IRQ_NONE; struct musb *musb = __hci; spin_lock_irqsave(&musb->Lock, flags); musb->int_usb = musb_readb(musb->pRegs, MGC_O_HDRC_INTRUSB); musb->int_tx = musb_readw(musb->pRegs, MGC_O_HDRC_INTRTX); musb->int_rx = musb_readw(musb->pRegs, MGC_O_HDRC_INTRRX); if (musb->int_usb || musb->int_tx || musb->int_rx) retval = musb_interrupt(musb); spin_unlock_irqrestore(&musb->Lock, flags); /* REVISIT we sometimes get spurious IRQs on g_ep0 * not clear why... */ if (retval != IRQ_HANDLED) DBG(5, "spurious?\n"); return IRQ_HANDLED;}/* * handle all the irqs defined by the HDRC core. for now we expect: other * irq sources (phy, dma, etc) will be handled first, musb->int_* values * will be assigned, and the irq will already have been acked. * * called in irq context with spinlock held, irqs blocked */irqreturn_t musb_interrupt(struct musb *musb){ irqreturn_t retval = IRQ_NONE; u8 devctl, power; int ep_num; u32 reg; devctl = musb_readb(musb->pRegs, MGC_O_HDRC_DEVCTL); power = musb_readb(musb->pRegs, MGC_O_HDRC_POWER); DBG(4, "** IRQ %s usb%04x tx%04x rx%04x\n", (devctl & MGC_M_DEVCTL_HM) ? "host" : "peripheral", musb->int_usb, musb->int_tx, musb->int_rx); /* the core can interrupt us for multiple reasons; docs have * a generic interrupt flowchart to follow */ if (musb->int_usb & STAGE0_MASK) retval |= musb_stage0_irq(musb, musb->int_usb, devctl, power); /* "stage 1" is handling endpoint irqs */ /* handle endpoint 0 first */ if (musb->int_tx & 1) { if (devctl & MGC_M_DEVCTL_HM) retval |= musb_h_ep0_irq(musb); else retval |= musb_g_ep0_irq(musb); } /* RX on endpoints 1-15 */ reg = musb->int_rx >> 1; ep_num = 1; while (reg) { if (reg & 1) { // MGC_SelectEnd(musb->pRegs, ep_num); /* REVISIT just retval = ep->rx_irq(...) */ retval = IRQ_HANDLED; if (devctl & MGC_M_DEVCTL_HM) { if (is_host_capable()) musb_host_rx(musb, ep_num); } else { if (is_peripheral_capable()) musb_g_rx(musb, ep_num); } } reg >>= 1; ep_num++; } /* TX on endpoints 1-15 */ reg = musb->int_tx >> 1; ep_num = 1; while (reg) { if (reg & 1) { // MGC_SelectEnd(musb->pRegs, ep_num); /* REVISIT just retval |= ep->tx_irq(...) */ retval = IRQ_HANDLED; if (devctl & MGC_M_DEVCTL_HM) { if (is_host_capable()) musb_host_tx(musb, ep_num); } else { if (is_peripheral_capable()) musb_g_tx(musb, ep_num); } } reg >>= 1; ep_num++; } /* finish handling "global" interrupts after handling fifos */ if (musb->int_usb) retval |= musb_stage2_irq(musb, musb->int_usb, devctl, power); return retval;}#define use_dma 0/*-------------------------------------------------------------------------*/static ssize_tmusb_mode_show(struct device *dev, struct device_attribute *attr, char *buf){ struct musb *musb = dev_to_musb(dev); unsigned long flags; int ret = -EINVAL; spin_lock_irqsave(&musb->Lock, flags); ret = sprintf(buf, "%s\n", otg_state_string(musb)); spin_unlock_irqrestore(&musb->Lock, flags); return ret;}static ssize_tmusb_mode_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t n){ struct musb *musb = dev_to_musb(dev); unsigned long flags; spin_lock_irqsave(&musb->Lock, flags); if (!strncmp(buf, "host", 4)) musb_platform_set_mode(musb, MUSB_HOST); if (!strncmp(buf, "peripheral", 10)) musb_platform_set_mode(musb, MUSB_PERIPHERAL); if (!strncmp(buf, "otg", 3)) musb_platform_set_mode(musb, MUSB_OTG); spin_unlock_irqrestore(&musb->Lock, flags); return n;}static DEVICE_ATTR(mode, 0644, musb_mode_show, musb_mode_store);static ssize_tmusb_cable_show(struct device *dev, struct device_attribute *attr, char *buf){ struct musb *musb = dev_to_musb(dev); char *v1= "", *v2 = "?"; unsigned long flags; int vbus; spin_lock_irqsave(&musb->Lock, flags); /* NOTE: board-specific issues, like too-big capacitors keeping * VBUS high for a long time after power has been removed, can * cause temporary false indications of a connection. */ vbus = musb_readb(musb->pRegs, MGC_O_HDRC_DEVCTL); if (vbus & 0x10) { /* REVISIT retest on real OTG hardware */ switch (musb->board_mode) { case MUSB_HOST: v2 = "A"; break; case MUSB_PERIPHERAL: v2 = "B"; break; case MUSB_OTG: v1 = "Mini-"; v2 = (vbus & MGC_M_DEVCTL_BDEVICE) ? "B" : "A"; break; } } else /* VBUS level below A-Valid */ v2 = "disconnected"; musb_platform_try_idle(musb, 0); spin_unlock_irqrestore(&musb->Lock, flags); return sprintf(buf, "%s%s\n", v1, v2);}static DEVICE_ATTR(cable, S_IRUGO, musb_cable_show, NULL);static ssize_tmusb_vbus_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t n){ struct musb *musb = dev_to_musb(dev); unsigned long flags; unsigned long val; spin_lock_irqsave(&musb->Lock, flags); if (sscanf(buf, "%lu", &val) < 1) { printk(KERN_ERR "Invalid VBUS timeout ms value\n"); return -EINVAL; } musb->a_wait_bcon = val; if (musb->xceiv.state == OTG_STATE_A_WAIT_BCON) musb->is_active = 0; musb_platform_try_idle(musb, jiffies + msecs_to_jiffies(val)); spin_unlock_irqrestore(&musb->Lock, flags); return n;}static ssize_tmusb_vbus_show(struct device *dev, struct device_attribute *attr, char *buf)
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?