]> git.sur5r.net Git - freertos/blob - FreeRTOS/Demo/SuperH_SH7216_Renesas/RTOSDemo/webserver/EMAC.c
Update to MIT licensed FreeRTOS V10.0.0 - see https://www.freertos.org/History.txt
[freertos] / FreeRTOS / Demo / SuperH_SH7216_Renesas / RTOSDemo / webserver / EMAC.c
1 /*\r
2  * FreeRTOS Kernel V10.0.0\r
3  * Copyright (C) 2017 Amazon.com, Inc. or its affiliates.  All Rights Reserved.\r
4  *\r
5  * Permission is hereby granted, free of charge, to any person obtaining a copy of\r
6  * this software and associated documentation files (the "Software"), to deal in\r
7  * the Software without restriction, including without limitation the rights to\r
8  * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\r
9  * the Software, and to permit persons to whom the Software is furnished to do so,\r
10  * subject to the following conditions:\r
11  *\r
12  * The above copyright notice and this permission notice shall be included in all\r
13  * copies or substantial portions of the Software. If you wish to use our Amazon\r
14  * FreeRTOS name, please do so in a fair use way that does not cause confusion.\r
15  *\r
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\r
18  * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\r
19  * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\r
20  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
21  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
22  *\r
23  * http://www.FreeRTOS.org\r
24  * http://aws.amazon.com/freertos\r
25  *\r
26  * 1 tab == 4 spaces!\r
27  */\r
28 \r
29 /* Hardware specific includes. */\r
30 #include "iodefine.h"\r
31 #include "typedefine.h"\r
32 #include "hwEthernet.h"\r
33 #include "hwEthernetPhy.h"\r
34 \r
35 /* FreeRTOS includes. */\r
36 #include "FreeRTOS.h"\r
37 #include "task.h"\r
38 #include "semphr.h"\r
39 \r
40 /* uIP includes. */\r
41 #include "net/uip.h"\r
42 \r
43 /* The time to wait between attempts to obtain a free buffer. */\r
44 #define emacBUFFER_WAIT_DELAY_ms                ( 3 / portTICK_PERIOD_MS )\r
45 \r
46 /* The number of times emacBUFFER_WAIT_DELAY_ms should be waited before giving\r
47 up on attempting to obtain a free buffer all together. */\r
48 #define emacBUFFER_WAIT_ATTEMPTS        ( 30 )\r
49 \r
50 /* The number of Rx descriptors. */\r
51 #define emacNUM_RX_DESCRIPTORS  3\r
52 \r
53 /* The number of Tx descriptors.  When using uIP there is not point in having\r
54 more than two. */\r
55 #define emacNUM_TX_BUFFERS      2\r
56 \r
57 /* The total number of EMAC buffers to allocate. */\r
58 #define emacNUM_BUFFERS         ( emacNUM_RX_DESCRIPTORS + emacNUM_TX_BUFFERS )\r
59 \r
60 /* The time to wait for the Tx descriptor to become free. */\r
61 #define emacTX_WAIT_DELAY_ms ( 10 / portTICK_PERIOD_MS )\r
62 \r
63 /* The total number of times to wait emacTX_WAIT_DELAY_ms for the Tx descriptor to\r
64 become free. */\r
65 #define emacTX_WAIT_ATTEMPTS ( 5 )\r
66 \r
67 /* Only Rx end and Tx end interrupts are used by this driver. */\r
68 #define emacTX_END_INTERRUPT    ( 1UL << 21UL )\r
69 #define emacRX_END_INTERRUPT    ( 1UL << 18UL )\r
70 \r
71 /*-----------------------------------------------------------*/\r
72 \r
73 /* The buffers and descriptors themselves. */\r
74 #pragma section RX_DESCR\r
75         ethfifo xRxDescriptors[ emacNUM_RX_DESCRIPTORS ];\r
76 #pragma section TX_DESCR\r
77         ethfifo xTxDescriptors[ emacNUM_TX_BUFFERS ];\r
78 #pragma section _ETHERNET_BUFFERS\r
79         char xEthernetBuffers[ emacNUM_BUFFERS ][ UIP_BUFSIZE ];\r
80 #pragma section\r
81 \r
82 /* Used to indicate which buffers are free and which are in use.  If an index\r
83 contains 0 then the corresponding buffer in xEthernetBuffers is free, otherwise \r
84 the buffer is in use or about to be used. */\r
85 static unsigned char ucBufferInUse[ emacNUM_BUFFERS ];\r
86 \r
87 /*-----------------------------------------------------------*/\r
88 \r
89 /*\r
90  * Initialise both the Rx and Tx descriptors.\r
91  */\r
92 static void prvInitialiseDescriptors( void );\r
93 \r
94 /*\r
95  * Return a pointer to a free buffer within xEthernetBuffers.\r
96  */\r
97 static unsigned char *prvGetNextBuffer( void );\r
98 \r
99 /*\r
100  * Return a buffer to the list of free buffers.\r
101  */\r
102 static void prvReturnBuffer( unsigned char *pucBuffer );\r
103 \r
104 /*\r
105  * Examine the status of the next Rx FIFO to see if it contains new data.\r
106  */\r
107 static unsigned long prvCheckRxFifoStatus( void );\r
108 \r
109 /*\r
110  * Setup the microcontroller for communication with the PHY.\r
111  */\r
112 static void prvSetupPortPinsAndReset( void );\r
113 \r
114 /*\r
115  * Configure the Ethernet interface peripherals.\r
116  */\r
117 static void prvConfigureEtherCAndEDMAC( void );\r
118 \r
119 /*\r
120  * Something has gone wrong with the descriptor usage.  Reset all the buffers\r
121  * and descriptors.\r
122  */\r
123 static void prvResetEverything( void );\r
124 \r
125 /*-----------------------------------------------------------*/\r
126 \r
127 /* Points to the Rx descriptor currently in use. */\r
128 static ethfifo *xCurrentRxDesc = NULL;\r
129 \r
130 /* The buffer used by the uIP stack to both receive and send.  This points to\r
131 one of the Ethernet buffers when its actually in use. */\r
132 unsigned char *uip_buf = NULL;\r
133 \r
134 /*-----------------------------------------------------------*/\r
135 \r
136 void vInitEmac( void )\r
137 {\r
138         /* Setup the SH hardware for MII communications. */\r
139         prvSetupPortPinsAndReset();\r
140         \r
141         /* Set the Rx and Tx descriptors into their initial state. */\r
142         prvInitialiseDescriptors();\r
143 \r
144         /* Set the MAC address into the ETHERC */\r
145         EtherC.MAHR =   ( ( unsigned long ) configMAC_ADDR0 << 24UL ) | \r
146                                         ( ( unsigned long ) configMAC_ADDR1 << 16UL ) | \r
147                                         ( ( unsigned long ) configMAC_ADDR2 << 8UL ) | \r
148                                         ( unsigned long ) configMAC_ADDR3;\r
149                                         \r
150         EtherC.MALR.BIT.MA = ( ( unsigned long ) configMAC_ADDR4 << 8UL ) |\r
151                                                  ( unsigned long ) configMAC_ADDR5;\r
152 \r
153         /* Perform rest of interface hardware configuration. */\r
154         prvConfigureEtherCAndEDMAC();\r
155         \r
156         /* Nothing received yet, so uip_buf points nowhere. */\r
157         uip_buf = NULL;\r
158 \r
159         /* Initialize the PHY */\r
160         phyReset();\r
161 }\r
162 /*-----------------------------------------------------------*/\r
163 \r
164 void vEMACWrite( void )\r
165 {\r
166 long x;\r
167 \r
168         /* Wait until the second transmission of the last packet has completed. */\r
169         for( x = 0; x < emacTX_WAIT_ATTEMPTS; x++ )\r
170         {\r
171                 if( ( xTxDescriptors[ 1 ].status & ACT ) != 0 )\r
172                 {\r
173                         /* Descriptor is still active. */\r
174                         vTaskDelay( emacTX_WAIT_DELAY_ms );\r
175                 }\r
176                 else\r
177                 {\r
178                         break;\r
179                 }\r
180         }\r
181         \r
182         /* Is the descriptor free after waiting for it? */\r
183         if( ( xTxDescriptors[ 1 ].status & ACT ) != 0 )\r
184         {\r
185                 /* Something has gone wrong. */\r
186                 prvResetEverything();\r
187         }\r
188         \r
189         /* Setup both descriptors to transmit the frame. */\r
190         xTxDescriptors[ 0 ].buf_p = ( char * ) uip_buf;\r
191         xTxDescriptors[ 0 ].bufsize = uip_len;  \r
192         xTxDescriptors[ 1 ].buf_p = ( char * ) uip_buf;\r
193         xTxDescriptors[ 1 ].bufsize = uip_len;\r
194 \r
195         /* uip_buf is being sent by the Tx descriptor.  Allocate a new buffer\r
196         for use by the stack. */\r
197         uip_buf = prvGetNextBuffer();\r
198 \r
199         /* Clear previous settings and go. */\r
200         xTxDescriptors[0].status &= ~( FP1 | FP0 );\r
201         xTxDescriptors[0].status |= ( FP1 | FP0 | ACT );\r
202         xTxDescriptors[1].status &= ~( FP1 | FP0 );\r
203         xTxDescriptors[1].status |= ( FP1 | FP0 | ACT );\r
204 \r
205         EDMAC.EDTRR.LONG = 0x00000001;\r
206 }\r
207 /*-----------------------------------------------------------*/\r
208 \r
209 unsigned long ulEMACRead( void )\r
210 {\r
211 unsigned long ulBytesReceived;\r
212 \r
213         ulBytesReceived = prvCheckRxFifoStatus();\r
214 \r
215         if( ulBytesReceived > 0 )\r
216         {\r
217                 xCurrentRxDesc->status &= ~( FP1 | FP0 );\r
218                 xCurrentRxDesc->status |= ACT;                  \r
219 \r
220                 if( EDMAC.EDRRR.LONG == 0x00000000L )\r
221                 {\r
222                         /* Restart Ethernet if it has stopped */\r
223                         EDMAC.EDRRR.LONG = 0x00000001L;\r
224                 }\r
225 \r
226                 /* Mark the pxDescriptor buffer as free as uip_buf is going to be set to\r
227                 the buffer that contains the received data. */\r
228                 prvReturnBuffer( uip_buf );\r
229                 \r
230                 uip_buf = ( void * ) xCurrentRxDesc->buf_p;\r
231 \r
232                 /* Move onto the next buffer in the ring. */\r
233                 xCurrentRxDesc = xCurrentRxDesc->next;\r
234         }\r
235 \r
236         return ulBytesReceived;\r
237 }\r
238 /*-----------------------------------------------------------*/\r
239 \r
240 long lEMACWaitForLink( void )\r
241 {\r
242 long lReturn;\r
243 \r
244         /* Set the link status. */\r
245         switch( phyStatus() )\r
246         {\r
247                 /* Half duplex link */\r
248                 case PHY_LINK_100H:\r
249                 case PHY_LINK_10H:\r
250                                                                 EtherC.ECMR.BIT.DM = 0;\r
251                                                                 lReturn = pdPASS;\r
252                                                                 break;\r
253 \r
254                 /* Full duplex link */\r
255                 case PHY_LINK_100F:\r
256                 case PHY_LINK_10F:\r
257                                                                 EtherC.ECMR.BIT.DM = 1;\r
258                                                                 lReturn = pdPASS;\r
259                                                                 break;\r
260 \r
261                 default:\r
262                                                                 lReturn = pdFAIL;\r
263                                                                 break;\r
264         }\r
265 \r
266         if( lReturn == pdPASS )\r
267         {\r
268                 /* Enable receive and transmit. */\r
269                 EtherC.ECMR.BIT.RE = 1;\r
270                 EtherC.ECMR.BIT.TE = 1;\r
271 \r
272                 /* Enable EDMAC receive */\r
273                 EDMAC.EDRRR.LONG = 0x1;\r
274         }\r
275         \r
276         return lReturn;\r
277 }\r
278 /*-----------------------------------------------------------*/\r
279 \r
280 static void prvInitialiseDescriptors( void )\r
281 {\r
282 ethfifo *pxDescriptor;\r
283 long x;\r
284 \r
285         for( x = 0; x < emacNUM_BUFFERS; x++ )\r
286         {\r
287                 /* Ensure none of the buffers are shown as in use at the start. */\r
288                 ucBufferInUse[ x ] = pdFALSE;\r
289         }\r
290 \r
291         /* Initialise the Rx descriptors. */\r
292         for( x = 0; x < emacNUM_RX_DESCRIPTORS; x++ )\r
293         {\r
294                 pxDescriptor = &( xRxDescriptors[ x ] );\r
295                 pxDescriptor->buf_p = &( xEthernetBuffers[ x ][ 0 ] );\r
296 \r
297                 pxDescriptor->bufsize = UIP_BUFSIZE;\r
298                 pxDescriptor->size = 0;\r
299                 pxDescriptor->status = ACT;\r
300                 pxDescriptor->next = &xRxDescriptors[ x + 1 ];  \r
301                 \r
302                 /* Mark this buffer as in use. */\r
303                 ucBufferInUse[ x ] = pdTRUE;\r
304         }\r
305 \r
306         /* The last descriptor points back to the start. */\r
307         pxDescriptor->status |= DL;\r
308         pxDescriptor->next = &xRxDescriptors[ 0 ];\r
309         \r
310         /* Initialise the Tx descriptors. */\r
311         for( x = 0; x < emacNUM_TX_BUFFERS; x++ )\r
312         {\r
313                 pxDescriptor = &( xTxDescriptors[ x ] );\r
314                 \r
315                 /* A buffer is not allocated to the Tx descriptor until a send is\r
316                 actually required. */\r
317                 pxDescriptor->buf_p = NULL;\r
318 \r
319                 pxDescriptor->bufsize = UIP_BUFSIZE;\r
320                 pxDescriptor->size = 0;\r
321                 pxDescriptor->status = 0;\r
322                 pxDescriptor->next = &xTxDescriptors[ x + 1 ];  \r
323         }\r
324 \r
325         /* The last descriptor points back to the start. */\r
326         pxDescriptor->status |= DL;\r
327         pxDescriptor->next = &( xTxDescriptors[ 0 ] );\r
328         \r
329         /* Use the first Rx descriptor to start with. */\r
330         xCurrentRxDesc = &( xRxDescriptors[ 0 ] );\r
331 }\r
332 /*-----------------------------------------------------------*/\r
333 \r
334 static unsigned char *prvGetNextBuffer( void )\r
335 {\r
336 long x;\r
337 unsigned char *pucReturn = NULL;\r
338 unsigned long ulAttempts = 0;\r
339 \r
340         while( pucReturn == NULL )\r
341         {\r
342                 /* Look through the buffers to find one that is not in use by\r
343                 anything else. */\r
344                 for( x = 0; x < emacNUM_BUFFERS; x++ )\r
345                 {\r
346                         if( ucBufferInUse[ x ] == pdFALSE )\r
347                         {\r
348                                 ucBufferInUse[ x ] = pdTRUE;\r
349                                 pucReturn = ( unsigned char * ) &( xEthernetBuffers[ x ][ 0 ] );\r
350                                 break;\r
351                         }\r
352                 }\r
353 \r
354                 /* Was a buffer found? */\r
355                 if( pucReturn == NULL )\r
356                 {\r
357                         ulAttempts++;\r
358 \r
359                         if( ulAttempts >= emacBUFFER_WAIT_ATTEMPTS )\r
360                         {\r
361                                 break;\r
362                         }\r
363 \r
364                         /* Wait then look again. */\r
365                         vTaskDelay( emacBUFFER_WAIT_DELAY_ms );\r
366                 }\r
367         }\r
368 \r
369         return pucReturn;\r
370 }\r
371 /*-----------------------------------------------------------*/\r
372 \r
373 static void prvReturnBuffer( unsigned char *pucBuffer )\r
374 {\r
375 unsigned long ul;\r
376 \r
377         /* Return a buffer to the pool of free buffers. */\r
378         for( ul = 0; ul < emacNUM_BUFFERS; ul++ )\r
379         {\r
380                 if( &( xEthernetBuffers[ ul ][ 0 ] ) == ( void * ) pucBuffer )\r
381                 {\r
382                         ucBufferInUse[ ul ] = pdFALSE;\r
383                         break;\r
384                 }\r
385         }\r
386 }\r
387 /*-----------------------------------------------------------*/\r
388 \r
389 static void prvResetEverything( void )\r
390 {\r
391         /* Temporary code just to see if this gets called.  This function has not\r
392         been implemented. */\r
393         portDISABLE_INTERRUPTS();\r
394         for( ;; );\r
395 }\r
396 /*-----------------------------------------------------------*/\r
397 \r
398 static unsigned long prvCheckRxFifoStatus( void )\r
399 {\r
400 unsigned long ulReturn = 0;\r
401 \r
402         if( ( xCurrentRxDesc->status & ACT ) != 0 )\r
403         {\r
404                 /* Current descriptor is still active. */\r
405         }\r
406         else if( ( xCurrentRxDesc->status & FE ) != 0 )\r
407         {\r
408                 /* Frame error.  Clear the error. */\r
409                 xCurrentRxDesc->status &= ~( FP1 | FP0 | FE );\r
410                 xCurrentRxDesc->status &= ~( RMAF | RRF | RTLF | RTSF | PRE | CERF );\r
411                 xCurrentRxDesc->status |= ACT;\r
412                 xCurrentRxDesc = xCurrentRxDesc->next;\r
413 \r
414                 if( EDMAC.EDRRR.LONG == 0x00000000UL )\r
415                 {\r
416                         /* Restart Ethernet if it has stopped. */\r
417                         EDMAC.EDRRR.LONG = 0x00000001UL;\r
418                 }       \r
419         }\r
420         else\r
421         {\r
422                 /* The descriptor contains a frame.  Because of the size of the buffers\r
423                 the frame should always be complete. */\r
424                 if( (xCurrentRxDesc->status & FP0) == FP0 )\r
425                 {\r
426                         ulReturn = xCurrentRxDesc->size;\r
427                 }\r
428                 else\r
429                 {\r
430                         /* Do not expect to get here. */\r
431                         prvResetEverything();\r
432                 }\r
433         }\r
434         \r
435         return ulReturn;\r
436 }\r
437 /*-----------------------------------------------------------*/\r
438 \r
439 static void prvSetupPortPinsAndReset( void )\r
440 {\r
441         /* Initialisation code taken from Renesas example project. */\r
442         \r
443         PFC.PACRL4.BIT.PA12MD = 0x7;            /* Set TX_CLK input      (EtherC) */\r
444         PFC.PACRL3.BIT.PA11MD = 0x7;            /* Set TX_EN output      (EtherC) */\r
445         PFC.PACRL3.BIT.PA10MD = 0x7;            /* Set MII_TXD0 output   (EtherC) */\r
446         PFC.PACRL3.BIT.PA9MD  = 0x7;            /* Set MII_TXD1 output   (EtherC) */\r
447         PFC.PACRL3.BIT.PA8MD  = 0x7;            /* Set MII_TXD2 output   (EtherC) */\r
448         PFC.PACRL2.BIT.PA7MD  = 0x7;            /* Set MII_TXD3 output   (EtherC) */\r
449         PFC.PACRL2.BIT.PA6MD  = 0x7;            /* Set TX_ER output      (EtherC) */\r
450         PFC.PDCRH4.BIT.PD31MD = 0x7;            /* Set RX_DV input       (EtherC) */\r
451         PFC.PDCRH4.BIT.PD30MD = 0x7;            /* Set RX_ER input       (EtherC) */\r
452         PFC.PDCRH4.BIT.PD29MD = 0x7;            /* Set MII_RXD3 input    (EtherC) */\r
453         PFC.PDCRH4.BIT.PD28MD = 0x7;            /* Set MII_RXD2 input    (EtherC) */\r
454         PFC.PDCRH3.BIT.PD27MD = 0x7;            /* Set MII_RXD1 input    (EtherC) */\r
455         PFC.PDCRH3.BIT.PD26MD = 0x7;            /* Set MII_RXD0 input    (EtherC) */\r
456         PFC.PDCRH3.BIT.PD25MD = 0x7;            /* Set RX_CLK input      (EtherC) */\r
457         PFC.PDCRH3.BIT.PD24MD = 0x7;            /* Set CRS input         (EtherC) */\r
458         PFC.PDCRH2.BIT.PD23MD = 0x7;            /* Set COL input         (EtherC) */\r
459         PFC.PDCRH2.BIT.PD22MD = 0x7;            /* Set WOL output        (EtherC) */\r
460         PFC.PDCRH2.BIT.PD21MD = 0x7;            /* Set EXOUT output      (EtherC) */\r
461         PFC.PDCRH2.BIT.PD20MD = 0x7;            /* Set MDC output        (EtherC) */\r
462         PFC.PDCRH1.BIT.PD19MD = 0x7;            /* Set LINKSTA input     (EtherC) */\r
463         PFC.PDCRH1.BIT.PD18MD = 0x7;            /* Set MDIO input/output (EtherC) */\r
464         \r
465         STB.CR4.BIT._ETHER = 0x0;       \r
466         EDMAC.EDMR.BIT.SWR = 1; \r
467         \r
468         /* Crude wait for reset to complete. */\r
469         vTaskDelay( 500 / portTICK_PERIOD_MS ); \r
470 }\r
471 /*-----------------------------------------------------------*/\r
472 \r
473 static void prvConfigureEtherCAndEDMAC( void )\r
474 {\r
475         /* Initialisation code taken from Renesas example project. */\r
476         \r
477         /* TODO:    Check   bit 5   */\r
478         EtherC.ECSR.LONG = 0x00000037;                          /* Clear all EtherC statuS BFR, PSRTO, LCHNG, MPD, ICD */\r
479 \r
480         /* TODO:    Check   bit 5   */\r
481         EtherC.ECSIPR.LONG = 0x00000020;                        /* Disable EtherC status change interrupt */\r
482         EtherC.RFLR.LONG = 1518;                                        /* Ether payload is 1500+ CRC */\r
483         EtherC.IPGR.LONG = 0x00000014;                          /* Intergap is 96-bit time */\r
484 \r
485         /* EDMAC */\r
486         EDMAC.EESR.LONG = 0x47FF0F9F;                           /* Clear all EtherC and EDMAC status bits */\r
487         EDMAC.RDLAR = ( void * ) xCurrentRxDesc;        /* Initialaize Rx Descriptor List Address */\r
488         EDMAC.TDLAR = &( xTxDescriptors[ 0 ] );         /* Initialaize Tx Descriptor List Address */\r
489         EDMAC.TRSCER.LONG = 0x00000000;                         /* Copy-back status is RFE & TFE only   */\r
490         EDMAC.TFTR.LONG = 0x00000000;                           /* Threshold of Tx_FIFO */\r
491         EDMAC.FDR.LONG = 0x00000000;                            /* Transmit fifo & receive fifo is 256 bytes */\r
492         EDMAC.RMCR.LONG = 0x00000003;                           /* Receive function is normal mode(continued) */\r
493 \r
494         /* Set the EDMAC interrupt priority - the interrupt priority must be\r
495         configKERNEL_INTERRUPT_PRIORITY no matter which peripheral is used to \r
496         generate the tick interrupt. */\r
497         INTC.IPR19.BIT._EDMAC = portKERNEL_INTERRUPT_PRIORITY;\r
498         EDMAC.EESIPR.LONG = emacTX_END_INTERRUPT | emacRX_END_INTERRUPT;        /* Enable Rx and Tx end interrupts. */\r
499 \r
500         /* Clear the interrupt flag. */\r
501         CMT0.CMCSR.BIT.CMF = 0;\r
502 }\r
503 /*-----------------------------------------------------------*/\r
504 \r
505 void vEMAC_ISR_Handler( void )\r
506 {\r
507 unsigned long ul = EDMAC.EESR.LONG;\r
508 long lHigherPriorityTaskWoken = pdFALSE;\r
509 extern SemaphoreHandle_t xEMACSemaphore;\r
510 static long ulTxEndInts = 0;\r
511 \r
512         /* Has a Tx end occurred? */\r
513         if( ul & emacTX_END_INTERRUPT )\r
514         {\r
515                 ++ulTxEndInts;\r
516                 if( ulTxEndInts >= 2 )\r
517                 {\r
518                         /* Only return the buffer to the pool once both Txes have completed. */\r
519                         prvReturnBuffer( ( void * ) xTxDescriptors[ 0 ].buf_p );\r
520                         ulTxEndInts = 0;\r
521                 }\r
522                 EDMAC.EESR.LONG = emacTX_END_INTERRUPT;\r
523         }\r
524 \r
525         /* Has an Rx end occurred? */\r
526         if( ul & emacRX_END_INTERRUPT )\r
527         {\r
528                 /* Make sure the Ethernet task is not blocked waiting for a packet. */\r
529                 xSemaphoreGiveFromISR( xEMACSemaphore, &lHigherPriorityTaskWoken );\r
530                 portYIELD_FROM_ISR( lHigherPriorityTaskWoken );\r
531                 EDMAC.EESR.LONG = emacRX_END_INTERRUPT;\r
532         }\r
533 }\r