]> git.sur5r.net Git - freertos/blob - FreeRTOS/Demo/CORTEX_LPC1768_IAR/webserver/emac.c
b70b1947fe11822d37a4cbef447bb38b8cdb0026
[freertos] / FreeRTOS / Demo / CORTEX_LPC1768_IAR / webserver / emac.c
1 /*\r
2     FreeRTOS V7.4.0 - Copyright (C) 2013 Real Time Engineers Ltd.\r
3 \r
4     FEATURES AND PORTS ARE ADDED TO FREERTOS ALL THE TIME.  PLEASE VISIT\r
5     http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.\r
6 \r
7     ***************************************************************************\r
8      *                                                                       *\r
9      *    FreeRTOS tutorial books are available in pdf and paperback.        *\r
10      *    Complete, revised, and edited pdf reference manuals are also       *\r
11      *    available.                                                         *\r
12      *                                                                       *\r
13      *    Purchasing FreeRTOS documentation will not only help you, by       *\r
14      *    ensuring you get running as quickly as possible and with an        *\r
15      *    in-depth knowledge of how to use FreeRTOS, it will also help       *\r
16      *    the FreeRTOS project to continue with its mission of providing     *\r
17      *    professional grade, cross platform, de facto standard solutions    *\r
18      *    for microcontrollers - completely free of charge!                  *\r
19      *                                                                       *\r
20      *    >>> See http://www.FreeRTOS.org/Documentation for details. <<<     *\r
21      *                                                                       *\r
22      *    Thank you for using FreeRTOS, and thank you for your support!      *\r
23      *                                                                       *\r
24     ***************************************************************************\r
25 \r
26 \r
27     This file is part of the FreeRTOS distribution.\r
28 \r
29     FreeRTOS is free software; you can redistribute it and/or modify it under\r
30     the terms of the GNU General Public License (version 2) as published by the\r
31     Free Software Foundation AND MODIFIED BY the FreeRTOS exception.\r
32 \r
33     >>>>>>NOTE<<<<<< The modification to the GPL is included to allow you to\r
34     distribute a combined work that includes FreeRTOS without being obliged to\r
35     provide the source code for proprietary components outside of the FreeRTOS\r
36     kernel.\r
37 \r
38     FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY\r
39     WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS\r
40     FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more\r
41     details. You should have received a copy of the GNU General Public License\r
42     and the FreeRTOS license exception along with FreeRTOS; if not itcan be\r
43     viewed here: http://www.freertos.org/a00114.html and also obtained by\r
44     writing to Real Time Engineers Ltd., contact details for whom are available\r
45     on the FreeRTOS WEB site.\r
46 \r
47     1 tab == 4 spaces!\r
48 \r
49     ***************************************************************************\r
50      *                                                                       *\r
51      *    Having a problem?  Start by reading the FAQ "My application does   *\r
52      *    not run, what could be wrong?"                                     *\r
53      *                                                                       *\r
54      *    http://www.FreeRTOS.org/FAQHelp.html                               *\r
55      *                                                                       *\r
56     ***************************************************************************\r
57 \r
58 \r
59     http://www.FreeRTOS.org - Documentation, books, training, latest versions, \r
60     license and Real Time Engineers Ltd. contact details.\r
61 \r
62     http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,\r
63     including FreeRTOS+Trace - an indispensable productivity tool, and our new\r
64     fully thread aware and reentrant UDP/IP stack.\r
65 \r
66     http://www.OpenRTOS.com - Real Time Engineers ltd license FreeRTOS to High \r
67     Integrity Systems, who sell the code with commercial support, \r
68     indemnification and middleware, under the OpenRTOS brand.\r
69     \r
70     http://www.SafeRTOS.com - High Integrity Systems also provide a safety \r
71     engineered and independently SIL3 certified version for use in safety and \r
72     mission critical applications that require provable dependability.\r
73 */\r
74 \r
75 /* Originally adapted from file written by Andreas Dannenberg.  Supplied with permission. */\r
76 \r
77 /* Kernel includes. */\r
78 #include "FreeRTOS.h"\r
79 #include "task.h"\r
80 #include "semphr.h"\r
81 \r
82 /* Hardware specific includes. */\r
83 #include "EthDev_LPC17xx.h"\r
84 \r
85 /* Time to wait between each inspection of the link status. */\r
86 #define emacWAIT_FOR_LINK_TO_ESTABLISH ( 500 / portTICK_RATE_MS )\r
87 \r
88 /* Short delay used in several places during the initialisation process. */\r
89 #define emacSHORT_DELAY                            ( 2 )\r
90 \r
91 /* Hardware specific bit definitions. */\r
92 #define emacLINK_ESTABLISHED            ( 0x0020)\r
93 #define emacFULL_DUPLEX_ENABLED         ( 0x0010 )\r
94 #define emac10BASE_T_MODE                       ( 0x0004 )\r
95 #define emacPINSEL2_VALUE                       ( 0x50150105 )\r
96 #define emacDIV_44                                      ( 0x28 )\r
97 \r
98 /* If no buffers are available, then wait this long before looking again.... */\r
99 #define emacBUFFER_WAIT_DELAY   ( 3 / portTICK_RATE_MS )\r
100 \r
101 /* ...and don't look more than this many times. */\r
102 #define emacBUFFER_WAIT_ATTEMPTS        ( 30 )\r
103 \r
104 /* Index to the Tx descriptor that is always used first for every Tx.  The second\r
105 descriptor is then used to re-send in order to speed up the uIP Tx process. */\r
106 #define emacTX_DESC_INDEX                       ( 0 )\r
107 \r
108 /*-----------------------------------------------------------*/\r
109 \r
110 /*\r
111  * Configure both the Rx and Tx descriptors during the init process.\r
112  */\r
113 static void prvInitDescriptors( void );\r
114 \r
115 /*\r
116  * Setup the IO and peripherals required for Ethernet communication.\r
117  */\r
118 static void prvSetupEMACHardware( void );\r
119 \r
120 /*\r
121  * Control the auto negotiate process.\r
122  */\r
123 static void prvConfigurePHY( void );\r
124 \r
125 /*\r
126  * Wait for a link to be established, then setup the PHY according to the link\r
127  * parameters.\r
128  */\r
129 static long prvSetupLinkStatus( void );\r
130 \r
131 /*\r
132  * Search the pool of buffers to find one that is free.  If a buffer is found\r
133  * mark it as in use before returning its address.\r
134  */\r
135 static unsigned char *prvGetNextBuffer( void );\r
136 \r
137 /*\r
138  * Return an allocated buffer to the pool of free buffers.\r
139  */\r
140 static void prvReturnBuffer( unsigned char *pucBuffer );\r
141 \r
142 /*\r
143  * Send lValue to the lPhyReg within the PHY.\r
144  */\r
145 static long prvWritePHY( long lPhyReg, long lValue );\r
146 \r
147 /*\r
148  * Read a value from ucPhyReg within the PHY.  *plStatus will be set to\r
149  * pdFALSE if there is an error.\r
150  */\r
151 static unsigned short prvReadPHY( unsigned char ucPhyReg, long *plStatus );\r
152 \r
153 /*-----------------------------------------------------------*/\r
154 \r
155 /* The semaphore used to wake the uIP task when data arrives. */\r
156 extern xSemaphoreHandle xEMACSemaphore;\r
157 \r
158 /* Each ucBufferInUse index corresponds to a position in the pool of buffers.\r
159 If the index contains a 1 then the buffer within pool is in use, if it\r
160 contains a 0 then the buffer is free. */\r
161 static unsigned char ucBufferInUse[ ETH_NUM_BUFFERS ] = { pdFALSE };\r
162 \r
163 /* The uip_buffer is not a fixed array, but instead gets pointed to the buffers\r
164 allocated within this file. */\r
165 unsigned char * uip_buf;\r
166 \r
167 /* Store the length of the data being sent so the data can be sent twice.  The\r
168 value will be set back to 0 once the data has been sent twice. */\r
169 static unsigned short usSendLen = 0;\r
170 \r
171 /*-----------------------------------------------------------*/\r
172 \r
173 long lEMACInit( void )\r
174 {\r
175 long lReturn = pdPASS;\r
176 unsigned long ulID1, ulID2;\r
177 \r
178         /* Reset peripherals, configure port pins and registers. */\r
179         prvSetupEMACHardware();\r
180 \r
181         /* Check the PHY part number is as expected. */\r
182         ulID1 = prvReadPHY( PHY_REG_IDR1, &lReturn );\r
183         ulID2 = prvReadPHY( PHY_REG_IDR2, &lReturn );\r
184         if( ( (ulID1 << 16UL ) | ( ulID2 & 0xFFFFUL ) ) == KS8721_ID )\r
185         {\r
186                 /* Set the Ethernet MAC Address registers */\r
187                 EMAC->SA0 = ( configMAC_ADDR0 << 8 ) | configMAC_ADDR1;\r
188                 EMAC->SA1 = ( configMAC_ADDR2 << 8 ) | configMAC_ADDR3;\r
189                 EMAC->SA2 = ( configMAC_ADDR4 << 8 ) | configMAC_ADDR5;\r
190 \r
191                 /* Initialize Tx and Rx DMA Descriptors */\r
192                 prvInitDescriptors();\r
193 \r
194                 /* Receive broadcast and perfect match packets */\r
195                 EMAC->RxFilterCtrl = RFC_UCAST_EN | RFC_BCAST_EN | RFC_PERFECT_EN;\r
196 \r
197                 /* Setup the PHY. */\r
198                 prvConfigurePHY();\r
199         }\r
200         else\r
201         {\r
202                 lReturn = pdFAIL;\r
203         }\r
204 \r
205         /* Check the link status. */\r
206         if( lReturn == pdPASS )\r
207         {\r
208                 lReturn = prvSetupLinkStatus();\r
209         }\r
210 \r
211         if( lReturn == pdPASS )\r
212         {\r
213                 /* Initialise uip_buf to ensure it points somewhere valid. */\r
214                 uip_buf = prvGetNextBuffer();\r
215 \r
216                 /* Reset all interrupts */\r
217                 EMAC->IntClear = ( INT_RX_OVERRUN | INT_RX_ERR | INT_RX_FIN | INT_RX_DONE | INT_TX_UNDERRUN | INT_TX_ERR | INT_TX_FIN | INT_TX_DONE | INT_SOFT_INT | INT_WAKEUP );\r
218 \r
219                 /* Enable receive and transmit mode of MAC Ethernet core */\r
220                 EMAC->Command |= ( CR_RX_EN | CR_TX_EN );\r
221                 EMAC->MAC1 |= MAC1_REC_EN;\r
222         }\r
223 \r
224         return lReturn;\r
225 }\r
226 /*-----------------------------------------------------------*/\r
227 \r
228 static unsigned char *prvGetNextBuffer( void )\r
229 {\r
230 long x;\r
231 unsigned char *pucReturn = NULL;\r
232 unsigned long ulAttempts = 0;\r
233 \r
234         while( pucReturn == NULL )\r
235         {\r
236                 /* Look through the buffers to find one that is not in use by\r
237                 anything else. */\r
238                 for( x = 0; x < ETH_NUM_BUFFERS; x++ )\r
239                 {\r
240                         if( ucBufferInUse[ x ] == pdFALSE )\r
241                         {\r
242                                 ucBufferInUse[ x ] = pdTRUE;\r
243                                 pucReturn = ( unsigned char * ) ETH_BUF( x );\r
244                                 break;\r
245                         }\r
246                 }\r
247 \r
248                 /* Was a buffer found? */\r
249                 if( pucReturn == NULL )\r
250                 {\r
251                         ulAttempts++;\r
252 \r
253                         if( ulAttempts >= emacBUFFER_WAIT_ATTEMPTS )\r
254                         {\r
255                                 break;\r
256                         }\r
257 \r
258                         /* Wait then look again. */\r
259                         vTaskDelay( emacBUFFER_WAIT_DELAY );\r
260                 }\r
261         }\r
262 \r
263         return pucReturn;\r
264 }\r
265 /*-----------------------------------------------------------*/\r
266 \r
267 static void prvInitDescriptors( void )\r
268 {\r
269 long x, lNextBuffer = 0;\r
270 \r
271         for( x = 0; x < NUM_RX_FRAG; x++ )\r
272         {\r
273                 /* Allocate the next Ethernet buffer to this descriptor. */\r
274                 RX_DESC_PACKET( x ) = ETH_BUF( lNextBuffer );\r
275                 RX_DESC_CTRL( x ) = RCTRL_INT | ( ETH_FRAG_SIZE - 1 );\r
276                 RX_STAT_INFO( x ) = 0;\r
277                 RX_STAT_HASHCRC( x ) = 0;\r
278 \r
279                 /* The Ethernet buffer is now in use. */\r
280                 ucBufferInUse[ lNextBuffer ] = pdTRUE;\r
281                 lNextBuffer++;\r
282         }\r
283 \r
284         /* Set EMAC Receive Descriptor Registers. */\r
285         EMAC->RxDescriptor = RX_DESC_BASE;\r
286         EMAC->RxStatus = RX_STAT_BASE;\r
287         EMAC->RxDescriptorNumber = NUM_RX_FRAG - 1;\r
288 \r
289         /* Rx Descriptors Point to 0 */\r
290         EMAC->RxConsumeIndex = 0;\r
291 \r
292         /* A buffer is not allocated to the Tx descriptors until they are actually\r
293         used. */\r
294         for( x = 0; x < NUM_TX_FRAG; x++ )\r
295         {\r
296                 TX_DESC_PACKET( x ) = ( unsigned long ) NULL;\r
297                 TX_DESC_CTRL( x ) = 0;\r
298                 TX_STAT_INFO( x ) = 0;\r
299         }\r
300 \r
301         /* Set EMAC Transmit Descriptor Registers. */\r
302         EMAC->TxDescriptor = TX_DESC_BASE;\r
303         EMAC->TxStatus = TX_STAT_BASE;\r
304         EMAC->TxDescriptorNumber = NUM_TX_FRAG - 1;\r
305 \r
306         /* Tx Descriptors Point to 0 */\r
307         EMAC->TxProduceIndex = 0;\r
308 }\r
309 /*-----------------------------------------------------------*/\r
310 \r
311 static void prvSetupEMACHardware( void )\r
312 {\r
313 unsigned short us;\r
314 long x, lDummy;\r
315 \r
316         /* Enable P1 Ethernet Pins. */\r
317         PINCON->PINSEL2 = emacPINSEL2_VALUE;\r
318         PINCON->PINSEL3 = ( PINCON->PINSEL3 & ~0x0000000F ) | 0x00000005;\r
319 \r
320         /* Power Up the EMAC controller. */\r
321         SC->PCONP |= PCONP_PCENET;\r
322         vTaskDelay( emacSHORT_DELAY );\r
323 \r
324         /* Reset all EMAC internal modules. */\r
325         EMAC->MAC1 = MAC1_RES_TX | MAC1_RES_MCS_TX | MAC1_RES_RX | MAC1_RES_MCS_RX | MAC1_SIM_RES | MAC1_SOFT_RES;\r
326         EMAC->Command = CR_REG_RES | CR_TX_RES | CR_RX_RES | CR_PASS_RUNT_FRM;\r
327 \r
328         /* A short delay after reset. */\r
329         vTaskDelay( emacSHORT_DELAY );\r
330 \r
331         /* Initialize MAC control registers. */\r
332         EMAC->MAC1 = MAC1_PASS_ALL;\r
333         EMAC->MAC2 = MAC2_CRC_EN | MAC2_PAD_EN;\r
334         EMAC->MAXF = ETH_MAX_FLEN;\r
335         EMAC->CLRT = CLRT_DEF;\r
336         EMAC->IPGR = IPGR_DEF;\r
337         EMAC->MCFG = emacDIV_44;\r
338 \r
339         /* Enable Reduced MII interface. */\r
340         EMAC->Command = CR_RMII | CR_PASS_RUNT_FRM;\r
341 \r
342         /* Reset Reduced MII Logic. */\r
343         EMAC->SUPP = SUPP_RES_RMII;\r
344         vTaskDelay( emacSHORT_DELAY );\r
345         EMAC->SUPP = 0;\r
346 \r
347         /* Put the PHY in reset mode */\r
348         prvWritePHY( PHY_REG_BMCR, MCFG_RES_MII );\r
349         prvWritePHY( PHY_REG_BMCR, MCFG_RES_MII );\r
350 \r
351         /* Wait for hardware reset to end. */\r
352         for( x = 0; x < 100; x++ )\r
353         {\r
354                 vTaskDelay( emacSHORT_DELAY * 5 );\r
355                 us = prvReadPHY( PHY_REG_BMCR, &lDummy );\r
356                 if( !( us & MCFG_RES_MII ) )\r
357                 {\r
358                         /* Reset complete */\r
359                         break;\r
360                 }\r
361         }\r
362 }\r
363 /*-----------------------------------------------------------*/\r
364 \r
365 static void prvConfigurePHY( void )\r
366 {\r
367 unsigned short us;\r
368 long x, lDummy;\r
369 \r
370         /* Auto negotiate the configuration. */\r
371         if( prvWritePHY( PHY_REG_BMCR, PHY_AUTO_NEG ) )\r
372         {\r
373                 vTaskDelay( emacSHORT_DELAY * 5 );\r
374 \r
375                 for( x = 0; x < 10; x++ )\r
376                 {\r
377                         us = prvReadPHY( PHY_REG_BMSR, &lDummy );\r
378 \r
379                         if( us & PHY_AUTO_NEG_COMPLETE )\r
380                         {\r
381                                 break;\r
382                         }\r
383 \r
384                         vTaskDelay( emacWAIT_FOR_LINK_TO_ESTABLISH );\r
385                 }\r
386         }\r
387 }\r
388 /*-----------------------------------------------------------*/\r
389 \r
390 static long prvSetupLinkStatus( void )\r
391 {\r
392 long lReturn = pdFAIL, x;\r
393 unsigned short usLinkStatus;\r
394 \r
395         /* Wait with timeout for the link to be established. */\r
396         for( x = 0; x < 10; x++ )\r
397         {\r
398                 usLinkStatus = prvReadPHY( PHY_CTRLER, &lReturn );\r
399                 if( usLinkStatus != 0x00 )\r
400                 {\r
401                         /* Link is established. */\r
402                         lReturn = pdPASS;\r
403                         break;\r
404                 }\r
405 \r
406         vTaskDelay( emacWAIT_FOR_LINK_TO_ESTABLISH );\r
407         }\r
408 \r
409         if( lReturn == pdPASS )\r
410         {\r
411                 /* Configure Full/Half Duplex mode. */\r
412                 if( usLinkStatus & emacFULL_DUPLEX_ENABLED )\r
413                 {\r
414                         /* Full duplex is enabled. */\r
415                         EMAC->MAC2 |= MAC2_FULL_DUP;\r
416                         EMAC->Command |= CR_FULL_DUP;\r
417                         EMAC->IPGT = IPGT_FULL_DUP;\r
418                 }\r
419                 else\r
420                 {\r
421                         /* Half duplex mode. */\r
422                         EMAC->IPGT = IPGT_HALF_DUP;\r
423                 }\r
424 \r
425                 /* Configure 100MBit/10MBit mode. */\r
426                 if( usLinkStatus & emac10BASE_T_MODE )\r
427                 {\r
428                         /* 10MBit mode. */\r
429                         EMAC->SUPP = 0;\r
430                 }\r
431                 else\r
432                 {\r
433                         /* 100MBit mode. */\r
434                         EMAC->SUPP = SUPP_SPEED;\r
435                 }\r
436         }\r
437 \r
438         return lReturn;\r
439 }\r
440 /*-----------------------------------------------------------*/\r
441 \r
442 static void prvReturnBuffer( unsigned char *pucBuffer )\r
443 {\r
444 unsigned long ul;\r
445 \r
446         /* Return a buffer to the pool of free buffers. */\r
447         for( ul = 0; ul < ETH_NUM_BUFFERS; ul++ )\r
448         {\r
449                 if( ETH_BUF( ul ) == ( unsigned long ) pucBuffer )\r
450                 {\r
451                         ucBufferInUse[ ul ] = pdFALSE;\r
452                         break;\r
453                 }\r
454         }\r
455 }\r
456 /*-----------------------------------------------------------*/\r
457 \r
458 unsigned long ulGetEMACRxData( void )\r
459 {\r
460 unsigned long ulLen = 0;\r
461 long lIndex;\r
462 \r
463         if( EMAC->RxProduceIndex != EMAC->RxConsumeIndex )\r
464         {\r
465                 /* Mark the current buffer as free as uip_buf is going to be set to\r
466                 the buffer that contains the received data. */\r
467                 prvReturnBuffer( uip_buf );\r
468 \r
469                 ulLen = ( RX_STAT_INFO( EMAC->RxConsumeIndex ) & RINFO_SIZE ) - 3;\r
470                 uip_buf = ( unsigned char * ) RX_DESC_PACKET( EMAC->RxConsumeIndex );\r
471 \r
472                 /* Allocate a new buffer to the descriptor. */\r
473         RX_DESC_PACKET( EMAC->RxConsumeIndex ) = ( unsigned long ) prvGetNextBuffer();\r
474 \r
475                 /* Move the consume index onto the next position, ensuring it wraps to\r
476                 the beginning at the appropriate place. */\r
477                 lIndex = EMAC->RxConsumeIndex;\r
478 \r
479                 lIndex++;\r
480                 if( lIndex >= NUM_RX_FRAG )\r
481                 {\r
482                         lIndex = 0;\r
483                 }\r
484 \r
485                 EMAC->RxConsumeIndex = lIndex;\r
486         }\r
487 \r
488         return ulLen;\r
489 }\r
490 /*-----------------------------------------------------------*/\r
491 \r
492 void vSendEMACTxData( unsigned short usTxDataLen )\r
493 {\r
494 unsigned long ulAttempts = 0UL;\r
495 \r
496         /* Check to see if the Tx descriptor is free, indicated by its buffer being\r
497         NULL. */\r
498         while( TX_DESC_PACKET( emacTX_DESC_INDEX ) != ( unsigned long ) NULL )\r
499         {\r
500                 /* Wait for the Tx descriptor to become available. */\r
501                 vTaskDelay( emacBUFFER_WAIT_DELAY );\r
502 \r
503                 ulAttempts++;\r
504                 if( ulAttempts > emacBUFFER_WAIT_ATTEMPTS )\r
505                 {\r
506                         /* Something has gone wrong as the Tx descriptor is still in use.\r
507                         Clear it down manually, the data it was sending will probably be\r
508                         lost. */\r
509                         prvReturnBuffer( ( unsigned char * ) TX_DESC_PACKET( emacTX_DESC_INDEX ) );\r
510                         break;\r
511                 }\r
512         }\r
513 \r
514         /* Setup the Tx descriptor for transmission.  Remember the length of the\r
515         data being sent so the second descriptor can be used to send it again from\r
516         within the ISR. */\r
517         usSendLen = usTxDataLen;\r
518         TX_DESC_PACKET( emacTX_DESC_INDEX ) = ( unsigned long ) uip_buf;\r
519         TX_DESC_CTRL( emacTX_DESC_INDEX ) = ( usTxDataLen | TCTRL_LAST | TCTRL_INT );\r
520         EMAC->TxProduceIndex = ( emacTX_DESC_INDEX + 1 );\r
521 \r
522         /* uip_buf is being sent by the Tx descriptor.  Allocate a new buffer. */\r
523         uip_buf = prvGetNextBuffer();\r
524 }\r
525 /*-----------------------------------------------------------*/\r
526 \r
527 static long prvWritePHY( long lPhyReg, long lValue )\r
528 {\r
529 const long lMaxTime = 10;\r
530 long x;\r
531 \r
532         EMAC->MADR = KS8721_DEF_ADR | lPhyReg;\r
533         EMAC->MWTD = lValue;\r
534 \r
535         x = 0;\r
536         for( x = 0; x < lMaxTime; x++ )\r
537         {\r
538                 if( ( EMAC->MIND & MIND_BUSY ) == 0 )\r
539                 {\r
540                         /* Operation has finished. */\r
541                         break;\r
542                 }\r
543 \r
544                 vTaskDelay( emacSHORT_DELAY );\r
545         }\r
546 \r
547         if( x < lMaxTime )\r
548         {\r
549                 return pdPASS;\r
550         }\r
551         else\r
552         {\r
553                 return pdFAIL;\r
554         }\r
555 }\r
556 /*-----------------------------------------------------------*/\r
557 \r
558 static unsigned short prvReadPHY( unsigned char ucPhyReg, long *plStatus )\r
559 {\r
560 long x;\r
561 const long lMaxTime = 10;\r
562 \r
563         EMAC->MADR = KS8721_DEF_ADR | ucPhyReg;\r
564         EMAC->MCMD = MCMD_READ;\r
565 \r
566         for( x = 0; x < lMaxTime; x++ )\r
567         {\r
568                 /* Operation has finished. */\r
569                 if( ( EMAC->MIND & MIND_BUSY ) == 0 )\r
570                 {\r
571                         break;\r
572                 }\r
573 \r
574                 vTaskDelay( emacSHORT_DELAY );\r
575         }\r
576 \r
577         EMAC->MCMD = 0;\r
578 \r
579         if( x >= lMaxTime )\r
580         {\r
581                 *plStatus = pdFAIL;\r
582         }\r
583 \r
584         return( EMAC->MRDD );\r
585 }\r
586 /*-----------------------------------------------------------*/\r
587 \r
588 void vEMAC_ISR( void )\r
589 {\r
590 unsigned long ulStatus;\r
591 long lHigherPriorityTaskWoken = pdFALSE;\r
592 \r
593         ulStatus = EMAC->IntStatus;\r
594 \r
595         /* Clear the interrupt. */\r
596         EMAC->IntClear = ulStatus;\r
597 \r
598         if( ulStatus & INT_RX_DONE )\r
599         {\r
600                 /* Ensure the uIP task is not blocked as data has arrived. */\r
601                 xSemaphoreGiveFromISR( xEMACSemaphore, &lHigherPriorityTaskWoken );\r
602         }\r
603 \r
604         if( ulStatus & INT_TX_DONE )\r
605         {\r
606                 if( usSendLen > 0 )\r
607                 {\r
608                         /* Send the data again, using the second descriptor.  As there are\r
609                         only two descriptors the index is set back to 0. */\r
610                         TX_DESC_PACKET( ( emacTX_DESC_INDEX + 1 ) ) = TX_DESC_PACKET( emacTX_DESC_INDEX );\r
611                         TX_DESC_CTRL( ( emacTX_DESC_INDEX + 1 ) ) = ( usSendLen | TCTRL_LAST | TCTRL_INT );\r
612                         EMAC->TxProduceIndex = ( emacTX_DESC_INDEX );\r
613 \r
614                         /* This is the second Tx so set usSendLen to 0 to indicate that the\r
615                         Tx descriptors will be free again. */\r
616                         usSendLen = 0UL;\r
617                 }\r
618                 else\r
619                 {\r
620                         /* The Tx buffer is no longer required. */\r
621                         prvReturnBuffer( ( unsigned char * ) TX_DESC_PACKET( emacTX_DESC_INDEX ) );\r
622             TX_DESC_PACKET( emacTX_DESC_INDEX ) = ( unsigned long ) NULL;\r
623                 }\r
624         }\r
625 \r
626         portEND_SWITCHING_ISR( lHigherPriorityTaskWoken );\r
627 }\r