if_dp83902a.c

来自「eCos操作系统源码」· C语言 代码 · 共 800 行 · 第 1/2 页

C
800
字号
//==========================================================================////      dev/if_dp83902a.c////      Ethernet device driver for NS DP83902a ethernet controller////==========================================================================//####ECOSGPLCOPYRIGHTBEGIN####// -------------------------------------------// This file is part of eCos, the Embedded Configurable Operating System.// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.//// 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):    gthomas// Contributors: gthomas, jskov, rsandifo// 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 <pkgconf/io_eth_drivers.h>#include <cyg/infra/cyg_type.h>#include <cyg/hal/hal_arch.h>#include <cyg/infra/diag.h>#include <cyg/hal/drv_api.h>#include <cyg/io/eth/eth_drv.h>#include <cyg/io/eth/netdev.h>#include <cyg/io/dp83902a.h>#define __WANT_DEVS#include CYGDAT_DEVS_ETH_NS_DP83902A_INL#undef __WANT_DEVS#ifdef CYGINT_IO_ETH_INT_SUPPORT_REQUIRED// This ISR is called when the ethernet interrupt occursstatic cyg_uint32dp83902a_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 voiddp83902a_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}#endif // CYGINT_IO_ETH_INT_SUPPORT_REQUIRED// The deliver function (ex-DSR)  handles the ethernet [logical] processingstatic voiddp83902a_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;    int i;    DEBUG_FUNCTION();    CYGHWR_NS_DP83902A_PLF_INIT(dp);    base = dp->base;    if (!base) return false;  // No device found    dp->tab = tab;    dp->cr_lock = 0;    CYGHWR_NS_DP83902A_PLF_RESET(dp);    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] );#ifdef CYGINT_IO_ETH_INT_SUPPORT_REQUIRED    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);#endif    // Initialize upper level driver    (sc->funs->eth_drv->init)(sc, dp->esa);    return true;}static voiddp83902a_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 voiddp83902a_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_buf_start); // Receive ring start page    DP_OUT(base, DP_BNDRY, dp->rx_buf_end-1); // Receive ring boundary    DP_OUT(base, DP_PSTOP, dp->rx_buf_end);   // Receive ring end page    dp->rx_next = dp->rx_buf_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 | DP_CR_STOP);  // Select page 1    DP_OUT(base, DP_P1_CURP, dp->rx_buf_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 intdp83902a_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 intdp83902a_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 voiddp83902a_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;#ifdef CYGHWR_NS_DP83902A_PLF_16BIT_DATA    // Make length even when using 16 bit transfers    if (pkt_len % 2) pkt_len++;#endif    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();#if DEBUG & 5    diag_printf("TX prep page %d len %d\n", start_page, pkt_len);#endif    DP_OUT(base, DP_ISR, DP_ISR_RDC);  // Clear end of DMA    {        // Dummy read. The manual sez something slightly different,        // but the code is extended a bit to do what Hitachi's monitor        // does (i.e., also read data).        cyg_uint16 tmp;#ifdef CYGHWR_NS_DP83902A_PLF_16BIT_DATA        int len = 2;#else        int len = 1;#endif        DP_OUT(base, DP_RSAL, 0x100-len);        DP_OUT(base, DP_RSAH, (start_page-1) & 0xff);        DP_OUT(base, DP_RBCL, len);        DP_OUT(base, DP_RBCH, 0);        DP_OUT(base, DP_CR, DP_CR_PAGE0 | DP_CR_RDMA | DP_CR_START);        DP_IN_DATA(dp->data, tmp);    }#ifdef CYGHWR_NS_DP83902A_PLF_BROKEN_TX_DMA    // Stall for a bit before continuing to work around random data    // corruption problems on some platforms.    CYGACC_CALL_IF_DELAY_US(1);#endif    // Send data to device buffer(s)    DP_OUT(base, DP_RSAL, 0);    DP_OUT(base, DP_RSAH, start_page);    DP_OUT(base, DP_RBCL, pkt_len & 0xFF);    DP_OUT(base, DP_RBCH, pkt_len >> 8);    DP_OUT(base, DP_CR, DP_CR_WDMA | DP_CR_START);

⌨️ 快捷键说明

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