1 /******************************************************************************
3 * (c) Copyright 2010-14 Xilinx, Inc. All rights reserved.
5 * This file contains confidential and proprietary information of Xilinx, Inc.
6 * and is protected under U.S. and international copyright and other
7 * intellectual property laws.
10 * This disclaimer is not a license and does not grant any rights to the
11 * materials distributed herewith. Except as otherwise provided in a valid
12 * license issued to you by Xilinx, and to the maximum extent permitted by
13 * applicable law: (1) THESE MATERIALS ARE MADE AVAILABLE "AS IS" AND WITH ALL
14 * FAULTS, AND XILINX HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, EXPRESS,
15 * IMPLIED, OR STATUTORY, INCLUDING BUT NOT LIMITED TO WARRANTIES OF
16 * MERCHANTABILITY, NON-INFRINGEMENT, OR FITNESS FOR ANY PARTICULAR PURPOSE;
17 * and (2) Xilinx shall not be liable (whether in contract or tort, including
18 * negligence, or under any other theory of liability) for any loss or damage
19 * of any kind or nature related to, arising under or in connection with these
20 * materials, including for any direct, or any indirect, special, incidental,
21 * or consequential loss or damage (including loss of data, profits, goodwill,
22 * or any type of loss or damage suffered as a result of any action brought by
23 * a third party) even if such damage or loss was reasonably foreseeable or
24 * Xilinx had been advised of the possibility of the same.
26 * CRITICAL APPLICATIONS
27 * Xilinx products are not designed or intended to be fail-safe, or for use in
28 * any application requiring fail-safe performance, such as life-support or
29 * safety devices or systems, Class III medical devices, nuclear facilities,
30 * applications related to the deployment of airbags, or any other applications
31 * that could lead to death, personal injury, or severe property or
32 * environmental damage (individually and collectively, "Critical
33 * Applications"). Customer assumes the sole risk and liability of any use of
34 * Xilinx products in Critical Applications, subject only to applicable laws
35 * and regulations governing limitations on product liability.
37 * THIS COPYRIGHT NOTICE AND DISCLAIMER MUST BE RETAINED AS PART OF THIS FILE
40 ******************************************************************************/
41 /******************************************************************************/
43 * @file xusbps_endpoint.c
45 * Endpoint specific function implementations.
50 * MODIFICATION HISTORY:
52 * Ver Who Date Changes
53 * ----- ---- -------- --------------------------------------------------------
54 * 1.00a jz 10/10/10 First release
55 * 1.03a nm 09/21/12 Fixed CR#678977. Added proper sequence for setup packet
57 * 1.04a nm 11/02/12 Fixed CR#683931. Mult bits are set properly in dQH.
58 * 2.00a kpc 04/03/14 Fixed CR#777763. Updated the macro names
59 * 2.1 kpc 04/28/14 Added XUsbPs_EpBufferSendWithZLT api and merged common
60 * code to XUsbPs_EpQueueRequest.
62 ******************************************************************************/
64 /***************************** Include Files **********************************/
66 #include <string.h> /* for bzero() */
70 #include "xusbps_endpoint.h"
72 /************************** Constant Definitions ******************************/
74 /**************************** Type Definitions ********************************/
76 /************************** Variable Definitions ******************************/
78 /************************** Function Prototypes ******************************/
80 static void XUsbPs_EpListInit(XUsbPs_DeviceConfig *DevCfgPtr);
81 static void XUsbPs_dQHInit(XUsbPs_DeviceConfig *DevCfgPtr);
82 static int XUsbPs_dTDInit(XUsbPs_DeviceConfig *DevCfgPtr);
83 static int XUsbPs_dTDAttachBuffer(XUsbPs_dTD *dTDPtr,
84 const u8 *BufferPtr, u32 BufferLen);
86 static void XUsbPs_dQHSetMaxPacketLenISO(XUsbPs_dQH *dQHPtr, u32 Len);
88 /* Functions to reconfigure endpoint upon host's set alternate interface
91 static void XUsbPs_dQHReinitEp(XUsbPs_DeviceConfig *DevCfgPtr,
92 int EpNum, unsigned short NewDirection);
93 static int XUsbPs_dTDReinitEp(XUsbPs_DeviceConfig *DevCfgPtr,
94 int EpNum, unsigned short NewDirection);
95 static int XUsbPs_EpQueueRequest(XUsbPs *InstancePtr, u8 EpNum,
96 const u8 *BufferPtr, u32 BufferLen, u8 ReqZero);
98 /******************************* Functions ************************************/
100 /*****************************************************************************/
103 * This function configures the DEVICE side of the controller. The caller needs
104 * to pass in the desired configuration (e.g. number of endpoints) and a
105 * DMAable buffer that will hold the Queue Head List and the Transfer
106 * Descriptors. The required size for this buffer can be obtained by the caller
107 * using the: XUsbPs_DeviceMemRequired() macro.
109 * @param InstancePtr is a pointer to the XUsbPs instance of the
111 * @param CfgPtr is a pointer to the configuration structure that contains
112 * the desired DEVICE side configuration.
115 * - XST_SUCCESS: The operation completed successfully.
116 * - XST_FAILURE: An error occured.
119 * The caller may configure the controller for both, DEVICE and
122 ******************************************************************************/
123 int XUsbPs_ConfigureDevice(XUsbPs *InstancePtr,
124 const XUsbPs_DeviceConfig *CfgPtr)
129 Xil_AssertNonvoid(InstancePtr != NULL);
130 Xil_AssertNonvoid(CfgPtr != NULL);
132 /* Copy the configuration data over into the local instance structure */
133 InstancePtr->DeviceConfig = *CfgPtr;
136 /* Align the buffer to a 2048 byte (XUSBPS_dQH_BASE_ALIGN) boundary.*/
137 InstancePtr->DeviceConfig.PhysAligned =
138 (InstancePtr->DeviceConfig.DMAMemPhys +
139 XUSBPS_dQH_BASE_ALIGN) &
140 ~(XUSBPS_dQH_BASE_ALIGN -1);
142 /* Initialize the endpoint pointer list data structure. */
143 XUsbPs_EpListInit(&InstancePtr->DeviceConfig);
146 /* Initialize the Queue Head structures in DMA memory. */
147 XUsbPs_dQHInit(&InstancePtr->DeviceConfig);
150 /* Initialize the Transfer Descriptors in DMA memory.*/
151 Status = XUsbPs_dTDInit(&InstancePtr->DeviceConfig);
152 if (XST_SUCCESS != Status) {
156 /* Changing the DEVICE mode requires a controller RESET. */
157 if (XST_SUCCESS != XUsbPs_Reset(InstancePtr)) {
161 /* Set the Queue Head List address. */
162 XUsbPs_WriteReg(InstancePtr->Config.BaseAddress,
163 XUSBPS_EPLISTADDR_OFFSET,
164 InstancePtr->DeviceConfig.PhysAligned);
166 /* Set the USB mode register to configure DEVICE mode.
168 * XUSBPS_MODE_SLOM_MASK note:
169 * Disable Setup Lockout. Setup Lockout is not required as we
170 * will be using the tripwire mechanism when handling setup
173 ModeValue = XUSBPS_MODE_CM_DEVICE_MASK | XUSBPS_MODE_SLOM_MASK;
175 XUsbPs_WriteReg(InstancePtr->Config.BaseAddress,
176 XUSBPS_MODE_OFFSET, ModeValue);
178 XUsbPs_SetBits(InstancePtr, XUSBPS_OTGCSR_OFFSET,
179 XUSBPS_OTGSC_OT_MASK);
184 /*****************************************************************************/
186 * This function sends a given data buffer.
188 * @param InstancePtr is a pointer to XUsbPs instance of the controller.
189 * @param EpNum is the number of the endpoint to receive data from.
190 * @param BufferPtr is a pointer to the buffer to send.
191 * @param BufferLen is the Buffer length.
194 * - XST_SUCCESS: The operation completed successfully.
195 * - XST_FAILURE: An error occured.
196 * - XST_USB_BUF_TOO_BIG: Provided buffer is too big (>16kB).
197 * - XST_USB_NO_DESC_AVAILABLE: No TX descriptor is available.
199 ******************************************************************************/
200 int XUsbPs_EpBufferSend(XUsbPs *InstancePtr, u8 EpNum,
201 const u8 *BufferPtr, u32 BufferLen)
203 Xil_AssertNonvoid(InstancePtr != NULL);
204 Xil_AssertNonvoid(EpNum < InstancePtr->DeviceConfig.NumEndpoints);
206 return XUsbPs_EpQueueRequest(InstancePtr, EpNum, BufferPtr,
210 /*****************************************************************************/
212 * This function sends a given data buffer and also zero length packet if the
213 * Bufferlen is in multiples of endpoint max packet size.
215 * @param InstancePtr is a pointer to XUsbPs instance of the controller.
216 * @param EpNum is the number of the endpoint to receive data from.
217 * @param BufferPtr is a pointer to the buffer to send.
218 * @param BufferLen is the Buffer length.
221 * - XST_SUCCESS: The operation completed successfully.
222 * - XST_FAILURE: An error occured.
223 * - XST_USB_BUF_TOO_BIG: Provided buffer is too big (>16kB).
224 * - XST_USB_NO_DESC_AVAILABLE: No TX descriptor is available.
226 ******************************************************************************/
227 int XUsbPs_EpBufferSendWithZLT(XUsbPs *InstancePtr, u8 EpNum,
228 const u8 *BufferPtr, u32 BufferLen)
233 Xil_AssertNonvoid(InstancePtr != NULL);
234 Xil_AssertNonvoid(EpNum < InstancePtr->DeviceConfig.NumEndpoints);
236 Ep = &InstancePtr->DeviceConfig.EpCfg[EpNum].In;
238 if ((BufferLen >= Ep->MaxPacketSize) &&
239 (BufferLen % Ep->MaxPacketSize == 0)) {
243 return XUsbPs_EpQueueRequest(InstancePtr, EpNum, BufferPtr,
247 /*****************************************************************************/
249 * This function sends a given data buffer and also sends ZLT packet if it is
252 * @param InstancePtr is a pointer to XUsbPs instance of the controller.
253 * @param EpNum is the number of the endpoint to receive data from.
254 * @param BufferPtr is a pointer to the buffer to send.
255 * @param BufferLen is the Buffer length.
256 * @param ReqZero is the
259 * - XST_SUCCESS: The operation completed successfully.
260 * - XST_FAILURE: An error occured.
261 * - XST_USB_BUF_TOO_BIG: Provided buffer is too big (>16kB).
262 * - XST_USB_NO_DESC_AVAILABLE: No TX descriptor is available.
264 ******************************************************************************/
265 static int XUsbPs_EpQueueRequest(XUsbPs *InstancePtr, u8 EpNum,
266 const u8 *BufferPtr, u32 BufferLen, u8 ReqZero)
274 u32 Mask = 0x00010000;
275 u32 BitMask = Mask << EpNum;
281 /* Locate the next available buffer in the ring. A buffer is available
282 * if its descriptor is not active.
284 Ep = &InstancePtr->DeviceConfig.Ep[EpNum].In;
286 Xil_DCacheFlushRange((unsigned int)BufferPtr, BufferLen);
288 if(Ep->dTDTail != Ep->dTDHead) {
291 XUsbPs_dTDInvalidateCache(Ep->dTDHead);
293 /* Tell the caller if we do not have any descriptors available. */
294 if (XUsbPs_dTDIsActive(Ep->dTDHead)) {
295 return XST_USB_NO_DESC_AVAILABLE;
298 /* Remember the current head. */
299 DescPtr = Ep->dTDHead;
302 Length = (BufferLen > XUSBPS_dTD_BUF_MAX_SIZE) ? XUSBPS_dTD_BUF_MAX_SIZE : BufferLen;
303 /* Attach the provided buffer to the current descriptor.*/
304 Status = XUsbPs_dTDAttachBuffer(Ep->dTDHead, BufferPtr, Length);
305 if (XST_SUCCESS != Status) {
311 XUsbPs_dTDSetActive(Ep->dTDHead);
312 if (BufferLen == 0 && (ReqZero == FALSE)) {
313 XUsbPs_dTDSetIOC(Ep->dTDHead);
316 XUsbPs_dTDClrTerminate(Ep->dTDHead);
317 XUsbPs_dTDFlushCache(Ep->dTDHead);
319 /* Advance the head descriptor pointer to the next descriptor. */
320 Ep->dTDHead = XUsbPs_dTDGetNLP(Ep->dTDHead);
321 /* Terminate the next descriptor and flush the cache.*/
322 XUsbPs_dTDInvalidateCache(Ep->dTDHead);
323 /* Tell the caller if we do not have any descriptors available. */
324 if (XUsbPs_dTDIsActive(Ep->dTDHead)) {
325 return XST_USB_NO_DESC_AVAILABLE;
328 if (ReqZero && BufferLen == 0) {
332 } while(BufferLen || exit);
334 XUsbPs_dTDSetTerminate(Ep->dTDHead);
335 XUsbPs_dTDFlushCache(Ep->dTDHead);
338 /* Read the endpoint prime register. */
339 RegValue = XUsbPs_ReadReg(InstancePtr->Config.BaseAddress, XUSBPS_EPPRIME_OFFSET);
340 if(RegValue & BitMask) {
345 RegValue = XUsbPs_ReadReg(InstancePtr->Config.BaseAddress, XUSBPS_CMD_OFFSET);
346 XUsbPs_WriteReg(InstancePtr->Config.BaseAddress, XUSBPS_CMD_OFFSET,
347 RegValue | XUSBPS_CMD_ATDTW_MASK);
348 Temp = XUsbPs_ReadReg(InstancePtr->Config.BaseAddress, XUSBPS_EPRDY_OFFSET)
350 } while(!(XUsbPs_ReadReg(InstancePtr->Config.BaseAddress, XUSBPS_CMD_OFFSET) &
351 XUSBPS_CMD_ATDTW_MASK));
353 RegValue = XUsbPs_ReadReg(InstancePtr->Config.BaseAddress, XUSBPS_CMD_OFFSET);
354 XUsbPs_WriteReg(InstancePtr->Config.BaseAddress, XUSBPS_CMD_OFFSET,
355 RegValue & ~XUSBPS_CMD_ATDTW_MASK);
362 /* Check, if the DMA engine is still running. If it is running, we do
363 * not clear Queue Head fields.
365 * Same cache rule as for the Transfer Descriptor applies for the Queue
368 XUsbPs_dQHInvalidateCache(Ep->dQH);
369 /* Add the dTD to the dQH */
370 XUsbPs_WritedQH(Ep->dQH, XUSBPS_dQHdTDNLP, DescPtr);
371 Token = XUsbPs_ReaddQH(Ep->dQH, XUSBPS_dQHdTDTOKEN);
372 Token &= ~(XUSBPS_dTDTOKEN_ACTIVE_MASK | XUSBPS_dTDTOKEN_HALT_MASK);
373 XUsbPs_WritedQH(Ep->dQH, XUSBPS_dQHdTDTOKEN, Token);
375 XUsbPs_dQHFlushCache(Ep->dQH);
377 Status = XUsbPs_EpPrime(InstancePtr, EpNum, XUSBPS_EP_DIRECTION_IN);
382 /*****************************************************************************/
384 * This function receives a data buffer from the endpoint of the given endpoint
387 * @param InstancePtr is a pointer to the XUsbPs instance of the
389 * @param EpNum is the number of the endpoint to receive data from.
390 * @param BufferPtr (OUT param) is a pointer to the buffer pointer to hold
391 * the reference of the data buffer.
392 * @param BufferLenPtr (OUT param) is a pointer to the integer that will
393 * hold the buffer length.
394 * @param Handle is the opaque handle to be used when the buffer is
398 * - XST_SUCCESS: The operation completed successfully.
399 * - XST_FAILURE: An error occured.
400 * - XST_USB_NO_BUF: No buffer available.
403 * After handling the data in the buffer, the user MUST release
404 * the buffer using the Handle by calling the
405 * XUsbPs_EpBufferRelease() function.
407 ******************************************************************************/
408 int XUsbPs_EpBufferReceive(XUsbPs *InstancePtr, u8 EpNum,
409 u8 **BufferPtr, u32 *BufferLenPtr, u32 *Handle)
412 XUsbPs_EpSetup *EpSetup;
415 Xil_AssertNonvoid(InstancePtr != NULL);
416 Xil_AssertNonvoid(BufferPtr != NULL);
417 Xil_AssertNonvoid(BufferLenPtr != NULL);
418 Xil_AssertNonvoid(Handle != NULL);
419 Xil_AssertNonvoid(EpNum < InstancePtr->DeviceConfig.NumEndpoints);
421 /* Locate the next available buffer in the ring. A buffer is available
422 * if its descriptor is not active.
424 Ep = &InstancePtr->DeviceConfig.Ep[EpNum].Out;
426 XUsbPs_dTDInvalidateCache(Ep->dTDCurr);
428 if (XUsbPs_dTDIsActive(Ep->dTDCurr)) {
429 return XST_USB_NO_BUF;
432 /* The buffer is not active which means that it has been processed by
433 * the DMA engine and contains valid data.
435 EpSetup = &InstancePtr->DeviceConfig.EpCfg[EpNum].Out;
438 /* Use the buffer pointer stored in the "user data" field of the
439 * Transfer Descriptor.
441 *BufferPtr = (u8 *) XUsbPs_ReaddTD(Ep->dTDCurr,
444 length = EpSetup->BufSize -
445 XUsbPs_dTDGetTransferLen(Ep->dTDCurr);
448 *BufferLenPtr = length;
453 *Handle = (u32) Ep->dTDCurr;
456 /* Reset the descriptor's BufferPointer0 and Transfer Length fields to
457 * their original value. Note that we can not yet re-activate the
458 * descriptor as the caller will be using the attached buffer. Once the
459 * caller releases the buffer by calling XUsbPs_EpBufferRelease(), we
460 * can re-activate the descriptor.
462 XUsbPs_WritedTD(Ep->dTDCurr, XUSBPS_dTDBPTR0, *BufferPtr);
463 XUsbPs_dTDSetTransferLen(Ep->dTDCurr, EpSetup->BufSize);
465 XUsbPs_dTDFlushCache(Ep->dTDCurr);
471 /*****************************************************************************/
473 * This function returns a previously received data buffer to the driver.
475 * @param Handle is a pointer to the buffer that is returned.
479 ******************************************************************************/
480 void XUsbPs_EpBufferRelease(u32 Handle)
484 /* Perform sanity check on Handle.*/
485 Xil_AssertVoid((0 != Handle) && (0 == (Handle % XUSBPS_dTD_ALIGN)));
487 /* Activate the descriptor and clear the Terminate bit. Make sure to do
488 * the proper cache handling.
490 dTDPtr = (XUsbPs_dTD *) Handle;
492 XUsbPs_dTDInvalidateCache(dTDPtr);
494 XUsbPs_dTDClrTerminate(dTDPtr);
495 XUsbPs_dTDSetActive(dTDPtr);
496 XUsbPs_dTDSetIOC(dTDPtr);
498 XUsbPs_dTDFlushCache(dTDPtr);
503 /*****************************************************************************/
505 * This function sets the handler for endpoint events.
507 * @param InstancePtr is a pointer to the XUsbPs instance of the
509 * @param EpNum is the number of the endpoint to receive data from.
510 * @param Direction is the direction of the endpoint (bitfield):
511 * - XUSBPS_EP_DIRECTION_OUT
512 * - XUSBPS_EP_DIRECTION_IN
513 * @param CallBackFunc is the Handler callback function.
514 * Can be NULL if the user wants to disable the handler entry.
515 * @param CallBackRef is the user definable data pointer that will be
516 * passed back if the handler is called. May be NULL.
519 * - XST_SUCCESS: The operation completed successfully.
520 * - XST_FAILURE: An error occured.
521 * - XST_INVALID_PARAM: Invalid parameter passed.
524 * The user can disable a handler by setting the callback function
527 ******************************************************************************/
528 int XUsbPs_EpSetHandler(XUsbPs *InstancePtr, u8 EpNum, u8 Direction,
529 XUsbPs_EpHandlerFunc CallBackFunc,
534 Xil_AssertNonvoid(InstancePtr != NULL);
535 Xil_AssertNonvoid(CallBackFunc != NULL);
536 Xil_AssertNonvoid(EpNum < InstancePtr->DeviceConfig.NumEndpoints);
538 Ep = &InstancePtr->DeviceConfig.Ep[EpNum];
540 if(Direction & XUSBPS_EP_DIRECTION_OUT) {
541 Ep->Out.HandlerFunc = CallBackFunc;
542 Ep->Out.HandlerRef = CallBackRef;
545 if(Direction & XUSBPS_EP_DIRECTION_IN) {
546 Ep->In.HandlerFunc = CallBackFunc;
547 Ep->In.HandlerRef = CallBackRef;
554 /*****************************************************************************/
556 * This function primes an endpoint.
558 * @param InstancePtr is pointer to the XUsbPs instance.
559 * @param EpNum is the number of the endpoint to receive data from.
560 * @param Direction is the direction of the endpoint (bitfield):
561 * - XUSBPS_EP_DIRECTION_OUT
562 * - XUSBPS_EP_DIRECTION_IN
565 * - XST_SUCCESS: The operation completed successfully.
566 * - XST_FAILURE: An error occured.
567 * - XST_INVALID_PARAM: Invalid parameter passed.
571 ******************************************************************************/
572 int XUsbPs_EpPrime(XUsbPs *InstancePtr, u8 EpNum, u8 Direction)
576 Xil_AssertNonvoid(InstancePtr != NULL);
577 Xil_AssertNonvoid(EpNum < InstancePtr->DeviceConfig.NumEndpoints);
579 /* Get the right bit mask for the endpoint direction. */
582 case XUSBPS_EP_DIRECTION_OUT:
586 case XUSBPS_EP_DIRECTION_IN:
591 return XST_INVALID_PARAM;
594 /* Write the endpoint prime register. */
595 XUsbPs_WriteReg(InstancePtr->Config.BaseAddress,
596 XUSBPS_EPPRIME_OFFSET, Mask << EpNum);
602 /*****************************************************************************/
604 * This function extracts the Setup Data from a given endpoint.
606 * @param InstancePtr is a pointer to the XUsbPs instance of the
608 * @param EpNum is the number of the endpoint to receive data from.
609 * @param SetupDataPtr is a pointer to the setup data structure to be
613 * - XST_SUCCESS: The operation completed successfully.
614 * - XST_FAILURE: An error occured.
617 ******************************************************************************/
618 int XUsbPs_EpGetSetupData(XUsbPs *InstancePtr, int EpNum,
619 XUsbPs_SetupData *SetupDataPtr)
628 Xil_AssertNonvoid(InstancePtr != NULL);
629 Xil_AssertNonvoid(SetupDataPtr != NULL);
630 Xil_AssertNonvoid(EpNum < InstancePtr->DeviceConfig.NumEndpoints);
632 Ep = &InstancePtr->DeviceConfig.Ep[EpNum].Out;
635 /* Get the data from the Queue Heads Setup buffer into local variables
636 * so we can extract the setup data values.
639 /* Arm the tripwire. The tripwire will tell us if a new setup
640 * packet arrived (in which case the tripwire bit will be
641 * cleared) while we were reading the buffer. If a new setup
642 * packet arrived the buffer is corrupted and we continue
645 XUsbPs_SetSetupTripwire(InstancePtr);
647 XUsbPs_dQHInvalidateCache(Ep->dQH);
649 Data[0] = XUsbPs_ReaddQH(Ep->dQH, XUSBPS_dQHSUB0);
650 Data[1] = XUsbPs_ReaddQH(Ep->dQH, XUSBPS_dQHSUB1);
651 } while (FALSE == XUsbPs_SetupTripwireIsSet(InstancePtr));
653 /* Clear the pending endpoint setup stat bit.
655 XUsbPs_WriteReg(InstancePtr->Config.BaseAddress,
656 XUSBPS_EPSTAT_OFFSET, 1 << EpNum);
658 /* Clear the Tripwire bit and continue.
660 XUsbPs_ClrSetupTripwire(InstancePtr);
663 /* Data in the setup buffer is being converted by the core to big
664 * endian format. We have to take care of proper byte swapping when
665 * reading the setup data values.
667 * Need to check if there is a smarter way to do this and take the
668 * processor/memory-controller endianess into account?
672 SetupDataPtr->bmRequestType = p[0];
673 SetupDataPtr->bRequest = p[1];
674 SetupDataPtr->wValue = (p[3] << 8) | p[2];
675 SetupDataPtr->wIndex = (p[5] << 8) | p[4];
676 SetupDataPtr->wLength = (p[7] << 8) | p[6];
678 /* Before we leave we need to make sure that the endpoint setup bit has
679 * cleared. It needs to be 0 before the endpoint can be re-primed.
681 * Note: According to the documentation this endpoint setup bit should
682 * clear within 1-2us after it has been written above. This means that
683 * we should never catch it being 1 here. However, we still need to
684 * poll it to make sure. Just in case, we use a counter 'Timeout' so we
685 * won't hang here if the bit is stuck for some reason.
687 Timeout = XUSBPS_TIMEOUT_COUNTER;
688 while ((XUsbPs_ReadReg(InstancePtr->Config.BaseAddress,
689 XUSBPS_EPSTAT_OFFSET) &
690 (1 << EpNum)) && --Timeout) {
701 /*****************************************************************************/
704 * This function initializes the endpoint pointer data structure.
706 * The function sets up the local data structure with the aligned addresses for
707 * the Queue Head and Transfer Descriptors.
709 * @param DevCfgPtr is pointer to the XUsbPs DEVICE configuration
715 * Endpoints of type XUSBPS_EP_TYPE_NONE are not used in the
716 * system. Therefore no memory is reserved for them.
718 ******************************************************************************/
719 static void XUsbPs_EpListInit(XUsbPs_DeviceConfig *DevCfgPtr)
725 XUsbPs_EpConfig *EpCfg;
727 /* Set up the XUsbPs_Endpoint array. This array is used to define the
728 * location of the Queue Head list and the Transfer Descriptors in the
729 * block of DMA memory that has been passed into the driver.
731 * 'p' is used to set the pointers in the local data structure.
732 * Initially 'p' is pointed to the beginning of the DMAable memory
733 * block. As pointers are assigned, 'p' is incremented by the size of
734 * the respective object.
737 EpCfg = DevCfgPtr->EpCfg;
739 /* Start off with 'p' pointing to the (aligned) beginning of the DMA
742 p = (u8 *) DevCfgPtr->PhysAligned;
745 /* Initialize the Queue Head pointer list.
747 * Each endpoint has two Queue Heads. One for the OUT direction and one
748 * for the IN direction. An OUT Queue Head is always followed by an IN
751 * Queue Head alignment is XUSBPS_dQH_ALIGN.
753 * Note that we have to reserve space here for unused endpoints.
755 for (EpNum = 0; EpNum < DevCfgPtr->NumEndpoints; ++EpNum) {
757 Ep[EpNum].Out.dQH = (XUsbPs_dQH *) p;
758 p += XUSBPS_dQH_ALIGN;
761 Ep[EpNum].In.dQH = (XUsbPs_dQH *) p;
762 p += XUSBPS_dQH_ALIGN;
766 /* 'p' now points to the first address after the Queue Head list. The
767 * Transfer Descriptors start here.
769 * Each endpoint has a variable number of Transfer Descriptors
770 * depending on user configuration.
772 * Transfer Descriptor alignment is XUSBPS_dTD_ALIGN.
774 for (EpNum = 0; EpNum < DevCfgPtr->NumEndpoints; ++EpNum) {
777 if (XUSBPS_EP_TYPE_NONE != EpCfg[EpNum].Out.Type) {
778 Ep[EpNum].Out.dTDs = (XUsbPs_dTD *) p;
779 Ep[EpNum].Out.dTDCurr = (XUsbPs_dTD *) p;
780 p += XUSBPS_dTD_ALIGN * EpCfg[EpNum].Out.NumBufs;
785 if (XUSBPS_EP_TYPE_NONE != EpCfg[EpNum].In.Type) {
786 Ep[EpNum].In.dTDs = (XUsbPs_dTD *) p;
787 Ep[EpNum].In.dTDHead = (XUsbPs_dTD *) p;
788 Ep[EpNum].In.dTDTail = (XUsbPs_dTD *) p;
789 p += XUSBPS_dTD_ALIGN * EpCfg[EpNum].In.NumBufs;
794 /* 'p' now points to the first address after the Transfer Descriptors.
795 * The data buffers for the OUT Transfer Desciptors start here.
797 * Note that IN (TX) Transfer Descriptors are not assigned buffers at
798 * this point. Buffers will be assigned when the user calls the send()
801 for (EpNum = 0; EpNum < DevCfgPtr->NumEndpoints; ++EpNum) {
803 if (XUSBPS_EP_TYPE_NONE != EpCfg[EpNum].Out.Type) {
804 /* If BufSize for this endpoint is set to 0 it means
805 * that we do not need to attach a buffer to this
806 * descriptor. We also initialize it's buffer pointer
809 if (0 == EpCfg[EpNum].Out.BufSize) {
810 Ep[EpNum].Out.dTDBufs = NULL;
814 Ep[EpNum].Out.dTDBufs = p;
815 p += EpCfg[EpNum].Out.BufSize * EpCfg[EpNum].Out.NumBufs;
820 /* Initialize the endpoint event handlers to NULL.
822 for (EpNum = 0; EpNum < DevCfgPtr->NumEndpoints; ++EpNum) {
823 Ep[EpNum].Out.HandlerFunc = NULL;
824 Ep[EpNum].In.HandlerFunc = NULL;
829 /*****************************************************************************/
832 * This function initializes the Queue Head List in memory.
834 * @param DevCfgPtr is a pointer to the XUsbPs DEVICE configuration
841 ******************************************************************************/
842 static void XUsbPs_dQHInit(XUsbPs_DeviceConfig *DevCfgPtr)
847 XUsbPs_EpConfig *EpCfg;
849 /* Setup pointers for simpler access. */
851 EpCfg = DevCfgPtr->EpCfg;
854 /* Go through the list of Queue Head entries and:
856 * - Set Transfer Descriptor addresses
857 * - Set Maximum Packet Size
858 * - Disable Zero Length Termination (ZLT) for non-isochronous transfers
859 * - Enable Interrupt On Setup (IOS)
862 for (EpNum = 0; EpNum < DevCfgPtr->NumEndpoints; ++EpNum) {
864 /* OUT Queue Heads.*/
865 if (XUSBPS_EP_TYPE_NONE != EpCfg[EpNum].Out.Type) {
866 XUsbPs_WritedQH(Ep[EpNum].Out.dQH,
867 XUSBPS_dQHCPTR, Ep[EpNum].Out.dTDs);
869 /* For isochronous, ep max packet size translates to different
870 * values in queue head than other types.
871 * Also enable ZLT for isochronous.
873 if(XUSBPS_EP_TYPE_ISOCHRONOUS == EpCfg[EpNum].Out.Type) {
874 XUsbPs_dQHSetMaxPacketLenISO(Ep[EpNum].Out.dQH,
875 EpCfg[EpNum].Out.MaxPacketSize);
876 XUsbPs_dQHEnableZLT(Ep[EpNum].Out.dQH);
878 XUsbPs_dQHSetMaxPacketLen(Ep[EpNum].Out.dQH,
879 EpCfg[EpNum].Out.MaxPacketSize);
880 XUsbPs_dQHDisableZLT(Ep[EpNum].Out.dQH);
883 /* Only control OUT needs this */
884 if(XUSBPS_EP_TYPE_CONTROL == EpCfg[EpNum].Out.Type) {
885 XUsbPs_dQHSetIOS(Ep[EpNum].Out.dQH);
888 /* Set up the overlay next dTD pointer. */
889 XUsbPs_WritedQH(Ep[EpNum].Out.dQH,
890 XUSBPS_dQHdTDNLP, Ep[EpNum].Out.dTDs);
892 XUsbPs_dQHFlushCache(Ep[EpNum].Out.dQH);
896 /* IN Queue Heads. */
897 if (XUSBPS_EP_TYPE_NONE != EpCfg[EpNum].In.Type) {
898 XUsbPs_WritedQH(Ep[EpNum].In.dQH,
899 XUSBPS_dQHCPTR, Ep[EpNum].In.dTDs);
902 /* Isochronous ep packet size can be larger than 1024.*/
903 if(XUSBPS_EP_TYPE_ISOCHRONOUS == EpCfg[EpNum].In.Type) {
904 XUsbPs_dQHSetMaxPacketLenISO(Ep[EpNum].In.dQH,
905 EpCfg[EpNum].In.MaxPacketSize);
906 XUsbPs_dQHEnableZLT(Ep[EpNum].In.dQH);
908 XUsbPs_dQHSetMaxPacketLen(Ep[EpNum].In.dQH,
909 EpCfg[EpNum].In.MaxPacketSize);
910 XUsbPs_dQHDisableZLT(Ep[EpNum].In.dQH);
913 XUsbPs_dQHFlushCache(Ep[EpNum].In.dQH);
919 /*****************************************************************************/
922 * This function initializes the Transfer Descriptors lists in memory.
924 * @param DevCfgPtr is a pointer to the XUsbPs DEVICE configuration
928 * - XST_SUCCESS: The operation completed successfully.
929 * - XST_FAILURE: An error occured.
931 ******************************************************************************/
932 static int XUsbPs_dTDInit(XUsbPs_DeviceConfig *DevCfgPtr)
937 XUsbPs_EpConfig *EpCfg;
939 /* Setup pointers for simpler access. */
941 EpCfg = DevCfgPtr->EpCfg;
944 /* Walk through the list of endpoints and initialize their Transfer
947 for (EpNum = 0; EpNum < DevCfgPtr->NumEndpoints; ++EpNum) {
951 XUsbPs_EpOut *Out = &Ep[EpNum].Out;
952 XUsbPs_EpIn *In = &Ep[EpNum].In;
958 * + Set the next link pointer
959 * + Set the interrupt complete and the active bit
960 * + Attach the buffer to the dTD
962 if (XUSBPS_EP_TYPE_NONE != EpCfg[EpNum].Out.Type) {
963 NumdTD = EpCfg[EpNum].Out.NumBufs;
969 for (Td = 0; Td < NumdTD; ++Td) {
972 int NextTd = (Td + 1) % NumdTD;
974 XUsbPs_dTDInvalidateCache(&Out->dTDs[Td]);
976 /* Set NEXT link pointer. */
977 XUsbPs_WritedTD(&Out->dTDs[Td], XUSBPS_dTDNLP,
980 /* Set the OUT descriptor ACTIVE and enable the
981 * interrupt on complete.
983 XUsbPs_dTDSetActive(&Out->dTDs[Td]);
984 XUsbPs_dTDSetIOC(&Out->dTDs[Td]);
987 /* Set up the data buffer with the descriptor. If the
988 * buffer pointer is NULL it means that we do not need
989 * to attach a buffer to this descriptor.
991 if (NULL == Out->dTDBufs) {
992 XUsbPs_dTDFlushCache(&Out->dTDs[Td]);
996 Status = XUsbPs_dTDAttachBuffer(
999 (Td * EpCfg[EpNum].Out.BufSize),
1000 EpCfg[EpNum].Out.BufSize);
1001 if (XST_SUCCESS != Status) {
1005 XUsbPs_dTDFlushCache(&Out->dTDs[Td]);
1012 * + Set the next link pointer
1013 * + Set the Terminate bit to mark it available
1015 if (XUSBPS_EP_TYPE_NONE != EpCfg[EpNum].In.Type) {
1016 NumdTD = EpCfg[EpNum].In.NumBufs;
1022 for (Td = 0; Td < NumdTD; ++Td) {
1023 int NextTd = (Td + 1) % NumdTD;
1025 XUsbPs_dTDInvalidateCache(&In->dTDs[Td]);
1027 /* Set NEXT link pointer. */
1028 XUsbPs_WritedTD(In->dTDs[Td], XUSBPS_dTDNLP,
1031 /* Set the IN descriptor's TERMINATE bits. */
1032 XUsbPs_dTDSetTerminate(In->dTDs[Td]);
1034 XUsbPs_dTDFlushCache(&In->dTDs[Td]);
1042 /*****************************************************************************/
1045 * This function associates a buffer with a Transfer Descriptor. The function
1046 * will take care of splitting the buffer into multiple 4kB aligned segments if
1047 * the buffer happens to span one or more 4kB pages.
1049 * @param dTDIndex is a pointer to the Transfer Descriptor
1050 * @param BufferPtr is pointer to the buffer to link to the descriptor.
1051 * @param BufferLen is the length of the buffer.
1054 * - XST_SUCCESS: The operation completed successfully.
1055 * - XST_FAILURE: An error occured.
1056 * - XST_USB_BUF_TOO_BIG: The provided buffer is bigger than tha
1057 * maximum allowed buffer size (16k).
1060 * Cache invalidation and flushing needs to be handler by the
1061 * caller of this function.
1063 ******************************************************************************/
1064 static int XUsbPs_dTDAttachBuffer(XUsbPs_dTD *dTDPtr,
1065 const u8 *BufferPtr, u32 BufferLen)
1071 Xil_AssertNonvoid(dTDPtr != NULL);
1073 /* Check if the buffer is smaller than 16kB. */
1074 if (BufferLen > XUSBPS_dTD_BUF_MAX_SIZE) {
1075 return XST_USB_BUF_TOO_BIG;
1078 /* Get a u32 of the buffer pointer to avoid casting in the following
1081 BufAddr = (u32) BufferPtr;
1084 /* Set the buffer pointer 0. Buffer pointer 0 can point to any location
1085 * in memory. It does not need to be 4kB aligned. However, if the
1086 * provided buffer spans one or more 4kB boundaries, we need to set up
1087 * the subsequent buffer pointers which must be 4kB aligned.
1089 XUsbPs_WritedTD(dTDPtr, XUSBPS_dTDBPTR(0), BufAddr);
1091 /* Check if the buffer spans a 4kB boundary.
1093 * Only do this check, if we are not sending a 0-length buffer.
1095 if (BufferLen > 0) {
1096 BufEnd = BufAddr + BufferLen -1;
1099 while ((BufAddr & 0xFFFFF000) != (BufEnd & 0xFFFFF000)) {
1100 /* The buffer spans at least one boundary, let's set
1101 * the next buffer pointer and repeat the procedure
1102 * until the end of the buffer and the pointer written
1103 * are in the same 4kB page.
1105 BufAddr = (BufAddr + 0x1000) & 0xFFFFF000;
1106 XUsbPs_WritedTD(dTDPtr, XUSBPS_dTDBPTR(PtrNum),
1112 /* Set the length of the buffer. */
1113 XUsbPs_dTDSetTransferLen(dTDPtr, BufferLen);
1116 /* We remember the buffer pointer in the user data field (reserved
1117 * field in the dTD). This makes it easier to reset the buffer pointer
1118 * after a buffer has been received on the endpoint. The buffer pointer
1119 * needs to be reset because the DMA engine modifies the buffer pointer
1122 XUsbPs_WritedTD(dTDPtr, XUSBPS_dTDUSERDATA, BufferPtr);
1128 /*****************************************************************************/
1130 * This function set the Max PacketLen for the queue head for isochronous EP.
1132 * If the max packet length is greater than XUSBPS_MAX_PACKET_SIZE, then
1133 * Mult bits are set to reflect that.
1135 * @param dQHPtr is a pointer to the dQH element.
1136 * @param Len is the Length to be set.
1138 ******************************************************************************/
1139 static void XUsbPs_dQHSetMaxPacketLenISO(XUsbPs_dQH *dQHPtr, u32 Len)
1141 u32 Mult = (Len & ENDPOINT_MAXP_MULT_MASK) >> ENDPOINT_MAXP_MULT_SHIFT;
1142 u32 MaxPktSize = (Mult > 1) ? ENDPOINT_MAXP_LENGTH : Len;
1144 if (MaxPktSize > XUSBPS_MAX_PACKET_SIZE) {
1152 /* Set Max packet size */
1153 XUsbPs_WritedQH(dQHPtr, XUSBPS_dQHCFG,
1154 (XUsbPs_ReaddQH(dQHPtr, XUSBPS_dQHCFG) &
1155 ~XUSBPS_dQHCFG_MPL_MASK) |
1156 (MaxPktSize << XUSBPS_dQHCFG_MPL_SHIFT));
1158 /* Set Mult to tell hardware how many transactions in each microframe */
1159 XUsbPs_WritedQH(dQHPtr, XUSBPS_dQHCFG,
1160 (XUsbPs_ReaddQH(dQHPtr, XUSBPS_dQHCFG) &
1161 ~XUSBPS_dQHCFG_MULT_MASK) |
1162 (Mult << XUSBPS_dQHCFG_MULT_SHIFT));
1166 /*****************************************************************************/
1168 * This function reconfigures one Ep corresponding to host's request of setting
1169 * alternate interface. The endpoint has been disabled before this call.
1171 * Both QH and dTDs are updated for the new configuration.
1173 * @param InstancePtr is a pointer to the XUsbPs instance of the
1176 * Pointer to the updated XUsbPs DEVICE configuration structure.
1179 * The endpoint to be reconfigured.
1181 * @param NewDirection
1182 * The new transfer direction the endpoint.
1184 * @param DirectionChanged
1185 * A boolean value indicate whether the transfer direction has changed.
1188 * XST_SUCCESS upon success, XST_FAILURE otherwise.
1190 ******************************************************************************/
1191 int XUsbPs_ReconfigureEp(XUsbPs *InstancePtr, XUsbPs_DeviceConfig *CfgPtr,
1192 int EpNum, unsigned short NewDirection,
1193 int DirectionChanged) {
1195 int Status = XST_SUCCESS;
1196 XUsbPs_Endpoint *Ep;
1197 XUsbPs_EpConfig *EpCfg;
1199 Xil_AssertNonvoid(InstancePtr != NULL);
1200 Xil_AssertNonvoid(CfgPtr != NULL);
1203 EpCfg = CfgPtr->EpCfg;
1205 /* If transfer direction changes, dTDs has to be reset
1206 * Number of buffers are preset and should not to be changed.
1208 if(DirectionChanged) {
1209 if(NewDirection == XUSBPS_EP_DIRECTION_OUT) {
1212 /* Swap the pointer to the dTDs.
1214 Ep[EpNum].Out.dTDs = Ep[EpNum].In.dTDs;
1215 p = (u8 *)(Ep[EpNum].Out.dTDs + XUSBPS_dTD_ALIGN * EpCfg[EpNum].Out.NumBufs);
1217 /* Set the OUT buffer if buffer size is not zero
1219 if(EpCfg[EpNum].Out.BufSize > 0) {
1220 Ep[EpNum].Out.dTDBufs = p;
1222 } else if(NewDirection == XUSBPS_EP_DIRECTION_IN) {
1223 Ep[EpNum].In.dTDs = Ep[EpNum].Out.dTDs;
1227 /* Reset dTD progress tracking pointers
1229 if(NewDirection == XUSBPS_EP_DIRECTION_IN) {
1230 Ep[EpNum].In.dTDHead = Ep[EpNum].In.dTDTail = Ep[EpNum].In.dTDs;
1231 } else if(NewDirection == XUSBPS_EP_DIRECTION_OUT) {
1232 Ep[EpNum].Out.dTDCurr = Ep[EpNum].Out.dTDs;
1235 /* Reinitialize information in QH
1237 XUsbPs_dQHReinitEp(CfgPtr, EpNum, NewDirection);
1239 /* Reinitialize the dTD linked list, and flush the cache
1241 Status = XUsbPs_dTDReinitEp(CfgPtr, EpNum, NewDirection);
1242 if(Status != XST_SUCCESS) {
1250 /*****************************************************************************/
1252 * This function re-initializes the Queue Head List in memory.
1253 * The endpoint 1 has been disabled before this call.
1256 * Pointer to the updated XUsbPs DEVICE configuration structure.
1259 * The endpoint to be reconfigured.
1261 * @param NewDirection
1262 * The new transfer direction of endpoint 1
1266 ******************************************************************************/
1267 static void XUsbPs_dQHReinitEp(XUsbPs_DeviceConfig *DevCfgPtr,
1268 int EpNum, unsigned short NewDirection)
1270 XUsbPs_Endpoint *Ep;
1271 XUsbPs_EpConfig *EpCfg;
1273 /* Setup pointers for simpler access.
1276 EpCfg = DevCfgPtr->EpCfg;
1279 /* Go through the list of Queue Head entries and:
1281 * - Set Transfer Descriptor addresses
1282 * - Set Maximum Packet Size
1283 * - Disable Zero Length Termination (ZLT) for non-isochronous transfers
1284 * - Enable Interrupt On Setup (IOS)
1287 if(NewDirection == XUSBPS_EP_DIRECTION_OUT) {
1290 XUsbPs_WritedQH(Ep[EpNum].Out.dQH,
1291 XUSBPS_dQHCPTR, Ep[EpNum].Out.dTDs);
1293 /* For isochronous, ep max packet size translates to different
1294 * values in queue head than other types.
1295 * Also enable ZLT for isochronous.
1297 if(XUSBPS_EP_TYPE_ISOCHRONOUS == EpCfg[EpNum].Out.Type) {
1298 XUsbPs_dQHSetMaxPacketLenISO(Ep[EpNum].Out.dQH,
1299 EpCfg[EpNum].Out.MaxPacketSize);
1300 XUsbPs_dQHEnableZLT(Ep[EpNum].Out.dQH);
1302 XUsbPs_dQHSetMaxPacketLen(Ep[EpNum].Out.dQH,
1303 EpCfg[EpNum].Out.MaxPacketSize);
1304 XUsbPs_dQHDisableZLT(Ep[EpNum].Out.dQH);
1307 XUsbPs_dQHSetIOS(Ep[EpNum].Out.dQH);
1309 /* Set up the overlay next dTD pointer.
1311 XUsbPs_WritedQH(Ep[EpNum].Out.dQH,
1312 XUSBPS_dQHdTDNLP, Ep[EpNum].Out.dTDs);
1314 XUsbPs_dQHFlushCache(Ep[EpNum].Out.dQH);
1316 } else if(NewDirection == XUSBPS_EP_DIRECTION_IN) {
1320 XUsbPs_WritedQH(Ep[EpNum].In.dQH,
1321 XUSBPS_dQHCPTR, Ep[EpNum].In.dTDs);
1323 /* Isochronous ep packet size can be larger than 1024. */
1324 if(XUSBPS_EP_TYPE_ISOCHRONOUS == EpCfg[EpNum].In.Type) {
1325 XUsbPs_dQHSetMaxPacketLenISO(Ep[EpNum].In.dQH,
1326 EpCfg[EpNum].In.MaxPacketSize);
1327 XUsbPs_dQHEnableZLT(Ep[EpNum].In.dQH);
1329 XUsbPs_dQHSetMaxPacketLen(Ep[EpNum].In.dQH,
1330 EpCfg[EpNum].In.MaxPacketSize);
1331 XUsbPs_dQHDisableZLT(Ep[EpNum].In.dQH);
1334 XUsbPs_dQHSetIOS(Ep[EpNum].In.dQH);
1336 XUsbPs_dQHFlushCache(Ep[EpNum].In.dQH);
1341 /*****************************************************************************/
1344 * This function re-initializes the Transfer Descriptors lists in memory.
1345 * The endpoint has been disabled before the call. The transfer descriptors
1346 * list pointer has been initialized too.
1349 * Pointer to the XUsbPs DEVICE configuration structure.
1352 * The endpoint to be reconfigured.
1354 * @param NewDirection
1355 * The new transfer direction of endpoint 1
1358 * - XST_SUCCESS: The operation completed successfully.
1359 * - XST_FAILURE: An error occured.
1361 ******************************************************************************/
1362 static int XUsbPs_dTDReinitEp(XUsbPs_DeviceConfig *DevCfgPtr,
1363 int EpNum, unsigned short NewDirection)
1365 XUsbPs_Endpoint *Ep;
1366 XUsbPs_EpConfig *EpCfg;
1371 /* Setup pointers for simpler access.
1374 EpCfg = DevCfgPtr->EpCfg;
1377 if(NewDirection == XUSBPS_EP_DIRECTION_OUT) {
1378 XUsbPs_EpOut *Out = &Ep[EpNum].Out;
1383 * + Set the next link pointer
1384 * + Set the interrupt complete and the active bit
1385 * + Attach the buffer to the dTD
1387 NumdTD = EpCfg[EpNum].Out.NumBufs;
1389 for (Td = 0; Td < NumdTD; ++Td) {
1392 int NextTd = (Td + 1) % NumdTD;
1394 XUsbPs_dTDInvalidateCache(&Out->dTDs[Td]);
1396 /* Set NEXT link pointer.
1398 XUsbPs_WritedTD(&Out->dTDs[Td], XUSBPS_dTDNLP,
1399 &Out->dTDs[NextTd]);
1401 /* Set the OUT descriptor ACTIVE and enable the
1402 * interrupt on complete.
1404 XUsbPs_dTDSetActive(&Out->dTDs[Td]);
1405 XUsbPs_dTDSetIOC(&Out->dTDs[Td]);
1407 /* Set up the data buffer with the descriptor. If the
1408 * buffer pointer is NULL it means that we do not need
1409 * to attach a buffer to this descriptor.
1411 if (Out->dTDBufs != NULL) {
1413 Status = XUsbPs_dTDAttachBuffer(
1416 (Td * EpCfg[EpNum].Out.BufSize),
1417 EpCfg[EpNum].Out.BufSize);
1418 if (Status != XST_SUCCESS) {
1422 XUsbPs_dTDFlushCache(&Out->dTDs[Td]);
1424 } else if(NewDirection == XUSBPS_EP_DIRECTION_IN) {
1425 XUsbPs_EpIn *In = &Ep[EpNum].In;
1430 * + Set the next link pointer
1431 * + Set the Terminate bit to mark it available
1433 NumdTD = EpCfg[EpNum].In.NumBufs;
1435 for (Td = 0; Td < NumdTD; ++Td) {
1436 int NextTd = (Td + 1) % NumdTD;
1438 XUsbPs_dTDInvalidateCache(&In->dTDs[Td]);
1440 /* Set NEXT link pointer.
1442 XUsbPs_WritedTD(&In->dTDs[Td], XUSBPS_dTDNLP,
1445 /* Set the IN descriptor's TERMINATE bits.
1447 XUsbPs_dTDSetTerminate(&In->dTDs[Td]);
1449 XUsbPs_dTDFlushCache(&In->dTDs[Td]);