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 + -
显示快捷键?