欢迎来到虫虫下载站 | 资源下载 资源专辑 关于我们
虫虫下载站

if_lan91cxx.c

eCos操作系统源码
C
第 1 页 / 共 4 页
字号:
//==========================================================================////      dev/if_lan91cxx.c////      Ethernet device driver for SMSC LAN91CXX compatible controllers////==========================================================================//####ECOSGPLCOPYRIGHTBEGIN####// -------------------------------------------// This file is part of eCos, the Embedded Configurable Operating System.// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.// Copyright (C) 2003 Nick Garnett // Copyright (C) 2004 Andrew Lunn//// 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####//####BSDCOPYRIGHTBEGIN####//// -------------------------------------------//// Portions of this software may have been derived from OpenBSD or other sources,// and are covered by the appropriate copyright disclaimers included herein.//// -------------------------------------------////####BSDCOPYRIGHTEND####//==========================================================================//#####DESCRIPTIONBEGIN####//// Author(s):    hmt, based on lan900 (for LAN91C110) driver by jskov//               jskov, based on CS8900 driver by Gary Thomas// Contributors: gthomas, jskov, hmt, jco@ict.es, nickg// Date:         2001-01-22// Purpose:      // Description:  hardware driver for LAN91CXX "LAN9000" ethernet// Notes:        Pointer register is not saved/restored on receive interrupts.//               The pointer is shared by both receive/transmit code.//               But the net stack manages atomicity for you here.////               The controller has an autorelease mode that allows TX packets//               to be freed automatically on successful transmission - but//               that is not used since we're only sending one packet at a//               time anyway.//               We may want to pingpong in future for throughput reasons.////               <jco@ict.es> Added support for PCMCIA mode and shifted//               address buses.////####DESCRIPTIONEND####////==========================================================================// Based on LAN91C110 and LAN91C96#include <pkgconf/system.h>#include <pkgconf/devs_eth_smsc_lan91cxx.h>#include <pkgconf/io_eth_drivers.h>#include <cyg/infra/cyg_type.h>#include <cyg/hal/hal_arch.h>#include <cyg/hal/hal_intr.h>#include <cyg/hal/hal_diag.h>#include <cyg/infra/cyg_ass.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>#ifdef CYGPKG_NET#include <pkgconf/net.h>#include <cyg/kernel/kapi.h>#include <net/if.h>  /* Needed for struct ifnet */#endif#ifdef CYGPKG_INFRA_DEBUG// Then we log, OOI, the number of times we get a bad packet number// from the tx done fifo.int lan91cxx_txfifo_good = 0;int lan91cxx_txfifo_bad = 0;#endif// Set to perms of:// 0 disables all debug output// 1 for process debug output// 2 for added data IO output: get_reg, put_reg// 4 for packet allocation/free output// 8 for only startup status, so we can tell we're installed OK#define DEBUG 0#if DEBUG#if defined(CYGPKG_REDBOOT)static void db_printf( char *fmt, ... ){    extern int start_console(void);    extern void end_console(int);    va_list a;    int old_console;    va_start( a, fmt );    old_console = start_console();      diag_vprintf( fmt, a );    end_console(old_console);    va_end( a );}#else#define db_printf diag_printf#endif#else#define db_printf( fmt, ... )#endif#if DEBUG & 1#define DEBUG_FUNCTION() do { db_printf("%s\n", __FUNCTION__); } while (0)#else#define DEBUG_FUNCTION() do {} while(0)#endif#if defined(ETH_DRV_GET_IF_STATS) || defined (ETH_DRV_GET_IF_STATS_UD)#define KEEP_STATISTICS#endif#ifdef KEEP_STATISTICS#define INCR_STAT( _x_ )        (cpd->stats. _x_ ++)#else#define INCR_STAT( _x_ )        CYG_EMPTY_STATEMENT#endif#include "smsc_lan91cxx.h"#ifdef LAN91CXX_IS_LAN91C111static void lan91cxx_write_phy(struct eth_drv_sc *sc, cyg_uint8 phyaddr,			       cyg_uint8 phyreg, cyg_uint16 value);static cyg_uint16 lan91cxx_read_phy(struct eth_drv_sc *sc, cyg_uint8 phyaddr,				    cyg_uint8 phyreg);#endifstatic void lan91cxx_poll(struct eth_drv_sc *sc);#ifdef LAN91CXX_IS_LAN91C111// Revision A of the LAN91C111 has a bug in which it does not set the// ODD bit in the status word and control byte of received packets. We// work around this by assuming the bit is always set and tacking the// extra odd byte onto the packet anyway. Higher protocol levels never// believe the packet size reported by the driver and always use the// values in the protocol headers. So this workaround is quite safe.// In theory nobody should be using the RevA part now, but it appears// that some people still have some in their parts bins.#define LAN91CXX_RX_STATUS_IS_ODD(__cpd,__stat) \        (((__cpd)->c111_reva)?1:((__stat) & LAN91CXX_RX_STATUS_ODDFRM))#define LAN91CXX_CONTROLBYTE_IS_ODD(__cpd,__val) \        (((__cpd)->c111_reva)?1:((__val) & LAN91CXX_CONTROLBYTE_ODD))#else#define LAN91CXX_RX_STATUS_IS_ODD(__cpd,__stat) ((__stat) & LAN91CXX_RX_STATUS_ODDFRM)#define LAN91CXX_CONTROLBYTE_IS_ODD(__cpd,__val) ((__val) & LAN91CXX_CONTROLBYTE_ODD)#endif#ifndef CYGPKG_IO_ETH_DRIVERS_STAND_ALONEstatic cyg_interrupt lan91cxx_interrupt;static cyg_handle_t  lan91cxx_interrupt_handle;// This ISR is called when the ethernet interrupt occursstatic int lan91cxx_isr(cyg_vector_t vector, cyg_addrword_t data)             /* , HAL_SavedRegisters *regs */{    struct eth_drv_sc *sc = (struct eth_drv_sc *)data;    struct lan91cxx_priv_data *cpd =        (struct lan91cxx_priv_data *)sc->driver_private;    DEBUG_FUNCTION();    INCR_STAT( interrupts );    cyg_drv_interrupt_mask(cpd->interrupt);    cyg_drv_interrupt_acknowledge(cpd->interrupt);    return (CYG_ISR_HANDLED|CYG_ISR_CALL_DSR);  // Run the DSR}#endif// The deliver function (ex-DSR)  handles the ethernet [logical] processingstatic voidlan91cxx_deliver(struct eth_drv_sc *sc){    struct lan91cxx_priv_data *cpd =        (struct lan91cxx_priv_data *)sc->driver_private;    DEBUG_FUNCTION();    // Service the interrupt:    lan91cxx_poll(sc);    // Allow interrupts to happen again    cyg_drv_interrupt_unmask(cpd->interrupt);}static intlan91cxx_int_vector(struct eth_drv_sc *sc){    struct lan91cxx_priv_data *cpd =        (struct lan91cxx_priv_data *)sc->driver_private;    return (cpd->interrupt);}static bool smsc_lan91cxx_init(struct cyg_netdevtab_entry *tab){    struct eth_drv_sc *sc = (struct eth_drv_sc *)tab->device_instance;    struct lan91cxx_priv_data *cpd =        (struct lan91cxx_priv_data *)sc->driver_private;    unsigned short val;    int i;#if CYGINT_DEVS_ETH_SMSC_LAN91CXX_PCMCIA_MODE    unsigned char ecor, ecsr;#endif    cyg_bool esa_configured = false;    DEBUG_FUNCTION();    cpd->txbusy = cpd->within_send = 0;        #ifdef CYGNUM_DEVS_ETH_SMSC_LAN91CXX_SHIFT_ADDR    cpd->addrsh = CYGNUM_DEVS_ETH_SMSC_LAN91CXX_SHIFT_ADDR;#else    cpd->addrsh = 0;#endif#if CYGINT_DEVS_ETH_SMSC_LAN91CXX_PCMCIA_MODE    // If the chip is configured in PCMCIA mode, the internal    // registers mapped in the attribute memory should be    // initialized (i.e. to enable the I/O map)        ecor = get_att(sc, LAN91CXX_ECOR);        // pulse SRESET on ECOR    ecor |= LAN91CXX_ECOR_RESET;    put_att(sc, LAN91CXX_ECOR, ecor);        HAL_DELAY_US(1);        ecor &= ~LAN91CXX_ECOR_RESET;    put_att(sc, LAN91CXX_ECOR, ecor);    // then, enable I/O map    ecor |= LAN91CXX_ECOR_ENABLE;        put_att(sc, LAN91CXX_ECOR, ecor);    // verify the register contents    if (ecor != get_att(sc, LAN91CXX_ECOR))        db_printf("LAN91CXX - Cannot access PCMCIA attribute registers\n");	    ecsr = get_att(sc, LAN91CXX_ECSR);#ifdef CYGSEM_DEVS_ETH_SMSC_LAN91CXX_8_BIT#error "91CXX 8-bit mode not yet supported."    ecsr |= LAN91CXX_ECSR_IOIS8;#else    ecsr &= ~LAN91CXX_ECSR_IOIS8;#endif    put_att(sc, LAN91CXX_ECSR, ecsr);        #endif#ifndef CYGPKG_IO_ETH_DRIVERS_STAND_ALONE    // Initialize environment, setup interrupt handler    cyg_drv_interrupt_create(cpd->interrupt,                             CYGNUM_DEVS_ETH_SMSC_LAN91CXX_INT_PRIO,                             (cyg_addrword_t)sc, //  Data item passed to interrupt handler                             (cyg_ISR_t *)lan91cxx_isr,                             (cyg_DSR_t *)eth_drv_dsr, // The logical driver DSR                             &lan91cxx_interrupt_handle,                             &lan91cxx_interrupt);    cyg_drv_interrupt_attach(lan91cxx_interrupt_handle);#endif // !CYGPKG_IO_ETH_DRIVERS_STAND_ALONE    cyg_drv_interrupt_acknowledge(cpd->interrupt);#ifndef CYGPKG_IO_ETH_DRIVERS_STAND_ALONE    cyg_drv_interrupt_unmask(cpd->interrupt);#endif // !CYGPKG_IO_ETH_DRIVERS_STAND_ALONE        // probe chip by reading the signature in BS register    val = get_banksel(sc);#if DEBUG & 9    db_printf("LAN91CXX - supposed BankReg @ %x = %04x\n",                cpd->base+LAN91CXX_BS, val );#endif    CYG_ASSERT( 0x3300 == (0xff00 & val), "No 91Cxx signature" );    val = get_reg(sc, LAN91CXX_REVISION);#if DEBUG & 9    db_printf("LAN91CXX - type: %01x, rev: %01x\n",                (val>>4)&0xf, val & 0xf);#endif#ifdef LAN91CXX_IS_LAN91C111    // Set RevA flag for LAN91C111 so we can cope with the odd-bit bug.    cpd->c111_reva = (val == 0x3390);#endif        // The controller may provide a function used to set up the ESA    if (cpd->config_enaddr)        (*cpd->config_enaddr)(cpd);    // Reset chip    put_reg(sc, LAN91CXX_RCR, LAN91CXX_RCR_SOFT_RST);    put_reg(sc, LAN91CXX_RCR, 0);    val = get_reg(sc, LAN91CXX_EPH_STATUS);#ifndef LAN91CXX_IS_LAN91C111    // LINK_OK on 91C111 is just a general purpose input and may not    // have anything to do with the link.    if (!(val & LAN91CXX_STATUS_LINK_OK)) { db_printf("no link\n");        return false;  // Link not connected    }#endif#if DEBUG & 9    db_printf("LAN91CXX - status: %04x\n", val);#endif#if 0 < CYGINT_DEVS_ETH_SMSC_LAN91CXX_STATIC_ESA    // Use statically configured ESA from the private data#if DEBUG & 9    db_printf("LAN91CXX - static ESA: %02x:%02x:%02x:%02x:%02x:%02x\n",                cpd->enaddr[0],

⌨️ 快捷键说明

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