Ejemplo n.º 1
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);
	}
}
Ejemplo n.º 2
0
/**
* 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);
		}
	}
}
Ejemplo n.º 3
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;
}