if_dp83816.c
来自「开放源码实时操作系统源码.」· C语言 代码 · 共 591 行 · 第 1/2 页
C
591 行
//==========================================================================
//
// dev/if_dp83816.c
//
// Ethernet device driver for NS DP83816 ethernet controller
//
//==========================================================================
//####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, 2004 Gary Thomas
// Copyright (C) 2004 eCosCentric Limited
//
// 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:
// Date: 2003-09-29
// Purpose:
// Description:
//
//####DESCRIPTIONEND####
//
//==========================================================================
#include <pkgconf/system.h>
#include <pkgconf/io_eth_drivers.h>
#include <cyg/infra/cyg_type.h>
#include <cyg/hal/hal_arch.h>
#include <cyg/hal/hal_endian.h>
#include <cyg/infra/diag.h>
#include <cyg/hal/drv_api.h>
#include <cyg/hal/hal_if.h>
#include <cyg/io/eth/eth_drv.h>
#include <cyg/io/eth/netdev.h>
#include <string.h> // memcpy
#include "dp83816.h"
#include CYGDAT_DEVS_ETH_NS_DP83816_INL
#if DEBUG & 1
int norecurse;
#endif
#ifdef CYGHWR_NS_DP83816_USE_EEPROM
static cyg_uint16 dp83816_eeprom_read(struct dp83816_priv_data *dp, int location);
#endif
#ifdef CYGINT_IO_ETH_INT_SUPPORT_REQUIRED
// This ISR is called when the ethernet interrupt occurs
static cyg_uint32
dp83816_isr(cyg_vector_t vector, cyg_addrword_t data)
{
struct eth_drv_sc *sc = (struct eth_drv_sc *)data;
dp83816_priv_data_t *dp = (dp83816_priv_data_t *)sc->driver_private;
DEBUG_FUNCTION();
cyg_drv_interrupt_mask(dp->interrupt);
cyg_drv_interrupt_acknowledge(dp->interrupt);
return (CYG_ISR_HANDLED|CYG_ISR_CALL_DSR); // Run the DSR
}
#endif // CYGINT_IO_ETH_INT_SUPPORT_REQUIRED
// The deliver function (ex-DSR) handles the ethernet [logical] processing
static void
dp83816_deliver(struct eth_drv_sc *sc)
{
#ifdef CYGINT_IO_ETH_INT_SUPPORT_REQUIRED
dp83816_priv_data_t *dp = (dp83816_priv_data_t *)sc->driver_private;
#endif
DEBUG_FUNCTION();
// Service the interrupt:
dp83816_poll(sc);
#ifdef CYGINT_IO_ETH_INT_SUPPORT_REQUIRED
// Allow interrupts to happen again
cyg_drv_interrupt_unmask(dp->interrupt);
#endif
}
static bool
dp83816_reset(dp83816_priv_data_t *dp)
{
unsigned char *bp;
dp83816_bd_t *bdp;
cyg_uint32 stat;
int i, timeout;
DP_OUT(dp->base, DP_CR, _CR_RST); // Reset device
timeout = 10000;
do {
DP_IN(dp->base, DP_CR, stat);
} while (((stat & _CR_RST) != 0) && (--timeout > 0));
if (timeout == 0) {
diag_printf("DP83816 - reset timed out! - stat: %x\n", stat);
return false;
}
// Rx ring
bdp = dp->rxnext = CYGARC_UNCACHED_ADDRESS(dp->rxd);
bp = dp->rxbuf;
for (i = 0; i < dp->rxnum; i++, bdp++) {
bdp->next = (dp83816_bd_t *)CYG_CPU_TO_LE32(CYGARC_PHYSICAL_ADDRESS(bdp+1));
bdp->stat = CYG_CPU_TO_LE32(BD_INTR | _DP83816_BUFSIZE); // Max buffer
bdp->buf = (unsigned char *)CYG_CPU_TO_LE32(CYGARC_PHYSICAL_ADDRESS(bp));
bp += _DP83816_BUFSIZE;
}
bdp--; bdp->next = (dp83816_bd_t *)CYG_CPU_TO_LE32(CYGARC_PHYSICAL_ADDRESS(dp->rxd));
DP_OUT(dp->base, DP_RXCFG, _RXCFG_MXDMA_128 | ((64/32)<<_RXCFG_DRTH_SHIFT));
DP_OUT(dp->base, DP_RXDP, CYGARC_PHYSICAL_ADDRESS(dp->rxd));
// Tx ring
bdp = dp->txfill = dp->txint = CYGARC_UNCACHED_ADDRESS(dp->txd);
bp = dp->txbuf;
for (i = 0; i < dp->txnum; i++, bdp++) {
bdp->next = (dp83816_bd_t *)CYG_CPU_TO_LE32(CYGARC_PHYSICAL_ADDRESS(bdp+1));
bdp->stat = 0; // Driver owns buffer for now
bdp->buf = (unsigned char *)CYG_CPU_TO_LE32(CYGARC_PHYSICAL_ADDRESS(bp));
bp += _DP83816_BUFSIZE;
}
bdp--; bdp->next = (dp83816_bd_t *)CYG_CPU_TO_LE32(CYGARC_PHYSICAL_ADDRESS(dp->txd));
DP_OUT(dp->base, DP_TXCFG, _TXCFG_ATP |
_TXCFG_MXDMA_128 |
/* _TXCFG_CSI | */
((256/32)<<_TXCFG_FLTH_SHIFT) |
((512/32)<<_TXCFG_DRTH_SHIFT));
DP_OUT(dp->base, DP_TXDP, CYGARC_PHYSICAL_ADDRESS(dp->txd));
dp->txbusy = 0;
// Fill in ESA
for (i = 0; i < 6; i+=2) {
DP_OUT(dp->base, DP_RFCR, i);
DP_OUT(dp->base, DP_RFDR, dp->enaddr[i] | (dp->enaddr[i+1]<<8));
}
// Setup up acceptance criteria
DP_OUT(dp->base, DP_RFCR, _RFCR_RFEN | _RFCR_AAB | _RFCR_APM);
// Set up interrupts
DP_IN(dp->base, DP_ISR, stat); // Clear any current interrupts
DP_OUT(dp->base, DP_IMR, 0x00000000); // Disable them all!
DP_OUT(dp->base, DP_IER, 0);
return true;
}
static bool
dp83816_init(struct cyg_netdevtab_entry *tab)
{
struct eth_drv_sc *sc = (struct eth_drv_sc *)tab->device_instance;
dp83816_priv_data_t *dp = (dp83816_priv_data_t *)sc->driver_private;
cyg_uint8 *base;
bool esa_ok = false;
unsigned char enaddr[6];
DEBUG_FUNCTION();
CYGHWR_NS_DP83816_PLF_INIT(dp);
base = dp->base;
if (!base) return false; // No device found
#ifdef CYGPKG_REDBOOT
#ifdef CYGSEM_REDBOOT_FLASH_CONFIG
esa_ok = flash_get_config(dp->esa_key, enaddr, CONFIG_ESA);
#endif
#elif defined (CONFIG_ESA)
esa_ok = CYGACC_CALL_IF_FLASH_CFG_OP(CYGNUM_CALL_IF_FLASH_CFG_GET,
dp->esa_key, enaddr, CONFIG_ESA);
#endif
// Get physical device address
// There are two different implementations due to parallel implementations.
// Both are included for backward compatibility, but
// the CYGHWR_DEVS_ETH_NS_DP83816_USE_EEPROM_ESA implementation is
// preferred simply because it is smaller.
#if defined(CYGHWR_DEVS_ETH_NS_DP83816_USE_EEPROM_ESA)
if (!esa_ok)
{
// Read the ESA from the PMATCH receive filter register, which
// will have been initialised from the EEPROM.
cyg_uint32 rfcrdat;
cyg_ucount8 i;
for (i = 0; i < 6; i+=2) {
DP_OUT(dp->base, DP_RFCR, i);
DP_IN(dp->base, DP_RFDR, rfcrdat );
enaddr[i] = rfcrdat & 0xff;
enaddr[i+1] = (rfcrdat>>8) & 0xff;
}
esa_ok = true;
}
#elif defined(CYGHWR_NS_DP83816_USE_EEPROM)
// This define (CYGHWR_NS_DP83816_USE_EEPROM) is deprecated.
{
cyg_uint16 t;
t = (dp83816_eeprom_read(dp, 0x0006) >> 15)
| (dp83816_eeprom_read(dp, 0x0007) << 1);
enaddr[0] = t & 0xFF;
enaddr[1] = t >> 8;
t = (dp83816_eeprom_read(dp, 0x0007) >> 15)
| (dp83816_eeprom_read(dp, 0x0008) << 1);
enaddr[2] = t & 0xFF;
enaddr[3] = t >> 8;
t = (dp83816_eeprom_read(dp, 0x0008) >> 15)
| (dp83816_eeprom_read(dp, 0x0009) << 1);
enaddr[4] = t & 0xFF;
enaddr[5] = t >> 8;
esa_ok = true;
}
#endif
if (esa_ok) {
memcpy(dp->enaddr, enaddr, sizeof(enaddr));
} else {
// Can't figure out ESA
diag_printf("DP83816 - Warning! ESA unknown\n");
}
// DEBUG_FUNCTION();
if (!dp83816_reset(dp)) return false;
#if DEBUG & 8
diag_printf("DP83816 - ESA: %02x:%02x:%02x:%02x:%02x:%02x\n",
dp->enaddr[0], dp->enaddr[1], dp->enaddr[2],
dp->enaddr[3], dp->enaddr[4], dp->enaddr[5] );
#endif
#ifdef CYGINT_IO_ETH_INT_SUPPORT_REQUIRED
cyg_drv_interrupt_create(
dp->interrupt,
0, // Priority - unused
(cyg_addrword_t)sc, // Data item passed to ISR & DSR
dp83816_isr, // ISR
eth_drv_dsr, // DSR
&dp->interrupt_handle, // handle to intr obj
&dp->interrupt_object ); // space for int obj
cyg_drv_interrupt_attach(dp->interrupt_handle);
cyg_drv_interrupt_unmask(dp->interrupt);
#elif defined(CYGPKG_REDBOOT)
cyg_drv_interrupt_unmask(dp->interrupt);
#endif
// Initialize upper level driver
(sc->funs->eth_drv->init)(sc, dp->enaddr);
return true;
}
static void
dp83816_stop(struct eth_drv_sc *sc)
{
dp83816_priv_data_t *dp = (dp83816_priv_data_t *)sc->driver_private;
DP_OUT(dp->base, DP_IMR, 0x00000000); // Disable interrupts
DP_OUT(dp->base, DP_IER, 0);
DP_OUT(dp->base, DP_CR, _CR_RXD | _CR_TXD);
}
//
// This function is called to "start up" the interface. It may be called
// multiple times, even when the hardware is already running. It will be
// called whenever something "hardware oriented" changes and should leave
// the hardware ready to send/receive packets.
//
static void
dp83816_start(struct eth_drv_sc *sc, unsigned char *enaddr, int flags)
{
dp83816_priv_data_t *dp = (dp83816_priv_data_t *)sc->driver_private;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?