📄 xusbps_endpoint.c
字号:
/******************************************************************************** (c) Copyright 2010-12 Xilinx, Inc. All rights reserved.** This file contains confidential and proprietary information of Xilinx, Inc.* and is protected under U.S. and international copyright and other* intellectual property laws.** DISCLAIMER* This disclaimer is not a license and does not grant any rights to the* materials distributed herewith. Except as otherwise provided in a valid* license issued to you by Xilinx, and to the maximum extent permitted by* applicable law: (1) THESE MATERIALS ARE MADE AVAILABLE "AS IS" AND WITH ALL* FAULTS, AND XILINX HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, EXPRESS,* IMPLIED, OR STATUTORY, INCLUDING BUT NOT LIMITED TO WARRANTIES OF* MERCHANTABILITY, NON-INFRINGEMENT, OR FITNESS FOR ANY PARTICULAR PURPOSE;* and (2) Xilinx shall not be liable (whether in contract or tort, including* negligence, or under any other theory of liability) for any loss or damage* of any kind or nature related to, arising under or in connection with these* materials, including for any direct, or any indirect, special, incidental,* or consequential loss or damage (including loss of data, profits, goodwill,* or any type of loss or damage suffered as a result of any action brought by* a third party) even if such damage or loss was reasonably foreseeable or* Xilinx had been advised of the possibility of the same.** CRITICAL APPLICATIONS* Xilinx products are not designed or intended to be fail-safe, or for use in* any application requiring fail-safe performance, such as life-support or* safety devices or systems, Class III medical devices, nuclear facilities,* applications related to the deployment of airbags, or any other applications* that could lead to death, personal injury, or severe property or* environmental damage (individually and collectively, "Critical* Applications"). Customer assumes the sole risk and liability of any use of* Xilinx products in Critical Applications, subject only to applicable laws* and regulations governing limitations on product liability.** THIS COPYRIGHT NOTICE AND DISCLAIMER MUST BE RETAINED AS PART OF THIS FILE* AT ALL TIMES.*******************************************************************************//******************************************************************************//** * @file xusbps_endpoint.c * * Endpoint specific function implementations. * * @note None. * * <pre> * MODIFICATION HISTORY: * * Ver Who Date Changes * ----- ---- -------- -------------------------------------------------------- * 1.00a jz 10/10/10 First release * </pre> ******************************************************************************//***************************** Include Files **********************************/#include <string.h> /* for bzero() */#include <stdio.h>#include "xusbps.h"#include "xusbps_endpoint.h"/************************** Constant Definitions ******************************//**************************** Type Definitions ********************************//************************** Variable Definitions ******************************//************************** Function Prototypes ******************************/static void XUsbPs_EpListInit(XUsbPs_DeviceConfig *DevCfgPtr);static void XUsbPs_dQHInit(XUsbPs_DeviceConfig *DevCfgPtr);static int XUsbPs_dTDInit(XUsbPs_DeviceConfig *DevCfgPtr);static int XUsbPs_dTDAttachBuffer(XUsbPs_dTD *dTDPtr, const u8 *BufferPtr, u32 BufferLen);static void XUsbPs_dQHSetMaxPacketLenISO(XUsbPs_dQH *dQHPtr, u32 Len);/* Functions to reconfigure endpoint upon host's set alternate interface * request. */static void XUsbPs_dQHReinitEp(XUsbPs_DeviceConfig *DevCfgPtr, int EpNum, unsigned short NewDirection);static int XUsbPs_dTDReinitEp(XUsbPs_DeviceConfig *DevCfgPtr, int EpNum, unsigned short NewDirection);/******************************* Functions ************************************//*****************************************************************************//** * * This function configures the DEVICE side of the controller. The caller needs * to pass in the desired configuration (e.g. number of endpoints) and a * DMAable buffer that will hold the Queue Head List and the Transfer * Descriptors. The required size for this buffer can be obtained by the caller * using the: XUsbPs_DeviceMemRequired() macro. * * @param InstancePtr is a pointer to the XUsbPs instance of the * controller. * @param CfgPtr is a pointer to the configuration structure that contains * the desired DEVICE side configuration. * * @return * - XST_SUCCESS: The operation completed successfully. * - XST_FAILURE: An error occured. * * @note * The caller may configure the controller for both, DEVICE and * HOST side. * ******************************************************************************/int XUsbPs_ConfigureDevice(XUsbPs *InstancePtr, const XUsbPs_DeviceConfig *CfgPtr){ int Status; u32 ModeValue = 0x0; Xil_AssertNonvoid(InstancePtr != NULL); Xil_AssertNonvoid(CfgPtr != NULL); /* Copy the configuration data over into the local instance structure */ InstancePtr->DeviceConfig = *CfgPtr; /* Align the buffer to a 2048 byte (XUSBPS_dQH_BASE_ALIGN) boundary.*/ InstancePtr->DeviceConfig.PhysAligned = (InstancePtr->DeviceConfig.DMAMemPhys + XUSBPS_dQH_BASE_ALIGN) & ~(XUSBPS_dQH_BASE_ALIGN -1); /* Clear out the buffer.*/ memset((void *) InstancePtr->DeviceConfig.DMAMemPhys, 0, XUsbPs_DeviceMemRequired(&InstancePtr->DeviceConfig)); /* Initialize the endpoint pointer list data structure. */ XUsbPs_EpListInit(&InstancePtr->DeviceConfig); /* Initialize the Queue Head structures in DMA memory. */ XUsbPs_dQHInit(&InstancePtr->DeviceConfig); /* Initialize the Transfer Descriptors in DMA memory.*/ Status = XUsbPs_dTDInit(&InstancePtr->DeviceConfig); if (XST_SUCCESS != Status) { return XST_FAILURE; } /* Changing the DEVICE mode requires a controller RESET. */ if (XST_SUCCESS != XUsbPs_Reset(InstancePtr)) { return XST_FAILURE; } /* Set the Queue Head List address. */ XUsbPs_WriteReg(InstancePtr->Config.BaseAddress, XUSBPS_EPLISTADDR_OFFSET, InstancePtr->DeviceConfig.PhysAligned); /* Set the USB mode register to configure DEVICE mode. * * XUSBPS_MODE_SLOM_MASK note: * Disable Setup Lockout. Setup Lockout is not required as we * will be using the tripwire mechanism when handling setup * packets. */ ModeValue = XUSBPS_MODE_CM_DEVICE_MASK | XUSBPS_MODE_SLOM_MASK; XUsbPs_WriteReg(InstancePtr->Config.BaseAddress, XUSBPS_MODE_OFFSET, ModeValue); XUsbPs_SetBits(InstancePtr, XUSBPS_OTGCSR_OFFSET, XUSBPS_OTGSC_OT_MASK); return XST_SUCCESS;}/*****************************************************************************//*** This function sends a given data buffer.** @param InstancePtr is a pointer to XUsbPs instance of the controller.* @param EpNum is the number of the endpoint to receive data from.* @param BufferPtr is a pointer to the buffer to send.* @param BufferLen is the Buffer length.** @return* - XST_SUCCESS: The operation completed successfully.* - XST_FAILURE: An error occured.* - XST_USB_BUF_TOO_BIG: Provided buffer is too big (>16kB).* - XST_USB_NO_DESC_AVAILABLE: No TX descriptor is available.*******************************************************************************/int XUsbPs_EpBufferSend(XUsbPs *InstancePtr, u8 EpNum, const u8 *BufferPtr, u32 BufferLen){ int Status; u32 Token; XUsbPs_EpIn *Ep; XUsbPs_dTD *DescPtr; u32 Length; u32 PipeEmpty = 1; u32 Mask = 0x00010000; u32 BitMask = Mask << EpNum; u32 RegValue; u32 Temp; Xil_AssertNonvoid(InstancePtr != NULL); Xil_AssertNonvoid(EpNum < InstancePtr->DeviceConfig.NumEndpoints); /* Locate the next available buffer in the ring. A buffer is available * if its descriptor is not active. */ Ep = &InstancePtr->DeviceConfig.Ep[EpNum].In; Xil_DCacheFlushRange((unsigned int)BufferPtr, BufferLen); if(Ep->dTDTail != Ep->dTDHead) { PipeEmpty = 0; } XUsbPs_dTDInvalidateCache(Ep->dTDHead); /* Tell the caller if we do not have any descriptors available. */ if (XUsbPs_dTDIsActive(Ep->dTDHead)) { return XST_USB_NO_DESC_AVAILABLE; } /* Remember the current head. */ DescPtr = Ep->dTDHead; do { Length = (BufferLen > XUSBPS_dTD_BUF_MAX_SIZE) ? XUSBPS_dTD_BUF_MAX_SIZE : BufferLen; /* Attach the provided buffer to the current descriptor.*/ Status = XUsbPs_dTDAttachBuffer(Ep->dTDHead, BufferPtr, Length); if (XST_SUCCESS != Status) { return XST_FAILURE; } BufferLen -= Length; BufferPtr += Length; XUsbPs_dTDSetActive(Ep->dTDHead); if(BufferLen == 0) XUsbPs_dTDSetIOC(Ep->dTDHead); XUsbPs_dTDClrTerminate(Ep->dTDHead); XUsbPs_dTDFlushCache(Ep->dTDHead); /* Advance the head descriptor pointer to the next descriptor. */ Ep->dTDHead = XUsbPs_dTDGetNLP(Ep->dTDHead); /* Terminate the next descriptor and flush the cache.*/ XUsbPs_dTDInvalidateCache(Ep->dTDHead); /* Tell the caller if we do not have any descriptors available. */ if (XUsbPs_dTDIsActive(Ep->dTDHead)) { return XST_USB_NO_DESC_AVAILABLE; } } while(BufferLen); XUsbPs_dTDSetTerminate(Ep->dTDHead); XUsbPs_dTDFlushCache(Ep->dTDHead); if(!PipeEmpty) { /* Read the endpoint prime register. */ RegValue = XUsbPs_ReadReg(InstancePtr->Config.BaseAddress, XUSBPS_EPPRIME_OFFSET); if(RegValue & BitMask) { return XST_SUCCESS; } do { RegValue = XUsbPs_ReadReg(InstancePtr->Config.BaseAddress, XUSBPS_CMD_OFFSET); XUsbPs_WriteReg(InstancePtr->Config.BaseAddress, XUSBPS_CMD_OFFSET, RegValue | XUSBPS_CMD_ATDTW_MASK); Temp = XUsbPs_ReadReg(InstancePtr->Config.BaseAddress, XUSBPS_EPRDY_OFFSET) & BitMask; } while(!(XUsbPs_ReadReg(InstancePtr->Config.BaseAddress, XUSBPS_CMD_OFFSET) & XUSBPS_CMD_ATDTW_MASK)); RegValue = XUsbPs_ReadReg(InstancePtr->Config.BaseAddress, XUSBPS_CMD_OFFSET); XUsbPs_WriteReg(InstancePtr->Config.BaseAddress, XUSBPS_CMD_OFFSET, RegValue & ~XUSBPS_CMD_ATDTW_MASK); if(Temp) { return XST_SUCCESS; } } /* Check, if the DMA engine is still running. If it is running, we do * not clear Queue Head fields. * * Same cache rule as for the Transfer Descriptor applies for the Queue * Head. */ XUsbPs_dQHInvalidateCache(Ep->dQH); /* Add the dTD to the dQH */ XUsbPs_WritedQH(Ep->dQH, XUSBPS_dQHdTDNLP, DescPtr); Token = XUsbPs_ReaddQH(Ep->dQH, XUSBPS_dQHdTDTOKEN); Token &= ~(XUSBPS_dTDTOKEN_ACTIVE_MASK | XUSBPS_dTDTOKEN_HALT_MASK); XUsbPs_WritedQH(Ep->dQH, XUSBPS_dQHdTDTOKEN, Token); XUsbPs_dQHFlushCache(Ep->dQH); Status = XUsbPs_EpPrime(InstancePtr, EpNum, XUSBPS_EP_DIRECTION_IN); return Status;}/*****************************************************************************//** * This function receives a data buffer from the endpoint of the given endpoint * number. * * @param InstancePtr is a pointer to the XUsbPs instance of the * controller. * @param EpNum is the number of the endpoint to receive data from. * @param BufferPtr (OUT param) is a pointer to the buffer pointer to hold * the reference of the data buffer. * @param BufferLenPtr (OUT param) is a pointer to the integer that will * hold the buffer length. * @param Handle is the opaque handle to be used when the buffer is * released. * * @return * - XST_SUCCESS: The operation completed successfully. * - XST_FAILURE: An error occured. * - XST_USB_NO_BUF: No buffer available. * * @note * After handling the data in the buffer, the user MUST release * the buffer using the Handle by calling the * XUsbPs_EpBufferRelease() function. * ******************************************************************************/int XUsbPs_EpBufferReceive(XUsbPs *InstancePtr, u8 EpNum, u8 **BufferPtr, u32 *BufferLenPtr, u32 *Handle){ XUsbPs_EpOut *Ep; XUsbPs_EpSetup *EpSetup; u32 length = 0; Xil_AssertNonvoid(InstancePtr != NULL); Xil_AssertNonvoid(BufferPtr != NULL); Xil_AssertNonvoid(BufferLenPtr != NULL); Xil_AssertNonvoid(Handle != NULL); Xil_AssertNonvoid(EpNum < InstancePtr->DeviceConfig.NumEndpoints); /* Locate the next available buffer in the ring. A buffer is available * if its descriptor is not active. */ Ep = &InstancePtr->DeviceConfig.Ep[EpNum].Out; XUsbPs_dTDInvalidateCache(Ep->dTDCurr); if (XUsbPs_dTDIsActive(Ep->dTDCurr)) { return XST_USB_NO_BUF; } /* The buffer is not active which means that it has been processed by * the DMA engine and contains valid data. */ EpSetup = &InstancePtr->DeviceConfig.EpCfg[EpNum].Out; /* Use the buffer pointer stored in the "user data" field of the * Transfer Descriptor. */ *BufferPtr = (u8 *) XUsbPs_ReaddTD(Ep->dTDCurr, XUSBPS_dTDUSERDATA); length = EpSetup->BufSize - XUsbPs_dTDGetTransferLen(Ep->dTDCurr); if(length > 0) { *BufferLenPtr = length; }else { *BufferLenPtr = 0; } *Handle = (u32) Ep->dTDCurr; /* Reset the descriptor's BufferPointer0 and Transfer Length fields to * their original value. Note that we can not yet re-activate the * descriptor as the caller will be using the attached buffer. Once the * caller releases the buffer by calling XUsbPs_EpBufferRelease(), we * can re-activate the descriptor. */ XUsbPs_WritedTD(Ep->dTDCurr, XUSBPS_dTDBPTR0, *BufferPtr); XUsbPs_dTDSetTransferLen(Ep->dTDCurr, EpSetup->BufSize); XUsbPs_dTDFlushCache(Ep->dTDCurr); return XST_SUCCESS;}/*****************************************************************************//*** This function returns a previously received data buffer to the driver.** @param Handle is a pointer to the buffer that is returned.** @return None.*******************************************************************************/void XUsbPs_EpBufferRelease(u32 Handle){ XUsbPs_dTD *dTDPtr; /* Perform sanity check on Handle.*/ Xil_AssertVoid((0 != Handle) && (0 == (Handle % XUSBPS_dTD_ALIGN))); /* Activate the descriptor and clear the Terminate bit. Make sure to do * the proper cache handling. */ dTDPtr = (XUsbPs_dTD *) Handle; XUsbPs_dTDInvalidateCache(dTDPtr); XUsbPs_dTDClrTerminate(dTDPtr); XUsbPs_dTDSetActive(dTDPtr); XUsbPs_dTDSetIOC(dTDPtr); XUsbPs_dTDFlushCache(dTDPtr);}/*****************************************************************************//** * This function sets the handler for endpoint events. * * @param InstancePtr is a pointer to the XUsbPs instance of the * controller. * @param EpNum is the number of the endpoint to receive data from. * @param Direction is the direction of the endpoint (bitfield): * - XUSBPS_EP_DIRECTION_OUT * - XUSBPS_EP_DIRECTION_IN * @param CallBackFunc is the Handler callback function. * Can be NULL if the user wants to disable the handler entry. * @param CallBackRef is the user definable data pointer that will be * passed back if the handler is called. May be NULL. * * @return * - XST_SUCCESS: The operation completed successfully. * - XST_FAILURE: An error occured. * - XST_INVALID_PARAM: Invalid parameter passed. * * @note * The user can disable a handler by setting the callback function * pointer to NULL. * ******************************************************************************/int XUsbPs_EpSetHandler(XUsbPs *InstancePtr, u8 EpNum, u8 Direction, XUsbPs_EpHandlerFunc CallBackFunc, void *CallBackRef){ XUsbPs_Endpoint *Ep; Xil_AssertNonvoid(InstancePtr != NULL); Xil_AssertNonvoid(CallBackFunc != NULL); Xil_AssertNonvoid(EpNum < InstancePtr->DeviceConfig.NumEndpoints);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -