plat_uds.c
来自「omap3 linux 2.6 用nocc去除了冗余代码」· C语言 代码 · 共 2,070 行 · 第 1/4 页
C
2,070 行
* another reset is due (at least for high speed, * to redo the chirp etc), it might work OK... */ case OTG_STATE_A_WAIT_BCON: case OTG_STATE_A_WAIT_VRISE: if (pThis->vbuserr_retry) { pThis->vbuserr_retry--; ignore = 1; devctl |= MGC_M_DEVCTL_SESSION; musb_writeb(pBase, MGC_O_HDRC_DEVCTL, devctl); } else { pThis->port1_status |= (1 << USB_PORT_FEAT_OVER_CURRENT) | (1 << USB_PORT_FEAT_C_OVER_CURRENT); } break; default: break; } DBG(1, "VBUS_ERROR in %s (%02x, %s), retry #%d, port1 %08x\n", otg_state_string(pThis), devctl, ({ char *s; switch (devctl & MGC_M_DEVCTL_VBUS) { case 0 << MGC_S_DEVCTL_VBUS: s = "<SessEnd"; break; case 1 << MGC_S_DEVCTL_VBUS: s = "<AValid"; break; case 2 << MGC_S_DEVCTL_VBUS: s = "<VBusValid"; break; //case 3 << MGC_S_DEVCTL_VBUS: default: s = "VALID"; break; }; s; }), VBUSERR_RETRY_COUNT - pThis->vbuserr_retry, pThis->port1_status); /* go through A_WAIT_VFALL then start a new session */ if (!ignore) musb_set_vbus(pThis, 0); handled = IRQ_HANDLED; } if (bIntrUSB & MGC_M_INTR_CONNECT) { struct usb_hcd *hcd = musb_to_hcd(pThis); handled = IRQ_HANDLED; pThis->is_active = 1; set_bit(HCD_FLAG_SAW_IRQ, &hcd->flags); pThis->bEnd0Stage = MGC_END0_START; /* flush endpoints when transitioning from Device Mode */ if (is_peripheral_active(pThis)) { // REVISIT HNP; just force disconnect } pThis->bDelayPortPowerOff = FALSE; musb_writew(pBase, MGC_O_HDRC_INTRTXE, pThis->wEndMask); musb_writew(pBase, MGC_O_HDRC_INTRRXE, pThis->wEndMask & 0xfffe); musb_writeb(pBase, MGC_O_HDRC_INTRUSBE, 0xf7); pThis->port1_status &= ~(USB_PORT_STAT_LOW_SPEED |USB_PORT_STAT_HIGH_SPEED |USB_PORT_STAT_ENABLE ); pThis->port1_status |= USB_PORT_STAT_CONNECTION |(USB_PORT_STAT_C_CONNECTION << 16); /* high vs full speed is just a guess until after reset */ if (devctl & MGC_M_DEVCTL_LSDEV) pThis->port1_status |= USB_PORT_STAT_LOW_SPEED; if (hcd->status_urb) usb_hcd_poll_rh_status(hcd); else usb_hcd_resume_root_hub(hcd); MUSB_HST_MODE(pThis); /* indicate new connection to OTG machine */ switch (pThis->xceiv.state) { case OTG_STATE_B_WAIT_ACON: DBG(1, "HNP: Waiting to switch to b_host state\n"); pThis->xceiv.state = OTG_STATE_B_HOST; hcd->self.is_b_host = 1; break; default: if ((devctl & MGC_M_DEVCTL_VBUS) == (3 << MGC_S_DEVCTL_VBUS)) { pThis->xceiv.state = OTG_STATE_A_HOST; hcd->self.is_b_host = 0; } break; } DBG(1, "CONNECT (%s) devctl %02x\n", otg_state_string(pThis), devctl); } /* mentor saves a bit: bus reset and babble share the same irq. * only host sees babble; only peripheral sees bus reset. */ if (bIntrUSB & MGC_M_INTR_RESET) { if (devctl & MGC_M_DEVCTL_HM) { /* * Looks like non-HS BABBLE can be ignored, but * HS BABBLE is an error condition. For HS the solution * is to avoid babble in the first place and fix whatever * causes BABBLE. When HS BABBLE happens we can only stop * the session. */ if (devctl & (MGC_M_DEVCTL_FSDEV | MGC_M_DEVCTL_LSDEV)) DBG(1, "BABBLE devctl: %02x\n", devctl); else { ERR("Stopping host session because of babble\n"); musb_writeb(pBase, MGC_O_HDRC_DEVCTL, 0); } } else { DBG(1, "BUS RESET\n"); musb_g_reset(pThis); schedule_work(&pThis->irq_work); } handled = IRQ_HANDLED; } return handled;}/* * Interrupt Service Routine to record USB "global" interrupts. * Since these do not happen often and signify things of * paramount importance, it seems OK to check them individually; * the order of the tests is specified in the manual * * @param pThis instance pointer * @param bIntrUSB register contents * @param devctl * @param power */static irqreturn_t musb_stage2_irq(struct musb * pThis, u8 bIntrUSB, u8 devctl, u8 power){ irqreturn_t handled = IRQ_NONE; if ((bIntrUSB & MGC_M_INTR_DISCONNECT) && !pThis->bIgnoreDisconnect) { DBG(1, "DISCONNECT (%s) as %s, devctl %02x\n", otg_state_string(pThis), MUSB_MODE(pThis), devctl); handled = IRQ_HANDLED; switch (pThis->xceiv.state) { case OTG_STATE_A_HOST: musb_root_disconnect(pThis); devctl = musb_readb(pThis->pRegs, MGC_O_HDRC_DEVCTL); if( (devctl & MGC_M_DEVCTL_BDEVICE) ) { pThis->xceiv.state = OTG_STATE_B_IDLE; } else { /*Start Timer*/ pThis->xceiv.state = OTG_STATE_A_WAIT_BCON; musb_otg_timer.data = (unsigned long)pThis; mod_timer( &musb_otg_timer, jiffies + msecs_to_jiffies(MGC_OTG_T_A_WAIT_BCON)); } break; case OTG_STATE_A_SUSPEND: musb_root_disconnect(pThis); if (pThis->a_wait_bcon != 0) musb_platform_try_idle(pThis, jiffies + msecs_to_jiffies(pThis->a_wait_bcon)); break; case OTG_STATE_A_WAIT_VFALL: case OTG_STATE_B_HOST: musb_hnp_stop(pThis); break; /* FALLTHROUGH */ case OTG_STATE_A_PERIPHERAL: musb_root_disconnect(pThis); /* FALLTHROUGH */ case OTG_STATE_B_WAIT_ACON: case OTG_STATE_B_PERIPHERAL: musb_g_disconnect(pThis); break; default: WARN("unhandled DISCONNECT transition (%s)\n", otg_state_string(pThis)); break; } schedule_work(&pThis->irq_work); } if (bIntrUSB & MGC_M_INTR_SUSPEND) { DBG(1, "SUSPEND (%s) devctl %02x power %02x\n", otg_state_string(pThis), devctl, power); handled = IRQ_HANDLED; switch (pThis->xceiv.state) { case OTG_STATE_A_PERIPHERAL: musb_hnp_stop(pThis); break; case OTG_STATE_B_PERIPHERAL: musb_g_suspend(pThis); pThis->is_active = is_otg_enabled(pThis) && pThis->xceiv.gadget->b_hnp_enable; if (pThis->is_active) { pThis->xceiv.state = OTG_STATE_B_WAIT_ACON; DBG(1, "HNP: Setting timer for b_ase0_brst\n"); musb_otg_timer.data = (unsigned long)pThis; mod_timer(&musb_otg_timer, jiffies + msecs_to_jiffies(TB_ASE0_BRST)); } break; case OTG_STATE_A_WAIT_BCON: if (pThis->a_wait_bcon != 0) musb_platform_try_idle(pThis, jiffies + msecs_to_jiffies(pThis->a_wait_bcon)); break; case OTG_STATE_A_HOST: pThis->xceiv.state = OTG_STATE_A_SUSPEND; pThis->is_active = is_otg_enabled(pThis) && pThis->xceiv.host->b_hnp_enable; break; case OTG_STATE_B_HOST: /* Transition to B_PERIPHERAL, see 6.8.2.6 p 44 */ DBG(1, "REVISIT: SUSPEND as B_HOST\n"); break; default: /* "should not happen" */ pThis->is_active = 0; break; } } return handled;}/*-------------------------------------------------------------------------*//** Program the HDRC to start (enable interrupts, dma, etc.).*/void musb_start(struct musb *musb){ void __iomem *regs = musb->pRegs; u8 devctl = musb_readb(regs, MGC_O_HDRC_DEVCTL); DBG(2, "<== devctl %02x\n", devctl); /* Set INT enable registers, enable interrupts */ musb_writew(regs, MGC_O_HDRC_INTRTXE, musb->wEndMask); musb_writew(regs, MGC_O_HDRC_INTRRXE, musb->wEndMask & 0xfffe); musb_writeb(regs, MGC_O_HDRC_INTRUSBE, 0xf7); musb_writeb(regs, MGC_O_HDRC_TESTMODE, 0); /* put into basic highspeed mode and start session */ musb_writeb(regs, MGC_O_HDRC_POWER, MGC_M_POWER_ISOUPDATE | MGC_M_POWER_SOFTCONN | MGC_M_POWER_HSENAB /* ENSUSPEND wedges tusb */ // | MGC_M_POWER_ENSUSPEND ); musb->is_active = 0; devctl = musb_readb(regs, MGC_O_HDRC_DEVCTL); devctl &= ~MGC_M_DEVCTL_SESSION; if (is_otg_enabled(musb)) { /* session started after: * (a) ID-grounded irq, host mode; * (b) vbus present/connect IRQ, peripheral mode; * (c) peripheral initiates, using SRP */ if ((devctl & MGC_M_DEVCTL_VBUS) == MGC_M_DEVCTL_VBUS) musb->is_active = 1; else devctl |= MGC_M_DEVCTL_SESSION; } else if (is_host_enabled(musb)) { /* assume ID pin is hard-wired to ground */ devctl |= MGC_M_DEVCTL_SESSION; } else /* peripheral is enabled */ { if ((devctl & MGC_M_DEVCTL_VBUS) == MGC_M_DEVCTL_VBUS) musb->is_active = 1; } musb_platform_enable(musb); musb_writeb(regs, MGC_O_HDRC_DEVCTL, devctl);}static void musb_generic_disable(struct musb *pThis){ void __iomem *pBase = pThis->pRegs; u16 temp; /* disable interrupts */ musb_writeb(pBase, MGC_O_HDRC_INTRUSBE, 0); musb_writew(pBase, MGC_O_HDRC_INTRTXE, 0); musb_writew(pBase, MGC_O_HDRC_INTRRXE, 0); /* off */ musb_writeb(pBase, MGC_O_HDRC_DEVCTL, 0); /* flush pending interrupts */ temp = musb_readb(pBase, MGC_O_HDRC_INTRUSB); temp = musb_readw(pBase, MGC_O_HDRC_INTRTX); temp = musb_readw(pBase, MGC_O_HDRC_INTRRX);}/* * Make the HDRC stop (disable interrupts, etc.); * reversible by musb_start * called on gadget driver unregister * with controller locked, irqs blocked * acts as a NOP unless some role activated the hardware */void musb_stop(struct musb *musb){ /* stop IRQs, timers, ... */ musb_platform_disable(musb); musb_generic_disable(musb); DBG(3, "HDRC disabled\n"); /* FIXME * - mark host and/or peripheral drivers unusable/inactive * - disable DMA (and enable it in HdrcStart) * - make sure we can musb_start() after musb_stop(); with * OTG mode, gadget driver module rmmod/modprobe cycles that * - ... */ musb_platform_try_idle(musb, 0);}static void musb_shutdown(struct platform_device *pdev){ struct musb *musb = dev_to_musb(&pdev->dev); unsigned long flags; spin_lock_irqsave(&musb->Lock, flags); musb_platform_disable(musb); musb_generic_disable(musb); if (musb->clock) { clk_put(musb->clock); musb->clock = NULL; } spin_unlock_irqrestore(&musb->Lock, flags); /* FIXME power down */}/*-------------------------------------------------------------------------*//* * The silicon either has hard-wired endpoint configurations, or else * "dynamic fifo" sizing. The driver has support for both, though at this * writing only the dynamic sizing is very well tested. We use normal * idioms to so both modes are compile-tested, but dead code elimination * leaves only the relevant one in the object file. * * We don't currently use dynamic fifo setup capability to do anything * more than selecting one of a bunch of predefined configurations. */#define can_dynfifo() 1static ushort __initdata fifo_mode = 4;/* "modprobe ... fifo_mode=1" etc */module_param(fifo_mode, ushort, 0);MODULE_PARM_DESC(fifo_mode, "initial endpoint configuration");#define DYN_FIFO_SIZE (1<<(MUSB_C_RAM_BITS+2))enum fifo_style { FIFO_RXTX, FIFO_TX, FIFO_RX } __attribute__ ((packed));enum buf_mode { BUF_SINGLE, BUF_DOUBLE } __attribute__ ((packed));struct fifo_cfg { u8 hw_ep_num; enum fifo_style style; enum buf_mode mode; u16 maxpacket;};/* * tables defining fifo_mode values. define more if you like. * for host side, make sure both halves of ep1 are set up. *//* mode 0 - fits in 2KB */static struct fifo_cfg __initdata mode_0_cfg[] = {{ .hw_ep_num = 1, .style = FIFO_TX, .maxpacket = 512, },{ .hw_ep_num = 1, .style = FIFO_RX, .maxpacket = 512, },{ .hw_ep_num = 2, .style = FIFO_RXTX, .maxpacket = 512, },{ .hw_ep_num = 3, .style = FIFO_RXTX, .maxpacket = 256, },{ .hw_ep_num = 4, .style = FIFO_RXTX, .maxpacket = 256, },};/* mode 1 - fits in 4KB */static struct fifo_cfg __initdata mode_1_cfg[] = {{ .hw_ep_num = 1, .style = FIFO_TX, .maxpacket = 512, .mode = BUF_DOUBLE, },{ .hw_ep_num = 1, .style = FIFO_RX, .maxpacket = 512, .mode = BUF_DOUBLE, },{ .hw_ep_num = 2, .style = FIFO_RXTX, .maxpacket = 512, .mode = BUF_DOUBLE, },{ .hw_ep_num = 3, .style = FIFO_RXTX, .maxpacket = 256, },{ .hw_ep_num = 4, .style = FIFO_RXTX, .maxpacket = 256, },};/* mode 2 - fits in 4KB */static struct fifo_cfg __initdata mode_2_cfg[] = {{ .hw_ep_num = 1, .style = FIFO_TX, .maxpacket = 512, },{ .hw_ep_num = 1, .style = FIFO_RX, .maxpacket = 512, },{ .hw_ep_num = 2, .style = FIFO_TX, .maxpacket = 512, },{ .hw_ep_num = 2, .style = FIFO_RX, .maxpacket = 512, },{ .hw_ep_num = 3, .style = FIFO_RXTX, .maxpacket = 256, },{ .hw_ep_num = 4, .style = FIFO_RXTX, .maxpacket = 256, },};/* mode 3 - fits in 4KB */static struct fifo_cfg __initdata mode_3_cfg[] = {{ .hw_ep_num = 1, .style = FIFO_TX, .maxpacket = 512, .mode = BUF_DOUBLE, },{ .hw_ep_num = 1, .style = FIFO_RX, .maxpacket = 512, .mode = BUF_DOUBLE, },{ .hw_ep_num = 2, .style = FIFO_TX, .maxpacket = 512, },{ .hw_ep_num = 2, .style = FIFO_RX, .maxpacket = 512, },{ .hw_ep_num = 3, .style = FIFO_RXTX, .maxpacket = 256, },{ .hw_ep_num = 4, .style = FIFO_RXTX, .maxpacket = 256, },};/* mode 4 - fits in 16KB */static struct fifo_cfg __initdata mode_4_cfg[] = {{ .hw_ep_num = 1, .style = FIFO_TX, .maxpacket = 512, },{ .hw_ep_num = 1, .style = FIFO_RX, .maxpacket = 512, },{ .hw_ep_num = 2, .style = FIFO_TX, .maxpacket = 512, },{ .hw_ep_num = 2, .style = FIFO_RX, .maxpacket = 512, },{ .hw_ep_num = 3, .style = FIFO_TX, .maxpacket = 512, },{ .hw_ep_num = 3, .style = FIFO_RX, .maxpacket = 512, },{ .hw_ep_num = 4, .style = FIFO_TX, .maxpacket = 512, },{ .hw_ep_num = 4, .style = FIFO_RX, .maxpacket = 512, },{ .hw_ep_num = 5, .style = FIFO_TX, .maxpacket = 512, },{ .hw_ep_num = 5, .style = FIFO_RX, .maxpacket = 512, },{ .hw_ep_num = 6, .style = FIFO_TX, .maxpacket = 512, },{ .hw_ep_num = 6, .style = FIFO_RX, .maxpacket = 512, },{ .hw_ep_num = 7, .style = FIFO_TX, .maxpacket = 512, },{ .hw_ep_num = 7, .style = FIFO_RX, .maxpacket = 512, },{ .hw_ep_num = 8, .style = FIFO_TX, .maxpacket = 512, },{ .hw_ep_num = 8, .style = FIFO_RX, .maxpacket = 512, },{ .hw_ep_num = 9, .style = FIFO_TX, .maxpacket = 512, },{ .hw_ep_num = 9, .style = FIFO_RX, .maxpacket = 512, },{ .hw_ep_num = 10, .style = FIFO_TX, .maxpacket = 512, },{ .hw_ep_num = 10, .style = FIFO_RX, .maxpacket = 512, },{ .hw_ep_num = 11, .style = FIFO_TX, .maxpacket = 512, },{ .hw_ep_num = 11, .style = FIFO_RX, .maxpacket = 512, },{ .hw_ep_num = 12, .style = FIFO_TX, .maxpacket = 512, },{ .hw_ep_num = 12, .style = FIFO_RX, .maxpacket = 512, },{ .hw_ep_num = 13, .style = FIFO_TX, .maxpacket = 512, },{ .hw_ep_num = 13, .style = FIFO_RX, .maxpacket = 512, },{ .hw_ep_num = 14, .style = FIFO_RXTX, .maxpacket = 1024, },{ .hw_ep_num = 15, .style = FIFO_RXTX, .maxpacket = 1024, },};/* * configure a fifo; for non-shared endpoints, this may be called * once for a tx fifo and once for an rx fifo. * * returns negative errno or offset for next fifo. */static int __initfifo_setup(struct musb *musb, struct musb_hw_ep *hw_ep, const struct fifo_cfg *cfg, u16 offset){ void __iomem *mbase = musb->pRegs; int size = 0; u16 maxpacket = cfg->maxpacket; u16 c_off = offset >> 3; u8 c_size; /* expect hw_ep has already been zero-initialized */ size = ffs(max(maxpacket, (u16) 8)) - 1; maxpacket = 1 << size; c_size = size - 3; if (cfg->mode == BUF_DOUBLE) { if ((offset + (maxpacket << 1)) > DYN_FIFO_SIZE) return -EMSGSIZE; c_size |= MGC_M_FIFOSZ_DPB; } else { if ((offset + maxpacket) > DYN_FIFO_SIZE) return -EMSGSIZE; } /* configure the FIFO */ musb_writeb(mbase, MGC_O_HDRC_INDEX, hw_ep->bLocalEnd); /* EP0 reserved endpoint for control, bidirectional; * EP1 reserved for bulk, two unidirection halves. */ if (hw_ep->bLocalEnd == 1) musb->bulk_ep = hw_ep; /* REVISIT error check: be sure ep0 can both rx and tx ... */ switch (cfg->style) { case FIFO_TX: musb_writeb(mbase, MGC_O_HDRC_TXFIFOSZ, c_size); musb_writew(mbase, MGC_O_HDRC_TXFIFOADD, c_off); hw_ep->tx_double_buffered = !!(c_size & MGC_M_FIFOSZ_DPB); hw_ep->wMaxPacketSizeTx = maxpacket; break; case FIFO_RX: musb_writeb(mbase, MGC_O_HDRC_RXFIFOSZ, c_size);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?