⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 eth_drv.c

📁 开放源码实时操作系统源码.
💻 C
📖 第 1 页 / 共 3 页
字号:
//==========================================================================
//
//      src/net/eth_drv.c
//
//      Hardware independent ethernet driver
//
//==========================================================================
//####ECOSGPLCOPYRIGHTBEGIN####
// -------------------------------------------
// This file is part of eCos, the Embedded Configurable Operating System.
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
// Copyright (C) 2002, 2003 Gary Thomas
//
// 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.,
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 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.
//
// This exception does not invalidate any other reasons why a work based on
// this file might be covered by the GNU General Public License.
//
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
// at http://sources.redhat.com/ecos/ecos-license/
// -------------------------------------------
//####ECOSGPLCOPYRIGHTEND####
//==========================================================================
//#####DESCRIPTIONBEGIN####
//
// Author(s):    gthomas
// Contributors: gthomas
// Date:         2000-01-10
// Purpose:      Hardware independent ethernet driver
// Description:  
//              
//
//####DESCRIPTIONEND####
//
//==========================================================================

// High-level ethernet driver

#include <sys/param.h>
#include <sys/errno.h>
#include <sys/ioctl.h>
#include <sys/mbuf.h>
#include <sys/socket.h>

#include <net/if.h>
#include <net/if_dl.h>
#include <net/if_types.h>
#include <net/netisr.h>

#ifdef INET
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/in_var.h>
#include <netinet/ip.h>
#include <netinet/if_ether.h>
#endif

#ifndef NBPFILTER
#define NBPFILTER 0
#endif

#if NBPFILTER > 0
#include <net/bpf.h>
#include <net/bpfdesc.h>
#endif

#include <cyg/infra/cyg_ass.h>
#include <cyg/hal/drv_api.h>
#include <pkgconf/hal.h>
#include <cyg/hal/hal_if.h>
#include <pkgconf/io_eth_drivers.h> // module configury; SIMULATED_FAILURES
#include <pkgconf/net.h>            // CYGPKG_NET_FAST_THREAD_TICKLE_DEVS?

#include <cyg/io/eth/eth_drv.h>
#include <cyg/io/eth/netdev.h>

#ifndef min
#define min( _x_, _y_ ) ((_x_) < (_y_) ? (_x_) : (_y_))
#endif

// ------------------------------------------------------------------------
#ifdef CYGPKG_IO_ETH_DRIVERS_SIMULATED_FAILURES

#define noLOG_RANDOM 32 // so you can tell this is really being random
#ifdef LOG_RANDOM
static struct {
    unsigned int *which;
    unsigned int random;
    unsigned int r100;
} random_log[LOG_RANDOM];

static int random_index = 0;
#endif

static unsigned int
randomize( unsigned int *p )
{
    unsigned int r100;
    HAL_CLOCK_READ( &r100 );
    r100 ^= *p;
    *p = (r100 * 1103515245) + 12345;
    r100 &= 127;
    if ( r100 >= 100 ) // spread the overflow around evenly
        r100 = 4 * (r100 - 100);
    if ( r100 >= 100 ) // and again - (125,126,127=>100,104,108)
        r100 = 12 * (r100 - 100); // =>(0,48,96)
#ifdef LOG_RANDOM
    random_log[random_index].which  = p;
    random_log[random_index].random = *p;
    random_log[random_index].r100   = r100;
    random_index++;
    random_index &= (LOG_RANDOM-1);
#endif
    return r100;
}

#define SIMULATE_FAIL_SEND     1
#define SIMULATE_FAIL_RECV     2
#define SIMULATE_FAIL_CORRUPT  3

static struct simulated_failure_state {
    struct eth_drv_sc *sc;
    unsigned int r_tx_fail;
    unsigned int r_rx_fail;
    unsigned int r_rx_corrupt;
    cyg_tick_count_t droptime;
    cyg_tick_count_t passtime;
} simulated_failure_states[2] = {{0},{0}};

static int
simulate_fail( struct eth_drv_sc *sc, int which )
{
    struct simulated_failure_state *s;  
    
    for ( s = &simulated_failure_states[0]; s < &simulated_failure_states[2];
          s++ ) {
        if ( 0 == s->sc ) {
            s->sc = sc;
            s->r_tx_fail    = (unsigned int)sc;
            s->r_rx_fail    = (unsigned int)sc ^ 0x01234567;
            s->r_rx_corrupt = (unsigned int)sc ^ 0xdeadbeef;
            s->droptime = 0;
            s->passtime = 0;
        }
        if ( sc == s->sc )
            break;
    }
    if ( &simulated_failure_states[2] == s ) {
        CYG_FAIL( "No free slot in simulated_failure_states[]" );
        return 1; // always fail
    }

#ifdef CYGPKG_IO_ETH_DRIVERS_SIMULATE_LINE_CUT
    // Regardless of the question, we say "yes" during the period of
    // unpluggedness...
    {
        cyg_tick_count_t now = cyg_current_time();
        if ( now > s->droptime && 0 == s->passtime ) { // [initial condition]
            s->droptime = 0; // go into a passing phase
            (void)randomize( &s->r_tx_fail );
            (void)randomize( &s->r_rx_fail );
            (void)randomize( &s->r_rx_corrupt );
            s->passtime = s->r_tx_fail + s->r_rx_fail + s->r_rx_corrupt;
            s->passtime &= 0x3fff; // 16k cS is up to 160S, about 2.5 minutes
            s->passtime += now;
        }
        else if ( now > s->passtime && 0 == s->droptime ) {
            s->passtime = 0; // go into a dropping phase
            (void)randomize( &s->r_tx_fail );
            (void)randomize( &s->r_rx_fail );
            (void)randomize( &s->r_rx_corrupt );
            s->droptime = s->r_tx_fail + s->r_rx_fail + s->r_rx_corrupt;
            s->droptime &= 0x0fff; // 4k cS is up to 40S, about 1/2 a minute
            s->droptime += now;
        }

        if ( now < s->droptime )
            return 1; // Say "no"
    }
#endif

    switch ( which ) {
#ifdef CYGPKG_IO_ETH_DRIVERS_SIMULATE_DROP_TX
    case SIMULATE_FAIL_SEND: {
        unsigned int z = randomize( &s->r_tx_fail );
        return z < CYGPKG_IO_ETH_DRIVERS_SIMULATE_DROP_TX;
    }
#endif
#ifdef CYGPKG_IO_ETH_DRIVERS_SIMULATE_DROP_RX
    case SIMULATE_FAIL_RECV: {
        unsigned int z = randomize( &s->r_rx_fail );
        return z < CYGPKG_IO_ETH_DRIVERS_SIMULATE_DROP_RX;
    }
#endif
#ifdef CYGPKG_IO_ETH_DRIVERS_SIMULATE_CORRUPT_RX
    case SIMULATE_FAIL_CORRUPT: {
        unsigned int z = randomize( &s->r_rx_corrupt );
        return z < CYGPKG_IO_ETH_DRIVERS_SIMULATE_CORRUPT_RX;
    }
#endif
    default:
        // do nothing - for when options above are not enabled.
    }
    return 0;
}

#define noLOG_CORRUPTION 32 // so you can tell this is really being random
#ifdef LOG_CORRUPTION
static struct {
    int len;
    int thislen;
    int off;
    unsigned char xor;
    unsigned char idx;
} corruption_log[LOG_CORRUPTION];

static int corruption_index = 0;
#endif

static void
simulate_fail_corrupt_sglist( struct eth_drv_sg *sg_list, int sg_len )
{
    unsigned int z, len, i, off;
    HAL_CLOCK_READ( &z );
    z += simulated_failure_states[0].r_rx_corrupt;
    z += simulated_failure_states[1].r_rx_corrupt;

    CYG_ASSERT( MAX_ETH_DRV_SG >= sg_len, "sg_len overflow in corrupt" );

    for ( i = 0, len = 0; i < sg_len && sg_list[i].buf && sg_list[i].len; i++ )
        len =+ sg_list[i].len;

    CYG_ASSERT( 1500 >= len, "sg...len > ether MTU" );
    if ( 14 >= len ) // normal ether header
        return;

    off = z & 2047; // next (2^N-1) > MTU
    while ( off > len )
        off -= len;

    for ( i = 0; i < sg_len && sg_list[i].buf && sg_list[i].len; i++ ) {
        if ( off < sg_list[i].len ) { // corrupt this one
            unsigned char *p = (unsigned char *)sg_list[i].buf;
            p[off] ^= (0xff & (z >> 11));
#ifdef LOG_CORRUPTION
            corruption_log[corruption_index].len = len;
            corruption_log[corruption_index].thislen = sg_list[i].len;
            corruption_log[corruption_index].off = off;
            corruption_log[corruption_index].xor = (0xff & (z >> 11));
            corruption_log[corruption_index].idx = i;
            corruption_index++;
            corruption_index &= (LOG_CORRUPTION-1);
#endif
            return;
        }
        off -= sg_list[i].len;
    }    
    CYG_FAIL( "Didn't corrupt anything" );
}

#endif // CYGPKG_IO_ETH_DRIVERS_SIMULATED_FAILURES
// ------------------------------------------------------------------------

#ifdef CYGSEM_HAL_VIRTUAL_VECTOR_SUPPORT

#include <cyg/hal/hal_if.h>

// Use with care!  Local variable defined!
#define START_CONSOLE()                                                                 \
{   /* NEW BLOCK */                                                                     \
    int _cur_console =                                                                  \
        CYGACC_CALL_IF_SET_CONSOLE_COMM(CYGNUM_CALL_IF_SET_COMM_ID_QUERY_CURRENT);      \
    {                                                                                   \
        int i;                                                                          \
        if ( CYGACC_CALL_IF_FLASH_CFG_OP( CYGNUM_CALL_IF_FLASH_CFG_GET,                 \
                                          "info_console_force", &i,                     \
                                          CYGNUM_FLASH_CFG_TYPE_CONFIG_BOOL ) ) {       \
            if ( i ) {                                                                  \
                if ( CYGACC_CALL_IF_FLASH_CFG_OP( CYGNUM_CALL_IF_FLASH_CFG_GET,         \
                                                  "info_console_number", &i,            \
                                                  CYGNUM_FLASH_CFG_TYPE_CONFIG_INT ) ){ \
                    /* Then i is the console to force it to: */                         \
                    CYGACC_CALL_IF_SET_CONSOLE_COMM( i );                               \
                }                                                                       \
            }                                                                           \
        }                                                                               \
    }

#define END_CONSOLE()                                   \
    CYGACC_CALL_IF_SET_CONSOLE_COMM(_cur_console);      \
}   /* END BLOCK */

#else
#define START_CONSOLE()
#define END_CONSOLE()
#endif
// ------------------------------------------------------------------------

#ifdef CYGPKG_NET_FREEBSD_STACK
extern char *_ioctl_name(u_long cmd);
typedef void void_fun(void *);
#endif

static int  eth_drv_ioctl(struct ifnet *, u_long, caddr_t);
static void eth_drv_send(struct ifnet *);
static void eth_drv_start(struct eth_drv_sc *sc);

#ifdef CYGDBG_IO_ETH_DRIVERS_DEBUG 
int cyg_io_eth_net_debug = CYGDBG_IO_ETH_DRIVERS_DEBUG_VERBOSITY;
#endif

// Interfaces exported to drivers

static void eth_drv_init(struct eth_drv_sc *sc, unsigned char *enaddr);
static void eth_drv_recv(struct eth_drv_sc *sc, int total_len);
static void eth_drv_tx_done(struct eth_drv_sc *sc, CYG_ADDRESS key, int status);

struct eth_drv_funs eth_drv_funs = {eth_drv_init, eth_drv_recv, eth_drv_tx_done};

//
// This function is called during system initialization to register a
// network interface with the system.
//
static void
eth_drv_init(struct eth_drv_sc *sc, unsigned char *enaddr)
{
    struct ifnet *ifp = &sc->sc_arpcom.ac_if;
#ifdef CYGPKG_NET_FREEBSD_STACK
    int unit;
    char *np, *xp;
#endif

    // Set up hardware address
    if (NULL != enaddr)
        bcopy(enaddr, &sc->sc_arpcom.ac_enaddr, ETHER_ADDR_LEN);

    // Initialize ifnet structure

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -