summaryrefslogtreecommitdiff
path: root/FreeRTOS/Demo/CORTEX_A9_Zynq_ZC702/RTOSDemo_bsp/ps7_cortexa9_0/libsrc/usbps_v2_1/src/xusbps_endpoint.c
diff options
context:
space:
mode:
Diffstat (limited to 'FreeRTOS/Demo/CORTEX_A9_Zynq_ZC702/RTOSDemo_bsp/ps7_cortexa9_0/libsrc/usbps_v2_1/src/xusbps_endpoint.c')
-rw-r--r--FreeRTOS/Demo/CORTEX_A9_Zynq_ZC702/RTOSDemo_bsp/ps7_cortexa9_0/libsrc/usbps_v2_1/src/xusbps_endpoint.c1455
1 files changed, 1455 insertions, 0 deletions
diff --git a/FreeRTOS/Demo/CORTEX_A9_Zynq_ZC702/RTOSDemo_bsp/ps7_cortexa9_0/libsrc/usbps_v2_1/src/xusbps_endpoint.c b/FreeRTOS/Demo/CORTEX_A9_Zynq_ZC702/RTOSDemo_bsp/ps7_cortexa9_0/libsrc/usbps_v2_1/src/xusbps_endpoint.c
new file mode 100644
index 000000000..fb3917b54
--- /dev/null
+++ b/FreeRTOS/Demo/CORTEX_A9_Zynq_ZC702/RTOSDemo_bsp/ps7_cortexa9_0/libsrc/usbps_v2_1/src/xusbps_endpoint.c
@@ -0,0 +1,1455 @@
+/******************************************************************************
+*
+* (c) Copyright 2010-14 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
+ * 1.03a nm 09/21/12 Fixed CR#678977. Added proper sequence for setup packet
+ * handling.
+ * 1.04a nm 11/02/12 Fixed CR#683931. Mult bits are set properly in dQH.
+ * 2.00a kpc 04/03/14 Fixed CR#777763. Updated the macro names
+ * 2.1 kpc 04/28/14 Added XUsbPs_EpBufferSendWithZLT api and merged common
+ * code to XUsbPs_EpQueueRequest.
+ * </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);
+static int XUsbPs_EpQueueRequest(XUsbPs *InstancePtr, u8 EpNum,
+ const u8 *BufferPtr, u32 BufferLen, u8 ReqZero);
+
+/******************************* 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);
+
+ /* 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)
+{
+ Xil_AssertNonvoid(InstancePtr != NULL);
+ Xil_AssertNonvoid(EpNum < InstancePtr->DeviceConfig.NumEndpoints);
+
+ return XUsbPs_EpQueueRequest(InstancePtr, EpNum, BufferPtr,
+ BufferLen, FALSE);
+}
+
+/*****************************************************************************/
+/**
+* This function sends a given data buffer and also zero length packet if the
+* Bufferlen is in multiples of endpoint max packet size.
+*
+* @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_EpBufferSendWithZLT(XUsbPs *InstancePtr, u8 EpNum,
+ const u8 *BufferPtr, u32 BufferLen)
+{
+ u8 ReqZero = FALSE;
+ XUsbPs_EpSetup *Ep;
+
+ Xil_AssertNonvoid(InstancePtr != NULL);
+ Xil_AssertNonvoid(EpNum < InstancePtr->DeviceConfig.NumEndpoints);
+
+ Ep = &InstancePtr->DeviceConfig.EpCfg[EpNum].In;
+
+ if ((BufferLen >= Ep->MaxPacketSize) &&
+ (BufferLen % Ep->MaxPacketSize == 0)) {
+ ReqZero = TRUE;
+ }
+
+ return XUsbPs_EpQueueRequest(InstancePtr, EpNum, BufferPtr,
+ BufferLen, ReqZero);
+}
+
+/*****************************************************************************/
+/**
+* This function sends a given data buffer and also sends ZLT packet if it is
+* requested.
+*
+* @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.
+* @param ReqZero is the
+*
+* @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.
+*
+******************************************************************************/
+static int XUsbPs_EpQueueRequest(XUsbPs *InstancePtr, u8 EpNum,
+ const u8 *BufferPtr, u32 BufferLen, u8 ReqZero)
+{
+ 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;
+ u32 exit = 1;
+
+
+ /* 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 && (ReqZero == FALSE)) {
+ XUsbPs_dTDSetIOC(Ep->dTDHead);
+ exit = 0;
+ }
+ 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;
+ }
+
+ if (ReqZero && BufferLen == 0) {
+ ReqZero = FALSE;
+ }
+
+ } while(BufferLen || exit);
+
+ 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);
+
+ Ep = &InstancePtr->DeviceConfig.Ep[EpNum];
+
+ if(Direction & XUSBPS_EP_DIRECTION_OUT) {
+ Ep->Out.HandlerFunc = CallBackFunc;
+ Ep->Out.HandlerRef = CallBackRef;
+ }
+
+ if(Direction & XUSBPS_EP_DIRECTION_IN) {
+ Ep->In.HandlerFunc = CallBackFunc;
+ Ep->In.HandlerRef = CallBackRef;
+ }
+
+ return XST_SUCCESS;
+}
+
+
+/*****************************************************************************/
+/**
+* This function primes an endpoint.
+*
+* @param InstancePtr is pointer to the XUsbPs instance.
+* @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
+*
+* @return
+* - XST_SUCCESS: The operation completed successfully.
+* - XST_FAILURE: An error occured.
+* - XST_INVALID_PARAM: Invalid parameter passed.
+*
+* @note None.
+*
+******************************************************************************/
+int XUsbPs_EpPrime(XUsbPs *InstancePtr, u8 EpNum, u8 Direction)
+{
+ u32 Mask;
+
+ Xil_AssertNonvoid(InstancePtr != NULL);
+ Xil_AssertNonvoid(EpNum < InstancePtr->DeviceConfig.NumEndpoints);
+
+ /* Get the right bit mask for the endpoint direction. */
+ switch (Direction) {
+
+ case XUSBPS_EP_DIRECTION_OUT:
+ Mask = 0x00000001;
+ break;
+
+ case XUSBPS_EP_DIRECTION_IN:
+ Mask = 0x00010000;
+ break;
+
+ default:
+ return XST_INVALID_PARAM;
+ }
+
+ /* Write the endpoint prime register. */
+ XUsbPs_WriteReg(InstancePtr->Config.BaseAddress,
+ XUSBPS_EPPRIME_OFFSET, Mask << EpNum);
+
+ return XST_SUCCESS;
+}
+
+
+/*****************************************************************************/
+/**
+* This function extracts the Setup Data from a given endpoint.
+*
+* @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 SetupDataPtr is a pointer to the setup data structure to be
+* filled.
+*
+* @return
+* - XST_SUCCESS: The operation completed successfully.
+* - XST_FAILURE: An error occured.
+*
+* @note None.
+******************************************************************************/
+int XUsbPs_EpGetSetupData(XUsbPs *InstancePtr, int EpNum,
+ XUsbPs_SetupData *SetupDataPtr)
+{
+ XUsbPs_EpOut *Ep;
+
+ u32 Data[2];
+ u8 *p;
+
+ int Timeout;
+
+ Xil_AssertNonvoid(InstancePtr != NULL);
+ Xil_AssertNonvoid(SetupDataPtr != NULL);
+ Xil_AssertNonvoid(EpNum < InstancePtr->DeviceConfig.NumEndpoints);
+
+ Ep = &InstancePtr->DeviceConfig.Ep[EpNum].Out;
+
+
+ /* Get the data from the Queue Heads Setup buffer into local variables
+ * so we can extract the setup data values.
+ */
+ do {
+ /* Arm the tripwire. The tripwire will tell us if a new setup
+ * packet arrived (in which case the tripwire bit will be
+ * cleared) while we were reading the buffer. If a new setup
+ * packet arrived the buffer is corrupted and we continue
+ * reading.
+ */
+ XUsbPs_SetSetupTripwire(InstancePtr);
+
+ XUsbPs_dQHInvalidateCache(Ep->dQH);
+
+ Data[0] = XUsbPs_ReaddQH(Ep->dQH, XUSBPS_dQHSUB0);
+ Data[1] = XUsbPs_ReaddQH(Ep->dQH, XUSBPS_dQHSUB1);
+ } while (FALSE == XUsbPs_SetupTripwireIsSet(InstancePtr));
+
+ /* Clear the pending endpoint setup stat bit.
+ */
+ XUsbPs_WriteReg(InstancePtr->Config.BaseAddress,
+ XUSBPS_EPSTAT_OFFSET, 1 << EpNum);
+
+ /* Clear the Tripwire bit and continue.
+ */
+ XUsbPs_ClrSetupTripwire(InstancePtr);
+
+
+ /* Data in the setup buffer is being converted by the core to big
+ * endian format. We have to take care of proper byte swapping when
+ * reading the setup data values.
+ *
+ * Need to check if there is a smarter way to do this and take the
+ * processor/memory-controller endianess into account?
+ */
+ p = (u8 *) Data;
+
+ SetupDataPtr->bmRequestType = p[0];
+ SetupDataPtr->bRequest = p[1];
+ SetupDataPtr->wValue = (p[3] << 8) | p[2];
+ SetupDataPtr->wIndex = (p[5] << 8) | p[4];
+ SetupDataPtr->wLength = (p[7] << 8) | p[6];
+
+ /* Before we leave we need to make sure that the endpoint setup bit has
+ * cleared. It needs to be 0 before the endpoint can be re-primed.
+ *
+ * Note: According to the documentation this endpoint setup bit should
+ * clear within 1-2us after it has been written above. This means that
+ * we should never catch it being 1 here. However, we still need to
+ * poll it to make sure. Just in case, we use a counter 'Timeout' so we
+ * won't hang here if the bit is stuck for some reason.
+ */
+ Timeout = XUSBPS_TIMEOUT_COUNTER;
+ while ((XUsbPs_ReadReg(InstancePtr->Config.BaseAddress,
+ XUSBPS_EPSTAT_OFFSET) &
+ (1 << EpNum)) && --Timeout) {
+ /* NOP */
+ }
+ if (0 == Timeout) {
+ return XST_FAILURE;
+ }
+
+ return XST_SUCCESS;
+}
+
+
+/*****************************************************************************/
+/**
+*
+* This function initializes the endpoint pointer data structure.
+*
+* The function sets up the local data structure with the aligned addresses for
+* the Queue Head and Transfer Descriptors.
+*
+* @param DevCfgPtr is pointer to the XUsbPs DEVICE configuration
+* structure.
+*
+* @return none
+*
+* @note
+* Endpoints of type XUSBPS_EP_TYPE_NONE are not used in the
+* system. Therefore no memory is reserved for them.
+*
+******************************************************************************/
+static void XUsbPs_EpListInit(XUsbPs_DeviceConfig *DevCfgPtr)
+{
+ int EpNum;
+ u8 *p;
+
+ XUsbPs_Endpoint *Ep;
+ XUsbPs_EpConfig *EpCfg;
+
+ /* Set up the XUsbPs_Endpoint array. This array is used to define the
+ * location of the Queue Head list and the Transfer Descriptors in the
+ * block of DMA memory that has been passed into the driver.
+ *
+ * 'p' is used to set the pointers in the local data structure.
+ * Initially 'p' is pointed to the beginning of the DMAable memory
+ * block. As pointers are assigned, 'p' is incremented by the size of
+ * the respective object.
+ */
+ Ep = DevCfgPtr->Ep;
+ EpCfg = DevCfgPtr->EpCfg;
+
+ /* Start off with 'p' pointing to the (aligned) beginning of the DMA
+ * buffer.
+ */
+ p = (u8 *) DevCfgPtr->PhysAligned;
+
+
+ /* Initialize the Queue Head pointer list.
+ *
+ * Each endpoint has two Queue Heads. One for the OUT direction and one
+ * for the IN direction. An OUT Queue Head is always followed by an IN
+ * Queue Head.
+ *
+ * Queue Head alignment is XUSBPS_dQH_ALIGN.
+ *
+ * Note that we have to reserve space here for unused endpoints.
+ */
+ for (EpNum = 0; EpNum < DevCfgPtr->NumEndpoints; ++EpNum) {
+ /* OUT Queue Head */
+ Ep[EpNum].Out.dQH = (XUsbPs_dQH *) p;
+ p += XUSBPS_dQH_ALIGN;
+
+ /* IN Queue Head */
+ Ep[EpNum].In.dQH = (XUsbPs_dQH *) p;
+ p += XUSBPS_dQH_ALIGN;
+ }
+
+
+ /* 'p' now points to the first address after the Queue Head list. The
+ * Transfer Descriptors start here.
+ *
+ * Each endpoint has a variable number of Transfer Descriptors
+ * depending on user configuration.
+ *
+ * Transfer Descriptor alignment is XUSBPS_dTD_ALIGN.
+ */
+ for (EpNum = 0; EpNum < DevCfgPtr->NumEndpoints; ++EpNum) {
+ /* OUT Descriptors.
+ */
+ if (XUSBPS_EP_TYPE_NONE != EpCfg[EpNum].Out.Type) {
+ Ep[EpNum].Out.dTDs = (XUsbPs_dTD *) p;
+ Ep[EpNum].Out.dTDCurr = (XUsbPs_dTD *) p;
+ p += XUSBPS_dTD_ALIGN * EpCfg[EpNum].Out.NumBufs;
+ }
+
+ /* IN Descriptors.
+ */
+ if (XUSBPS_EP_TYPE_NONE != EpCfg[EpNum].In.Type) {
+ Ep[EpNum].In.dTDs = (XUsbPs_dTD *) p;
+ Ep[EpNum].In.dTDHead = (XUsbPs_dTD *) p;
+ Ep[EpNum].In.dTDTail = (XUsbPs_dTD *) p;
+ p += XUSBPS_dTD_ALIGN * EpCfg[EpNum].In.NumBufs;
+ }
+ }
+
+
+ /* 'p' now points to the first address after the Transfer Descriptors.
+ * The data buffers for the OUT Transfer Desciptors start here.
+ *
+ * Note that IN (TX) Transfer Descriptors are not assigned buffers at
+ * this point. Buffers will be assigned when the user calls the send()
+ * function.
+ */
+ for (EpNum = 0; EpNum < DevCfgPtr->NumEndpoints; ++EpNum) {
+
+ if (XUSBPS_EP_TYPE_NONE != EpCfg[EpNum].Out.Type) {
+ /* If BufSize for this endpoint is set to 0 it means
+ * that we do not need to attach a buffer to this
+ * descriptor. We also initialize it's buffer pointer
+ * to NULL.
+ */
+ if (0 == EpCfg[EpNum].Out.BufSize) {
+ Ep[EpNum].Out.dTDBufs = NULL;
+ continue;
+ }
+
+ Ep[EpNum].Out.dTDBufs = p;
+ p += EpCfg[EpNum].Out.BufSize * EpCfg[EpNum].Out.NumBufs;
+ }
+ }
+
+
+ /* Initialize the endpoint event handlers to NULL.
+ */
+ for (EpNum = 0; EpNum < DevCfgPtr->NumEndpoints; ++EpNum) {
+ Ep[EpNum].Out.HandlerFunc = NULL;
+ Ep[EpNum].In.HandlerFunc = NULL;
+ }
+}
+
+
+/*****************************************************************************/
+/**
+*
+* This function initializes the Queue Head List in memory.
+*
+* @param DevCfgPtr is a pointer to the XUsbPs DEVICE configuration
+* structure.
+*
+* @return None
+*
+* @note None.
+*
+******************************************************************************/
+static void XUsbPs_dQHInit(XUsbPs_DeviceConfig *DevCfgPtr)
+{
+ int EpNum;
+
+ 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)
+ *
+ */
+ for (EpNum = 0; EpNum < DevCfgPtr->NumEndpoints; ++EpNum) {
+
+ /* OUT Queue Heads.*/
+ if (XUSBPS_EP_TYPE_NONE != EpCfg[EpNum].Out.Type) {
+ 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);
+ }
+
+ /* Only control OUT needs this */
+ if(XUSBPS_EP_TYPE_CONTROL == EpCfg[EpNum].Out.Type) {
+ 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);
+ }
+
+
+ /* IN Queue Heads. */
+ if (XUSBPS_EP_TYPE_NONE != EpCfg[EpNum].In.Type) {
+ 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_dQHFlushCache(Ep[EpNum].In.dQH);
+ }
+ }
+}
+
+
+/*****************************************************************************/
+/**
+ *
+ * This function initializes the Transfer Descriptors lists in memory.
+ *
+ * @param DevCfgPtr is a pointer to the XUsbPs DEVICE configuration
+ * structure.
+ *
+ * @return
+ * - XST_SUCCESS: The operation completed successfully.
+ * - XST_FAILURE: An error occured.
+ *
+ ******************************************************************************/
+static int XUsbPs_dTDInit(XUsbPs_DeviceConfig *DevCfgPtr)
+{
+ int EpNum;
+
+ XUsbPs_Endpoint *Ep;
+ XUsbPs_EpConfig *EpCfg;
+
+ /* Setup pointers for simpler access. */
+ Ep = DevCfgPtr->Ep;
+ EpCfg = DevCfgPtr->EpCfg;
+
+
+ /* Walk through the list of endpoints and initialize their Transfer
+ * Descriptors.
+ */
+ for (EpNum = 0; EpNum < DevCfgPtr->NumEndpoints; ++EpNum) {
+ int Td;
+ int NumdTD;
+
+ XUsbPs_EpOut *Out = &Ep[EpNum].Out;
+ XUsbPs_EpIn *In = &Ep[EpNum].In;
+
+
+ /* OUT Descriptors
+ * ===============
+ *
+ * + Set the next link pointer
+ * + Set the interrupt complete and the active bit
+ * + Attach the buffer to the dTD
+ */
+ if (XUSBPS_EP_TYPE_NONE != EpCfg[EpNum].Out.Type) {
+ NumdTD = EpCfg[EpNum].Out.NumBufs;
+ }
+ else {
+ NumdTD = 0;
+ }
+
+ 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 (NULL == Out->dTDBufs) {
+ XUsbPs_dTDFlushCache(&Out->dTDs[Td]);
+ continue;
+ }
+
+ Status = XUsbPs_dTDAttachBuffer(
+ &Out->dTDs[Td],
+ Out->dTDBufs +
+ (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)
+{
+ u32 Mult = (Len & ENDPOINT_MAXP_MULT_MASK) >> ENDPOINT_MAXP_MULT_SHIFT;
+ u32 MaxPktSize = (Mult > 1) ? ENDPOINT_MAXP_LENGTH : Len;
+
+ if (MaxPktSize > XUSBPS_MAX_PACKET_SIZE) {
+ return;
+ }
+
+ if (Mult > 3) {
+ return;
+ }
+
+ /* Set Max packet size */
+ XUsbPs_WritedQH(dQHPtr, XUSBPS_dQHCFG,
+ (XUsbPs_ReaddQH(dQHPtr, XUSBPS_dQHCFG) &
+ ~XUSBPS_dQHCFG_MPL_MASK) |
+ (MaxPktSize << 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;
+}
+