1 /******************************************************************************
3 * Copyright (C) 2010 - 2014 Xilinx, Inc. All rights reserved.
5 * Permission is hereby granted, free of charge, to any person obtaining a copy
6 * of this software and associated documentation files (the "Software"), to deal
7 * in the Software without restriction, including without limitation the rights
8 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 * copies of the Software, and to permit persons to whom the Software is
10 * furnished to do so, subject to the following conditions:
12 * The above copyright notice and this permission notice shall be included in
13 * all copies or substantial portions of the Software.
15 * Use of the Software is limited solely to applications:
16 * (a) running on a Xilinx device, or
17 * (b) that interact with a Xilinx device through a bus or interconnect.
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
22 * XILINX BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
23 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
24 * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
27 * Except as contained in this notice, the name of the Xilinx shall not be used
28 * in advertising or otherwise to promote the sale, use or other dealings in
29 * this Software without prior written authorization from Xilinx.
31 ******************************************************************************/
32 /******************************************************************************/
35 * @addtogroup usbps_v2_1
38 * This file contains the functions that are related to interrupt processing
39 * for the EPB USB driver.
42 * MODIFICATION HISTORY:
44 * Ver Who Date Changes
45 * ----- ---- -------- ----------------------------------------------------------
46 * 1.00a jz 10/10/10 First release
47 * 1.03a nm 09/21/12 Fixed CR#678977. Added proper sequence for setup packet
50 ******************************************************************************/
52 /***************************** Include Files **********************************/
55 #include "xusbps_endpoint.h"
57 /************************** Constant Definitions ******************************/
59 /**************************** Type Definitions ********************************/
61 /***************** Macros (Inline Functions) Definitions **********************/
63 /************************** Variable Definitions ******************************/
65 /************************** Function Prototypes *******************************/
67 static void XUsbPs_IntrHandleTX(XUsbPs *InstancePtr, u32 EpCompl);
68 static void XUsbPs_IntrHandleRX(XUsbPs *InstancePtr, u32 EpCompl);
69 static void XUsbPs_IntrHandleReset(XUsbPs *InstancePtr, u32 IrqSts);
70 static void XUsbPs_IntrHandleEp0Setup(XUsbPs *InstancePtr);
72 /*****************************************************************************/
74 * This function is the first-level interrupt handler for the USB core. All USB
75 * interrupts will be handled here. Depending on the type of the interrupt,
76 * second level interrupt handler may be called. Second level interrupt
77 * handlers will be registered by the user using the:
78 * XUsbPs_IntrSetHandler()
80 * XUsbPs_EpSetHandler()
84 * @param HandlerRef is a Reference passed to the interrupt register
85 * function. In our case this will be a pointer to the XUsbPs
92 ******************************************************************************/
93 void XUsbPs_IntrHandler(void *HandlerRef)
99 Xil_AssertVoid(HandlerRef != NULL);
101 InstancePtr = (XUsbPs *) HandlerRef;
103 /* Handle controller (non-endpoint) related interrupts. */
104 IrqSts = XUsbPs_ReadReg(InstancePtr->Config.BaseAddress,
107 /* Clear the interrupt status register. */
108 XUsbPs_WriteReg(InstancePtr->Config.BaseAddress,
109 XUSBPS_ISR_OFFSET, IrqSts);
111 /* Nak interrupt, used to respond to host's IN request */
112 if(IrqSts & XUSBPS_IXR_NAK_MASK) {
113 /* Ack the hardware */
114 XUsbPs_WriteReg(InstancePtr->Config.BaseAddress,
115 XUSBPS_EPNAKISR_OFFSET,
116 XUsbPs_ReadReg(InstancePtr->Config.BaseAddress,
117 XUSBPS_EPNAKISR_OFFSET));
121 /***************************************************************
123 * Handle general interrupts. Endpoint interrupts will be handler
128 /* RESET interrupt.*/
129 if (IrqSts & XUSBPS_IXR_UR_MASK) {
130 XUsbPs_IntrHandleReset(InstancePtr, IrqSts);
134 /* Check if we have a user handler that needs to be called. Note that
135 * this is the handler for general interrupts. Endpoint interrupts will
138 if ((IrqSts & InstancePtr->HandlerMask) && InstancePtr->HandlerFunc) {
139 (InstancePtr->HandlerFunc)(InstancePtr->HandlerRef, IrqSts);
143 /***************************************************************
145 * Handle Endpoint interrupts.
148 if (IrqSts & XUSBPS_IXR_UI_MASK) {
152 /* ENDPOINT 0 SETUP PACKET HANDLING
154 * Check if we got a setup packet on endpoint 0. Currently we
155 * only check for setup packets on endpoint 0 as we would not
156 * expect setup packets on any other endpoint (even though it
157 * is possible to send setup packets on other endpoints).
159 EpStat = XUsbPs_ReadReg(InstancePtr->Config.BaseAddress,
160 XUSBPS_EPSTAT_OFFSET);
161 if (EpStat & 0x0001) {
162 /* Handle the setup packet */
163 XUsbPs_IntrHandleEp0Setup(InstancePtr);
165 /* Re-Prime the endpoint.
166 * Endpoint is de-primed if a setup packet comes in.
168 XUsbPs_EpPrime(InstancePtr, 0, XUSBPS_EP_DIRECTION_OUT);
171 /* Check for RX and TX complete interrupts. */
172 EpCompl = XUsbPs_ReadReg(InstancePtr->Config.BaseAddress,
173 XUSBPS_EPCOMPL_OFFSET);
176 /* ACK the complete interrupts. */
177 XUsbPs_WriteReg(InstancePtr->Config.BaseAddress,
178 XUSBPS_EPCOMPL_OFFSET, EpCompl);
180 /* Check OUT (RX) endpoints. */
181 if (EpCompl & XUSBPS_EP_OUT_MASK) {
182 XUsbPs_IntrHandleRX(InstancePtr, EpCompl);
185 /* Check IN (TX) endpoints. */
186 if (EpCompl & XUSBPS_EP_IN_MASK) {
187 XUsbPs_IntrHandleTX(InstancePtr, EpCompl);
193 /*****************************************************************************/
195 * This function registers the user callback handler for controller
196 * (non-endpoint) interrupts.
198 * @param InstancePtr is a pointer to the XUsbPs instance of the
200 * @param CallBackFunc is the Callback function to register.
201 * CallBackFunc may be NULL to clear the entry.
202 * @param CallBackRef is the user data reference passed to the
203 * callback function. CallBackRef may be NULL.
204 * @param Mask is the User interrupt mask. Defines which interrupts
205 * will cause the callback to be called.
208 * - XST_SUCCESS: Callback registered successfully.
209 * - XST_FAILURE: Callback could not be registered.
213 ******************************************************************************/
214 int XUsbPs_IntrSetHandler(XUsbPs *InstancePtr,
215 XUsbPs_IntrHandlerFunc CallBackFunc,
216 void *CallBackRef, u32 Mask)
218 Xil_AssertNonvoid(InstancePtr != NULL);
220 InstancePtr->HandlerFunc = CallBackFunc;
221 InstancePtr->HandlerRef = CallBackRef;
222 InstancePtr->HandlerMask = Mask;
228 /*****************************************************************************/
230 * This function handles TX buffer interrupts. It is called by the interrupt
231 * when a transmit complete interrupt occurs. It returns buffers of completed
232 * descriptors to the caller.
234 * @param InstancePtr is a pointer to the XUsbPs instance of the
236 * @param EpCompl is the Bit mask of endpoints that caused a transmit
237 * complete interrupt.
243 ******************************************************************************/
244 static void XUsbPs_IntrHandleTX(XUsbPs *InstancePtr, u32 EpCompl)
250 /* Check all endpoints for TX complete bits.
253 NumEp = InstancePtr->DeviceConfig.NumEndpoints;
255 /* Check for every endpoint if its TX complete bit is
258 for (Index = 0; Index < NumEp; Index++, Mask <<= 1) {
261 if (!(EpCompl & Mask)) {
264 /* The TX complete bit for this endpoint is
265 * set. Walk the list of descriptors to see
266 * which ones are completed.
268 Ep = &InstancePtr->DeviceConfig.Ep[Index].In;
269 while (Ep->dTDTail != Ep->dTDHead) {
271 XUsbPs_dTDInvalidateCache(Ep->dTDTail);
273 /* If the descriptor is not active then the buffer has
276 if (XUsbPs_dTDIsActive(Ep->dTDTail)) {
280 if (Ep->HandlerFunc) {
283 BufPtr = (void *) XUsbPs_ReaddTD(Ep->dTDTail,
286 Ep->HandlerFunc(Ep->HandlerRef, Index,
287 XUSBPS_EP_EVENT_DATA_TX,
291 Ep->dTDTail = XUsbPs_dTDGetNLP(Ep->dTDTail);
297 /*****************************************************************************/
299 * This function handles RX buffer interrupts. It is called by the interrupt
300 * when a receive complete interrupt occurs. It notifies the callback functions
301 * that have been registered with the individual endpoints that data has been
305 * Pointer to the XUsbPs instance of the controller.
308 * Bit mask of endpoints that caused a receive complete interrupt.
312 ******************************************************************************/
313 static void XUsbPs_IntrHandleRX(XUsbPs *InstancePtr, u32 EpCompl)
320 /* Check all endpoints for RX complete bits. */
322 NumEp = InstancePtr->DeviceConfig.NumEndpoints;
325 /* Check for every endpoint if its RX complete bit is set.*/
326 for (Index = 0; Index < NumEp; Index++, Mask <<= 1) {
329 if (!(EpCompl & Mask)) {
332 Ep = &InstancePtr->DeviceConfig.Ep[Index].Out;
334 XUsbPs_dTDInvalidateCache(Ep->dTDCurr);
336 /* Handle all finished dTDs */
337 while (!XUsbPs_dTDIsActive(Ep->dTDCurr)) {
339 if (Ep->HandlerFunc) {
340 Ep->HandlerFunc(Ep->HandlerRef, Index,
341 XUSBPS_EP_EVENT_DATA_RX, NULL);
344 Ep->dTDCurr = XUsbPs_dTDGetNLP(Ep->dTDCurr);
345 XUsbPs_dTDInvalidateCache(Ep->dTDCurr);
347 /* Re-Prime the endpoint.*/
348 XUsbPs_EpPrime(InstancePtr, Index, XUSBPS_EP_DIRECTION_OUT);
353 /*****************************************************************************/
355 * This function handles a RESET interrupt. It will notify the interrupt
356 * handler callback of the RESET condition.
358 * @param InstancePtr is pointer to the XUsbPs instance of the controller
359 * @param IrqSts is the Interrupt status register content.
360 * To be passed on to the user.
366 ******************************************************************************/
367 static void XUsbPs_IntrHandleReset(XUsbPs *InstancePtr, u32 IrqSts)
371 /* Clear all setup token semaphores by reading the
372 * XUSBPS_EPSTAT_OFFSET register and writing its value back to
375 XUsbPs_WriteReg(InstancePtr->Config.BaseAddress, XUSBPS_EPSTAT_OFFSET,
376 XUsbPs_ReadReg(InstancePtr->Config.BaseAddress,
377 XUSBPS_EPSTAT_OFFSET));
379 /* Clear all the endpoint complete status bits by reading the
380 * XUSBPS_EPCOMPL_OFFSET register and writings its value back
383 XUsbPs_WriteReg(InstancePtr->Config.BaseAddress,
384 XUSBPS_EPCOMPL_OFFSET,
385 XUsbPs_ReadReg(InstancePtr->Config.BaseAddress,
386 XUSBPS_EPCOMPL_OFFSET));
388 /* Cancel all endpoint prime status by waiting until all bits
389 * in XUSBPS_EPPRIME_OFFSET are 0 and then writing 0xFFFFFFFF
390 * to XUSBPS_EPFLUSH_OFFSET.
392 * Avoid hanging here by using a Timeout counter...
394 Timeout = XUSBPS_TIMEOUT_COUNTER;
395 while ((XUsbPs_ReadReg(InstancePtr->Config.BaseAddress,
396 XUSBPS_EPPRIME_OFFSET) &
397 XUSBPS_EP_ALL_MASK) && --Timeout) {
400 XUsbPs_WriteReg(InstancePtr->Config.BaseAddress,
401 XUSBPS_EPFLUSH_OFFSET, 0xFFFFFFFF);
403 /* Make sure that the reset bit in XUSBPS_PORTSCR1_OFFSET is
404 * still set at this point. If the code gets to this point and
405 * the reset bit has already been cleared we are in trouble and
406 * hardware reset is necessary.
408 if (!(XUsbPs_ReadReg(InstancePtr->Config.BaseAddress,
409 XUSBPS_PORTSCR1_OFFSET) &
410 XUSBPS_PORTSCR_PR_MASK)) {
411 /* Send a notification to the user that a hardware
412 * RESET is required. At this point we can only hope
413 * that the user registered an interrupt handler and
414 * will issue a hardware RESET.
416 if (InstancePtr->HandlerFunc) {
417 (InstancePtr->HandlerFunc)(InstancePtr->HandlerRef,
424 /* If we get here there is nothing more to do. The user
425 * should have reset the core.
430 /* Check if we have a user handler that needs to be called.
432 if (InstancePtr->HandlerFunc) {
433 (InstancePtr->HandlerFunc)(InstancePtr->HandlerRef, IrqSts);
436 /* We are done. After RESET we don't proceed in the interrupt
442 /*****************************************************************************/
444 * This function handles a Setup Packet interrupt. It will notify the interrupt
445 * handler callback of the RESET condition.
447 * @param InstancePtr is a pointer to the XUsbPs instance of the
454 ******************************************************************************/
455 static void XUsbPs_IntrHandleEp0Setup(XUsbPs *InstancePtr)
460 /* Notifiy the user. */
461 Ep = &InstancePtr->DeviceConfig.Ep[0].Out;
463 if (Ep->HandlerFunc) {
464 Ep->HandlerFunc(Ep->HandlerRef, 0,
465 XUSBPS_EP_EVENT_SETUP_DATA_RECEIVED, NULL);