/** * This function perform the reset sequence to the given usbps interface by * configuring the appropriate control bits in the usbps specifc registers. * the usbps reset sequence involves the below steps * Disbale the interrupts * Clear the status registers * Apply the reset command and wait for reset complete status * Update the relevant control registers with reset values * @param BaseAddress of the interface * * @return N/A. * * @note None. * ******************************************************************************/ void XUsbPs_ResetHw(u32 BaseAddress) { u32 RegVal; u32 Timeout = 0; /* Host and device mode */ /* Disable the interrupts */ XUsbPs_WriteReg(BaseAddress,XUSBPS_IER_OFFSET,0x0); /* Clear the interuupt status */ RegVal = XUsbPs_ReadReg(BaseAddress,XUSBPS_ISR_OFFSET); XUsbPs_WriteReg(BaseAddress,XUSBPS_ISR_OFFSET,RegVal); /* Perform the reset operation using USB CMD register */ RegVal = XUsbPs_ReadReg(BaseAddress,XUSBPS_CMD_OFFSET); RegVal = RegVal | XUSBPS_CMD_RST_MASK; XUsbPs_WriteReg(BaseAddress,XUSBPS_CMD_OFFSET,RegVal); RegVal = XUsbPs_ReadReg(BaseAddress,XUSBPS_CMD_OFFSET); /* Wait till the reset operation returns success */ /* * FIX ME: right now no indication to the caller or user about * timeout overflow */ while ((RegVal & XUSBPS_CMD_RST_MASK) && (Timeout < XUSBPS_RESET_TIMEOUT)) { RegVal = XUsbPs_ReadReg(BaseAddress,XUSBPS_CMD_OFFSET); Timeout++; } /* Update periodic list base address register with reset value */ XUsbPs_WriteReg(BaseAddress,XUSBPS_LISTBASE_OFFSET,0x0); /* Update async/endpoint list base address register with reset value */ XUsbPs_WriteReg(BaseAddress,XUSBPS_ASYNCLISTADDR_OFFSET,0x0); }
/** * * 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 performs device reset, device is stopped at the end. * * @param InstancePtr is a pointer to XUsbPs instance of the controller. * * @return None. * * @note None. * ******************************************************************************/ void XUsbPs_DeviceReset(XUsbPs *InstancePtr) { int Timeout; /* Clear all setup token semaphores by reading the * XUSBPS_EPSTAT_OFFSET register and writing its value back to * itself. */ XUsbPs_WriteReg(InstancePtr->Config.BaseAddress, XUSBPS_EPSTAT_OFFSET, XUsbPs_ReadReg(InstancePtr->Config.BaseAddress, XUSBPS_EPSTAT_OFFSET)); /* Clear all the endpoint complete status bits by reading the * XUSBPS_EPCOMPL_OFFSET register and writings its value back * to itself. */ XUsbPs_WriteReg(InstancePtr->Config.BaseAddress, XUSBPS_EPCOMPL_OFFSET, XUsbPs_ReadReg(InstancePtr->Config.BaseAddress, XUSBPS_EPCOMPL_OFFSET)); /* Cancel all endpoint prime status by waiting until all bits * in XUSBPS_EPPRIME_OFFSET are 0 and then writing 0xFFFFFFFF * to XUSBPS_EPFLUSH_OFFSET. * * Avoid hanging here by using a Timeout counter... */ Timeout = XUSBPS_TIMEOUT_COUNTER; while ((XUsbPs_ReadReg(InstancePtr->Config.BaseAddress, XUSBPS_EPPRIME_OFFSET) & XUSBPS_EP_ALL_MASK) && --Timeout) { /* NOP */ } XUsbPs_WriteReg(InstancePtr->Config.BaseAddress, XUSBPS_EPFLUSH_OFFSET, 0xFFFFFFFF); XUsbPs_Stop(InstancePtr); /* Write to CR register for controller reset */ XUsbPs_WriteReg(InstancePtr->Config.BaseAddress, XUSBPS_CMD_OFFSET, XUsbPs_ReadReg(InstancePtr->Config.BaseAddress, XUSBPS_CMD_OFFSET) | XUSBPS_CMD_RST_MASK); /* Wait for reset to finish, hardware clears the reset bit once done */ Timeout = 1000000; while((XUsbPs_ReadReg(InstancePtr->Config.BaseAddress, XUSBPS_CMD_OFFSET) & XUSBPS_CMD_RST_MASK) && --Timeout) { /* NOP */ } }
/** * 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 functions sets the controller's DEVICE address. It also sets the * advance bit so the controller will wait for the next IN-ACK before the new * address takes effect. * * @param InstancePtr is a pointer to XUsbPs instance of the controller. * @param Address is the Address of the device. * * @return * - XST_SUCCESS: Address set successfully. * - XST_FAILURE: An error occured. * - XST_INVALID_PARAM: Invalid parameter passed, e.g. address * value too big. * * @note None. * *****************************************************************************/ int XUsbPs_SetDeviceAddress(XUsbPs *InstancePtr, u8 Address) { Xil_AssertNonvoid(InstancePtr != NULL); /* Check address range validity. */ if (Address > XUSBPS_DEVICEADDR_MAX) { return XST_INVALID_PARAM; } /* Set the address register with the Address value provided. Also set * the Address Advance Bit. This will cause the address to be set only * after an IN occured and has been ACKed on the endpoint. */ XUsbPs_WriteReg(InstancePtr->Config.BaseAddress, XUSBPS_DEVICEADDR_OFFSET, (Address << XUSBPS_DEVICEADDR_ADDR_SHIFT) | XUSBPS_DEVICEADDR_DEVICEAADV_MASK); return XST_SUCCESS; }
/** * * This function resets the USB device. All the configuration registers are * reset to their default values. The function waits until the reset operation * is complete or for a certain duration within which the reset operation is * expected to be completed. * * @param InstancePtr is a pointer to XUsbPs instance of the controller. * * @return * - XST_SUCCESS Reset operation completed successfully. * - XST_FAILURE Reset operation timed out. * * @note None. * ******************************************************************************/ int XUsbPs_Reset(XUsbPs *InstancePtr) { int Timeout; Xil_AssertNonvoid(InstancePtr != NULL); /* Write a 1 to the RESET bit. The RESET bit is cleared by HW once the * RESET is complete. * * We are going to wait for the RESET bit to clear before we return * from this function. Unfortunately we do not have timers available at * this point to determine when we should report a Timeout. * * However, by using a large number for the poll loop we can assume * that the polling operation will take longer than the expected time * the HW needs to RESET. If the poll loop expires we can assume a * Timeout. The drawback is that on a slow system (and even on a fast * system) this can lead to _very_ long Timeout periods. */ XUsbPs_WriteReg(InstancePtr->Config.BaseAddress, XUSBPS_CMD_OFFSET, XUSBPS_CMD_RST_MASK); /* Wait for the RESET bit to be cleared by HW. */ Timeout = XUSBPS_TIMEOUT_COUNTER; while ((XUsbPs_ReadReg(InstancePtr->Config.BaseAddress, XUSBPS_CMD_OFFSET) & XUSBPS_CMD_RST_MASK) && --Timeout) { /* NOP */ } if (0 == Timeout) { return XST_FAILURE; } return XST_SUCCESS; }
/** * This function is the first-level interrupt handler for the USB core. All USB * interrupts will be handled here. Depending on the type of the interrupt, * second level interrupt handler may be called. Second level interrupt * handlers will be registered by the user using the: * XUsbPs_IntrSetHandler() * and/or * XUsbPs_EpSetHandler() * functions. * * * @param HandlerRef is a Reference passed to the interrupt register * function. In our case this will be a pointer to the XUsbPs * instance. * * @return None * * @note None * ******************************************************************************/ void XUsbPs_IntrHandler(void *HandlerRef) { XUsbPs *InstancePtr; u32 IrqSts; Xil_AssertVoid(HandlerRef != NULL); InstancePtr = (XUsbPs *) HandlerRef; /* Handle controller (non-endpoint) related interrupts. */ IrqSts = XUsbPs_ReadReg(InstancePtr->Config.BaseAddress, XUSBPS_ISR_OFFSET); /* Clear the interrupt status register. */ XUsbPs_WriteReg(InstancePtr->Config.BaseAddress, XUSBPS_ISR_OFFSET, IrqSts); /* Nak interrupt, used to respond to host's IN request */ if(IrqSts & XUSBPS_IXR_NAK_MASK) { /* Ack the hardware */ XUsbPs_WriteReg(InstancePtr->Config.BaseAddress, XUSBPS_EPNAKISR_OFFSET, XUsbPs_ReadReg(InstancePtr->Config.BaseAddress, XUSBPS_EPNAKISR_OFFSET)); } /*************************************************************** * * Handle general interrupts. Endpoint interrupts will be handler * later. * */ /* RESET interrupt.*/ if (IrqSts & XUSBPS_IXR_UR_MASK) { XUsbPs_IntrHandleReset(InstancePtr, IrqSts); return; } /* Check if we have a user handler that needs to be called. Note that * this is the handler for general interrupts. Endpoint interrupts will * be handled below. */ if ((IrqSts & InstancePtr->HandlerMask) && InstancePtr->HandlerFunc) { (InstancePtr->HandlerFunc)(InstancePtr->HandlerRef, IrqSts); } /*************************************************************** * * Handle Endpoint interrupts. * */ if (IrqSts & XUSBPS_IXR_UI_MASK) { u32 EpStat; u32 EpCompl; /* ENDPOINT 0 SETUP PACKET HANDLING * * Check if we got a setup packet on endpoint 0. Currently we * only check for setup packets on endpoint 0 as we would not * expect setup packets on any other endpoint (even though it * is possible to send setup packets on other endpoints). */ EpStat = XUsbPs_ReadReg(InstancePtr->Config.BaseAddress, XUSBPS_EPSTAT_OFFSET); if (EpStat & 0x0001) { /* Handle the setup packet */ XUsbPs_IntrHandleEp0Setup(InstancePtr); /* Re-Prime the endpoint. * Endpoint is de-primed if a setup packet comes in. */ XUsbPs_EpPrime(InstancePtr, 0, XUSBPS_EP_DIRECTION_OUT); } /* Check for RX and TX complete interrupts. */ EpCompl = XUsbPs_ReadReg(InstancePtr->Config.BaseAddress, XUSBPS_EPCOMPL_OFFSET); /* ACK the complete interrupts. */ XUsbPs_WriteReg(InstancePtr->Config.BaseAddress, XUSBPS_EPCOMPL_OFFSET, EpCompl); /* Check OUT (RX) endpoints. */ if (EpCompl & XUSBPS_EP_OUT_MASK) { XUsbPs_IntrHandleRX(InstancePtr, EpCompl); } /* Check IN (TX) endpoints. */ if (EpCompl & XUSBPS_EP_IN_MASK) { XUsbPs_IntrHandleTX(InstancePtr, EpCompl); } } }
/** * This function handles a RESET interrupt. It will notify the interrupt * handler callback of the RESET condition. * * @param InstancePtr is pointer to the XUsbPs instance of the controller * @param IrqSts is the Interrupt status register content. * To be passed on to the user. * * @return None * * @Note None. * ******************************************************************************/ static void XUsbPs_IntrHandleReset(XUsbPs *InstancePtr, u32 IrqSts) { int Timeout; /* Clear all setup token semaphores by reading the * XUSBPS_EPSTAT_OFFSET register and writing its value back to * itself. */ XUsbPs_WriteReg(InstancePtr->Config.BaseAddress, XUSBPS_EPSTAT_OFFSET, XUsbPs_ReadReg(InstancePtr->Config.BaseAddress, XUSBPS_EPSTAT_OFFSET)); /* Clear all the endpoint complete status bits by reading the * XUSBPS_EPCOMPL_OFFSET register and writings its value back * to itself. */ XUsbPs_WriteReg(InstancePtr->Config.BaseAddress, XUSBPS_EPCOMPL_OFFSET, XUsbPs_ReadReg(InstancePtr->Config.BaseAddress, XUSBPS_EPCOMPL_OFFSET)); /* Cancel all endpoint prime status by waiting until all bits * in XUSBPS_EPPRIME_OFFSET are 0 and then writing 0xFFFFFFFF * to XUSBPS_EPFLUSH_OFFSET. * * Avoid hanging here by using a Timeout counter... */ Timeout = XUSBPS_TIMEOUT_COUNTER; while ((XUsbPs_ReadReg(InstancePtr->Config.BaseAddress, XUSBPS_EPPRIME_OFFSET) & XUSBPS_EP_ALL_MASK) && --Timeout) { /* NOP */ } XUsbPs_WriteReg(InstancePtr->Config.BaseAddress, XUSBPS_EPFLUSH_OFFSET, 0xFFFFFFFF); /* Make sure that the reset bit in XUSBPS_PORTSCR1_OFFSET is * still set at this point. If the code gets to this point and * the reset bit has already been cleared we are in trouble and * hardware reset is necessary. */ if (!(XUsbPs_ReadReg(InstancePtr->Config.BaseAddress, XUSBPS_PORTSCR1_OFFSET) & XUSBPS_PORTSCR_PR_MASK)) { /* Send a notification to the user that a hardware * RESET is required. At this point we can only hope * that the user registered an interrupt handler and * will issue a hardware RESET. */ if (InstancePtr->HandlerFunc) { (InstancePtr->HandlerFunc)(InstancePtr->HandlerRef, IrqSts); } else { for (;;); } /* If we get here there is nothing more to do. The user * should have reset the core. */ return; } /* Check if we have a user handler that needs to be called. */ if (InstancePtr->HandlerFunc) { (InstancePtr->HandlerFunc)(InstancePtr->HandlerRef, IrqSts); } /* We are done. After RESET we don't proceed in the interrupt * handler. */ }
/** * 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_SetTripwire(InstancePtr); XUsbPs_dQHInvalidateCache(Ep->dQH); Data[0] = XUsbPs_ReaddQH(Ep->dQH, XUSBPS_dQHSUB0); Data[1] = XUsbPs_ReaddQH(Ep->dQH, XUSBPS_dQHSUB1); } while (FALSE == XUsbPs_TripwireIsSet(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_ClrTripwire(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 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; }