⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 usb_hcd.c

📁 8032底层驱动部分。因为可以移植 所以单独来拿出来
💻 C
📖 第 1 页 / 共 5 页
字号:
			DMA_Stop(g_UsbHcdInfo.dma_port);
		}
	
		savedMask = SaveAndSetIRQMask();
		if (DMA_CheckITStat(g_UsbHcdInfo.dma_port))
		{	
			DMA_ACKI(g_UsbHcdInfo.dma_port);
			IRQClearInt(IRQ_DMA_CODE);
		}
		RestoreIRQMask(savedMask);
	}

	/* stop USB DMA actions. Disable DMA*/
	if(g_UsbHcdInfo.dma_dir==USB_OUT_EP_TYPE)
		fm_dma_index = VUSB_FM_DMA_TX1;
	else
		fm_dma_index = VUSB_FM_DMA_RX1;
	DRV_WriteReg8(USB_DMA_DIS, 1<<fm_dma_index);

	g_UsbHcdInfo.dma_pktrdy= KAL_FALSE;
	g_UsbHcdInfo.dma_running = KAL_FALSE;

	g_UsbHcdInfo.dma_tx_ep = 0;
	g_UsbHcdInfo.dma_res_tx_ep = 0;
	g_UsbHcdInfo.fast_mode_tx_ep= 0;
	g_UsbHcdInfo.b_wait_dma = KAL_FALSE;
	g_UsbHcdInfo.b_wait_fm_done = KAL_FALSE;
}

/* stop and free DMA channel resource*/
void USB_HCD_Free_DMA_Channel(void)
{
	if(g_UsbHcdInfo.dma_port != 0)
	{
		USB_HCD_Remove_Pkt(g_UsbHcdInfo.dma_index);
		USB_HCD_Stop_DMA_Channel();
		g_UsbHcdInfo.b_wait_dma = KAL_FALSE;
		DMA_FreeChannel(g_UsbHcdInfo.dma_port);
	}	

	g_UsbHcdInfo.dma_port = 0;
}


/* DMA callback */
static void USB_HCD_DMA_Callback(void)
{
	kal_uint32	fm_dma_index;

	/* disable USB DMA*/
	if(g_UsbHcdInfo.dma_dir==USB_OUT_EP_TYPE)
		fm_dma_index = VUSB_FM_DMA_TX1;
	else
		fm_dma_index = VUSB_FM_DMA_RX1;
	DRV_WriteReg8(USB_DMA_DIS, 1<<fm_dma_index);

	/* the last pkt length not multiple of MAX_PKT_LEN, send the last pkt if needed */	
	if (g_UsbHcdInfo.dma_pktrdy)
	{	
		if(g_UsbHcdInfo.dma_dir == USB_OUT_EP_TYPE)
		{
			/* tx, config the last one packet */
			/* Note that even if fast mode is used, the tx_even_odd is right here because all data has been
			    sent to FIFO, so even_odd calculation when configuring DMA is right */
			WRITE_EP0_BDT_PID(USB_BDT_TX, g_UsbHcdInfo.tx_even_odd,
								(g_UsbHcdInfo.ep_info[g_UsbHcdInfo.dma_index].data_length<<VUSB_BDT_BC_SHIFT) |
								(g_UsbHcdInfo.ep_info[g_UsbHcdInfo.dma_index].data01<<VUSB_BDT_DATA01_SHIFT)|VUSB_BDT_OWNS_BIT);

			/* next data01 (data01 is changed before sent out), and even_odd is changed after token done */
			g_UsbHcdInfo.ep_info[g_UsbHcdInfo.dma_index].data01^=1;

			DRV_WriteReg8(USB_ENDPT_CTL(0), VUSB_ENDPT_BULK_TX);
			/* send token in the last step*/
			DRV_WriteReg8(USB_TOKEN, VUSB_TOKEN_OUT|(g_UsbHcdInfo.ep_info[g_UsbHcdInfo.dma_index].ep_num&VUSB_TOKEN_ENDPT));
		}
		else
		{
			/* rx, the last one already recevd (short pkt)*/
			/* nothing need to do */
		}
		g_UsbHcdInfo.dma_pktrdy = KAL_FALSE;
	}

	/* if application callback function dose not request to clear drv_runnung set by itself, clear running state here*/
	if(g_UsbHcdInfo.dma_callback_upd_run== KAL_FALSE)
		g_UsbHcdInfo.dma_running = KAL_FALSE;

	if(g_UsbHcdInfo.dma_res_tx_ep==0)
	{
		/* If not tx res, both tx and rx need to check both DMA and USB token done interrupt is handled */
		if(g_UsbHcdInfo.b_wait_fm_done == KAL_FALSE)
		{
			/* fast mode token done has been handled */
			if(g_UsbHcdInfo.ep_hdlr[g_UsbHcdInfo.dma_index]!=NULL)
				g_UsbHcdInfo.ep_hdlr[g_UsbHcdInfo.dma_index](USB_HCD_OK, g_UsbHcdInfo.fast_mode_data_size);
		}
		g_UsbHcdInfo.b_wait_dma = KAL_FALSE;
	}
}

/* DMA setupt function */ 
/* If the last one "callback_upd_run" parameter true => 
     application decides to clear "driver dma running status" by itself*/
void USB_HCD_DMA_Setup(kal_uint32 index, USB_EP_TYPE  type, kal_uint32 addr, kal_uint32 length, 
						kal_bool callback_upd_run)
{
	DMA_INPUT		dma_input;
   	DMA_HWMENU	dma_menu;
	kal_uint32		fm_pkt_num;
	kal_uint32		fm_dma_index;


	ASSERT(g_UsbHcdInfo.dma_running == KAL_FALSE);
	g_UsbHcdInfo.dma_running = KAL_TRUE;

	ASSERT(g_UsbHcdInfo.dma_port!=0);

	g_UsbHcdInfo.dma_callback_upd_run= callback_upd_run;
	g_UsbHcdInfo.dma_dir= type;
   	
	/*DMA_CONFIG*/
	/* single mode */
	dma_menu.TMOD.burst_mode = 0;

	if(type==USB_OUT_EP_TYPE)
	{
		dma_menu.master = DMA_USB1TX; 
		fm_dma_index = VUSB_FM_DMA_TX1;
		g_UsbHcdInfo.fast_mode_tx_ep = index;
		g_UsbHcdInfo.dma_res_tx_ep = index;
		g_UsbHcdInfo.dma_tx_ep = index;
	}
	else
	{
		dma_menu.master = DMA_USB1RX; 
		fm_dma_index = VUSB_FM_DMA_RX1;
		g_UsbHcdInfo.fast_mode_tx_ep = 0;	
		g_UsbHcdInfo.dma_res_tx_ep = 0;
		g_UsbHcdInfo.dma_tx_ep = 0;
	}

	dma_input.callback = USB_HCD_DMA_Callback;

	dma_menu.addr = (kal_uint32)addr;
	
	/* half channel */
	if(type==USB_OUT_EP_TYPE)
		dma_input.type = DMA_HWTX;
	else
		dma_input.type = DMA_HWRX;
	dma_input.menu = &dma_menu;


	/**** Configure generic DMA *****/
	if(addr&0x3)
	{
		/* address is not 4 bytes aignment, use B2W to copy data */
		dma_menu.TMOD.burst_mode = KAL_TRUE;
		dma_menu.TMOD.cycle = 4;
		dma_input.size = DMA_BYTE; 
		/* must pad length to multile of 4, this is hardware limitation */
		/* copy multiple of 4 bytes to FIFO, but still fill BDT as real packet size */ 
		if((length & 0x3) != 0)
		{
			/* Note that length must be multiple of 4, 
			    so the application receive buffer must be padding to multiple of 4.
			    If not, assert it because it may override the remaining buffer */
			if(type==USB_IN_EP_TYPE)
				EXT_ASSERT(0, type, length, 0);
			/* In tx, just padding the DMA length to multiple of 4
			    The really sent length is determined by BDT but not DMA length */
			dma_input.count= length + (4-(length & 0x3));
		}
		else
		{
			dma_input.count = length;
		}	
	}
	else 
	{
		/*address is 4 byts alignment, use word to copy data */
		dma_input.size = DMA_LONG; 
		/* must pad length to multile of 4, this is hardware limit */
		/* copy multiple of 4 bytes to FIFO, but still fill BDT as real packet size */ 
		if((length & 0x3) != 0)
		{
			/* Note that length must be multiple of 4, 
			    so the application receive buffer must be padding to multiple of 4.
			    If not, assert it because it may override the remaining buffer */
			if(type==USB_IN_EP_TYPE)
				EXT_ASSERT(0, type, length, 0);
			/* In tx, just padding the DMA length to multiple of 4
			    The really sent length is determined by BDT but not DMA length */
			dma_input.count = (length + (4-(length & 0x3)))>>2;
		}
		else
		{
			dma_input.count = length>>2;
		}
	}
	
	/* see if it is mutiple of max packet length*/
	/* length % 64 */	
	if(length & 0x3f)
	{
		g_UsbHcdInfo.dma_pktrdy = KAL_TRUE;
		/* the last residue packet size */
		g_UsbHcdInfo.dma_pktlength = length&0x3f;
	}
	else
	{
		g_UsbHcdInfo.dma_res_tx_ep = 0;
		/* do not need one more packet for the residue of 64 bytes*/
		g_UsbHcdInfo.dma_pktrdy = KAL_FALSE;
		/* the last residue packet size */
		g_UsbHcdInfo.dma_pktlength = 0;
	}
	/* Configure DMA */
	DMA_Config_B2W(g_UsbHcdInfo.dma_port, &dma_input, KAL_TRUE, dma_menu.TMOD.burst_mode);
	
	/**** Configure Fast mode *****/
	/* length/64*/
	fm_pkt_num = length >> 6 ;
	/* for rx less than 64 bytes packet, pad to receive 64 bytes*/
	if((g_UsbHcdInfo.dma_pktrdy ==KAL_TRUE) && (type==USB_IN_EP_TYPE))
		fm_pkt_num += 1;
		
	/* Setup BDT */
	if(type==USB_OUT_EP_TYPE)	 
	{
		WRITE_EP0_BDT_PID(USB_BDT_TX, g_UsbHcdInfo.tx_even_odd,
								(USB_EP_BULK_MAXP << VUSB_BDT_BC_SHIFT) |
								(g_UsbHcdInfo.ep_info[index].data01<<VUSB_BDT_DATA01_SHIFT) |VUSB_BDT_OWNS_BIT);
		/* Update data toggle flag*/
		if(fm_pkt_num&0x1)
			g_UsbHcdInfo.ep_info[index].data01^=1;
	}
	else
	{
		WRITE_EP0_BDT_PID(USB_BDT_RX, g_UsbHcdInfo.rx_even_odd,
								(USB_EP_BULK_MAXP << VUSB_BDT_BC_SHIFT) |
								(g_UsbHcdInfo.ep_info[index].data01<<VUSB_BDT_DATA01_SHIFT) |VUSB_BDT_OWNS_BIT);
		/* Update data toggle flag*/
		if(fm_pkt_num&0x1)
			g_UsbHcdInfo.ep_info[index].data01^=1;
	}
	
	/* Set transfer number*/
	DRV_WriteReg8(USB_FM_PKT_NUML, fm_pkt_num&0xff);
	DRV_WriteReg8(USB_FM_PKT_NUMH, (fm_pkt_num>>8)&0xff);
	DRV_WriteReg8(USB_FM_PKT_CNTL, 0);
	DRV_WriteReg8(USB_FM_PKT_CNTH, 0);

	g_UsbHcdInfo.dma_index = index;
	g_UsbHcdInfo.fast_mode_data_size = 0;

	g_UsbHcdInfo.b_wait_dma = KAL_FALSE;
	g_UsbHcdInfo.b_wait_fm_done = KAL_FALSE;

	/* Enable fast mode only if fm_count > 0*/
	if(fm_pkt_num > 0)
	{
		/* Note that this should set before enable DMA */
		g_UsbHcdInfo.b_wait_dma = KAL_TRUE;
		g_UsbHcdInfo.b_wait_fm_done = KAL_TRUE;
		// set IN-NAK timeout as interval * 64 ms
		/* Select DMA channel of fm engine*/
		DRV_WriteReg8(USB_DMA_FM_SELECT, fm_dma_index);
		DRV_WriteReg8(USB_FM_TIMEOUT, g_UsbHcdInfo.ep_info[index].interval);
		if(DRV_Reg8(USB_FM_CTL)&VUSB_FM_CTL_SUCERREN)
			DRV_WriteReg8(USB_FM_CTL, (VUSB_FM_CTL_SUCERREN|VUSB_FM_CTL_FMENB)&(~VUSB_FM_CTL_SUCERREN));
		else
			DRV_WriteReg8(USB_FM_CTL, VUSB_FM_CTL_SUCERREN|VUSB_FM_CTL_FMENB);
	}
	else
	{
		/* Enable DMA only for tx with fm_count==0 */
		/* If tx packet length is less than 64 bytes, this conditionis matched */
		g_UsbHcdInfo.fast_mode_tx_ep = 0;
		DRV_WriteReg8(USB_DMA_ENB, 1<<fm_dma_index);
	}
		
	if(type==USB_IN_EP_TYPE)
	{
		DRV_WriteReg8(USB_ENDPT_CTL(0), VUSB_ENDPT_BULK_RX);
		
		/* send token in the last step*/
		DRV_WriteReg8(USB_TOKEN, VUSB_TOKEN_IN|(g_UsbHcdInfo.ep_info[index].ep_num&VUSB_TOKEN_ENDPT));
	}
	else if((fm_pkt_num > 0) && (type==USB_OUT_EP_TYPE))
	{
		/* for only tx res condition, let DMA done handler to send the token*/
		DRV_WriteReg8(USB_ENDPT_CTL(0), VUSB_ENDPT_BULK_TX);

		/* send token in the last step*/
		DRV_WriteReg8(USB_TOKEN, VUSB_TOKEN_OUT|(g_UsbHcdInfo.ep_info[index].ep_num&VUSB_TOKEN_ENDPT));
	}	
}



/************************************************************
	HCD HISR
*************************************************************/

void USB_HCD_HISR(void)
{
	volatile kal_uint8	IntrStatus;
	volatile kal_uint8	ErrorStatus;
	volatile kal_uint8	FastErrorStatus;
	volatile kal_uint8	direction;
	volatile kal_uint8	even_odd;
	volatile kal_uint32	status;
	volatile kal_uint8	fm_even_odd;
	kal_uint8			current_ep_index;
	kal_uint8	pkt_length;
	kal_bool			b_fast_mode = KAL_FALSE;
	kal_bool	b_schedule = KAL_FALSE;
	kal_bool	b_dis_schedule = KAL_FALSE;

	g_UsbHcdInfo.b_unmask_irq = KAL_TRUE;

	IntrStatus = DRV_Reg8(USB_INT_STAT)&DRV_Reg8(USB_INT_ENB);
	ErrorStatus = DRV_Reg8(USB_ERR_STAT)&DRV_Reg8(USB_ERR_ENB);
	FastErrorStatus = DRV_Reg8(USB_FM_ERR_STAT);

	/* Get the direction and status of the transfer before clear interrupt status*/      
	direction = (DRV_Reg8(USB_STAT) >> 3) & 0x01;
	even_odd = (DRV_Reg8(USB_STAT) >> 2) & 0x01;
		
	/* Clear interrupt*/
	if(FastErrorStatus&(VUSB_FM_ERR_SHORT_ERR|VUSB_FM_ERR_NAK_ERR|VUSB_FM_ERR_SUC_ERR))
	{
		/* Should handle short packet here */
		DRV_WriteReg8(USB_FM_ERR_STAT, FastErrorStatus&(VUSB_FM_ERR_SHORT_ERR|VUSB_FM_ERR_NAK_ERR|VUSB_FM_ERR_SUC_ERR));
	}
	DRV_WriteReg8(USB_INT_STAT, IntrStatus);
	DRV_WriteReg8(USB_ERR_STAT, ErrorStatus);

	/* Software should not control to happen this*/
	if(FastErrorStatus&USB_FM_ERR_STA_OVR_FLW)
		EXT_ASSERT(0, FastErrorStatus, 0, 0);

	if (IntrStatus & VUSB_INT_STAT_RESET)
	{
		if(g_UsbHcdInfo.dma_running==KAL_TRUE)
		{
			if((g_UsbHcdInfo.dma_index==-1) || (g_UsbHcdInfo.dma_index!=g_UsbHcdInfo.processing_ep_id))
				EXT_ASSERT(0, g_UsbHcdInfo.dma_index, g_UsbHcdInfo.processing_ep_id, 0);
			if(g_UsbHcdInfo.ep_hdlr[g_UsbHcdInfo.dma_index]!=NULL)
				g_UsbHcdInfo.ep_hdlr[g_UsbHcdInfo.dma_index](USB_HCD_DETATCH, 0);
			USB_HCD_Remove_Pkt(g_UsbHcdInfo.dma_index);
			USB_HCD_Stop_DMA_Channel();
			g_UsbHcdInfo.b_wait_dma = KAL_FALSE;
			 g_UsbHcdInfo.processing_ep_id = -1;
		}

		/* Remove and notify all queued endpoints */
		{
			kal_int8 queue_index = -1;
			queue_index = USB_HCD_Get_Pending_Pkts();
			while(queue_index!=-1)
			{
				USB_HCD_Remove_Pkt(queue_index);
				if(g_UsbHcdInfo.ep_hdlr[queue_index]!=NULL)
					g_UsbHcdInfo.ep_hdlr[queue_index](USB_HCD_DETATCH, 0);
				queue_index = USB_HCD_Get_Pending_Pkts();
			}
		}	
		
		USB_HCD_Process_Detach();
		g_UsbHcdInfo.rx_curent_index = -1;
		g_UsbHcdInfo.tx_curent_index = -1;
		g_UsbHcdInfo.processing_ep_id = -1;
 		
		return;
	} /* End VUSB_INT_STAT_RESET */


	if(IntrStatus&VUSB_INT_STAT_TOKEN_DONE)
	{
		/* update scheduler*/
		current_ep_index = g_UsbHcdInfo.processing_ep_id;
		USB_HCD_Remove_Pkt(g_UsbHcdInfo.processing_ep_id);
		g_UsbHcdInfo.processing_ep_id = -1;
		
		if(direction==USB_BDT_RX)
		{
			status = READ_EP0_BDT_PID(USB_BDT_RX, even_odd)&VUSB_BDT_PID_MASKS;
		}
		else
		{
			status = READ_EP0_BDT_PID(USB_BDT_TX, even_odd)&VUSB_BDT_PID_MASKS;
		}

		/* re-queue the NAK or error packets to the end*/
		if((g_UsbHcdInfo.ep_info[current_ep_index].ep_type!=USB_HCD_ENDPT_ISO)
			&& ((status==VUSB_BDT_BUS_TIMEOUT_PID) || (status == VUSB_BDT_NAK_PID) ||
				(status == VUSB_BDT_ERROR_PID) || (status == VUSB_BDT_STALL_PID) || (ErrorStatus)))
		{
			if(direction==USB_BDT_RX)
			{
				g_UsbHcdInfo.rx_curent_index = -1;
				/* next even odd */
				g_UsbHcdInfo.rx_even_odd = even_odd^1;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -