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