]> git.sur5r.net Git - freertos/blobdiff - FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/ATSAM4E/NetworkInterface.c
Update version number in readiness for V10.3.0 release. Sync SVN with reviewed releas...
[freertos] / FreeRTOS-Plus / Source / FreeRTOS-Plus-TCP / portable / NetworkInterface / ATSAM4E / NetworkInterface.c
index 83c96a07c078c448f34e6d632b0537eeaa342b70..3528269bdb908c29673e1a7e78ce9df880a03342 100644 (file)
-/*\r
-FreeRTOS+TCP V2.0.11\r
-Copyright (C) 2017 Amazon.com, Inc. or its affiliates.  All Rights Reserved.\r
-\r
-Permission is hereby granted, free of charge, to any person obtaining a copy of\r
-this software and associated documentation files (the "Software"), to deal in\r
-the Software without restriction, including without limitation the rights to\r
-use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\r
-the Software, and to permit persons to whom the Software is furnished to do so,\r
-subject to the following conditions:\r
-\r
-The above copyright notice and this permission notice shall be included in all\r
-copies or substantial portions of the Software.\r
-\r
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\r
-FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\r
-COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\r
-IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
-CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
-\r
- http://aws.amazon.com/freertos\r
- http://www.FreeRTOS.org\r
-*/\r
-\r
-/* Standard includes. */\r
-#include <stdint.h>\r
-#include <stdio.h>\r
-#include <stdlib.h>\r
-\r
-/* FreeRTOS includes. */\r
-#include "FreeRTOS.h"\r
-#include "task.h"\r
-#include "queue.h"\r
-#include "semphr.h"\r
-\r
-/* FreeRTOS+TCP includes. */\r
-#include "FreeRTOS_IP.h"\r
-#include "FreeRTOS_Sockets.h"\r
-#include "FreeRTOS_IP_Private.h"\r
-#include "NetworkBufferManagement.h"\r
-#include "NetworkInterface.h"\r
-\r
-/* Some files from the Atmel Software Framework */\r
-/*_RB_ The SAM4E portable layer has three different header files called gmac.h! */\r
-#include "instance/gmac.h"\r
-#include <sysclk.h>\r
-#include <ethernet_phy.h>\r
-\r
-#ifndef        BMSR_LINK_STATUS\r
-       #define BMSR_LINK_STATUS            0x0004  //!< Link status\r
-#endif\r
-\r
-#ifndef        PHY_LS_HIGH_CHECK_TIME_MS\r
-       /* Check if the LinkSStatus in the PHY is still high after 15 seconds of not\r
-       receiving packets. */\r
-       #define PHY_LS_HIGH_CHECK_TIME_MS       15000\r
-#endif\r
-\r
-#ifndef        PHY_LS_LOW_CHECK_TIME_MS\r
-       /* Check if the LinkSStatus in the PHY is still low every second. */\r
-       #define PHY_LS_LOW_CHECK_TIME_MS        1000\r
-#endif\r
-\r
-/* Interrupt events to process.  Currently only the Rx event is processed\r
-although code for other events is included to allow for possible future\r
-expansion. */\r
-#define EMAC_IF_RX_EVENT        1UL\r
-#define EMAC_IF_TX_EVENT        2UL\r
-#define EMAC_IF_ERR_EVENT       4UL\r
-#define EMAC_IF_ALL_EVENT       ( EMAC_IF_RX_EVENT | EMAC_IF_TX_EVENT | EMAC_IF_ERR_EVENT )\r
-\r
-#define ETHERNET_CONF_PHY_ADDR  BOARD_GMAC_PHY_ADDR\r
-\r
-#define HZ_PER_MHZ                             ( 1000000UL )\r
-\r
-#ifndef        EMAC_MAX_BLOCK_TIME_MS\r
-       #define EMAC_MAX_BLOCK_TIME_MS  100ul\r
-#endif\r
-\r
-#if !defined( GMAC_USES_TX_CALLBACK ) || ( GMAC_USES_TX_CALLBACK != 1 )\r
-       #error Please define GMAC_USES_TX_CALLBACK as 1\r
-#endif\r
-\r
-/* Default the size of the stack used by the EMAC deferred handler task to 4x\r
-the size of the stack used by the idle task - but allow this to be overridden in\r
-FreeRTOSConfig.h as configMINIMAL_STACK_SIZE is a user definable constant. */\r
-#ifndef configEMAC_TASK_STACK_SIZE\r
-       #define configEMAC_TASK_STACK_SIZE ( 4 * configMINIMAL_STACK_SIZE )\r
-#endif\r
-\r
-/*-----------------------------------------------------------*/\r
-\r
-/*\r
- * Wait a fixed time for the link status to indicate the network is up.\r
- */\r
-static BaseType_t xGMACWaitLS( TickType_t xMaxTime );\r
-\r
-#if( ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM == 1 ) && ( ipconfigHAS_TX_CRC_OFFLOADING == 0 )\r
-       void vGMACGenerateChecksum( uint8_t *apBuffer );\r
-#endif\r
-\r
-/*\r
- * Called from the ASF GMAC driver.\r
- */\r
-static void prvRxCallback( uint32_t ulStatus );\r
-static void prvTxCallback( uint32_t ulStatus, uint8_t *puc_buffer );\r
-\r
-/*\r
- * A deferred interrupt handler task that processes GMAC interrupts.\r
- */\r
-static void prvEMACHandlerTask( void *pvParameters );\r
-\r
-/*\r
- * Initialise the ASF GMAC driver.\r
- */\r
-static BaseType_t prvGMACInit( void );\r
-\r
-/*\r
- * Try to obtain an Rx packet from the hardware.\r
- */\r
-static uint32_t prvEMACRxPoll( void );\r
-\r
-/*-----------------------------------------------------------*/\r
-\r
-/* Bit map of outstanding ETH interrupt events for processing.  Currently only\r
-the Rx interrupt is handled, although code is included for other events to\r
-enable future expansion. */\r
-static volatile uint32_t ulISREvents;\r
-\r
-/* A copy of PHY register 1: 'PHY_REG_01_BMSR' */\r
-static uint32_t ulPHYLinkStatus = 0;\r
-static volatile BaseType_t xGMACSwitchRequired;\r
-\r
-/* ethernet_phy_addr: the address of the PHY in use.\r
-Atmel was a bit ambiguous about it so the address will be stored\r
-in this variable, see ethernet_phy.c */\r
-extern int ethernet_phy_addr;\r
-\r
-/* LLMNR multicast address. */\r
-static const uint8_t llmnr_mac_address[] = { 0x01, 0x00, 0x5E, 0x00, 0x00, 0xFC };\r
-\r
-/* The GMAC object as defined by the ASF drivers. */\r
-static gmac_device_t gs_gmac_dev;\r
-\r
-/* MAC address to use. */\r
-extern const uint8_t ucMACAddress[ 6 ];\r
-\r
-/* Holds the handle of the task used as a deferred interrupt processor.  The\r
-handle is used so direct notifications can be sent to the task for all EMAC/DMA\r
-related interrupts. */\r
-TaskHandle_t xEMACTaskHandle = NULL;\r
-\r
-static QueueHandle_t xTxBufferQueue;\r
-int tx_release_count[ 4 ];\r
-\r
-/* xTXDescriptorSemaphore is a counting semaphore with\r
-a maximum count of GMAC_TX_BUFFERS, which is the number of\r
-DMA TX descriptors. */\r
-static SemaphoreHandle_t xTXDescriptorSemaphore = NULL;\r
-\r
-/*-----------------------------------------------------------*/\r
-\r
-/*\r
- * GMAC interrupt handler.\r
- */\r
-void GMAC_Handler(void)\r
-{\r
-       xGMACSwitchRequired = pdFALSE;\r
-\r
-       /* gmac_handler() may call prvRxCallback() which may change\r
-       the value of xGMACSwitchRequired. */\r
-       gmac_handler( &gs_gmac_dev );\r
-\r
-       if( xGMACSwitchRequired != pdFALSE )\r
-       {\r
-               portEND_SWITCHING_ISR( xGMACSwitchRequired );\r
-       }\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-static void prvRxCallback( uint32_t ulStatus )\r
-{\r
-       if( ( ( ulStatus & GMAC_RSR_REC ) != 0 ) && ( xEMACTaskHandle != NULL ) )\r
-       {\r
-               /* let the prvEMACHandlerTask know that there was an RX event. */\r
-               ulISREvents |= EMAC_IF_RX_EVENT;\r
-               /* Only an RX interrupt can wakeup prvEMACHandlerTask. */\r
-               vTaskNotifyGiveFromISR( xEMACTaskHandle, ( BaseType_t * ) &xGMACSwitchRequired );\r
-       }\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-static void prvTxCallback( uint32_t ulStatus, uint8_t *puc_buffer )\r
-{\r
-       if( ( xTxBufferQueue != NULL ) && ( xEMACTaskHandle != NULL ) )\r
-       {\r
-               /* let the prvEMACHandlerTask know that there was an RX event. */\r
-               ulISREvents |= EMAC_IF_TX_EVENT;\r
-\r
-               vTaskNotifyGiveFromISR( xEMACTaskHandle, ( BaseType_t * ) &xGMACSwitchRequired );\r
-               xQueueSendFromISR( xTxBufferQueue, &puc_buffer, ( BaseType_t * ) &xGMACSwitchRequired );\r
-               tx_release_count[ 2 ]++;\r
-       }\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-BaseType_t xNetworkInterfaceInitialise( void )\r
-{\r
-const TickType_t x5_Seconds = 5000UL;\r
-\r
-       if( xEMACTaskHandle == NULL )\r
-       {\r
-               prvGMACInit();\r
-\r
-               /* Wait at most 5 seconds for a Link Status in the PHY. */\r
-               xGMACWaitLS( pdMS_TO_TICKS( x5_Seconds ) );\r
-\r
-               /* The handler task is created at the highest possible priority to\r
-               ensure the interrupt handler can return directly to it. */\r
-               xTaskCreate( prvEMACHandlerTask, "EMAC", configEMAC_TASK_STACK_SIZE, NULL, configMAX_PRIORITIES - 1, &xEMACTaskHandle );\r
-               configASSERT( xEMACTaskHandle );\r
-       }\r
-\r
-       if( xTxBufferQueue == NULL )\r
-       {\r
-               xTxBufferQueue = xQueueCreate( GMAC_TX_BUFFERS, sizeof( void * ) );\r
-               configASSERT( xTxBufferQueue );\r
-       }\r
-\r
-       if( xTXDescriptorSemaphore == NULL )\r
-       {\r
-               xTXDescriptorSemaphore = xSemaphoreCreateCounting( ( UBaseType_t ) GMAC_TX_BUFFERS, ( UBaseType_t ) GMAC_TX_BUFFERS );\r
-               configASSERT( xTXDescriptorSemaphore );\r
-       }\r
-       /* When returning non-zero, the stack will become active and\r
-    start DHCP (in configured) */\r
-       return ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != 0;\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-BaseType_t xGetPhyLinkStatus( void )\r
-{\r
-BaseType_t xResult;\r
-\r
-       /* This function returns true if the Link Status in the PHY is high. */\r
-       if( ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != 0 )\r
-       {\r
-               xResult = pdTRUE;\r
-       }\r
-       else\r
-       {\r
-               xResult = pdFALSE;\r
-       }\r
-\r
-       return xResult;\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-BaseType_t xNetworkInterfaceOutput( NetworkBufferDescriptor_t * const pxDescriptor, BaseType_t bReleaseAfterSend )\r
-{\r
-/* Do not wait too long for a free TX DMA buffer. */\r
-const TickType_t xBlockTimeTicks = pdMS_TO_TICKS( 50u );\r
-\r
-       do {\r
-               if( ( ulPHYLinkStatus & BMSR_LINK_STATUS ) == 0 )\r
-               {\r
-                       /* Do not attempt to send packets as long as the Link Status is low. */\r
-                       break;\r
-               }\r
-               if( xTXDescriptorSemaphore == NULL )\r
-               {\r
-                       /* Semaphore has not been created yet? */\r
-                       break;\r
-               }\r
-               if( xSemaphoreTake( xTXDescriptorSemaphore, xBlockTimeTicks ) != pdPASS )\r
-               {\r
-                       /* Time-out waiting for a free TX descriptor. */\r
-                       tx_release_count[ 3 ]++;\r
-                       break;\r
-               }\r
-               #if( ipconfigZERO_COPY_TX_DRIVER != 0 )\r
-               {\r
-                       /* Confirm that the pxDescriptor may be kept by the driver. */\r
-                       configASSERT( bReleaseAfterSend != pdFALSE );\r
-               }\r
-               #endif /* ipconfigZERO_COPY_TX_DRIVER */\r
-\r
-               gmac_dev_write( &gs_gmac_dev, (void *)pxDescriptor->pucEthernetBuffer, pxDescriptor->xDataLength, prvTxCallback );\r
-\r
-               #if( ipconfigZERO_COPY_TX_DRIVER != 0 )\r
-               {\r
-                       /* Confirm that the pxDescriptor may be kept by the driver. */\r
-                       bReleaseAfterSend = pdFALSE;\r
-               }\r
-               #endif /* ipconfigZERO_COPY_TX_DRIVER */\r
-               /* Not interested in a call-back after TX. */\r
-               iptraceNETWORK_INTERFACE_TRANSMIT();\r
-       } while( 0 );\r
-\r
-       if( bReleaseAfterSend != pdFALSE )\r
-       {\r
-               vReleaseNetworkBufferAndDescriptor( pxDescriptor );\r
-       }\r
-       return pdTRUE;\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-static BaseType_t prvGMACInit( void )\r
-{\r
-uint32_t ncfgr;\r
-\r
-       gmac_options_t gmac_option;\r
-\r
-       memset( &gmac_option, '\0', sizeof( gmac_option ) );\r
-       gmac_option.uc_copy_all_frame = 0;\r
-       gmac_option.uc_no_boardcast = 0;\r
-       memcpy( gmac_option.uc_mac_addr, ucMACAddress, sizeof( gmac_option.uc_mac_addr ) );\r
-\r
-       gs_gmac_dev.p_hw = GMAC;\r
-       gmac_dev_init( GMAC, &gs_gmac_dev, &gmac_option );\r
-\r
-       NVIC_SetPriority( GMAC_IRQn, configMAC_INTERRUPT_PRIORITY );\r
-       NVIC_EnableIRQ( GMAC_IRQn );\r
-\r
-       /* Contact the Ethernet PHY and store it's address in 'ethernet_phy_addr' */\r
-       ethernet_phy_init( GMAC, ETHERNET_CONF_PHY_ADDR, sysclk_get_cpu_hz() );\r
-\r
-       ethernet_phy_auto_negotiate( GMAC, ethernet_phy_addr );\r
-       ethernet_phy_set_link( GMAC, ethernet_phy_addr, 1 );\r
-\r
-       /* The GMAC driver will call a hook prvRxCallback(), which\r
-       in turn will wake-up the task by calling vTaskNotifyGiveFromISR() */\r
-       gmac_dev_set_rx_callback( &gs_gmac_dev, prvRxCallback );\r
-       gmac_set_address( GMAC, 1, (uint8_t*)llmnr_mac_address );\r
-\r
-       ncfgr = GMAC_NCFGR_SPD | GMAC_NCFGR_FD;\r
-\r
-       GMAC->GMAC_NCFGR = ( GMAC->GMAC_NCFGR & ~( GMAC_NCFGR_SPD | GMAC_NCFGR_FD ) ) | ncfgr;\r
-\r
-       return 1;\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-static inline unsigned long ulReadMDIO( unsigned /*short*/ usAddress )\r
-{\r
-uint32_t ulValue, ulReturn;\r
-int rc;\r
-\r
-       gmac_enable_management( GMAC, 1 );\r
-       rc = gmac_phy_read( GMAC, ethernet_phy_addr, usAddress, &ulValue );\r
-       gmac_enable_management( GMAC, 0 );\r
-       if( rc == GMAC_OK )\r
-       {\r
-               ulReturn = ulValue;\r
-       }\r
-       else\r
-       {\r
-               ulReturn = 0UL;\r
-       }\r
-\r
-       return ulReturn;\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-static BaseType_t xGMACWaitLS( TickType_t xMaxTime )\r
-{\r
-TickType_t xStartTime = xTaskGetTickCount();\r
-TickType_t xEndTime;\r
-BaseType_t xReturn;\r
-const TickType_t xShortTime = pdMS_TO_TICKS( 100UL );\r
-\r
-       for( ;; )\r
-       {\r
-               xEndTime = xTaskGetTickCount();\r
-\r
-               if( ( xEndTime - xStartTime ) > xMaxTime )\r
-               {\r
-                       /* Wated more than xMaxTime, return. */\r
-                       xReturn = pdFALSE;\r
-                       break;\r
-               }\r
-\r
-               /* Check the link status again. */\r
-               ulPHYLinkStatus = ulReadMDIO( PHY_REG_01_BMSR );\r
-\r
-               if( ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != 0 )\r
-               {\r
-                       /* Link is up - return. */\r
-                       xReturn = pdTRUE;\r
-                       break;\r
-               }\r
-\r
-               /* Link is down - wait in the Blocked state for a short while (to allow\r
-               other tasks to execute) before checking again. */\r
-               vTaskDelay( xShortTime );\r
-       }\r
-\r
-       FreeRTOS_printf( ( "xGMACWaitLS: %ld (PHY %d) freq %lu Mz\n",\r
-               xReturn,\r
-               ethernet_phy_addr,\r
-               sysclk_get_cpu_hz() / HZ_PER_MHZ ) );\r
-\r
-       return xReturn;\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-//#if( ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM == 1 ) && ( ipconfigHAS_TX_CRC_OFFLOADING == 0 )\r
-\r
-       void vGMACGenerateChecksum( uint8_t *apBuffer )\r
-       {\r
-       ProtocolPacket_t *xProtPacket = (ProtocolPacket_t *)apBuffer;\r
-\r
-               if ( xProtPacket->xTCPPacket.xEthernetHeader.usFrameType == ipIPv4_FRAME_TYPE )\r
-               {\r
-                       IPHeader_t *pxIPHeader = &(xProtPacket->xTCPPacket.xIPHeader);\r
-\r
-                       /* Calculate the IP header checksum. */\r
-                       pxIPHeader->usHeaderChecksum = 0x00;\r
-                       pxIPHeader->usHeaderChecksum = usGenerateChecksum( 0, ( uint8_t * ) &( pxIPHeader->ucVersionHeaderLength ), ipSIZE_OF_IPv4_HEADER );\r
-                       pxIPHeader->usHeaderChecksum = ~FreeRTOS_htons( pxIPHeader->usHeaderChecksum );\r
-\r
-                       /* Calculate the TCP checksum for an outgoing packet. */\r
-                       usGenerateProtocolChecksum( ( uint8_t * ) apBuffer, pdTRUE );\r
-               }\r
-       }\r
-\r
-//#endif\r
-/*-----------------------------------------------------------*/\r
-\r
-static uint32_t prvEMACRxPoll( void )\r
-{\r
-unsigned char *pucUseBuffer;\r
-uint32_t ulReceiveCount, ulResult, ulReturnValue = 0;\r
-static NetworkBufferDescriptor_t *pxNextNetworkBufferDescriptor = NULL;\r
-const UBaseType_t xMinDescriptorsToLeave = 2UL;\r
-const TickType_t xBlockTime = pdMS_TO_TICKS( 100UL );\r
-static IPStackEvent_t xRxEvent = { eNetworkRxEvent, NULL };\r
-\r
-       for( ;; )\r
-       {\r
-               /* If pxNextNetworkBufferDescriptor was not left pointing at a valid\r
-               descriptor then allocate one now. */\r
-               if( ( pxNextNetworkBufferDescriptor == NULL ) && ( uxGetNumberOfFreeNetworkBuffers() > xMinDescriptorsToLeave ) )\r
-               {\r
-                       pxNextNetworkBufferDescriptor = pxGetNetworkBufferWithDescriptor( ipTOTAL_ETHERNET_FRAME_SIZE, xBlockTime );\r
-               }\r
-\r
-               if( pxNextNetworkBufferDescriptor != NULL )\r
-               {\r
-                       /* Point pucUseBuffer to the buffer pointed to by the descriptor. */\r
-                       pucUseBuffer = ( unsigned char* ) ( pxNextNetworkBufferDescriptor->pucEthernetBuffer - ipconfigPACKET_FILLER_SIZE );\r
-               }\r
-               else\r
-               {\r
-                       /* As long as pxNextNetworkBufferDescriptor is NULL, the incoming\r
-                       messages will be flushed and ignored. */\r
-                       pucUseBuffer = NULL;\r
-               }\r
-\r
-               /* Read the next packet from the hardware into pucUseBuffer. */\r
-               ulResult = gmac_dev_read( &gs_gmac_dev, pucUseBuffer, ipTOTAL_ETHERNET_FRAME_SIZE, &ulReceiveCount );\r
-\r
-               if( ( ulResult != GMAC_OK ) || ( ulReceiveCount == 0 ) )\r
-               {\r
-                       /* No data from the hardware. */\r
-                       break;\r
-               }\r
-\r
-               if( pxNextNetworkBufferDescriptor == NULL )\r
-               {\r
-                       /* Data was read from the hardware, but no descriptor was available\r
-                       for it, so it will be dropped. */\r
-                       iptraceETHERNET_RX_EVENT_LOST();\r
-                       continue;\r
-               }\r
-\r
-               iptraceNETWORK_INTERFACE_RECEIVE();\r
-               pxNextNetworkBufferDescriptor->xDataLength = ( size_t ) ulReceiveCount;\r
-               xRxEvent.pvData = ( void * ) pxNextNetworkBufferDescriptor;\r
-\r
-               /* Send the descriptor to the IP task for processing. */\r
-               if( xSendEventStructToIPTask( &xRxEvent, xBlockTime ) != pdTRUE )\r
-               {\r
-                       /* The buffer could not be sent to the stack so must be released\r
-                       again. */\r
-                       vReleaseNetworkBufferAndDescriptor( pxNextNetworkBufferDescriptor );\r
-                       iptraceETHERNET_RX_EVENT_LOST();\r
-                       FreeRTOS_printf( ( "prvEMACRxPoll: Can not queue return packet!\n" ) );\r
-               }\r
-\r
-               /* Now the buffer has either been passed to the IP-task,\r
-               or it has been released in the code above. */\r
-               pxNextNetworkBufferDescriptor = NULL;\r
-               ulReturnValue++;\r
-       }\r
-\r
-       return ulReturnValue;\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-static void prvEMACHandlerTask( void *pvParameters )\r
-{\r
-TimeOut_t xPhyTime;\r
-TickType_t xPhyRemTime;\r
-UBaseType_t uxLastMinBufferCount = 0, uxCount;\r
-UBaseType_t uxCurrentCount;\r
-#if( ipconfigCHECK_IP_QUEUE_SPACE != 0 )\r
-       UBaseType_t uxLastMinQueueSpace;\r
-#endif\r
-#if( ipconfigZERO_COPY_TX_DRIVER != 0 )\r
-       NetworkBufferDescriptor_t *pxBuffer;\r
-#endif\r
-uint8_t *pucBuffer;\r
-BaseType_t xResult = 0;\r
-uint32_t xStatus;\r
-const TickType_t ulMaxBlockTime = pdMS_TO_TICKS( EMAC_MAX_BLOCK_TIME_MS );\r
-\r
-       /* Remove compiler warnings about unused parameters. */\r
-       ( void ) pvParameters;\r
-\r
-       configASSERT( xEMACTaskHandle );\r
-\r
-       vTaskSetTimeOutState( &xPhyTime );\r
-       xPhyRemTime = pdMS_TO_TICKS( PHY_LS_LOW_CHECK_TIME_MS );\r
-\r
-       for( ;; )\r
-       {\r
-               uxCurrentCount = uxGetMinimumFreeNetworkBuffers();\r
-               if( uxLastMinBufferCount != uxCurrentCount )\r
-               {\r
-                       /* The logging produced below may be helpful\r
-                       while tuning +TCP: see how many buffers are in use. */\r
-                       uxLastMinBufferCount = uxCurrentCount;\r
-                       FreeRTOS_printf( ( "Network buffers: %lu lowest %lu\n",\r
-                               uxGetNumberOfFreeNetworkBuffers(), uxCurrentCount ) );\r
-               }\r
-\r
-               #if( ipconfigCHECK_IP_QUEUE_SPACE != 0 )\r
-               {\r
-                       uxCurrentCount = uxGetMinimumIPQueueSpace();\r
-                       if( uxLastMinQueueSpace != uxCurrentCount )\r
-                       {\r
-                               /* The logging produced below may be helpful\r
-                               while tuning +TCP: see how many buffers are in use. */\r
-                               uxLastMinQueueSpace = uxCurrentCount;\r
-                               FreeRTOS_printf( ( "Queue space: lowest %lu\n", uxCurrentCount ) );\r
-                       }\r
-               }\r
-               #endif /* ipconfigCHECK_IP_QUEUE_SPACE */\r
-\r
-               if( ( ulISREvents & EMAC_IF_ALL_EVENT ) == 0 )\r
-               {\r
-                       /* No events to process now, wait for the next. */\r
-                       ulTaskNotifyTake( pdFALSE, ulMaxBlockTime );\r
-               }\r
-\r
-               if( ( ulISREvents & EMAC_IF_RX_EVENT ) != 0 )\r
-               {\r
-                       ulISREvents &= ~EMAC_IF_RX_EVENT;\r
-\r
-                       /* Wait for the EMAC interrupt to indicate that another packet has been\r
-                       received. */\r
-                       xResult = prvEMACRxPoll();\r
-               }\r
-\r
-               if( ( ulISREvents & EMAC_IF_TX_EVENT ) != 0 )\r
-               {\r
-                       /* Future extension: code to release TX buffers if zero-copy is used. */\r
-                       ulISREvents &= ~EMAC_IF_TX_EVENT;\r
-                       while( xQueueReceive( xTxBufferQueue, &pucBuffer, 0 ) != pdFALSE )\r
-                       {\r
-                               #if( ipconfigZERO_COPY_TX_DRIVER != 0 )\r
-                               {\r
-                                       pxBuffer = pxPacketBuffer_to_NetworkBuffer( pucBuffer );\r
-                                       if( pxBuffer != NULL )\r
-                                       {\r
-                                               vReleaseNetworkBufferAndDescriptor( pxBuffer );\r
-                                               tx_release_count[ 0 ]++;\r
-                                       }\r
-                                       else\r
-                                       {\r
-                                               tx_release_count[ 1 ]++;\r
-                                       }\r
-                               }\r
-                               #else\r
-                               {\r
-                                       tx_release_count[ 0 ]++;\r
-                               }\r
-                               #endif\r
-                               uxCount = uxQueueMessagesWaiting( ( QueueHandle_t ) xTXDescriptorSemaphore );\r
-                               if( uxCount < GMAC_TX_BUFFERS )\r
-                               {\r
-                                       /* Tell the counting semaphore that one more TX descriptor is available. */\r
-                                       xSemaphoreGive( xTXDescriptorSemaphore );\r
-                               }\r
-                       }\r
-               }\r
-\r
-               if( ( ulISREvents & EMAC_IF_ERR_EVENT ) != 0 )\r
-               {\r
-                       /* Future extension: logging about errors that occurred. */\r
-                       ulISREvents &= ~EMAC_IF_ERR_EVENT;\r
-               }\r
-\r
-               if( xResult > 0 )\r
-               {\r
-                       /* A packet was received. No need to check for the PHY status now,\r
-                       but set a timer to check it later on. */\r
-                       vTaskSetTimeOutState( &xPhyTime );\r
-                       xPhyRemTime = pdMS_TO_TICKS( PHY_LS_HIGH_CHECK_TIME_MS );\r
-                       xResult = 0;\r
-               }\r
-               else if( xTaskCheckForTimeOut( &xPhyTime, &xPhyRemTime ) != pdFALSE )\r
-               {\r
-                       /* Check the link status again. */\r
-                       xStatus = ulReadMDIO( PHY_REG_01_BMSR );\r
-\r
-                       if( ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != ( xStatus & BMSR_LINK_STATUS ) )\r
-                       {\r
-                               ulPHYLinkStatus = xStatus;\r
-                               FreeRTOS_printf( ( "prvEMACHandlerTask: PHY LS now %d\n", ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != 0 ) );\r
-                       }\r
-\r
-                       vTaskSetTimeOutState( &xPhyTime );\r
-                       if( ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != 0 )\r
-                       {\r
-                               xPhyRemTime = pdMS_TO_TICKS( PHY_LS_HIGH_CHECK_TIME_MS );\r
-                       }\r
-                       else\r
-                       {\r
-                               xPhyRemTime = pdMS_TO_TICKS( PHY_LS_LOW_CHECK_TIME_MS );\r
-                       }\r
-               }\r
-       }\r
-}\r
-/*-----------------------------------------------------------*/\r
+/*
+FreeRTOS+TCP V2.0.11
+Copyright (C) 2017 Amazon.com, Inc. or its affiliates.  All Rights Reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software is furnished to do so,
+subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+ http://aws.amazon.com/freertos
+ http://www.FreeRTOS.org
+*/
+
+/* Standard includes. */
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+/* FreeRTOS includes. */
+#include "FreeRTOS.h"
+#include "task.h"
+#include "queue.h"
+#include "semphr.h"
+
+/* FreeRTOS+TCP includes. */
+#include "FreeRTOS_IP.h"
+#include "FreeRTOS_Sockets.h"
+#include "FreeRTOS_IP_Private.h"
+#include "NetworkBufferManagement.h"
+#include "NetworkInterface.h"
+
+/* Some files from the Atmel Software Framework */
+/*_RB_ The SAM4E portable layer has three different header files called gmac.h! */
+#include "instance/gmac.h"
+#include <sysclk.h>
+#include <ethernet_phy.h>
+
+#ifndef        BMSR_LINK_STATUS
+       #define BMSR_LINK_STATUS            0x0004  //!< Link status
+#endif
+
+#ifndef        PHY_LS_HIGH_CHECK_TIME_MS
+       /* Check if the LinkSStatus in the PHY is still high after 15 seconds of not
+       receiving packets. */
+       #define PHY_LS_HIGH_CHECK_TIME_MS       15000
+#endif
+
+#ifndef        PHY_LS_LOW_CHECK_TIME_MS
+       /* Check if the LinkSStatus in the PHY is still low every second. */
+       #define PHY_LS_LOW_CHECK_TIME_MS        1000
+#endif
+
+/* Interrupt events to process.  Currently only the Rx event is processed
+although code for other events is included to allow for possible future
+expansion. */
+#define EMAC_IF_RX_EVENT        1UL
+#define EMAC_IF_TX_EVENT        2UL
+#define EMAC_IF_ERR_EVENT       4UL
+#define EMAC_IF_ALL_EVENT       ( EMAC_IF_RX_EVENT | EMAC_IF_TX_EVENT | EMAC_IF_ERR_EVENT )
+
+#define ETHERNET_CONF_PHY_ADDR  BOARD_GMAC_PHY_ADDR
+
+#define HZ_PER_MHZ                             ( 1000000UL )
+
+#ifndef        EMAC_MAX_BLOCK_TIME_MS
+       #define EMAC_MAX_BLOCK_TIME_MS  100ul
+#endif
+
+#if !defined( GMAC_USES_TX_CALLBACK ) || ( GMAC_USES_TX_CALLBACK != 1 )
+       #error Please define GMAC_USES_TX_CALLBACK as 1
+#endif
+
+/* Default the size of the stack used by the EMAC deferred handler task to 4x
+the size of the stack used by the idle task - but allow this to be overridden in
+FreeRTOSConfig.h as configMINIMAL_STACK_SIZE is a user definable constant. */
+#ifndef configEMAC_TASK_STACK_SIZE
+       #define configEMAC_TASK_STACK_SIZE ( 4 * configMINIMAL_STACK_SIZE )
+#endif
+
+/*-----------------------------------------------------------*/
+
+/*
+ * Wait a fixed time for the link status to indicate the network is up.
+ */
+static BaseType_t xGMACWaitLS( TickType_t xMaxTime );
+
+#if( ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM == 1 ) && ( ipconfigHAS_TX_CRC_OFFLOADING == 0 )
+       void vGMACGenerateChecksum( uint8_t *apBuffer );
+#endif
+
+/*
+ * Called from the ASF GMAC driver.
+ */
+static void prvRxCallback( uint32_t ulStatus );
+static void prvTxCallback( uint32_t ulStatus, uint8_t *puc_buffer );
+
+/*
+ * A deferred interrupt handler task that processes GMAC interrupts.
+ */
+static void prvEMACHandlerTask( void *pvParameters );
+
+/*
+ * Initialise the ASF GMAC driver.
+ */
+static BaseType_t prvGMACInit( void );
+
+/*
+ * Try to obtain an Rx packet from the hardware.
+ */
+static uint32_t prvEMACRxPoll( void );
+
+/*-----------------------------------------------------------*/
+
+/* Bit map of outstanding ETH interrupt events for processing.  Currently only
+the Rx interrupt is handled, although code is included for other events to
+enable future expansion. */
+static volatile uint32_t ulISREvents;
+
+/* A copy of PHY register 1: 'PHY_REG_01_BMSR' */
+static uint32_t ulPHYLinkStatus = 0;
+static volatile BaseType_t xGMACSwitchRequired;
+
+/* ethernet_phy_addr: the address of the PHY in use.
+Atmel was a bit ambiguous about it so the address will be stored
+in this variable, see ethernet_phy.c */
+extern int ethernet_phy_addr;
+
+/* LLMNR multicast address. */
+static const uint8_t llmnr_mac_address[] = { 0x01, 0x00, 0x5E, 0x00, 0x00, 0xFC };
+
+/* The GMAC object as defined by the ASF drivers. */
+static gmac_device_t gs_gmac_dev;
+
+/* MAC address to use. */
+extern const uint8_t ucMACAddress[ 6 ];
+
+/* Holds the handle of the task used as a deferred interrupt processor.  The
+handle is used so direct notifications can be sent to the task for all EMAC/DMA
+related interrupts. */
+TaskHandle_t xEMACTaskHandle = NULL;
+
+static QueueHandle_t xTxBufferQueue;
+int tx_release_count[ 4 ];
+
+/* xTXDescriptorSemaphore is a counting semaphore with
+a maximum count of GMAC_TX_BUFFERS, which is the number of
+DMA TX descriptors. */
+static SemaphoreHandle_t xTXDescriptorSemaphore = NULL;
+
+/*-----------------------------------------------------------*/
+
+/*
+ * GMAC interrupt handler.
+ */
+void GMAC_Handler(void)
+{
+       xGMACSwitchRequired = pdFALSE;
+
+       /* gmac_handler() may call prvRxCallback() which may change
+       the value of xGMACSwitchRequired. */
+       gmac_handler( &gs_gmac_dev );
+
+       if( xGMACSwitchRequired != pdFALSE )
+       {
+               portEND_SWITCHING_ISR( xGMACSwitchRequired );
+       }
+}
+/*-----------------------------------------------------------*/
+
+static void prvRxCallback( uint32_t ulStatus )
+{
+       if( ( ( ulStatus & GMAC_RSR_REC ) != 0 ) && ( xEMACTaskHandle != NULL ) )
+       {
+               /* let the prvEMACHandlerTask know that there was an RX event. */
+               ulISREvents |= EMAC_IF_RX_EVENT;
+               /* Only an RX interrupt can wakeup prvEMACHandlerTask. */
+               vTaskNotifyGiveFromISR( xEMACTaskHandle, ( BaseType_t * ) &xGMACSwitchRequired );
+       }
+}
+/*-----------------------------------------------------------*/
+
+static void prvTxCallback( uint32_t ulStatus, uint8_t *puc_buffer )
+{
+       if( ( xTxBufferQueue != NULL ) && ( xEMACTaskHandle != NULL ) )
+       {
+               /* let the prvEMACHandlerTask know that there was an RX event. */
+               ulISREvents |= EMAC_IF_TX_EVENT;
+
+               vTaskNotifyGiveFromISR( xEMACTaskHandle, ( BaseType_t * ) &xGMACSwitchRequired );
+               xQueueSendFromISR( xTxBufferQueue, &puc_buffer, ( BaseType_t * ) &xGMACSwitchRequired );
+               tx_release_count[ 2 ]++;
+       }
+}
+/*-----------------------------------------------------------*/
+
+BaseType_t xNetworkInterfaceInitialise( void )
+{
+const TickType_t x5_Seconds = 5000UL;
+
+       if( xEMACTaskHandle == NULL )
+       {
+               prvGMACInit();
+
+               /* Wait at most 5 seconds for a Link Status in the PHY. */
+               xGMACWaitLS( pdMS_TO_TICKS( x5_Seconds ) );
+
+               /* The handler task is created at the highest possible priority to
+               ensure the interrupt handler can return directly to it. */
+               xTaskCreate( prvEMACHandlerTask, "EMAC", configEMAC_TASK_STACK_SIZE, NULL, configMAX_PRIORITIES - 1, &xEMACTaskHandle );
+               configASSERT( xEMACTaskHandle );
+       }
+
+       if( xTxBufferQueue == NULL )
+       {
+               xTxBufferQueue = xQueueCreate( GMAC_TX_BUFFERS, sizeof( void * ) );
+               configASSERT( xTxBufferQueue );
+       }
+
+       if( xTXDescriptorSemaphore == NULL )
+       {
+               xTXDescriptorSemaphore = xSemaphoreCreateCounting( ( UBaseType_t ) GMAC_TX_BUFFERS, ( UBaseType_t ) GMAC_TX_BUFFERS );
+               configASSERT( xTXDescriptorSemaphore );
+       }
+       /* When returning non-zero, the stack will become active and
+    start DHCP (in configured) */
+       return ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != 0;
+}
+/*-----------------------------------------------------------*/
+
+BaseType_t xGetPhyLinkStatus( void )
+{
+BaseType_t xResult;
+
+       /* This function returns true if the Link Status in the PHY is high. */
+       if( ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != 0 )
+       {
+               xResult = pdTRUE;
+       }
+       else
+       {
+               xResult = pdFALSE;
+       }
+
+       return xResult;
+}
+/*-----------------------------------------------------------*/
+
+BaseType_t xNetworkInterfaceOutput( NetworkBufferDescriptor_t * const pxDescriptor, BaseType_t bReleaseAfterSend )
+{
+/* Do not wait too long for a free TX DMA buffer. */
+const TickType_t xBlockTimeTicks = pdMS_TO_TICKS( 50u );
+
+       do {
+               if( ( ulPHYLinkStatus & BMSR_LINK_STATUS ) == 0 )
+               {
+                       /* Do not attempt to send packets as long as the Link Status is low. */
+                       break;
+               }
+               if( xTXDescriptorSemaphore == NULL )
+               {
+                       /* Semaphore has not been created yet? */
+                       break;
+               }
+               if( xSemaphoreTake( xTXDescriptorSemaphore, xBlockTimeTicks ) != pdPASS )
+               {
+                       /* Time-out waiting for a free TX descriptor. */
+                       tx_release_count[ 3 ]++;
+                       break;
+               }
+               #if( ipconfigZERO_COPY_TX_DRIVER != 0 )
+               {
+                       /* Confirm that the pxDescriptor may be kept by the driver. */
+                       configASSERT( bReleaseAfterSend != pdFALSE );
+               }
+               #endif /* ipconfigZERO_COPY_TX_DRIVER */
+
+               gmac_dev_write( &gs_gmac_dev, (void *)pxDescriptor->pucEthernetBuffer, pxDescriptor->xDataLength, prvTxCallback );
+
+               #if( ipconfigZERO_COPY_TX_DRIVER != 0 )
+               {
+                       /* Confirm that the pxDescriptor may be kept by the driver. */
+                       bReleaseAfterSend = pdFALSE;
+               }
+               #endif /* ipconfigZERO_COPY_TX_DRIVER */
+               /* Not interested in a call-back after TX. */
+               iptraceNETWORK_INTERFACE_TRANSMIT();
+       } while( 0 );
+
+       if( bReleaseAfterSend != pdFALSE )
+       {
+               vReleaseNetworkBufferAndDescriptor( pxDescriptor );
+       }
+       return pdTRUE;
+}
+/*-----------------------------------------------------------*/
+
+static BaseType_t prvGMACInit( void )
+{
+uint32_t ncfgr;
+
+       gmac_options_t gmac_option;
+
+       memset( &gmac_option, '\0', sizeof( gmac_option ) );
+       gmac_option.uc_copy_all_frame = 0;
+       gmac_option.uc_no_boardcast = 0;
+       memcpy( gmac_option.uc_mac_addr, ucMACAddress, sizeof( gmac_option.uc_mac_addr ) );
+
+       gs_gmac_dev.p_hw = GMAC;
+       gmac_dev_init( GMAC, &gs_gmac_dev, &gmac_option );
+
+       NVIC_SetPriority( GMAC_IRQn, configMAC_INTERRUPT_PRIORITY );
+       NVIC_EnableIRQ( GMAC_IRQn );
+
+       /* Contact the Ethernet PHY and store it's address in 'ethernet_phy_addr' */
+       ethernet_phy_init( GMAC, ETHERNET_CONF_PHY_ADDR, sysclk_get_cpu_hz() );
+
+       ethernet_phy_auto_negotiate( GMAC, ethernet_phy_addr );
+       ethernet_phy_set_link( GMAC, ethernet_phy_addr, 1 );
+
+       /* The GMAC driver will call a hook prvRxCallback(), which
+       in turn will wake-up the task by calling vTaskNotifyGiveFromISR() */
+       gmac_dev_set_rx_callback( &gs_gmac_dev, prvRxCallback );
+       gmac_set_address( GMAC, 1, (uint8_t*)llmnr_mac_address );
+
+       ncfgr = GMAC_NCFGR_SPD | GMAC_NCFGR_FD;
+
+       GMAC->GMAC_NCFGR = ( GMAC->GMAC_NCFGR & ~( GMAC_NCFGR_SPD | GMAC_NCFGR_FD ) ) | ncfgr;
+
+       return 1;
+}
+/*-----------------------------------------------------------*/
+
+static inline unsigned long ulReadMDIO( unsigned /*short*/ usAddress )
+{
+uint32_t ulValue, ulReturn;
+int rc;
+
+       gmac_enable_management( GMAC, 1 );
+       rc = gmac_phy_read( GMAC, ethernet_phy_addr, usAddress, &ulValue );
+       gmac_enable_management( GMAC, 0 );
+       if( rc == GMAC_OK )
+       {
+               ulReturn = ulValue;
+       }
+       else
+       {
+               ulReturn = 0UL;
+       }
+
+       return ulReturn;
+}
+/*-----------------------------------------------------------*/
+
+static BaseType_t xGMACWaitLS( TickType_t xMaxTime )
+{
+TickType_t xStartTime = xTaskGetTickCount();
+TickType_t xEndTime;
+BaseType_t xReturn;
+const TickType_t xShortTime = pdMS_TO_TICKS( 100UL );
+
+       for( ;; )
+       {
+               xEndTime = xTaskGetTickCount();
+
+               if( ( xEndTime - xStartTime ) > xMaxTime )
+               {
+                       /* Wated more than xMaxTime, return. */
+                       xReturn = pdFALSE;
+                       break;
+               }
+
+               /* Check the link status again. */
+               ulPHYLinkStatus = ulReadMDIO( PHY_REG_01_BMSR );
+
+               if( ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != 0 )
+               {
+                       /* Link is up - return. */
+                       xReturn = pdTRUE;
+                       break;
+               }
+
+               /* Link is down - wait in the Blocked state for a short while (to allow
+               other tasks to execute) before checking again. */
+               vTaskDelay( xShortTime );
+       }
+
+       FreeRTOS_printf( ( "xGMACWaitLS: %ld (PHY %d) freq %lu Mz\n",
+               xReturn,
+               ethernet_phy_addr,
+               sysclk_get_cpu_hz() / HZ_PER_MHZ ) );
+
+       return xReturn;
+}
+/*-----------------------------------------------------------*/
+
+//#if( ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM == 1 ) && ( ipconfigHAS_TX_CRC_OFFLOADING == 0 )
+
+       void vGMACGenerateChecksum( uint8_t *apBuffer )
+       {
+       ProtocolPacket_t *xProtPacket = (ProtocolPacket_t *)apBuffer;
+
+               if ( xProtPacket->xTCPPacket.xEthernetHeader.usFrameType == ipIPv4_FRAME_TYPE )
+               {
+                       IPHeader_t *pxIPHeader = &(xProtPacket->xTCPPacket.xIPHeader);
+
+                       /* Calculate the IP header checksum. */
+                       pxIPHeader->usHeaderChecksum = 0x00;
+                       pxIPHeader->usHeaderChecksum = usGenerateChecksum( 0, ( uint8_t * ) &( pxIPHeader->ucVersionHeaderLength ), ipSIZE_OF_IPv4_HEADER );
+                       pxIPHeader->usHeaderChecksum = ~FreeRTOS_htons( pxIPHeader->usHeaderChecksum );
+
+                       /* Calculate the TCP checksum for an outgoing packet. */
+                       usGenerateProtocolChecksum( ( uint8_t * ) apBuffer, pdTRUE );
+               }
+       }
+
+//#endif
+/*-----------------------------------------------------------*/
+
+static uint32_t prvEMACRxPoll( void )
+{
+unsigned char *pucUseBuffer;
+uint32_t ulReceiveCount, ulResult, ulReturnValue = 0;
+static NetworkBufferDescriptor_t *pxNextNetworkBufferDescriptor = NULL;
+const UBaseType_t xMinDescriptorsToLeave = 2UL;
+const TickType_t xBlockTime = pdMS_TO_TICKS( 100UL );
+static IPStackEvent_t xRxEvent = { eNetworkRxEvent, NULL };
+
+       for( ;; )
+       {
+               /* If pxNextNetworkBufferDescriptor was not left pointing at a valid
+               descriptor then allocate one now. */
+               if( ( pxNextNetworkBufferDescriptor == NULL ) && ( uxGetNumberOfFreeNetworkBuffers() > xMinDescriptorsToLeave ) )
+               {
+                       pxNextNetworkBufferDescriptor = pxGetNetworkBufferWithDescriptor( ipTOTAL_ETHERNET_FRAME_SIZE, xBlockTime );
+               }
+
+               if( pxNextNetworkBufferDescriptor != NULL )
+               {
+                       /* Point pucUseBuffer to the buffer pointed to by the descriptor. */
+                       pucUseBuffer = ( unsigned char* ) ( pxNextNetworkBufferDescriptor->pucEthernetBuffer - ipconfigPACKET_FILLER_SIZE );
+               }
+               else
+               {
+                       /* As long as pxNextNetworkBufferDescriptor is NULL, the incoming
+                       messages will be flushed and ignored. */
+                       pucUseBuffer = NULL;
+               }
+
+               /* Read the next packet from the hardware into pucUseBuffer. */
+               ulResult = gmac_dev_read( &gs_gmac_dev, pucUseBuffer, ipTOTAL_ETHERNET_FRAME_SIZE, &ulReceiveCount );
+
+               if( ( ulResult != GMAC_OK ) || ( ulReceiveCount == 0 ) )
+               {
+                       /* No data from the hardware. */
+                       break;
+               }
+
+               if( pxNextNetworkBufferDescriptor == NULL )
+               {
+                       /* Data was read from the hardware, but no descriptor was available
+                       for it, so it will be dropped. */
+                       iptraceETHERNET_RX_EVENT_LOST();
+                       continue;
+               }
+
+               iptraceNETWORK_INTERFACE_RECEIVE();
+               pxNextNetworkBufferDescriptor->xDataLength = ( size_t ) ulReceiveCount;
+               xRxEvent.pvData = ( void * ) pxNextNetworkBufferDescriptor;
+
+               /* Send the descriptor to the IP task for processing. */
+               if( xSendEventStructToIPTask( &xRxEvent, xBlockTime ) != pdTRUE )
+               {
+                       /* The buffer could not be sent to the stack so must be released
+                       again. */
+                       vReleaseNetworkBufferAndDescriptor( pxNextNetworkBufferDescriptor );
+                       iptraceETHERNET_RX_EVENT_LOST();
+                       FreeRTOS_printf( ( "prvEMACRxPoll: Can not queue return packet!\n" ) );
+               }
+
+               /* Now the buffer has either been passed to the IP-task,
+               or it has been released in the code above. */
+               pxNextNetworkBufferDescriptor = NULL;
+               ulReturnValue++;
+       }
+
+       return ulReturnValue;
+}
+/*-----------------------------------------------------------*/
+
+static void prvEMACHandlerTask( void *pvParameters )
+{
+TimeOut_t xPhyTime;
+TickType_t xPhyRemTime;
+UBaseType_t uxLastMinBufferCount = 0, uxCount;
+UBaseType_t uxCurrentCount;
+#if( ipconfigCHECK_IP_QUEUE_SPACE != 0 )
+       UBaseType_t uxLastMinQueueSpace;
+#endif
+#if( ipconfigZERO_COPY_TX_DRIVER != 0 )
+       NetworkBufferDescriptor_t *pxBuffer;
+#endif
+uint8_t *pucBuffer;
+BaseType_t xResult = 0;
+uint32_t xStatus;
+const TickType_t ulMaxBlockTime = pdMS_TO_TICKS( EMAC_MAX_BLOCK_TIME_MS );
+
+       /* Remove compiler warnings about unused parameters. */
+       ( void ) pvParameters;
+
+       configASSERT( xEMACTaskHandle );
+
+       vTaskSetTimeOutState( &xPhyTime );
+       xPhyRemTime = pdMS_TO_TICKS( PHY_LS_LOW_CHECK_TIME_MS );
+
+       for( ;; )
+       {
+               uxCurrentCount = uxGetMinimumFreeNetworkBuffers();
+               if( uxLastMinBufferCount != uxCurrentCount )
+               {
+                       /* The logging produced below may be helpful
+                       while tuning +TCP: see how many buffers are in use. */
+                       uxLastMinBufferCount = uxCurrentCount;
+                       FreeRTOS_printf( ( "Network buffers: %lu lowest %lu\n",
+                               uxGetNumberOfFreeNetworkBuffers(), uxCurrentCount ) );
+               }
+
+               #if( ipconfigCHECK_IP_QUEUE_SPACE != 0 )
+               {
+                       uxCurrentCount = uxGetMinimumIPQueueSpace();
+                       if( uxLastMinQueueSpace != uxCurrentCount )
+                       {
+                               /* The logging produced below may be helpful
+                               while tuning +TCP: see how many buffers are in use. */
+                               uxLastMinQueueSpace = uxCurrentCount;
+                               FreeRTOS_printf( ( "Queue space: lowest %lu\n", uxCurrentCount ) );
+                       }
+               }
+               #endif /* ipconfigCHECK_IP_QUEUE_SPACE */
+
+               if( ( ulISREvents & EMAC_IF_ALL_EVENT ) == 0 )
+               {
+                       /* No events to process now, wait for the next. */
+                       ulTaskNotifyTake( pdFALSE, ulMaxBlockTime );
+               }
+
+               if( ( ulISREvents & EMAC_IF_RX_EVENT ) != 0 )
+               {
+                       ulISREvents &= ~EMAC_IF_RX_EVENT;
+
+                       /* Wait for the EMAC interrupt to indicate that another packet has been
+                       received. */
+                       xResult = prvEMACRxPoll();
+               }
+
+               if( ( ulISREvents & EMAC_IF_TX_EVENT ) != 0 )
+               {
+                       /* Future extension: code to release TX buffers if zero-copy is used. */
+                       ulISREvents &= ~EMAC_IF_TX_EVENT;
+                       while( xQueueReceive( xTxBufferQueue, &pucBuffer, 0 ) != pdFALSE )
+                       {
+                               #if( ipconfigZERO_COPY_TX_DRIVER != 0 )
+                               {
+                                       pxBuffer = pxPacketBuffer_to_NetworkBuffer( pucBuffer );
+                                       if( pxBuffer != NULL )
+                                       {
+                                               vReleaseNetworkBufferAndDescriptor( pxBuffer );
+                                               tx_release_count[ 0 ]++;
+                                       }
+                                       else
+                                       {
+                                               tx_release_count[ 1 ]++;
+                                       }
+                               }
+                               #else
+                               {
+                                       tx_release_count[ 0 ]++;
+                               }
+                               #endif
+                               uxCount = uxQueueMessagesWaiting( ( QueueHandle_t ) xTXDescriptorSemaphore );
+                               if( uxCount < GMAC_TX_BUFFERS )
+                               {
+                                       /* Tell the counting semaphore that one more TX descriptor is available. */
+                                       xSemaphoreGive( xTXDescriptorSemaphore );
+                               }
+                       }
+               }
+
+               if( ( ulISREvents & EMAC_IF_ERR_EVENT ) != 0 )
+               {
+                       /* Future extension: logging about errors that occurred. */
+                       ulISREvents &= ~EMAC_IF_ERR_EVENT;
+               }
+
+               if( xResult > 0 )
+               {
+                       /* A packet was received. No need to check for the PHY status now,
+                       but set a timer to check it later on. */
+                       vTaskSetTimeOutState( &xPhyTime );
+                       xPhyRemTime = pdMS_TO_TICKS( PHY_LS_HIGH_CHECK_TIME_MS );
+                       xResult = 0;
+               }
+               else if( xTaskCheckForTimeOut( &xPhyTime, &xPhyRemTime ) != pdFALSE )
+               {
+                       /* Check the link status again. */
+                       xStatus = ulReadMDIO( PHY_REG_01_BMSR );
+
+                       if( ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != ( xStatus & BMSR_LINK_STATUS ) )
+                       {
+                               ulPHYLinkStatus = xStatus;
+                               FreeRTOS_printf( ( "prvEMACHandlerTask: PHY LS now %d\n", ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != 0 ) );
+                       }
+
+                       vTaskSetTimeOutState( &xPhyTime );
+                       if( ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != 0 )
+                       {
+                               xPhyRemTime = pdMS_TO_TICKS( PHY_LS_HIGH_CHECK_TIME_MS );
+                       }
+                       else
+                       {
+                               xPhyRemTime = pdMS_TO_TICKS( PHY_LS_LOW_CHECK_TIME_MS );
+                       }
+               }
+       }
+}
+/*-----------------------------------------------------------*/