]> git.sur5r.net Git - freertos/blob - FreeRTOS/Demo/CORTEX_A9_Zynq_ZC702/RTOSDemo_bsp/ps7_cortexa9_0/libsrc/usbps_v2_1/src/xusbps_intr.c
ce4109d6e3949e54da1b24713c7a7f00e0c784b7
[freertos] / FreeRTOS / Demo / CORTEX_A9_Zynq_ZC702 / RTOSDemo_bsp / ps7_cortexa9_0 / libsrc / usbps_v2_1 / src / xusbps_intr.c
1 /******************************************************************************
2 *
3 * Copyright (C) 2010 - 2014 Xilinx, Inc.  All rights reserved.
4 *
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:
11 *
12 * The above copyright notice and this permission notice shall be included in
13 * all copies or substantial portions of the Software.
14 *
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.
18 *
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
25 * SOFTWARE.
26 *
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.
30 *
31 ******************************************************************************/
32 /******************************************************************************/
33 /**
34  * @file xusbps_intr.c
35 * @addtogroup usbps_v2_1
36 * @{
37  *
38  * This file contains the functions that are related to interrupt processing
39  * for the EPB USB driver.
40  *
41  * <pre>
42  * MODIFICATION HISTORY:
43  *
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
48  *                    handling.
49  * </pre>
50  ******************************************************************************/
51
52 /***************************** Include Files **********************************/
53
54 #include "xusbps.h"
55 #include "xusbps_endpoint.h"
56
57 /************************** Constant Definitions ******************************/
58
59 /**************************** Type Definitions ********************************/
60
61 /***************** Macros (Inline Functions) Definitions **********************/
62
63 /************************** Variable Definitions ******************************/
64
65 /************************** Function Prototypes *******************************/
66
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);
71
72 /*****************************************************************************/
73 /**
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()
79 * and/or
80 *    XUsbPs_EpSetHandler()
81 * functions.
82 *
83 *
84 * @param        HandlerRef is a Reference passed to the interrupt register
85 *               function. In our case this will be a pointer to the XUsbPs
86 *               instance.
87 *
88 * @return       None
89 *
90 * @note         None
91 *
92 ******************************************************************************/
93 void XUsbPs_IntrHandler(void *HandlerRef)
94 {
95         XUsbPs  *InstancePtr;
96
97         u32     IrqSts;
98
99         Xil_AssertVoid(HandlerRef != NULL);
100
101         InstancePtr = (XUsbPs *) HandlerRef;
102
103         /* Handle controller (non-endpoint) related interrupts. */
104         IrqSts = XUsbPs_ReadReg(InstancePtr->Config.BaseAddress,
105                                 XUSBPS_ISR_OFFSET);
106
107         /* Clear the interrupt status register. */
108         XUsbPs_WriteReg(InstancePtr->Config.BaseAddress,
109                                 XUSBPS_ISR_OFFSET, IrqSts);
110
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));
118         }
119
120
121         /***************************************************************
122          *
123          * Handle general interrupts. Endpoint interrupts will be handler
124          * later.
125          *
126          */
127
128         /* RESET interrupt.*/
129         if (IrqSts & XUSBPS_IXR_UR_MASK) {
130                 XUsbPs_IntrHandleReset(InstancePtr, IrqSts);
131                 return;
132         }
133
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
136          * be handled below.
137          */
138         if ((IrqSts & InstancePtr->HandlerMask) && InstancePtr->HandlerFunc) {
139                 (InstancePtr->HandlerFunc)(InstancePtr->HandlerRef, IrqSts);
140         }
141
142
143         /***************************************************************
144          *
145          * Handle Endpoint interrupts.
146          *
147          */
148         if (IrqSts & XUSBPS_IXR_UI_MASK) {
149                 u32     EpStat;
150                 u32     EpCompl;
151
152                 /* ENDPOINT 0 SETUP PACKET HANDLING
153                  *
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).
158                  */
159                 EpStat = XUsbPs_ReadReg(InstancePtr->Config.BaseAddress,
160                                                 XUSBPS_EPSTAT_OFFSET);
161                 if (EpStat & 0x0001) {
162                         /* Handle the setup packet */
163                         XUsbPs_IntrHandleEp0Setup(InstancePtr);
164
165                         /* Re-Prime the endpoint.
166                          * Endpoint is de-primed if a setup packet comes in.
167                          */
168                         XUsbPs_EpPrime(InstancePtr, 0, XUSBPS_EP_DIRECTION_OUT);
169                 }
170
171                 /* Check for RX and TX complete interrupts. */
172                 EpCompl = XUsbPs_ReadReg(InstancePtr->Config.BaseAddress,
173                                                 XUSBPS_EPCOMPL_OFFSET);
174
175
176                 /* ACK the complete interrupts. */
177                 XUsbPs_WriteReg(InstancePtr->Config.BaseAddress,
178                                         XUSBPS_EPCOMPL_OFFSET, EpCompl);
179
180                 /* Check OUT (RX) endpoints. */
181                 if (EpCompl & XUSBPS_EP_OUT_MASK) {
182                         XUsbPs_IntrHandleRX(InstancePtr, EpCompl);
183                 }
184
185                 /* Check IN (TX) endpoints. */
186                 if (EpCompl & XUSBPS_EP_IN_MASK) {
187                         XUsbPs_IntrHandleTX(InstancePtr, EpCompl);
188                 }
189         }
190 }
191
192
193 /*****************************************************************************/
194 /**
195 * This function registers the user callback handler for controller
196 * (non-endpoint) interrupts.
197 *
198 * @param        InstancePtr is a pointer to the XUsbPs instance of the
199 *               controller.
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.
206 *
207 * @return
208 *               - XST_SUCCESS: Callback registered successfully.
209 *               - XST_FAILURE: Callback could not be registered.
210 *
211 * @note         None.
212 *
213 ******************************************************************************/
214 int XUsbPs_IntrSetHandler(XUsbPs *InstancePtr,
215                            XUsbPs_IntrHandlerFunc CallBackFunc,
216                            void *CallBackRef, u32 Mask)
217 {
218         Xil_AssertNonvoid(InstancePtr != NULL);
219
220         InstancePtr->HandlerFunc        = CallBackFunc;
221         InstancePtr->HandlerRef         = CallBackRef;
222         InstancePtr->HandlerMask        = Mask;
223
224         return XST_SUCCESS;
225 }
226
227
228 /*****************************************************************************/
229 /**
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.
233 *
234 * @param        InstancePtr is a pointer to the XUsbPs instance of the
235 *               controller.
236 * @param        EpCompl is the Bit mask of endpoints that caused a transmit
237 *               complete interrupt.
238 *
239 * @return       None
240 *
241 * @note         None.
242 *
243 ******************************************************************************/
244 static void XUsbPs_IntrHandleTX(XUsbPs *InstancePtr, u32 EpCompl)
245 {
246         int Index;
247         u32 Mask;
248         int NumEp;
249
250         /* Check all endpoints for TX complete bits.
251          */
252         Mask    = 0x00010000;
253         NumEp   = InstancePtr->DeviceConfig.NumEndpoints;
254
255         /* Check for every endpoint if its TX complete bit is
256          * set.
257          */
258         for (Index = 0; Index < NumEp; Index++, Mask <<= 1) {
259                 XUsbPs_EpIn     *Ep;
260
261                 if (!(EpCompl & Mask)) {
262                         continue;
263                 }
264                 /* The TX complete bit for this endpoint is
265                  * set. Walk the list of descriptors to see
266                  * which ones are completed.
267                  */
268                 Ep = &InstancePtr->DeviceConfig.Ep[Index].In;
269                 while (Ep->dTDTail != Ep->dTDHead) {
270
271                         XUsbPs_dTDInvalidateCache(Ep->dTDTail);
272
273                         /* If the descriptor is not active then the buffer has
274                          * not been sent yet.
275                          */
276                         if (XUsbPs_dTDIsActive(Ep->dTDTail)) {
277                                 break;
278                         }
279
280                         if (Ep->HandlerFunc) {
281                                 void *BufPtr;
282
283                                 BufPtr = (void *) XUsbPs_ReaddTD(Ep->dTDTail,
284                                                         XUSBPS_dTDUSERDATA);
285
286                                 Ep->HandlerFunc(Ep->HandlerRef, Index,
287                                                 XUSBPS_EP_EVENT_DATA_TX,
288                                                                 BufPtr);
289                         }
290
291                         Ep->dTDTail = XUsbPs_dTDGetNLP(Ep->dTDTail);
292                 }
293         }
294 }
295
296
297 /*****************************************************************************/
298 /**
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
302  * received.
303  *
304  * @param       InstancePtr
305  *              Pointer to the XUsbPs instance of the controller.
306  *
307  * @param       EpCompl
308  *              Bit mask of endpoints that caused a receive complete interrupt.
309  * @return
310  *              none
311  *
312  ******************************************************************************/
313 static void XUsbPs_IntrHandleRX(XUsbPs *InstancePtr, u32 EpCompl)
314 {
315         XUsbPs_EpOut    *Ep;
316         int             Index;
317         u32             Mask;
318         int             NumEp;
319
320         /* Check all endpoints for RX complete bits. */
321         Mask    = 0x00000001;
322         NumEp   = InstancePtr->DeviceConfig.NumEndpoints;
323
324
325         /* Check for every endpoint if its RX complete bit is set.*/
326         for (Index = 0; Index < NumEp; Index++, Mask <<= 1) {
327                 int numP = 0;
328
329                 if (!(EpCompl & Mask)) {
330                         continue;
331                 }
332                 Ep = &InstancePtr->DeviceConfig.Ep[Index].Out;
333
334                 XUsbPs_dTDInvalidateCache(Ep->dTDCurr);
335
336                 /* Handle all finished dTDs */
337                 while (!XUsbPs_dTDIsActive(Ep->dTDCurr)) {
338                         numP += 1;
339                         if (Ep->HandlerFunc) {
340                                 Ep->HandlerFunc(Ep->HandlerRef, Index,
341                                                 XUSBPS_EP_EVENT_DATA_RX, NULL);
342                         }
343
344                         Ep->dTDCurr = XUsbPs_dTDGetNLP(Ep->dTDCurr);
345                         XUsbPs_dTDInvalidateCache(Ep->dTDCurr);
346                 }
347                 /* Re-Prime the endpoint.*/
348                 XUsbPs_EpPrime(InstancePtr, Index, XUSBPS_EP_DIRECTION_OUT);
349         }
350 }
351
352
353 /*****************************************************************************/
354 /**
355 * This function handles a RESET interrupt. It will notify the interrupt
356 * handler callback of the RESET condition.
357 *
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.
361 *
362 * @return       None
363 *
364 * @Note         None.
365 *
366 ******************************************************************************/
367 static void XUsbPs_IntrHandleReset(XUsbPs *InstancePtr, u32 IrqSts)
368 {
369         int Timeout;
370
371         /* Clear all setup token semaphores by reading the
372          * XUSBPS_EPSTAT_OFFSET register and writing its value back to
373          * itself.
374          */
375         XUsbPs_WriteReg(InstancePtr->Config.BaseAddress, XUSBPS_EPSTAT_OFFSET,
376                 XUsbPs_ReadReg(InstancePtr->Config.BaseAddress,
377                                 XUSBPS_EPSTAT_OFFSET));
378
379         /* Clear all the endpoint complete status bits by reading the
380          * XUSBPS_EPCOMPL_OFFSET register and writings its value back
381          * to itself.
382          */
383         XUsbPs_WriteReg(InstancePtr->Config.BaseAddress,
384                         XUSBPS_EPCOMPL_OFFSET,
385                 XUsbPs_ReadReg(InstancePtr->Config.BaseAddress,
386                                 XUSBPS_EPCOMPL_OFFSET));
387
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.
391          *
392          * Avoid hanging here by using a Timeout counter...
393          */
394         Timeout = XUSBPS_TIMEOUT_COUNTER;
395         while ((XUsbPs_ReadReg(InstancePtr->Config.BaseAddress,
396                                         XUSBPS_EPPRIME_OFFSET) &
397                                         XUSBPS_EP_ALL_MASK) && --Timeout) {
398                 /* NOP */
399         }
400         XUsbPs_WriteReg(InstancePtr->Config.BaseAddress,
401                                 XUSBPS_EPFLUSH_OFFSET, 0xFFFFFFFF);
402
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.
407          */
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.
415                  */
416                 if (InstancePtr->HandlerFunc) {
417                         (InstancePtr->HandlerFunc)(InstancePtr->HandlerRef,
418                                                    IrqSts);
419                 }
420                 else {
421                         for (;;);
422                 }
423
424                 /* If we get here there is nothing more to do. The user
425                  * should have reset the core.
426                  */
427                 return;
428         }
429
430         /* Check if we have a user handler that needs to be called.
431          */
432         if (InstancePtr->HandlerFunc) {
433                 (InstancePtr->HandlerFunc)(InstancePtr->HandlerRef, IrqSts);
434         }
435
436         /* We are done. After RESET we don't proceed in the interrupt
437          * handler.
438          */
439 }
440
441
442 /*****************************************************************************/
443 /**
444 * This function handles a Setup Packet interrupt. It will notify the interrupt
445 * handler callback of the RESET condition.
446 *
447 * @param        InstancePtr is a pointer to the XUsbPs instance of the
448 *               controller.
449 *
450 * @return       None
451 *
452 * @Note         None
453 *
454 ******************************************************************************/
455 static void XUsbPs_IntrHandleEp0Setup(XUsbPs *InstancePtr)
456 {
457
458         XUsbPs_EpOut    *Ep;
459
460         /* Notifiy the user. */
461         Ep = &InstancePtr->DeviceConfig.Ep[0].Out;
462
463         if (Ep->HandlerFunc) {
464                 Ep->HandlerFunc(Ep->HandlerRef, 0,
465                                 XUSBPS_EP_EVENT_SETUP_DATA_RECEIVED, NULL);
466         }
467 }
468
469
470 /** @} */