📄 eth_drv.c
字号:
//==========================================================================
//
// 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 + -