]> git.sur5r.net Git - freertos/blobdiff - FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/ksz8851snl/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 / ksz8851snl / NetworkInterface.c
index e4ae1168f6ef0a1e52e8f47f03e44ac3938d7f62..544e5ba095497386218b939f7dbc2d1ba1ee632c 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>
-#include <stdarg.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"
-
-#include "sam4e_xplained_pro.h"
-#include "hr_gettime.h"
-#include "conf_eth.h"
-#include "ksz8851snl.h"
-#include "ksz8851snl_reg.h"
-
-/* Some files from the Atmel Software Framework */
-#include <sysclk.h>
-#include <pdc/pdc.h>
-#include <spi/spi.h>
-
-/*
-       Sending a packet:
-
-               1) Called by UP-task, add buffer to the TX-list:
-                       xNetworkInterfaceOutput()
-                               tx_buffers[ us_tx_head ] = pxNetworkBuffer;
-                               tx_busy[ us_tx_head ] = pdTRUE;
-                               us_tx_head++;
-
-               2) Called by EMAC-Task: start SPI transfer
-                       ksz8851snl_update()
-                       if( ul_spi_pdc_status == SPI_PDC_IDLE )
-                       {
-                               if( ( tx_busy[ us_tx_tail ] != pdFALSE ) &&
-                                       ( us_pending_frame == 0 ) &&
-                                       ( ul_had_intn_interrupt == 0 ) )
-                               {
-                                       // disable all interrupts.
-                                       ksz8851_reg_write( REG_INT_MASK, 0 );
-                                       Bring KSZ8851SNL_CSN_GPIO low
-                                       ksz8851_fifo_write( pxNetworkBuffer->pucEthernetBuffer, xLength, xLength );
-                                       ul_spi_pdc_status = SPI_PDC_TX_START;
-                                       tx_cur_buffer = pxNetworkBuffer;
-                               }
-                       }
-               3) Wait for SPI RXBUFF interrupt
-                       SPI_Handler()
-                               if( ul_spi_pdc_status == SPI_PDC_TX_START )
-                               {
-                                       if( SPI_Status & SPI_SR_RXBUFF )
-                                       {
-                                               ul_spi_pdc_status = SPI_PDC_TX_COMPLETE;
-                                       }
-                               }
-
-               4) Called by EMAC-Task: finish SPI transfer
-                       ksz8851snl_update()
-                               if( ul_spi_pdc_status == SPI_PDC_TX_COMPLETE )
-                               {
-                                       ul_spi_pdc_status = SPI_PDC_IDLE;
-                                       Bring KSZ8851SNL_CSN_GPIO high
-                                       // TX step12: disable TXQ write access.
-                                       ksz8851_reg_clrbits( REG_RXQ_CMD, RXQ_START );
-                                       // TX step12.1: enqueue frame in TXQ.
-                                       ksz8851_reg_setbits( REG_TXQ_CMD, TXQ_ENQUEUE );
-
-                                       // RX step13: enable INT_RX flag.
-                                       ksz8851_reg_write( REG_INT_MASK, INT_RX );
-
-                                       // Buffer sent, free the corresponding buffer and mark descriptor as owned by software.
-                                       vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer );
-
-                                       tx_buffers[ us_tx_tail ] = NULL;
-                                       tx_busy[ us_tx_tail ] = pdFALSE;
-                                       us_tx_tail++
-                               }
-
-       Receiving a packet:
-
-               1) Wait for a INTN interrupt
-                       INTN_Handler()
-                               ul_had_intn_interrupt = 1
-                               vTaskNotifyGiveFromISR();       // Wake up the EMAC task
-
-               2) Called by EMAC-Task: check for new fragments and start SPI transfer
-                       ksz8851snl_update()
-                               if( ul_spi_pdc_status == SPI_PDC_IDLE )
-                               {
-                                       if( ( ul_had_intn_interrupt != 0 ) || ( us_pending_frame > 0 ) )
-                                       {
-                                               if( us_pending_frame == 0 )
-                                               {
-                                                       us_pending_frame = ksz8851_reg_read(REG_RX_FRAME_CNT_THRES) >> 8;
-                                                       if( us_pending_frame == 0 )
-                                                       {
-                                                               break;
-                                                       }
-                                               }
-                                               // RX step2: disable all interrupts.
-                                               ksz8851_reg_write( REG_INT_MASK, 0 );
-                                               Check if there is a valid packet: REG_RX_FHR_STATUS
-                                               Read the length of the next fragment: REG_RX_FHR_BYTE_CNT
-                                               ul_spi_pdc_status = SPI_PDC_RX_START;
-                                               gpio_set_pin_low(KSZ8851SNL_CSN_GPIO);
-                                               // Start SPI data transfer
-                                               ksz8851_fifo_read( pxNetworkBuffer->pucEthernetBuffer, xReadLength );
-                                       }
-                               }
-
-               3) Wait for SPI RXBUFF interrupt
-                       SPI_Handler()
-                       if( ul_spi_pdc_status == SPI_PDC_RX_START:
-                       {
-                               if( ( ulCurrentSPIStatus & SPI_SR_RXBUFF ) != 0 )
-                               {
-                                       // Transfer complete, disable SPI RXBUFF interrupt.
-                                       spi_disable_interrupt( KSZ8851SNL_SPI, SPI_IDR_RXBUFF );
-
-                                       ul_spi_pdc_status = SPI_PDC_RX_COMPLETE;
-                               }
-                       }
-               }
-
-               4) Finish SPI transfer
-                       ksz8851snl_update()
-                               if( ul_spi_pdc_status == SPI_PDC_RX_COMPLETE )
-                               {
-                                       ul_spi_pdc_status = SPI_PDC_IDLE;
-                                       Bring KSZ8851SNL_CSN_GPIO high
-                                       // RX step21: end RXQ read access.
-                                       ksz8851_reg_clrbits(REG_RXQ_CMD, RXQ_START);
-                                       // RX step22-23: update frame count to be read.
-                                       us_pending_frame--
-                                       // RX step24: enable INT_RX flag if transfer complete.
-                                       if( us_pending_frame == 0 )
-                                       {
-                                               // Allow more RX interrupts.
-                                               ksz8851_reg_write( REG_INT_MASK, INT_RX );
-                                       }
-
-                                       // Mark descriptor ready to be read.
-                                       rx_ready[ rxHead ] = pdTRUE;
-                                       rxHead++
-                               }
-*/
-
-#define PHY_REG_00_BMCR            0x00 // Basic mode control register
-#define PHY_REG_01_BMSR            0x01 // Basic mode status register
-#define PHY_REG_02_PHYSID1         0x02 // PHYS ID 1
-#define PHY_REG_03_PHYSID2         0x03 // PHYS ID 2
-#define PHY_REG_04_ADVERTISE       0x04 // Advertisement control reg
-#define PHY_REG_05_LPA             0x05 // Link partner ability reg
-#define        PHY_REG_06_ANER            0x06 //      6       RW              Auto-Negotiation Expansion Register
-#define        PHY_REG_07_ANNPTR          0x07 //      7       RW              Auto-Negotiation Next Page TX
-#define        PHY_REG_08_RESERVED0       0x08 // 0x08..0x0Fh  8-15    RW              RESERVED
-
-#define BMSR_LINK_STATUS            0x0004  //!< Link status
-
-#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
-
-#ifdef ipconfigHAS_TX_CRC_OFFLOADING
-       #undef ipconfigHAS_TX_CRC_OFFLOADING
-#endif
-/* Override this define because the KSZ8851 is programmed to set all outgoing CRC's */
-#define        ipconfigHAS_TX_CRC_OFFLOADING   1
-
-#ifndef        EMAC_MAX_BLOCK_TIME_MS
-       #define EMAC_MAX_BLOCK_TIME_MS  100ul
-#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 ( 6 * configMINIMAL_STACK_SIZE )
-#endif
-
-#define SPI_PDC_IDLE                   0
-#define SPI_PDC_RX_START               1
-#define SPI_PDC_TX_ERROR               2
-#define SPI_PDC_RX_COMPLETE            3
-#define SPI_PDC_TX_START               4
-#define SPI_PDC_RX_ERROR               5
-#define SPI_PDC_TX_COMPLETE            6
-
-/**
- * ksz8851snl driver structure.
- */
-typedef struct {
-       /** Set to 1 when owner is software (ready to read), 0 for Micrel. */
-       uint32_t rx_ready[MICREL_RX_BUFFERS];
-       /** Set to 1 when owner is Micrel, 0 for software. */
-       uint32_t tx_busy[MICREL_TX_BUFFERS];
-       /** RX NetworkBufferDescriptor_t pointer list */
-       NetworkBufferDescriptor_t *rx_buffers[MICREL_RX_BUFFERS];
-       /** TX NetworkBufferDescriptor_t pointer list */
-       NetworkBufferDescriptor_t *tx_buffers[MICREL_TX_BUFFERS];
-       NetworkBufferDescriptor_t *tx_cur_buffer;
-
-       /** Circular buffer head pointer for packet received. */
-       uint32_t us_rx_head;
-       /** Circular buffer tail pointer for packet to be read. */
-       uint32_t us_rx_tail;
-       /** Circular buffer head pointer by upper layer (buffer to be sent). */
-       uint32_t us_tx_head;
-       /** Circular buffer tail pointer incremented by handlers (buffer sent). */
-       uint32_t us_tx_tail;
-
-       uint32_t ul_total_tx;
-       uint32_t ul_total_rx;
-       uint32_t tx_space;
-
-       /** Still experimental: hash table to allow certain multicast addresses. */
-       uint16_t pusHashTable[ 4 ];
-
-       /* ul_spi_pdc_status has "SPI_PDC_xxx" values. */
-       volatile uint32_t ul_spi_pdc_status;
-
-       /* ul_had_intn_interrupt becomes true within the INTN interrupt. */
-       volatile uint32_t ul_had_intn_interrupt;
-
-       uint16_t us_pending_frame;
-} xKSZ8851_Device_t;
-
-/* SPI PDC register base.
-Declared in ASF\sam\components\ksz8851snl\ksz8851snl.c */
-extern Pdc *g_p_spi_pdc;
-
-/* Temporary buffer for PDC reception.
-declared in ASF\sam\components\ksz8851snl\ksz8851snl.c */
-extern uint8_t tmpbuf[1536];
-
-COMPILER_ALIGNED(8)
-static xKSZ8851_Device_t xMicrelDevice;
-
-static TaskHandle_t xTransmitHandle;
-
-/*-----------------------------------------------------------*/
-
-/*
- * Wait a fixed time for the link status to indicate the network is up.
- */
-static BaseType_t xGMACWaitLS( TickType_t xMaxTime );
-
-/*
- * A deferred interrupt handler task that processes GMAC interrupts.
- */
-static void prvEMACHandlerTask( void *pvParameters );
-
-/*
- * Try to obtain an Rx packet from the hardware.
- */
-static uint32_t prvEMACRxPoll( void );
-
-static inline unsigned long ulReadMDIO( unsigned uAddress );
-
-static void ksz8851snl_low_level_init( void );
-
-static NetworkBufferDescriptor_t *ksz8851snl_low_level_input( 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;
-
-static void ksz8851snl_update( void );
-
-static void ksz8851snl_rx_init( void );
-
-static void ksz8851snl_tx_init( void );
-
-/* 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;
-
-
-/*-----------------------------------------------------------*/
-
-BaseType_t xNetworkInterfaceInitialise( void )
-{
-const TickType_t x5_Seconds = 5000UL;
-
-       if( xEMACTaskHandle == NULL )
-       {
-               ksz8851snl_low_level_init();
-
-               /* 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, "KSZ8851", configEMAC_TASK_STACK_SIZE, NULL, configMAX_PRIORITIES - 1, &xEMACTaskHandle );
-               configASSERT( xEMACTaskHandle );
-       }
-
-       /* When returning non-zero, the stack will become active and
-    start DHCP (in configured) */
-       ulPHYLinkStatus = ulReadMDIO( PHY_REG_01_BMSR );
-
-       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 pxNetworkBuffer, BaseType_t bReleaseAfterSend )
-{
-BaseType_t xResult = pdFALSE;
-int txHead = xMicrelDevice.us_tx_head;
-
-       /* Make sure the next descriptor is free. */
-       if( xMicrelDevice.tx_busy[ txHead ] != pdFALSE )
-       {
-               /* All TX buffers busy. */
-       }
-       else if( ( ulPHYLinkStatus & BMSR_LINK_STATUS ) == 0 )
-       {
-               /* Output: LS low. */
-       }
-       else
-       {
-               /* Pass the packet. */
-               xMicrelDevice.tx_buffers[ txHead ] = pxNetworkBuffer;
-               /* The descriptor is now owned by Micrel. */
-               xMicrelDevice.tx_busy[ txHead ] = pdTRUE;
-
-               /* Move the head pointer. */
-               if( ++txHead == MICREL_TX_BUFFERS )
-               {
-                       txHead = 0;
-               }
-               xMicrelDevice.us_tx_head = txHead;
-               if( xEMACTaskHandle != NULL )
-               {
-                       xTaskNotifyGive( xEMACTaskHandle );
-               }
-
-       #if( ipconfigZERO_COPY_TX_DRIVER != 1 )
-               #warning Please ipconfigZERO_COPY_TX_DRIVER as 1
-       #endif
-               configASSERT( bReleaseAfterSend != pdFALSE );
-               xResult = pdTRUE;
-       }
-       if( ( xResult == pdFALSE ) && ( bReleaseAfterSend  != pdFALSE ) )
-       {
-               vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer );
-       }
-       return xResult;
-}
-/*-----------------------------------------------------------*/
-
-/* This Micrel has numbered it's PHY registers in a different way.
-Translate the register index. */
-static int ks8851_phy_reg( int reg )
-{
-       switch (reg) {
-       case PHY_REG_00_BMCR:
-               return REG_PHY_CNTL;    // P1MBCR;
-       case PHY_REG_01_BMSR:
-               return REG_PHY_STATUS;
-       case PHY_REG_02_PHYSID1:
-               return REG_PHY_ID_LOW;
-       case PHY_REG_03_PHYSID2:
-               return REG_PHY_ID_HIGH;
-       case PHY_REG_04_ADVERTISE:
-               return REG_PHY_AUTO_NEGOTIATION;
-       case PHY_REG_05_LPA:
-               return REG_PHY_REMOTE_CAPABILITY;
-       }
-
-       return 0x0;
-}
-/*-----------------------------------------------------------*/
-
-static inline unsigned long ulReadMDIO( unsigned uAddress )
-{
-uint16_t usPHYStatus;
-int ks8851_reg = ks8851_phy_reg( uAddress );
-
-       if( ks8851_reg != 0 )
-       {
-               usPHYStatus = ksz8851_reg_read( ks8851_reg );
-       }
-       else
-       {
-               /* Other addresses not yet implemented. */
-               usPHYStatus = 0;
-       }
-       return usPHYStatus;
-}
-/*-----------------------------------------------------------*/
-
-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 );
-const uint32_t ulHz_Per_MHz = 1000000UL;
-
-       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 freq %lu Mz\n",
-               xReturn,
-               sysclk_get_cpu_hz() / ulHz_Per_MHz ) );
-
-       return xReturn;
-}
-/*-----------------------------------------------------------*/
-
-static void vPioSetPinHigh(uint32_t ul_pin)
-{
-       Pio *p_pio = (Pio *)((uint32_t)PIOA + (PIO_DELTA * (ul_pin >> 5)));
-       // Value to be driven on the I/O line: 1.
-       p_pio->PIO_SODR = 1 << (ul_pin & 0x1F);
-}
-
-/**
- * \brief Handler for SPI interrupt.
- */
-void SPI_Handler(void)
-{
-BaseType_t xDoWakeup = pdFALSE;
-BaseType_t xKSZTaskWoken = pdFALSE;
-uint32_t ulCurrentSPIStatus;
-uint32_t ulEnabledSPIStatus;
-
-       ulCurrentSPIStatus = spi_read_status( KSZ8851SNL_SPI );
-       ulEnabledSPIStatus = spi_read_interrupt_mask( KSZ8851SNL_SPI );
-       ulCurrentSPIStatus &= ulEnabledSPIStatus;
-       spi_disable_interrupt( KSZ8851SNL_SPI, ulCurrentSPIStatus );
-
-
-       switch( xMicrelDevice.ul_spi_pdc_status )
-       {
-               case SPI_PDC_RX_START:
-               {
-                       if( ( ulCurrentSPIStatus & SPI_SR_OVRES ) != 0 )
-                       {
-                               pdc_disable_transfer(g_p_spi_pdc, PERIPH_PTCR_RXTDIS | PERIPH_PTCR_TXTDIS);
-                               xMicrelDevice.ul_spi_pdc_status = SPI_PDC_RX_ERROR;
-                               xDoWakeup = pdTRUE;
-                       }
-                       else
-                       {
-                               if( ( ulCurrentSPIStatus & SPI_SR_RXBUFF ) != 0 )
-                               {
-                                       xMicrelDevice.ul_spi_pdc_status = SPI_PDC_RX_COMPLETE;
-                                       xDoWakeup = pdTRUE;
-                               }
-                       }
-               }
-               break;
-
-               case SPI_PDC_TX_START:
-               {
-                       /* Middle of TX. */
-                       if( ( ulCurrentSPIStatus & SPI_SR_OVRES ) != 0 )
-                       {
-                               pdc_disable_transfer(g_p_spi_pdc, PERIPH_PTCR_RXTDIS | PERIPH_PTCR_TXTDIS);
-                               xMicrelDevice.ul_spi_pdc_status = SPI_PDC_TX_ERROR;
-                               xDoWakeup = pdTRUE;
-                       }
-                       else
-                       {
-                               if( ( ulCurrentSPIStatus & SPI_SR_ENDRX ) != 0 )
-                               {
-                                       /* Enable RX complete interrupt. */
-                                       spi_enable_interrupt( KSZ8851SNL_SPI, SPI_IER_RXBUFF );
-                               }
-                               /* End of TX. */
-                               if( ( ulCurrentSPIStatus & SPI_END_OF_TX ) != 0 )
-                               {
-                                       xMicrelDevice.ul_spi_pdc_status = SPI_PDC_TX_COMPLETE;
-                                       xDoWakeup = pdTRUE;
-                               }
-                       }
-               }
-               break;
-       }       /* switch( xMicrelDevice.ul_spi_pdc_status ) */
-
-       if( xDoWakeup != pdFALSE )
-       {
-               if( xEMACTaskHandle != NULL )
-               {
-                       vTaskNotifyGiveFromISR( xEMACTaskHandle, ( BaseType_t * ) &xKSZTaskWoken );
-               }
-       }
-       else
-       {
-       }
-       portEND_SWITCHING_ISR( xKSZTaskWoken );
-}
-/*-----------------------------------------------------------*/
-
-static void INTN_Handler(uint32_t id, uint32_t mask)
-{
-BaseType_t xKSZTaskWoken = pdFALSE;
-
-       if( ( id == INTN_ID ) &&
-               ( mask == INTN_PIN_MSK ) )
-       {
-               /* Clear the PIO interrupt flags. */
-               pio_get_interrupt_status( INTN_PIO );
-
-               /* Set the INTN flag. */
-               xMicrelDevice.ul_had_intn_interrupt++;
-               if( xEMACTaskHandle != NULL )
-               {
-                       vTaskNotifyGiveFromISR( xEMACTaskHandle, &( xKSZTaskWoken ) );
-               }
-       }
-       portEND_SWITCHING_ISR( xKSZTaskWoken );
-}
-/*-----------------------------------------------------------*/
-
-/**
- * \brief Populate the RX descriptor ring buffers with pbufs.
- *
- * \param p_ksz8851snl_dev Pointer to driver data structure.
- */
-static void ksz8851snl_rx_populate_queue( void )
-{
-       uint32_t ul_index = 0;
-       NetworkBufferDescriptor_t *pxNetworkBuffer;
-
-       /* Set up the RX descriptors */
-       for (ul_index = 0; ul_index < MICREL_RX_BUFFERS; ul_index++) {
-               if( xMicrelDevice.rx_buffers[ ul_index ] == NULL )
-               {
-                       /* Allocate a new NetworkBufferDescriptor_t with the maximum size. */
-                       pxNetworkBuffer = pxGetNetworkBufferWithDescriptor( ipconfigNETWORK_MTU + 36, 100 );
-                       if( pxNetworkBuffer == NULL )
-                       {
-                               FreeRTOS_printf( ( "ksz8851snl_rx_populate_queue: NetworkBufferDescriptor_t allocation failure\n" ) );
-                               configASSERT( 1 == 2 );
-                       }
-
-                       /* Make sure lwIP is well configured so one NetworkBufferDescriptor_t can contain the maximum packet size. */
-                       //LWIP_ASSERT("ksz8851snl_rx_populate_queue: NetworkBufferDescriptor_t size too small!", pbuf_clen(pxNetworkBuffer) <= 1);
-
-                       /* Save NetworkBufferDescriptor_t pointer to be sent to lwIP upper layer. */
-                       xMicrelDevice.rx_buffers[ ul_index ] = pxNetworkBuffer;
-                       /* Pass it to Micrel for reception. */
-                       xMicrelDevice.rx_ready[ ul_index ] = pdFALSE;
-               }
-       }
-}
-
-unsigned tx_space, wait_tx_space, tx_status, fhr_status;
-unsigned rx_debug = 0;
-/**
- * \brief Update Micrel state machine and perform required actions.
- *
- * \param netif the lwIP network interface structure for this ethernetif.
- */
-static void ksz8851snl_update()
-{
-       uint16_t txmir = 0;
-
-/* Check for free PDC. */
-       switch( xMicrelDevice.ul_spi_pdc_status )
-       {
-       case SPI_PDC_TX_ERROR:
-               {
-               uint32_t ulValue;
-       //              /* TX step11: end TX transfer. */
-                       gpio_set_pin_high( KSZ8851SNL_CSN_GPIO );
-
-                       vTaskDelay( 2 ); gpio_set_pin_low( KSZ8851SNL_CSN_GPIO );
-                       vTaskDelay( 1 ); gpio_set_pin_high( KSZ8851SNL_CSN_GPIO );
-                       vTaskDelay( 1 );
-
-                       /* Disable asynchronous transfer mode. */
-                       xMicrelDevice.ul_spi_pdc_status = SPI_PDC_IDLE;
-
-                       /* TX step12: disable TXQ write access. */
-                       ksz8851_reg_clrbits( REG_RXQ_CMD, RXQ_START );
-
-                       ulValue = ksz8851snl_reset_tx();
-
-                       xMicrelDevice.tx_space = ksz8851_reg_read( REG_TX_MEM_INFO ) & TX_MEM_AVAILABLE_MASK;
-
-                       FreeRTOS_printf( ("SPI_PDC_TX_ERROR %02X\n", ulValue ) );
-               }
-               break;
-
-       case SPI_PDC_RX_ERROR:
-               {
-               uint32_t ulValue;
-                       /* TX step11: end TX transfer. */
-                       gpio_set_pin_high( KSZ8851SNL_CSN_GPIO );
-
-                       vTaskDelay( 2 ); gpio_set_pin_low( KSZ8851SNL_CSN_GPIO );
-                       vTaskDelay( 1 ); gpio_set_pin_high( KSZ8851SNL_CSN_GPIO );
-                       vTaskDelay( 1 );
-
-                       /* Disable asynchronous transfer mode. */
-                       xMicrelDevice.ul_spi_pdc_status = SPI_PDC_IDLE;
-
-                       /* TX step12: disable TXQ write access. */
-                       ksz8851_reg_clrbits( REG_RXQ_CMD, RXQ_START );
-
-                       //ulValue = ksz8851snl_reset_rx();
-                       ulValue = ksz8851snl_reinit();
-
-                       xGMACWaitLS( pdMS_TO_TICKS( 5000UL ) );
-
-                       FreeRTOS_printf( ("SPI_PDC_RX_ERROR %02X\n", ulValue ) );
-               }
-               break;
-       }
-       switch( xMicrelDevice.ul_spi_pdc_status )
-       {
-               case SPI_PDC_IDLE:
-               {
-               int txTail = xMicrelDevice.us_tx_tail;
-
-                       /*
-                        * ========================== Handle RX ==========================
-                        */
-                       if( ( xMicrelDevice.ul_had_intn_interrupt != 0 ) || ( xMicrelDevice.us_pending_frame > 0 ) )
-                       {
-                       int rxHead = xMicrelDevice.us_rx_head;
-                       NetworkBufferDescriptor_t *pxNetworkBuffer;
-#warning try
-                               xMicrelDevice.ul_had_intn_interrupt = 0;
-
-                               if( xMicrelDevice.us_pending_frame == 0 )
-                               {
-                               uint16_t int_status;
-                                       /* RX step1: read interrupt status for INT_RX flag. */
-                                       int_status = ksz8851_reg_read( REG_INT_STATUS );
-
-
-                                       /* RX step2: disable all interrupts. */
-                                       ksz8851_reg_write( REG_INT_MASK, 0 );
-
-                                       /* RX step3: clear INT_RX flag. */
-                                       ksz8851_reg_setbits( REG_INT_STATUS, INT_RX );
-
-                                       /* RX step4-5: check for received frames. */
-                                       xMicrelDevice.us_pending_frame = ksz8851_reg_read(REG_RX_FRAME_CNT_THRES) >> 8;
-                                       if( xMicrelDevice.us_pending_frame == 0 )
-                                       {
-                                               /* RX step24: enable INT_RX flag. */
-                                               ksz8851_reg_write(REG_INT_MASK, INT_RX);
-                                               return;
-                                       }
-                               }
-#warning try
-                               xMicrelDevice.ul_had_intn_interrupt = 0;
-
-                               /* Now xMicrelDevice.us_pending_frame != 0 */
-
-                               /* Don't break Micrel state machine, wait for a free descriptor first! */
-                               if( xMicrelDevice.rx_ready[ rxHead ] != pdFALSE )
-                               {
-                                       FreeRTOS_printf( ( "ksz8851snl_update: out of free descriptor! [tail=%u head=%u]\n",
-                                                       xMicrelDevice.us_rx_tail, rxHead ) );
-                                       return;
-                               }
-                               pxNetworkBuffer = xMicrelDevice.rx_buffers[ rxHead ];
-
-                               if( pxNetworkBuffer == NULL )
-                               {
-                                       ksz8851snl_rx_populate_queue();
-                                       FreeRTOS_printf( ( "ksz8851snl_update: no buffer set [head=%u]\n", rxHead ) );
-                                       return;
-                               }
-
-                               /* RX step6: get RX packet status. */
-                               fhr_status = ksz8851_reg_read( REG_RX_FHR_STATUS );
-                               if( ( ( fhr_status & RX_VALID ) == 0 ) || ( ( fhr_status & RX_ERRORS ) != 0 ) )
-                               {
-                                       ksz8851_reg_setbits(REG_RXQ_CMD, RXQ_CMD_FREE_PACKET);
-                                       FreeRTOS_printf( ( "ksz8851snl_update: RX packet error!\n" ) );
-
-                                       /* RX step4-5: check for received frames. */
-                                       xMicrelDevice.us_pending_frame = ksz8851_reg_read(REG_RX_FRAME_CNT_THRES) >> 8;
-                                       if( xMicrelDevice.us_pending_frame == 0 )
-                                       {
-                                               /* RX step24: enable INT_RX flag. */
-                                               ksz8851_reg_write(REG_INT_MASK, INT_RX);
-                                       }
-                                       ulISREvents |= EMAC_IF_ERR_EVENT;
-                               }
-                               else
-                               {
-                               size_t xLength;
-                                       /* RX step7: read frame length. */
-                                       xLength = ksz8851_reg_read(REG_RX_FHR_BYTE_CNT) & RX_BYTE_CNT_MASK;
-
-                                       /* RX step8: Drop packet if len is invalid or no descriptor available. */
-                                       if( xLength == 0 )
-                                       {
-                                               ksz8851_reg_setbits( REG_RXQ_CMD, RXQ_CMD_FREE_PACKET );
-                                               FreeRTOS_printf( ( "ksz8851snl_update: RX bad len!\n" ) );
-                                               ulISREvents |= EMAC_IF_ERR_EVENT;
-                                       }
-                                       else
-                                       {
-                                       size_t xReadLength = xLength;
-
-                                               xMicrelDevice.ul_total_rx++;
-                                               /* RX step9: reset RX frame pointer. */
-                                               ksz8851_reg_clrbits(REG_RX_ADDR_PTR, ADDR_PTR_MASK);
-
-                                               /* RX step10: start RXQ read access. */
-                                               ksz8851_reg_setbits(REG_RXQ_CMD, RXQ_START);
-                                               /* RX step11-17: start asynchronous FIFO read operation. */
-                                               xMicrelDevice.ul_spi_pdc_status = SPI_PDC_RX_START;
-                                               gpio_set_pin_low( KSZ8851SNL_CSN_GPIO );
-                                               if( ( xReadLength & ( sizeof( size_t ) - 1 ) ) != 0 )
-                                               {
-                                                       xReadLength = ( xReadLength | ( sizeof( size_t ) - 1 ) ) + 1;
-                                               }
-
-                                               /* Pass the buffer minus 2 bytes, see ksz8851snl.c: RXQ_TWOBYTE_OFFSET. */
-                                               ksz8851_fifo_read( pxNetworkBuffer->pucEthernetBuffer - 2, xReadLength );
-                                               /* Remove CRC and update buffer length. */
-                                               xLength -= 4;
-                                               pxNetworkBuffer->xDataLength = xLength;
-                                               /* Wait for SPI interrupt to set status 'SPI_PDC_RX_COMPLETE'. */
-                                       }
-                               }
-                               break;
-                       } /* ul_had_intn_interrupt || us_pending_frame */
-                       /*
-                        * ========================== Handle TX ==========================
-                        */
-
-                       /* Fetch next packet to be sent. */
-                       if( ( xMicrelDevice.tx_busy[ txTail ] != pdFALSE ) &&
-                               ( xMicrelDevice.us_pending_frame == 0 ) &&
-                               ( xMicrelDevice.ul_had_intn_interrupt == 0 ) )
-                       {
-                       NetworkBufferDescriptor_t *pxNetworkBuffer = xMicrelDevice.tx_buffers[ txTail ];
-                       size_t xLength = pxNetworkBuffer->xDataLength;
-                       int iIndex = xLength;
-
-                               xLength = 4 * ( ( xLength + 3 ) / 4 );
-                               while( iIndex < ( int ) xLength )
-                               {
-                                       pxNetworkBuffer->pucEthernetBuffer[ iIndex ] = '\0';
-                                       iIndex++;
-                               }
-                               pxNetworkBuffer->xDataLength = xLength;
-
-                               /* TX step1: check if TXQ memory size is available for transmit. */
-                               txmir = ksz8851_reg_read( REG_TX_MEM_INFO );
-                               txmir = txmir & TX_MEM_AVAILABLE_MASK;
-
-                               if( txmir < ( xLength + 8 ) )
-                               {
-                                       if( wait_tx_space == pdFALSE )
-                                       {
-                                               tx_status = ksz8851_reg_read( REG_TX_STATUS );
-                                               fhr_status = ksz8851_reg_read( REG_RX_FHR_STATUS );
-                                               wait_tx_space = pdTRUE;
-                                       }
-                                       //return;
-                                       rx_debug = 1;
-                                       tx_space = txmir;
-                               }
-                               else
-                               {
-                                       tx_space = txmir;
-
-                                       /* TX step2: disable all interrupts. */
-                                       ksz8851_reg_write( REG_INT_MASK, 0 );
-
-                                       xMicrelDevice.tx_space -= xLength;
-
-                                       /* TX step3: enable TXQ write access. */
-                                       ksz8851_reg_setbits( REG_RXQ_CMD, RXQ_START );
-                                       /* TX step4-8: perform FIFO write operation. */
-                                       xMicrelDevice.ul_spi_pdc_status = SPI_PDC_TX_START;
-                                       xMicrelDevice.tx_cur_buffer = pxNetworkBuffer;
-                                       /* Bring SPI SS low. */
-                                       gpio_set_pin_low( KSZ8851SNL_CSN_GPIO );
-                                       xMicrelDevice.ul_total_tx++;
-
-                                       ksz8851_fifo_write( pxNetworkBuffer->pucEthernetBuffer, xLength, xLength );
-                               }
-                       }
-               }
-               break;  /* SPI_PDC_IDLE */
-
-       case SPI_PDC_RX_COMPLETE:
-               {
-               int rxHead = xMicrelDevice.us_rx_head;
-                       /* RX step18-19: pad with dummy data to keep dword alignment. */
-                       /* Packet lengths will be rounded up to a multiple of "sizeof size_t". */
-//                     xLength = xMicrelDevice.rx_buffers[ rxHead ]->xDataLength & 3;
-//                     if( xLength != 0 )
-//                     {
-//                             ksz8851_fifo_dummy( 4 - xLength );
-//                     }
-
-                       /* RX step20: end RX transfer. */
-                       gpio_set_pin_high( KSZ8851SNL_CSN_GPIO );
-
-                       /* Disable asynchronous transfer mode. */
-                       xMicrelDevice.ul_spi_pdc_status = SPI_PDC_IDLE;
-
-                       /* RX step21: end RXQ read access. */
-                       ksz8851_reg_clrbits(REG_RXQ_CMD, RXQ_START);
-
-                       /* RX step22-23: update frame count to be read. */
-                       xMicrelDevice.us_pending_frame -= 1;
-
-                       /* RX step24: enable INT_RX flag if transfer complete. */
-                       if( xMicrelDevice.us_pending_frame == 0 )
-                       {
-                               ksz8851_reg_write(REG_INT_MASK, INT_RX);
-                       }
-
-                       /* Mark descriptor ready to be read. */
-                       xMicrelDevice.rx_ready[ rxHead ] = pdTRUE;
-                       if( ++rxHead == MICREL_RX_BUFFERS )
-                       {
-                               rxHead = 0;
-                       }
-                       xMicrelDevice.us_rx_head = rxHead;
-                       if( rx_debug != 0 )
-                       {
-                       uint32_t txmir;
-                               rx_debug = 0;
-                               txmir = ksz8851_reg_read( REG_TX_MEM_INFO );
-                               txmir = txmir & TX_MEM_AVAILABLE_MASK;
-                       }
-                       /* Tell prvEMACHandlerTask that RX packets are available. */
-                       ulISREvents |= EMAC_IF_RX_EVENT;
-               }       /* case SPI_PDC_RX_COMPLETE */
-               break;
-
-       case SPI_PDC_TX_COMPLETE:
-               {
-               int txTail = xMicrelDevice.us_tx_tail;
-               NetworkBufferDescriptor_t *pxNetworkBuffer = xMicrelDevice.tx_buffers[ txTail ];
-
-               size_t xLength;
-                       /* TX step9-10: pad with dummy data to keep dword alignment. */
-                       /* Not necessary: length is already a multiple of 4. */
-                       xLength = pxNetworkBuffer->xDataLength & 3;
-                       if( xLength != 0 )
-                       {
-//                             ksz8851_fifo_dummy( 4 - xLength );
-                       }
-
-//                     /* TX step11: end TX transfer. */
-                       gpio_set_pin_high( KSZ8851SNL_CSN_GPIO );
-
-                       /* Disable asynchronous transfer mode. */
-                       xMicrelDevice.ul_spi_pdc_status = SPI_PDC_IDLE;
-
-                       /* TX step12: disable TXQ write access. */
-                       ksz8851_reg_clrbits( REG_RXQ_CMD, RXQ_START );
-
-                       xMicrelDevice.tx_space = ksz8851_reg_read( REG_TX_MEM_INFO ) & TX_MEM_AVAILABLE_MASK;
-
-                       /* TX step12.1: enqueue frame in TXQ. */
-                       ksz8851_reg_setbits( REG_TXQ_CMD, TXQ_ENQUEUE );
-
-                       /* RX step13: enable INT_RX flag. */
-//                     ksz8851_reg_write( REG_INT_MASK, INT_RX );
-                       /* Buffer sent, free the corresponding buffer and mark descriptor as owned by software. */
-                       vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer );
-
-                       xMicrelDevice.tx_buffers[ txTail ] = NULL;
-                       xMicrelDevice.tx_busy[ txTail ] = pdFALSE;
-                       if( ++txTail == MICREL_TX_BUFFERS )
-                       {
-                               txTail = 0;
-                       }
-
-                       xMicrelDevice.us_tx_tail = txTail;
-                       /* Experiment. */
-                       //xMicrelDevice.ul_had_intn_interrupt = 1;
-                       if( xTransmitHandle != NULL )
-                       {
-                               xTaskNotifyGive( xTransmitHandle );
-                       }
-#warning moved downward
-                       /* RX step13: enable INT_RX flag. */
-                       ksz8851_reg_write( REG_INT_MASK, INT_RX );
-                       /* Prevent the EMAC task from sleeping a single time. */
-                       ulISREvents |= EMAC_IF_TX_EVENT;
-               }       /* case SPI_PDC_TX_COMPLETE */
-               break;
-       }       /* switch( xMicrelDevice.ul_spi_pdc_status ) */
-}
-
-/**
- * \brief Set up the RX descriptor ring buffers.
- *
- * This function sets up the descriptor list used for RX packets.
- *
- */
-static void ksz8851snl_rx_init()
-{
-       uint32_t ul_index = 0;
-
-       /* Init pointer index. */
-       xMicrelDevice.us_rx_head = 0;
-       xMicrelDevice.us_rx_tail = 0;
-
-       /* Set up the RX descriptors. */
-       for (ul_index = 0; ul_index < MICREL_RX_BUFFERS; ul_index++) {
-               xMicrelDevice.rx_buffers[ul_index] = NULL;
-               xMicrelDevice.rx_ready[ul_index] = pdFALSE;
-       }
-
-       /* Build RX buffer and descriptors. */
-       ksz8851snl_rx_populate_queue();
-}
-
-/**
- * \brief Set up the TX descriptor ring buffers.
- *
- * This function sets up the descriptor list used for TX packets.
- *
- */
-static void ksz8851snl_tx_init()
-{
-       uint32_t ul_index = 0;
-
-       /* Init TX index pointer. */
-       xMicrelDevice.us_tx_head = 0;
-       xMicrelDevice.us_tx_tail = 0;
-
-       /* Set up the TX descriptors */
-       for( ul_index = 0; ul_index < MICREL_TX_BUFFERS; ul_index++ )
-       {
-               xMicrelDevice.tx_busy[ul_index] = pdFALSE;
-       }
-       xMicrelDevice.tx_space = 6144;
-}
-
-/**
- * \brief Initialize ksz8851snl ethernet controller.
- *
- * \note Called from ethernetif_init().
- *
- * \param netif the lwIP network interface structure for this ethernetif.
- */
-static void ksz8851snl_low_level_init( void )
-{
-       ksz8851snl_rx_init();
-       ksz8851snl_tx_init();
-
-       /* Enable NVIC interrupts. */
-       NVIC_SetPriority(SPI_IRQn, INT_PRIORITY_SPI);
-       NVIC_EnableIRQ(SPI_IRQn);
-
-       /* Initialize SPI link. */
-       if( ksz8851snl_init() < 0 )
-       {
-               FreeRTOS_printf( ( "ksz8851snl_low_level_init: failed to initialize the Micrel driver!\n" ) );
-               configASSERT(0 == 1);
-       }
-       memset( xMicrelDevice.pusHashTable, 255, sizeof( xMicrelDevice.pusHashTable ) );
-       ksz8851_reg_write( REG_MAC_HASH_0, FreeRTOS_htons( xMicrelDevice.pusHashTable[ 0 ] ) );
-       ksz8851_reg_write( REG_MAC_HASH_2, FreeRTOS_htons( xMicrelDevice.pusHashTable[ 1 ] ) );
-       ksz8851_reg_write( REG_MAC_HASH_4, FreeRTOS_htons( xMicrelDevice.pusHashTable[ 2 ] ) );
-       ksz8851_reg_write( REG_MAC_HASH_6, FreeRTOS_htons( xMicrelDevice.pusHashTable[ 3 ] ) );
-
-       /* Initialize interrupt line INTN. */
-       configure_intn( INTN_Handler );
-}
-
-/**
- * \brief Use pre-allocated pbuf as DMA source and return the incoming packet.
- *
- * \param netif the lwIP network interface structure for this ethernetif.
- *
- * \return a pbuf filled with the received packet (including MAC header).
- * 0 on memory error.
- */
-static NetworkBufferDescriptor_t *ksz8851snl_low_level_input( void )
-{
-NetworkBufferDescriptor_t *pxNetworkBuffer = NULL;
-int rxTail = xMicrelDevice.us_rx_tail;
-
-       /* Check that descriptor is owned by software (ie packet received). */
-       if( xMicrelDevice.rx_ready[ rxTail ] != pdFALSE )
-       {
-
-               /* Fetch pre-allocated buffer */
-               pxNetworkBuffer = xMicrelDevice.rx_buffers[ rxTail ];
-
-               /* Remove this pbuf from its descriptor. */
-               xMicrelDevice.rx_buffers[ rxTail ] = NULL;
-
-               /* Clears rx_ready and sets rx_buffers. */
-               ksz8851snl_rx_populate_queue();
-
-               if( ++rxTail == MICREL_RX_BUFFERS )
-               {
-                       rxTail = 0;
-               }
-               xMicrelDevice.us_rx_tail = rxTail;
-       }
-
-       return pxNetworkBuffer;
-}
-/*-----------------------------------------------------------*/
-
-static uint32_t prvEMACRxPoll( void )
-{
-NetworkBufferDescriptor_t *pxNetworkBuffer;
-IPStackEvent_t xRxEvent = { eNetworkRxEvent, NULL };
-uint32_t ulReturnValue = 0;
-
-       for( ;; )
-       {
-       /* Only for logging. */
-       int rxTail = xMicrelDevice.us_rx_tail;
-       EthernetHeader_t *pxEthernetHeader;
-
-       pxNetworkBuffer = ksz8851snl_low_level_input();
-       
-               if( pxNetworkBuffer == NULL )
-               {
-                       break;
-               }
-               pxEthernetHeader = ( EthernetHeader_t * ) ( pxNetworkBuffer->pucEthernetBuffer );
-
-               if( ( pxEthernetHeader->usFrameType != ipIPv4_FRAME_TYPE ) &&
-                       ( pxEthernetHeader->usFrameType != ipARP_FRAME_TYPE     ) )
-               {
-                       FreeRTOS_printf( ( "Frame type %02X received\n", pxEthernetHeader->usFrameType ) );
-               }
-               ulReturnValue++;
-
-               xRxEvent.pvData = ( void * )pxNetworkBuffer;
-               /* Send the descriptor to the IP task for processing. */
-               if( xSendEventStructToIPTask( &xRxEvent, 100UL ) != pdTRUE )
-               {
-                       vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer );
-                       iptraceETHERNET_RX_EVENT_LOST();
-                       FreeRTOS_printf( ( "prvEMACRxPoll: Can not queue return packet!\n" ) );
-               }
-       }
-
-       return ulReturnValue;
-}
-/*-----------------------------------------------------------*/
-
-static void prvEMACHandlerTask( void *pvParameters )
-{
-TimeOut_t xPhyTime;
-TickType_t xPhyRemTime;
-TickType_t xLoggingTime;
-UBaseType_t uxLastMinBufferCount = 0;
-UBaseType_t uxCurrentCount;
-BaseType_t xResult = 0;
-uint32_t xStatus;
-const TickType_t ulMaxBlockTime = pdMS_TO_TICKS( EMAC_MAX_BLOCK_TIME_MS );
-#if( ipconfigCHECK_IP_QUEUE_SPACE != 0 )
-       UBaseType_t uxLastMinQueueSpace = 0;
-#endif
-
-       /* Remove compiler warnings about unused parameters. */
-       ( void ) pvParameters;
-
-       configASSERT( xEMACTaskHandle );
-
-       vTaskSetTimeOutState( &xPhyTime );
-       xPhyRemTime = pdMS_TO_TICKS( PHY_LS_LOW_CHECK_TIME_MS );
-       xLoggingTime = xTaskGetTickCount();
-
-       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 */
-
-               /* Run the state-machine of the ksz8851 driver. */
-               ksz8851snl_update();
-
-               if( ( ulISREvents & EMAC_IF_ALL_EVENT ) == 0 )
-               {
-                       /* No events to process now, wait for the next. */
-                       ulTaskNotifyTake( pdTRUE, ulMaxBlockTime );
-               }
-
-               if( ( xTaskGetTickCount() - xLoggingTime ) > 10000 )
-               {
-                       xLoggingTime += 10000;
-                       FreeRTOS_printf( ( "Now Tx/Rx %7d /%7d\n",
-                               xMicrelDevice.ul_total_tx, xMicrelDevice.ul_total_rx ) );
-               }
-
-               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;
-               }
-
-               if( ( ulISREvents & EMAC_IF_ERR_EVENT ) != 0 )
-               {
-                       /* Future extension: logging about errors that occurred. */
-                       ulISREvents &= ~EMAC_IF_ERR_EVENT;
-               }
-
-               if( xResult > 0 )
-               {
-                       /* As long as packets are being received, assume that
-                       the Link Status is high. */
-                       ulPHYLinkStatus |= BMSR_LINK_STATUS;
-                       /* 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 ) &&
-                       ( xMicrelDevice.ul_spi_pdc_status == SPI_PDC_IDLE ) )
-               {
-                       /* 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
+#include <stdarg.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
+#include "sam4e_xplained_pro.h"\r
+#include "hr_gettime.h"\r
+#include "conf_eth.h"\r
+#include "ksz8851snl.h"\r
+#include "ksz8851snl_reg.h"\r
+\r
+/* Some files from the Atmel Software Framework */\r
+#include <sysclk.h>\r
+#include <pdc/pdc.h>\r
+#include <spi/spi.h>\r
+\r
+/*\r
+       Sending a packet:\r
+\r
+               1) Called by UP-task, add buffer to the TX-list:\r
+                       xNetworkInterfaceOutput()\r
+                               tx_buffers[ us_tx_head ] = pxNetworkBuffer;\r
+                               tx_busy[ us_tx_head ] = pdTRUE;\r
+                               us_tx_head++;\r
+\r
+               2) Called by EMAC-Task: start SPI transfer\r
+                       ksz8851snl_update()\r
+                       if( ul_spi_pdc_status == SPI_PDC_IDLE )\r
+                       {\r
+                               if( ( tx_busy[ us_tx_tail ] != pdFALSE ) &&\r
+                                       ( us_pending_frame == 0 ) &&\r
+                                       ( ul_had_intn_interrupt == 0 ) )\r
+                               {\r
+                                       // disable all interrupts.\r
+                                       ksz8851_reg_write( REG_INT_MASK, 0 );\r
+                                       Bring KSZ8851SNL_CSN_GPIO low\r
+                                       ksz8851_fifo_write( pxNetworkBuffer->pucEthernetBuffer, xLength, xLength );\r
+                                       ul_spi_pdc_status = SPI_PDC_TX_START;\r
+                                       tx_cur_buffer = pxNetworkBuffer;\r
+                               }\r
+                       }\r
+               3) Wait for SPI RXBUFF interrupt\r
+                       SPI_Handler()\r
+                               if( ul_spi_pdc_status == SPI_PDC_TX_START )\r
+                               {\r
+                                       if( SPI_Status & SPI_SR_RXBUFF )\r
+                                       {\r
+                                               ul_spi_pdc_status = SPI_PDC_TX_COMPLETE;\r
+                                       }\r
+                               }\r
+\r
+               4) Called by EMAC-Task: finish SPI transfer\r
+                       ksz8851snl_update()\r
+                               if( ul_spi_pdc_status == SPI_PDC_TX_COMPLETE )\r
+                               {\r
+                                       ul_spi_pdc_status = SPI_PDC_IDLE;\r
+                                       Bring KSZ8851SNL_CSN_GPIO high\r
+                                       // TX step12: disable TXQ write access.\r
+                                       ksz8851_reg_clrbits( REG_RXQ_CMD, RXQ_START );\r
+                                       // TX step12.1: enqueue frame in TXQ.\r
+                                       ksz8851_reg_setbits( REG_TXQ_CMD, TXQ_ENQUEUE );\r
+\r
+                                       // RX step13: enable INT_RX flag.\r
+                                       ksz8851_reg_write( REG_INT_MASK, INT_RX );\r
+\r
+                                       // Buffer sent, free the corresponding buffer and mark descriptor as owned by software.\r
+                                       vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer );\r
+\r
+                                       tx_buffers[ us_tx_tail ] = NULL;\r
+                                       tx_busy[ us_tx_tail ] = pdFALSE;\r
+                                       us_tx_tail++\r
+                               }\r
+\r
+       Receiving a packet:\r
+\r
+               1) Wait for a INTN interrupt\r
+                       INTN_Handler()\r
+                               ul_had_intn_interrupt = 1\r
+                               vTaskNotifyGiveFromISR();       // Wake up the EMAC task\r
+\r
+               2) Called by EMAC-Task: check for new fragments and start SPI transfer\r
+                       ksz8851snl_update()\r
+                               if( ul_spi_pdc_status == SPI_PDC_IDLE )\r
+                               {\r
+                                       if( ( ul_had_intn_interrupt != 0 ) || ( us_pending_frame > 0 ) )\r
+                                       {\r
+                                               if( us_pending_frame == 0 )\r
+                                               {\r
+                                                       us_pending_frame = ksz8851_reg_read(REG_RX_FRAME_CNT_THRES) >> 8;\r
+                                                       if( us_pending_frame == 0 )\r
+                                                       {\r
+                                                               break;\r
+                                                       }\r
+                                               }\r
+                                               // RX step2: disable all interrupts.\r
+                                               ksz8851_reg_write( REG_INT_MASK, 0 );\r
+                                               Check if there is a valid packet: REG_RX_FHR_STATUS\r
+                                               Read the length of the next fragment: REG_RX_FHR_BYTE_CNT\r
+                                               ul_spi_pdc_status = SPI_PDC_RX_START;\r
+                                               gpio_set_pin_low(KSZ8851SNL_CSN_GPIO);\r
+                                               // Start SPI data transfer\r
+                                               ksz8851_fifo_read( pxNetworkBuffer->pucEthernetBuffer, xReadLength );\r
+                                       }\r
+                               }\r
+\r
+               3) Wait for SPI RXBUFF interrupt\r
+                       SPI_Handler()\r
+                       if( ul_spi_pdc_status == SPI_PDC_RX_START:\r
+                       {\r
+                               if( ( ulCurrentSPIStatus & SPI_SR_RXBUFF ) != 0 )\r
+                               {\r
+                                       // Transfer complete, disable SPI RXBUFF interrupt.\r
+                                       spi_disable_interrupt( KSZ8851SNL_SPI, SPI_IDR_RXBUFF );\r
+\r
+                                       ul_spi_pdc_status = SPI_PDC_RX_COMPLETE;\r
+                               }\r
+                       }\r
+               }\r
+\r
+               4) Finish SPI transfer\r
+                       ksz8851snl_update()\r
+                               if( ul_spi_pdc_status == SPI_PDC_RX_COMPLETE )\r
+                               {\r
+                                       ul_spi_pdc_status = SPI_PDC_IDLE;\r
+                                       Bring KSZ8851SNL_CSN_GPIO high\r
+                                       // RX step21: end RXQ read access.\r
+                                       ksz8851_reg_clrbits(REG_RXQ_CMD, RXQ_START);\r
+                                       // RX step22-23: update frame count to be read.\r
+                                       us_pending_frame--\r
+                                       // RX step24: enable INT_RX flag if transfer complete.\r
+                                       if( us_pending_frame == 0 )\r
+                                       {\r
+                                               // Allow more RX interrupts.\r
+                                               ksz8851_reg_write( REG_INT_MASK, INT_RX );\r
+                                       }\r
+\r
+                                       // Mark descriptor ready to be read.\r
+                                       rx_ready[ rxHead ] = pdTRUE;\r
+                                       rxHead++\r
+                               }\r
+*/\r
+\r
+#define PHY_REG_00_BMCR            0x00 // Basic mode control register\r
+#define PHY_REG_01_BMSR            0x01 // Basic mode status register\r
+#define PHY_REG_02_PHYSID1         0x02 // PHYS ID 1\r
+#define PHY_REG_03_PHYSID2         0x03 // PHYS ID 2\r
+#define PHY_REG_04_ADVERTISE       0x04 // Advertisement control reg\r
+#define PHY_REG_05_LPA             0x05 // Link partner ability reg\r
+#define        PHY_REG_06_ANER            0x06 //      6       RW              Auto-Negotiation Expansion Register\r
+#define        PHY_REG_07_ANNPTR          0x07 //      7       RW              Auto-Negotiation Next Page TX\r
+#define        PHY_REG_08_RESERVED0       0x08 // 0x08..0x0Fh  8-15    RW              RESERVED\r
+\r
+#define BMSR_LINK_STATUS            0x0004  //!< Link status\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
+#ifdef ipconfigHAS_TX_CRC_OFFLOADING\r
+       #undef ipconfigHAS_TX_CRC_OFFLOADING\r
+#endif\r
+/* Override this define because the KSZ8851 is programmed to set all outgoing CRC's */\r
+#define        ipconfigHAS_TX_CRC_OFFLOADING   1\r
+\r
+#ifndef        EMAC_MAX_BLOCK_TIME_MS\r
+       #define EMAC_MAX_BLOCK_TIME_MS  100ul\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 ( 6 * configMINIMAL_STACK_SIZE )\r
+#endif\r
+\r
+#define SPI_PDC_IDLE                   0\r
+#define SPI_PDC_RX_START               1\r
+#define SPI_PDC_TX_ERROR               2\r
+#define SPI_PDC_RX_COMPLETE            3\r
+#define SPI_PDC_TX_START               4\r
+#define SPI_PDC_RX_ERROR               5\r
+#define SPI_PDC_TX_COMPLETE            6\r
+\r
+/**\r
+ * ksz8851snl driver structure.\r
+ */\r
+typedef struct {\r
+       /** Set to 1 when owner is software (ready to read), 0 for Micrel. */\r
+       uint32_t rx_ready[MICREL_RX_BUFFERS];\r
+       /** Set to 1 when owner is Micrel, 0 for software. */\r
+       uint32_t tx_busy[MICREL_TX_BUFFERS];\r
+       /** RX NetworkBufferDescriptor_t pointer list */\r
+       NetworkBufferDescriptor_t *rx_buffers[MICREL_RX_BUFFERS];\r
+       /** TX NetworkBufferDescriptor_t pointer list */\r
+       NetworkBufferDescriptor_t *tx_buffers[MICREL_TX_BUFFERS];\r
+       NetworkBufferDescriptor_t *tx_cur_buffer;\r
+\r
+       /** Circular buffer head pointer for packet received. */\r
+       uint32_t us_rx_head;\r
+       /** Circular buffer tail pointer for packet to be read. */\r
+       uint32_t us_rx_tail;\r
+       /** Circular buffer head pointer by upper layer (buffer to be sent). */\r
+       uint32_t us_tx_head;\r
+       /** Circular buffer tail pointer incremented by handlers (buffer sent). */\r
+       uint32_t us_tx_tail;\r
+\r
+       uint32_t ul_total_tx;\r
+       uint32_t ul_total_rx;\r
+       uint32_t tx_space;\r
+\r
+       /** Still experimental: hash table to allow certain multicast addresses. */\r
+       uint16_t pusHashTable[ 4 ];\r
+\r
+       /* ul_spi_pdc_status has "SPI_PDC_xxx" values. */\r
+       volatile uint32_t ul_spi_pdc_status;\r
+\r
+       /* ul_had_intn_interrupt becomes true within the INTN interrupt. */\r
+       volatile uint32_t ul_had_intn_interrupt;\r
+\r
+       uint16_t us_pending_frame;\r
+} xKSZ8851_Device_t;\r
+\r
+/* SPI PDC register base.\r
+Declared in ASF\sam\components\ksz8851snl\ksz8851snl.c */\r
+extern Pdc *g_p_spi_pdc;\r
+\r
+/* Temporary buffer for PDC reception.\r
+declared in ASF\sam\components\ksz8851snl\ksz8851snl.c */\r
+extern uint8_t tmpbuf[1536];\r
+\r
+COMPILER_ALIGNED(8)\r
+static xKSZ8851_Device_t xMicrelDevice;\r
+\r
+static TaskHandle_t xTransmitHandle;\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
+/*\r
+ * A deferred interrupt handler task that processes GMAC interrupts.\r
+ */\r
+static void prvEMACHandlerTask( void *pvParameters );\r
+\r
+/*\r
+ * Try to obtain an Rx packet from the hardware.\r
+ */\r
+static uint32_t prvEMACRxPoll( void );\r
+\r
+static inline unsigned long ulReadMDIO( unsigned uAddress );\r
+\r
+static void ksz8851snl_low_level_init( void );\r
+\r
+static NetworkBufferDescriptor_t *ksz8851snl_low_level_input( 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
+static void ksz8851snl_update( void );\r
+\r
+static void ksz8851snl_rx_init( void );\r
+\r
+static void ksz8851snl_tx_init( void );\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
+\r
+/*-----------------------------------------------------------*/\r
+\r
+BaseType_t xNetworkInterfaceInitialise( void )\r
+{\r
+const TickType_t x5_Seconds = 5000UL;\r
+\r
+       if( xEMACTaskHandle == NULL )\r
+       {\r
+               ksz8851snl_low_level_init();\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, "KSZ8851", configEMAC_TASK_STACK_SIZE, NULL, configMAX_PRIORITIES - 1, &xEMACTaskHandle );\r
+               configASSERT( xEMACTaskHandle );\r
+       }\r
+\r
+       /* When returning non-zero, the stack will become active and\r
+    start DHCP (in configured) */\r
+       ulPHYLinkStatus = ulReadMDIO( PHY_REG_01_BMSR );\r
+\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 pxNetworkBuffer, BaseType_t bReleaseAfterSend )\r
+{\r
+BaseType_t xResult = pdFALSE;\r
+int txHead = xMicrelDevice.us_tx_head;\r
+\r
+       /* Make sure the next descriptor is free. */\r
+       if( xMicrelDevice.tx_busy[ txHead ] != pdFALSE )\r
+       {\r
+               /* All TX buffers busy. */\r
+       }\r
+       else if( ( ulPHYLinkStatus & BMSR_LINK_STATUS ) == 0 )\r
+       {\r
+               /* Output: LS low. */\r
+       }\r
+       else\r
+       {\r
+               /* Pass the packet. */\r
+               xMicrelDevice.tx_buffers[ txHead ] = pxNetworkBuffer;\r
+               /* The descriptor is now owned by Micrel. */\r
+               xMicrelDevice.tx_busy[ txHead ] = pdTRUE;\r
+\r
+               /* Move the head pointer. */\r
+               if( ++txHead == MICREL_TX_BUFFERS )\r
+               {\r
+                       txHead = 0;\r
+               }\r
+               xMicrelDevice.us_tx_head = txHead;\r
+               if( xEMACTaskHandle != NULL )\r
+               {\r
+                       xTaskNotifyGive( xEMACTaskHandle );\r
+               }\r
+\r
+       #if( ipconfigZERO_COPY_TX_DRIVER != 1 )\r
+               #warning Please ipconfigZERO_COPY_TX_DRIVER as 1\r
+       #endif\r
+               configASSERT( bReleaseAfterSend != pdFALSE );\r
+               xResult = pdTRUE;\r
+       }\r
+       if( ( xResult == pdFALSE ) && ( bReleaseAfterSend  != pdFALSE ) )\r
+       {\r
+               vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer );\r
+       }\r
+       return xResult;\r
+}\r
+/*-----------------------------------------------------------*/\r
+\r
+/* This Micrel has numbered it's PHY registers in a different way.\r
+Translate the register index. */\r
+static int ks8851_phy_reg( int reg )\r
+{\r
+       switch (reg) {\r
+       case PHY_REG_00_BMCR:\r
+               return REG_PHY_CNTL;    // P1MBCR;\r
+       case PHY_REG_01_BMSR:\r
+               return REG_PHY_STATUS;\r
+       case PHY_REG_02_PHYSID1:\r
+               return REG_PHY_ID_LOW;\r
+       case PHY_REG_03_PHYSID2:\r
+               return REG_PHY_ID_HIGH;\r
+       case PHY_REG_04_ADVERTISE:\r
+               return REG_PHY_AUTO_NEGOTIATION;\r
+       case PHY_REG_05_LPA:\r
+               return REG_PHY_REMOTE_CAPABILITY;\r
+       }\r
+\r
+       return 0x0;\r
+}\r
+/*-----------------------------------------------------------*/\r
+\r
+static inline unsigned long ulReadMDIO( unsigned uAddress )\r
+{\r
+uint16_t usPHYStatus;\r
+int ks8851_reg = ks8851_phy_reg( uAddress );\r
+\r
+       if( ks8851_reg != 0 )\r
+       {\r
+               usPHYStatus = ksz8851_reg_read( ks8851_reg );\r
+       }\r
+       else\r
+       {\r
+               /* Other addresses not yet implemented. */\r
+               usPHYStatus = 0;\r
+       }\r
+       return usPHYStatus;\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
+const uint32_t ulHz_Per_MHz = 1000000UL;\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 freq %lu Mz\n",\r
+               xReturn,\r
+               sysclk_get_cpu_hz() / ulHz_Per_MHz ) );\r
+\r
+       return xReturn;\r
+}\r
+/*-----------------------------------------------------------*/\r
+\r
+static void vPioSetPinHigh(uint32_t ul_pin)\r
+{\r
+       Pio *p_pio = (Pio *)((uint32_t)PIOA + (PIO_DELTA * (ul_pin >> 5)));\r
+       // Value to be driven on the I/O line: 1.\r
+       p_pio->PIO_SODR = 1 << (ul_pin & 0x1F);\r
+}\r
+\r
+/**\r
+ * \brief Handler for SPI interrupt.\r
+ */\r
+void SPI_Handler(void)\r
+{\r
+BaseType_t xDoWakeup = pdFALSE;\r
+BaseType_t xKSZTaskWoken = pdFALSE;\r
+uint32_t ulCurrentSPIStatus;\r
+uint32_t ulEnabledSPIStatus;\r
+\r
+       ulCurrentSPIStatus = spi_read_status( KSZ8851SNL_SPI );\r
+       ulEnabledSPIStatus = spi_read_interrupt_mask( KSZ8851SNL_SPI );\r
+       ulCurrentSPIStatus &= ulEnabledSPIStatus;\r
+       spi_disable_interrupt( KSZ8851SNL_SPI, ulCurrentSPIStatus );\r
+\r
+\r
+       switch( xMicrelDevice.ul_spi_pdc_status )\r
+       {\r
+               case SPI_PDC_RX_START:\r
+               {\r
+                       if( ( ulCurrentSPIStatus & SPI_SR_OVRES ) != 0 )\r
+                       {\r
+                               pdc_disable_transfer(g_p_spi_pdc, PERIPH_PTCR_RXTDIS | PERIPH_PTCR_TXTDIS);\r
+                               xMicrelDevice.ul_spi_pdc_status = SPI_PDC_RX_ERROR;\r
+                               xDoWakeup = pdTRUE;\r
+                       }\r
+                       else\r
+                       {\r
+                               if( ( ulCurrentSPIStatus & SPI_SR_RXBUFF ) != 0 )\r
+                               {\r
+                                       xMicrelDevice.ul_spi_pdc_status = SPI_PDC_RX_COMPLETE;\r
+                                       xDoWakeup = pdTRUE;\r
+                               }\r
+                       }\r
+               }\r
+               break;\r
+\r
+               case SPI_PDC_TX_START:\r
+               {\r
+                       /* Middle of TX. */\r
+                       if( ( ulCurrentSPIStatus & SPI_SR_OVRES ) != 0 )\r
+                       {\r
+                               pdc_disable_transfer(g_p_spi_pdc, PERIPH_PTCR_RXTDIS | PERIPH_PTCR_TXTDIS);\r
+                               xMicrelDevice.ul_spi_pdc_status = SPI_PDC_TX_ERROR;\r
+                               xDoWakeup = pdTRUE;\r
+                       }\r
+                       else\r
+                       {\r
+                               if( ( ulCurrentSPIStatus & SPI_SR_ENDRX ) != 0 )\r
+                               {\r
+                                       /* Enable RX complete interrupt. */\r
+                                       spi_enable_interrupt( KSZ8851SNL_SPI, SPI_IER_RXBUFF );\r
+                               }\r
+                               /* End of TX. */\r
+                               if( ( ulCurrentSPIStatus & SPI_END_OF_TX ) != 0 )\r
+                               {\r
+                                       xMicrelDevice.ul_spi_pdc_status = SPI_PDC_TX_COMPLETE;\r
+                                       xDoWakeup = pdTRUE;\r
+                               }\r
+                       }\r
+               }\r
+               break;\r
+       }       /* switch( xMicrelDevice.ul_spi_pdc_status ) */\r
+\r
+       if( xDoWakeup != pdFALSE )\r
+       {\r
+               if( xEMACTaskHandle != NULL )\r
+               {\r
+                       vTaskNotifyGiveFromISR( xEMACTaskHandle, ( BaseType_t * ) &xKSZTaskWoken );\r
+               }\r
+       }\r
+       else\r
+       {\r
+       }\r
+       portEND_SWITCHING_ISR( xKSZTaskWoken );\r
+}\r
+/*-----------------------------------------------------------*/\r
+\r
+static void INTN_Handler(uint32_t id, uint32_t mask)\r
+{\r
+BaseType_t xKSZTaskWoken = pdFALSE;\r
+\r
+       if( ( id == INTN_ID ) &&\r
+               ( mask == INTN_PIN_MSK ) )\r
+       {\r
+               /* Clear the PIO interrupt flags. */\r
+               pio_get_interrupt_status( INTN_PIO );\r
+\r
+               /* Set the INTN flag. */\r
+               xMicrelDevice.ul_had_intn_interrupt++;\r
+               if( xEMACTaskHandle != NULL )\r
+               {\r
+                       vTaskNotifyGiveFromISR( xEMACTaskHandle, &( xKSZTaskWoken ) );\r
+               }\r
+       }\r
+       portEND_SWITCHING_ISR( xKSZTaskWoken );\r
+}\r
+/*-----------------------------------------------------------*/\r
+\r
+/**\r
+ * \brief Populate the RX descriptor ring buffers with pbufs.\r
+ *\r
+ * \param p_ksz8851snl_dev Pointer to driver data structure.\r
+ */\r
+static void ksz8851snl_rx_populate_queue( void )\r
+{\r
+       uint32_t ul_index = 0;\r
+       NetworkBufferDescriptor_t *pxNetworkBuffer;\r
+\r
+       /* Set up the RX descriptors */\r
+       for (ul_index = 0; ul_index < MICREL_RX_BUFFERS; ul_index++) {\r
+               if( xMicrelDevice.rx_buffers[ ul_index ] == NULL )\r
+               {\r
+                       /* Allocate a new NetworkBufferDescriptor_t with the maximum size. */\r
+                       pxNetworkBuffer = pxGetNetworkBufferWithDescriptor( ipconfigNETWORK_MTU + 36, 100 );\r
+                       if( pxNetworkBuffer == NULL )\r
+                       {\r
+                               FreeRTOS_printf( ( "ksz8851snl_rx_populate_queue: NetworkBufferDescriptor_t allocation failure\n" ) );\r
+                               configASSERT( 1 == 2 );\r
+                       }\r
+\r
+                       /* Make sure lwIP is well configured so one NetworkBufferDescriptor_t can contain the maximum packet size. */\r
+                       //LWIP_ASSERT("ksz8851snl_rx_populate_queue: NetworkBufferDescriptor_t size too small!", pbuf_clen(pxNetworkBuffer) <= 1);\r
+\r
+                       /* Save NetworkBufferDescriptor_t pointer to be sent to lwIP upper layer. */\r
+                       xMicrelDevice.rx_buffers[ ul_index ] = pxNetworkBuffer;\r
+                       /* Pass it to Micrel for reception. */\r
+                       xMicrelDevice.rx_ready[ ul_index ] = pdFALSE;\r
+               }\r
+       }\r
+}\r
+\r
+unsigned tx_space, wait_tx_space, tx_status, fhr_status;\r
+unsigned rx_debug = 0;\r
+/**\r
+ * \brief Update Micrel state machine and perform required actions.\r
+ *\r
+ * \param netif the lwIP network interface structure for this ethernetif.\r
+ */\r
+static void ksz8851snl_update()\r
+{\r
+       uint16_t txmir = 0;\r
+\r
+/* Check for free PDC. */\r
+       switch( xMicrelDevice.ul_spi_pdc_status )\r
+       {\r
+       case SPI_PDC_TX_ERROR:\r
+               {\r
+               uint32_t ulValue;\r
+       //              /* TX step11: end TX transfer. */\r
+                       gpio_set_pin_high( KSZ8851SNL_CSN_GPIO );\r
+\r
+                       vTaskDelay( 2 ); gpio_set_pin_low( KSZ8851SNL_CSN_GPIO );\r
+                       vTaskDelay( 1 ); gpio_set_pin_high( KSZ8851SNL_CSN_GPIO );\r
+                       vTaskDelay( 1 );\r
+\r
+                       /* Disable asynchronous transfer mode. */\r
+                       xMicrelDevice.ul_spi_pdc_status = SPI_PDC_IDLE;\r
+\r
+                       /* TX step12: disable TXQ write access. */\r
+                       ksz8851_reg_clrbits( REG_RXQ_CMD, RXQ_START );\r
+\r
+                       ulValue = ksz8851snl_reset_tx();\r
+\r
+                       xMicrelDevice.tx_space = ksz8851_reg_read( REG_TX_MEM_INFO ) & TX_MEM_AVAILABLE_MASK;\r
+\r
+                       FreeRTOS_printf( ("SPI_PDC_TX_ERROR %02X\n", ulValue ) );\r
+               }\r
+               break;\r
+\r
+       case SPI_PDC_RX_ERROR:\r
+               {\r
+               uint32_t ulValue;\r
+                       /* TX step11: end TX transfer. */\r
+                       gpio_set_pin_high( KSZ8851SNL_CSN_GPIO );\r
+\r
+                       vTaskDelay( 2 ); gpio_set_pin_low( KSZ8851SNL_CSN_GPIO );\r
+                       vTaskDelay( 1 ); gpio_set_pin_high( KSZ8851SNL_CSN_GPIO );\r
+                       vTaskDelay( 1 );\r
+\r
+                       /* Disable asynchronous transfer mode. */\r
+                       xMicrelDevice.ul_spi_pdc_status = SPI_PDC_IDLE;\r
+\r
+                       /* TX step12: disable TXQ write access. */\r
+                       ksz8851_reg_clrbits( REG_RXQ_CMD, RXQ_START );\r
+\r
+                       //ulValue = ksz8851snl_reset_rx();\r
+                       ulValue = ksz8851snl_reinit();\r
+\r
+                       xGMACWaitLS( pdMS_TO_TICKS( 5000UL ) );\r
+\r
+                       FreeRTOS_printf( ("SPI_PDC_RX_ERROR %02X\n", ulValue ) );\r
+               }\r
+               break;\r
+       }\r
+       switch( xMicrelDevice.ul_spi_pdc_status )\r
+       {\r
+               case SPI_PDC_IDLE:\r
+               {\r
+               int txTail = xMicrelDevice.us_tx_tail;\r
+\r
+                       /*\r
+                        * ========================== Handle RX ==========================\r
+                        */\r
+                       if( ( xMicrelDevice.ul_had_intn_interrupt != 0 ) || ( xMicrelDevice.us_pending_frame > 0 ) )\r
+                       {\r
+                       int rxHead = xMicrelDevice.us_rx_head;\r
+                       NetworkBufferDescriptor_t *pxNetworkBuffer;\r
+#warning try\r
+                               xMicrelDevice.ul_had_intn_interrupt = 0;\r
+\r
+                               if( xMicrelDevice.us_pending_frame == 0 )\r
+                               {\r
+                               uint16_t int_status;\r
+                                       /* RX step1: read interrupt status for INT_RX flag. */\r
+                                       int_status = ksz8851_reg_read( REG_INT_STATUS );\r
+\r
+\r
+                                       /* RX step2: disable all interrupts. */\r
+                                       ksz8851_reg_write( REG_INT_MASK, 0 );\r
+\r
+                                       /* RX step3: clear INT_RX flag. */\r
+                                       ksz8851_reg_setbits( REG_INT_STATUS, INT_RX );\r
+\r
+                                       /* RX step4-5: check for received frames. */\r
+                                       xMicrelDevice.us_pending_frame = ksz8851_reg_read(REG_RX_FRAME_CNT_THRES) >> 8;\r
+                                       if( xMicrelDevice.us_pending_frame == 0 )\r
+                                       {\r
+                                               /* RX step24: enable INT_RX flag. */\r
+                                               ksz8851_reg_write(REG_INT_MASK, INT_RX);\r
+                                               return;\r
+                                       }\r
+                               }\r
+#warning try\r
+                               xMicrelDevice.ul_had_intn_interrupt = 0;\r
+\r
+                               /* Now xMicrelDevice.us_pending_frame != 0 */\r
+\r
+                               /* Don't break Micrel state machine, wait for a free descriptor first! */\r
+                               if( xMicrelDevice.rx_ready[ rxHead ] != pdFALSE )\r
+                               {\r
+                                       FreeRTOS_printf( ( "ksz8851snl_update: out of free descriptor! [tail=%u head=%u]\n",\r
+                                                       xMicrelDevice.us_rx_tail, rxHead ) );\r
+                                       return;\r
+                               }\r
+                               pxNetworkBuffer = xMicrelDevice.rx_buffers[ rxHead ];\r
+\r
+                               if( pxNetworkBuffer == NULL )\r
+                               {\r
+                                       ksz8851snl_rx_populate_queue();\r
+                                       FreeRTOS_printf( ( "ksz8851snl_update: no buffer set [head=%u]\n", rxHead ) );\r
+                                       return;\r
+                               }\r
+\r
+                               /* RX step6: get RX packet status. */\r
+                               fhr_status = ksz8851_reg_read( REG_RX_FHR_STATUS );\r
+                               if( ( ( fhr_status & RX_VALID ) == 0 ) || ( ( fhr_status & RX_ERRORS ) != 0 ) )\r
+                               {\r
+                                       ksz8851_reg_setbits(REG_RXQ_CMD, RXQ_CMD_FREE_PACKET);\r
+                                       FreeRTOS_printf( ( "ksz8851snl_update: RX packet error!\n" ) );\r
+\r
+                                       /* RX step4-5: check for received frames. */\r
+                                       xMicrelDevice.us_pending_frame = ksz8851_reg_read(REG_RX_FRAME_CNT_THRES) >> 8;\r
+                                       if( xMicrelDevice.us_pending_frame == 0 )\r
+                                       {\r
+                                               /* RX step24: enable INT_RX flag. */\r
+                                               ksz8851_reg_write(REG_INT_MASK, INT_RX);\r
+                                       }\r
+                                       ulISREvents |= EMAC_IF_ERR_EVENT;\r
+                               }\r
+                               else\r
+                               {\r
+                               size_t xLength;\r
+                                       /* RX step7: read frame length. */\r
+                                       xLength = ksz8851_reg_read(REG_RX_FHR_BYTE_CNT) & RX_BYTE_CNT_MASK;\r
+\r
+                                       /* RX step8: Drop packet if len is invalid or no descriptor available. */\r
+                                       if( xLength == 0 )\r
+                                       {\r
+                                               ksz8851_reg_setbits( REG_RXQ_CMD, RXQ_CMD_FREE_PACKET );\r
+                                               FreeRTOS_printf( ( "ksz8851snl_update: RX bad len!\n" ) );\r
+                                               ulISREvents |= EMAC_IF_ERR_EVENT;\r
+                                       }\r
+                                       else\r
+                                       {\r
+                                       size_t xReadLength = xLength;\r
+\r
+                                               xMicrelDevice.ul_total_rx++;\r
+                                               /* RX step9: reset RX frame pointer. */\r
+                                               ksz8851_reg_clrbits(REG_RX_ADDR_PTR, ADDR_PTR_MASK);\r
+\r
+                                               /* RX step10: start RXQ read access. */\r
+                                               ksz8851_reg_setbits(REG_RXQ_CMD, RXQ_START);\r
+                                               /* RX step11-17: start asynchronous FIFO read operation. */\r
+                                               xMicrelDevice.ul_spi_pdc_status = SPI_PDC_RX_START;\r
+                                               gpio_set_pin_low( KSZ8851SNL_CSN_GPIO );\r
+                                               if( ( xReadLength & ( sizeof( size_t ) - 1 ) ) != 0 )\r
+                                               {\r
+                                                       xReadLength = ( xReadLength | ( sizeof( size_t ) - 1 ) ) + 1;\r
+                                               }\r
+\r
+                                               /* Pass the buffer minus 2 bytes, see ksz8851snl.c: RXQ_TWOBYTE_OFFSET. */\r
+                                               ksz8851_fifo_read( pxNetworkBuffer->pucEthernetBuffer - 2, xReadLength );\r
+                                               /* Remove CRC and update buffer length. */\r
+                                               xLength -= 4;\r
+                                               pxNetworkBuffer->xDataLength = xLength;\r
+                                               /* Wait for SPI interrupt to set status 'SPI_PDC_RX_COMPLETE'. */\r
+                                       }\r
+                               }\r
+                               break;\r
+                       } /* ul_had_intn_interrupt || us_pending_frame */\r
+                       /*\r
+                        * ========================== Handle TX ==========================\r
+                        */\r
+\r
+                       /* Fetch next packet to be sent. */\r
+                       if( ( xMicrelDevice.tx_busy[ txTail ] != pdFALSE ) &&\r
+                               ( xMicrelDevice.us_pending_frame == 0 ) &&\r
+                               ( xMicrelDevice.ul_had_intn_interrupt == 0 ) )\r
+                       {\r
+                       NetworkBufferDescriptor_t *pxNetworkBuffer = xMicrelDevice.tx_buffers[ txTail ];\r
+                       size_t xLength = pxNetworkBuffer->xDataLength;\r
+                       int iIndex = xLength;\r
+\r
+                               xLength = 4 * ( ( xLength + 3 ) / 4 );\r
+                               while( iIndex < ( int ) xLength )\r
+                               {\r
+                                       pxNetworkBuffer->pucEthernetBuffer[ iIndex ] = '\0';\r
+                                       iIndex++;\r
+                               }\r
+                               pxNetworkBuffer->xDataLength = xLength;\r
+\r
+                               /* TX step1: check if TXQ memory size is available for transmit. */\r
+                               txmir = ksz8851_reg_read( REG_TX_MEM_INFO );\r
+                               txmir = txmir & TX_MEM_AVAILABLE_MASK;\r
+\r
+                               if( txmir < ( xLength + 8 ) )\r
+                               {\r
+                                       if( wait_tx_space == pdFALSE )\r
+                                       {\r
+                                               tx_status = ksz8851_reg_read( REG_TX_STATUS );\r
+                                               fhr_status = ksz8851_reg_read( REG_RX_FHR_STATUS );\r
+                                               wait_tx_space = pdTRUE;\r
+                                       }\r
+                                       //return;\r
+                                       rx_debug = 1;\r
+                                       tx_space = txmir;\r
+                               }\r
+                               else\r
+                               {\r
+                                       tx_space = txmir;\r
+\r
+                                       /* TX step2: disable all interrupts. */\r
+                                       ksz8851_reg_write( REG_INT_MASK, 0 );\r
+\r
+                                       xMicrelDevice.tx_space -= xLength;\r
+\r
+                                       /* TX step3: enable TXQ write access. */\r
+                                       ksz8851_reg_setbits( REG_RXQ_CMD, RXQ_START );\r
+                                       /* TX step4-8: perform FIFO write operation. */\r
+                                       xMicrelDevice.ul_spi_pdc_status = SPI_PDC_TX_START;\r
+                                       xMicrelDevice.tx_cur_buffer = pxNetworkBuffer;\r
+                                       /* Bring SPI SS low. */\r
+                                       gpio_set_pin_low( KSZ8851SNL_CSN_GPIO );\r
+                                       xMicrelDevice.ul_total_tx++;\r
+\r
+                                       ksz8851_fifo_write( pxNetworkBuffer->pucEthernetBuffer, xLength, xLength );\r
+                               }\r
+                       }\r
+               }\r
+               break;  /* SPI_PDC_IDLE */\r
+\r
+       case SPI_PDC_RX_COMPLETE:\r
+               {\r
+               int rxHead = xMicrelDevice.us_rx_head;\r
+                       /* RX step18-19: pad with dummy data to keep dword alignment. */\r
+                       /* Packet lengths will be rounded up to a multiple of "sizeof size_t". */\r
+//                     xLength = xMicrelDevice.rx_buffers[ rxHead ]->xDataLength & 3;\r
+//                     if( xLength != 0 )\r
+//                     {\r
+//                             ksz8851_fifo_dummy( 4 - xLength );\r
+//                     }\r
+\r
+                       /* RX step20: end RX transfer. */\r
+                       gpio_set_pin_high( KSZ8851SNL_CSN_GPIO );\r
+\r
+                       /* Disable asynchronous transfer mode. */\r
+                       xMicrelDevice.ul_spi_pdc_status = SPI_PDC_IDLE;\r
+\r
+                       /* RX step21: end RXQ read access. */\r
+                       ksz8851_reg_clrbits(REG_RXQ_CMD, RXQ_START);\r
+\r
+                       /* RX step22-23: update frame count to be read. */\r
+                       xMicrelDevice.us_pending_frame -= 1;\r
+\r
+                       /* RX step24: enable INT_RX flag if transfer complete. */\r
+                       if( xMicrelDevice.us_pending_frame == 0 )\r
+                       {\r
+                               ksz8851_reg_write(REG_INT_MASK, INT_RX);\r
+                       }\r
+\r
+                       /* Mark descriptor ready to be read. */\r
+                       xMicrelDevice.rx_ready[ rxHead ] = pdTRUE;\r
+                       if( ++rxHead == MICREL_RX_BUFFERS )\r
+                       {\r
+                               rxHead = 0;\r
+                       }\r
+                       xMicrelDevice.us_rx_head = rxHead;\r
+                       if( rx_debug != 0 )\r
+                       {\r
+                       uint32_t txmir;\r
+                               rx_debug = 0;\r
+                               txmir = ksz8851_reg_read( REG_TX_MEM_INFO );\r
+                               txmir = txmir & TX_MEM_AVAILABLE_MASK;\r
+                       }\r
+                       /* Tell prvEMACHandlerTask that RX packets are available. */\r
+                       ulISREvents |= EMAC_IF_RX_EVENT;\r
+               }       /* case SPI_PDC_RX_COMPLETE */\r
+               break;\r
+\r
+       case SPI_PDC_TX_COMPLETE:\r
+               {\r
+               int txTail = xMicrelDevice.us_tx_tail;\r
+               NetworkBufferDescriptor_t *pxNetworkBuffer = xMicrelDevice.tx_buffers[ txTail ];\r
+\r
+               size_t xLength;\r
+                       /* TX step9-10: pad with dummy data to keep dword alignment. */\r
+                       /* Not necessary: length is already a multiple of 4. */\r
+                       xLength = pxNetworkBuffer->xDataLength & 3;\r
+                       if( xLength != 0 )\r
+                       {\r
+//                             ksz8851_fifo_dummy( 4 - xLength );\r
+                       }\r
+\r
+//                     /* TX step11: end TX transfer. */\r
+                       gpio_set_pin_high( KSZ8851SNL_CSN_GPIO );\r
+\r
+                       /* Disable asynchronous transfer mode. */\r
+                       xMicrelDevice.ul_spi_pdc_status = SPI_PDC_IDLE;\r
+\r
+                       /* TX step12: disable TXQ write access. */\r
+                       ksz8851_reg_clrbits( REG_RXQ_CMD, RXQ_START );\r
+\r
+                       xMicrelDevice.tx_space = ksz8851_reg_read( REG_TX_MEM_INFO ) & TX_MEM_AVAILABLE_MASK;\r
+\r
+                       /* TX step12.1: enqueue frame in TXQ. */\r
+                       ksz8851_reg_setbits( REG_TXQ_CMD, TXQ_ENQUEUE );\r
+\r
+                       /* RX step13: enable INT_RX flag. */\r
+//                     ksz8851_reg_write( REG_INT_MASK, INT_RX );\r
+                       /* Buffer sent, free the corresponding buffer and mark descriptor as owned by software. */\r
+                       vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer );\r
+\r
+                       xMicrelDevice.tx_buffers[ txTail ] = NULL;\r
+                       xMicrelDevice.tx_busy[ txTail ] = pdFALSE;\r
+                       if( ++txTail == MICREL_TX_BUFFERS )\r
+                       {\r
+                               txTail = 0;\r
+                       }\r
+\r
+                       xMicrelDevice.us_tx_tail = txTail;\r
+                       /* Experiment. */\r
+                       //xMicrelDevice.ul_had_intn_interrupt = 1;\r
+                       if( xTransmitHandle != NULL )\r
+                       {\r
+                               xTaskNotifyGive( xTransmitHandle );\r
+                       }\r
+#warning moved downward\r
+                       /* RX step13: enable INT_RX flag. */\r
+                       ksz8851_reg_write( REG_INT_MASK, INT_RX );\r
+                       /* Prevent the EMAC task from sleeping a single time. */\r
+                       ulISREvents |= EMAC_IF_TX_EVENT;\r
+               }       /* case SPI_PDC_TX_COMPLETE */\r
+               break;\r
+       }       /* switch( xMicrelDevice.ul_spi_pdc_status ) */\r
+}\r
+\r
+/**\r
+ * \brief Set up the RX descriptor ring buffers.\r
+ *\r
+ * This function sets up the descriptor list used for RX packets.\r
+ *\r
+ */\r
+static void ksz8851snl_rx_init()\r
+{\r
+       uint32_t ul_index = 0;\r
+\r
+       /* Init pointer index. */\r
+       xMicrelDevice.us_rx_head = 0;\r
+       xMicrelDevice.us_rx_tail = 0;\r
+\r
+       /* Set up the RX descriptors. */\r
+       for (ul_index = 0; ul_index < MICREL_RX_BUFFERS; ul_index++) {\r
+               xMicrelDevice.rx_buffers[ul_index] = NULL;\r
+               xMicrelDevice.rx_ready[ul_index] = pdFALSE;\r
+       }\r
+\r
+       /* Build RX buffer and descriptors. */\r
+       ksz8851snl_rx_populate_queue();\r
+}\r
+\r
+/**\r
+ * \brief Set up the TX descriptor ring buffers.\r
+ *\r
+ * This function sets up the descriptor list used for TX packets.\r
+ *\r
+ */\r
+static void ksz8851snl_tx_init()\r
+{\r
+       uint32_t ul_index = 0;\r
+\r
+       /* Init TX index pointer. */\r
+       xMicrelDevice.us_tx_head = 0;\r
+       xMicrelDevice.us_tx_tail = 0;\r
+\r
+       /* Set up the TX descriptors */\r
+       for( ul_index = 0; ul_index < MICREL_TX_BUFFERS; ul_index++ )\r
+       {\r
+               xMicrelDevice.tx_busy[ul_index] = pdFALSE;\r
+       }\r
+       xMicrelDevice.tx_space = 6144;\r
+}\r
+\r
+/**\r
+ * \brief Initialize ksz8851snl ethernet controller.\r
+ *\r
+ * \note Called from ethernetif_init().\r
+ *\r
+ * \param netif the lwIP network interface structure for this ethernetif.\r
+ */\r
+static void ksz8851snl_low_level_init( void )\r
+{\r
+       ksz8851snl_rx_init();\r
+       ksz8851snl_tx_init();\r
+\r
+       /* Enable NVIC interrupts. */\r
+       NVIC_SetPriority(SPI_IRQn, INT_PRIORITY_SPI);\r
+       NVIC_EnableIRQ(SPI_IRQn);\r
+\r
+       /* Initialize SPI link. */\r
+       if( ksz8851snl_init() < 0 )\r
+       {\r
+               FreeRTOS_printf( ( "ksz8851snl_low_level_init: failed to initialize the Micrel driver!\n" ) );\r
+               configASSERT(0 == 1);\r
+       }\r
+       memset( xMicrelDevice.pusHashTable, 255, sizeof( xMicrelDevice.pusHashTable ) );\r
+       ksz8851_reg_write( REG_MAC_HASH_0, FreeRTOS_htons( xMicrelDevice.pusHashTable[ 0 ] ) );\r
+       ksz8851_reg_write( REG_MAC_HASH_2, FreeRTOS_htons( xMicrelDevice.pusHashTable[ 1 ] ) );\r
+       ksz8851_reg_write( REG_MAC_HASH_4, FreeRTOS_htons( xMicrelDevice.pusHashTable[ 2 ] ) );\r
+       ksz8851_reg_write( REG_MAC_HASH_6, FreeRTOS_htons( xMicrelDevice.pusHashTable[ 3 ] ) );\r
+\r
+       /* Initialize interrupt line INTN. */\r
+       configure_intn( INTN_Handler );\r
+}\r
+\r
+/**\r
+ * \brief Use pre-allocated pbuf as DMA source and return the incoming packet.\r
+ *\r
+ * \param netif the lwIP network interface structure for this ethernetif.\r
+ *\r
+ * \return a pbuf filled with the received packet (including MAC header).\r
+ * 0 on memory error.\r
+ */\r
+static NetworkBufferDescriptor_t *ksz8851snl_low_level_input( void )\r
+{\r
+NetworkBufferDescriptor_t *pxNetworkBuffer = NULL;\r
+int rxTail = xMicrelDevice.us_rx_tail;\r
+\r
+       /* Check that descriptor is owned by software (ie packet received). */\r
+       if( xMicrelDevice.rx_ready[ rxTail ] != pdFALSE )\r
+       {\r
+\r
+               /* Fetch pre-allocated buffer */\r
+               pxNetworkBuffer = xMicrelDevice.rx_buffers[ rxTail ];\r
+\r
+               /* Remove this pbuf from its descriptor. */\r
+               xMicrelDevice.rx_buffers[ rxTail ] = NULL;\r
+\r
+               /* Clears rx_ready and sets rx_buffers. */\r
+               ksz8851snl_rx_populate_queue();\r
+\r
+               if( ++rxTail == MICREL_RX_BUFFERS )\r
+               {\r
+                       rxTail = 0;\r
+               }\r
+               xMicrelDevice.us_rx_tail = rxTail;\r
+       }\r
+\r
+       return pxNetworkBuffer;\r
+}\r
+/*-----------------------------------------------------------*/\r
+\r
+static uint32_t prvEMACRxPoll( void )\r
+{\r
+NetworkBufferDescriptor_t *pxNetworkBuffer;\r
+IPStackEvent_t xRxEvent = { eNetworkRxEvent, NULL };\r
+uint32_t ulReturnValue = 0;\r
+\r
+       for( ;; )\r
+       {\r
+       /* Only for logging. */\r
+       int rxTail = xMicrelDevice.us_rx_tail;\r
+       EthernetHeader_t *pxEthernetHeader;\r
+\r
+       pxNetworkBuffer = ksz8851snl_low_level_input();\r
+       \r
+               if( pxNetworkBuffer == NULL )\r
+               {\r
+                       break;\r
+               }\r
+               pxEthernetHeader = ( EthernetHeader_t * ) ( pxNetworkBuffer->pucEthernetBuffer );\r
+\r
+               if( ( pxEthernetHeader->usFrameType != ipIPv4_FRAME_TYPE ) &&\r
+                       ( pxEthernetHeader->usFrameType != ipARP_FRAME_TYPE     ) )\r
+               {\r
+                       FreeRTOS_printf( ( "Frame type %02X received\n", pxEthernetHeader->usFrameType ) );\r
+               }\r
+               ulReturnValue++;\r
+\r
+               xRxEvent.pvData = ( void * )pxNetworkBuffer;\r
+               /* Send the descriptor to the IP task for processing. */\r
+               if( xSendEventStructToIPTask( &xRxEvent, 100UL ) != pdTRUE )\r
+               {\r
+                       vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer );\r
+                       iptraceETHERNET_RX_EVENT_LOST();\r
+                       FreeRTOS_printf( ( "prvEMACRxPoll: Can not queue return packet!\n" ) );\r
+               }\r
+       }\r
+\r
+       return ulReturnValue;\r
+}\r
+/*-----------------------------------------------------------*/\r
+\r
+static void prvEMACHandlerTask( void *pvParameters )\r
+{\r
+TimeOut_t xPhyTime;\r
+TickType_t xPhyRemTime;\r
+TickType_t xLoggingTime;\r
+UBaseType_t uxLastMinBufferCount = 0;\r
+UBaseType_t uxCurrentCount;\r
+BaseType_t xResult = 0;\r
+uint32_t xStatus;\r
+const TickType_t ulMaxBlockTime = pdMS_TO_TICKS( EMAC_MAX_BLOCK_TIME_MS );\r
+#if( ipconfigCHECK_IP_QUEUE_SPACE != 0 )\r
+       UBaseType_t uxLastMinQueueSpace = 0;\r
+#endif\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
+       xLoggingTime = xTaskGetTickCount();\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
+               /* Run the state-machine of the ksz8851 driver. */\r
+               ksz8851snl_update();\r
+\r
+               if( ( ulISREvents & EMAC_IF_ALL_EVENT ) == 0 )\r
+               {\r
+                       /* No events to process now, wait for the next. */\r
+                       ulTaskNotifyTake( pdTRUE, ulMaxBlockTime );\r
+               }\r
+\r
+               if( ( xTaskGetTickCount() - xLoggingTime ) > 10000 )\r
+               {\r
+                       xLoggingTime += 10000;\r
+                       FreeRTOS_printf( ( "Now Tx/Rx %7d /%7d\n",\r
+                               xMicrelDevice.ul_total_tx, xMicrelDevice.ul_total_rx ) );\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
+               }\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
+                       /* As long as packets are being received, assume that\r
+                       the Link Status is high. */\r
+                       ulPHYLinkStatus |= BMSR_LINK_STATUS;\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
+                       ( xMicrelDevice.ul_spi_pdc_status == SPI_PDC_IDLE ) )\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