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

📄 xusbps_endpoint.c

📁 定制简单LED的IP核的设计源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
						(Td * EpCfg[EpNum].Out.BufSize),					EpCfg[EpNum].Out.BufSize);			if (XST_SUCCESS != Status) {				return XST_FAILURE;			}			XUsbPs_dTDFlushCache(&Out->dTDs[Td]);		}		/* IN Descriptors		 * ==============		 *		 * + Set the next link pointer		 * + Set the Terminate bit to mark it available		 */		if (XUSBPS_EP_TYPE_NONE != EpCfg[EpNum].In.Type) {			NumdTD = EpCfg[EpNum].In.NumBufs;		}		else {			NumdTD = 0;		}		for (Td = 0; Td < NumdTD; ++Td) {			int NextTd = (Td + 1) % NumdTD;			XUsbPs_dTDInvalidateCache(&In->dTDs[Td]);			/* Set NEXT link pointer. */			XUsbPs_WritedTD(In->dTDs[Td], XUSBPS_dTDNLP,					  In->dTDs[NextTd]);			/* Set the IN descriptor's TERMINATE bits. */			XUsbPs_dTDSetTerminate(In->dTDs[Td]);			XUsbPs_dTDFlushCache(&In->dTDs[Td]);		}	}	return XST_SUCCESS;}/*****************************************************************************//** * * This function associates a buffer with a Transfer Descriptor. The function * will take care of splitting the buffer into multiple 4kB aligned segments if * the buffer happens to span one or more 4kB pages. * * @param	dTDIndex is a pointer to the Transfer Descriptor * @param	BufferPtr is pointer to the buffer to link to the descriptor. * @param	BufferLen is the length of the buffer. * * @return *		- XST_SUCCESS: The operation completed successfully. *		- XST_FAILURE: An error occured. *		- XST_USB_BUF_TOO_BIG: The provided buffer is bigger than tha *		maximum allowed buffer size (16k). * * @note * 		Cache invalidation and flushing needs to be handler by the * 		caller of this function. * ******************************************************************************/static int XUsbPs_dTDAttachBuffer(XUsbPs_dTD *dTDPtr,					const u8 *BufferPtr, u32 BufferLen){	u32	BufAddr;	u32	BufEnd;	u32	PtrNum;	Xil_AssertNonvoid(dTDPtr    != NULL);	/* Check if the buffer is smaller than 16kB. */	if (BufferLen > XUSBPS_dTD_BUF_MAX_SIZE) {		return XST_USB_BUF_TOO_BIG;	}	/* Get a u32 of the buffer pointer to avoid casting in the following	 * logic operations.	 */	BufAddr = (u32) BufferPtr;	/* Set the buffer pointer 0. Buffer pointer 0 can point to any location	 * in memory. It does not need to be 4kB aligned. However, if the	 * provided buffer spans one or more 4kB boundaries, we need to set up	 * the subsequent buffer pointers which must be 4kB aligned.	 */	XUsbPs_WritedTD(dTDPtr, XUSBPS_dTDBPTR(0), BufAddr);	/* Check if the buffer spans a 4kB boundary.	 *	 * Only do this check, if we are not sending a 0-length buffer.	 */	if (BufferLen > 0) {		BufEnd = BufAddr + BufferLen -1;		PtrNum = 1;		while ((BufAddr & 0xFFFFF000) != (BufEnd & 0xFFFFF000)) {			/* The buffer spans at least one boundary, let's set			 * the next buffer pointer and repeat the procedure			 * until the end of the buffer and the pointer written			 * are in the same 4kB page.			 */			BufAddr = (BufAddr + 0x1000) & 0xFFFFF000;			XUsbPs_WritedTD(dTDPtr, XUSBPS_dTDBPTR(PtrNum),								BufAddr);			PtrNum++;		}	}	/* Set the length of the buffer. */	XUsbPs_dTDSetTransferLen(dTDPtr, BufferLen);	/* We remember the buffer pointer in the user data field (reserved	 * field in the dTD). This makes it easier to reset the buffer pointer	 * after a buffer has been received on the endpoint. The buffer pointer	 * needs to be reset because the DMA engine modifies the buffer pointer	 * while receiving.	 */	XUsbPs_WritedTD(dTDPtr, XUSBPS_dTDUSERDATA, BufferPtr);	return XST_SUCCESS;}/*****************************************************************************//** * This function set the Max PacketLen for the queue head for isochronous EP. * * If the max packet length is greater than XUSBPS_MAX_PACKET_SIZE, then * Mult bits are set to reflect that. * * @param	dQHPtr is a pointer to the dQH element. * @param	Len is the Length to be set. * ******************************************************************************/static void XUsbPs_dQHSetMaxPacketLenISO(XUsbPs_dQH *dQHPtr, u32 Len){	int mult = (Len & ENDPOINT_MAXP_MULT_MASK) >> ENDPOINT_MAXP_MULT_SHIFT;	int maxp_size = (int)(Len & ENDPOINT_MAXP_LENGTH_MASK);	if(maxp_size > XUSBPS_MAX_PACKET_SIZE){		return;	}	if(mult > 2) {		return;	}	/* Ch9 uses zero-based count on mult, CI uses one-based count. */	mult += 1;	XUsbPs_WritedQH(dQHPtr, XUSBPS_dQHCFG,		(XUsbPs_ReaddQH(dQHPtr, XUSBPS_dQHCFG) &			~XUSBPS_dQHCFG_MPL_MASK) |			(maxp_size << XUSBPS_dQHCFG_MPL_SHIFT));	/* Set Mult to tell hardware how many transactions in each microframe */	XUsbPs_WritedQH(dQHPtr, XUSBPS_dQHCFG,		(XUsbPs_ReaddQH(dQHPtr, XUSBPS_dQHCFG) &			~XUSBPS_dQHCFG_MULT_MASK) |			(mult << XUSBPS_dQHCFG_MULT_SHIFT));}/*****************************************************************************//*** This function reconfigures one Ep corresponding to host's request of setting* alternate interface. The endpoint has been disabled before this call.** Both QH and dTDs are updated for the new configuration.** @param	InstancePtr is a pointer to the XUsbPs instance of the*		controller.* @param	CfgPtr* 		Pointer to the updated XUsbPs DEVICE configuration structure.** @param	EpNum*		The endpoint to be reconfigured.** @param NewDirection*		The new transfer direction the endpoint.** @param DirectionChanged*		A boolean value indicate whether the transfer direction has changed.** @return*	XST_SUCCESS upon success, XST_FAILURE otherwise.*******************************************************************************/int XUsbPs_ReconfigureEp(XUsbPs *InstancePtr, XUsbPs_DeviceConfig *CfgPtr,				int EpNum, unsigned short NewDirection,				int DirectionChanged) {	int Status = XST_SUCCESS;	XUsbPs_Endpoint *Ep;	XUsbPs_EpConfig *EpCfg;	Xil_AssertNonvoid(InstancePtr != NULL);	Xil_AssertNonvoid(CfgPtr      != NULL);	Ep = CfgPtr->Ep;	EpCfg = CfgPtr->EpCfg;	/* If transfer direction changes, dTDs has to be reset	 * Number of buffers are preset and should not to be changed.	 */	if(DirectionChanged) {		if(NewDirection == XUSBPS_EP_DIRECTION_OUT) {			u8 *p;			/* Swap the pointer to the dTDs.			 */			Ep[EpNum].Out.dTDs = Ep[EpNum].In.dTDs;			p = (u8 *)(Ep[EpNum].Out.dTDs + XUSBPS_dTD_ALIGN * EpCfg[EpNum].Out.NumBufs);			/* Set the OUT buffer if buffer size is not zero			 */			if(EpCfg[EpNum].Out.BufSize > 0) {				Ep[EpNum].Out.dTDBufs = p;			}		} else if(NewDirection == XUSBPS_EP_DIRECTION_IN) {			Ep[EpNum].In.dTDs = Ep[EpNum].Out.dTDs;		}	}	/* Reset dTD progress tracking pointers	 */	if(NewDirection == XUSBPS_EP_DIRECTION_IN) {		Ep[EpNum].In.dTDHead = Ep[EpNum].In.dTDTail = Ep[EpNum].In.dTDs;	} else if(NewDirection == XUSBPS_EP_DIRECTION_OUT) {		Ep[EpNum].Out.dTDCurr = Ep[EpNum].Out.dTDs;	}	/* Reinitialize information in QH	 */	XUsbPs_dQHReinitEp(CfgPtr, EpNum, NewDirection);	/* Reinitialize the dTD linked list, and flush the cache	 */	Status = XUsbPs_dTDReinitEp(CfgPtr, EpNum, NewDirection);	if(Status != XST_SUCCESS) {		return Status;	}	return XST_SUCCESS;}/*****************************************************************************//** * This function re-initializes the Queue Head List in memory. * The endpoint 1 has been disabled before this call. * * @param	DevCfgPtr * 		Pointer to the updated XUsbPs DEVICE configuration structure. * * @param	EpNum *		The endpoint to be reconfigured. * * @param	NewDirection *		The new transfer direction of endpoint 1 * * @return	none * ******************************************************************************/static void XUsbPs_dQHReinitEp(XUsbPs_DeviceConfig *DevCfgPtr,int EpNum, unsigned short NewDirection){	XUsbPs_Endpoint	*Ep;	XUsbPs_EpConfig	*EpCfg;	/* Setup pointers for simpler access.	 */	Ep	= DevCfgPtr->Ep;	EpCfg	= DevCfgPtr->EpCfg;	/* Go through the list of Queue Head entries and:	 *	 * - Set Transfer Descriptor addresses	 * - Set Maximum Packet Size	 * - Disable Zero Length Termination (ZLT) for non-isochronous transfers	 * - Enable Interrupt On Setup (IOS)	 *	 */	if(NewDirection == XUSBPS_EP_DIRECTION_OUT) {		/* OUT Queue Heads.		 */		XUsbPs_WritedQH(Ep[EpNum].Out.dQH,			XUSBPS_dQHCPTR, Ep[EpNum].Out.dTDs);		/* For isochronous, ep max packet size translates to different		 * values in queue head than other types.		 * Also	enable ZLT for isochronous.		 */		if(XUSBPS_EP_TYPE_ISOCHRONOUS == EpCfg[EpNum].Out.Type) {			XUsbPs_dQHSetMaxPacketLenISO(Ep[EpNum].Out.dQH,   					EpCfg[EpNum].Out.MaxPacketSize);			XUsbPs_dQHEnableZLT(Ep[EpNum].Out.dQH);		}else {			XUsbPs_dQHSetMaxPacketLen(Ep[EpNum].Out.dQH,				    EpCfg[EpNum].Out.MaxPacketSize);			XUsbPs_dQHDisableZLT(Ep[EpNum].Out.dQH);		}		XUsbPs_dQHSetIOS(Ep[EpNum].Out.dQH);		/* Set up the overlay next dTD pointer.		 */		XUsbPs_WritedQH(Ep[EpNum].Out.dQH,				XUSBPS_dQHdTDNLP, Ep[EpNum].Out.dTDs);		XUsbPs_dQHFlushCache(Ep[EpNum].Out.dQH);	} else if(NewDirection == XUSBPS_EP_DIRECTION_IN) {		/* IN Queue Heads.		 */		XUsbPs_WritedQH(Ep[EpNum].In.dQH,			  XUSBPS_dQHCPTR, Ep[EpNum].In.dTDs);		/* Isochronous ep packet size can be larger than 1024. */		if(XUSBPS_EP_TYPE_ISOCHRONOUS == EpCfg[EpNum].In.Type) {			XUsbPs_dQHSetMaxPacketLenISO(Ep[EpNum].In.dQH,   				EpCfg[EpNum].In.MaxPacketSize);			XUsbPs_dQHEnableZLT(Ep[EpNum].In.dQH);		}else {			XUsbPs_dQHSetMaxPacketLen(Ep[EpNum].In.dQH,			    EpCfg[EpNum].In.MaxPacketSize);			XUsbPs_dQHDisableZLT(Ep[EpNum].In.dQH);		}		XUsbPs_dQHSetIOS(Ep[EpNum].In.dQH);		XUsbPs_dQHFlushCache(Ep[EpNum].In.dQH);	}}/*****************************************************************************//** * * This function re-initializes the Transfer Descriptors lists in memory. * The endpoint has been disabled before the call. The transfer descriptors * list pointer has been initialized too. * * @param	DevCfgPtr * 		Pointer to the XUsbPs DEVICE configuration structure. * * @param	EpNum *		The endpoint to be reconfigured. * * @param	NewDirection *		The new transfer direction of endpoint 1 * * @return *		- XST_SUCCESS: The operation completed successfully. *		- XST_FAILURE: An error occured. * ******************************************************************************/static int XUsbPs_dTDReinitEp(XUsbPs_DeviceConfig *DevCfgPtr,int EpNum, unsigned short NewDirection){	XUsbPs_Endpoint	*Ep;	XUsbPs_EpConfig	*EpCfg;	int	Td;	int	NumdTD;	/* Setup pointers for simpler access.	 */	Ep	= DevCfgPtr->Ep;	EpCfg	= DevCfgPtr->EpCfg;	if(NewDirection == XUSBPS_EP_DIRECTION_OUT) {		XUsbPs_EpOut	*Out = &Ep[EpNum].Out;		/* OUT Descriptors		 * ===============		 *		 * + Set the next link pointer		 * + Set the interrupt complete and the active bit		 * + Attach the buffer to the dTD		 */		NumdTD = EpCfg[EpNum].Out.NumBufs;		for (Td = 0; Td < NumdTD; ++Td) {			int	Status;			int NextTd = (Td + 1) % NumdTD;			XUsbPs_dTDInvalidateCache(&Out->dTDs[Td]);			/* Set NEXT link pointer.			 */			XUsbPs_WritedTD(&Out->dTDs[Td], XUSBPS_dTDNLP,					  &Out->dTDs[NextTd]);			/* Set the OUT descriptor ACTIVE and enable the			 * interrupt on complete.			 */			XUsbPs_dTDSetActive(&Out->dTDs[Td]);			XUsbPs_dTDSetIOC(&Out->dTDs[Td]);			/* Set up the data buffer with the descriptor. If the			 * buffer pointer is NULL it means that we do not need			 * to attach a buffer to this descriptor.			 */			if (Out->dTDBufs != NULL) {				Status = XUsbPs_dTDAttachBuffer(						&Out->dTDs[Td],						Out->dTDBufs +							(Td * EpCfg[EpNum].Out.BufSize),						EpCfg[EpNum].Out.BufSize);				if (Status != XST_SUCCESS) {					return XST_FAILURE;				}			}			XUsbPs_dTDFlushCache(&Out->dTDs[Td]);		}	} else if(NewDirection == XUSBPS_EP_DIRECTION_IN) {		XUsbPs_EpIn	*In  = &Ep[EpNum].In;		/* IN Descriptors		 * ==============		 *		 * + Set the next link pointer		 * + Set the Terminate bit to mark it available		 */		NumdTD = EpCfg[EpNum].In.NumBufs;		for (Td = 0; Td < NumdTD; ++Td) {			int NextTd = (Td + 1) % NumdTD;			XUsbPs_dTDInvalidateCache(&In->dTDs[Td]);			/* Set NEXT link pointer.			 */			XUsbPs_WritedTD(&In->dTDs[Td], XUSBPS_dTDNLP,					  &In->dTDs[NextTd]);			/* Set the IN descriptor's TERMINATE bits.			 */			XUsbPs_dTDSetTerminate(&In->dTDs[Td]);			XUsbPs_dTDFlushCache(&In->dTDs[Td]);		}	}	return XST_SUCCESS;}

⌨️ 快捷键说明

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