]> git.sur5r.net Git - freertos/blob - FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/STM32Fxx/NetworkInterface.c
Added +TCP code to main repo.
[freertos] / FreeRTOS-Plus / Source / FreeRTOS-Plus-TCP / portable / NetworkInterface / STM32Fxx / NetworkInterface.c
1 /*\r
2  * Some constants, hardware definitions and comments taken from ST's HAL driver\r
3  * library, COPYRIGHT(c) 2015 STMicroelectronics.\r
4  */\r
5 \r
6 /*\r
7  * FreeRTOS+TCP Labs Build 160919 (C) 2016 Real Time Engineers ltd.\r
8  * Authors include Hein Tibosch and Richard Barry\r
9  *\r
10  *******************************************************************************\r
11  ***** NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ***\r
12  ***                                                                         ***\r
13  ***                                                                         ***\r
14  ***   FREERTOS+TCP IS STILL IN THE LAB (mainly because the FTP and HTTP     ***\r
15  ***   demos have a dependency on FreeRTOS+FAT, which is only in the Labs    ***\r
16  ***   download):                                                            ***\r
17  ***                                                                         ***\r
18  ***   FreeRTOS+TCP is functional and has been used in commercial products   ***\r
19  ***   for some time.  Be aware however that we are still refining its       ***\r
20  ***   design, the source code does not yet quite conform to the strict      ***\r
21  ***   coding and style standards mandated by Real Time Engineers ltd., and  ***\r
22  ***   the documentation and testing is not necessarily complete.            ***\r
23  ***                                                                         ***\r
24  ***   PLEASE REPORT EXPERIENCES USING THE SUPPORT RESOURCES FOUND ON THE    ***\r
25  ***   URL: http://www.FreeRTOS.org/contact  Active early adopters may, at   ***\r
26  ***   the sole discretion of Real Time Engineers Ltd., be offered versions  ***\r
27  ***   under a license other than that described below.                      ***\r
28  ***                                                                         ***\r
29  ***                                                                         ***\r
30  ***** NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ***\r
31  *******************************************************************************\r
32  *\r
33  * FreeRTOS+TCP can be used under two different free open source licenses.  The\r
34  * license that applies is dependent on the processor on which FreeRTOS+TCP is\r
35  * executed, as follows:\r
36  *\r
37  * If FreeRTOS+TCP is executed on one of the processors listed under the Special\r
38  * License Arrangements heading of the FreeRTOS+TCP license information web\r
39  * page, then it can be used under the terms of the FreeRTOS Open Source\r
40  * License.  If FreeRTOS+TCP is used on any other processor, then it can be used\r
41  * under the terms of the GNU General Public License V2.  Links to the relevant\r
42  * licenses follow:\r
43  *\r
44  * The FreeRTOS+TCP License Information Page: http://www.FreeRTOS.org/tcp_license\r
45  * The FreeRTOS Open Source License: http://www.FreeRTOS.org/license\r
46  * The GNU General Public License Version 2: http://www.FreeRTOS.org/gpl-2.0.txt\r
47  *\r
48  * FreeRTOS+TCP is distributed in the hope that it will be useful.  You cannot\r
49  * use FreeRTOS+TCP unless you agree that you use the software 'as is'.\r
50  * FreeRTOS+TCP is provided WITHOUT ANY WARRANTY; without even the implied\r
51  * warranties of NON-INFRINGEMENT, MERCHANTABILITY or FITNESS FOR A PARTICULAR\r
52  * PURPOSE. Real Time Engineers Ltd. disclaims all conditions and terms, be they\r
53  * implied, expressed, or statutory.\r
54  *\r
55  * 1 tab == 4 spaces!\r
56  *\r
57  * http://www.FreeRTOS.org\r
58  * http://www.FreeRTOS.org/plus\r
59  * http://www.FreeRTOS.org/labs\r
60  *\r
61  */\r
62 \r
63 /* Standard includes. */\r
64 #include <stdint.h>\r
65 #include <stdio.h>\r
66 #include <stdlib.h>\r
67 \r
68 /* FreeRTOS includes. */\r
69 #include "FreeRTOS.h"\r
70 #include "task.h"\r
71 #include "queue.h"\r
72 #include "semphr.h"\r
73 \r
74 /* FreeRTOS+TCP includes. */\r
75 #include "FreeRTOS_IP.h"\r
76 #include "FreeRTOS_Sockets.h"\r
77 #include "FreeRTOS_IP_Private.h"\r
78 #include "FreeRTOS_DNS.h"\r
79 #include "NetworkBufferManagement.h"\r
80 #include "NetworkInterface.h"\r
81 \r
82 /* ST includes. */\r
83 #include "stm32f4xx_hal.h"\r
84 \r
85 #ifndef BMSR_LINK_STATUS\r
86         #define BMSR_LINK_STATUS            0x0004UL\r
87 #endif\r
88 \r
89 #ifndef PHY_LS_HIGH_CHECK_TIME_MS\r
90         /* Check if the LinkSStatus in the PHY is still high after 15 seconds of not\r
91         receiving packets. */\r
92         #define PHY_LS_HIGH_CHECK_TIME_MS       15000\r
93 #endif\r
94 \r
95 #ifndef PHY_LS_LOW_CHECK_TIME_MS\r
96         /* Check if the LinkSStatus in the PHY is still low every second. */\r
97         #define PHY_LS_LOW_CHECK_TIME_MS        1000\r
98 #endif\r
99 \r
100 /* Interrupt events to process.  Currently only the Rx event is processed\r
101 although code for other events is included to allow for possible future\r
102 expansion. */\r
103 #define EMAC_IF_RX_EVENT        1UL\r
104 #define EMAC_IF_TX_EVENT        2UL\r
105 #define EMAC_IF_ERR_EVENT       4UL\r
106 #define EMAC_IF_ALL_EVENT       ( EMAC_IF_RX_EVENT | EMAC_IF_TX_EVENT | EMAC_IF_ERR_EVENT )\r
107 \r
108 #define ETH_DMA_ALL_INTS \\r
109         ( ETH_DMA_IT_TST | ETH_DMA_IT_PMT | ETH_DMA_IT_MMC | ETH_DMA_IT_NIS | ETH_DMA_IT_ER | \\r
110           ETH_DMA_IT_FBE | ETH_DMA_IT_RWT | ETH_DMA_IT_RPS | ETH_DMA_IT_RBU | ETH_DMA_IT_R | \\r
111           ETH_DMA_IT_TU | ETH_DMA_IT_RO | ETH_DMA_IT_TJT | ETH_DMA_IT_TPS | ETH_DMA_IT_T )\r
112 \r
113 /* Naming and numbering of PHY registers. */\r
114 #define PHY_REG_00_BMCR                 0x00    /* Basic Mode Control Register. */\r
115 #define PHY_REG_01_BMSR                 0x01    /* Basic Mode Status Register. */\r
116 #define PHY_REG_02_PHYSID1              0x02    /* PHYS ID 1 */\r
117 #define PHY_REG_03_PHYSID2              0x03    /* PHYS ID 2 */\r
118 #define PHY_REG_04_ADVERTISE    0x04    /* Advertisement control reg */\r
119 \r
120 #define PHY_ID_LAN8720          0x0007c0f0\r
121 #define PHY_ID_DP83848I         0x20005C90\r
122 \r
123 #ifndef USE_STM324xG_EVAL\r
124         #define USE_STM324xG_EVAL       1\r
125 #endif\r
126 \r
127 #if( USE_STM324xG_EVAL == 0 )\r
128         #define EXPECTED_PHY_ID                 PHY_ID_LAN8720\r
129         #define PHY_REG_1F_PHYSPCS              0x1F    /* 31 RW PHY Special Control Status */\r
130         /* Use 3 bits in register 31 */\r
131         #define PHYSPCS_SPEED_MASK              0x0C\r
132         #define PHYSPCS_SPEED_10                0x04\r
133         #define PHYSPCS_SPEED_100               0x08\r
134         #define PHYSPCS_FULL_DUPLEX             0x10\r
135 #else\r
136         #define EXPECTED_PHY_ID         PHY_ID_DP83848I\r
137 \r
138         #define PHY_REG_10_PHY_SR               0x10    /* PHY status register Offset */\r
139         #define PHY_REG_19_PHYCR                0x19    /* 25 RW PHY Control Register */\r
140 #endif\r
141 \r
142 /* Some defines used internally here to indicate preferences about speed, MDIX\r
143 (wired direct or crossed), and duplex (half or full). */\r
144 #define PHY_SPEED_10       1\r
145 #define PHY_SPEED_100      2\r
146 #define PHY_SPEED_AUTO     (PHY_SPEED_10|PHY_SPEED_100)\r
147 \r
148 #define PHY_MDIX_DIRECT    1\r
149 #define PHY_MDIX_CROSSED   2\r
150 #define PHY_MDIX_AUTO      (PHY_MDIX_CROSSED|PHY_MDIX_DIRECT)\r
151 \r
152 #define PHY_DUPLEX_HALF    1\r
153 #define PHY_DUPLEX_FULL    2\r
154 #define PHY_DUPLEX_AUTO    (PHY_DUPLEX_FULL|PHY_DUPLEX_HALF)\r
155 \r
156 #define PHY_AUTONEGO_COMPLETE    ((uint16_t)0x0020)  /*!< Auto-Negotiation process completed   */\r
157 \r
158 /*\r
159  * Description of all capabilities that can be advertised to\r
160  * the peer (usually a switch or router).\r
161  */\r
162 #define ADVERTISE_CSMA                  0x0001          /* Only selector supported. */\r
163 #define ADVERTISE_10HALF                0x0020          /* Try for 10mbps half-duplex. */\r
164 #define ADVERTISE_10FULL                0x0040          /* Try for 10mbps full-duplex. */\r
165 #define ADVERTISE_100HALF               0x0080          /* Try for 100mbps half-duplex. */\r
166 #define ADVERTISE_100FULL               0x0100          /* Try for 100mbps full-duplex. */\r
167 \r
168 #define ADVERTISE_ALL                   ( ADVERTISE_10HALF | ADVERTISE_10FULL | \\r
169                                                                   ADVERTISE_100HALF | ADVERTISE_100FULL)\r
170 \r
171 /*\r
172  * Value for the 'PHY_REG_00_BMCR', the PHY's Basic Mode Control Register.\r
173  */\r
174 #define BMCR_FULLDPLX                   0x0100          /* Full duplex. */\r
175 #define BMCR_ANRESTART                  0x0200          /* Auto negotiation restart. */\r
176 #define BMCR_ANENABLE                   0x1000          /* Enable auto negotiation. */\r
177 #define BMCR_SPEED100                   0x2000          /* Select 100Mbps. */\r
178 #define BMCR_RESET                              0x8000          /* Reset the PHY. */\r
179 \r
180 #define PHYCR_MDIX_EN                   0x8000          /* Enable Auto MDIX. */\r
181 #define PHYCR_MDIX_FORCE                0x4000          /* Force MDIX crossed. */\r
182 \r
183 #define ipFRAGMENT_OFFSET_BIT_MASK              ( ( uint16_t ) 0x0fff ) /* The bits in the two byte IP header field that make up the fragment offset value. */\r
184 \r
185 /*\r
186  * Most users will want a PHY that negotiates about\r
187  * the connection properties: speed, dmix and duplex.\r
188  * On some rare cases, you want to select what is being\r
189  * advertised, properties like MDIX and duplex.\r
190  */\r
191 \r
192 #if !defined( ipconfigETHERNET_AN_ENABLE )\r
193         /* Enable auto-negotiation */\r
194         #define ipconfigETHERNET_AN_ENABLE                              1\r
195 #endif\r
196 \r
197 #if !defined( ipconfigETHERNET_AUTO_CROSS_ENABLE )\r
198         #define ipconfigETHERNET_AUTO_CROSS_ENABLE              1\r
199 #endif\r
200 \r
201 #if( ipconfigETHERNET_AN_ENABLE == 0 )\r
202         /*\r
203          * The following three defines are only used in case there\r
204          * is no auto-negotiation.\r
205          */\r
206         #if !defined( ipconfigETHERNET_CROSSED_LINK )\r
207                 #define ipconfigETHERNET_CROSSED_LINK                   1\r
208         #endif\r
209 \r
210         #if !defined( ipconfigETHERNET_USE_100MB )\r
211                 #define ipconfigETHERNET_USE_100MB                              1\r
212         #endif\r
213 \r
214         #if !defined( ipconfigETHERNET_USE_FULL_DUPLEX )\r
215                 #define ipconfigETHERNET_USE_FULL_DUPLEX                1\r
216         #endif\r
217 #endif /* ipconfigETHERNET_AN_ENABLE == 0 */\r
218 \r
219 /* Default the size of the stack used by the EMAC deferred handler task to twice\r
220 the size of the stack used by the idle task - but allow this to be overridden in\r
221 FreeRTOSConfig.h as configMINIMAL_STACK_SIZE is a user definable constant. */\r
222 #ifndef configEMAC_TASK_STACK_SIZE\r
223         #define configEMAC_TASK_STACK_SIZE ( 2 * configMINIMAL_STACK_SIZE )\r
224 #endif\r
225 \r
226 /*-----------------------------------------------------------*/\r
227 \r
228 /*\r
229  * A deferred interrupt handler task that processes\r
230  */\r
231 static void prvEMACHandlerTask( void *pvParameters );\r
232 \r
233 /*\r
234  * Force a negotiation with the Switch or Router and wait for LS.\r
235  */\r
236 static void prvEthernetUpdateConfig( BaseType_t xForce );\r
237 \r
238 /*\r
239  * See if there is a new packet and forward it to the IP-task.\r
240  */\r
241 static BaseType_t prvNetworkInterfaceInput( void );\r
242 \r
243 #if( ipconfigUSE_LLMNR != 0 )\r
244         /*\r
245          * For LLMNR, an extra MAC-address must be configured to\r
246          * be able to receive the multicast messages.\r
247          */\r
248         static void prvMACAddressConfig(ETH_HandleTypeDef *heth, uint32_t ulIndex, uint8_t *Addr);\r
249 #endif\r
250 \r
251 /*\r
252  * Check if a given packet should be accepted.\r
253  */\r
254 static BaseType_t xMayAcceptPacket( uint8_t *pcBuffer );\r
255 \r
256 /*\r
257  * Initialise the TX descriptors.\r
258  */\r
259 static void prvDMATxDescListInit( void );\r
260 \r
261 /*\r
262  * Initialise the RX descriptors.\r
263  */\r
264 static void prvDMARxDescListInit( void );\r
265 \r
266 #if( ipconfigZERO_COPY_TX_DRIVER != 0 )\r
267         /* After packets have been sent, the network\r
268         buffers will be released. */\r
269         static void vClearTXBuffers( void );\r
270 #endif /* ipconfigZERO_COPY_TX_DRIVER */\r
271 \r
272 /*-----------------------------------------------------------*/\r
273 \r
274 typedef struct _PhyProperties_t\r
275 {\r
276         uint8_t speed;\r
277         uint8_t mdix;\r
278         uint8_t duplex;\r
279         uint8_t spare;\r
280 } PhyProperties_t;\r
281 \r
282 /* Bit map of outstanding ETH interrupt events for processing.  Currently only\r
283 the Rx interrupt is handled, although code is included for other events to\r
284 enable future expansion. */\r
285 static volatile uint32_t ulISREvents;\r
286 \r
287 /* A copy of PHY register 1: 'PHY_REG_01_BMSR' */\r
288 static uint32_t ulPHYLinkStatus = 0;\r
289 \r
290 #if( ipconfigUSE_LLMNR == 1 )\r
291         static const uint8_t xLLMNR_MACAddress[] = { 0x01, 0x00, 0x5E, 0x00, 0x00, 0xFC };\r
292 #endif\r
293 \r
294 /* Ethernet handle. */\r
295 static ETH_HandleTypeDef xETH;\r
296 \r
297 #if( ipconfigZERO_COPY_TX_DRIVER != 0 )\r
298         /* xTXDescriptorSemaphore is a counting semaphore with\r
299         a maximum count of ETH_TXBUFNB, which is the number of\r
300         DMA TX descriptors. */\r
301         static SemaphoreHandle_t xTXDescriptorSemaphore = NULL;\r
302 #endif /* ipconfigZERO_COPY_TX_DRIVER */\r
303 \r
304 /*\r
305  * Note: it is adviced to define both\r
306  *\r
307  *     #define  ipconfigZERO_COPY_RX_DRIVER   1\r
308  *     #define  ipconfigZERO_COPY_TX_DRIVER   1\r
309  *\r
310  * The method using memcpy is slower and probaly uses more RAM memory.\r
311  * The possibility is left in the code just for comparison.\r
312  *\r
313  * It is adviced to define ETH_TXBUFNB at least 4. Note that no\r
314  * TX buffers are allocated in a zero-copy driver.\r
315  */\r
316 /* MAC buffers: ---------------------------------------------------------*/\r
317 __ALIGN_BEGIN ETH_DMADescTypeDef  DMARxDscrTab[ ETH_RXBUFNB ] __ALIGN_END;/* Ethernet Rx MA Descriptor */\r
318 #if( ipconfigZERO_COPY_RX_DRIVER == 0 )\r
319         __ALIGN_BEGIN uint8_t Rx_Buff[ ETH_RXBUFNB ][ ETH_RX_BUF_SIZE ] __ALIGN_END; /* Ethernet Receive Buffer */\r
320 #endif\r
321 \r
322 __ALIGN_BEGIN ETH_DMADescTypeDef  DMATxDscrTab[ ETH_TXBUFNB ] __ALIGN_END;/* Ethernet Tx DMA Descriptor */\r
323 #if( ipconfigZERO_COPY_TX_DRIVER == 0 )\r
324         __ALIGN_BEGIN uint8_t Tx_Buff[ ETH_TXBUFNB ][ ETH_TX_BUF_SIZE ] __ALIGN_END; /* Ethernet Transmit Buffer */\r
325 #endif\r
326 \r
327 #if( ipconfigZERO_COPY_TX_DRIVER != 0 )\r
328         /* DMATxDescToClear points to the next TX DMA descriptor\r
329         that must be cleared by vClearTXBuffers(). */\r
330         static __IO ETH_DMADescTypeDef  *DMATxDescToClear;\r
331 #endif\r
332 \r
333 /* Value to be written into the 'Basic mode Control Register'. */\r
334 static uint32_t ulBCRvalue;\r
335 \r
336 /* Value to be written into the 'Advertisement Control Register'. */\r
337 static uint32_t ulACRValue;\r
338 \r
339 /* ucMACAddress as it appears in main.c */\r
340 extern const uint8_t ucMACAddress[ 6 ];\r
341 \r
342 /* Holds the handle of the task used as a deferred interrupt processor.  The\r
343 handle is used so direct notifications can be sent to the task for all EMAC/DMA\r
344 related interrupts. */\r
345 static TaskHandle_t xEMACTaskHandle = NULL;\r
346 \r
347 /* For local use only: describe the PHY's properties: */\r
348 const PhyProperties_t xPHYProperties =\r
349 {\r
350         #if( ipconfigETHERNET_AN_ENABLE != 0 )\r
351                 .speed = PHY_SPEED_AUTO,\r
352                 .duplex = PHY_DUPLEX_AUTO,\r
353         #else\r
354                 #if( ipconfigETHERNET_USE_100MB != 0 )\r
355                         .speed = PHY_SPEED_100,\r
356                 #else\r
357                         .speed = PHY_SPEED_10,\r
358                 #endif\r
359 \r
360                 #if( ipconfigETHERNET_USE_FULL_DUPLEX != 0 )\r
361                         .duplex = PHY_DUPLEX_FULL,\r
362                 #else\r
363                         .duplex = PHY_DUPLEX_HALF,\r
364                 #endif\r
365         #endif\r
366 \r
367         #if( ipconfigETHERNET_AN_ENABLE != 0 ) && ( ipconfigETHERNET_AUTO_CROSS_ENABLE != 0 )\r
368                 .mdix = PHY_MDIX_AUTO,\r
369         #elif( ipconfigETHERNET_CROSSED_LINK != 0 )\r
370                 .mdix = PHY_MDIX_CROSSED,\r
371         #else\r
372                 .mdix = PHY_MDIX_DIRECT,\r
373         #endif\r
374 };\r
375 \r
376 /*-----------------------------------------------------------*/\r
377 \r
378 void HAL_ETH_RxCpltCallback( ETH_HandleTypeDef *heth )\r
379 {\r
380 BaseType_t xHigherPriorityTaskWoken = pdFALSE;\r
381 \r
382         /* Ethernet RX-Complete callback function, elsewhere declared as weak. */\r
383     ulISREvents |= EMAC_IF_RX_EVENT;\r
384         /* Wakeup the prvEMACHandlerTask. */\r
385         if( xEMACTaskHandle != NULL )\r
386         {\r
387                 vTaskNotifyGiveFromISR( xEMACTaskHandle, &xHigherPriorityTaskWoken );\r
388                 portYIELD_FROM_ISR( xHigherPriorityTaskWoken );\r
389         }\r
390 }\r
391 /*-----------------------------------------------------------*/\r
392 \r
393 #if( ipconfigZERO_COPY_TX_DRIVER != 0 )\r
394         void HAL_ETH_TxCpltCallback( ETH_HandleTypeDef *heth )\r
395         {\r
396         BaseType_t xHigherPriorityTaskWoken = pdFALSE;\r
397 \r
398                 /* This call-back is only useful in case packets are being sent\r
399                 zero-copy.  Once they're sent, the buffers will be released\r
400                 by the function vClearTXBuffers(). */\r
401                 ulISREvents |= EMAC_IF_TX_EVENT;\r
402                 /* Wakeup the prvEMACHandlerTask. */\r
403                 if( xEMACTaskHandle != NULL )\r
404                 {\r
405                         vTaskNotifyGiveFromISR( xEMACTaskHandle, &xHigherPriorityTaskWoken );\r
406                         portYIELD_FROM_ISR( xHigherPriorityTaskWoken );\r
407                 }\r
408 \r
409         }\r
410 #endif /* ipconfigZERO_COPY_TX_DRIVER */\r
411 \r
412 /*-----------------------------------------------------------*/\r
413 \r
414 #if( ipconfigZERO_COPY_TX_DRIVER != 0 )\r
415         static void vClearTXBuffers()\r
416         {\r
417         __IO ETH_DMADescTypeDef  *txLastDescriptor = xETH.TxDesc;\r
418         NetworkBufferDescriptor_t *pxNetworkBuffer;\r
419         uint8_t *ucPayLoad;\r
420         size_t uxCount = ( ( UBaseType_t ) ETH_TXBUFNB ) - uxSemaphoreGetCount( xTXDescriptorSemaphore );\r
421 \r
422                 /* This function is called after a TX-completion interrupt.\r
423                 It will release each Network Buffer used in xNetworkInterfaceOutput().\r
424                 'uxCount' represents the number of descriptors given to DMA for transmission.\r
425                 After sending a packet, the DMA will clear the 'ETH_DMATXDESC_OWN' bit. */\r
426                 while( ( uxCount > 0 ) && ( ( DMATxDescToClear->Status & ETH_DMATXDESC_OWN ) == 0 ) )\r
427                 {\r
428                         if( ( DMATxDescToClear == txLastDescriptor ) && ( uxCount != ETH_TXBUFNB ) )\r
429                         {\r
430                                 break;\r
431                         }\r
432 \r
433                         ucPayLoad = ( uint8_t * )DMATxDescToClear->Buffer1Addr;\r
434 \r
435                         if( ucPayLoad != NULL )\r
436                         {\r
437                                 pxNetworkBuffer = pxPacketBuffer_to_NetworkBuffer( ucPayLoad );\r
438                                 if( pxNetworkBuffer != NULL )\r
439                                 {\r
440                                         vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer ) ;\r
441                                 }\r
442                                 DMATxDescToClear->Buffer1Addr = ( uint32_t )0u;\r
443                         }\r
444 \r
445                         DMATxDescToClear = ( ETH_DMADescTypeDef * )( DMATxDescToClear->Buffer2NextDescAddr );\r
446 \r
447                         uxCount--;\r
448                         /* Tell the counting semaphore that one more TX descriptor is available. */\r
449                         xSemaphoreGive( xTXDescriptorSemaphore );\r
450                 }\r
451         }\r
452 #endif /* ipconfigZERO_COPY_TX_DRIVER */\r
453 /*-----------------------------------------------------------*/\r
454 \r
455 BaseType_t xNetworkInterfaceInitialise( void )\r
456 {\r
457 HAL_StatusTypeDef hal_eth_init_status;\r
458 BaseType_t xResult;\r
459 \r
460         if( xEMACTaskHandle == NULL )\r
461         {\r
462                 #if( ipconfigZERO_COPY_TX_DRIVER != 0 )\r
463                 {\r
464                         if( xTXDescriptorSemaphore == NULL )\r
465                         {\r
466                                 xTXDescriptorSemaphore = xSemaphoreCreateCounting( ( UBaseType_t ) ETH_TXBUFNB, ( UBaseType_t ) ETH_TXBUFNB );\r
467                                 configASSERT( xTXDescriptorSemaphore );\r
468                         }\r
469                 }\r
470                 #endif /* ipconfigZERO_COPY_TX_DRIVER */\r
471 \r
472                 /* Initialise ETH */\r
473 \r
474                 xETH.Instance = ETH;\r
475                 xETH.Init.AutoNegotiation = ETH_AUTONEGOTIATION_ENABLE;\r
476                 xETH.Init.Speed = ETH_SPEED_100M;\r
477                 xETH.Init.DuplexMode = ETH_MODE_FULLDUPLEX;\r
478                 xETH.Init.PhyAddress = 1;\r
479 \r
480                 xETH.Init.MACAddr = ( uint8_t *) ucMACAddress;\r
481                 xETH.Init.RxMode = ETH_RXINTERRUPT_MODE;\r
482 \r
483                 /* using the ETH_CHECKSUM_BY_HARDWARE option:\r
484                 both the IP and the protocol checksums will be calculated\r
485                 by the peripheral. */\r
486                 xETH.Init.ChecksumMode = ETH_CHECKSUM_BY_HARDWARE;\r
487 \r
488                 xETH.Init.MediaInterface = ETH_MEDIA_INTERFACE_MII;\r
489                 hal_eth_init_status = HAL_ETH_Init( &xETH );\r
490 \r
491                 /* Only for inspection by debugger. */\r
492                 ( void ) hal_eth_init_status;\r
493 \r
494                 /* Set the TxDesc and RxDesc pointers. */\r
495                 xETH.TxDesc = DMATxDscrTab;\r
496                 xETH.RxDesc = DMARxDscrTab;\r
497 \r
498                 /* Make sure that all unused fields are cleared. */\r
499                 memset( &DMATxDscrTab, '\0', sizeof( DMATxDscrTab ) );\r
500                 memset( &DMARxDscrTab, '\0', sizeof( DMARxDscrTab ) );\r
501 \r
502                 #if( ipconfigZERO_COPY_TX_DRIVER != 0 )\r
503                 {\r
504                         /* Initialize Tx Descriptors list: Chain Mode */\r
505                         DMATxDescToClear = DMATxDscrTab;\r
506                 }\r
507                 #endif /* ipconfigZERO_COPY_TX_DRIVER */\r
508 \r
509                 /* Initialise TX-descriptors. */\r
510                 prvDMATxDescListInit();\r
511 \r
512                 /* Initialise RX-descriptors. */\r
513                 prvDMARxDescListInit();\r
514 \r
515                 #if( ipconfigUSE_LLMNR != 0 )\r
516                 {\r
517                         /* Program the LLMNR address at index 1. */\r
518                         prvMACAddressConfig( &xETH, ETH_MAC_ADDRESS1, ( uint8_t *) xLLMNR_MACAddress );\r
519                 }\r
520                 #endif\r
521 \r
522                 /* Force a negotiation with the Switch or Router and wait for LS. */\r
523                 prvEthernetUpdateConfig( pdTRUE );\r
524 \r
525                 /* The deferred interrupt handler task is created at the highest\r
526                 possible priority to ensure the interrupt handler can return directly\r
527                 to it.  The task's handle is stored in xEMACTaskHandle so interrupts can\r
528                 notify the task when there is something to process. */\r
529                 xTaskCreate( prvEMACHandlerTask, "EMAC", configEMAC_TASK_STACK_SIZE, NULL, configMAX_PRIORITIES - 1, &xEMACTaskHandle );\r
530         } /* if( xEMACTaskHandle == NULL ) */\r
531 \r
532         if( ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != 0 )\r
533         {\r
534                 xETH.Instance->DMAIER |= ETH_DMA_ALL_INTS;\r
535                 xResult = pdPASS;\r
536                 FreeRTOS_printf( ( "Link Status is high\n" ) ) ;\r
537         }\r
538         else\r
539         {\r
540                 /* For now pdFAIL will be returned. But prvEMACHandlerTask() is running\r
541                 and it will keep on checking the PHY and set ulPHYLinkStatus when necessary. */\r
542                 xResult = pdFAIL;\r
543                 FreeRTOS_printf( ( "Link Status still low\n" ) ) ;\r
544         }\r
545         /* When returning non-zero, the stack will become active and\r
546     start DHCP (in configured) */\r
547         return xResult;\r
548 }\r
549 /*-----------------------------------------------------------*/\r
550 \r
551 static void prvDMATxDescListInit()\r
552 {\r
553 ETH_DMADescTypeDef *pxDMADescriptor;\r
554 BaseType_t xIndex;\r
555 \r
556         /* Get the pointer on the first member of the descriptor list */\r
557         pxDMADescriptor = DMATxDscrTab;\r
558 \r
559         /* Fill each DMA descriptor with the right values */\r
560         for( xIndex = 0; xIndex < ETH_TXBUFNB; xIndex++, pxDMADescriptor++ )\r
561         {\r
562                 /* Set Second Address Chained bit */\r
563                 pxDMADescriptor->Status = ETH_DMATXDESC_TCH;\r
564 \r
565                 #if( ipconfigZERO_COPY_TX_DRIVER == 0 )\r
566                 {\r
567                         /* Set Buffer1 address pointer */\r
568                         pxDMADescriptor->Buffer1Addr = ( uint32_t )( Tx_Buff[ xIndex ] );\r
569                 }\r
570                 #endif\r
571 \r
572                 if( xETH.Init.ChecksumMode == ETH_CHECKSUM_BY_HARDWARE )\r
573                 {\r
574                         /* Set the DMA Tx descriptors checksum insertion for TCP, UDP, and ICMP */\r
575                         pxDMADescriptor->Status |= ETH_DMATXDESC_CHECKSUMTCPUDPICMPFULL;\r
576                 }\r
577 \r
578                 /* Initialize the next descriptor with the Next Descriptor Polling Enable */\r
579                 if( xIndex < ETH_TXBUFNB - 1 )\r
580                 {\r
581                         /* Set next descriptor address register with next descriptor base address */\r
582                         pxDMADescriptor->Buffer2NextDescAddr = ( uint32_t ) ( pxDMADescriptor + 1 );\r
583                 }\r
584                 else\r
585                 {\r
586                         /* For last descriptor, set next descriptor address register equal to the first descriptor base address */\r
587                         pxDMADescriptor->Buffer2NextDescAddr = ( uint32_t ) DMATxDscrTab;\r
588                 }\r
589         }\r
590 \r
591         /* Set Transmit Descriptor List Address Register */\r
592         xETH.Instance->DMATDLAR = ( uint32_t ) DMATxDscrTab;\r
593 }\r
594 /*-----------------------------------------------------------*/\r
595 \r
596 static void prvDMARxDescListInit()\r
597 {\r
598 ETH_DMADescTypeDef *pxDMADescriptor;\r
599 BaseType_t xIndex;\r
600         /*\r
601          * RX-descriptors.\r
602          */\r
603 \r
604         /* Get the pointer on the first member of the descriptor list */\r
605         pxDMADescriptor = DMARxDscrTab;\r
606 \r
607         /* Fill each DMA descriptor with the right values */\r
608         for( xIndex = 0; xIndex < ETH_RXBUFNB; xIndex++, pxDMADescriptor++ )\r
609         {\r
610 \r
611                 /* Set Buffer1 size and Second Address Chained bit */\r
612                 pxDMADescriptor->ControlBufferSize = ETH_DMARXDESC_RCH | (uint32_t)ETH_RX_BUF_SIZE;  \r
613 \r
614                 #if( ipconfigZERO_COPY_RX_DRIVER != 0 )\r
615                 {\r
616                 /* Set Buffer1 address pointer */\r
617                 NetworkBufferDescriptor_t *pxBuffer;\r
618 \r
619                         pxBuffer = pxGetNetworkBufferWithDescriptor( ETH_RX_BUF_SIZE, 100ul );\r
620                         /* If the assert below fails, make sure that there are at least 'ETH_RXBUFNB'\r
621                         Network Buffers available during start-up ( ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS ) */\r
622                         configASSERT( pxBuffer != NULL );\r
623                         if( pxBuffer != NULL )\r
624                         {\r
625                                 pxDMADescriptor->Buffer1Addr = (uint32_t)pxBuffer->pucEthernetBuffer;\r
626                                 pxDMADescriptor->Status = ETH_DMARXDESC_OWN;\r
627                         }\r
628                 }\r
629                 #else\r
630                 {\r
631                         /* Set Buffer1 address pointer */\r
632                         pxDMADescriptor->Buffer1Addr = ( uint32_t )( Rx_Buff[ xIndex ] );\r
633                         /* Set Own bit of the Rx descriptor Status */\r
634                         pxDMADescriptor->Status = ETH_DMARXDESC_OWN;\r
635                 }\r
636                 #endif\r
637 \r
638                 /* Initialize the next descriptor with the Next Descriptor Polling Enable */\r
639                 if( xIndex < ETH_RXBUFNB - 1 )\r
640                 {\r
641                         /* Set next descriptor address register with next descriptor base address */\r
642                         pxDMADescriptor->Buffer2NextDescAddr = ( uint32_t )( pxDMADescriptor + 1 );\r
643                 }\r
644                 else\r
645                 {\r
646                         /* For last descriptor, set next descriptor address register equal to the first descriptor base address */\r
647                         pxDMADescriptor->Buffer2NextDescAddr = ( uint32_t ) DMARxDscrTab;\r
648                 }\r
649 \r
650         }\r
651         /* Set Receive Descriptor List Address Register */\r
652         xETH.Instance->DMARDLAR = ( uint32_t ) DMARxDscrTab;\r
653 }\r
654 /*-----------------------------------------------------------*/\r
655 \r
656 static void prvMACAddressConfig(ETH_HandleTypeDef *heth, uint32_t ulIndex, uint8_t *Addr)\r
657 {\r
658 uint32_t ulTempReg;\r
659 \r
660         /* Calculate the selected MAC address high register. */\r
661         ulTempReg = 0x80000000ul | ( ( uint32_t ) Addr[ 5 ] << 8 ) | ( uint32_t ) Addr[ 4 ];\r
662 \r
663         /* Load the selected MAC address high register. */\r
664         ( *(__IO uint32_t *)( ( uint32_t ) ( ETH_MAC_ADDR_HBASE + ulIndex ) ) ) = ulTempReg;\r
665 \r
666         /* Calculate the selected MAC address low register. */\r
667         ulTempReg = ( ( uint32_t ) Addr[ 3 ] << 24 ) | ( ( uint32_t ) Addr[ 2 ] << 16 ) | ( ( uint32_t ) Addr[ 1 ] << 8 ) | Addr[ 0 ];\r
668 \r
669         /* Load the selected MAC address low register */\r
670         ( *(__IO uint32_t *) ( ( uint32_t ) ( ETH_MAC_ADDR_LBASE + ulIndex ) ) ) = ulTempReg;\r
671 }\r
672 /*-----------------------------------------------------------*/\r
673 \r
674 BaseType_t xNetworkInterfaceOutput( NetworkBufferDescriptor_t * const pxDescriptor, BaseType_t bReleaseAfterSend )\r
675 {\r
676 BaseType_t xReturn = pdFAIL;\r
677 uint32_t ulTransmitSize = 0;\r
678 __IO ETH_DMADescTypeDef *pxDmaTxDesc;\r
679 /* Do not wait too long for a free TX DMA buffer. */\r
680 const TickType_t xBlockTimeTicks = pdMS_TO_TICKS( 50u );\r
681 \r
682         #if( ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM != 0 )\r
683         {\r
684         ProtocolPacket_t *pxPacket;\r
685 \r
686                 /* If the peripheral must calculate the checksum, it wants\r
687                 the protocol checksum to have a value of zero. */\r
688                 pxPacket = ( ProtocolPacket_t * ) ( pxDescriptor->pucEthernetBuffer );\r
689 \r
690                 if( pxPacket->xICMPPacket.xIPHeader.ucProtocol == ipPROTOCOL_ICMP )\r
691                 {\r
692                         pxPacket->xICMPPacket.xICMPHeader.usChecksum = ( uint16_t )0u;\r
693                 }\r
694         }\r
695         #endif\r
696 \r
697         /* Open a do {} while ( 0 ) loop to be able to call break. */\r
698         do\r
699         {\r
700                 if( ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != 0 )\r
701                 {\r
702                         #if( ipconfigZERO_COPY_TX_DRIVER != 0 )\r
703                         {\r
704                                 if( xTXDescriptorSemaphore == NULL )\r
705                                 {\r
706                                         break;\r
707                                 }\r
708                                 if( xSemaphoreTake( xTXDescriptorSemaphore, xBlockTimeTicks ) != pdPASS )\r
709                                 {\r
710                                         /* Time-out waiting for a free TX descriptor. */\r
711                                         break;\r
712                                 }\r
713                         }\r
714                         #endif /* ipconfigZERO_COPY_TX_DRIVER */\r
715 \r
716                         /* This function does the actual transmission of the packet. The packet is\r
717                         contained in 'pxDescriptor' that is passed to the function. */\r
718                         pxDmaTxDesc = xETH.TxDesc;\r
719 \r
720                         /* Is this buffer available? */\r
721                         if( ( pxDmaTxDesc->Status & ETH_DMATXDESC_OWN ) == 0 )\r
722                         {\r
723                                 /* Is this buffer available? */\r
724                                 /* Get bytes in current buffer. */\r
725                                 ulTransmitSize = pxDescriptor->xDataLength;\r
726 \r
727                                 if( ulTransmitSize > ETH_TX_BUF_SIZE )\r
728                                 {\r
729                                         ulTransmitSize = ETH_TX_BUF_SIZE;\r
730                                 }\r
731 \r
732                                 #if( ipconfigZERO_COPY_TX_DRIVER == 0 )\r
733                                 {\r
734                                         /* Copy the bytes. */\r
735                                         memcpy( ( void * ) pxDmaTxDesc->Buffer1Addr, pxDescriptor->pucEthernetBuffer, ulTransmitSize );\r
736                                         pxDmaTxDesc->Status |= ETH_DMATXDESC_CIC_TCPUDPICMP_FULL;\r
737                                 }\r
738                                 #else\r
739                                 {\r
740                                         /* Move the buffer. */\r
741                                         pxDmaTxDesc->Buffer1Addr = ( uint32_t )pxDescriptor->pucEthernetBuffer;\r
742                                         /* Ask to set the IPv4 checksum.\r
743                                         Also need an Interrupt on Completion so that 'vClearTXBuffers()' will be called.. */\r
744                                         pxDmaTxDesc->Status |= ETH_DMATXDESC_CIC_TCPUDPICMP_FULL | ETH_DMATXDESC_IC;\r
745                                         /* The Network Buffer has been passed to DMA, no need to release it. */\r
746                                         bReleaseAfterSend = pdFALSE_UNSIGNED;\r
747                                 }\r
748                                 #endif /* ipconfigZERO_COPY_TX_DRIVER */\r
749 \r
750                                 /* Prepare transmit descriptors to give to DMA. */\r
751 \r
752                                 /* Set LAST and FIRST segment */\r
753                                 pxDmaTxDesc->Status |= ETH_DMATXDESC_FS | ETH_DMATXDESC_LS;\r
754                                 /* Set frame size */\r
755                                 pxDmaTxDesc->ControlBufferSize = ( ulTransmitSize & ETH_DMATXDESC_TBS1 );\r
756                                 /* Set Own bit of the Tx descriptor Status: gives the buffer back to ETHERNET DMA */\r
757                                 pxDmaTxDesc->Status |= ETH_DMATXDESC_OWN;\r
758 \r
759                                 /* Point to next descriptor */\r
760                                 xETH.TxDesc = ( ETH_DMADescTypeDef * ) ( xETH.TxDesc->Buffer2NextDescAddr );\r
761         \r
762                                 /* Resume DMA transmission*/\r
763                                 xETH.Instance->DMATPDR = 0;\r
764                                 iptraceNETWORK_INTERFACE_TRANSMIT();\r
765                                 xReturn = pdPASS;\r
766                         }\r
767                 }\r
768                 else\r
769                 {\r
770                         /* The PHY has no Link Status, packet shall be dropped. */\r
771                 }\r
772         } while( 0 );\r
773         /* The buffer has been sent so can be released. */\r
774         if( bReleaseAfterSend != pdFALSE )\r
775         {\r
776                 vReleaseNetworkBufferAndDescriptor( pxDescriptor );\r
777         }\r
778 \r
779         return xReturn;\r
780 }\r
781 /*-----------------------------------------------------------*/\r
782 \r
783 static BaseType_t xMayAcceptPacket( uint8_t *pcBuffer )\r
784 {\r
785 const ProtocolPacket_t *pxProtPacket = ( const ProtocolPacket_t * )pcBuffer;\r
786 \r
787         switch( pxProtPacket->xTCPPacket.xEthernetHeader.usFrameType )\r
788         {\r
789         case ipARP_FRAME_TYPE:\r
790                 /* Check it later. */\r
791                 return pdTRUE;\r
792         case ipIPv4_FRAME_TYPE:\r
793                 /* Check it here. */\r
794                 break;\r
795         default:\r
796                 /* Refuse the packet. */\r
797                 return pdFALSE;\r
798         }\r
799 \r
800         #if( ipconfigETHERNET_DRIVER_FILTERS_PACKETS == 1 )\r
801         {\r
802                 const IPHeader_t *pxIPHeader = &(pxProtPacket->xTCPPacket.xIPHeader);\r
803                 uint32_t ulDestinationIPAddress;\r
804 \r
805                 /* Ensure that the incoming packet is not fragmented (only outgoing packets\r
806                  * can be fragmented) as these are the only handled IP frames currently. */\r
807                 if( ( pxIPHeader->usFragmentOffset & FreeRTOS_ntohs( ipFRAGMENT_OFFSET_BIT_MASK ) ) != 0U )\r
808                 {\r
809                         return pdFALSE;\r
810                 }\r
811                 /* HT: Might want to make the following configurable because\r
812                  * most IP messages have a standard length of 20 bytes */\r
813 \r
814                 /* 0x45 means: IPv4 with an IP header of 5 x 4 = 20 bytes\r
815                  * 0x47 means: IPv4 with an IP header of 7 x 4 = 28 bytes */\r
816                 if( pxIPHeader->ucVersionHeaderLength < 0x45 || pxIPHeader->ucVersionHeaderLength > 0x4F )\r
817                 {\r
818                         return pdFALSE;\r
819                 }\r
820 \r
821                 ulDestinationIPAddress = pxIPHeader->ulDestinationIPAddress;\r
822                 /* Is the packet for this node? */\r
823                 if( ( ulDestinationIPAddress != *ipLOCAL_IP_ADDRESS_POINTER ) &&\r
824                         /* Is it a broadcast address x.x.x.255 ? */\r
825                         ( ( FreeRTOS_ntohl( ulDestinationIPAddress ) & 0xff ) != 0xff ) &&\r
826                 #if( ipconfigUSE_LLMNR == 1 )\r
827                         ( ulDestinationIPAddress != ipLLMNR_IP_ADDR ) &&\r
828                 #endif\r
829                         ( *ipLOCAL_IP_ADDRESS_POINTER != 0 ) ) {\r
830                         FreeRTOS_printf( ( "Drop IP %lxip\n", FreeRTOS_ntohl( ulDestinationIPAddress ) ) );\r
831                         return pdFALSE;\r
832                 }\r
833 \r
834                 if( pxIPHeader->ucProtocol == ipPROTOCOL_UDP )\r
835                 {\r
836                         uint16_t port = pxProtPacket->xUDPPacket.xUDPHeader.usDestinationPort;\r
837 \r
838                         if( ( xPortHasUDPSocket( port ) == pdFALSE )\r
839                         #if ipconfigUSE_LLMNR == 1\r
840                                 && ( port != FreeRTOS_ntohs( ipLLMNR_PORT ) )\r
841                         #endif\r
842                         #if ipconfigUSE_NBNS == 1\r
843                                 && ( port != FreeRTOS_ntohs( ipNBNS_PORT ) )\r
844                         #endif\r
845                         #if ipconfigUSE_DNS == 1\r
846                                 && ( pxProtPacket->xUDPPacket.xUDPHeader.usSourcePort != FreeRTOS_ntohs( ipDNS_PORT ) )\r
847                         #endif\r
848                                 ) {\r
849                                 /* Drop this packet, not for this device. */\r
850                                 return pdFALSE;\r
851                         }\r
852                 }\r
853         }\r
854         #endif  /* ipconfigETHERNET_DRIVER_FILTERS_PACKETS */\r
855         return pdTRUE;\r
856 }\r
857 /*-----------------------------------------------------------*/\r
858 \r
859 static BaseType_t prvNetworkInterfaceInput( void )\r
860 {\r
861 NetworkBufferDescriptor_t *pxCurDescriptor;\r
862 NetworkBufferDescriptor_t *pxNewDescriptor = NULL;\r
863 BaseType_t xReceivedLength, xAccepted;\r
864 __IO ETH_DMADescTypeDef *pxDMARxDescriptor;\r
865 xIPStackEvent_t xRxEvent = { eNetworkRxEvent, NULL };\r
866 const TickType_t xDescriptorWaitTime = pdMS_TO_TICKS( 250 );\r
867 uint8_t *pucBuffer;\r
868 \r
869         pxDMARxDescriptor = xETH.RxDesc;\r
870 \r
871         if( ( pxDMARxDescriptor->Status & ETH_DMARXDESC_OWN) == 0 )\r
872         {\r
873                 /* Get the Frame Length of the received packet: substruct 4 bytes of the CRC */\r
874                 xReceivedLength = ( ( pxDMARxDescriptor->Status & ETH_DMARXDESC_FL ) >> ETH_DMARXDESC_FRAMELENGTHSHIFT ) - 4;\r
875 \r
876                 pucBuffer = (uint8_t *) pxDMARxDescriptor->Buffer1Addr;\r
877 \r
878                 /* Update the ETHERNET DMA global Rx descriptor with next Rx descriptor */\r
879                 /* Chained Mode */    \r
880                 /* Selects the next DMA Rx descriptor list for next buffer to read */ \r
881                 xETH.RxDesc = ( ETH_DMADescTypeDef* )pxDMARxDescriptor->Buffer2NextDescAddr;\r
882         }\r
883         else\r
884         {\r
885                 xReceivedLength = 0;\r
886         }\r
887 \r
888         /* Obtain the size of the packet and put it into the "usReceivedLength" variable. */\r
889 \r
890         /* get received frame */\r
891         if( xReceivedLength > 0ul )\r
892         {\r
893                 /* In order to make the code easier and faster, only packets in a single buffer\r
894                 will be accepted.  This can be done by making the buffers large enough to\r
895                 hold a complete Ethernet packet (1536 bytes).\r
896                 Therefore, two sanity checks: */\r
897                 configASSERT( xReceivedLength <= ETH_RX_BUF_SIZE );\r
898 \r
899                 if( ( pxDMARxDescriptor->Status & ( ETH_DMARXDESC_CE | ETH_DMARXDESC_IPV4HCE | ETH_DMARXDESC_FT ) ) != ETH_DMARXDESC_FT )\r
900                 {\r
901                         /* Not an Ethernet frame-type or a checmsum error. */\r
902                         xAccepted = pdFALSE;\r
903                 }\r
904                 else\r
905                 {\r
906                         /* See if this packet must be handled. */\r
907                         xAccepted = xMayAcceptPacket( pucBuffer );\r
908                 }\r
909 \r
910                 if( xAccepted != pdFALSE )\r
911                 {\r
912                         /* The packet wil be accepted, but check first if a new Network Buffer can\r
913                         be obtained. If not, the packet will still be dropped. */\r
914                         pxNewDescriptor = pxGetNetworkBufferWithDescriptor( ETH_RX_BUF_SIZE, xDescriptorWaitTime );\r
915 \r
916                         if( pxNewDescriptor == NULL )\r
917                         {\r
918                                 /* A new descriptor can not be allocated now. This packet will be dropped. */\r
919                                 xAccepted = pdFALSE;\r
920                         }\r
921                 }\r
922                 #if( ipconfigZERO_COPY_RX_DRIVER != 0 )\r
923                 {\r
924                         /* Find out which Network Buffer was originally passed to the descriptor. */\r
925                         pxCurDescriptor = pxPacketBuffer_to_NetworkBuffer( pucBuffer );\r
926                         configASSERT( pxCurDescriptor != NULL );\r
927                 }\r
928                 #else\r
929                 {\r
930                         /* In this mode, the two descriptors are the same. */\r
931                         pxCurDescriptor = pxNewDescriptor;\r
932                         if( pxNewDescriptor != NULL )\r
933                         {\r
934                                 /* The packet is acepted and a new Network Buffer was created,\r
935                                 copy data to the Network Bufffer. */\r
936                                 memcpy( pxNewDescriptor->pucEthernetBuffer, pucBuffer, xReceivedLength );\r
937                         }\r
938                 }\r
939                 #endif\r
940 \r
941                 if( xAccepted != pdFALSE )\r
942                 {\r
943                         pxCurDescriptor->xDataLength = xReceivedLength;\r
944                         xRxEvent.pvData = ( void * ) pxCurDescriptor;\r
945 \r
946                         /* Pass the data to the TCP/IP task for processing. */\r
947                         if( xSendEventStructToIPTask( &xRxEvent, xDescriptorWaitTime ) == pdFALSE )\r
948                         {\r
949                                 /* Could not send the descriptor into the TCP/IP stack, it\r
950                                 must be released. */\r
951                                 vReleaseNetworkBufferAndDescriptor( pxCurDescriptor );\r
952                                 iptraceETHERNET_RX_EVENT_LOST();\r
953                         }\r
954                         else\r
955                         {\r
956                                 iptraceNETWORK_INTERFACE_RECEIVE();\r
957                         }\r
958                 }\r
959 \r
960                 /* Release descriptors to DMA */\r
961                 #if( ipconfigZERO_COPY_RX_DRIVER != 0 )\r
962                 {\r
963                         /* Set Buffer1 address pointer */\r
964                         if( pxNewDescriptor != NULL )\r
965                         {\r
966                                 pxDMARxDescriptor->Buffer1Addr = (uint32_t)pxNewDescriptor->pucEthernetBuffer;\r
967                         }\r
968                         else\r
969                         {\r
970                                 /* The packet was dropped and the same Network\r
971                                 Buffer will be used to receive a new packet. */\r
972                         }\r
973                 }\r
974                 #endif /* ipconfigZERO_COPY_RX_DRIVER */\r
975 \r
976                 /* Set Buffer1 size and Second Address Chained bit */\r
977                 pxDMARxDescriptor->ControlBufferSize = ETH_DMARXDESC_RCH | (uint32_t)ETH_RX_BUF_SIZE;  \r
978                 pxDMARxDescriptor->Status = ETH_DMARXDESC_OWN;\r
979 \r
980                 /* When Rx Buffer unavailable flag is set clear it and resume\r
981                 reception. */\r
982                 if( ( xETH.Instance->DMASR & ETH_DMASR_RBUS ) != 0 )\r
983                 {\r
984                         /* Clear RBUS ETHERNET DMA flag. */\r
985                         xETH.Instance->DMASR = ETH_DMASR_RBUS;\r
986 \r
987                         /* Resume DMA reception. */\r
988                         xETH.Instance->DMARPDR = 0;\r
989                 }\r
990         }\r
991 \r
992         return ( xReceivedLength > 0 );\r
993 }\r
994 /*-----------------------------------------------------------*/\r
995 \r
996 void vMACBProbePhy( void )\r
997 {\r
998 uint32_t ulConfig, ulAdvertise, ulLower, ulUpper, ulMACPhyID, ulValue;\r
999 TimeOut_t xPhyTime;\r
1000 TickType_t xRemTime = 0;\r
1001 #if( EXPECTED_PHY_ID == PHY_ID_DP83848I )\r
1002         uint32_t ulPhyControl;\r
1003 #endif\r
1004 \r
1005         HAL_ETH_ReadPHYRegister(&xETH, PHY_REG_03_PHYSID2, &ulLower);\r
1006         HAL_ETH_ReadPHYRegister(&xETH, PHY_REG_02_PHYSID1, &ulUpper);\r
1007 \r
1008         ulMACPhyID = ( ( ulUpper << 16 ) & 0xFFFF0000 ) | ( ulLower & 0xFFF0 );\r
1009 \r
1010         /* The expected ID for the 'LAN8720' is 0x0007c0f0. */\r
1011         /* The expected ID for the 'DP83848I' is 0x20005C90. */\r
1012 \r
1013         FreeRTOS_printf( ( "PHY ID %lX (%s)\n", ulMACPhyID,\r
1014                 ( ulMACPhyID == EXPECTED_PHY_ID ) ? "OK" : "Unknown" ) );\r
1015 \r
1016         /* Remove compiler warning if FreeRTOS_printf() is not defined. */\r
1017         ( void ) ulMACPhyID;\r
1018 \r
1019     /* Set advertise register. */\r
1020         if( ( xPHYProperties.speed == PHY_SPEED_AUTO ) && ( xPHYProperties.duplex == PHY_DUPLEX_AUTO ) )\r
1021         {\r
1022                 ulAdvertise = ADVERTISE_CSMA | ADVERTISE_ALL;\r
1023                 /* Reset auto-negotiation capability. */\r
1024         }\r
1025         else\r
1026         {\r
1027                 ulAdvertise = ADVERTISE_CSMA;\r
1028 \r
1029                 if( xPHYProperties.speed == PHY_SPEED_AUTO )\r
1030                 {\r
1031                         if( xPHYProperties.duplex == PHY_DUPLEX_FULL )\r
1032                         {\r
1033                                 ulAdvertise |= ADVERTISE_10FULL | ADVERTISE_100FULL;\r
1034                         }\r
1035                         else\r
1036                         {\r
1037                                 ulAdvertise |= ADVERTISE_10HALF | ADVERTISE_100HALF;\r
1038                         }\r
1039                 }\r
1040                 else if( xPHYProperties.duplex == PHY_DUPLEX_AUTO )\r
1041                 {\r
1042                         if( xPHYProperties.speed == PHY_SPEED_10 )\r
1043                         {\r
1044                                 ulAdvertise |= ADVERTISE_10FULL | ADVERTISE_10HALF;\r
1045                         }\r
1046                         else\r
1047                         {\r
1048                                 ulAdvertise |= ADVERTISE_100FULL | ADVERTISE_100HALF;\r
1049                         }\r
1050                 }\r
1051                 else if( xPHYProperties.speed == PHY_SPEED_100 )\r
1052                 {\r
1053                         if( xPHYProperties.duplex == PHY_DUPLEX_FULL )\r
1054                         {\r
1055                                 ulAdvertise |= ADVERTISE_100FULL;\r
1056                         }\r
1057                         else\r
1058                         {\r
1059                                 ulAdvertise |= ADVERTISE_100HALF;\r
1060                         }\r
1061                 }\r
1062                 else\r
1063                 {\r
1064                         if( xPHYProperties.duplex == PHY_DUPLEX_FULL )\r
1065                         {\r
1066                                 ulAdvertise |= ADVERTISE_10FULL;\r
1067                         }\r
1068                         else\r
1069                         {\r
1070                                 ulAdvertise |= ADVERTISE_10HALF;\r
1071                         }\r
1072                 }\r
1073         }\r
1074 \r
1075         /* Read Control register. */\r
1076         HAL_ETH_ReadPHYRegister( &xETH, PHY_REG_00_BMCR, &ulConfig );\r
1077 \r
1078         HAL_ETH_WritePHYRegister( &xETH, PHY_REG_00_BMCR, ulConfig | BMCR_RESET );\r
1079         xRemTime = ( TickType_t ) pdMS_TO_TICKS( 1000UL );\r
1080         vTaskSetTimeOutState( &xPhyTime );\r
1081 \r
1082         for( ; ; )\r
1083         {\r
1084                 HAL_ETH_ReadPHYRegister( &xETH, PHY_REG_00_BMCR, &ulValue );\r
1085                 if( ( ulValue & BMCR_RESET ) == 0 )\r
1086                 {\r
1087                         FreeRTOS_printf( ( "BMCR_RESET ready\n" ) );\r
1088                         break;\r
1089                 }\r
1090                 if( xTaskCheckForTimeOut( &xPhyTime, &xRemTime ) != pdFALSE )\r
1091                 {\r
1092                         FreeRTOS_printf( ( "BMCR_RESET timed out\n" ) );\r
1093                         break;\r
1094                 }\r
1095         }\r
1096         HAL_ETH_WritePHYRegister( &xETH, PHY_REG_00_BMCR, ulConfig & ~BMCR_RESET );\r
1097 \r
1098         vTaskDelay( pdMS_TO_TICKS( 50ul ) );\r
1099 \r
1100     /* Write advertise register. */\r
1101         HAL_ETH_WritePHYRegister( &xETH, PHY_REG_04_ADVERTISE, ulAdvertise );\r
1102 \r
1103         /*\r
1104                         AN_EN        AN1         AN0       Forced Mode\r
1105                           0           0           0        10BASE-T, Half-Duplex\r
1106                           0           0           1        10BASE-T, Full-Duplex\r
1107                           0           1           0        100BASE-TX, Half-Duplex\r
1108                           0           1           1        100BASE-TX, Full-Duplex\r
1109                         AN_EN        AN1         AN0       Advertised Mode\r
1110                           1           0           0        10BASE-T, Half/Full-Duplex\r
1111                           1           0           1        100BASE-TX, Half/Full-Duplex\r
1112                           1           1           0        10BASE-T Half-Duplex\r
1113                                                                                            100BASE-TX, Half-Duplex\r
1114                           1           1           1        10BASE-T, Half/Full-Duplex\r
1115                                                                                            100BASE-TX, Half/Full-Duplex\r
1116         */\r
1117 \r
1118     /* Read Control register. */\r
1119         HAL_ETH_ReadPHYRegister( &xETH, PHY_REG_00_BMCR, &ulConfig );\r
1120 \r
1121         ulConfig &= ~( BMCR_ANRESTART | BMCR_ANENABLE | BMCR_SPEED100 | BMCR_FULLDPLX );\r
1122 \r
1123         /* HT 12/9/14: always set AN-restart and AN-enable, even though the choices\r
1124         are limited. */\r
1125         ulConfig |= (BMCR_ANRESTART | BMCR_ANENABLE);\r
1126 \r
1127         if( xPHYProperties.speed == PHY_SPEED_100 )\r
1128         {\r
1129                 ulConfig |= BMCR_SPEED100;\r
1130         }\r
1131         else if( xPHYProperties.speed == PHY_SPEED_10 )\r
1132         {\r
1133                 ulConfig &= ~BMCR_SPEED100;\r
1134         }\r
1135 \r
1136         if( xPHYProperties.duplex == PHY_DUPLEX_FULL )\r
1137         {\r
1138                 ulConfig |= BMCR_FULLDPLX;\r
1139         }\r
1140         else if( xPHYProperties.duplex == PHY_DUPLEX_HALF )\r
1141         {\r
1142                 ulConfig &= ~BMCR_FULLDPLX;\r
1143         }\r
1144 \r
1145         #if( EXPECTED_PHY_ID == PHY_ID_LAN8720 )\r
1146         {\r
1147         }\r
1148         #elif( EXPECTED_PHY_ID == PHY_ID_DP83848I )\r
1149         {\r
1150                 /* Read PHY Control register. */\r
1151                 HAL_ETH_ReadPHYRegister( &xETH, PHY_REG_19_PHYCR, &ulPhyControl );\r
1152 \r
1153                 /* Clear bits which might get set: */\r
1154                 ulPhyControl &= ~( PHYCR_MDIX_EN|PHYCR_MDIX_FORCE );\r
1155 \r
1156                 if( xPHYProperties.mdix == PHY_MDIX_AUTO )\r
1157                 {\r
1158                         ulPhyControl |= PHYCR_MDIX_EN;\r
1159                 }\r
1160                 else if( xPHYProperties.mdix == PHY_MDIX_CROSSED )\r
1161                 {\r
1162                         /* Force direct link = Use crossed RJ45 cable. */\r
1163                         ulPhyControl &= ~PHYCR_MDIX_FORCE;\r
1164                 }\r
1165                 else\r
1166                 {\r
1167                         /* Force crossed link = Use direct RJ45 cable. */\r
1168                         ulPhyControl |= PHYCR_MDIX_FORCE;\r
1169                 }\r
1170                 /* update PHY Control Register. */\r
1171                 HAL_ETH_WritePHYRegister( &xETH, PHY_REG_19_PHYCR, ulPhyControl );\r
1172         }\r
1173         #endif\r
1174         FreeRTOS_printf( ( "+TCP: advertise: %lX config %lX\n", ulAdvertise, ulConfig ) );\r
1175 \r
1176         /* Now the two values to global values for later use. */\r
1177         ulBCRvalue = ulConfig;\r
1178         ulACRValue = ulAdvertise;\r
1179 }\r
1180 /*-----------------------------------------------------------*/\r
1181 \r
1182 static void prvEthernetUpdateConfig( BaseType_t xForce )\r
1183 {\r
1184 __IO uint32_t ulTimeout = 0;\r
1185 uint32_t ulRegValue = 0;\r
1186 \r
1187         FreeRTOS_printf( ( "prvEthernetUpdateConfig: LS %d Force %d\n",\r
1188                 ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != 0 ,\r
1189                 xForce ) );\r
1190 \r
1191         if( ( xForce != pdFALSE ) || ( ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != 0 ) )\r
1192         {\r
1193                 /* Restart the auto-negotiation. */\r
1194                 if( xETH.Init.AutoNegotiation != ETH_AUTONEGOTIATION_DISABLE )\r
1195                 {\r
1196                         /* Enable Auto-Negotiation. */\r
1197                         HAL_ETH_WritePHYRegister( &xETH, PHY_REG_00_BMCR, ulBCRvalue | BMCR_ANRESTART );\r
1198                         HAL_ETH_WritePHYRegister( &xETH, PHY_REG_04_ADVERTISE, ulACRValue);\r
1199 \r
1200                         /* Wait until the auto-negotiation will be completed */\r
1201                         do\r
1202                         {\r
1203                                 ulTimeout++;\r
1204                                 HAL_ETH_ReadPHYRegister( &xETH, PHY_REG_01_BMSR, &ulRegValue );\r
1205                         } while( ( ( ulRegValue & PHY_AUTONEGO_COMPLETE) == 0 ) && ( ulTimeout < PHY_READ_TO ) );\r
1206 \r
1207                         HAL_ETH_WritePHYRegister( &xETH, PHY_REG_00_BMCR, ulBCRvalue & ~BMCR_ANRESTART );\r
1208 \r
1209                         if( ulTimeout < PHY_READ_TO )\r
1210                         {\r
1211                                 /* Reset Timeout counter. */\r
1212                                 ulTimeout = 0;\r
1213 \r
1214                                 HAL_ETH_ReadPHYRegister( &xETH, PHY_REG_01_BMSR, &ulRegValue);\r
1215                                 if( ( ulRegValue & BMSR_LINK_STATUS ) != 0 )\r
1216                                 {\r
1217                                         ulPHYLinkStatus |= BMSR_LINK_STATUS;\r
1218                                 }\r
1219                                 else\r
1220                                 {\r
1221                                         ulPHYLinkStatus &= ~( BMSR_LINK_STATUS );\r
1222                                 }\r
1223 \r
1224                                 #if( EXPECTED_PHY_ID == PHY_ID_LAN8720 )\r
1225                                 {\r
1226                                 /* 31 RW PHY Special Control Status */\r
1227                                 uint32_t ulControlStatus;\r
1228 \r
1229                                         HAL_ETH_ReadPHYRegister( &xETH, PHY_REG_1F_PHYSPCS, &ulControlStatus);\r
1230                                         ulRegValue = 0;\r
1231                                         if( ( ulControlStatus & PHYSPCS_FULL_DUPLEX ) != 0 )\r
1232                                         {\r
1233                                                 ulRegValue |= PHY_DUPLEX_STATUS;\r
1234                                         }\r
1235                                         if( ( ulControlStatus & PHYSPCS_SPEED_MASK ) == PHYSPCS_SPEED_10 )\r
1236                                         {\r
1237                                                 ulRegValue |= PHY_SPEED_STATUS;\r
1238                                         }\r
1239 \r
1240                                 }\r
1241                                 #elif( EXPECTED_PHY_ID == PHY_ID_DP83848I )\r
1242                                 {\r
1243                                         /* Read the result of the auto-negotiation. */\r
1244                                         HAL_ETH_ReadPHYRegister( &xETH, PHY_REG_10_PHY_SR, &ulRegValue);\r
1245                                 }\r
1246                                 #endif\r
1247                                 FreeRTOS_printf( ( ">> Autonego ready: %08lx: %s duplex %u mbit %s status\n",\r
1248                                         ulRegValue,\r
1249                                         (ulRegValue & PHY_DUPLEX_STATUS) ? "full" : "half",\r
1250                                         (ulRegValue & PHY_SPEED_STATUS) ? 10 : 100,\r
1251                                         ((ulPHYLinkStatus |= BMSR_LINK_STATUS) != 0) ? "high" : "low" ) );\r
1252 \r
1253                                 /* Configure the MAC with the Duplex Mode fixed by the\r
1254                                 auto-negotiation process. */\r
1255                                 if( ( ulRegValue & PHY_DUPLEX_STATUS ) != ( uint32_t ) RESET )\r
1256                                 {\r
1257                                         /* Set Ethernet duplex mode to Full-duplex following the\r
1258                                         auto-negotiation. */\r
1259                                         xETH.Init.DuplexMode = ETH_MODE_FULLDUPLEX;\r
1260                                 }\r
1261                                 else\r
1262                                 {\r
1263                                         /* Set Ethernet duplex mode to Half-duplex following the\r
1264                                         auto-negotiation. */\r
1265                                         xETH.Init.DuplexMode = ETH_MODE_HALFDUPLEX;\r
1266                                 }\r
1267 \r
1268                                 /* Configure the MAC with the speed fixed by the\r
1269                                 auto-negotiation process. */\r
1270                                 if( ( ulRegValue & PHY_SPEED_STATUS) != 0 )\r
1271                                 {\r
1272                                         /* Set Ethernet speed to 10M following the\r
1273                                         auto-negotiation. */\r
1274                                         xETH.Init.Speed = ETH_SPEED_10M;\r
1275                                 }\r
1276                                 else\r
1277                                 {\r
1278                                         /* Set Ethernet speed to 100M following the\r
1279                                         auto-negotiation. */\r
1280                                         xETH.Init.Speed = ETH_SPEED_100M;\r
1281                                 }\r
1282                         }       /* if( ulTimeout < PHY_READ_TO ) */\r
1283                 }\r
1284                 else /* AutoNegotiation Disable */\r
1285                 {\r
1286                 uint16_t usValue;\r
1287 \r
1288                         /* Check parameters */\r
1289                         assert_param( IS_ETH_SPEED( xETH.Init.Speed ) );\r
1290                         assert_param( IS_ETH_DUPLEX_MODE( xETH.Init.DuplexMode ) );\r
1291 \r
1292                         /* Set MAC Speed and Duplex Mode to PHY */\r
1293                         usValue = ( uint16_t ) ( xETH.Init.DuplexMode >> 3 ) | ( uint16_t ) ( xETH.Init.Speed >> 1 );\r
1294                         HAL_ETH_WritePHYRegister( &xETH, PHY_REG_00_BMCR, usValue );\r
1295                 }\r
1296 \r
1297                 /* ETHERNET MAC Re-Configuration */\r
1298                 HAL_ETH_ConfigMAC( &xETH, (ETH_MACInitTypeDef *) NULL);\r
1299 \r
1300                 /* Restart MAC interface */\r
1301                 HAL_ETH_Start( &xETH);\r
1302         }\r
1303         else\r
1304         {\r
1305                 /* Stop MAC interface */\r
1306                 HAL_ETH_Stop( &xETH );\r
1307         }\r
1308 }\r
1309 /*-----------------------------------------------------------*/\r
1310 \r
1311 BaseType_t xGetPhyLinkStatus( void )\r
1312 {\r
1313 BaseType_t xReturn;\r
1314 \r
1315         if( ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != 0 )\r
1316         {\r
1317                 xReturn = pdPASS;\r
1318         }\r
1319         else\r
1320         {\r
1321                 xReturn = pdFAIL;\r
1322         }\r
1323 \r
1324         return xReturn;\r
1325 }\r
1326 /*-----------------------------------------------------------*/\r
1327 \r
1328 static void prvEMACHandlerTask( void *pvParameters )\r
1329 {\r
1330 TimeOut_t xPhyTime;\r
1331 TickType_t xPhyRemTime;\r
1332 UBaseType_t uxLastMinBufferCount = 0;\r
1333 #if( ipconfigCHECK_IP_QUEUE_SPACE != 0 )\r
1334 UBaseType_t uxLastMinQueueSpace = 0;\r
1335 #endif\r
1336 UBaseType_t uxCurrentCount;\r
1337 BaseType_t xResult = 0;\r
1338 uint32_t xStatus;\r
1339 const TickType_t ulMaxBlockTime = pdMS_TO_TICKS( 100UL );\r
1340 \r
1341         /* Remove compiler warnings about unused parameters. */\r
1342         ( void ) pvParameters;\r
1343 \r
1344         vTaskSetTimeOutState( &xPhyTime );\r
1345         xPhyRemTime = pdMS_TO_TICKS( PHY_LS_LOW_CHECK_TIME_MS );\r
1346 \r
1347         for( ;; )\r
1348         {\r
1349                 uxCurrentCount = uxGetMinimumFreeNetworkBuffers();\r
1350                 if( uxLastMinBufferCount != uxCurrentCount )\r
1351                 {\r
1352                         /* The logging produced below may be helpful\r
1353                         while tuning +TCP: see how many buffers are in use. */\r
1354                         uxLastMinBufferCount = uxCurrentCount;\r
1355                         FreeRTOS_printf( ( "Network buffers: %lu lowest %lu\n",\r
1356                                 uxGetNumberOfFreeNetworkBuffers(), uxCurrentCount ) );\r
1357                 }\r
1358 \r
1359                 #if( ipconfigZERO_COPY_TX_DRIVER != 0 )\r
1360                 if( xTXDescriptorSemaphore != NULL )\r
1361                 {\r
1362                 static UBaseType_t uxLowestSemCount = ( UBaseType_t ) ETH_TXBUFNB - 1;\r
1363 \r
1364                         uxCurrentCount = uxSemaphoreGetCount( xTXDescriptorSemaphore );\r
1365                         if( uxLowestSemCount > uxCurrentCount )\r
1366                         {\r
1367                                 uxLowestSemCount = uxCurrentCount;\r
1368                                 FreeRTOS_printf( ( "TX DMA buffers: lowest %lu\n", uxLowestSemCount ) );\r
1369                         }\r
1370 \r
1371                 }\r
1372                 #endif\r
1373                 #if( ipconfigCHECK_IP_QUEUE_SPACE != 0 )\r
1374                 {\r
1375                         uxCurrentCount = uxGetMinimumIPQueueSpace();\r
1376                         if( uxLastMinQueueSpace != uxCurrentCount )\r
1377                         {\r
1378                                 /* The logging produced below may be helpful\r
1379                                 while tuning +TCP: see how many buffers are in use. */\r
1380                                 uxLastMinQueueSpace = uxCurrentCount;\r
1381                                 FreeRTOS_printf( ( "Queue space: lowest %lu\n", uxCurrentCount ) );\r
1382                         }\r
1383                 }\r
1384                 #endif /* ipconfigCHECK_IP_QUEUE_SPACE */\r
1385 \r
1386                 if( ( ulISREvents & EMAC_IF_ALL_EVENT ) == 0 )\r
1387                 {\r
1388                         /* No events to process now, wait for the next. */\r
1389                         ulTaskNotifyTake( pdFALSE, ulMaxBlockTime );\r
1390                 }\r
1391 \r
1392                 if( ( ulISREvents & EMAC_IF_RX_EVENT ) != 0 )\r
1393                 {\r
1394                         ulISREvents &= ~EMAC_IF_RX_EVENT;\r
1395 \r
1396                         xResult = prvNetworkInterfaceInput();\r
1397                         if( xResult > 0 )\r
1398                         {\r
1399                                 while( prvNetworkInterfaceInput() > 0 )\r
1400                                 {\r
1401                                 }\r
1402                         }\r
1403                 }\r
1404 \r
1405                 if( ( ulISREvents & EMAC_IF_TX_EVENT ) != 0 )\r
1406                 {\r
1407                         /* Code to release TX buffers if zero-copy is used. */\r
1408                         ulISREvents &= ~EMAC_IF_TX_EVENT;\r
1409                         #if( ipconfigZERO_COPY_TX_DRIVER != 0 )\r
1410                         {\r
1411                                 /* Check if DMA packets have been delivered. */\r
1412                                 vClearTXBuffers();\r
1413                         }\r
1414                         #endif\r
1415                 }\r
1416 \r
1417                 if( ( ulISREvents & EMAC_IF_ERR_EVENT ) != 0 )\r
1418                 {\r
1419                         /* Future extension: logging about errors that occurred. */\r
1420                         ulISREvents &= ~EMAC_IF_ERR_EVENT;\r
1421                 }\r
1422 \r
1423                 if( xResult > 0 )\r
1424                 {\r
1425                         /* A packet was received. No need to check for the PHY status now,\r
1426                         but set a timer to check it later on. */\r
1427                         vTaskSetTimeOutState( &xPhyTime );\r
1428                         xPhyRemTime = pdMS_TO_TICKS( PHY_LS_HIGH_CHECK_TIME_MS );\r
1429                         xResult = 0;\r
1430                 }\r
1431                 else if( xTaskCheckForTimeOut( &xPhyTime, &xPhyRemTime ) != pdFALSE )\r
1432                 {\r
1433                         HAL_ETH_ReadPHYRegister( &xETH, PHY_REG_01_BMSR, &xStatus );\r
1434                         if( ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != ( xStatus & BMSR_LINK_STATUS ) )\r
1435                         {\r
1436                                 ulPHYLinkStatus = xStatus;\r
1437                                 FreeRTOS_printf( ( "prvEMACHandlerTask: PHY LS now %d\n", ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != 0 ) );\r
1438                                 prvEthernetUpdateConfig( pdFALSE );\r
1439                         }\r
1440 \r
1441                         vTaskSetTimeOutState( &xPhyTime );\r
1442                         if( ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != 0 )\r
1443                         {\r
1444                                 xPhyRemTime = pdMS_TO_TICKS( PHY_LS_HIGH_CHECK_TIME_MS );\r
1445                         }\r
1446                         else\r
1447                         {\r
1448                                 xPhyRemTime = pdMS_TO_TICKS( PHY_LS_LOW_CHECK_TIME_MS );\r
1449                         }\r
1450                 }\r
1451         }\r
1452 }\r
1453 /*-----------------------------------------------------------*/\r
1454 \r
1455 void ETH_IRQHandler( void )\r
1456 {\r
1457         HAL_ETH_IRQHandler( &xETH );\r
1458 }\r