changeset 3241:acfb9769162d

* cdl/enc424j600_eth_drivers.cdl: * host/enc424j600_eth_drivers.cdl: * include/enc424j600_eth.h: * src/enc424j600_spi.h: * src/enc424j600_spi.c: * tests/netconn_test_server.c: New package [Bugzilla ID #1000910].
author jlarmour
date Fri, 04 May 2012 16:40:04 +0000
parents b67f16dc337c
children 1057533611c4
files packages/devs/eth/microchip/enc424j600/current/ChangeLog packages/devs/eth/microchip/enc424j600/current/cdl/enc424j600_eth_drivers.cdl packages/devs/eth/microchip/enc424j600/current/host/test_tcp_client.c packages/devs/eth/microchip/enc424j600/current/include/enc424j600_eth.h packages/devs/eth/microchip/enc424j600/current/src/enc424j600_spi.c packages/devs/eth/microchip/enc424j600/current/src/enc424j600_spi.h packages/devs/eth/microchip/enc424j600/current/tests/netconn_test_server.c
diffstat 7 files changed, 2640 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
new file mode 100644
--- /dev/null
+++ b/packages/devs/eth/microchip/enc424j600/current/ChangeLog
@@ -0,0 +1,33 @@
+2012-04-20  Ilija Stanislevik  <ilijas@siva.mk>
+
+	* cdl/enc424j600_eth_drivers.cdl:
+	* host/enc424j600_eth_drivers.cdl:
+	* include/enc424j600_eth.h:
+	* src/enc424j600_spi.h:
+	* src/enc424j600_spi.c:
+	* tests/netconn_test_server.c:
+	New package [Bugzilla ID #1000910].
+
+//===========================================================================
+// ####GPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 2012 Free Software Foundation, Inc.
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 or (at your option) any
+// later version.
+//
+// This program is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the
+// Free Software Foundation, Inc., 51 Franklin Street,
+// Fifth Floor, Boston, MA  02110-1301, USA.
+// -------------------------------------------
+// ####GPLCOPYRIGHTEND####
+//===========================================================================
new file mode 100644
--- /dev/null
+++ b/packages/devs/eth/microchip/enc424j600/current/cdl/enc424j600_eth_drivers.cdl
@@ -0,0 +1,271 @@
+# ====================================================================
+#
+#      enc424j600_eth_drivers.cdl
+#
+#      Ethernet driver for Microchip ENC424J600 controller
+#
+# ====================================================================
+## ####ECOSGPLCOPYRIGHTBEGIN####
+## -------------------------------------------
+## This file is part of eCos, the Embedded Configurable Operating System.
+## Copyright (C) 2009, 2010 Free Software Foundation, Inc.
+##
+## eCos is free software; you can redistribute it and/or modify it under
+## the terms of the GNU General Public License as published by the Free
+## Software Foundation; either version 2 or (at your option) any later
+## version.
+##
+## eCos is distributed in the hope that it will be useful, but WITHOUT
+## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+## FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+## for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with eCos; if not, write to the Free Software Foundation, Inc.,
+## 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+##
+## As a special exception, if other files instantiate templates or use
+## macros or inline functions from this file, or you compile this file
+## and link it with other works to produce a work based on this file,
+## this file does not by itself cause the resulting work to be covered by
+## the GNU General Public License. However the source code for this file
+## must still be made available in accordance with section (3) of the GNU
+## General Public License v2.
+##
+## This exception does not invalidate any other reasons why a work based
+## on this file might be covered by the GNU General Public License.
+## -------------------------------------------
+## ####ECOSGPLCOPYRIGHTEND####
+# ====================================================================
+######DESCRIPTIONBEGIN####
+#
+# Author(s):      Ilija Stanislevik
+# Contributors:
+# Date:           2010-11-23
+#
+#####DESCRIPTIONEND####
+#
+# ====================================================================
+
+cdl_package CYGPKG_DEVS_ETH_ENC424J600 {
+    display       "Microchip ENC424J600 / ENC624J600 ethernet controller"
+
+    parent        CYGPKG_IO_ETH_DRIVERS
+    active_if     CYGPKG_IO_ETH_DRIVERS
+
+    implements    CYGHWR_NET_DRIVERS
+    implements    CYGHWR_NET_DRIVER_ETH0
+    implements    CYGINT_IO_ETH_MULTICAST
+
+    active_if     CYGPKG_IO_SPI
+
+    requires { CYGINT_IO_ETH_INT_SUPPORT_REQUIRED implies
+               (CYGNUM_DEVS_ETH_ENC424J600_INTERRUPT_VECTOR != "")
+             }
+
+    requires { CYGINT_IO_ETH_INT_SUPPORT_REQUIRED implies
+               (CYGNUM_DEVS_ETH_ENC424J600_INTERRUPT_PRIORITY != "")
+             }
+
+    include_dir   cyg/io/eth
+    description   "
+        Driver for Microchip ENC424J600 and ENC624J600 Ethernet controllers,
+        connected to the platform with an SPI interface."
+
+    compile       -library=libextras.a enc424j600_spi.c
+
+    define_proc {
+        puts $::cdl_header "#include <pkgconf/system.h>"
+    }
+
+    cdl_component CYGPKG_DEVS_ETH_ENC424J600_OPTIONS {
+        display     "Microchip ENC424J600 driver build options"
+        flavor      none
+        no_define
+
+        cdl_option CYGPKG_DEVS_ETH_ENC424J600_CFLAGS_ADD {
+            display       "Additional compiler flags"
+            flavor        data
+            no_define
+            default_value { "-D_KERNEL -D__ECOS" }
+            description   "
+                This option modifies the set of compiler flags for
+                building the ENC424J600 ethernet driver package.
+                These flags are used in addition
+                to the set of global flags."
+        }
+
+    }
+
+    cdl_option CYGDAT_IO_ETH_ENC424J600_NAME {
+        display       "Ethernet device name"
+        flavor        data
+        default_value { "\"eth0\"" }
+    }
+
+    cdl_component CYGSEM_DEVS_ETH_ENC424J600_NO_AUTO_NEGOTIATION {
+        display       "No auto negotiation of speed and duplex"
+        default_value 0
+        description   "
+            Enable this component in order to manually configure the link speed
+            and duplex configuration. Otherwise the chip will automatically
+            negotiate them with the peer."
+
+        cdl_option CYGNUM_DEVS_ETH_ENC424J600_SPEED {
+            display       "Ethernet speed in megabit per second"
+            flavor        data
+            legal_values  { 100 10 }
+            default_value 100
+        }
+
+        cdl_option CYGSEM_DEVS_ETH_ENC424J600_FULL_DUPLEX {
+            display       "Full duplex"
+            default_value 1
+        }
+    }
+
+    cdl_component CYGSEM_DEVS_ETH_ENC424J600_SET_ESA {
+        display       "Set the Ethernet station address"
+        flavor        bool
+        default_value 0
+        description   "
+            Enabling this option will override the ENC424J600
+            factory set ethernet station address (MAC address)."
+
+        cdl_option CYGDAT_DEVS_ETH_ENC424J600_ESA {
+            display       "Ethernet station address"
+            flavor        data
+            default_value { " { 0x00, 0x04, 0xa3, 0x10, 0x08, 0x3e } "}
+            description   "The ethernet station address"
+        }
+    }
+
+    cdl_option CYGNUM_DEVS_ETH_ENC424J600_ACCEPTABLE_PACKET_SIZE {
+        display       "Largest acceptable packet size"
+        flavor        data
+        legal_values  60 to 9600
+        default_value 1518
+        description "
+            This option configures the size in bytes of the largest
+            packet expected to be sent or received. The chip will
+            truncate any received or transmitted packet to this
+            size. This size excludes any space required for the
+            Preamble, Start of Frame Delimiter and the Frame Check
+            Sequence (CRC)."
+    }
+
+    cdl_option CYGNUM_DEVS_ETH_ENC424J600_TXBUF_SIZE {
+        display       "Size of transmit buffer"
+        flavor        data
+        legal_values  CYGNUM_DEVS_ETH_ENC424J600_ACCEPTABLE_PACKET_SIZE to (0x6000 - CYGNUM_DEVS_ETH_ENC424J600_ACCEPTABLE_PACKET_SIZE -2)
+        default_value CYGNUM_DEVS_ETH_ENC424J600_ACCEPTABLE_PACKET_SIZE
+        description "
+            The 0x6000 bytes of on-chip RAM are divided between transmit
+            buffer and receive buffer. This parameter impacts the sizes of
+            both. The transmit buffer must be large enough to hold one
+            transmit packet."
+    }
+
+    cdl_option CYGSEM_DEVS_ETH_ENC424J600_FLOWC {
+        display       "Flow control"
+        flavor        data
+        default_value { "None" }
+        legal_values  { "None" "OnChip" }
+        description   "
+            Enabling flow control prevents overflow of the input buffer if
+            received packets are not processed fast enough."
+    }
+
+    cdl_component CYGNUM_DEVS_ETH_ENC424J600_FLOW_CONTROL_PARAMETERS {
+        display       "Flow control parameters"
+        active_if     { CYGSEM_DEVS_ETH_ENC424J600_FLOWC != "None" }
+        flavor        none
+
+        cdl_option CYGNUM_DEVS_ETH_ENC424J600_FLOWC_UPPER_WATERMARK {
+            display       "Upper threshold for flow control"
+            flavor        data
+            default_value 16
+            legal_values  2 to 255
+            description   "
+                This threshold is measured in multiples of blocks of
+                96 bytes. When this number of blocks have been used
+                in the on-chip receive buffer, the device considers its
+                receive buffer full and initiates flow control."
+        }
+
+        cdl_option CYGNUM_DEVS_ETH_ENC424J600_FLOWC_LOWER_WATERMARK {
+            display       "Lower threshold for flow control"
+            flavor        data
+            default_value 15
+            legal_values  1 to (CYGNUM_DEVS_ETH_ENC424J600_FLOWC_UPPER_WATERMARK - 1)
+            description   "
+                This threshold is measured in multiples of blocks of
+                96 bytes. If flow control has been activated, then
+                when the number of occupied blocks in the on-chip
+                receive buffer falls below this level, the device
+                considers the buffer to be empty enough to receive
+                more data and therefore disengages flow control."
+        }
+
+        cdl_option CYGNUM_DEVS_ETH_ENC424J600_FLOWC_PAUSE {
+            display       "Duration of flow control pause"
+            flavor        data
+            default_value { 0x1000 }
+            legal_values  0 to 0xffff
+            description   "
+                Duration of flow control pause in units of 512 bit times. Valid for full-duplex
+                operation only."
+        }
+    }
+
+    cdl_option CYGNUM_DEVS_ETH_ENC424J600_CLOCKOUT_FREQUENCY {
+        display       "Frequency of clock output at the CLKOUT pin"
+        flavor        data
+        default_value { "0" }
+        legal_values  {
+            "0" "33M33" "25M00"
+            "20M00" "16M67" "12M50" "10M00"
+            "8M333" "8M000" "6M250" "5M000"
+            "4M000" "3M125"
+            "0M0" "100K" "50K"
+        }
+        description   "
+            The ENC424J600 has a clock output which can be used by
+            other parts of the system.  M stands for megahertz, K for
+            kilohertz, and where these letters are used stands for the
+            position of a decimal point.  Values 0 and 0M0 both mean
+            DC output, or, in other words, no clock output.  This
+            driver does not make use of the clock output facility
+            itself. Control of the clock output frequency is provided
+            here as a convenience."
+    }
+
+    cdl_component CYGPKG_DEVS_ETH_ENC424J600_INTERRUPT {
+        display       "Interrupt configuration"
+        flavor        none
+        no_define
+        active_if     CYGINT_IO_ETH_INT_SUPPORT_REQUIRED
+        description   "
+            Configuration options related to interrupt handling."
+
+        cdl_option CYGNUM_DEVS_ETH_ENC424J600_INTERRUPT_PRIORITY {
+            display       "Interrupt priority"
+            flavor        data
+            default_value { is_active(CYGNUM_HAL_SPIETH_INTERRUPT_PRIORITY) ? CYGNUM_HAL_SPIETH_INTERRUPT_PRIORITY : "\"\"" }
+            description   "
+                Interrupt priority for the ENC424J600. The default value
+                is typically set by the platform HAL."
+        }
+
+        cdl_option CYGNUM_DEVS_ETH_ENC424J600_INTERRUPT_VECTOR {
+            display       "Interrupt vector"
+            flavor data
+            default_value { is_active(CYGNUM_ETH_SPIETH_HAL_INTERRUPT_VECTOR) ? CYGNUM_ETH_SPIETH_HAL_INTERRUPT_VECTOR : "\"\"" }
+            description   "
+                Interrupt vector for the ENC424J600. The default value is
+                typically set by the platform HAL."
+        }
+    }
+}
+
+# End of enc424j600_eth_drivers.cdl
new file mode 100644
--- /dev/null
+++ b/packages/devs/eth/microchip/enc424j600/current/host/test_tcp_client.c
@@ -0,0 +1,198 @@
+//=================================================================
+//
+//        test_tcp_client.c
+//
+//        TCP/Ethernet testing - host-side
+//
+//==========================================================================
+// ####ECOSGPLCOPYRIGHTBEGIN####                                            
+// -------------------------------------------                              
+// This file is part of eCos, the Embedded Configurable Operating System.   
+// Copyright (C) 2010 Free Software Foundation, Inc.
+//
+// eCos is free software; you can redistribute it and/or modify it under    
+// the terms of the GNU General Public License as published by the Free     
+// Software Foundation; either version 2 or (at your option) any later      
+// version.                                                                 
+//
+// eCos is distributed in the hope that it will be useful, but WITHOUT      
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or    
+// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License    
+// for more details.                                                        
+//
+// You should have received a copy of the GNU General Public License        
+// along with eCos; if not, write to the Free Software Foundation, Inc.,    
+// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.            
+//
+// As a special exception, if other files instantiate templates or use      
+// macros or inline functions from this file, or you compile this file      
+// and link it with other works to produce a work based on this file,       
+// this file does not by itself cause the resulting work to be covered by   
+// the GNU General Public License. However the source code for this file    
+// must still be made available in accordance with section (3) of the GNU   
+// General Public License v2.                                               
+//
+// This exception does not invalidate any other reasons why a work based    
+// on this file might be covered by the GNU General Public License.         
+// -------------------------------------------                              
+// ####ECOSGPLCOPYRIGHTEND####                                              
+//==========================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s):     Ilija Stanislevik
+// Date:          2010-02-10
+//####DESCRIPTIONEND####
+//==========================================================================
+
+/*
+ The target hardware runs a listener/server application. The server
+ calculates checksum on recived packets for the whole duration of 
+ connection. Once conection ends, it displays the checksum.
+ 
+ The host client generates pseudorandom data and sends it to the target.
+ Before sending, it calculates checksum. Once data sent, it dispalys
+ the checksum for comparison with the checksum at target side.
+ 
+ For now, no attempts has been made to employ a host other than Linux.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+
+#define NUM_ARG 4
+
+struct addrinfo * hostaddr_p;
+int socket_d;
+struct sockaddr serv_addr;
+
+void print_syntax(char *name)
+{
+    printf("Syntax: %s ip_address port bytes_to_send\n", name);
+    printf("        Format ip_address as d1.d2.d3.d4, where dx is integer 0-255\n\n");
+}
+
+int main(int argc, char *argv[])
+{
+    int retval;
+    struct addrinfo hint_s;
+    struct addrinfo *p;
+    char ipstr[INET6_ADDRSTRLEN];
+    unsigned long int msg_len;
+    unsigned long int left_to_send;
+    unsigned long int i;
+    unsigned long int csum;
+    char *msg_p = NULL;
+    char *fill_p;
+    unsigned char value;
+
+    if(NUM_ARG != argc)
+    {
+        printf("\nError:  Wrong number of arguments %d instead of %d.\n", argc-1, NUM_ARG-1);
+        print_syntax(argv[0]);
+        return EXIT_FAILURE;
+    }
+
+    memset(&hint_s, 0, sizeof(struct addrinfo));
+    hint_s.ai_family = AF_INET;
+    hint_s.ai_socktype = SOCK_STREAM;
+    hint_s.ai_flags = AI_NUMERICSERV;
+    hint_s.ai_protocol = 0;          /* Any protocol */
+    hint_s.ai_canonname = NULL;
+    hint_s.ai_addr = NULL;
+    hint_s.ai_next = NULL;
+    retval = getaddrinfo(argv[1], argv[2], &hint_s, &hostaddr_p);
+    if(0 != retval)
+    {
+        printf("\nError:  %s\n", gai_strerror(retval));
+        print_syntax(argv[0]);
+        return EXIT_FAILURE;
+    }
+
+    printf("IP addresses for %s:\n", argv[1]);
+
+    for(p = hostaddr_p; p != NULL; p = p->ai_next)
+    {
+        void *addr;
+        char *ipver;
+        // get the pointer to the address itself,
+        // different fields in IPv4 and IPv6:
+        if (p->ai_family == AF_INET)
+        { // IPv4
+            struct sockaddr_in *ipv4 = (struct sockaddr_in *)p->ai_addr;
+            addr = &(ipv4->sin_addr);
+            ipver = "IPv4";
+        }
+        else
+        { // IPv6
+            struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *)p->ai_addr;
+            addr = &(ipv6->sin6_addr);
+            ipver = "IPv6";
+        }
+        // convert the IP to a string and print it:
+        inet_ntop(p->ai_family, addr, ipstr, sizeof ipstr);
+        printf(" %s: %s\n", ipver, ipstr);
+    }
+
+    socket_d = socket(hostaddr_p->ai_family, hostaddr_p->ai_socktype, hostaddr_p->ai_protocol);
+    if(-1 == socket_d)
+    {
+        printf("Error:  Can't get socket. errno %d\n", errno);
+        return EXIT_FAILURE;
+    }
+
+    retval = connect(socket_d, hostaddr_p->ai_addr, hostaddr_p->ai_addrlen);
+    if(0 != retval)
+    {
+        perror("\nError:  Failed connect()\n");
+        return EXIT_FAILURE;
+    }
+
+    // Prepare message to send
+    msg_len = strtoul(argv[3], NULL, 0);
+    msg_len &= ~0x3;
+    if (0 == msg_len)
+    {
+        printf("Nothing to do (bytes_to_send == 0). Exiting.\n");
+        return EXIT_SUCCESS;
+    }
+    else
+    {
+        printf("Preparing to send %lu bytes.\n", msg_len);
+    }
+
+    msg_p = malloc(msg_len);
+    if(NULL == msg_p)
+    {
+        printf("Error:  Can't allocate %lu bytes.\n", msg_len);
+        return EXIT_FAILURE;
+    }
+
+    fill_p = msg_p;
+    csum = 0;
+
+    for(i=0; i<msg_len; i++)
+    {
+        value = random() & 0xff;
+        *fill_p++ = value;
+        csum += value;
+    }
+
+    left_to_send = msg_len;
+    do
+    {
+        retval = send(socket_d, msg_p, msg_len, 0);
+        left_to_send -= retval;
+        printf("%d bytes sent.\n", retval);
+    } while(left_to_send);
+    printf("Checksum %08lx\n", csum);
+
+    freeaddrinfo(hostaddr_p); // free the linked list
+
+    return EXIT_SUCCESS;
+}
new file mode 100644
--- /dev/null
+++ b/packages/devs/eth/microchip/enc424j600/current/include/enc424j600_eth.h
@@ -0,0 +1,100 @@
+#ifndef CYGONCE_DEVS_ETH_ENC424J600_ETH_H_
+#define CYGONCE_DEVS_ETH_ENC424J600_ETH_H_
+
+//==========================================================================
+//
+//      enc424j600_eth.h
+//
+//      Microchip enc424j600 Ethernet chip
+//
+//==========================================================================
+// ####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 2010, 2012 Free Software Foundation, Inc.
+//
+// eCos is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 2 or (at your option) any later
+// version.
+//
+// eCos is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+// for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with eCos; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+//
+// As a special exception, if other files instantiate templates or use
+// macros or inline functions from this file, or you compile this file
+// and link it with other works to produce a work based on this file,
+// this file does not by itself cause the resulting work to be covered by
+// the GNU General Public License. However the source code for this file
+// must still be made available in accordance with section (3) of the GNU
+// General Public License v2.
+//
+// This exception does not invalidate any other reasons why a work based
+// on this file might be covered by the GNU General Public License.
+// -------------------------------------------
+// ####ECOSGPLCOPYRIGHTEND####
+//==========================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s):    Ilija Stanislevik
+// Contributors:
+// Date:         2010-11-23
+// Purpose:
+// Description:
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+#include <pkgconf/devs_eth_enc424j600.h>
+
+// Ethernet flow control options
+enum enc424j600_flow_control_e
+{
+    ENC424J600_NO_FC,            // No flow control
+    ENC424J600_ONCHIP_AUTO_FC    // On-chip automatic flow control. Not tested yet.
+};
+
+// enc424j600 clock out frequencies
+enum enc424j600_clkout_e
+{
+    ENC424J600_CLKO_0,    // DC
+    ENC424J600_CLKO_33M33, ENC424J600_CLKO_25M00, ENC424J600_CLKO_20M00,
+    ENC424J600_CLKO_16M67, ENC424J600_CLKO_12M50, ENC424J600_CLKO_10M00,
+    ENC424J600_CLKO_8M333, ENC424J600_CLKO_8M000, ENC424J600_CLKO_6M250,
+    ENC424J600_CLKO_5M000, ENC424J600_CLKO_4M000, ENC424J600_CLKO_3M125,
+    ENC424J600_CLKO_0M0,  // DC
+    ENC424J600_CLKO_100K, ENC424J600_CLKO_50K
+};
+
+struct enc424j600_priv_data_s;
+typedef cyg_bool (*provide_esa_t)(struct enc424j600_priv_data_s*);
+
+typedef struct enc424j600_priv_data_s
+{
+    // Configurable data
+    cyg_spi_device            *spi_service_device; // SPI device used to communicate
+                                                   // with the Ethernet chip
+    provide_esa_t              provide_esa;
+    bool                       hardwired_esa;
+    unsigned char              esa[ETHER_ADDR_LEN];
+    cyg_handle_t               interrupt_handle;
+    cyg_interrupt              interrupt_object;
+    struct cyg_netdevtab_entry *tab;
+
+    // Really private data
+    cyg_uint16                 NextPacketPointer;
+    enum { ENC424J600_LINK_OFF, ENC424J600_LINK_ON } link_status;
+    bool                       txbusy;
+    unsigned long              txkey;
+} enc424j600_priv_data_t;
+
+#endif /* CYGONCE_DEVS_ETH_ENC424J600_ETH_H_ */
+
+// End of enc424j600_eth.h
new file mode 100644
--- /dev/null
+++ b/packages/devs/eth/microchip/enc424j600/current/src/enc424j600_spi.c
@@ -0,0 +1,1340 @@
+//==========================================================================
+//
+//      enc424j600_spi.c
+//
+//      Microchip enc424j600 Ethernet chip
+//
+//==========================================================================
+// ####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 2010, 2012 Free Software Foundation, Inc.
+//
+// eCos is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 2 or (at your option) any later
+// version.
+//
+// eCos is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+// for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with eCos; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+//
+// As a special exception, if other files instantiate templates or use
+// macros or inline functions from this file, or you compile this file
+// and link it with other works to produce a work based on this file,
+// this file does not by itself cause the resulting work to be covered by
+// the GNU General Public License. However the source code for this file
+// must still be made available in accordance with section (3) of the GNU
+// General Public License v2.
+//
+// This exception does not invalidate any other reasons why a work based
+// on this file might be covered by the GNU General Public License.
+// -------------------------------------------
+// ####ECOSGPLCOPYRIGHTEND####
+//==========================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s):    Ilija Stanislevik
+// Contributors:
+// Date:         2010-11-23
+// Purpose:
+// Description:
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+#include <cyg/hal/hal_io.h>
+#include <cyg/hal/hal_if.h>
+
+#include <cyg/infra/cyg_type.h>
+#include <cyg/hal/hal_arch.h>
+#include <cyg/infra/cyg_ass.h>
+#include <cyg/infra/cyg_trac.h>
+#include <cyg/infra/diag.h>
+#include <cyg/hal/drv_api.h>
+#include <cyg/io/eth/netdev.h>
+#include <cyg/io/eth/eth_drv.h>
+
+#include <cyg/io/spi.h>                 // Common SPI API
+
+#include "enc424j600_spi.h"
+#include <cyg/io/eth/enc424j600_eth.h>
+
+// Set ENC424J600_DEBUG to:
+// 0 to suppress all printout
+// 1 to print error reports
+// 2 to print interrupt tracing
+// 4 printout _init() progress
+// 8 to print progress tracing data
+// 0x10  for test with dummy stack
+// 0x20  to printout status registers
+#define ENC424J600_DEBUG (0)
+
+#define ENC424J600_DONT_DROP_CS    (0)
+#define ENC424J600_DO_DROP_CS      (1)
+#define ENC424J600_TXBUF_START     (0)
+
+#define ENC424J600_RXBUF_START (ENC424J600_TXBUF_START + CYGNUM_DEVS_ETH_ENC424J600_TXBUF_SIZE)
+
+#ifndef CYGINT_IO_ETH_INT_SUPPORT_REQUIRED
+#   define SPI_POLLING true
+#else
+#   define SPI_POLLING false
+#endif
+
+static enc424j600_priv_data_t eth0_enc424j600_priv_data;
+
+ETH_DRV_SC(eth0_spi_sc,
+           &eth0_enc424j600_priv_data,  // Driver specific data.
+           CYGDAT_IO_ETH_ENC424J600_NAME,
+           enc424j600_spi_start,
+           enc424j600_spi_stop,
+           enc424j600_spi_control,
+           enc424j600_spi_can_send,
+           enc424j600_spi_send,
+           enc424j600_spi_recv,
+           enc424j600_spi_deliver,
+           enc424j600_spi_poll,
+           enc424j600_spi_int_vector
+);
+
+NETDEVTAB_ENTRY(eth0_spi_netdev,
+                "eth_spi",
+                enc424j600_spi_init,
+                &eth0_spi_sc);
+
+// Local service functions
+
+// Interface for enc424j600 "single byte instruction".
+static void
+simple_operation(enc424j600_priv_data_t *dpd, enum enc424j600_spi_opcode_1_e opcode)
+{
+    cyg_spi_transaction_begin(dpd->spi_service_device);
+    cyg_spi_transaction_transfer(dpd->spi_service_device,
+            SPI_POLLING,
+            1,
+            & opcode,
+            NULL,           // not interested in answer
+            ENC424J600_DO_DROP_CS);
+    cyg_spi_transaction_end(dpd->spi_service_device);
+
+    return;
+}
+
+// Interface for enc424j600 "banked N-byte instructions".
+// Banked read, write, bit set or bit clear operation with control register
+static int
+banked_register_operation(enc424j600_priv_data_t *cpd,
+    enum enc424j600_spi_opcode_e opcode,
+    cyg_uint8 address,
+    cyg_uint16 length,
+    cyg_uint8 *buffer)
+{
+    if ((NULL == buffer) || (0 == length))
+    {
+#if ENC424J600_DEBUG & 1
+        diag_printf("Wrong parm buffer=0x%x or length=%d.\n", (int)buffer, length);
+#endif
+        return -1;
+    }
+
+    if ((ENC424J600_ECON1H < address) || (opcode & ENC424J600_ECON1H))
+    {
+#if ENC424J600_DEBUG & 1
+        diag_printf("Wrong address=0x%02x or opcode=0x%02x for banked operation.\n",
+            address, opcode);
+#endif
+        return -1;
+    }
+
+    address |= opcode;  // combine them in single byte
+    cyg_spi_transaction_begin(cpd->spi_service_device);
+    // Send the opcode and address,
+    cyg_spi_transaction_transfer(cpd->spi_service_device,
+        SPI_POLLING,
+        1,
+        & address,
+        NULL,           // not interested in answer
+        ENC424J600_DONT_DROP_CS);
+    // then the data.
+    cyg_spi_transaction_transfer(cpd->spi_service_device,
+        SPI_POLLING,
+        length,
+        (ENC424J600_READCR == opcode) ? NULL : buffer,
+        (ENC424J600_READCR == opcode) ? buffer : NULL,
+        ENC424J600_DO_DROP_CS);
+    cyg_spi_transaction_end(cpd->spi_service_device);
+
+    return 0;
+}
+
+// Interface for enc424j600 "unbanked N-byte instructions".
+// Unbanked read, write, bit set or bit clear operation with control register
+static int
+unbanked_register_operation(enc424j600_priv_data_t *cpd,
+    enum enc424j600_spi_opcode_u_e opcode,
+    cyg_uint8 address,
+    cyg_uint16 length,
+    cyg_uint8 *buffer)
+{
+    if ((NULL == buffer) || (0 == length))
+    {
+#if ENC424J600_DEBUG & 1
+        diag_printf("Wrong parm buffer=0x%x or length=%d.\n", (int)buffer, length);
+#endif
+        return -1;
+    }
+
+    cyg_spi_transaction_begin(cpd->spi_service_device);
+    // Send the opcode,
+    cyg_spi_transaction_transfer(cpd->spi_service_device,
+        SPI_POLLING,
+        1,
+        & opcode,
+        NULL,           // not interested in answer
+        ENC424J600_DONT_DROP_CS);
+    // then the address
+    cyg_spi_transaction_transfer(cpd->spi_service_device,
+        SPI_POLLING,
+        1,
+        & address,
+        NULL,           // not interested in answer
+        ENC424J600_DONT_DROP_CS);
+    // and finally the data.
+    cyg_spi_transaction_transfer(cpd->spi_service_device,
+        SPI_POLLING,
+        length,
+        (ENC424J600_READCRU == opcode) ? NULL : buffer,
+        (ENC424J600_READCRU == opcode) ? buffer : NULL,
+        ENC424J600_DO_DROP_CS);
+    cyg_spi_transaction_end(cpd->spi_service_device);
+
+    return 0;
+}
+
+// Get ESA from the Ethernet chip, unbanked
+static int
+read_esa_u(enc424j600_priv_data_t *cpd, cyg_uint8 *esa_buf)
+{
+    int retval = -1;
+    cyg_uint8 response_msg[ETHER_ADDR_LEN];
+
+#if ENC424J600_DEBUG & 8
+    diag_printf("read_esa_u()...\n");
+#endif
+    if (NULL == esa_buf)
+    {
+        return -1;
+    }
+
+    retval = unbanked_register_operation(cpd, ENC424J600_READCRU, ENC424J600_MAADR3_U, ETHER_ADDR_LEN,
+                                         &response_msg[0]);
+    if (0 != retval)
+    {
+        return retval;
+    }
+    *esa_buf++ = response_msg[4];
+    *esa_buf++ = response_msg[5];
+    *esa_buf++ = response_msg[2];
+    *esa_buf++ = response_msg[3];
+    *esa_buf++ = response_msg[0];
+    *esa_buf   = response_msg[1];
+
+    return 0;
+}
+
+// Set ESA into Ethernet chip, unbanked
+static int
+write_esa_u(enc424j600_priv_data_t *dpd, cyg_uint8 *esa_buf)
+{
+    int retval = -1;
+    cyg_uint8 msg[8];
+
+#if ENC424J600_DEBUG & 8
+    diag_printf("write_esa_u()...1...\n");
+#endif
+    if (NULL == esa_buf)
+    {
+        return -1;
+    }
+
+    msg[4] = *esa_buf++;
+    msg[5] = *esa_buf++;
+    msg[2] = *esa_buf++;
+    msg[3] = *esa_buf++;
+    msg[0] = *esa_buf++;
+    msg[1] = *esa_buf;
+
+    retval = unbanked_register_operation(dpd, ENC424J600_WRITECRU, ENC424J600_MAADR3_U, 6, &msg[0]);
+    if (0 != retval)
+    {
+#if ENC424J600_DEBUG & 1
+    diag_printf("Writing ESA into chip failed.\n");
+#endif
+        return retval;
+    }
+
+    return 0;
+}
+
+#if ENC424J600_DEBUG & 0x20
+// Read data from PHY register
+static void
+read_phy(enc424j600_priv_data_t *dpd,
+    const enum enc424j600_pr_address_e pr_address,
+    cyg_uint16 *retval_p)
+{
+    cyg_uint8 aux[2] = {pr_address, 0x01};
+    cyg_uint8 status;
+
+    unbanked_register_operation(dpd, ENC424J600_WRITECRU, ENC424J600_MIREGADR_U, 2, &aux[0]);
+    unbanked_register_operation(dpd, ENC424J600_READCRU, ENC424J600_MICMD_U, 2, &aux[0]);
+    aux[0] |= ENC424J600_MIIRD;
+    unbanked_register_operation(dpd, ENC424J600_WRITECRU, ENC424J600_MICMD_U, 2, &aux[0]);
+    CYGACC_CALL_IF_DELAY_US(26);
+    do
+    {   // Check and busy wait for read operation to complete
+        unbanked_register_operation(dpd, ENC424J600_READCRU, ENC424J600_MISTAT_U, 1, &status);
+    } while(0 != (status & ENC424J600_MISTAT_BUSY));
+
+    aux[0] &= !ENC424J600_MIIRD; // Clear ENC424J600_MIIRD bit
+    unbanked_register_operation(dpd, ENC424J600_WRITECRU, ENC424J600_MICMD_U, 2, &aux[0]);
+
+    unbanked_register_operation(dpd, ENC424J600_READCRU, ENC424J600_MIRD_U, 2, &aux[0]);
+    *retval_p = aux[0] + 256 * aux[1];
+
+    return;
+}
+#endif
+
+// Write data to PHY register
+static void
+write_phy(enc424j600_priv_data_t *dpd,
+    const enum enc424j600_pr_address_e pr_address,
+    const cyg_uint16 value)
+{
+    cyg_uint8 aux[2] = {pr_address, 0x01};
+
+    unbanked_register_operation(dpd, ENC424J600_WRITECRU, ENC424J600_MIREGADR_U, 2, &aux[0]);
+    aux[0] = value & 0xff;
+    aux[1] = (value >> 8) & 0xff;
+    unbanked_register_operation(dpd, ENC424J600_WRITECRU, ENC424J600_MIWR_U, 2, &aux[0]);
+
+    return;
+    // There must be no other MIIM operation in the following 25.6 us!
+}
+
+// Write value for on-chip pointer.
+static void
+set_pointer(enc424j600_priv_data_t *dpd,
+    enum enc424j600_spi_bufferp_e oc_pointer,
+    cyg_uint16 value
+    )
+{
+    cyg_spi_transaction_begin(dpd->spi_service_device);
+    cyg_spi_transaction_transfer(dpd->spi_service_device,
+        SPI_POLLING,
+        1,
+        & oc_pointer,
+        NULL,           // not interested in answer
+        ENC424J600_DONT_DROP_CS);
+    cyg_spi_transaction_transfer(dpd->spi_service_device,
+        SPI_POLLING,
+        2,
+        (cyg_uint8 *) & value,
+        NULL,           // not interested in answer
+        ENC424J600_DO_DROP_CS);
+    cyg_spi_transaction_end(dpd->spi_service_device);
+    return;
+}
+
+static inline void
+write_to_tx_buffer(enc424j600_priv_data_t *dpd,
+    cyg_uint16 length,
+    cyg_uint8 *buffer)
+{
+    cyg_uint8 oc_pointer = ENC424J600_WGPDATA; // We use General Purpose Buffer
+
+    cyg_spi_transaction_begin(dpd->spi_service_device);
+    cyg_spi_transaction_transfer(dpd->spi_service_device,
+        SPI_POLLING,
+        1,
+        & oc_pointer,
+        NULL,           // not interested in answer
+        ENC424J600_DONT_DROP_CS);
+    cyg_spi_transaction_transfer(dpd->spi_service_device,
+        SPI_POLLING,
+        length,
+        buffer,
+        NULL,
+        ENC424J600_DO_DROP_CS);
+    cyg_spi_transaction_end(dpd->spi_service_device);
+
+    return;
+}
+
+static int
+read_from_rx_buffer(enc424j600_priv_data_t *dpd,
+    cyg_uint16 length,
+    cyg_uint8 *buffer)
+{
+    cyg_uint8 oc_pointer = ENC424J600_RRXDATA;
+
+//    if ((0 == length) || (NULL == buffer))
+    if (0 == length)
+    {
+        return -1;
+    }
+    cyg_spi_transaction_begin(dpd->spi_service_device);
+    cyg_spi_transaction_transfer(dpd->spi_service_device,
+        SPI_POLLING,
+        1,
+        & oc_pointer,
+        NULL,           // not interested in answer
+        ENC424J600_DONT_DROP_CS);
+    cyg_spi_transaction_transfer(dpd->spi_service_device,
+        SPI_POLLING,
+        length,
+        NULL,
+        buffer,
+        ENC424J600_DO_DROP_CS);
+    cyg_spi_transaction_end(dpd->spi_service_device);
+
+    return 0;
+}
+
+static void
+set_MAC(enc424j600_priv_data_t *dpd,
+    cyg_uint8 ethernet_status   // As read from upper byte of ESTAT register
+    )
+{
+    cyg_uint8 aux[2];
+
+    if (0 != (ethernet_status & ENC424J600_PHYDPX))
+    {   // Full duplex
+#if ENC424J600_DEBUG & 0x20
+        diag_printf("Full duplex\n");
+#endif
+        unbanked_register_operation(dpd, ENC424J600_READCRU, ENC424J600_MACON2_U, 2, &aux[0]);
+        aux[0] |= ENC424J600_FULDPX;    // Set MAC to full duplex
+        unbanked_register_operation(dpd, ENC424J600_WRITECRU, ENC424J600_MACON2_U, 2, &aux[0]);
+
+        aux[1] = 0;
+        aux[0] = 0x15;  // Inter-packet gap
+        unbanked_register_operation(dpd, ENC424J600_WRITECRU, ENC424J600_MABBIPG_U, 2, &aux[0]);
+    }
+    else
+    {   // Half duplex
+#if ENC424J600_DEBUG & 0x20
+        diag_printf("Half duplex\n");
+#endif
+        unbanked_register_operation(dpd, ENC424J600_READCRU, ENC424J600_MACON2_U, 2, &aux[0]);
+        aux[0] &= !ENC424J600_FULDPX; // Set MAC to half duplex
+        unbanked_register_operation(dpd, ENC424J600_WRITECRU, ENC424J600_MACON2_U, 2, &aux[0]);
+
+        aux[1] = 0;
+        aux[0] = 0x12;  // Inter-packet gap
+        unbanked_register_operation(dpd, ENC424J600_WRITECRU, ENC424J600_MABBIPG_U, 2, &aux[0]);
+    }
+
+    return;
+}
+
+static void
+enc424j600_spi_LINKevent(struct eth_drv_sc *sc)
+{
+    enc424j600_priv_data_t *dpd = (enc424j600_priv_data_t *)sc->driver_private;
+    cyg_uint8 iflag = ENC424J600_LINKIF;
+    cyg_uint8 aux[2];
+
+#if ENC424J600_DEBUG & 8
+    diag_printf("enc424j600_spi_LINKevent()....\n");
+#endif
+
+    banked_register_operation(dpd, ENC424J600_READCR, ENC424J600_ESTATL, 2, &aux[0]);
+#if ENC424J600_DEBUG & 0x20
+    diag_printf("ESTAT %02x%02x Link ", aux[1], aux[0]);
+#endif
+    if (0 != (aux[1] & ENC424J600_PHYLNK))
+    {
+        dpd->link_status = ENC424J600_LINK_ON;
+
+#if ENC424J600_DEBUG & 0x20
+        diag_printf("ON\n");
+#endif
+        // Link is just established. Set up the MAC
+        set_MAC(dpd, aux[1]);
+    }
+    else
+    {
+        dpd->link_status = ENC424J600_LINK_OFF;
+
+#if ENC424J600_DEBUG & 0x20
+        diag_printf("OFF\n");
+#endif
+    }
+#if ENC424J600_DEBUG & 0x20
+    unbanked_register_operation(dpd, ENC424J600_READCRU, ENC424J600_MACON1_U, 2, &aux[0]);
+    diag_printf("MACON1 %02x%02x\n", aux[1], aux[0]);
+    unbanked_register_operation(dpd, ENC424J600_READCRU, ENC424J600_MACON2_U, 2, &aux[0]);
+    diag_printf("MACON2 %02x%02x\n", aux[1], aux[0]);
+    read_phy(dpd, ENC424J600_PHSTAT1, (cyg_uint16 *) &aux[0]);
+    diag_printf("PHSTAT1 %02x%02x\n", aux[1], aux[0]);
+    read_phy(dpd, ENC424J600_PHSTAT3, (cyg_uint16 *) &aux[0]);
+    diag_printf("PHSTAT3 %02x%02x\n", aux[1], aux[0]);
+    read_phy(dpd, ENC424J600_PHANLPA, (cyg_uint16 *) &aux[0]);
+    diag_printf("PHANLPA %02x%02x\n", aux[1], aux[0]);
+    read_phy(dpd, ENC424J600_PHANA, (cyg_uint16 *) &aux[0]);
+    diag_printf("PHANA %02x%02x\n", aux[1], aux[0]);
+    banked_register_operation(dpd, ENC424J600_READCR, ENC424J600_ECON1L, 2, &aux[0]);
+    diag_printf("ECON1 %02x%02x\n", aux[1], aux[0]);
+    unbanked_register_operation(dpd, ENC424J600_READCRU, ENC424J600_ECON2_U, 2, &aux[0]);
+    diag_printf("ECON2 %02x%02x\n", aux[1], aux[0]);
+
+#endif
+
+    // Clear Link interrupt flag
+    banked_register_operation(dpd, ENC424J600_BITFIELDCLEAR, ENC424J600_EIRH, 1, &iflag);
+}
+
+static void
+enc424j600_spi_PCFULevent(struct eth_drv_sc *sc)
+{
+    enc424j600_priv_data_t *dpd = (enc424j600_priv_data_t *)sc->driver_private;
+    cyg_uint8 flags = ENC424J600_PCFULIF;
+
+#if ENC424J600_DEBUG & 8
+    diag_printf("\nenc424j600_spi_PCFULevent()....\n\n");
+#endif
+    simple_operation(dpd, ENC424J600_SETPKTDEC);   // Decrement received packet counter
+    banked_register_operation(dpd, ENC424J600_BITFIELDCLEAR, ENC424J600_EIRL, 1, &flags);
+}
+
+static void
+enc424j600_spi_RXABTevent(struct eth_drv_sc *sc)
+{
+    enc424j600_priv_data_t *dpd = (enc424j600_priv_data_t *)sc->driver_private;
+    cyg_uint8 flags = ENC424J600_RXABTIF;
+
+#if ENC424J600_DEBUG & 8
+    diag_printf("\nenc424j600_spi_RXABTevent()....\n\n");
+#endif
+    banked_register_operation(dpd, ENC424J600_BITFIELDCLEAR, ENC424J600_EIRL, 1, &flags);
+}
+
+static void
+enc424j600_spi_TXevent(struct eth_drv_sc *sc)
+{
+    enc424j600_priv_data_t *dpd = (enc424j600_priv_data_t *)sc->driver_private;
+    cyg_uint8 iflag = ENC424J600_TXIF;
+
+#if ENC424J600_DEBUG & 8
+    diag_printf("TX event.\n");
+#endif
+
+    dpd->txbusy = false;
+    banked_register_operation(dpd, ENC424J600_BITFIELDCLEAR, ENC424J600_EIRL, 1, &iflag);
+}
+
+static void
+enc424j600_spi_TXABTevent(struct eth_drv_sc *sc)
+{
+    enc424j600_priv_data_t *dpd = (enc424j600_priv_data_t *)sc->driver_private;
+    cyg_uint8 iflag = ENC424J600_TXABTIF;
+
+#if ENC424J600_DEBUG & 8
+    diag_printf("TXABT event.\n");
+#endif
+
+    dpd->txbusy = false;
+    banked_register_operation(dpd, ENC424J600_BITFIELDCLEAR, ENC424J600_EIRL, 1, &iflag);
+}
+
+static void
+enc424j600_spi_RXevent(struct eth_drv_sc *sc)
+{
+    enc424j600_priv_data_t *dpd = (enc424j600_priv_data_t *)sc->driver_private;
+    cyg_uint8 pkcnt;    // Local copy of the packet counter
+    cyg_uint8 rsv[2];
+    cyg_uint16 packet_length;
+
+#if ENC424J600_DEBUG & 8
+    diag_printf("enc424j600_spi_RXevent()....\n");
+#endif
+
+    // Take info on single received packet
+    banked_register_operation(dpd, ENC424J600_READCR, ENC424J600_ESTATL, 1, &pkcnt);
+    if (0 != pkcnt)
+    {
+#if ENC424J600_DEBUG & 8
+        diag_printf("There are %u packets pending in receive buffer.\n", pkcnt);
+#endif
+        // Prepare on-chip read pointer
+        set_pointer(dpd, ENC424J600_RXRDPT, dpd->NextPacketPointer);
+        // The two bytes to read next point to the next packet
+        read_from_rx_buffer(dpd, 2, (cyg_uint8 *) & dpd->NextPacketPointer);
+
+        // Next 6 bytes to read are the Read Status Vector. We need only the first two.
+        read_from_rx_buffer(dpd, 2, & rsv[0]);
+        read_from_rx_buffer(dpd, 4, NULL);
+        packet_length = rsv[0] + rsv[1] * 256;
+        sc->funs->eth_drv->recv(sc, packet_length);
+    }
+
+    return;
+}
+
+// - End of local service functions -------------------------
+
+// - Higher level interface functions -----------------------
+
+#ifdef CYGINT_IO_ETH_INT_SUPPORT_REQUIRED
+// This ISR is called when the Ethernet interrupt occurs
+static cyg_uint32
+enc424j600_spi_isr(cyg_vector_t vector, cyg_addrword_t data, HAL_SavedRegisters *regs)
+{
+    cyg_drv_interrupt_mask(CYGNUM_DEVS_ETH_ENC424J600_INTERRUPT_VECTOR);
+    cyg_drv_interrupt_acknowledge(CYGNUM_DEVS_ETH_ENC424J600_INTERRUPT_VECTOR);
+
+    return (CYG_ISR_HANDLED|CYG_ISR_CALL_DSR);  // Run the DSR
+}
+
+static void
+enc424j600_spi_dsr(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data)
+{
+    enc424j600_priv_data_t *dpd = (enc424j600_priv_data_t *)data;
+    struct cyg_netdevtab_entry *ndp = (struct cyg_netdevtab_entry *)(dpd->tab);
+    struct eth_drv_sc *sc = (struct eth_drv_sc *)(ndp->device_instance);
+#if (ENC424J600_DEBUG & 2)
+    diag_printf("DSR: Interrupt! count %u\n", count);
+#endif
+
+#if (ENC424J600_DEBUG & 0x10)
+    extern void fake_eth_drv_dsr(cyg_vector_t vector,
+                            cyg_ucount32 count,
+                            cyg_addrword_t data);
+
+    fake_eth_drv_dsr( vector, count, (cyg_addrword_t)sc );
+#else
+    eth_drv_dsr( vector, count, (cyg_addrword_t)sc );
+#endif
+
+    return;
+}
+#endif // #ifdef CYGINT_IO_ETH_INT_SUPPORT_REQUIRED
+
+// Initialization of driver and chip
+
+#define ENC424J600_INIT_SPI_READY_RETRY 100
+#define ENC424J600_INIT_CLK_READY_RETRY 100
+#define ENC424J600_INIT_RETRY_PERIOD_US 100
+
+static bool
+enc424j600_spi_init(struct cyg_netdevtab_entry *tab)
+{
+    int retval;
+    cyg_uint8 aux_8[2];
+    cyg_bool esa_configured = false;
+#ifdef CYGSEM_DEVS_ETH_ENC424J600_SET_ESA
+    cyg_uint8 esa_from_cdl[ETHER_ADDR_LEN] = CYGDAT_DEVS_ETH_ENC424J600_ESA;
+#endif
+    unsigned int i;  // loop counter
+
+    struct eth_drv_sc *sc = (struct eth_drv_sc *)tab->device_instance;
+    enc424j600_priv_data_t *dpd = (enc424j600_priv_data_t *)sc->driver_private;
+
+    dpd->tab = tab;
+
+    CYG_DEVS_ETH_ENC424J600_PLF_INIT(tab);  // Platform HAL should define this macro
+
+#ifdef CYGINT_IO_ETH_INT_SUPPORT_REQUIRED
+    // Install interrupt handler.
+    cyg_drv_interrupt_create(CYGNUM_DEVS_ETH_ENC424J600_INTERRUPT_VECTOR,
+         CYGNUM_DEVS_ETH_ENC424J600_INTERRUPT_PRIORITY,
+         (cyg_addrword_t)dpd, //  Data item passed to interrupt handler
+         (cyg_ISR_t *)enc424j600_spi_isr,
+         (cyg_DSR_t *)enc424j600_spi_dsr,
+         &dpd->interrupt_handle,
+         &dpd->interrupt_object);
+    cyg_drv_interrupt_attach(dpd->interrupt_handle);
+    cyg_drv_interrupt_configure(CYGNUM_DEVS_ETH_ENC424J600_INTERRUPT_VECTOR,
+            ENC424J600_ETH_INTERRUPT_LEVEL_LOW, ENC424J600_ETH_INTERRUPT_EDGE_FALLING);
+    cyg_drv_interrupt_acknowledge(CYGNUM_DEVS_ETH_ENC424J600_INTERRUPT_VECTOR);
+    cyg_drv_interrupt_unmask(CYGNUM_DEVS_ETH_ENC424J600_INTERRUPT_VECTOR);
+#if ENC424J600_DEBUG & 4
+    diag_printf("%s(): Interrupt handler is installed.\n", __FUNCTION__);
+#endif
+#endif  //  #ifdef CYGINT_IO_ETH_INT_SUPPORT_REQUIRED
+
+    // Check if the Ethernet chip is connected and listening
+    for (i=0; i <= ENC424J600_INIT_SPI_READY_RETRY; i++)
+    {
+        aux_8[1] = (cyg_uint8)0x12;   // Test pattern
+        aux_8[0] = (cyg_uint8)0x34;
+        banked_register_operation(dpd, ENC424J600_WRITECR, ENC424J600_EUDASTL, 2, &aux_8[0]);
+        banked_register_operation(dpd, ENC424J600_READCR, ENC424J600_EUDASTL, 2, &aux_8[0]);
+        // Verify the test pattern
+        if ((0x12 == aux_8[1]) && (0x34 == aux_8[0]))
+        {   // verified
+            break;
+        }
+        CYGACC_CALL_IF_DELAY_US(ENC424J600_INIT_RETRY_PERIOD_US);
+    }
+
+    if (i > ENC424J600_INIT_SPI_READY_RETRY)
+    {
+        CYG_FAIL("enc424j600 SPI is not ready!\n");
+        return false;
+    }
+
+#if ENC424J600_DEBUG & 4
+        diag_printf("enc424j600 SPI is there.\n");
+#endif
+
+    // Check if ENC424J600_CLKRDY flag is set
+    for (i=0; i <= ENC424J600_INIT_CLK_READY_RETRY; i++)
+    {
+        banked_register_operation(dpd, ENC424J600_READCR, ENC424J600_ESTATL, 2, &aux_8[0]);
+        if (0 == (aux_8[1] & ENC424J600_CLKRDY))
+        {
+            i++;
+        }
+        else
+        {   // clock is ready
+            break;
+        }
+        CYGACC_CALL_IF_DELAY_US(ENC424J600_INIT_RETRY_PERIOD_US);
+    }
+    if (i > ENC424J600_INIT_CLK_READY_RETRY)
+    {
+        CYG_FAIL("enc424j600 clock is not ready!\n");
+        return false;
+    }
+
+#if ENC424J600_DEBUG & 4
+        diag_printf("enc424j600 clock is ready.\n");
+#endif
+
+    // Issue a System Reset for Ethernet chip
+    aux_8[0] = ENC424J600_ETHRST;
+    unbanked_register_operation(dpd, ENC424J600_BITFIELDSETU, ENC424J600_ECON2_U, 1, &aux_8[0]);
+    CYGACC_CALL_IF_DELAY_US(25);
+    // Check if the reset really happened
+    banked_register_operation(dpd, ENC424J600_READCR, ENC424J600_EUDASTL, 2, &aux_8[0]);
+    if ((0 != aux_8[0]) || (0 != aux_8[1]))
+    {
+        CYG_FAIL("enc424j600 is not reset!\n");
+        return false;
+    }
+#if ENC424J600_DEBUG & 4
+    diag_printf("Successful reset of the Ethernet chip.\n");
+#endif
+
+    CYGACC_CALL_IF_DELAY_US(256);
+
+#define CLOCKOUT_CODE(_freq_) CLOCKOUT_LABEL(_freq_)
+#define CLOCKOUT_LABEL(_freq_) (ENC424J600_CLKO_##_freq_)
+
+    // Set clock output frequency. External hardware may need it.
+    unbanked_register_operation(dpd, ENC424J600_READCRU, ENC424J600_ECON2_U + 1, 1, &aux_8[1]);
+    aux_8[1] &= 0xf0;
+    aux_8[1] |= (cyg_uint8)CLOCKOUT_CODE(CYGNUM_DEVS_ETH_ENC424J600_CLOCKOUT_FREQUENCY);
+#if ENC424J600_DEBUG & 4
+    diag_printf("Setting clock out, ECON2H 0x%02x\n", aux_8[1]);
+#endif
+    unbanked_register_operation(dpd, ENC424J600_WRITECRU, ENC424J600_ECON2_U + 1, 1, &aux_8[1]);
+
+
+    // Find ESA - check possible sources in sequence and stop when
+    // one provides the ESA:
+    //   RedBoot option (via provide_esa)
+    //   Set by application
+    //   Set by configuration option
+    //   Ethernet chip (manufacture-time set)
+
+    if (NULL != dpd->provide_esa)
+    {
+        esa_configured = dpd->provide_esa(dpd);
+# if ENC424J600_DEBUG & 4
+        if (esa_configured)
+            diag_printf("Got ESA from RedBoot option\n");
+# endif
+    }
+    if (!esa_configured && dpd->hardwired_esa)
+    {
+        // ESA is already set in dpd->esa[]
+#if ENC424J600_DEBUG & 4
+        diag_printf("Got hardcoded ESA\n");
+#endif
+        esa_configured = true;
+    }
+#ifdef CYGSEM_DEVS_ETH_ENC424J600_SET_ESA
+    else
+    {
+        memcpy(dpd->esa, esa_from_cdl, ETHER_ADDR_LEN);
+        esa_configured = true;
+# if ENC424J600_DEBUG & 4
+        diag_printf("Got ESA from CDL.\n");
+# endif
+    }
+#endif  //  #ifdef CYGSEM_DEVS_ETH_ENC424J600_SET_ESA
+
+    if (!esa_configured)
+    {
+# if ENC424J600_DEBUG & 4
+        diag_printf("ESA is not provided. Getting it from the chip.\n");
+# endif
+        retval = read_esa_u(dpd, &(dpd->esa[0]));
+        if (0 != retval)
+        {
+            CYG_FAIL("Reading ESA from chip failed.\n");
+            return false;
+        }
+    }
+    else
+    {
+# if ENC424J600_DEBUG & 4
+        diag_printf("Setting ESA into chip. Will last till next reset.\n");
+# endif
+        retval = write_esa_u(dpd, &(dpd->esa[0]));
+        if (0 != retval)
+        {
+            CYG_FAIL("Writing ESA into chip failed.\n");
+            return false;
+        }
+    }
+
+# if ENC424J600_DEBUG & 4
+    cyg_uint8 cesa[ETHER_ADDR_LEN] = {0,0,0,0,0,0};
+    diag_printf("ESA %02x:%02x:%02x:%02x:%02x:%02x\n",
+                dpd->esa[0], dpd->esa[1], dpd->esa[2],
+                dpd->esa[3], dpd->esa[4], dpd->esa[5]);
+    retval = read_esa_u(dpd, &cesa[0]);
+    if (0 != retval)
+    {
+        diag_printf("Reading ESA from chip failed.\n");
+    }
+    diag_printf("Control reading from chip: ");
+    diag_printf("%02x:%02x:%02x:%02x:%02x:%02x\n",
+        cesa[0], cesa[1], cesa[2],
+        cesa[3], cesa[4], cesa[5]);
+# endif
+
+    // Set receive filters
+    aux_8[0] = ENC424J600_BCEN | ENC424J600_UCEN | ENC424J600_RUNTEN | ENC424J600_CRCEN;
+    unbanked_register_operation(dpd, ENC424J600_WRITECRU, ENC424J600_ERXFCON_U, 1, &aux_8[0]);
+
+#ifdef CYGSEM_DEVS_ETH_ENC424J600_FLOWC_OnChip
+#if ENC424J600_DEBUG & 4
+    diag_printf("eth_spi_enc424j600_init() Setting auto flow control\n");
+#endif
+    // Duration of pause
+    aux_8[0] = CYGNUM_DEVS_ETH_ENC424J600_FLOWC_PAUSE & 0xff;
+    aux_8[1] = (CYGNUM_DEVS_ETH_ENC424J600_FLOWC_PAUSE >> 8 ) & 0xff;
+    unbanked_register_operation(dpd, ENC424J600_WRITECRU, ENC424J600_EPAUS_U, 2, &aux_8[0]);
+
+    // Thresholds for flow control
+    aux_8[0] = CYGNUM_DEVS_ETH_ENC424J600_FLOWC_LOWER_WATERMARK;
+    aux_8[1] = CYGNUM_DEVS_ETH_ENC424J600_FLOWC_UPPER_WATERMARK;
+    unbanked_register_operation(dpd, ENC424J600_WRITECRU, ENC424J600_ERXWM_U, 2, &aux_8[0]);
+
+    aux_8[0] = ENC424J600_AUTOFC;  // Enable automatic flow control
+    unbanked_register_operation(dpd, ENC424J600_BITFIELDSETU, ENC424J600_ECON2_U, 1, &aux_8[0]);
+
+#else
+    // No flow control
+    simple_operation(dpd, ENC424J600_FCDISABLE);
+#endif
+
+    // Set PHY speed and duplex
+    aux_8[0] = aux_8[1] = 0;
+#ifndef CYGNUM_DEVS_ETH_ENC424J600_NO_AUTO_NEGOTIATION
+    aux_8[1] = ENC424J600_ANEN;  // Enable auto negotiation
+#else
+#   if(CYGNUM_DEVS_ETH_ENC424J600_SPEED == 100)
+        aux_8[1] |= ENC424J600_SPD100;
+#   endif
+#   ifdef CYGSEM_DEVS_ETH_ENC424J600_FULL_DUPLEX
+        aux_8[1] |= ENC424J600_PFULDPX;
+#   endif
+#endif
+#if ENC424J600_DEBUG & 4
+    diag_printf("Writing PHCON1 0x%02x%02x\n", aux_8[1], aux_8[0]);
+#endif
+    write_phy(dpd, ENC424J600_PHCON1, (aux_8[1] << 8) + aux_8[0]);
+    CYGACC_CALL_IF_DELAY_US(26);
+
+    // Compose and set PHY capabilities advertisement register
+    aux_8[1] = 0;
+    aux_8[0] = ENC424J600_IEEE802_3STD;
+#ifdef CYGNUM_DEVS_ETH_ENC424J600_FLOWC_ENC424J600_ONCHIP_AUTO_FC
+    aux_8[1] |= ENC424J600_ADPAUS_SYMM;
+#endif
+
+#ifdef CYGNUM_DEVS_ETH_ENC424J600_NO_AUTO_NEGOTIATION
+#   ifdef CYGSEM_DEVS_ETH_ENC424J600_FULL_DUPLEX
+#      if(CYGNUM_DEVS_ETH_ENC424J600_SPEED == 100)
+           aux_8[1] |= ENC424J600_AD100FD;
+#      else
+           aux_8[0] |= ENC424J600_AD10FD;
+#      endif
+#   else
+#      if(CYGNUM_DEVS_ETH_ENC424J600_SPEED == 100)
+           aux_8[0] |= ENC424J600_AD100;
+#      else
+           aux_8[0] |= ENC424J600_AD10;
+#      endif
+#   endif
+#else
+    aux_8[1] |= ENC424J600_AD100FD;
+    aux_8[0] |= ENC424J600_AD100 | ENC424J600_AD10FD | ENC424J600_AD10;
+#endif
+
+    write_phy(dpd, ENC424J600_PHANA, (aux_8[1] << 8) + aux_8[0]);
+
+#if ENC424J600_DEBUG & 4
+    diag_printf("Setting CRC generation\n");
+#endif
+
+    // Set ENC424J600_TXCRCEN, PADCFG
+    unbanked_register_operation(dpd, ENC424J600_READCRU, ENC424J600_MACON2_U, 2, &aux_8[0]);
+    aux_8[0] = 0xa0;      // Pad VLAN frames to 64bytes, others to 60
+    aux_8[0] |= ENC424J600_TXCRCEN;  // Calculate and append CRC in transmit frames
+    unbanked_register_operation(dpd, ENC424J600_WRITECRU, ENC424J600_MACON2_U, 2, &aux_8[0]);
+
+#if ENC424J600_DEBUG & 4
+    diag_printf("Setting acceptable packet size\n");
+#endif
+    // Set acceptable packet size
+    aux_8[0] = CYGNUM_DEVS_ETH_ENC424J600_ACCEPTABLE_PACKET_SIZE & 0xff;
+    aux_8[1] = (CYGNUM_DEVS_ETH_ENC424J600_ACCEPTABLE_PACKET_SIZE >> 8) & 0xff;
+    unbanked_register_operation(dpd, ENC424J600_WRITECRU, ENC424J600_MAMXFL_U, 2, &aux_8[0]);
+
+#if ENC424J600_DEBUG & 2
+    diag_printf("Initializing upper level driver\n");
+#endif
+    (sc->funs->eth_drv->init)(sc, dpd->esa);
+
+#if ENC424J600_DEBUG & 4
+    diag_printf("End of _init().\n");
+#endif
+
+    return true;
+}
+
+//
+// This function is called to "start up" the interface.  It may be called
+// multiple times, even when the hardware is already running.  It will be
+// called whenever something "hardware oriented" changes and should leave
+// the hardware ready to send/receive packets.
+//
+static void
+enc424j600_spi_start(struct eth_drv_sc *sc, unsigned char *enaddr, int flags)
+{
+    enc424j600_priv_data_t *dpd = (enc424j600_priv_data_t *)sc->driver_private;
+    cyg_uint8 aux[2];
+    cyg_uint8 pkcnt;
+
+#if ENC424J600_DEBUG & 8
+    diag_printf("enc424j600_spi_start() begin.\n");
+#endif
+    // Disable packet reception
+    simple_operation(dpd, ENC424J600_DISABLERX);
+
+    // Enable interrupts in Ethernet chip
+    simple_operation(dpd, ENC424J600_CLREIE); // First disable interrupts globally
+
+    aux[0] = ENC424J600_PKTIE | ENC424J600_TXIE | ENC424J600_TXABTIE | ENC424J600_RXABTIE | ENC424J600_PCFULIE; // then set the desired ones
+    aux[1] = ENC424J600_LINKIE;
+    unbanked_register_operation(dpd, ENC424J600_BITFIELDSETU, ENC424J600_EIE_U, 2, &aux[0]);
+
+    // Are there any packets left in receive buffer?
+    banked_register_operation(dpd, ENC424J600_READCR, ENC424J600_ESTATL, 1, &pkcnt);
+
+    while (0 < pkcnt--)
+    {
+        simple_operation(dpd, ENC424J600_SETPKTDEC);   // Decrement on-chip packet counter
+    }                                       // This clears ENC424J600_PKTIF, if set.
+
+    // Set the chip's receive buffer start address and buffer head.
+    aux[0] = ENC424J600_RXBUF_START & 0xfe;          // make it even, just in case it's not
+    aux[1] = (ENC424J600_RXBUF_START >> 8) & 0x7f;   // clear the MSB
+#if ENC424J600_DEBUG & 8
+    diag_printf("Setting receive buffer start address, ERXST 0x%02x%02x.\n",
+                aux[1], aux[0]);
+#endif
+    unbanked_register_operation(dpd, ENC424J600_WRITECRU, ENC424J600_ERXST_U, 2, &aux[0]);
+    unbanked_register_operation(dpd, ENC424J600_WRITECRU, ENC424J600_ERXHEAD_U, 2, &aux[0]);
+
+    // Next packet will be received at the buffer start address
+    *(cyg_uint8 *) & dpd->NextPacketPointer = ENC424J600_RXBUF_START & 0xff;
+    *(((cyg_uint8 *)&dpd->NextPacketPointer) + 1) = (ENC424J600_RXBUF_START >> 8 ) & 0xff;
+
+    // Set receive buffer tail
+    aux[1] = 0x5f;  // just bellow the end of on-chip SRAM
+    aux[0] = 0xfe;
+#if ENC424J600_DEBUG & 8
+    diag_printf("Setting receive buffer tail, ERXTAIL 0x%02x%02x.\n",
+                aux[1], aux[0]);
+#endif
+    unbanked_register_operation(dpd, ENC424J600_WRITECRU, ENC424J600_ERXTAIL_U, 2, &aux[0]);
+
+    // Abort any pending transmission
+    aux[0] = ENC424J600_TXRTS;
+    banked_register_operation(dpd, ENC424J600_BITFIELDCLEAR, ENC424J600_ECON1L, 1, &aux[0]);
+    dpd->txbusy = false;
+
+    // Set start of transmit buffer
+    aux[0] = ENC424J600_TXBUF_START & 0xff;
+    aux[1] = (ENC424J600_TXBUF_START >> 8 ) & 0xff;
+#if ENC424J600_DEBUG & 8
+    diag_printf("Writing ETXST 0x%02x%02x.\n", aux[1], aux[0]);
+#endif
+    unbanked_register_operation(dpd, ENC424J600_WRITECRU, ENC424J600_ETXST_U, 2, &aux[0]);
+
+    // Clear any remaining interrupt flags
+    aux[0] = ENC424J600_TXIF | ENC424J600_TXABTIF | ENC424J600_RXABTIF | ENC424J600_PCFULIF;
+    aux[1] = ENC424J600_LINKIF;
+    banked_register_operation(dpd, ENC424J600_BITFIELDCLEAR, ENC424J600_EIRL, 2, &aux[0]);
+
+#ifdef CYGINT_IO_ETH_INT_SUPPORT_REQUIRED
+    simple_operation(dpd, ENC424J600_SETEIE);  // Enable interrupts
+#endif
+
+    // Enable packet reception
+    simple_operation(dpd, ENC424J600_ENABLERX);
+
+    banked_register_operation(dpd, ENC424J600_READCR, ENC424J600_ESTATL, 2, &aux[0]);
+    if (0 != (aux[1] & ENC424J600_PHYLNK))
+    {
+        if (ENC424J600_LINK_ON != dpd->link_status)
+        {
+            dpd->link_status = ENC424J600_LINK_ON;
+            set_MAC(dpd, aux[1]);
+        }
+    }
+    else
+    {
+        dpd->link_status = ENC424J600_LINK_OFF;
+    }
+
+#if ENC424J600_DEBUG & 8
+    diag_printf("enc424j600_spi_start() end.\n");
+#endif
+
+    return;
+}
+
+// Stop receiving and sending packets
+static void
+enc424j600_spi_stop(struct eth_drv_sc *sc)
+{
+    enc424j600_priv_data_t *dpd = (enc424j600_priv_data_t *)sc->driver_private;
+    cyg_uint8 aux[2];
+
+#if ENC424J600_DEBUG & 8
+    diag_printf("enc424j600_spi_stop() begin.\n");
+#endif
+    // Disable packet reception
+    simple_operation(dpd, ENC424J600_DISABLERX);
+
+    // Disable interrupts in Ethernet chip
+    aux[1] = ENC424J600_INTIE;
+    aux[0] = ENC424J600_PKTIE | ENC424J600_TXIE | ENC424J600_TXABTIE | ENC424J600_RXABTIE | ENC424J600_PCFULIE;
+    unbanked_register_operation(dpd, ENC424J600_BITFIELDCLEARU, ENC424J600_EIE_U, 2, &aux[0]);
+
+    return;
+}
+
+static void
+enc424j600_spi_deliver(struct eth_drv_sc *sc)
+{
+
+    enc424j600_spi_poll(sc);
+
+    return;
+}
+
+// Special control operations
+static int
+enc424j600_spi_control(struct eth_drv_sc *sc, unsigned long key, void *data,
+        int data_length)
+{
+    enc424j600_priv_data_t *dpd;
+    unsigned char *esa;
+    struct eth_drv_mc_list *mc_list;
+    cyg_uint8 aux;
+
+    if ((NULL == sc) || (NULL == data))
+    {
+#if ENC424J600_DEBUG & 1
+        diag_printf("Wrong parameter(s) for enc424j600_spi_control().\n");
+#endif
+        return -1;
+    }
+    dpd = (enc424j600_priv_data_t *)sc->driver_private;
+    switch (key)
+    {
+        case ETH_DRV_SET_MAC_ADDRESS:
+            if (ETHER_ADDR_LEN != data_length)
+            {
+#if ENC424J600_DEBUG & 1
+                diag_printf("Wrong data length for ETH_DRV_SET_MAC_ADDRESS.\n");
+#endif
+                return -1;
+            }
+            esa = (unsigned char *)data;
+            // Write ESA in the chip. Will last till the next reset.
+            return write_esa_u(dpd, esa);
+
+#ifdef ETH_DRV_GET_MAC_ADDRESS
+        case ETH_DRV_GET_MAC_ADDRESS:
+            if (ETHER_ADDR_LEN > data_length)
+            {
+#if ENC424J600_DEBUG & 1
+                diag_printf("Too small data length for ETH_DRV_GET_MAC_ADDRESS.\n");
+#endif
+                return -1;
+            }
+            esa = (unsigned char *)data;
+            // Get ESA from the chip
+            return read_esa_u(dpd, esa);
+#endif
+
+        case ETH_DRV_SET_MC_LIST:
+        case ETH_DRV_SET_MC_ALL:
+            // Note: this code always affects all multicast addresses if any
+            // are desired.
+            mc_list = data;
+            simple_operation(dpd, ENC424J600_DISABLERX);
+            aux = ENC424J600_MCEN;
+            if (0 == mc_list->len)
+            {   // Disable reception of multicast packets
+                unbanked_register_operation(dpd,
+                    ENC424J600_BITFIELDCLEARU, ENC424J600_ERXFCON_U, 1, &aux);
+            }
+            else
+            {   // Enable reception of multicast packets
+                unbanked_register_operation(dpd,
+                    ENC424J600_BITFIELDSETU, ENC424J600_ERXFCON_U, 1, &aux);
+            }
+            simple_operation(dpd, ENC424J600_ENABLERX);
+
+            return 0;
+
+        default:
+#if ENC424J600_DEBUG & 1
+            diag_printf("Unsupported key %lx for enc424j600_spi_control().\n", key);
+#endif
+            return -1;
+    }
+}
+
+// Continue transfer from chip's buffer where the enc424j600_spi_RXevent() stopped.
+// Take one packet.
+static void
+enc424j600_spi_recv(struct eth_drv_sc *sc,
+    struct eth_drv_sg *sg_list,
+    int chunks)
+{
+    int chunk;
+    enc424j600_priv_data_t *dpd = (enc424j600_priv_data_t *)sc->driver_private;
+    cyg_uint16 rbuf_tail;
+    cyg_uint8 * aux_p;
+    cyg_uint8 aux[2];
+
+#if ENC424J600_DEBUG & 8
+    diag_printf("enc424j600_spi_recv()...\n");
+#endif
+
+    for(chunk = 0; chunk < chunks; chunk++)
+    {
+        read_from_rx_buffer(dpd, (*sg_list).len, (cyg_uint8 *)(*sg_list).buf);
+        sg_list++;
+    }
+    aux_p = (cyg_uint8 *) & dpd->NextPacketPointer;
+    rbuf_tail = *aux_p + *(aux_p+1) * (cyg_uint16)256 ;
+    rbuf_tail -= 2;
+    if (rbuf_tail == ENC424J600_RXBUF_START)
+    {   // Wrap over
+        rbuf_tail = 0x5ffe;
+    }
+    aux[0] = rbuf_tail & 0xff;
+    aux[1] = (rbuf_tail >> 8) & 0xff;
+#if ENC424J600_DEBUG & 8
+    diag_printf("Setting receive buffer tail, ERXTAIL 0x%02x%02x.\n",
+        aux[1], aux[0]);
+#endif
+    unbanked_register_operation(dpd, ENC424J600_WRITECRU, ENC424J600_ERXTAIL_U, 2, &aux[0]);
+
+    simple_operation(dpd, ENC424J600_SETPKTDEC);   // Decrement packet count. If zeroed,
+                                        // ENC424J600_PKTIF interrupt flag will be reset.
+
+    return;
+}
+
+// This routine is called to see if it is possible to send another packet.
+// It will return non-zero if a transmit is possible, zero otherwise.
+static int
+enc424j600_spi_can_send(struct eth_drv_sc *sc)
+{
+    if (((enc424j600_priv_data_t *)sc->driver_private)->txbusy)
+    {
+        return 0;
+    }
+    else
+    {
+        return 1;
+    }
+}
+
+// This routine is called to send data to the hardware.
+static void
+enc424j600_spi_send(struct eth_drv_sc *sc,
+    struct eth_drv_sg *sg_list,
+    int sg_len,
+    int total,
+    unsigned long key)
+{
+    enc424j600_priv_data_t *dpd = (enc424j600_priv_data_t *)sc->driver_private;
+    int block;
+    cyg_uint8 aux[2];
+    cyg_uint8 opcode = ENC424J600_WGPDATA;
+
+    if (0 >= sg_len) return;
+
+    // Check if there is enough room in transmit buffer
+    if (total > ENC424J600_RXBUF_START - ENC424J600_TXBUF_START)
+    {
+      sc->funs->eth_drv->tx_done(sc, (CYG_ADDRESS)key, 0);
+#if ENC424J600_DEBUG & 1
+      diag_printf("enc424j600_spi_send(): Packet to send is too large (%d bytes).\n",
+            total);
+#endif
+        return;
+    }
+
+    dpd->txbusy = true;
+    dpd->txkey = key;
+
+    aux[0] = ENC424J600_TXBUF_START & 0xff;
+    aux[1] = (((cyg_uint8)ENC424J600_TXBUF_START) >> 8) & 0xff;
+    set_pointer(dpd, ENC424J600_GPBWRPT, (aux[1] << 8) + aux[0]);
+
+#if ENC424J600_DEBUG & 8
+    diag_printf("Starting SPI transaction to send a packet.\n");
+#endif
+    cyg_spi_transaction_begin(dpd->spi_service_device);
+    cyg_spi_transaction_transfer(dpd->spi_service_device,
+        SPI_POLLING,
+        1,
+        & opcode,
+        NULL,
+        ENC424J600_DONT_DROP_CS);
+
+    for (block = 0; block < sg_len; block++)
+    {
+        cyg_spi_transaction_transfer(dpd->spi_service_device,
+            SPI_POLLING,
+            sg_list->len,
+            (cyg_uint8 *)sg_list->buf,
+            NULL,
+            (block == sg_len) ? ENC424J600_DO_DROP_CS : ENC424J600_DONT_DROP_CS );
+        sg_list++;
+    }
+    cyg_spi_transaction_end(dpd->spi_service_device);
+
+    aux[0] = total & 0xff;
+    aux[1] = (total >> 8 ) & 0xff;
+#if ENC424J600_DEBUG & 8
+    diag_printf("Writing ETXLEN 0x%02x%02x.\n", aux[1], aux[0]);
+#endif
+    unbanked_register_operation(dpd, ENC424J600_WRITECRU, ENC424J600_ETXLEN_U, 2, &aux[0]);
+
+#if ENC424J600_DEBUG & 8
+    diag_printf("Setting request to send.\n");
+#endif
+    simple_operation(dpd, ENC424J600_SETTXRTS);
+
+    sc->funs->eth_drv->tx_done(sc, (CYG_ADDRESS)key, 0);
+
+    return;
+}
+
+static void
+enc424j600_spi_poll(struct eth_drv_sc *sc)
+{
+    enc424j600_priv_data_t *dpd = (enc424j600_priv_data_t *)sc->driver_private;
+    cyg_uint8   aux[2];
+    cyg_uint16  iflags;
+
+#if ENC424J600_DEBUG & 8
+    diag_printf("enc424j600_spi_poll(%x)...\n", (cyg_uint32)sc);
+#endif
+
+#ifdef CYGINT_IO_ETH_INT_SUPPORT_REQUIRED
+    // Globally disable interrupt source in Ethernet chip
+    simple_operation(dpd, ENC424J600_CLREIE);
+#endif
+    do
+    {
+        // Figure out what caused the interrupt
+        banked_register_operation(dpd, ENC424J600_READCR, ENC424J600_EIRL, 2, &aux[0]);
+        aux[1] &= ENC424J600_LINKIF;
+        aux[0] &= (ENC424J600_PKTIF | ENC424J600_TXIF | ENC424J600_TXABTIF | ENC424J600_RXABTIF | ENC424J600_PCFULIF);
+        iflags = aux[0] + (cyg_uint16)256 * aux[1];
+        if (0 != (aux[0] & ENC424J600_PKTIF))
+        {   // Packets are pending in chip's receive buffer
+            enc424j600_spi_RXevent(sc);
+        }
+        if ( 0 != (aux[1] & ENC424J600_LINKIF))
+        {   // Link status changed
+            enc424j600_spi_LINKevent(sc);
+        }
+        if (0 != (aux[0] & ENC424J600_TXIF))
+        {   // Packet has been sent
+            enc424j600_spi_TXevent(sc);
+        }
+        if (0 != (aux[0] & ENC424J600_TXABTIF))
+        {   // Packet send has been aborted
+            enc424j600_spi_TXABTevent(sc);
+        }
+        if ( 0 != (aux[0] & ENC424J600_PCFULIF))
+        {   // Packet counter overflow
+            enc424j600_spi_PCFULevent(sc);
+        }
+        if ( 0 != (aux[0] & ENC424J600_RXABTIF))
+        {   // Incoming packet rejected due to buffer or counter overflow
+            enc424j600_spi_RXABTevent(sc);
+        }
+    } while(0 != iflags);
+
+#ifdef CYGINT_IO_ETH_INT_SUPPORT_REQUIRED
+    cyg_drv_interrupt_unmask(CYGNUM_DEVS_ETH_ENC424J600_INTERRUPT_VECTOR);
+
+    // Globally enable interrupt source in Ethernet chip
+    simple_operation(dpd, ENC424J600_SETEIE);
+#endif
+
+    return;
+}
+
+static int
+enc424j600_spi_int_vector(struct eth_drv_sc *sc)
+{
+#ifdef CYGINT_IO_ETH_INT_SUPPORT_REQUIRED
+    return CYGNUM_DEVS_ETH_ENC424J600_INTERRUPT_VECTOR;
+#else
+    return 0;
+#endif
+}
+
+// - End of higher level interface -----------------------------
+
+// End of enc424j600_spi.c
new file mode 100644
--- /dev/null
+++ b/packages/devs/eth/microchip/enc424j600/current/src/enc424j600_spi.h
@@ -0,0 +1,344 @@
+#ifndef CYGONCE_DEVS_ETH_ENC424J600_SPI_H_
+#define CYGONCE_DEVS_ETH_ENC424J600_SPI_H_
+//==========================================================================
+//
+//      enc424j600_spi.h
+//
+//      Microchip enc424j600 Ethernet chip
+//
+//==========================================================================
+// ####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 2010 Free Software Foundation, Inc.
+//
+// eCos is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 2 or (at your option) any later
+// version.
+//
+// eCos is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+// for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with eCos; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+//
+// As a special exception, if other files instantiate templates or use
+// macros or inline functions from this file, or you compile this file
+// and link it with other works to produce a work based on this file,
+// this file does not by itself cause the resulting work to be covered by
+// the GNU General Public License. However the source code for this file
+// must still be made available in accordance with section (3) of the GNU
+// General Public License v2.
+//
+// This exception does not invalidate any other reasons why a work based
+// on this file might be covered by the GNU General Public License.
+// -------------------------------------------
+// ####ECOSGPLCOPYRIGHTEND####
+//==========================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s):    Ilija Stanislevik
+// Contributors:
+// Date:         2010-11-23
+// Purpose:
+// Description:
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+// Addresses of enc424j600 registers, banked access
+// Banks 0, 1, 2 & 3
+#define ENC424J600_EUDASTL      (0X16)
+#define ENC424J600_EUDASTH      (0X17)
+#define ENC424J600_EUDANDL      (0X18)
+#define ENC424J600_EUDANDH      (0X19)
+#define ENC424J600_ESTATL       (0x1a)
+#define ENC424J600_ESTATH       (0x1b)
+#define ENC424J600_EIRL         (0x1c)
+#define ENC424J600_EIRH         (0x1d)
+#define ENC424J600_ECON1L       (0x1e)
+#define ENC424J600_ECON1H       (0x1f)
+
+// Only bank 0
+#define ENC424J600_ETXSTL       (0x00)
+#define ENC424J600_ETXSTH       (0x01)
+#define ENC424J600_ETXLENL      (0x02)
+#define ENC424J600_ETXLENH      (0x03)
+#define ENC424J600_ERXSTL       (0x04)
+#define ENC424J600_ERXSTH       (0x05)
+#define ENC424J600_ERXTAILL     (0x06)
+#define ENC424J600_ERXTAILH     (0x07)
+#define ENC424J600_ERXHEADL     (0x08)
+#define ENC424J600_ERXHEADH     (0x09)
+
+// Only bank 1
+#define ENC424J600_ERXFCONL     (0x14)
+#define ENC424J600_ERXFCONH     (0x15)
+
+// Only bank 2
+#define ENC424J600_MACON1L      (0x00)
+#define ENC424J600_MACON1H      (0x01)
+#define ENC424J600_MACON2L      (0x02)
+#define ENC424J600_MACON2H      (0x03)
+#define ENC424J600_MABBIPGL     (0x04)
+#define ENC424J600_MABBIPGH     (0x05)
+#define ENC424J600_MAMXFLL      (0x0a)
+#define ENC424J600_MAMXFLH      (0x0b)
+#define ENC424J600_MICMDL       (0x12)
+#define ENC424J600_MICMDH       (0x13)
+#define ENC424J600_MIREGADRL    (0x14)
+#define ENC424J600_MIREGADRH    (0x15)
+#define ENC424J600_EIRL         (0x1c)
+#define ENC424J600_EIRH         (0x1d)
+#define ENC424J600_ECON1L       (0x1e)
+#define ENC424J600_ECON1H       (0x1f)
+
+// Only bank 3
+#define ENC424J600_MAADR3L      (0x00)
+#define ENC424J600_MIWRL        (0x06)
+#define ENC424J600_MIWRH        (0x07)
+#define ENC424J600_MIRDL        (0x08)
+#define ENC424J600_MIRDH        (0x09)
+#define ENC424J600_MISTATL      (0x0a)
+#define ENC424J600_MISTATH      (0x0b)
+#define ENC424J600_EPAUSL       (0x0c)
+#define ENC424J600_EPAUSH       (0x0d)
+#define ENC424J600_ECON2L       (0x0e)
+#define ENC424J600_ECON2H       (0x0f)
+#define ENC424J600_ERXWML       (0x10)
+#define ENC424J600_ERXWMH       (0x11)
+#define ENC424J600_EIEL         (0x12)
+#define ENC424J600_EIEH         (0x13)
+
+// Addresses of enc424j600 registers, unbanked access
+// Bank 0
+#define ENC424J600_BANK0_Of     (0)
+#define ENC424J600_ETXST_U      (ENC424J600_ETXSTL       + ENC424J600_BANK0_Of)
+#define ENC424J600_ETXLEN_U     (ENC424J600_ETXLENL      + ENC424J600_BANK0_Of)
+#define ENC424J600_EUDAST_U     (ENC424J600_EUDASTL      + ENC424J600_BANK0_Of)
+#define ENC424J600_EUDAND_U     (ENC424J600_EUDANDL      + ENC424J600_BANK0_Of)
+#define ENC424J600_ESTAT_U      (ENC424J600_ESTATL       + ENC424J600_BANK0_Of)
+#define ENC424J600_ERXST_U      (ENC424J600_ERXSTL       + ENC424J600_BANK0_Of)
+#define ENC424J600_ERXTAIL_U    (ENC424J600_ERXTAILL     + ENC424J600_BANK0_Of)
+#define ENC424J600_ERXHEAD_U    (ENC424J600_ERXHEADL     + ENC424J600_BANK0_Of)
+
+// Bank 1
+#define ENC424J600_BANK1_Of     (0x20)
+#define ENC424J600_ERXFCON_U   ( ENC424J600_ERXFCONL     + ENC424J600_BANK1_Of)
+
+// Bank 2
+#define ENC424J600_BANK2_Of     (0x40)
+#define ENC424J600_MACON1_U     (ENC424J600_MACON1L      + ENC424J600_BANK2_Of)
+#define ENC424J600_MACON2_U     (ENC424J600_MACON2L      + ENC424J600_BANK2_Of)
+#define ENC424J600_MABBIPG_U    (ENC424J600_MABBIPGL     + ENC424J600_BANK2_Of)
+#define ENC424J600_MAMXFL_U     (ENC424J600_MAMXFLL      + ENC424J600_BANK2_Of)
+#define ENC424J600_MICMD_U      (ENC424J600_MICMDL       + ENC424J600_BANK2_Of)
+#define ENC424J600_MIREGADR_U   (ENC424J600_MIREGADRL    + ENC424J600_BANK2_Of)
+#define ENC424J600_EIR_U        (ENC424J600_EIRL         + ENC424J600_BANK2_Of)
+#define ENC424J600_ECON1_U      (ENC424J600_ECON1L       + ENC424J600_BANK2_Of)
+
+// Bank 3
+#define ENC424J600_BANK3_Of     (0x60)
+#define ENC424J600_MAADR3_U     (ENC424J600_MAADR3L      + ENC424J600_BANK3_Of)
+#define ENC424J600_MIWR_U       (ENC424J600_MIWRL        + ENC424J600_BANK3_Of)
+#define ENC424J600_MIRD_U       (ENC424J600_MIRDL        + ENC424J600_BANK3_Of)
+#define ENC424J600_MISTAT_U     (ENC424J600_MISTATL      + ENC424J600_BANK3_Of)
+#define ENC424J600_EPAUS_U      (ENC424J600_EPAUSL       + ENC424J600_BANK3_Of)
+#define ENC424J600_ECON2_U      (ENC424J600_ECON2L       + ENC424J600_BANK3_Of)
+#define ENC424J600_ERXWM_U      (ENC424J600_ERXWML       + ENC424J600_BANK3_Of)
+#define ENC424J600_EIE_U        (ENC424J600_EIEL         + ENC424J600_BANK3_Of)
+
+// Addresses of enc424j600 PHY registers, special access
+
+enum enc424j600_pr_address_e
+{
+    ENC424J600_PHCON1  = 0,
+    ENC424J600_PHSTAT1 = 1,
+    ENC424J600_PHANA   = 4,
+    ENC424J600_PHANLPA = 5,
+    ENC424J600_PHANE   = 6,
+    ENC424J600_PHCON2  = 0x11,
+    ENC424J600_PHSTST2 = 0x1b,
+    ENC424J600_PHSTAT3 = 0x1f
+};
+
+//---------- end of register addresses --------------------------------------------------
+
+//---------- definitions of bits in control registers -----------------------------------
+
+// Interrupt flags (EIR register) higher byte
+#define ENC424J600_MODEXIF (0x40)
+#define ENC424J600_HASHIF  (0x20)
+#define ENC424J600_AESIF   (0x10)
+#define ENC424J600_LINKIF  (0x08)    // PHY status has changed
+
+// Interrupt flags (EIR register) lower byte
+#define ENC424J600_PKTIF   (0x40)    // RX packet(s) pending
+#define ENC424J600_DMAIF   (0x20)
+#define ENC424J600_TXIF    (0x08)    // Transmit done
+#define ENC424J600_TXABTIF (0x04)    // Packet transmission aborted due to an error
+#define ENC424J600_RXABTIF (0x02)    // RX packet rejected due to lack of space / to many
+                                     // pending packets
+#define ENC424J600_PCFULIF (0x01)    // To many pending packets
+
+// Interrupt enable bits (EIE register) higher byte
+#define ENC424J600_INTIE   (0x80)    // Global interrupt enable
+#define ENC424J600_MODEXIE (0x40)
+#define ENC424J600_HASHIE  (0x20)
+#define ENC424J600_AESIE   (0x10)
+#define ENC424J600_LINKIE  (0x08)    // PHY status has changed
+
+// Interrupt enable bits (EIE register) lower byte
+#define ENC424J600_PKTIE   (0x40)    // RX packet(s) pending
+#define ENC424J600_DMAIE   (0x20)
+#define ENC424J600_TXIE    (0x08)    // Transmit done
+#define ENC424J600_TXABTIE (0x04)    // Packet transmission aborted due to an error
+#define ENC424J600_RXABTIE (0x02)    // RX packet rejected due to lack of space / too many
+                                     // pending packets
+#define ENC424J600_PCFULIE (0x01)    // Too many pending packets
+
+// MICMD
+#define ENC424J600_MIIRD       (0x01)
+#define ENC424J600_MIISCAN     (0x02)
+
+// MISTAT
+#define ENC424J600_MISTAT_BUSY     (0x01)
+#define ENC424J600_MISTAT_SCAN     (0x02)
+#define ENC424J600_MISTAT_NVALID   (0x04)
+
+//ESTAT upper byte
+#define ENC424J600_PHYLNK      (0x01)
+#define ENC424J600_PHYDPX      (0x04)
+#define ENC424J600_CLKRDY      (0x10)
+#define ENC424J600_RXBUSY      (0x20)
+#define ENC424J600_FCIDLE      (0x40)
+#define ENC424J600_INT         (0x80)
+
+// ECON1 lower byte
+#define ENC424J600_TXRTS       (0x02)
+
+//ECON2 upper byte
+#define ENC424J600_STRCH       (0x40)
+#define ENC424J600_ETHEN       (0x80)
+
+// ECON2 lower byte
+#define ENC424J600_ETHRST      (0x10)
+#define ENC424J600_AUTOFC      (0x80)
+
+// MACON2 upper byte
+#define ENC424J600_NOBKOFF     (0x10)
+#define ENC424J600_BPEN        (0x20)
+#define ENC424J600_DEFER       (0x40)
+
+// MACON2 lower byte
+#define ENC424J600_FULDPX      (0x01)
+#define ENC424J600_HFRMEN      (0x04)
+#define ENC424J600_PHDREN      (0x08)
+#define ENC424J600_TXCRCEN     (0x10)
+
+// ERXFCON lower byte
+#define ENC424J600_BCEN        (0x01)    // accept broadcast packets
+#define ENC424J600_MCEN        (0x02)    // accept multicast packets
+#define ENC424J600_UCEN        (0x08)    // accept packets destined for local MAC address
+#define ENC424J600_RUNTEN      (0x10)    // discard runt packets
+#define ENC424J600_CRCEN       (0x40)    // discard packets with invalid CRC
+
+// PHCON1 upper byte
+#define ENC424J600_PFULDPX     (0x01)    // full duplex
+#define ENC424J600_RENEG       (0x02)    // restart negotiation
+#define ENC424J600_ANEN        (0x10)    // auto negotiation enable
+#define ENC424J600_SPD100      (0x20)    // 100Mb/s
+
+// PHANA upper byte
+#define ENC424J600_ADPAUS_BOTH     (0x0c)    // both symmetric and asymmetric flow control
+#define ENC424J600_ADPAUS_ASYM     (0x08)    // asymmetric flow control towards link partner
+#define ENC424J600_ADPAUS_SYMM     (0x04)    // symmetric flow control
+#define ENC424J600_ADPAUS_NONE     (0x00)    // no flow control
+#define ENC424J600_AD100FD         (0x01)
+
+// PHANA lower byte
+#define ENC424J600_AD100           (0x80)
+#define ENC424J600_AD10FD          (0x40)
+#define ENC424J600_AD10            (0x20)
+#define ENC424J600_IEEE802_3STD    (0x01)    //  IEEE Standard Selector Field bits
+
+//---------- end of definitions of bits in control registers -------------------------
+
+// enc424j600 SPI instructions opcodes
+
+// Single byte instructions
+enum enc424j600_spi_opcode_1_e
+{
+    ENC424J600_SETETHRST   = 0xca, // Issue System Reset
+    ENC424J600_SETPKTDEC   = 0xcc, // Decrement packet counter
+    ENC424J600_SETTXRTS    = 0xd4, // Send a packet
+    ENC424J600_FCDISABLE   = 0xe0, // Disable flow control
+    ENC424J600_FCSINGLE    = 0xe2, // Send a single pause frame
+    ENC424J600_FCMULTIPLE  = 0xe4, // Keep sending pause frames
+    ENC424J600_FCCLEAR     = 0xe6, // Send the final pause frame
+    ENC424J600_ENABLERX    = 0xe8, // Enable receiver
+    ENC424J600_DISABLERX   = 0xea, // Disable receiver
+    ENC424J600_SETEIE      = 0xec, // Enable interrupts
+    ENC424J600_CLREIE      = 0xee, // Disable interrupts
+};
+
+// Pointer definitions for 3-byte instructions
+enum enc424j600_spi_bufferp_e
+{
+    ENC424J600_GPBRDPT     = 0x60, // General purpose buffer read pointer
+    ENC424J600_RXRDPT      = 0x64, // Receive buffer read pointer
+    ENC424J600_UDARDPT     = 0x68, // User-defined area read pointer
+    ENC424J600_GPBWRPT     = 0x6c, // General purpose buffer write pointer
+    ENC424J600_RXWRPT      = 0x70, // Receive buffer write pointer
+    ENC424J600_UDAWRPT     = 0x74, // User-defined area write pointer
+
+};
+
+enum enc424j600_spi_opcode_3_e
+{
+    ENC424J600_WRITE3     = 0x00, // Pointer writing
+    ENC424J600_READ3      = 0x02  // Pointer reading
+
+};
+
+// N-byte unbanked SFR instructions
+enum enc424j600_spi_opcode_u_e
+{
+    ENC424J600_READCRU         = 0x20, // Read Control Register, Unbanked
+    ENC424J600_WRITECRU        = 0x22, // Write Control Register, Unbanked
+    ENC424J600_BITFIELDSETU    = 0x24, // Bit Field Set, Unbanked
+    ENC424J600_BITFIELDCLEARU  = 0x26 // Bit Field Clear, Unbanked
+};
+
+// N-byte banked SFR instructions
+enum enc424j600_spi_opcode_e
+{
+    ENC424J600_READCR          = 0x00, // Read Control Register, Banked
+    ENC424J600_WRITECR         = 0x40, // Write Control Register, Banked
+    ENC424J600_BITFIELDSET     = 0x80, // Bit Field Set, Banked
+    ENC424J600_BITFIELDCLEAR   = 0xa0 // Bit Field Clear, Banked
+};
+
+// N-byte SRAM instructions
+enum enc424j600_spi_opcode_sram_e
+{
+    ENC424J600_RGPDATA = 0x28,  // Read from General Purpose buffer
+    ENC424J600_WGPDATA = 0x2a,  // Write to General Purpose buffer
+    ENC424J600_RRXDATA = 0x2c,  // Read from Rx buffer
+    ENC424J600_WRXDATA = 0x2e   // Write to Rx buffer
+};
+
+#define ENC424J600_ETH_INTERRUPT_LEVEL_HIGH    (true)
+#define ENC424J600_ETH_INTERRUPT_LEVEL_LOW     (false)
+#define ENC424J600_ETH_INTERRUPT_EDGE_RISING   (true)
+#define ENC424J600_ETH_INTERRUPT_EDGE_FALLING  (false)
+
+//#define ETH_DRV_GET_MAC_ADDRESS (0x1100)
+
+#endif /* ifndef CYGONCE_DEVS_ETH_ENC424J600_SPI_H_ */
+// End of enc424j600_spi.h
new file mode 100644
--- /dev/null
+++ b/packages/devs/eth/microchip/enc424j600/current/tests/netconn_test_server.c
@@ -0,0 +1,354 @@
+//==========================================================================
+//
+//      netconn_test_server.c
+//
+//      Utility to test enc424j600 Ethernet driver
+//
+//==========================================================================
+// ####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 2010 Free Software Foundation, Inc.
+//
+// eCos is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 2 or (at your option) any later
+// version.
+//
+// eCos is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+// for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with eCos; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+//
+// As a special exception, if other files instantiate templates or use
+// macros or inline functions from this file, or you compile this file
+// and link it with other works to produce a work based on this file,
+// this file does not by itself cause the resulting work to be covered by
+// the GNU General Public License. However the source code for this file
+// must still be made available in accordance with section (3) of the GNU
+// General Public License v2.
+//
+// This exception does not invalidate any other reasons why a work based
+// on this file might be covered by the GNU General Public License.
+// -------------------------------------------
+// ####ECOSGPLCOPYRIGHTEND####
+//==========================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s):    Ilija Stanislevik
+// Contributors:
+// Date:         2010-08-04
+// Purpose:
+// Description:  Utility to test enc424j600 (or any other) Ethernet driver
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+#include <cyg/infra/cyg_type.h>
+#include <cyg/infra/testcase.h>         // Test macros
+#include <cyg/infra/cyg_ass.h>          // Assertion macros
+#include <cyg/infra/diag.h>             // Diagnostic output
+#include <cyg/hal/hal_io.h>
+#include <cyg/hal/hal_if.h>
+
+#include <cyg/hal/hal_arch.h>           // CYGNUM_HAL_STACK_SIZE_TYPICAL
+#include <cyg/kernel/kapi.h>
+
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <cyg/error/codes.h>
+#include <cyg/io/io.h>
+
+#include <cyg/io/spi.h>
+
+#include <cyg/io/eth/netdev.h>
+#include <network.h>
+
+#include <lwip/netif.h>
+#include <cyg/io/eth/eth_drv.h>
+
+#define PORTNUM 2000
+
+// Threads' data structures
+typedef struct thread_s
+{
+    cyg_uint8 stack [CYGNUM_HAL_STACK_SIZE_TYPICAL];
+    cyg_thread data;
+    cyg_handle_t handle;
+} thread_s_t;
+
+typedef struct
+{
+    struct netconn * connection_p;
+    cyg_uint32 id;
+} server_argument_t;
+
+//#define INIT_PRIORITY     5
+#define INIT_PRIORITY     12
+#define LISTENER_PRIORITY INIT_PRIORITY+1
+#define SERVER_PRIORITY   LISTENER_PRIORITY-1
+
+// Init thread
+
+thread_s_t init_thread;
+
+void run_init(void)
+{
+    diag_printf("i: Initializing network stack...\n");
+    cyg_lwip_sequential_init();
+}
+
+// Server thread
+
+void server(cyg_addrword_t arg_p)
+{
+    struct netconn *newconn = NULL;
+    struct netbuf *income_buffer = NULL;
+    struct ip_addr from_addr;
+    struct ip_addr my_addr;
+    cyg_uint16 from_port = 0;
+    cyg_uint16 my_port = 0;
+    cyg_uint8 *addr_byte_p = NULL;
+    cyg_uint16 total_len;
+    cyg_uint8 * data_buf = NULL;
+    cyg_int32 retval;
+    cyg_uint32 id;
+    cyg_uint32 csum;
+
+    newconn = ((server_argument_t *)arg_p) -> connection_p;
+    id = ((server_argument_t *)arg_p) -> id;
+
+    retval = netconn_addr(newconn, &my_addr, &my_port);
+    if(0 != retval)
+    {
+        diag_printf("%u: netconn_addr() return %d. Exiting.\n", id, retval);
+        netconn_delete(newconn);
+        cyg_thread_exit();
+    }
+
+    retval = netconn_peer(newconn, &from_addr, &from_port);
+    if(0 != retval)
+    {
+        diag_printf("%u: netconn_peer() return %d. Exiting.\n", id, retval);
+        netconn_delete(newconn);
+        cyg_thread_exit();
+    }
+
+    addr_byte_p = (cyg_uint8 *) & from_addr.addr;
+    diag_printf("%u: Connected to remote peer %u.%u.%u.%u port %u, at my port %u\n", id,
+        *addr_byte_p, *(addr_byte_p+1), *(addr_byte_p+2), *(addr_byte_p+3),
+        from_port, my_port);
+    diag_printf("newconn %x\n", (unsigned)newconn);
+
+    csum =0;
+
+    while((income_buffer = netconn_recv(newconn)) != NULL)
+    {
+        total_len = netbuf_len(income_buffer);
+        if(0 != total_len)
+        {
+            data_buf = malloc(total_len);
+            if(NULL == data_buf)
+            {
+                diag_printf("%u: Can not allocate %u bytes. Exiting.\n", id, total_len);
+                netconn_delete(newconn);
+                cyg_thread_exit();
+            }
+
+            cyg_uint8 *local_data_p = data_buf;
+            do
+            {
+                cyg_uint8 *in_data_p;
+                cyg_uint16 len;
+                int i;
+
+                netbuf_data(income_buffer, (void **)&in_data_p, &len);
+                for(i=0; i<len; i++)
+                {
+                    csum += *local_data_p++ = *in_data_p++;
+                }
+            } while(netbuf_next(income_buffer) >= 0);
+            diag_printf("\nReceived %u bytes\n", total_len);
+
+            free(data_buf);
+        }
+        netbuf_delete(income_buffer);
+    }
+
+    diag_printf("Checksum %08x\n", csum);
+
+    retval = netconn_close(newconn);
+    if( 0 != retval)
+    {
+        diag_printf("%u: netconn_close(%x) return %d.\n", id, (unsigned)newconn, retval);
+    }
+
+    retval = netconn_delete(newconn);
+    if( 0 != retval)
+    {
+        diag_printf("%u: netconn_delete(%x) return %d. Exiting.\n", id, (unsigned)newconn, retval);
+        cyg_thread_exit();
+    }
+
+    diag_printf("%u: TCP connection closed.\n", id);
+
+}
+
+// Listener thread
+
+thread_s_t listener_thread;
+
+void listener(void)
+{
+    struct netconn *conn = NULL;
+    struct netconn *newconn = NULL;
+    struct netif *mynetif = NULL;
+    server_argument_t server_launch_args_s;
+    cyg_uint32 server_id = 0;
+    thread_s_t * new_thread_data = NULL;
+    char server_name[20];
+    cyg_int32 retval;
+
+    // This large malloc is just for testing
+//    new_thread_data = malloc(150 * sizeof(thread_s_t));
+
+    cyg_thread_delay(500);     // Sleep over the initialization of network
+
+    mynetif = netif_find("et0");
+    diag_printf("l: netif_find(et0) return %x\n", (unsigned int)mynetif);
+    retval = netif_is_up(mynetif);
+    diag_printf("l: netif_is_up() return %u\n", retval);
+
+    diag_printf("l: Creating TCP connection...\n");
+    conn = netconn_new(NETCONN_TCP);
+    if (NULL == conn)
+    {
+        diag_printf("l: netconn_new() return NULL. Exiting.\n");
+        cyg_thread_exit();
+    }
+    diag_printf("l: Binding to port %d...\n", PORTNUM);
+    retval = netconn_bind(conn, NULL, PORTNUM);
+    if (0 != retval)
+    {
+        diag_printf("l: netconn_bind() return %d. Exiting.\n", retval);
+        cyg_thread_exit();
+    }
+
+    diag_printf("l: Setting up for listening...\n");
+    retval = netconn_listen(conn);
+    if( 0!= retval)
+    {
+        diag_printf("l: netconn_listen() return %d. Exiting.\n", retval);
+        cyg_thread_exit();
+    }
+
+    do
+    {
+        diag_printf("l: Waiting for a new connection...\n");
+        newconn = netconn_accept(conn);
+        if (NULL == newconn)
+        {
+            diag_printf("l: netconn_accept() return NULL. Exiting.\n");
+            cyg_thread_exit();
+        }
+
+        // It's time to start a server thread
+
+        new_thread_data = malloc(sizeof(thread_s_t));
+        if(NULL == new_thread_data)
+        {
+            diag_printf("l: Can't allocate memory for another server.\n");
+            netconn_close(newconn);
+            netconn_delete(newconn);
+            continue;
+        }
+        /*
+         * Thread data is never freed after the thread exit.
+         * After a number of connections made, it will be impossible to
+         * allocate memory for additional servers.
+         */
+
+        server_launch_args_s.connection_p = newconn;
+        server_launch_args_s.id = ++server_id;
+        sprintf(server_name, "s%u", server_id);
+
+        diag_printf("l: Starting %s...\n", server_name);
+
+        cyg_thread_create(
+            SERVER_PRIORITY,
+            (cyg_thread_entry_t*) server,
+            (cyg_addrword_t)&server_launch_args_s,
+            server_name,
+            &(new_thread_data->stack[0]),
+            CYGNUM_HAL_STACK_SIZE_TYPICAL,
+            &(new_thread_data->handle),
+            &(new_thread_data->data)
+        );
+        cyg_thread_resume(new_thread_data->handle);
+
+    } while(true);
+}
+
+//---------------------------------------------------------------------------
+void show_threads(void)
+{
+    cyg_handle_t thread = 0;
+    cyg_uint16 id = 0;
+
+    while( cyg_thread_get_next( &thread, &id ) )
+    {
+        cyg_thread_info info;
+
+        if( !cyg_thread_get_info( thread, id, &info ) )
+            break;
+
+        diag_printf("ID: %04x name: %10s pri: %d\n",
+                info.id, info.name?info.name:"----", info.set_pri );
+        diag_printf("  stack_base %x    stack_size %d\n", info.stack_base, info.stack_size);
+    }
+}
+
+void cyg_user_start(void)
+{
+    diag_printf("%u: Starting initializer...\n", __LINE__);
+    cyg_thread_create(
+        INIT_PRIORITY,
+        (cyg_thread_entry_t*) run_init,
+        0,
+        "initializer",
+        &init_thread.stack[0],
+        CYGNUM_HAL_STACK_SIZE_TYPICAL,
+        &init_thread.handle,
+        &init_thread.data
+    );
+    cyg_thread_resume(init_thread.handle);
+
+    diag_printf("%u: Starting listener...\n", __LINE__);
+
+    cyg_thread_create(
+        LISTENER_PRIORITY,
+        (cyg_thread_entry_t*) listener,
+        0,
+        "listener",
+        &listener_thread.stack[0],
+        CYGNUM_HAL_STACK_SIZE_TYPICAL,
+        &listener_thread.handle,
+        &listener_thread.data
+    );
+    cyg_thread_resume(listener_thread.handle);
+
+    show_threads();
+
+    diag_printf("%u: Starting scheduler...\n", __LINE__);
+    cyg_scheduler_start();
+}
+
+//=============================================================================
+