/**
* This function handles TX buffer interrupts. It is called by the interrupt
* when a transmit complete interrupt occurs. It returns buffers of completed
* descriptors to the caller.
*
* @param	InstancePtr is a pointer to the XUsbPs instance of the
*		controller.
* @param	EpCompl is the Bit mask of endpoints that caused a transmit
*		complete interrupt.
*
* @return	None
*
* @note		None.
*
******************************************************************************/
static void XUsbPs_IntrHandleTX(XUsbPs *InstancePtr, u32 EpCompl)
{
	int Index;
	u32 Mask;
	int NumEp;

	/* Check all endpoints for TX complete bits.
	 */
	Mask	= 0x00010000;
	NumEp	= InstancePtr->DeviceConfig.NumEndpoints;

	/* Check for every endpoint if its TX complete bit is
	 * set.
	 */
	for (Index = 0; Index < NumEp; Index++, Mask <<= 1) {
		XUsbPs_EpIn	*Ep;

		if (!(EpCompl & Mask)) {
			continue;
		}
		/* The TX complete bit for this endpoint is
		 * set. Walk the list of descriptors to see
		 * which ones are completed.
		 */
		Ep = &InstancePtr->DeviceConfig.Ep[Index].In;
		while (Ep->dTDTail != Ep->dTDHead) {

			XUsbPs_dTDInvalidateCache(Ep->dTDTail);

			/* If the descriptor is not active then the buffer has
			 * not been sent yet.
			 */
			if (XUsbPs_dTDIsActive(Ep->dTDTail)) {
				break;
			}

			if (Ep->HandlerFunc) {
				void *BufPtr;

				BufPtr = (void *) XUsbPs_ReaddTD(Ep->dTDTail,
							XUSBPS_dTDUSERDATA);

				Ep->HandlerFunc(Ep->HandlerRef, Index,
						XUSBPS_EP_EVENT_DATA_TX,
								BufPtr);
			}

			Ep->dTDTail = XUsbPs_dTDGetNLP(Ep->dTDTail);
		}
	}
}
/**
 * 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;
}