From e72f8fd961931cb85a6f3a95f9e872fa1a5c7ec9 Mon Sep 17 00:00:00 2001 From: patacongo Date: Sat, 21 May 2011 18:25:31 +0000 Subject: [PATCH] Add E1000 PIC NIC driver from Yu Qiang git-svn-id: https://nuttx.svn.sourceforge.net/svnroot/nuttx/trunk@3638 7fd9a85b-ad96-42d3-883c-3090e2eb8679 --- apps/ChangeLog.txt | 4 + apps/nshlib/nsh_netcmds.c | 44 +- apps/nshlib/nsh_parse.c | 2 +- nuttx/ChangeLog | 6 + nuttx/Documentation/NuttShell.html | 49 +- nuttx/arch/rgmp/src/nuttx.c | 10 +- nuttx/arch/rgmp/src/rgmp.c | 15 + nuttx/configs/rgmp/default/defconfig | 19 +- nuttx/configs/rgmp/nsh/defconfig | 19 +- nuttx/drivers/net/Make.defs | 4 + nuttx/drivers/net/e1000.c | 1044 ++++++++++++++++++++++++++ nuttx/drivers/net/e1000.h | 123 +++ nuttx/drivers/net/vnet.c | 3 +- nuttx/lib/net/Make.defs | 2 +- nuttx/lib/net/lib_inetaddr.c | 74 ++ 15 files changed, 1395 insertions(+), 23 deletions(-) create mode 100644 nuttx/drivers/net/e1000.c create mode 100644 nuttx/drivers/net/e1000.h create mode 100644 nuttx/lib/net/lib_inetaddr.c diff --git a/apps/ChangeLog.txt b/apps/ChangeLog.txt index a17488542..495268cb7 100755 --- a/apps/ChangeLog.txt +++ b/apps/ChangeLog.txt @@ -49,3 +49,7 @@ on initial check-in. 6.4 2011-xx-xx Gregory Nutt + + * nshlib/nsh_netcmds.c: If a network device name and IP address are provided + with the ifconfig command, then this command will now set the network address. + diff --git a/apps/nshlib/nsh_netcmds.c b/apps/nshlib/nsh_netcmds.c index 1bd1e93e4..6e210c020 100644 --- a/apps/nshlib/nsh_netcmds.c +++ b/apps/nshlib/nsh_netcmds.c @@ -466,8 +466,48 @@ int cmd_get(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv) #ifndef CONFIG_NSH_DISABLE_IFCONFIG int cmd_ifconfig(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv) { - netdev_foreach(ifconfig_callback, vtbl); - uip_statistics(vtbl); + struct in_addr addr; + in_addr_t ip; + + /* With one or no arguments, ifconfig simply shows the status of ethernet + * device: + * + * ifconfig + * ifconfig [nic_name] + */ + + if (argc <= 2) + { + netdev_foreach(ifconfig_callback, vtbl); + uip_statistics(vtbl); + return OK; + } + + /* If both the network interface name and an IP address are supplied as + * arguments, then ifconfig will set the address of the ethernet device: + * + * ifconfig nic_name ip_address + */ + + /* Set host ip address */ + + ip = addr.s_addr = inet_addr(argv[2]); + uip_sethostaddr(argv[1], &addr); + + /* Set gateway */ + + ip = NTOHL(ip); + ip &= ~0x000000ff; + ip |= 0x00000001; + + addr.s_addr = HTONL(ip); + uip_setdraddr(argv[1], &addr); + + /* Set netmask */ + + addr.s_addr = inet_addr("255.255.255.0"); + uip_setnetmask(argv[1], &addr); + return OK; } #endif diff --git a/apps/nshlib/nsh_parse.c b/apps/nshlib/nsh_parse.c index ef861b2de..f6a778a03 100644 --- a/apps/nshlib/nsh_parse.c +++ b/apps/nshlib/nsh_parse.c @@ -191,7 +191,7 @@ static const struct cmdmap_s g_cmdmap[] = #ifdef CONFIG_NET # ifndef CONFIG_NSH_DISABLE_IFCONFIG - { "ifconfig", cmd_ifconfig, 1, 1, NULL }, + { "ifconfig", cmd_ifconfig, 1, 3, "[nic_name [ip]]" }, # endif #endif diff --git a/nuttx/ChangeLog b/nuttx/ChangeLog index 998a0acfa..7b700a0d2 100644 --- a/nuttx/ChangeLog +++ b/nuttx/ChangeLog @@ -1764,3 +1764,9 @@ * lib/drivers/cc1101: Add initial, functional CC1101 wireless driver (contributed by Uros Platise) + * arch/mips and configs/pcblogic-pic32mx: The MicroChip PIC32MX port is now + code complete and ready to begin testing. + * drivers/net/e1000.c/h: A PCI-based E1000 ethernet driver submitted + by Yu Qiang. + * lib/net/lib_inetaddr.c: An implementatino of the inet_addr() function + submitted y Yu Qiang. \ No newline at end of file diff --git a/nuttx/Documentation/NuttShell.html b/nuttx/Documentation/NuttShell.html index d1dd3d922..80c653739 100644 --- a/nuttx/Documentation/NuttShell.html +++ b/nuttx/Documentation/NuttShell.html @@ -8,7 +8,7 @@

NuttShell (NSH)

-

Last Updated: March 18, 2011

+

Last Updated: May 21, 2011

@@ -603,7 +603,7 @@ mount -t vfat /dev/ram1 /tmp The behavior of this script depends upon three things: @@ -620,7 +620,7 @@ mount -t vfat /dev/ram1 /tmp

NOTE: apps/nshlib/rcS.template generates the standard, default nsh_romfsimg.h file. - If CONFIG_NSH_ARCHROMFS is defined in the NuttX configuration file, then a custom, board-specific nsh_romfsimg.h file residing in configs/<board>/include will be used. + If CONFIG_NSH_ARCHROMFS is defined in the NuttX configuration file, then a custom, board-specific nsh_romfsimg.h file residing in configs/<board>/include will be used. NOTE when the OS is configured, include/arch/board will be linked to configs/<board>/include.

@@ -985,21 +985,46 @@ help

Command Syntax:

    -ifconfig
    +ifconfig [nic_name [ip_address]]
     

Synopsis. - Show the current configuration of the network, for example: + Two forms of the ifconfigcommand are supported:

-
    +
      +
    1. +

      + With one or no arguments, ifconfig will shows the + current configuration of the network and, perhaps, the status of ethernet + device: +

      +
        +ifconfig
        +ifconfig [nic_name]
        +
      +

      + As an example: +

      +
         nsh> ifconfig
         eth0    HWaddr 00:18:11:80:10:06
                 IPaddr:10.0.0.2 DRaddr:10.0.0.1 Mask:255.255.255.0
         
      -

      - if uIP statistics are enabled (CONFIG_NET_STATISTICS), then - this command will also show the detailed state of uIP. -

      +

      + If uIP statistics are enabled (CONFIG_NET_STATISTICS), then + this command will also show the detailed state of uIP. +

      +
    2. +
    3. +

      + If both the network interface name and an IP address are supplied as arguments, + then ifconfig will set the address of the ethernet device: +

      +
        +ifconfig nic_name ip_address
        +
          + +
    @@ -1631,7 +1656,7 @@ sh <script-path>

    Synopsis. Execute the sequence of NSH commands in the file referred - to by <script-path>. + to by <script-path>.

    @@ -1696,7 +1721,7 @@ unset <name>

    Synopsis. Remove the value associated with the environment variable - <name>. Example: + <name>. Example:

       nsh> echo $foobar
      diff --git a/nuttx/arch/rgmp/src/nuttx.c b/nuttx/arch/rgmp/src/nuttx.c
      index ba5ffdd9b..b81fc98dd 100644
      --- a/nuttx/arch/rgmp/src/nuttx.c
      +++ b/nuttx/arch/rgmp/src/nuttx.c
      @@ -85,6 +85,7 @@ void up_initialize(void)
           extern pidhash_t g_pidhash[];
           extern void up_register_bridges(void);
           extern void vnet_initialize(void);
      +    extern void e1000_mod_init(void);
       
           // intialize the current_task to g_idletcb
           current_task = g_pidhash[PIDHASH(0)].tcb;
      @@ -92,12 +93,19 @@ void up_initialize(void)
           // setup console
           up_register_bridges();
       
      -    // setup net device
      +#ifdef CONFIG_NET_VNET
      +    // setup vnet device
           vnet_initialize();
      +#endif
       
           // setup COM device
           up_serialinit();
       
      +#ifdef CONFIG_NET_E1000
      +    // setup e1000
      +    e1000_mod_init();
      +#endif
      +
           // enable interrupt
           sti();
       }
      diff --git a/nuttx/arch/rgmp/src/rgmp.c b/nuttx/arch/rgmp/src/rgmp.c
      index 904729d51..6cc7aceb4 100644
      --- a/nuttx/arch/rgmp/src/rgmp.c
      +++ b/nuttx/arch/rgmp/src/rgmp.c
      @@ -154,4 +154,19 @@ int rtos_sem_down(void *sem)
           return sem_wait(sem);
       }
       
      +void rtos_stop_running(void)
      +{
      +    extern void e1000_mod_exit(void);
      +
      +    cli();
      +    
      +#ifdef CONFIG_NET_E1000
      +    e1000_mod_exit();
      +#endif
      +
      +    while(1) {
      +	asm volatile("hlt");
      +    }
      +}
      +
       
      diff --git a/nuttx/configs/rgmp/default/defconfig b/nuttx/configs/rgmp/default/defconfig
      index 772a1671f..198a0ddcb 100644
      --- a/nuttx/configs/rgmp/default/defconfig
      +++ b/nuttx/configs/rgmp/default/defconfig
      @@ -385,13 +385,28 @@ CONFIG_HEAP_BASE=
       CONFIG_HEAP_SIZE=
       
       
      -#
      +##########################################
       # RGMP specific configuration
      +##########################################
      +
      +#
      +# VNET
       #
       CONFIG_NET_VNET=y
       CONFIG_VNET_NINTERFACES=1
      +
      +#
      +# Serial port
      +#
       CONFIG_COM1=y
       CONFIG_COM2=y
       CONFIG_COM3=n
       CONFIG_COM4=n
      -CONFIG_E1000=n
      +
      +#
      +# E1000
      +#
      +CONFIG_NET_E1000=n
      +CONFIG_E1000_N_TX_DESC=128
      +CONFIG_E1000_N_RX_DESC=128
      +CONFIG_E1000_BUFF_SIZE=0x800
      diff --git a/nuttx/configs/rgmp/nsh/defconfig b/nuttx/configs/rgmp/nsh/defconfig
      index d8db04caa..081204024 100644
      --- a/nuttx/configs/rgmp/nsh/defconfig
      +++ b/nuttx/configs/rgmp/nsh/defconfig
      @@ -415,13 +415,28 @@ CONFIG_HEAP_BASE=
       CONFIG_HEAP_SIZE=
       
       
      -#
      +##########################################
       # RGMP specific configuration
      +##########################################
      +
      +#
      +# VNET
       #
       CONFIG_NET_VNET=y
       CONFIG_VNET_NINTERFACES=1
      +
      +#
      +# Serial port
      +#
       CONFIG_COM1=y
       CONFIG_COM2=y
       CONFIG_COM3=n
       CONFIG_COM4=n
      -CONFIG_E1000=n
      \ No newline at end of file
      +
      +#
      +# E1000
      +#
      +CONFIG_NET_E1000=n
      +CONFIG_E1000_N_TX_DESC=128
      +CONFIG_E1000_N_RX_DESC=128
      +CONFIG_E1000_BUFF_SIZE=0x800
      diff --git a/nuttx/drivers/net/Make.defs b/nuttx/drivers/net/Make.defs
      index eba3e5078..ab256cd8a 100644
      --- a/nuttx/drivers/net/Make.defs
      +++ b/nuttx/drivers/net/Make.defs
      @@ -55,6 +55,10 @@ ifeq ($(CONFIG_NET_VNET),y)
         CSRCS += vnet.c
       endif
       
      +ifeq ($(CONFIG_NET_E1000),y)
      +  CSRCS += e1000.c
      +endif
      +
       ifeq ($(CONFIG_NET_SLIP),y)
         CSRCS += slip.c
       endif
      diff --git a/nuttx/drivers/net/e1000.c b/nuttx/drivers/net/e1000.c
      new file mode 100644
      index 000000000..97b51a745
      --- /dev/null
      +++ b/nuttx/drivers/net/e1000.c
      @@ -0,0 +1,1044 @@
      +/****************************************************************************
      + * drivers/net/e1000.c
      + *
      + *   Copyright (C) 2011 Yu Qiang. All rights reserved.
      + *   Author: Yu Qiang 
      + *
      + * This file is a part of NuttX:
      + *
      + *   Copyright (C) 2011 Gregory Nutt. All rights reserved.
      + *
      + * Redistribution and use in source and binary forms, with or without
      + * modification, are permitted provided that the following conditions
      + * are met:
      + *
      + * 1. Redistributions of source code must retain the above copyright
      + *    notice, this list of conditions and the following disclaimer.
      + * 2. Redistributions in binary form must reproduce the above copyright
      + *    notice, this list of conditions and the following disclaimer in
      + *    the documentation and/or other materials provided with the
      + *    distribution.
      + * 3. Neither the name NuttX nor the names of its contributors may be
      + *    used to endorse or promote products derived from this software
      + *    without specific prior written permission.
      + *
      + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
      + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
      + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
      + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
      + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
      + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
      + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
      + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
      + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
      + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
      + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
      + * POSSIBILITY OF SUCH DAMAGE.
      + *
      + ****************************************************************************/
      +
      +/****************************************************************************
      + * Included Files
      + ****************************************************************************/
      +
      +#include 
      +#include 
      +#include 
      +#include 
      +#include 
      +#include 
      +#include 
      +#include 
      +
      +#include 
      +#include 
      +
      +#include 
      +#include 
      +#include 
      +
      +#include 
      +#include 
      +#include 
      +#include 
      +#include 
      +#include "e1000.h"
      +
      +/****************************************************************************
      + * Pre-processor Definitions
      + ****************************************************************************/
      +
      +/* TX poll deley = 1 seconds. CLK_TCK is the number of clock ticks per second */
      +
      +#define E1000_WDDELAY   (1*CLK_TCK)
      +#define E1000_POLLHSEC  (1*2)
      +
      +/* TX timeout = 1 minute */
      +
      +#define E1000_TXTIMEOUT (60*CLK_TCK)
      +
      +/* This is a helper pointer for accessing the contents of the Ethernet header */
      +
      +#define BUF ((struct uip_eth_hdr *)e1000->uip_dev.d_buf)
      +
      +/****************************************************************************
      + * Private Types
      + ****************************************************************************/
      +
      +struct tx_ring {
      +    struct tx_desc *desc;
      +    char *buf;
      +    int tail;      // where to write desc
      +};
      +
      +struct rx_ring {
      +    struct rx_desc *desc;
      +    char *buf;
      +    int head;      // where to read
      +    int tail;      // where to release free desc
      +    int free;      // number of freed desc
      +};
      +
      +struct e1000_dev {
      +    uint32_t phy_mem_base;
      +    uint32_t io_mem_base;
      +    uint32_t mem_size;
      +    int pci_dev_id;
      +    unsigned char src_mac[6];
      +    unsigned char dst_mac[6];
      +    int irq;
      +    struct irq_action int_desc;
      +    struct tx_ring tx_ring;
      +    struct rx_ring rx_ring;
      +    struct e1000_dev *next;
      +
      +    // NuttX net data
      +    bool bifup;               /* true:ifup false:ifdown */
      +    WDOG_ID txpoll;           /* TX poll timer */
      +    WDOG_ID txtimeout;        /* TX timeout timer */
      +
      +    /* This holds the information visible to uIP/NuttX */
      +
      +    struct uip_driver_s uip_dev;  /* Interface understood by uIP */
      +};
      +
      +struct e1000_dev_head {
      +    struct e1000_dev *next;
      +};
      +
      +/****************************************************************************
      + * Private Data
      + ****************************************************************************/
      +
      +static struct e1000_dev_head e1000_list = {0};
      +
      +/****************************************************************************
      + * Private Function Prototypes
      + ****************************************************************************/
      +
      +/* Common TX logic */
      +
      +static int  e1000_transmit(struct e1000_dev *e1000);
      +static int  e1000_uiptxpoll(struct uip_driver_s *dev);
      +
      +/* Interrupt handling */
      +
      +static void e1000_receive(struct e1000_dev *e1000);
      +
      +/* Watchdog timer expirations */
      +
      +static void e1000_polltimer(int argc, uint32_t arg, ...);
      +static void e1000_txtimeout(int argc, uint32_t arg, ...);
      +
      +/* NuttX callback functions */
      +
      +static int e1000_ifup(struct uip_driver_s *dev);
      +static int e1000_ifdown(struct uip_driver_s *dev);
      +static int e1000_txavail(struct uip_driver_s *dev);
      +#ifdef CONFIG_NET_IGMP
      +static int e1000_addmac(struct uip_driver_s *dev, const uint8_t *mac);
      +static int e1000_rmmac(struct uip_driver_s *dev, const uint8_t *mac);
      +#endif
      +
      +/****************************************************************************
      + * Private Functions
      + ****************************************************************************/
      + 
      +static inline void e1000_outl(struct e1000_dev *dev, int reg, uint32_t val)
      +{
      +    writel(dev->io_mem_base+reg, val);
      +}
      +
      +static inline uint32_t e1000_inl(struct e1000_dev *dev, int reg)
      +{
      +    return readl(dev->io_mem_base+reg);
      +}
      +
      +/****************************** e1000 driver ********************************/
      +
      +static void e1000_reset(struct e1000_dev *dev)
      +{
      +    uint32_t dev_control;
      +
      +    // Reset the network controller hardware
      +    dev_control = 0;
      +    dev_control |= (1<<0);   // FD-bit (Full Duplex)
      +    dev_control |= (0<<2);   // GIOMD-bit (GIO Master Disable)
      +    dev_control |= (1<<3);   // LRST-bit (Link Reset)
      +    dev_control |= (1<<6);   // SLU-bit (Set Link Up)	
      +    dev_control |= (1<<8);   // SPEED=2 (1000Mbps)
      +    dev_control |= (0<<11);  // FRCSPD-bit (Force Speed)
      +    dev_control |= (0<<12);  // FRCDPLX-bit (Force Duplex)
      +    dev_control |= (0<<20);  // ADVD3WUC-bit (Advertise D3 Wake Up Cap)
      +    dev_control |= (1<<26);  // RST-bit (Device Reset)
      +    dev_control |= (1<<27);  // RFCE-bit (Receive Flow Control Enable)
      +    dev_control |= (1<<28);  // TFCE-bit (Transmit Flow Control Enable) 
      +    dev_control |= (0<<30);  // VME-bit (VLAN Mode Enable) 
      +    dev_control |= (0<<31);  // PHY_RST-bit (PHY Reset)
      +
      +    e1000_outl(dev, E1000_IMC, 0xFFFFFFFF);
      +    e1000_outl(dev, E1000_STATUS, 0x00000000);
      +    e1000_outl(dev, E1000_CTRL, dev_control);
      +    dev_control &= ~(1<<26);  // clear RST-bit (Device Reset)
      +    e1000_outl(dev, E1000_CTRL, dev_control);	
      +    up_mdelay(2000);
      +    e1000_outl(dev, E1000_CTRL_EXT, 0x001401C0);
      +}
      +
      +static void e1000_turn_on(struct e1000_dev *dev)
      +{
      +    int	tx_control, rx_control;
      +    uint32_t ims = 0;
      +
      +    // turn on the controller's receive engine
      +    rx_control = e1000_inl(dev, E1000_RCTL);
      +    rx_control |= (1<<1);
      +    e1000_outl(dev, E1000_RCTL, rx_control);	
      +
      +    // turn on the controller's transmit engine
      +    tx_control = e1000_inl(dev, E1000_TCTL);
      +    tx_control |= (1<<1);
      +    e1000_outl(dev, E1000_TCTL, tx_control);	
      +
      +    // enable the controller's interrupts
      +    e1000_outl(dev, E1000_ICR, 0xFFFFFFFF);
      +    e1000_outl(dev, E1000_IMC, 0xFFFFFFFF);
      +
      +    ims |= 1<<0;      // TXDW
      +    ims |= 1<<1;      // TXQE
      +    ims |= 1<<2;      // LSC
      +    ims |= 1<<4;      // RXDMT0 
      +    ims |= 1<<7;      // RXT0 
      +    e1000_outl(dev, E1000_IMS, ims);
      +}
      +
      +static void e1000_turn_off(struct e1000_dev *dev)
      +{
      +    int	tx_control, rx_control;
      +
      +    // turn off the controller's receive engine
      +    rx_control = e1000_inl(dev, E1000_RCTL);
      +    rx_control &= ~(1<<1);
      +    e1000_outl(dev, E1000_RCTL, rx_control);	
      +
      +    // turn off the controller's transmit engine
      +    tx_control = e1000_inl(dev, E1000_TCTL);
      +    tx_control &= ~(1<<1);
      +    e1000_outl(dev, E1000_TCTL, tx_control);	
      +
      +    // turn off the controller's interrupts
      +    e1000_outl(dev, E1000_IMC, 0xFFFFFFFF);
      +}
      +
      +static void e1000_init(struct e1000_dev *dev)
      +{
      +    uint32_t rxd_phys, txd_phys, kmem_phys;
      +    uint32_t rx_control, tx_control;
      +    uint32_t pba;
      +    int i;
      +
      +    e1000_reset(dev);
      +
      +    // configure the controller's 'receive' engine
      +    rx_control = 0;
      +    rx_control |= (0<<1);	  // EN-bit (Enable)
      +    rx_control |= (0<<2);	  // SPB-bit (Store Bad Packets) 	
      +    rx_control |= (0<<3);	  // UPE-bit (Unicast Promiscuous Mode)
      +    rx_control |= (1<<4);	  // MPE-bit (Multicast Promiscuous Mode)
      +    rx_control |= (0<<5);	  // LPE-bit (Long Packet Enable)
      +    rx_control |= (0<<6);	  // LBM=0 (Loop-Back Mode)
      +    rx_control |= (0<<8);	  // RDMTS=0 (Rx Descriptor Min Threshold Size)
      +    rx_control |= (0<<10);  // DTYPE=0 (Descriptor Type)
      +    rx_control |= (0<<12);  // MO=0 (Multicast Offset)
      +    rx_control |= (1<<15);  // BAM-bit (Broadcast Address Mode)
      +    rx_control |= (0<<16);  // BSIZE=0 (Buffer Size = 2048) 	
      +    rx_control |= (0<<18);  // VLE-bit (VLAN filter Enable)
      +    rx_control |= (0<<19);  // CFIEN-bit (Canonical Form Indicator Enable)	
      +    rx_control |= (0<<20);  // CFI-bit (Canonical Form Indicator)
      +    rx_control |= (1<<22);  // DPF-bit (Discard Pause Frames)	
      +    rx_control |= (0<<23);  // PMCF-bit (Pass MAC Control Frames)
      +    rx_control |= (0<<25);  // BSEX=0 (Buffer Size EXtension)
      +    rx_control |= (1<<26);  // SECRC-bit (Strip Ethernet CRC)
      +    rx_control |= (0<<27);  // FLEXBUF=0 (Flexible Buffer size)	
      +    e1000_outl(dev, E1000_RCTL, rx_control);
      +
      +    // configure the controller's 'transmit' engine
      +    tx_control = 0;
      +    tx_control |= (0<<1);	   // EN-bit (Enable)
      +    tx_control |= (1<<3);	   // PSP-bit (Pad Short Packets)
      +    tx_control |= (15<<4);   // CT=15 (Collision Threshold)
      +    tx_control |= (63<<12);  // COLD=63 (Collision Distance)
      +    tx_control |= (0<<22);   // SWXOFF-bit (Software XOFF)
      +    tx_control |= (1<<24);   // RTLC-bit (Re-Transmit on Late Collision)
      +    tx_control |= (0<<25);   // UNORTX-bit (Underrun No Re-Transmit)
      +    tx_control |= (0<<26);   // TXCSCMT=0 (TxDesc Mininum Threshold)
      +    tx_control |= (0<<28);   // MULR-bit (Multiple Request Support)
      +    e1000_outl(dev, E1000_TCTL, tx_control);
      +
      +    // hardware flow control
      +    pba = e1000_inl(dev, E1000_PBA);
      +    // get receive FIFO size
      +    pba = (pba & 0x000000ff)<<10;
      +    e1000_outl(dev, E1000_FCAL, 0x00C28001);
      +    e1000_outl(dev, E1000_FCAH, 0x00000100);
      +    e1000_outl(dev, E1000_FCT, 0x00008808);
      +    e1000_outl(dev, E1000_FCTTV, 0x00000680);
      +    e1000_outl(dev, E1000_FCRTL, (pba*8/10)|0x80000000);
      +    e1000_outl(dev, E1000_FCRTH, pba*9/10);
      +
      +    // setup tx rings
      +    txd_phys = PADDR(dev->tx_ring.desc);
      +    kmem_phys = PADDR(dev->tx_ring.buf);
      +    for (i=0; itx_ring.desc[i].base_address = kmem_phys;
      +	dev->tx_ring.desc[i].packet_length = 0;
      +	dev->tx_ring.desc[i].cksum_offset = 0;
      +	dev->tx_ring.desc[i].cksum_origin = 0;
      +	dev->tx_ring.desc[i].desc_status = 1;
      +	dev->tx_ring.desc[i].desc_command = (1<<0)|(1<<1)|(1<<3);
      +	dev->tx_ring.desc[i].special_info = 0;
      +    }
      +    dev->tx_ring.tail = 0;
      +    e1000_outl(dev, E1000_TDT, 0);
      +    e1000_outl(dev, E1000_TDH, 0);
      +    // tell controller the location, size, and fetch-policy for Tx queue
      +    e1000_outl(dev, E1000_TDBAL, txd_phys);
      +    e1000_outl(dev, E1000_TDBAH, 0x00000000);
      +    e1000_outl(dev, E1000_TDLEN, CONFIG_E1000_N_TX_DESC*16);
      +    e1000_outl(dev, E1000_TXDCTL, 0x01010000);
      +
      +    // setup rx rings
      +    rxd_phys = PADDR(dev->rx_ring.desc);
      +    kmem_phys = PADDR(dev->rx_ring.buf);
      +    for (i=0; irx_ring.desc[i].base_address = kmem_phys;
      +	dev->rx_ring.desc[i].packet_length = 0;
      +	dev->rx_ring.desc[i].packet_cksum = 0;
      +	dev->rx_ring.desc[i].desc_status = 0;
      +	dev->rx_ring.desc[i].desc_errors = 0;
      +	dev->rx_ring.desc[i].vlan_tag = 0;
      +    }
      +    dev->rx_ring.head = 0;
      +    dev->rx_ring.tail = CONFIG_E1000_N_RX_DESC-1;
      +    dev->rx_ring.free = 0;
      +    // give the controller ownership of all receive descriptors
      +    e1000_outl(dev, E1000_RDH, 0);
      +    e1000_outl(dev, E1000_RDT, CONFIG_E1000_N_RX_DESC-1);
      +    // tell controller the location, size, and fetch-policy for RX queue
      +    e1000_outl(dev, E1000_RDBAL, rxd_phys);
      +    e1000_outl(dev, E1000_RDBAH, 0x00000000);
      +    e1000_outl(dev, E1000_RDLEN, CONFIG_E1000_N_RX_DESC*16);
      +    e1000_outl(dev, E1000_RXDCTL, 0x01010000);
      +
      +    e1000_turn_on(dev);
      +}
      +
      +/****************************************************************************
      + * Function: e1000_transmit
      + *
      + * Description:
      + *   Start hardware transmission.  Called either from the txdone interrupt
      + *   handling or from watchdog based polling.
      + *
      + * Parameters:
      + *   e1000  - Reference to the driver state structure
      + *
      + * Returned Value:
      + *   OK on success; a negated errno on failure
      + *
      + * Assumptions:
      + *   May or may not be called from an interrupt handler.  In either case,
      + *   global interrupts are disabled, either explicitly or indirectly through
      + *   interrupt handling logic.
      + *
      + ****************************************************************************/
      +
      +static int e1000_transmit(struct e1000_dev *e1000)
      +{
      +    int tail = e1000->tx_ring.tail;
      +    unsigned char *cp = (unsigned char *)
      +	(e1000->tx_ring.buf + tail * CONFIG_E1000_BUFF_SIZE);
      +    int count = e1000->uip_dev.d_len;
      +
      +    /* Verify that the hardware is ready to send another packet.  If we get
      +     * here, then we are committed to sending a packet; Higher level logic
      +     * must have assured that there is not transmission in progress.
      +     */
      +
      +    if (!e1000->tx_ring.desc[tail].desc_status)
      +	return -1;
      +
      +    /* Increment statistics */
      +
      +    /* Send the packet: address=skel->sk_dev.d_buf, length=skel->sk_dev.d_len */
      +    memcpy(cp, e1000->uip_dev.d_buf, e1000->uip_dev.d_len);
      +
      +    // prepare the transmit-descriptor
      +    e1000->tx_ring.desc[tail].packet_length = count<60 ? 60:count;
      +    e1000->tx_ring.desc[tail].desc_status = 0;
      +
      +    // give ownership of this descriptor to the network controller
      +    tail = (tail + 1) % CONFIG_E1000_N_TX_DESC;
      +    e1000->tx_ring.tail = tail;
      +    e1000_outl(e1000, E1000_TDT, tail);
      +
      +    /* Enable Tx interrupts */
      +
      +    /* Setup the TX timeout watchdog (perhaps restarting the timer) */
      +
      +    wd_start(e1000->txtimeout, E1000_TXTIMEOUT, e1000_txtimeout, 1, (uint32_t)e1000);
      +    return OK;
      +}
      +
      +/****************************************************************************
      + * Function: e1000_uiptxpoll
      + *
      + * Description:
      + *   The transmitter is available, check if uIP has any outgoing packets ready
      + *   to send.  This is a callback from uip_poll().  uip_poll() may be called:
      + *
      + *   1. When the preceding TX packet send is complete,
      + *   2. When the preceding TX packet send timesout and the interface is reset
      + *   3. During normal TX polling
      + *
      + * Parameters:
      + *   dev  - Reference to the NuttX driver state structure
      + *
      + * Returned Value:
      + *   OK on success; a negated errno on failure
      + *
      + * Assumptions:
      + *   May or may not be called from an interrupt handler.  In either case,
      + *   global interrupts are disabled, either explicitly or indirectly through
      + *   interrupt handling logic.
      + *
      + ****************************************************************************/
      +
      +static int e1000_uiptxpoll(struct uip_driver_s *dev)
      +{
      +    struct e1000_dev *e1000 = (struct e1000_dev *)dev->d_private;
      +    int tail = e1000->tx_ring.tail;
      +
      +    /* If the polling resulted in data that should be sent out on the network,
      +     * the field d_len is set to a value > 0.
      +     */
      +
      +    if (e1000->uip_dev.d_len > 0) {
      +	uip_arp_out(&e1000->uip_dev);
      +	e1000_transmit(e1000);
      +
      +	/* Check if there is room in the device to hold another packet. If not,
      +	 * return a non-zero value to terminate the poll.
      +	 */
      +	if (!e1000->tx_ring.desc[tail].desc_status)
      +	    return -1;
      +    }
      +
      +    /* If zero is returned, the polling will continue until all connections have
      +     * been examined.
      +     */
      +
      +    return 0;
      +}
      +
      +/****************************************************************************
      + * Function: e1000_receive
      + *
      + * Description:
      + *   An interrupt was received indicating the availability of a new RX packet
      + *
      + * Parameters:
      + *   e1000  - Reference to the driver state structure
      + *
      + * Returned Value:
      + *   None
      + *
      + * Assumptions:
      + *   Global interrupts are disabled by interrupt handling logic.
      + *
      + ****************************************************************************/
      +
      +static void e1000_receive(struct e1000_dev *e1000)
      +{
      +    int head = e1000->rx_ring.head;
      +    unsigned char *cp = (unsigned char *)
      +	(e1000->rx_ring.buf + head * CONFIG_E1000_BUFF_SIZE);
      +    int cnt;
      +
      +    while (e1000->rx_ring.desc[head].desc_status) {
      +
      +	/* Check for errors and update statistics */
      +	
      +	// Here we do not handle packets that exceed packet-buffer size
      +	if ((e1000->rx_ring.desc[head].desc_status & 3) == 1) {
      +	    cprintf("NIC READ: Oversized packet\n");
      +	    goto next;
      +	}
      +	
      +	/* Check if the packet is a valid size for the uIP buffer configuration */
      +	
      +	// get the number of actual data-bytes in this packet
      +	cnt = e1000->rx_ring.desc[head].packet_length;
      +	
      +	if (cnt > CONFIG_NET_BUFSIZE || cnt < 14) {
      +	    cprintf("NIC READ: invalid package size\n");
      +	    goto next;
      +	}
      +    
      +	/* Copy the data data from the hardware to e1000->uip_dev.d_buf.  Set
      +	 * amount of data in e1000->uip_dev.d_len
      +	 */
      +    
      +	// now we try to copy these data-bytes to the UIP buffer
      +	memcpy(e1000->uip_dev.d_buf, cp, cnt);
      +	e1000->uip_dev.d_len = cnt;
      +
      +	/* We only accept IP packets of the configured type and ARP packets */
      +
      +#ifdef CONFIG_NET_IPv6
      +	if (BUF->type == HTONS(UIP_ETHTYPE_IP6))
      +#else
      +	if (BUF->type == HTONS(UIP_ETHTYPE_IP))
      +#endif
      +	{
      +	    uip_arp_ipin(&e1000->uip_dev);
      +	    uip_input(&e1000->uip_dev);
      +
      +	    /* If the above function invocation resulted in data that should be
      +	     * sent out on the network, the field  d_len will set to a value > 0.
      +	     */
      +
      +	    if (e1000->uip_dev.d_len > 0) {
      +		uip_arp_out(&e1000->uip_dev);
      +		e1000_transmit(e1000);
      +	    }
      +	}
      +	else if (BUF->type == htons(UIP_ETHTYPE_ARP)) {
      +	    uip_arp_arpin(&e1000->uip_dev);
      +
      +	    /* If the above function invocation resulted in data that should be
      +	     * sent out on the network, the field  d_len will set to a value > 0.
      +	     */
      +
      +	    if (e1000->uip_dev.d_len > 0) {
      +		e1000_transmit(e1000);
      +	    }
      +	}
      +
      +    next:
      +	e1000->rx_ring.desc[head].desc_status = 0;
      +	e1000->rx_ring.head = (head + 1) % CONFIG_E1000_N_RX_DESC;
      +	e1000->rx_ring.free++;
      +	head = e1000->rx_ring.head;
      +	cp = (unsigned char *)(e1000->rx_ring.buf + head * CONFIG_E1000_BUFF_SIZE);
      +    }
      +}
      +
      +/****************************************************************************
      + * Function: e1000_txtimeout
      + *
      + * Description:
      + *   Our TX watchdog timed out.  Called from the timer interrupt handler.
      + *   The last TX never completed.  Reset the hardware and start again.
      + *
      + * Parameters:
      + *   argc - The number of available arguments
      + *   arg  - The first argument
      + *
      + * Returned Value:
      + *   None
      + *
      + * Assumptions:
      + *   Global interrupts are disabled by the watchdog logic.
      + *
      + ****************************************************************************/
      +
      +static void e1000_txtimeout(int argc, uint32_t arg, ...)
      +{
      +    struct e1000_dev *e1000 = (struct e1000_dev *)arg;
      +
      +    /* Increment statistics and dump debug info */
      +
      +    /* Then reset the hardware */
      +    e1000_init(e1000);
      +
      +    /* Then poll uIP for new XMIT data */
      +
      +    (void)uip_poll(&e1000->uip_dev, e1000_uiptxpoll);
      +}
      +
      +/****************************************************************************
      + * Function: e1000_polltimer
      + *
      + * Description:
      + *   Periodic timer handler.  Called from the timer interrupt handler.
      + *
      + * Parameters:
      + *   argc - The number of available arguments
      + *   arg  - The first argument
      + *
      + * Returned Value:
      + *   None
      + *
      + * Assumptions:
      + *   Global interrupts are disabled by the watchdog logic.
      + *
      + ****************************************************************************/
      +
      +static void e1000_polltimer(int argc, uint32_t arg, ...)
      +{
      +    struct e1000_dev *e1000 = (struct e1000_dev *)arg;
      +    int tail = e1000->tx_ring.tail;
      +
      +    /* Check if there is room in the send another TX packet.  We cannot perform
      +     * the TX poll if he are unable to accept another packet for transmission.
      +     */
      +    if (!e1000->tx_ring.desc[tail].desc_status)
      +	return;
      +
      +    /* If so, update TCP timing states and poll uIP for new XMIT data. Hmmm..
      +     * might be bug here.  Does this mean if there is a transmit in progress,
      +     * we will missing TCP time state updates?
      +     */
      +
      +    (void)uip_timer(&e1000->uip_dev, e1000_uiptxpoll, E1000_POLLHSEC);
      +
      +    /* Setup the watchdog poll timer again */
      +
      +    (void)wd_start(e1000->txpoll, E1000_WDDELAY, e1000_polltimer, 1, arg);
      +}
      +
      +/****************************************************************************
      + * Function: e1000_ifup
      + *
      + * Description:
      + *   NuttX Callback: Bring up the Ethernet interface when an IP address is
      + *   provided 
      + *
      + * Parameters:
      + *   dev  - Reference to the NuttX driver state structure
      + *
      + * Returned Value:
      + *   None
      + *
      + * Assumptions:
      + *
      + ****************************************************************************/
      +
      +static int e1000_ifup(struct uip_driver_s *dev)
      +{
      +    struct e1000_dev *e1000 = (struct e1000_dev *)dev->d_private;
      +
      +    ndbg("Bringing up: %d.%d.%d.%d\n",
      +	 dev->d_ipaddr & 0xff, (dev->d_ipaddr >> 8) & 0xff,
      +	 (dev->d_ipaddr >> 16) & 0xff, dev->d_ipaddr >> 24 );
      +
      +    /* Initialize PHYs, the Ethernet interface, and setup up Ethernet interrupts */
      +    e1000_init(e1000);
      +
      +    /* Set and activate a timer process */
      +
      +    (void)wd_start(e1000->txpoll, E1000_WDDELAY, e1000_polltimer, 1, (uint32_t)e1000);
      +
      +    if (e1000_inl(e1000, E1000_STATUS) & 2)
      +	e1000->bifup = true;
      +    else
      +	e1000->bifup = false;
      +
      +    return OK;
      +}
      +
      +/****************************************************************************
      + * Function: e1000_ifdown
      + *
      + * Description:
      + *   NuttX Callback: Stop the interface.
      + *
      + * Parameters:
      + *   dev  - Reference to the NuttX driver state structure
      + *
      + * Returned Value:
      + *   None
      + *
      + * Assumptions:
      + *
      + ****************************************************************************/
      +
      +static int e1000_ifdown(struct uip_driver_s *dev)
      +{
      +    struct e1000_dev *e1000 = (struct e1000_dev *)dev->d_private;
      +    irqstate_t flags;
      +
      +    /* Disable the Ethernet interrupt */
      +
      +    flags = irqsave();
      +
      +    e1000_turn_off(e1000);
      +
      +    /* Cancel the TX poll timer and TX timeout timers */
      +
      +    wd_cancel(e1000->txpoll);
      +    wd_cancel(e1000->txtimeout);
      +
      +    /* Put the the EMAC is its reset, non-operational state.  This should be
      +     * a known configuration that will guarantee the skel_ifup() always
      +     * successfully brings the interface back up.
      +     */
      +    //e1000_reset(e1000);
      +
      +    /* Mark the device "down" */
      +
      +    e1000->bifup = false;
      +    irqrestore(flags);
      +
      +    return OK;
      +}
      +
      +/****************************************************************************
      + * Function: e1000_txavail
      + *
      + * Description:
      + *   Driver callback invoked when new TX data is available.  This is a 
      + *   stimulus perform an out-of-cycle poll and, thereby, reduce the TX
      + *   latency.
      + *
      + * Parameters:
      + *   dev  - Reference to the NuttX driver state structure
      + *
      + * Returned Value:
      + *   None
      + *
      + * Assumptions:
      + *   Called in normal user mode
      + *
      + ****************************************************************************/
      +
      +static int e1000_txavail(struct uip_driver_s *dev)
      +{
      +    struct e1000_dev *e1000 = (struct e1000_dev *)dev->d_private;
      +    int tail = e1000->tx_ring.tail;
      +    irqstate_t flags;
      +
      +    /* Disable interrupts because this function may be called from interrupt
      +     * level processing.
      +     */
      +
      +    flags = irqsave();
      +
      +    /* Ignore the notification if the interface is not yet up */
      +
      +    if (e1000->bifup) {
      +	/* Check if there is room in the hardware to hold another outgoing packet. */
      +	if (e1000->tx_ring.desc[tail].desc_status)
      +	    (void)uip_poll(&e1000->uip_dev, e1000_uiptxpoll);
      +    }
      +
      +    irqrestore(flags);
      +    return OK;
      +}
      +
      +/****************************************************************************
      + * Function: e1000_addmac
      + *
      + * Description:
      + *   NuttX Callback: Add the specified MAC address to the hardware multicast
      + *   address filtering
      + *
      + * Parameters:
      + *   dev  - Reference to the NuttX driver state structure
      + *   mac  - The MAC address to be added 
      + *
      + * Returned Value:
      + *   None
      + *
      + * Assumptions:
      + *
      + ****************************************************************************/
      +
      +#ifdef CONFIG_NET_IGMP
      +static int e1000_addmac(struct uip_driver_s *dev, const uint8_t *mac)
      +{
      +  struct e1000_dev *e1000 = (struct e1000_dev *)dev->d_private;
      +
      +  /* Add the MAC address to the hardware multicast routing table */
      +
      +  return OK;
      +}
      +#endif
      +
      +/****************************************************************************
      + * Function: e1000_rmmac
      + *
      + * Description:
      + *   NuttX Callback: Remove the specified MAC address from the hardware multicast
      + *   address filtering
      + *
      + * Parameters:
      + *   dev  - Reference to the NuttX driver state structure
      + *   mac  - The MAC address to be removed 
      + *
      + * Returned Value:
      + *   None
      + *
      + * Assumptions:
      + *
      + ****************************************************************************/
      +
      +#ifdef CONFIG_NET_IGMP
      +static int e1000_rmmac(struct uip_driver_s *dev, const uint8_t *mac)
      +{
      +  struct e1000_dev *e1000 = (struct e1000_dev *)dev->d_private;
      +
      +  /* Add the MAC address to the hardware multicast routing table */
      +
      +  return OK;
      +}
      +#endif
      +
      +irqreturn_t  e1000_interrupt_handler(struct Trapframe *tf, void *dev_id)
      +{
      +    struct e1000_dev *e1000 = (struct e1000_dev *)dev_id;
      +    
      +    /* Get and clear interrupt status bits */
      +    int intr_cause = e1000_inl(e1000, E1000_ICR);
      +    e1000_outl(e1000, E1000_ICR, intr_cause);
      +
      +    // not for me
      +    if (intr_cause == 0) 
      +	return IRQ_NONE;
      +
      +    /* Handle interrupts according to status bit settings */
      +
      +    // Link status change
      +    if (intr_cause & (1<<2)) {
      +	if (e1000_inl(e1000, E1000_STATUS) & 2)
      +	    e1000->bifup = true;
      +	else
      +	    e1000->bifup = false;
      +    }
      +    
      +    /* Check if we received an incoming packet, if so, call skel_receive() */
      +
      +    // Rx-descriptor Timer expired
      +    if (intr_cause & (1<<7))
      +	e1000_receive(e1000);
      +
      +    // Tx queue empty
      +    if (intr_cause & (1<<1))
      +	wd_cancel(e1000->txtimeout);
      +
      +    /* Check is a packet transmission just completed.  If so, call skel_txdone.
      +     * This may disable further Tx interrupts if there are no pending
      +     * tansmissions.
      +     */
      +
      +    // Tx-descriptor Written back
      +    if (intr_cause & (1<<0))
      +	uip_poll(&e1000->uip_dev, e1000_uiptxpoll);
      +  
      +
      +    // Rx-Descriptors Low
      +    if (intr_cause & (1<<4)) {
      +	int tail;
      +	tail = e1000->rx_ring.tail + e1000->rx_ring.free;
      +	tail %= CONFIG_E1000_N_RX_DESC;
      +	e1000->rx_ring.tail = tail;
      +	e1000->rx_ring.free = 0;
      +	e1000_outl(e1000, E1000_RDT, tail);
      +    }
      +
      +    return IRQ_HANDLED;
      +}
      +
      +/******************************* PCI driver *********************************/
      +
      +static pci_id_t e1000_id_table[] = {
      +    {.sep = {INTEL_VENDERID, E1000_82573L}},
      +    {.sep = {INTEL_VENDERID, E1000_82540EM}},
      +    {.sep = {INTEL_VENDERID, E1000_82574L}},
      +    {.sep = {INTEL_VENDERID, E1000_82567LM}},
      +    {.sep = {INTEL_VENDERID, E1000_82541PI}},
      +    {.sep = {0,0}}	
      +};
      +
      +static int e1000_probe(uint16_t addr, pci_id_t id)
      +{
      +    uint32_t mmio_base, mmio_size;
      +    uint32_t pci_cmd, size;
      +    int err, irq;
      +    void *kmem, *omem;
      +    struct e1000_dev *dev;
      +
      +    // alloc e1000_dev memory
      +    dev = kzalloc(sizeof(struct e1000_dev));
      +    if (dev == NULL)
      +	return -1;
      +
      +    // enable device
      +    err = pci_enable_device(addr, PCI_RESOURCE_MEM);
      +    if (err)
      +	goto error;
      +
      +    // get e1000 device type
      +    dev->pci_dev_id = id.join;
      +
      +    // remap the controller's i/o-memory into kernel's address-space
      +    mmio_base = pci_resource_start(addr, 0);
      +    mmio_size = pci_resource_len(addr, 0);
      +    err = rgmp_memmap_nocache(mmio_base, mmio_size, mmio_base);
      +    if (err) 
      +	goto error;
      +    dev->phy_mem_base = mmio_base;
      +    dev->io_mem_base = mmio_base;
      +    dev->mem_size = mmio_size;
      +
      +    // make sure the controller's Bus Master capability is enabled
      +    pci_cmd = pci_config_readl(addr, PCI_COMMAND);
      +    pci_cmd |= (1<<2);
      +    pci_config_writel(addr, PCI_COMMAND, pci_cmd);
      +
      +    // MAC address
      +    memset(dev->dst_mac, 0xFF, 6);
      +    memcpy(dev->src_mac, (void *)(dev->io_mem_base+E1000_RA), 6);
      +
      +    // get e1000 IRQ
      +    irq = pci_read_irq(addr);
      +    dev->irq = irq;
      +    dev->int_desc.handler = e1000_interrupt_handler;
      +    dev->int_desc.dev_id = dev;
      +    err = rgmp_request_irq(irq, &dev->int_desc, IDC_SHARE);
      +    if (err)
      +	goto err0;
      +
      +    // Here we alloc a big block of memory once and make it
      +    // aligned to page boundary and multiple of page size. This
      +    // is because the memory can be modified by E1000 DMA and
      +    // should be mapped no-cache which will hugely reduce memory 
      +    // access performance. The page size alloc will restrict
      +    // this bad effect only within the memory we alloc here.
      +    size = CONFIG_E1000_N_TX_DESC * sizeof(struct tx_desc) +
      +	   CONFIG_E1000_N_TX_DESC * CONFIG_E1000_BUFF_SIZE +
      +	   CONFIG_E1000_N_RX_DESC * sizeof(struct rx_desc) + 
      +	   CONFIG_E1000_N_RX_DESC * CONFIG_E1000_BUFF_SIZE;
      +    size = ROUNDUP(size, PGSIZE);
      +    omem = kmem = memalign(PGSIZE, size);
      +    if (kmem == NULL) {
      +	err = -ENOMEM;
      +	goto err1;
      +    }
      +    rgmp_memremap_nocache((uintptr_t)kmem, size);
      +
      +    // alloc memory for tx ring
      +    dev->tx_ring.desc = (struct tx_desc*)kmem;
      +    kmem += CONFIG_E1000_N_TX_DESC * sizeof(struct tx_desc);
      +    dev->tx_ring.buf = kmem;
      +    kmem += CONFIG_E1000_N_TX_DESC * CONFIG_E1000_BUFF_SIZE;
      +
      +    // alloc memory for rx rings
      +    dev->rx_ring.desc = (struct rx_desc*)kmem;
      +    kmem += CONFIG_E1000_N_RX_DESC * sizeof(struct rx_desc);
      +    dev->rx_ring.buf = kmem;
      +
      +    /* Initialize the driver structure */
      +
      +    dev->uip_dev.d_ifup    = e1000_ifup;     /* I/F up (new IP address) callback */
      +    dev->uip_dev.d_ifdown  = e1000_ifdown;   /* I/F down callback */
      +    dev->uip_dev.d_txavail = e1000_txavail;  /* New TX data callback */
      +#ifdef CONFIG_NET_IGMP
      +    dev->uip_dev.d_addmac  = e1000_addmac;   /* Add multicast MAC address */
      +    dev->uip_dev.d_rmmac   = e1000_rmmac;    /* Remove multicast MAC address */
      +#endif
      +    dev->uip_dev.d_private = dev;            /* Used to recover private state from dev */
      +
      +    /* Create a watchdog for timing polling for and timing of transmisstions */
      +
      +    dev->txpoll       = wd_create();         /* Create periodic poll timer */
      +    dev->txtimeout    = wd_create();         /* Create TX timeout timer */
      +
      +    // Put the interface in the down state.
      +    // e1000 reset
      +    e1000_reset(dev);
      +
      +    /* Read the MAC address from the hardware */
      +    memcpy(dev->uip_dev.d_mac.ether_addr_octet, (void *)(dev->io_mem_base+E1000_RA), 6);
      +
      +    /* Register the device with the OS so that socket IOCTLs can be performed */
      +    err = netdev_register(&dev->uip_dev);
      +    if (err)
      +	goto err2;
      +
      +    // insert into e1000_list
      +    dev->next = e1000_list.next;
      +    e1000_list.next = dev;
      +    cprintf("bring up e1000 device: %04x %08x\n", addr, id.join);
      +
      +    return 0;
      +
      + err2:
      +    rgmp_memremap((uintptr_t)omem, size);
      +    free(omem);
      + err1:
      +    rgmp_free_irq(irq, &dev->int_desc);
      + err0:
      +    rgmp_memunmap(mmio_base, mmio_size);
      + error:
      +    kfree(dev);
      +    cprintf("e1000 device probe fail: %d\n", err);
      +    return err;
      +}
      +
      +/****************************************************************************
      + * Public Functions
      + ****************************************************************************/
      +
      +void e1000_mod_init(void)
      +{
      +    pci_probe_device(e1000_id_table, e1000_probe);
      +    return 0;
      +}
      +
      +void e1000_mod_exit(void)
      +{
      +    uint32_t size;
      +    struct e1000_dev *dev;
      +
      +    size = CONFIG_E1000_N_TX_DESC * sizeof(struct tx_desc) +
      +	   CONFIG_E1000_N_TX_DESC * CONFIG_E1000_BUFF_SIZE +
      +	   CONFIG_E1000_N_RX_DESC * sizeof(struct rx_desc) + 
      +	   CONFIG_E1000_N_RX_DESC * CONFIG_E1000_BUFF_SIZE;
      +    size = ROUNDUP(size, PGSIZE);
      +
      +    for (dev=e1000_list.next; dev!=NULL; dev=dev->next) {
      +	netdev_unregister(&dev->uip_dev);
      +	e1000_reset(dev);
      +	wd_delete(dev->txpoll);
      +	wd_delete(dev->txtimeout);
      +	rgmp_memremap((uintptr_t)dev->tx_ring.desc, size);
      +	free(dev->tx_ring.desc);
      +	rgmp_free_irq(dev->irq, &dev->int_desc);
      +	rgmp_memunmap((uintptr_t)dev->io_mem_base, dev->mem_size);
      +	kfree(dev);
      +    }
      +
      +    e1000_list.next = NULL;
      +}
      diff --git a/nuttx/drivers/net/e1000.h b/nuttx/drivers/net/e1000.h
      new file mode 100644
      index 000000000..04f986fef
      --- /dev/null
      +++ b/nuttx/drivers/net/e1000.h
      @@ -0,0 +1,123 @@
      +/****************************************************************************
      + * drivers/net/e1000.h
      + *
      + *   Copyright (C) 2011 Yu Qiang. All rights reserved.
      + *   Author: Yu Qiang 
      + *
      + * This file is a part of NuttX:
      + *
      + *   Copyright (C) 2011 Gregory Nutt. All rights reserved.
      + *
      + * Redistribution and use in source and binary forms, with or without
      + * modification, are permitted provided that the following conditions
      + * are met:
      + *
      + * 1. Redistributions of source code must retain the above copyright
      + *    notice, this list of conditions and the following disclaimer.
      + * 2. Redistributions in binary form must reproduce the above copyright
      + *    notice, this list of conditions and the following disclaimer in
      + *    the documentation and/or other materials provided with the
      + *    distribution.
      + * 3. Neither the name NuttX nor the names of its contributors may be
      + *    used to endorse or promote products derived from this software
      + *    without specific prior written permission.
      + *
      + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
      + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
      + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
      + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
      + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
      + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
      + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
      + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
      + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
      + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
      + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
      + * POSSIBILITY OF SUCH DAMAGE.
      + *
      + ****************************************************************************/
      +
      +#ifndef __DRIVERS_NET_E1000_H
      +#define __DRIVERS_NET_E1000_H
      +
      +/****************************************************************************
      + * Included Files
      + ****************************************************************************/
      +
      +#include 
      +#include 
      +#include 
      +
      +/****************************************************************************
      + * Pre-processor Definitions
      + ****************************************************************************/
      +
      +/************** PCI ID ***************/
      +
      +#define INTEL_VENDERID   0x8086
      +#define E1000_82573L     0x109a
      +#define E1000_82540EM    0x100e
      +#define E1000_82574L     0x10d3
      +#define E1000_82567LM    0x10f5
      +#define E1000_82541PI    0x107c
      +
      +/****************************************************************************
      + * Public Types
      + ****************************************************************************/
      +
      +enum e1000_registers {
      +	E1000_CTRL	= 0x0000,	// Device Control
      +	E1000_STATUS	= 0x0008,	// Device Status
      +	E1000_CTRL_EXT	= 0x0018,	// Device Control Extension
      +	E1000_FCAL      = 0x0028,       // Flow Control Address Low
      +	E1000_FCAH      = 0x002C,       // Flow Control Address High
      +	E1000_FCT       = 0x0030,       // Flow Control Type
      +	E1000_ICR	= 0x00C0,	// Interrupt Cause Read
      +	E1000_ICS	= 0x00C8,	// Interrupt Cause Set
      +	E1000_IMS	= 0x00D0,	// Interrupt Mask Set
      +	E1000_IMC	= 0x00D8,	// Interrupt Mask Clear
      +	E1000_RCTL	= 0x0100,	// Receive Control
      +	E1000_FCTTV     = 0x0170,       // Flow Control Transmit Timer Value
      +	E1000_TCTL	= 0x0400,	// Transmit Control
      +	E1000_PBA       = 0x1000,       // Packet Buffer Allocation
      +	E1000_FCRTL     = 0x2160,       // Flow Control Receive Threshold Low
      +	E1000_FCRTH     = 0x2168,       // Flow Control Receive Threshold High
      +	E1000_RDBAL	= 0x2800,	// Rx Descriptor Base Address Low	
      +	E1000_RDBAH	= 0x2804,	// Rx Descriptor Base Address High
      +	E1000_RDLEN	= 0x2808,	// Rx Descriptor Length
      +	E1000_RDH	= 0x2810,	// Rx Descriptor Head	
      +	E1000_RDT	= 0x2818,	// Rx Descriptor Tail	
      +	E1000_RXDCTL	= 0x2828,	// Rx Descriptor Control	
      +	E1000_TDBAL	= 0x3800,	// Tx Descriptor Base Address Low	
      +	E1000_TDBAH	= 0x3804,	// Tx Descriptor Base Address High
      +	E1000_TDLEN	= 0x3808,	// Tx Descriptor Length
      +	E1000_TDH	= 0x3810,	// Tx Descriptor Head	
      +	E1000_TDT	= 0x3818,	// Tx Descriptor Tail	
      +	E1000_TXDCTL	= 0x3828,	// Tx Descriptor Control	
      +	E1000_TPR	= 0x40D0,	// Total Packets Received
      +	E1000_TPT	= 0x40D4,	// Total Packets Transmitted
      +	E1000_RA	= 0x5400,	// Receive-filter Array
      +};
      +
      +/***************** e1000 device structure *****************/
      +
      +struct tx_desc {
      +    uint64_t base_address;
      +    uint16_t packet_length;
      +    uint8_t  cksum_offset;
      +    uint8_t  desc_command;
      +    uint8_t  desc_status;
      +    uint8_t  cksum_origin;
      +    uint16_t special_info;
      +};
      +
      +struct rx_desc {
      +    uint64_t base_address;
      +    uint16_t packet_length;
      +    uint16_t packet_cksum;
      +    uint8_t  desc_status;
      +    uint8_t  desc_errors;
      +    uint16_t vlan_tag;
      +};
      +
      +#endif
      diff --git a/nuttx/drivers/net/vnet.c b/nuttx/drivers/net/vnet.c
      index 6475334b5..c12976a0f 100644
      --- a/nuttx/drivers/net/vnet.c
      +++ b/nuttx/drivers/net/vnet.c
      @@ -123,7 +123,6 @@ static int  vnet_uiptxpoll(struct uip_driver_s *dev);
       
       /* Interrupt handling */
       
      -static void vnet_receive(FAR struct vnet_driver_s *vnet);
       static void vnet_txdone(FAR struct vnet_driver_s *vnet);
       
       /* Watchdog timer expirations */
      @@ -250,7 +249,7 @@ static int vnet_uiptxpoll(struct uip_driver_s *dev)
       }
       
       /****************************************************************************
      - * Function: vnet_receive
      + * Function: rtos_vnet_recv
        *
        * Description:
        *   An interrupt was received indicating the availability of a new RX packet
      diff --git a/nuttx/lib/net/Make.defs b/nuttx/lib/net/Make.defs
      index 5cacb1079..ca7ab9587 100644
      --- a/nuttx/lib/net/Make.defs
      +++ b/nuttx/lib/net/Make.defs
      @@ -33,4 +33,4 @@
       #
       ############################################################################
       
      -NET_SRCS = lib_htons.c lib_htonl.c lib_inetntoa.c lib_etherntoa.c
      +NET_SRCS = lib_htons.c lib_htonl.c lib_inetntoa.c lib_etherntoa.c lib_inetaddr.c
      diff --git a/nuttx/lib/net/lib_inetaddr.c b/nuttx/lib/net/lib_inetaddr.c
      new file mode 100644
      index 000000000..48b01d682
      --- /dev/null
      +++ b/nuttx/lib/net/lib_inetaddr.c
      @@ -0,0 +1,74 @@
      +/****************************************************************************
      + * lib/net/lib_inetaddr.c
      + *
      + *   Copyright (C) 2011 Yu Qiang. All rights reserved.
      + *   Author: Yu Qiang 
      + *
      + * This file is a part of NuttX:
      + *
      + *   Copyright (C) 2011 Gregory Nutt. All rights reserved.
      + *
      + * Redistribution and use in source and binary forms, with or without
      + * modification, are permitted provided that the following conditions
      + * are met:
      + *
      + * 1. Redistributions of source code must retain the above copyright
      + *    notice, this list of conditions and the following disclaimer.
      + * 2. Redistributions in binary form must reproduce the above copyright
      + *    notice, this list of conditions and the following disclaimer in
      + *    the documentation and/or other materials provided with the
      + *    distribution.
      + * 3. Neither the name NuttX nor the names of its contributors may be
      + *    used to endorse or promote products derived from this software
      + *    without specific prior written permission.
      + *
      + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
      + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
      + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
      + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
      + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
      + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
      + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
      + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
      + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
      + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
      + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
      + * POSSIBILITY OF SUCH DAMAGE.
      + *
      + ****************************************************************************/
      +
      +/****************************************************************************
      + * Included Files
      + ****************************************************************************/
      +
      +#include 
      +#include 
      +
      +/****************************************************************************
      + * Public Functions
      + ****************************************************************************/
      +
      +/****************************************************************************
      + * name inet_addr
      + *
      + * Description:
      + *   The inet_addr() function converts the string pointed to by cp, in the
      + *   standard IPv4 dotted decimal notation, to an integer value suitable for
      + *   use as an Internet address.
      + 
      + ****************************************************************************/
      +
      +in_addr_t inet_addr(FAR const char *cp)
      +{
      +  unsigned int a, b, c, d;
      +  uint32_t result;
      +
      +  sscanf(cp, "%u.%u.%u.%u", &a, &b, &c, &d);
      +  result   = a << 8;
      +  result  |= b;
      +  result <<= 8;
      +  result  |= c;
      +  result <<= 8;
      +  result  |= d;
      +  return HTONL(result);
      +}