]> git.sur5r.net Git - freertos/blob - FreeRTOS/Demo/CORTEX_Kinetis_K60_Tower_IAR/webserver/EMAC.c
Add FreeRTOS-Plus directory.
[freertos] / FreeRTOS / Demo / CORTEX_Kinetis_K60_Tower_IAR / webserver / EMAC.c
1 /*\r
2     FreeRTOS V7.1.1 - Copyright (C) 2012 Real Time Engineers Ltd.\r
3         \r
4 \r
5     ***************************************************************************\r
6      *                                                                       *\r
7      *    FreeRTOS tutorial books are available in pdf and paperback.        *\r
8      *    Complete, revised, and edited pdf reference manuals are also       *\r
9      *    available.                                                         *\r
10      *                                                                       *\r
11      *    Purchasing FreeRTOS documentation will not only help you, by       *\r
12      *    ensuring you get running as quickly as possible and with an        *\r
13      *    in-depth knowledge of how to use FreeRTOS, it will also help       *\r
14      *    the FreeRTOS project to continue with its mission of providing     *\r
15      *    professional grade, cross platform, de facto standard solutions    *\r
16      *    for microcontrollers - completely free of charge!                  *\r
17      *                                                                       *\r
18      *    >>> See http://www.FreeRTOS.org/Documentation for details. <<<     *\r
19      *                                                                       *\r
20      *    Thank you for using FreeRTOS, and thank you for your support!      *\r
21      *                                                                       *\r
22     ***************************************************************************\r
23 \r
24 \r
25     This file is part of the FreeRTOS distribution.\r
26 \r
27     FreeRTOS is free software; you can redistribute it and/or modify it under\r
28     the terms of the GNU General Public License (version 2) as published by the\r
29     Free Software Foundation AND MODIFIED BY the FreeRTOS exception.\r
30     >>>NOTE<<< The modification to the GPL is included to allow you to\r
31     distribute a combined work that includes FreeRTOS without being obliged to\r
32     provide the source code for proprietary components outside of the FreeRTOS\r
33     kernel.  FreeRTOS is distributed in the hope that it will be useful, but\r
34     WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY\r
35     or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\r
36     more details. You should have received a copy of the GNU General Public\r
37     License and the FreeRTOS license exception along with FreeRTOS; if not it\r
38     can be viewed here: http://www.freertos.org/a00114.html and also obtained\r
39     by writing to Richard Barry, contact details for whom are available on the\r
40     FreeRTOS WEB site.\r
41 \r
42     1 tab == 4 spaces!\r
43     \r
44     ***************************************************************************\r
45      *                                                                       *\r
46      *    Having a problem?  Start by reading the FAQ "My application does   *\r
47      *    not run, what could be wrong?                                      *\r
48      *                                                                       *\r
49      *    http://www.FreeRTOS.org/FAQHelp.html                               *\r
50      *                                                                       *\r
51     ***************************************************************************\r
52 \r
53     \r
54     http://www.FreeRTOS.org - Documentation, training, latest information, \r
55     license and contact details.\r
56     \r
57     http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,\r
58     including FreeRTOS+Trace - an indispensable productivity tool.\r
59 \r
60     Real Time Engineers ltd license FreeRTOS to High Integrity Systems, who sell \r
61     the code with commercial support, indemnification, and middleware, under \r
62     the OpenRTOS brand: http://www.OpenRTOS.com.  High Integrity Systems also\r
63     provide a safety engineered and independently SIL3 certified version under \r
64     the SafeRTOS brand: http://www.SafeRTOS.com.\r
65 */\r
66 \r
67 /* Freescale includes. */\r
68 #include "common.h"\r
69 #include "eth_phy.h"\r
70 #include "enet.h"\r
71 #include "mii.h"\r
72 \r
73 /* FreeRTOS includes. */\r
74 #include "FreeRTOS.h"\r
75 #include "task.h"\r
76 #include "queue.h"\r
77 \r
78 /* uIP includes. */\r
79 #include "net/uip.h"\r
80 \r
81 /* The time to wait between attempts to obtain a free buffer. */\r
82 #define emacBUFFER_WAIT_DELAY_ms                ( 3 / portTICK_RATE_MS )\r
83 \r
84 /* The number of times emacBUFFER_WAIT_DELAY_ms should be waited before giving\r
85 up on attempting to obtain a free buffer all together. */\r
86 #define emacBUFFER_WAIT_ATTEMPTS                ( 30 )\r
87 \r
88 /* The number of Rx descriptors. */\r
89 #define emacNUM_RX_DESCRIPTORS                  8\r
90 \r
91 /* The number of Tx descriptors.  When using uIP there is not point in having\r
92 more than two. */\r
93 #define emacNUM_TX_BUFFERS                              2\r
94 \r
95 /* The total number of EMAC buffers to allocate. */\r
96 #define emacNUM_BUFFERS                                 ( emacNUM_RX_DESCRIPTORS + emacNUM_TX_BUFFERS )\r
97 \r
98 /* The time to wait for the Tx descriptor to become free. */\r
99 #define emacTX_WAIT_DELAY_ms                    ( 10 / portTICK_RATE_MS )\r
100 \r
101 /* The total number of times to wait emacTX_WAIT_DELAY_ms for the Tx descriptor to\r
102 become free. */\r
103 #define emacTX_WAIT_ATTEMPTS                    ( 50 )\r
104 \r
105 /* Constants used for set up and initialisation. */\r
106 #define emacTX_INTERRUPT_NO                     ( 76 )\r
107 #define emacRX_INTERRUPT_NO                     ( 77 )\r
108 #define emacERROR_INTERRUPT_NO          ( 78 )\r
109 #define emacLINK_DELAY                          ( 500 / portTICK_RATE_MS )\r
110 #define emacPHY_STATUS                          ( 0x1F )\r
111 #define emacPHY_DUPLEX_STATUS           ( 4 << 2 )\r
112 #define emacPHY_SPEED_STATUS            ( 1 << 2 )\r
113 \r
114 /*-----------------------------------------------------------*/\r
115 \r
116 /*\r
117  * Initialise both the Rx and Tx descriptors.\r
118  */\r
119 static void prvInitialiseDescriptors( void );\r
120 \r
121 /*\r
122  * Return a pointer to a free buffer within xEthernetBuffers.\r
123  */\r
124 static unsigned char *prvGetNextBuffer( void );\r
125 \r
126 /*\r
127  * Return a buffer to the list of free buffers.\r
128  */\r
129 static void prvReturnBuffer( unsigned char *pucBuffer );\r
130 \r
131 /*\r
132  * Examine the status of the next Rx descriptor to see if it contains new data.\r
133  */\r
134 static unsigned short prvCheckRxStatus( void );\r
135 \r
136 /*\r
137  * Something has gone wrong with the descriptor usage.  Reset all the buffers\r
138  * and descriptors.\r
139  */\r
140 static void prvResetEverything( void );\r
141 \r
142 /*-----------------------------------------------------------*/\r
143 \r
144 /* The buffers and descriptors themselves.  */\r
145 #pragma data_alignment=16\r
146 volatile NBUF xRxDescriptors[ emacNUM_RX_DESCRIPTORS ];\r
147 \r
148 #pragma data_alignment=16\r
149 volatile NBUF xTxDescriptors[ emacNUM_TX_BUFFERS ];\r
150 \r
151 #pragma data_alignment=16\r
152 char xEthernetBuffers[ emacNUM_BUFFERS ][ UIP_BUFSIZE ];\r
153 \r
154 /* Used to indicate which buffers are free and which are in use.  If an index\r
155 contains 0 then the corresponding buffer in xEthernetBuffers is free, otherwise\r
156 the buffer is in use or about to be used. */\r
157 static unsigned char ucBufferInUse[ emacNUM_BUFFERS ];\r
158 \r
159 /* Points to the Rx descriptor currently in use. */\r
160 static volatile NBUF *pxCurrentRxDesc = NULL;\r
161 \r
162 /* pxCurrentRxDesc points to descriptor within the xRxDescriptors array that\r
163 has an index defined by ulRxDescriptorIndex. */\r
164 static unsigned long ulRxDescriptorIndex = 0UL;\r
165 \r
166 /* The buffer used by the uIP stack to both receive and send.  This points to\r
167 one of the Ethernet buffers when its actually in use. */\r
168 unsigned char *uip_buf = NULL;\r
169 \r
170 /*-----------------------------------------------------------*/\r
171 \r
172 void vEMACInit( void )\r
173 {\r
174 int iData;\r
175 extern int periph_clk_khz;\r
176 const unsigned portCHAR ucMACAddress[] =\r
177 {\r
178         configMAC_ADDR0, configMAC_ADDR1, configMAC_ADDR2, configMAC_ADDR3, configMAC_ADDR4, configMAC_ADDR5\r
179 };\r
180 \r
181         /* Enable the ENET clock. */\r
182         SIM_SCGC2 |= SIM_SCGC2_ENET_MASK;\r
183 \r
184         /* Allow concurrent access to MPU controller to avoid bus errors. */\r
185         MPU_CESR = 0;\r
186 \r
187         prvInitialiseDescriptors();\r
188 \r
189         /* Reset and enable. */\r
190         ENET_ECR = ENET_ECR_RESET_MASK;\r
191         \r
192         /* Wait at least 8 clock cycles */\r
193         vTaskDelay( 2 );\r
194         \r
195         /* Start the MII interface*/\r
196         mii_init( 0, periph_clk_khz / 1000L );\r
197 \r
198         /* Configure the transmit interrupt. */\r
199         set_irq_priority( emacTX_INTERRUPT_NO, configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY );\r
200         enable_irq( emacTX_INTERRUPT_NO );\r
201 \r
202         /* Configure the receive interrupt. */\r
203         set_irq_priority( emacRX_INTERRUPT_NO, configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY );\r
204         enable_irq( emacRX_INTERRUPT_NO );\r
205 \r
206         /* Configure the error interrupt. */\r
207         set_irq_priority( emacERROR_INTERRUPT_NO, configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY );\r
208         enable_irq( emacERROR_INTERRUPT_NO );\r
209 \r
210         /* Configure the pins to the PHY - RMII mode used. */\r
211         PORTB_PCR0  = PORT_PCR_MUX( 4 ); /* RMII0_MDIO / MII0_MDIO. */\r
212         PORTB_PCR1  = PORT_PCR_MUX( 4 ); /* RMII0_MDC / MII0_MDC */\r
213         PORTA_PCR14 = PORT_PCR_MUX( 4 ); /* RMII0_CRS_DV / MII0_RXDV */\r
214         PORTA_PCR12 = PORT_PCR_MUX( 4 ); /* RMII0_RXD1 / MII0_RXD1 */\r
215         PORTA_PCR13 = PORT_PCR_MUX( 4 ); /* RMII0_RXD0/MII0_RXD0 */\r
216         PORTA_PCR15 = PORT_PCR_MUX( 4 ); /* RMII0_TXEN/MII0_TXEN */\r
217         PORTA_PCR16 = PORT_PCR_MUX( 4 ); /* RMII0_TXD0/MII0_TXD0 */\r
218         PORTA_PCR17 = PORT_PCR_MUX( 4 ); /* RMII0_TXD1/MII0_TXD1 */\r
219 \r
220         /* Is there communication with the PHY? */\r
221         do\r
222         {\r
223                 vTaskDelay( emacLINK_DELAY );\r
224                 iData = 0xFFFF;\r
225                 mii_read( 0, configPHY_ADDRESS, PHY_PHYIDR1, &iData );\r
226         \r
227         } while( iData == 0xFFFF );\r
228 \r
229         /* Start to auto negotiate. */\r
230         mii_write( 0, configPHY_ADDRESS, PHY_BMCR, ( PHY_BMCR_AN_RESTART | PHY_BMCR_AN_ENABLE ) );\r
231         \r
232         /* Wait for auto negotiate to complete. */\r
233         do\r
234         {\r
235                 vTaskDelay( emacLINK_DELAY );\r
236                 mii_read( 0, configPHY_ADDRESS, PHY_BMSR, &iData );\r
237         \r
238         } while( !( iData & PHY_BMSR_AN_COMPLETE ) );\r
239 \r
240         /* A link has been established.  What was negotiated? */\r
241         iData = 0;\r
242         mii_read( 0, configPHY_ADDRESS, emacPHY_STATUS, &iData );\r
243 \r
244         /* Clear the Individual and Group Address Hash registers */\r
245         ENET_IALR = 0;\r
246         ENET_IAUR = 0;\r
247         ENET_GALR = 0;\r
248         ENET_GAUR = 0;\r
249 \r
250         /* Set the Physical Address for the selected ENET */\r
251         enet_set_address( 0, ucMACAddress );\r
252 \r
253         ENET_RCR = ENET_RCR_MAX_FL( UIP_BUFSIZE ) | ENET_RCR_MII_MODE_MASK | ENET_RCR_CRCFWD_MASK | ENET_RCR_RMII_MODE_MASK;\r
254 \r
255         /* Clear the control registers. */\r
256         ENET_TCR = 0;\r
257 \r
258         if( iData & emacPHY_DUPLEX_STATUS )\r
259         {\r
260                 /* Full duplex */\r
261                 ENET_RCR &= ( unsigned long )~ENET_RCR_DRT_MASK;\r
262                 ENET_TCR |= ENET_TCR_FDEN_MASK;\r
263         }\r
264         else\r
265         {\r
266                 /* Half duplex */\r
267                 ENET_RCR |= ENET_RCR_DRT_MASK;\r
268                 ENET_TCR &= (unsigned portLONG)~ENET_TCR_FDEN_MASK;\r
269         }\r
270 \r
271         if( iData & emacPHY_SPEED_STATUS )\r
272         {\r
273                 /* 10Mbps */\r
274                 ENET_RCR |= ENET_RCR_RMII_10T_MASK;\r
275         }\r
276 \r
277     ENET_ECR = ENET_ECR_EN1588_MASK;\r
278 \r
279         /* Store and forward checksum. */\r
280         ENET_TFWR = ENET_TFWR_STRFWD_MASK;\r
281 \r
282         /* Set Rx Buffer Size */\r
283         ENET_MRBR = ( unsigned short ) UIP_BUFSIZE;\r
284         \r
285         /* Point to the start of the circular Rx buffer descriptor queue */\r
286         ENET_RDSR = ( unsigned long ) &( xRxDescriptors[ 0 ] );\r
287         \r
288         /* Point to the start of the circular Tx buffer descriptor queue */\r
289         ENET_TDSR = ( unsigned long ) &( xTxDescriptors[ 0 ] );\r
290         \r
291         /* Clear all ENET interrupt events */\r
292         ENET_EIR = ( unsigned long ) -1;\r
293         \r
294         /* Enable interrupts. */\r
295         ENET_EIMR = 0\r
296                         /*rx irqs*/\r
297                         | ENET_EIMR_RXF_MASK/* only for complete frame, not partial buffer descriptor | ENET_EIMR_RXB_MASK*/\r
298                         /*xmit irqs*/\r
299                         | ENET_EIMR_TXF_MASK/* only for complete frame, not partial buffer descriptor | ENET_EIMR_TXB_MASK*/\r
300                         /*enet irqs*/\r
301                         | ENET_EIMR_UN_MASK | ENET_EIMR_RL_MASK | ENET_EIMR_LC_MASK | ENET_EIMR_BABT_MASK | ENET_EIMR_BABR_MASK | ENET_EIMR_EBERR_MASK\r
302                         ;\r
303         \r
304         /* Enable the MAC itself. */\r
305         ENET_ECR |= ENET_ECR_ETHEREN_MASK;\r
306         \r
307         /* Indicate that there have been empty receive buffers produced */\r
308         ENET_RDAR = ENET_RDAR_RDAR_MASK;\r
309 }\r
310 /*-----------------------------------------------------------*/\r
311 \r
312 static void prvInitialiseDescriptors( void )\r
313 {\r
314 volatile NBUF *pxDescriptor;\r
315 long x;\r
316 \r
317         for( x = 0; x < emacNUM_BUFFERS; x++ )\r
318         {\r
319                 /* Ensure none of the buffers are shown as in use at the start. */\r
320                 ucBufferInUse[ x ] = pdFALSE;\r
321         }\r
322 \r
323         /* Initialise the Rx descriptors. */\r
324         for( x = 0; x < emacNUM_RX_DESCRIPTORS; x++ )\r
325         {\r
326                 pxDescriptor = &( xRxDescriptors[ x ] );\r
327                 pxDescriptor->data = ( uint8_t* ) &( xEthernetBuffers[ x ][ 0 ] );\r
328                 pxDescriptor->data = ( uint8_t* ) __REV( ( unsigned long ) pxDescriptor->data );\r
329                 pxDescriptor->length = 0;\r
330                 pxDescriptor->status = RX_BD_E;\r
331                 pxDescriptor->bdu = 0;\r
332                 pxDescriptor->ebd_status = RX_BD_INT;\r
333                 \r
334                 /* Mark this buffer as in use. */\r
335                 ucBufferInUse[ x ] = pdTRUE;\r
336         }\r
337 \r
338         /* The last descriptor points back to the start. */\r
339         pxDescriptor->status |= RX_BD_W;\r
340         \r
341         /* Initialise the Tx descriptors. */\r
342         for( x = 0; x < emacNUM_TX_BUFFERS; x++ )\r
343         {\r
344                 pxDescriptor = &( xTxDescriptors[ x ] );\r
345                 \r
346                 /* A buffer is not allocated to the Tx descriptor until a send is\r
347                 actually required. */\r
348                 pxDescriptor->data = NULL;\r
349                 pxDescriptor->length = 0;\r
350                 pxDescriptor->status = TX_BD_TC;\r
351                 pxDescriptor->ebd_status = TX_BD_INT;\r
352         }\r
353 \r
354         /* The last descriptor points back to the start. */\r
355         pxDescriptor->status |= TX_BD_W;\r
356         \r
357         /* Use the first Rx descriptor to start with. */\r
358         ulRxDescriptorIndex = 0UL;\r
359         pxCurrentRxDesc = &( xRxDescriptors[ 0 ] );\r
360 }\r
361 /*-----------------------------------------------------------*/\r
362 \r
363 void vEMACWrite( void )\r
364 {\r
365 long x;\r
366 \r
367         /* Wait until the second transmission of the last packet has completed. */\r
368         for( x = 0; x < emacTX_WAIT_ATTEMPTS; x++ )\r
369         {\r
370                 if( ( xTxDescriptors[ 1 ].status & TX_BD_R ) != 0 )\r
371                 {\r
372                         /* Descriptor is still active. */\r
373                         vTaskDelay( emacTX_WAIT_DELAY_ms );\r
374                 }\r
375                 else\r
376                 {\r
377                         break;\r
378                 }\r
379         }\r
380         \r
381         /* Is the descriptor free after waiting for it? */\r
382         if( ( xTxDescriptors[ 1 ].status & TX_BD_R ) != 0 )\r
383         {\r
384                 /* Something has gone wrong. */\r
385                 prvResetEverything();\r
386         }\r
387         \r
388         /* Setup both descriptors to transmit the frame. */\r
389         xTxDescriptors[ 0 ].data = ( uint8_t * ) __REV( ( unsigned long ) uip_buf );\r
390         xTxDescriptors[ 0 ].length = __REVSH( uip_len );\r
391         xTxDescriptors[ 1 ].data = ( uint8_t * ) __REV( ( unsigned long ) uip_buf );\r
392         xTxDescriptors[ 1 ].length = __REVSH( uip_len );\r
393 \r
394         /* uip_buf is being sent by the Tx descriptor.  Allocate a new buffer\r
395         for use by the stack. */\r
396         uip_buf = prvGetNextBuffer();\r
397 \r
398         /* Clear previous settings and go. */\r
399         xTxDescriptors[ 0 ].status |= ( TX_BD_R | TX_BD_L );\r
400         xTxDescriptors[ 1 ].status |= ( TX_BD_R | TX_BD_L );\r
401 \r
402         /* Start the Tx. */\r
403         ENET_TDAR = ENET_TDAR_TDAR_MASK;\r
404 }\r
405 /*-----------------------------------------------------------*/\r
406 \r
407 static unsigned char *prvGetNextBuffer( void )\r
408 {\r
409 long x;\r
410 unsigned char *pucReturn = NULL;\r
411 unsigned long ulAttempts = 0;\r
412 \r
413         while( pucReturn == NULL )\r
414         {\r
415                 /* Look through the buffers to find one that is not in use by\r
416                 anything else. */\r
417                 for( x = 0; x < emacNUM_BUFFERS; x++ )\r
418                 {\r
419                         if( ucBufferInUse[ x ] == pdFALSE )\r
420                         {\r
421                                 ucBufferInUse[ x ] = pdTRUE;\r
422                                 pucReturn = ( unsigned char * ) &( xEthernetBuffers[ x ][ 0 ] );\r
423                                 break;\r
424                         }\r
425                 }\r
426 \r
427                 /* Was a buffer found? */\r
428                 if( pucReturn == NULL )\r
429                 {\r
430                         ulAttempts++;\r
431 \r
432                         if( ulAttempts >= emacBUFFER_WAIT_ATTEMPTS )\r
433                         {\r
434                                 break;\r
435                         }\r
436 \r
437                         /* Wait then look again. */\r
438                         vTaskDelay( emacBUFFER_WAIT_DELAY_ms );\r
439                 }\r
440         }\r
441 \r
442         return pucReturn;\r
443 }\r
444 /*-----------------------------------------------------------*/\r
445 \r
446 static void prvResetEverything( void )\r
447 {\r
448         /* Temporary code just to see if this gets called.  This function has not\r
449         been implemented. */\r
450         portDISABLE_INTERRUPTS();\r
451         for( ;; );\r
452 }\r
453 /*-----------------------------------------------------------*/\r
454 \r
455 unsigned short usEMACRead( void )\r
456 {\r
457 unsigned short usBytesReceived;\r
458 \r
459         usBytesReceived = prvCheckRxStatus();\r
460         usBytesReceived = __REVSH( usBytesReceived );\r
461 \r
462         if( usBytesReceived > 0 )\r
463         {\r
464                 /* Mark the pxDescriptor buffer as free as uip_buf is going to be set to\r
465                 the buffer that contains the received data. */\r
466                 prvReturnBuffer( uip_buf );\r
467 \r
468                 /* Point uip_buf to the data about to be processed. */\r
469                 uip_buf = ( void * ) pxCurrentRxDesc->data;\r
470                 uip_buf = ( void * ) __REV( ( unsigned long ) uip_buf );\r
471                 \r
472                 /* Allocate a new buffer to the descriptor, as uip_buf is now using it's\r
473                 old descriptor. */\r
474                 pxCurrentRxDesc->data = ( uint8_t * ) prvGetNextBuffer();\r
475                 pxCurrentRxDesc->data = ( uint8_t* ) __REV( ( unsigned long ) pxCurrentRxDesc->data );\r
476 \r
477                 /* Prepare the descriptor to go again. */\r
478                 pxCurrentRxDesc->status |= RX_BD_E;\r
479 \r
480                 /* Move onto the next buffer in the ring. */\r
481                 ulRxDescriptorIndex++;\r
482                 if( ulRxDescriptorIndex >= emacNUM_RX_DESCRIPTORS )\r
483                 {\r
484                         ulRxDescriptorIndex = 0UL;\r
485                 }\r
486                 pxCurrentRxDesc = &( xRxDescriptors[ ulRxDescriptorIndex ] );\r
487                 \r
488                 /* Restart Ethernet if it has stopped */\r
489                 ENET_RDAR = ENET_RDAR_RDAR_MASK;\r
490         }\r
491 \r
492         return usBytesReceived;\r
493 }\r
494 /*-----------------------------------------------------------*/\r
495 \r
496 static void prvReturnBuffer( unsigned char *pucBuffer )\r
497 {\r
498 unsigned long ul;\r
499 \r
500         /* Return a buffer to the pool of free buffers. */\r
501         for( ul = 0; ul < emacNUM_BUFFERS; ul++ )\r
502         {\r
503                 if( &( xEthernetBuffers[ ul ][ 0 ] ) == ( void * ) pucBuffer )\r
504                 {\r
505                         ucBufferInUse[ ul ] = pdFALSE;\r
506                         break;\r
507                 }\r
508         }\r
509 }\r
510 /*-----------------------------------------------------------*/\r
511 \r
512 static unsigned short prvCheckRxStatus( void )\r
513 {\r
514 unsigned long usReturn = 0;\r
515 \r
516         if( ( pxCurrentRxDesc->status & RX_BD_E ) != 0 )\r
517         {\r
518                 /* Current descriptor is still active. */\r
519         }\r
520         else\r
521         {\r
522                 /* The descriptor contains a frame.  Because of the size of the buffers\r
523                 the frame should always be complete. */\r
524                 usReturn = pxCurrentRxDesc->length;\r
525         }\r
526         \r
527         return usReturn;\r
528 }\r
529 /*-----------------------------------------------------------*/\r
530 \r
531 void vEMAC_TxISRHandler( void )\r
532 {\r
533         /* Clear the interrupt. */\r
534         ENET_EIR = ENET_EIR_TXF_MASK;\r
535 \r
536         /* Check the buffers have not already been freed in the first of the\r
537         two Tx interrupts - which could potentially happen if the second Tx completed\r
538         during the interrupt for the first Tx. */\r
539         if( xTxDescriptors[ 0 ].data != NULL )\r
540         {\r
541                 if( ( ( xTxDescriptors[ 0 ].status & TX_BD_R ) == 0 ) && ( ( xTxDescriptors[ 0 ].status & TX_BD_R ) == 0 ) )\r
542                 {\r
543                         configASSERT( xTxDescriptors[ 0 ].data == xTxDescriptors[ 1 ].data );\r
544                         \r
545                         xTxDescriptors[ 0 ].data = ( uint8_t* ) __REV( ( unsigned long ) xTxDescriptors[ 0 ].data );\r
546                         prvReturnBuffer( xTxDescriptors[ 0 ].data );\r
547                         \r
548                         /* Just to mark the fact that the buffer has already been released. */\r
549                         xTxDescriptors[ 0 ].data = NULL;\r
550                 }\r
551         }\r
552 }\r
553 /*-----------------------------------------------------------*/\r
554 \r
555 void vEMAC_RxISRHandler( void )\r
556 {\r
557 const unsigned long ulRxEvent = uipETHERNET_RX_EVENT;\r
558 long lHigherPriorityTaskWoken = pdFALSE;\r
559 extern xQueueHandle xEMACEventQueue;\r
560 \r
561         /* Clear the interrupt. */\r
562         ENET_EIR = ENET_EIR_RXF_MASK;\r
563 \r
564         /* An Ethernet Rx event has occurred. */\r
565         xQueueSendFromISR( xEMACEventQueue, &ulRxEvent, &lHigherPriorityTaskWoken );\r
566         portEND_SWITCHING_ISR( lHigherPriorityTaskWoken );\r
567 }\r
568 /*-----------------------------------------------------------*/\r
569 \r
570 void vEMAC_ErrorISRHandler( void )\r
571 {\r
572         /* Clear the interrupt. */\r
573         ENET_EIR = ENET_EIR & ENET_EIMR;\r
574 \r
575         /* Attempt recovery.  Not very sophisticated. */\r
576         prvInitialiseDescriptors();\r
577         ENET_RDAR = ENET_RDAR_RDAR_MASK;\r
578 }\r
579 /*-----------------------------------------------------------*/\r
580 \r
581 \r