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

📄 if_dp83902a.c

📁 基于ecos的redboot
💻 C
📖 第 1 页 / 共 2 页
字号:
//==========================================================================
//
//      dev/if_dp83902a.c
//
//      Ethernet device driver for NS DP83902a ethernet controller
//
//==========================================================================
//####COPYRIGHTBEGIN####
//                                                                          
// -------------------------------------------                              
// The contents of this file are subject to the Red Hat eCos Public License 
// Version 1.1 (the "License"); you may not use this file except in         
// compliance with the License.  You may obtain a copy of the License at    
// http://www.redhat.com/                                                   
//                                                                          
// Software distributed under the License is distributed on an "AS IS"      
// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.  See the 
// License for the specific language governing rights and limitations under 
// the License.                                                             
//                                                                          
// The Original Code is eCos - Embedded Configurable Operating System,      
// released September 30, 1998.                                             
//                                                                          
// The Initial Developer of the Original Code is Red Hat.                   
// Portions created by Red Hat are                                          
// Copyright (C) 1998, 1999, 2000, 2001 Red Hat, Inc.
// All Rights Reserved.                                                     
// -------------------------------------------                              
//                                                                          
//####COPYRIGHTEND####
//####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):    gthomas
// Contributors: gthomas, jskov
// Date:         2001-06-13
// Purpose:      
// Description:
//
// FIXME:        Will fail if pinged with large packets (1520 bytes)
//               Add promisc config
//               Add SNMP
//
//####DESCRIPTIONEND####
//
//==========================================================================

#include <pkgconf/system.h>
#include <cyg/infra/cyg_type.h>
#include <cyg/hal/hal_arch.h>
#include <cyg/infra/diag.h>
#include <cyg/hal/drv_api.h>
#define __ECOS
#include <eth_drv.h>
#include <netdev.h>

#ifdef CYGPKG_NET
#include <pkgconf/net.h>
#include <pkgconf/io_eth_drivers.h>
#else
#include <cyg/hal/hal_if.h>
#endif

#include <cyg/io/dp83902a.h>

#define __WANT_DEVS
#include CYGDAT_DEVS_ETH_NS_DP83902A_INL
#undef __WANT_DEVS

// This ISR is called when the ethernet interrupt occurs
static cyg_uint32
dp83902a_isr(cyg_vector_t vector, cyg_addrword_t data)
{
    dp83902a_priv_data_t *dp = (dp83902a_priv_data_t *)data;

    DEBUG_FUNCTION();
//    INCR_STAT( interrupts );

    cyg_drv_interrupt_mask(dp->interrupt);
    cyg_drv_interrupt_acknowledge(dp->interrupt);
    return (CYG_ISR_HANDLED|CYG_ISR_CALL_DSR);  // Run the DSR
}

static void
dp83902a_dsr(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data)
{
    // This conditioning out is necessary because of explicit calls to this
    // DSR - which would not ever be called in the case of a polled mode
    // usage ie. in RedBoot.
#ifdef CYGPKG_IO_ETH_DRIVERS_NET
    dp83902a_priv_data_t* dp = (dp83902a_priv_data_t *)data;
    struct cyg_netdevtab_entry *ndp = (struct cyg_netdevtab_entry *)(dp->tab);
    struct eth_drv_sc *sc = (struct eth_drv_sc *)(ndp->device_instance);

    DEBUG_FUNCTION();

    // but here, it must be a *sc:
    eth_drv_dsr( vector, count, (cyg_addrword_t)sc );
#else
# ifndef CYGPKG_REDBOOT
#  error Empty DP83902A ethernet DSR is compiled.  Is this what you want?
# endif
#endif
}


// The deliver function (ex-DSR)  handles the ethernet [logical] processing
static void
dp83902a_deliver(struct eth_drv_sc *sc)
{
    dp83902a_priv_data_t *dp = (dp83902a_priv_data_t *)sc->driver_private;

    DEBUG_FUNCTION();

    // Service the interrupt:
    dp83902a_poll(sc);
    // Allow interrupts to happen again
    cyg_drv_interrupt_unmask(dp->interrupt);
}

static bool 
dp83902a_init(struct cyg_netdevtab_entry *tab)
{
    struct eth_drv_sc *sc = (struct eth_drv_sc *)tab->device_instance;
    dp83902a_priv_data_t *dp = (dp83902a_priv_data_t *)sc->driver_private;
    cyg_uint8* base = dp->base;
    int i;

    DEBUG_FUNCTION();

    dp->tab = tab;
    dp->cr_lock = 0;

    CYGHWR_NS_DP83902A_PLF_RESET(base);

    DEBUG_LINE();

    // Prepare ESA
    DP_OUT(base, DP_CR, DP_CR_NODMA | DP_CR_PAGE1);  // Select page 1
    if (dp->hardwired_esa) {
        // Force the NIC to use the specified ESA
        for (i = 0; i < 6; i++)
            DP_OUT(base, DP_P1_PAR0+i, dp->esa[i]);
    } else {
        // Use the address from the serial EEPROM
        for (i = 0; i < 6; i++)
            DP_IN(base, DP_P1_PAR0+i, dp->esa[i]);
    }
    DP_OUT(base, DP_CR, DP_CR_NODMA | DP_CR_PAGE0);  // Select page 0

    diag_printf("DP83902A - %s ESA: %02x:%02x:%02x:%02x:%02x:%02x\n",
                (dp->hardwired_esa) ? "static" : "eeprom",
                dp->esa[0],
                dp->esa[1],
                dp->esa[2],
                dp->esa[3],
                dp->esa[4],
                dp->esa[5] );

    cyg_drv_interrupt_create(
        dp->interrupt,
        0,                  // Priority - unused
        (cyg_addrword_t)dp,// Data item passed to ISR & DSR
        dp83902a_isr,          // ISR
        dp83902a_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);

    // Initialize upper level driver
    (sc->funs->eth_drv->init)(sc, dp->esa);

    return true;
}

static void
dp83902a_stop(struct eth_drv_sc *sc)
{
    dp83902a_priv_data_t *dp = (dp83902a_priv_data_t *)sc->driver_private;
    cyg_uint8 *base = dp->base;

    DEBUG_FUNCTION();

    CR_UP();
    DP_OUT(base, DP_CR, DP_CR_PAGE0 | DP_CR_NODMA | DP_CR_STOP);  // Brutal
    DP_OUT(base, DP_ISR, 0xFF);               // Clear any pending interrupts
    DP_OUT(base, DP_IMR, 0x00);               // Disable all interrupts
    CR_DOWN();

    dp->running = false;
}

//
// 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
dp83902a_start(struct eth_drv_sc *sc, unsigned char *enaddr, int flags)
{
    dp83902a_priv_data_t *dp = (dp83902a_priv_data_t *)sc->driver_private;
    cyg_uint8 *base = dp->base;
    int i;

    DEBUG_FUNCTION();

    CR_UP();
    DP_OUT(base, DP_CR, DP_CR_PAGE0 | DP_CR_NODMA | DP_CR_STOP); // Brutal
    DP_OUT(base, DP_DCR, DP_DCR_INIT);
    DP_OUT(base, DP_RBCH, 0);                 // Remote byte count
    DP_OUT(base, DP_RBCL, 0);
    DP_OUT(base, DP_RCR, DP_RCR_MON);     // Accept no packets
    DP_OUT(base, DP_TCR, DP_TCR_LOCAL);   // Transmitter [virtually] off
    DP_OUT(base, DP_TPSR, DP_TX_BUF1);    // Transmitter start page
    dp->tx1 = dp->tx2 = 0;
    dp->tx_next = DP_TX_BUF1;
    dp->tx_started = false;
    DP_OUT(base, DP_PSTART, DP_RX_START); // Receive ring start page
    DP_OUT(base, DP_BNDRY, DP_RX_STOP-1); // Receive ring boundary
    DP_OUT(base, DP_PSTOP, DP_RX_STOP);   // Receive ring end page
    dp->rx_next = DP_RX_START-1;
    DP_OUT(base, DP_ISR, 0xFF);               // Clear any pending interrupts
    DP_OUT(base, DP_IMR, DP_IMR_All);     // Enable all interrupts
    DP_OUT(base, DP_CR, DP_CR_NODMA | DP_CR_PAGE1);  // Select page 1
    DP_OUT(base, DP_P1_CURP, DP_RX_START);   // Current page - next free page for Rx
    for (i = 0;  i < ETHER_ADDR_LEN;  i++) {
        DP_OUT(base, DP_P1_PAR0+i, enaddr[i]);
    }
    // Enable and start device
    DP_OUT(base, DP_CR, DP_CR_PAGE0 | DP_CR_NODMA | DP_CR_START);  
    DP_OUT(base, DP_TCR, DP_TCR_NORMAL); // Normal transmit operations
    DP_OUT(base, DP_RCR, DP_RCR_AB);  // Accept broadcast, no errors, no multicast
    dp->running = true;
    CR_DOWN();
}

//
// This routine is called to perform special "control" opertions
//
static int
dp83902a_control(struct eth_drv_sc *sc, unsigned long key,
               void *data, int data_len)
{
    switch (key) {
    case ETH_DRV_SET_MAC_ADDRESS:
        return 0;
        break;
    default:
        return 1;
        break;
    }
}

//
// This routine is called to see if it is possible to send another packet.
// It will return non-zero if a transmit is possible, zero otherwise.
//
static int
dp83902a_can_send(struct eth_drv_sc *sc)
{
    dp83902a_priv_data_t *dp = (dp83902a_priv_data_t *)sc->driver_private;

    DEBUG_FUNCTION();

    return ((dp->tx1 == 0) || (dp->tx2 == 0));
}

//
// This routine is called to start the transmitter.  It is split out from the
// data handling routine so it may be called either when data becomes first 
// available or when an Tx interrupt occurs
//

static void
dp83902a_start_xmit(struct eth_drv_sc *sc, int start_page, int len)
{    
    dp83902a_priv_data_t *dp = (dp83902a_priv_data_t *)sc->driver_private;
    cyg_uint8 *base = dp->base;

    DEBUG_FUNCTION();

#if DEBUG & 1
    diag_printf("Tx pkt %d len %d\n", start_page, len);
    if (dp->tx_started)
        diag_printf("TX already started?!?\n");
#endif

    CR_UP();
    DP_OUT(base, DP_ISR, (DP_ISR_TxP | DP_ISR_TxE));
    DP_OUT(base, DP_CR, DP_CR_PAGE0 | DP_CR_NODMA | DP_CR_START);
    DP_OUT(base, DP_TBCL, len & 0xFF);
    DP_OUT(base, DP_TBCH, len >> 8);
    DP_OUT(base, DP_TPSR, start_page);
    DP_OUT(base, DP_CR, DP_CR_NODMA | DP_CR_TXPKT | DP_CR_START);

    CR_DOWN();
    dp->tx_started = true;
}

//
// This routine is called to send data to the hardware.  It is known a-priori
// that there is free buffer space (dp->tx_next).
//
static void 
dp83902a_send(struct eth_drv_sc *sc, struct eth_drv_sg *sg_list, int sg_len, 
            int total_len, unsigned long key)
{
    struct dp83902a_priv_data *dp = (struct dp83902a_priv_data *)sc->driver_private;
    cyg_uint8 *base = dp->base;
    int i, len, start_page, pkt_len;
    unsigned char *data;
    cyg_uint8 isr;
#if DEBUG & 4
    int dx;
#endif

    DEBUG_FUNCTION();

    pkt_len = total_len;
    if (pkt_len < IEEE_8023_MIN_FRAME) pkt_len = IEEE_8023_MIN_FRAME;
    start_page = dp->tx_next;
    if (dp->tx_next == DP_TX_BUF1) {
        dp->tx1 = start_page;
        dp->tx1_len = pkt_len;
        dp->tx1_key = key;
        dp->tx_next = DP_TX_BUF2;
    } else {
        dp->tx2 = start_page;
        dp->tx2_len = pkt_len;
        dp->tx2_key = key;
        dp->tx_next = DP_TX_BUF1;
    }
    CR_UP();

⌨️ 快捷键说明

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