]> git.sur5r.net Git - freertos/blobdiff - FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/ATSAM4E/NetworkInterface.c
git-svn-id: https://svn.code.sf.net/p/freertos/code/trunk@2822 1d2547de-c912-0410...
[freertos] / FreeRTOS-Plus / Source / FreeRTOS-Plus-TCP / portable / NetworkInterface / ATSAM4E / NetworkInterface.c
index 3528269bdb908c29673e1a7e78ce9df880a03342..83c96a07c078c448f34e6d632b0537eeaa342b70 100644 (file)
-/*
-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 );
-                       }
-               }
-       }
-}
-/*-----------------------------------------------------------*/
+/*\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