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 + -
显示快捷键?