if_cs8900a.c

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

C
684
字号
//==========================================================================////      dev/if_cs8900a.c////      Device driver for Cirrus Logic CS8900A 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// Date:         2001-11-02// Purpose:      // Description:  Driver for CS8900 ethernet controller//// Note:         Platform can define CYGSEM_DEVS_ETH_CL_CS8900A_NOINTS//               to get a timer thread polling instead of interupt based//               operation.//// Note:         Driver will need some changes to support multiple instances////####DESCRIPTIONEND####////==========================================================================#include <pkgconf/system.h>#ifdef CYGPKG_KERNEL#include <cyg/kernel/kapi.h>#endif#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_endian.h>#include <cyg/infra/diag.h>#include <cyg/hal/drv_api.h>#undef __ECOS#define __ECOS#include <cyg/io/eth/eth_drv.h>#include <cyg/io/eth/netdev.h>#include <cyg/io/cs8900.h>#define __WANT_DEVS#include CYGDAT_DEVS_ETH_CL_CS8900A_INL#undef __WANT_DEVS// NOINTS operation only relevant when the NET package is loaded#if !defined(CYGPKG_NET) || !defined(CYGPKG_KERNEL)# undef CYGSEM_DEVS_ETH_CL_CS8900A_NOINTS#endif#ifdef CYGSEM_DEVS_ETH_CL_CS8900A_NOINTS#define STACK_SIZE CYGNUM_HAL_STACK_SIZE_MINIMUMstatic char cs8900a_fake_int_stack[STACK_SIZE];static cyg_thread cs8900a_fake_int_thread_data;static cyg_handle_t cs8900a_fake_int_thread_handle;static void cs8900a_fake_int(cyg_addrword_t);#endif#ifdef CYGDBG_IO_ETH_DRIVERS_DEBUGextern int cyg_io_eth_net_debug;#endifstatic void cs8900a_poll(struct eth_drv_sc *sc);#ifdef CYGINT_IO_ETH_INT_SUPPORT_REQUIRED// This ISR is called when the ethernet interrupt occursstatic intcs8900a_isr(cyg_vector_t vector, cyg_addrword_t data, HAL_SavedRegisters *regs){    cs8900a_priv_data_t* cpd = (cs8900a_priv_data_t *)data;    cyg_drv_interrupt_mask(cpd->interrupt);    cyg_drv_interrupt_acknowledge(cpd->interrupt);    return (CYG_ISR_HANDLED|CYG_ISR_CALL_DSR);  // Run the DSR}static voidcs8900a_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 CYGINT_IO_ETH_INT_SUPPORT_REQUIRED    cs8900a_priv_data_t* cpd = (cs8900a_priv_data_t *)data;    struct cyg_netdevtab_entry *ndp = (struct cyg_netdevtab_entry *)(cpd->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 CS8900A ethernet DSR is compiled.  Is this what you want?# endif#endif}#endif// The deliver function (ex-DSR)  handles the ethernet [logical] processingstatic voidcs8900a_deliver(struct eth_drv_sc *sc){    cs8900a_poll(sc);#ifdef CYGINT_IO_ETH_INT_SUPPORT_REQUIRED    {        cs8900a_priv_data_t *cpd = (cs8900a_priv_data_t *)sc->driver_private;        // Allow interrupts to happen again        cyg_drv_interrupt_unmask(cpd->interrupt);    }#endif}static intcs8900a_int_vector(struct eth_drv_sc *sc){    cs8900a_priv_data_t *cpd = (cs8900a_priv_data_t *)sc->driver_private;    return (cpd->interrupt);}static bool cs8900a_init(struct cyg_netdevtab_entry *tab){    struct eth_drv_sc *sc = (struct eth_drv_sc *)tab->device_instance;    cs8900a_priv_data_t *cpd = (cs8900a_priv_data_t *)sc->driver_private;    cyg_addrword_t base = cpd->base;    cyg_uint16 chip_type, chip_rev, chip_status;    cyg_uint16 i;    long timeout = 500000;    cyg_bool esa_configured = false;        cpd->tab = tab;    CYGHWR_CL_CS8900A_PLF_INIT(cpd);#ifdef CYGINT_IO_ETH_INT_SUPPORT_REQUIRED    // Initialize environment, setup interrupt handler    cyg_drv_interrupt_create(cpd->interrupt,                             0, // Priority - what goes here?                             (cyg_addrword_t)cpd, //  Data item passed to interrupt handler                             (cyg_ISR_t *)cs8900a_isr,                             (cyg_DSR_t *)cs8900a_dsr,                             &cpd->interrupt_handle,                             &cpd->interrupt_object);    cyg_drv_interrupt_attach(cpd->interrupt_handle);    cyg_drv_interrupt_acknowledge(cpd->interrupt);    cyg_drv_interrupt_unmask(cpd->interrupt);#ifdef CYGSEM_DEVS_ETH_CL_CS8900A_NOINTS    cyg_thread_create(1,                 // Priority                      cs8900a_fake_int,   // entry                      (cyg_addrword_t)sc, // entry parameter                      "CS8900 int",      // Name                      &cs8900a_fake_int_stack[0],         // Stack                      STACK_SIZE,        // Size                      &cs8900a_fake_int_thread_handle,    // Handle                      &cs8900a_fake_int_thread_data       // Thread data structure            );    cyg_thread_resume(cs8900a_fake_int_thread_handle);  // Start it#endif#endif    // Read controller ID - the first is a dummy read, since (on some    // platforms) the first access to the controller seems to skip the    // MSB 8 bits.    get_reg(base, PP_ChipID);    chip_type = get_reg(base, PP_ChipID);    chip_rev = get_reg(base, PP_ChipRev);#if DEBUG & 8    diag_printf("CS8900A[%p] - type: 0x%04x, rev: 0x%04x\n", base, chip_type, chip_rev);#endif    if (chip_type != PP_ChipID_CL) {#if DEBUG & 8        diag_printf("CS8900 - invalid type (0x%04x), must be 0x630e\n", chip_type);#endif        return false;    }    CYGHWR_CL_CS8900A_PLF_RESET(base);    put_reg(base, PP_SelfCtl, PP_SelfCtl_Reset);  // Reset chip    CYGHWR_CL_CS8900A_PLF_POST_RESET(base);        while ((get_reg(base, PP_SelfStat) & PP_SelfStat_InitD) == 0) {        if (--timeout <= 0) {#if DEBUG & 8            diag_printf("CS8900 didn't reset - abort!\n");#endif            return false;        }    }    chip_status = get_reg(base, PP_SelfStat);#if DEBUG & 8    diag_printf("CS8900 - status: 0x%04x (%sEEPROM present)\n", chip_status,                chip_status & PP_SelfStat_EEPROM ? "" : "no ");#endif    // Disable reception whilst finding the ESA    put_reg(base, PP_LineCTL, 0 );    // Find ESA - check possible sources in sequence and stop when    // one provides the ESA:    //   RedBoot option (via provide_esa)    //   Compile-time configuration    //   EEPROM    //   <fail configuration of device>    if (NULL != cpd->provide_esa) {        esa_configured = cpd->provide_esa(cpd);# if DEBUG & 8        if (esa_configured)            diag_printf("Got ESA from RedBoot option\n");# endif    }    if (!esa_configured && cpd->hardwired_esa) {        // ESA is already set in cpd->esa[]        esa_configured = true;    }    if (!esa_configured && (chip_status & PP_SelfStat_EEPROM)) {        // Get ESA from EEPROM - via the PP_IA registers        cyg_uint16 esa_word;        for (i = 0;  i < sizeof(cpd->esa);  i += 2) {#ifndef CYGIMP_DEVS_ETH_CL_CS8900A_DATABUS_BYTE_SWAPPED            esa_word = get_reg(base, PP_IA+i);            cpd->esa[i] = (esa_word & 0xFF);            cpd->esa[i+1] = (esa_word >> 8) & 0xFF;#else            esa_word = get_reg(base, PP_IA+CYG_SWAP16(i));            cpd->esa[i+1] = (esa_word & 0xFF);            cpd->esa[i] = (esa_word >> 8) & 0xFF;#endif        }        esa_configured = true;    }    if (!esa_configured) {# if DEBUG & 8        diag_printf("CS8900 - no EEPROM, static ESA or RedBoot config option.\n");# endif        return false;    }    // Tell the chip what ESA to use    for (i = 0;  i < sizeof(cpd->esa);  i += 2) {#ifndef CYGIMP_DEVS_ETH_CL_CS8900A_DATABUS_BYTE_SWAPPED        put_reg(base, PP_IA+i, cpd->esa[i] | (cpd->esa[i+1] << 8));#else        put_reg(base, PP_IA+CYG_SWAP16(i), cpd->esa[i+1] | (cpd->esa[i] << 8));#endif    }    // Set logical address mask    for (i = 0;  i < 8;  i += 2) {#ifndef CYGIMP_DEVS_ETH_CL_CS8900A_DATABUS_BYTE_SWAPPED        put_reg(base, PP_LAF+i, 0xFFFF);#else        put_reg(base, PP_LAF+CYG_SWAP16(i), 0xFFFF);#endif    }# if DEBUG & 8    diag_printf("ESA %02x:%02x:%02x:%02x:%02x:%02x\n",                cpd->esa[0], cpd->esa[1], cpd->esa[2],                cpd->esa[3], cpd->esa[4], cpd->esa[5]);# endif    // Initialize upper level driver    (sc->funs->eth_drv->init)(sc, cpd->esa);    return true;}static voidcs8900a_stop(struct eth_drv_sc *sc){    cs8900a_priv_data_t *cpd = (cs8900a_priv_data_t *)sc->driver_private;    cyg_addrword_t base = cpd->base;    put_reg(base, PP_LineCTL, 0);}// 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 voidcs8900a_start(struct eth_drv_sc *sc, cyg_uint8 *esa, int flags){    cyg_uint16 stat;    cs8900a_priv_data_t *cpd = (cs8900a_priv_data_t *)sc->driver_private;    cyg_addrword_t base = cpd->base;    put_reg(base, PP_BusCtl, PP_BusCtl_MemoryE);  // Disable interrupts, memory mode    put_reg(base, PP_IntReg, PP_IntReg_IRQ0);  // Only possibility    put_reg(base, PP_RxCFG, PP_RxCFG_RxOK | PP_RxCFG_CRC |                       PP_RxCFG_RUNT | PP_RxCFG_EXTRA);    cpd->rxmode = PP_RxCTL_RxOK | PP_RxCTL_Broadcast | PP_RxCTL_IA;    put_reg(base, PP_RxCTL, cpd->rxmode);    put_reg(base, PP_TxCFG, PP_TxCFG_TxOK | PP_TxCFG_Collision |                       PP_TxCFG_CRS | PP_TxCFG_SQE | PP_TxCFG_Late |                       PP_TxCFG_Jabber | PP_TxCFG_16Collisions);

⌨️ 快捷键说明

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