Exemplo n.º 1
0
/**
* 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);
		}
	}
}
Exemplo n.º 2
0
/**
 * This function handles RX buffer interrupts. It is called by the interrupt
 * when a receive complete interrupt occurs. It notifies the callback functions
 * that have been registered with the individual endpoints that data has been
 * received.
 *
 * @param	InstancePtr
 * 		Pointer to the XUsbPs instance of the controller.
 *
 * @param	EpCompl
 * 		Bit mask of endpoints that caused a receive complete interrupt.
 * @return
 *		none
 *
 ******************************************************************************/
static void XUsbPs_IntrHandleRX(XUsbPs *InstancePtr, u32 EpCompl)
{
	XUsbPs_EpOut	*Ep;
	int		Index;
	u32		Mask;
	int		NumEp;

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


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

		if (!(EpCompl & Mask)) {
			continue;
		}
		Ep = &InstancePtr->DeviceConfig.Ep[Index].Out;

		XUsbPs_dTDInvalidateCache(Ep->dTDCurr);

		/* Handle all finished dTDs */
		while (!XUsbPs_dTDIsActive(Ep->dTDCurr)) {
			numP += 1;
			if (Ep->HandlerFunc) {
				Ep->HandlerFunc(Ep->HandlerRef, Index,
						XUSBPS_EP_EVENT_DATA_RX, NULL);
			}

			Ep->dTDCurr = XUsbPs_dTDGetNLP(Ep->dTDCurr);
			XUsbPs_dTDInvalidateCache(Ep->dTDCurr);
		}
		/* Re-Prime the endpoint.*/
		XUsbPs_EpPrime(InstancePtr, Index, XUSBPS_EP_DIRECTION_OUT);
	}
}
Exemplo n.º 3
0
/**
* 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);

}
Exemplo n.º 4
0
/**
 *
 * 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;
}
Exemplo n.º 5
0
/**
 * 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;
}
Exemplo n.º 6
0
/**
* 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;
}
Exemplo n.º 7
0
/**
 *
 * 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;
}