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

📄 if_lancepci.c

📁 eCos操作系统源码
💻 C
📖 第 1 页 / 共 3 页
字号:
//==========================================================================////      dev/if_lancepci.c////      Ethernet device driver for AMD PCI Lance (for instance vmWare VLANCE)//      compatible controllers////==========================================================================//####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):    jskov, based on lan91cxx driver by hmt & jskov, iz// Contributors: gthomas, jskov, hmt, iz// Date:         2002-07-17, 2003-01-26// Purpose:// Description:  hardware driver for AMD Lance PCI (and possibly PCnet)//               and wmWare VLANCE ethernet// Notes:        The controller is used in its 16bit mode. That means that//               all addresses are 24bit only - and that all controller//               accessed memory must be within the same 16MB region//               (starting at 0 on older controllers).////               The KEEP_STATISTICS code is not implemented yet. Look//               for FIXME macro.////####DESCRIPTIONEND####////==========================================================================//#####VMWAREDESCRIPTIONBEGIN####//// Notes:        The vmWare VLACNCE virtual controller does not seem to do//               anything about SUSPEND  and seems it must be reinitialized after//               every STOP. In addition it lacks some registers.////		 Sometimes, the driver must wait to let Vmware get a tick, to//		 process the chip initialization and control functions!!!////		 That's the reason for not patching the PCnet driver//		 but cloning a special one from it.//////####VMWAREDESCRIPTIONEND####//==========================================================================#include <pkgconf/system.h>#include <pkgconf/devs_eth_amd_lancepci.h>#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/infra/cyg_ass.h>#include <cyg/infra/diag.h>#include <cyg/hal/drv_api.h>#include <cyg/hal/hal_if.h>             // delays#include <string.h>#include <cyg/io/eth/netdev.h>#include <cyg/io/eth/eth_drv.h>#ifdef CYGPKG_NET#include <pkgconf/net.h>#include <cyg/kernel/kapi.h>#include <net/if.h>  			// Needed for struct ifnet#include <pkgconf/io_eth_drivers.h>#endif#include CYGHWR_MEMORY_LAYOUT_H#ifdef CYGPKG_IO_PCI#include <cyg/io/pci.h>#else#error "Need PCI package here"#endif#define FIXME 0#define _BUF_SIZE 1544#ifdef CYGPKG_INFRA_DEBUG// Then we log, OOI, the number of times we get a bad packet number// from the tx done fifo.int lancepci_txfifo_good = 0;int lancepci_txfifo_bad = 0;#endif#include "amd_lance.h"#define __WANT_DEVS#include CYGDAT_DEVS_ETH_AMD_LANCEPCI_INL#undef  __WANT_DEVS//#define DEBUG 0xff#if defined(CYGPKG_REDBOOT)static void db_printf( char *fmt, ... ){    extern int start_console(void);    extern void end_console(int);    va_list a;    int old_console;    va_start( a, fmt );    old_console = start_console();    diag_vprintf( fmt, a );    end_console(old_console);    va_end( a );}#else#define db_printf diag_printf#endifstatic struct eth_drv_sc *oursc;	//a dummy sc pointerstatic void lancepci_poll(struct eth_drv_sc *sc);// This ISR is called when the ethernet interrupt occursstatic cyg_uint32lancepci_isr(cyg_vector_t vector, cyg_addrword_t data){    struct lancepci_priv_data *cpd = (struct lancepci_priv_data *)data;    DEBUG_FUNCTION();    INCR_STAT( interrupts );    cpd->event = get_reg(oursc, LANCE_CSR_CSCR);    if (cpd->event & LANCE_CSR_CSCR_TINT)        cpd->txbusyh=0;				// take care of HW txbusy flag    cyg_drv_interrupt_mask(cpd->interrupt);    cyg_drv_interrupt_acknowledge(cpd->interrupt);    return (CYG_ISR_HANDLED|CYG_ISR_CALL_DSR);  // Run the DSR}static voidlancepci_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    struct lancepci_priv_data* cpd = (struct lancepci_priv_data *)data;    struct cyg_netdevtab_entry *ndp = (struct cyg_netdevtab_entry *)(cpd->ndp);    struct eth_drv_sc *sc = (struct eth_drv_sc *)(ndp->device_instance);    // but here, it must be a *sc:    eth_drv_dsr( vector, count, (cyg_addrword_t)sc );#else# ifndef CYGPKG_REDBOOT#  error Empty lancepci ethernet DSR is compiled.  Is this what you want?# endif#endif}// The deliver function (ex-DSR)  handles the ethernet [logical] processingstatic voidlancepci_deliver(struct eth_drv_sc *sc){    struct lancepci_priv_data *cpd =        (struct lancepci_priv_data *)sc->driver_private;    DEBUG_FUNCTION();    // Service the interrupt:    lancepci_poll(sc);    // Allow interrupts to happen again    cyg_drv_interrupt_unmask(cpd->interrupt);}static intlancepci_int_vector(struct eth_drv_sc *sc){    struct lancepci_priv_data *cpd =        (struct lancepci_priv_data *)sc->driver_private;    return (cpd->interrupt);}// ------------------------------------------------------------------------// Memory management//// Simply carve off from the front of the PCI mapped window into real memorystatic cyg_uint32 lancepci_heap_size;static cyg_uint8 *lancepci_heap_base;static cyg_uint8 *lancepci_heap_free;static void*pciwindow_mem_alloc(int size){    void *p_memory;    int _size = size;    CYG_ASSERT(        (CYGHWR_AMD_LANCEPCI_PCI_MEM_MAP_BASE <= (int)lancepci_heap_free)        &&        ((CYGHWR_AMD_LANCEPCI_PCI_MEM_MAP_BASE +          CYGHWR_AMD_LANCEPCI_PCI_MEM_MAP_SIZE) > (int)lancepci_heap_free)        &&        (0 < lancepci_heap_size)        &&        (CYGHWR_AMD_LANCEPCI_PCI_MEM_MAP_SIZE >= lancepci_heap_size)        &&        (CYGHWR_AMD_LANCEPCI_PCI_MEM_MAP_BASE == (int)lancepci_heap_base),        "Heap variables corrupted" );    p_memory = (void *)0;    size = (size + 3) & ~3;    if ( (lancepci_heap_free+size) < (lancepci_heap_base+lancepci_heap_size) ) {        cyg_uint32 *p;        p_memory = (void *)lancepci_heap_free;        lancepci_heap_free += size;        for ( p = (cyg_uint32 *)p_memory; _size > 0; _size -= 4 )            *p++ = 0;    }#if DEBUG & 9    db_printf("Allocated %d bytes at 0x%08x\n", size, p_memory);#endif    return p_memory;}static cyg_pci_match_func find_lancepci_match_func;static cyg_boolfind_lancepci_match_func( cyg_uint16 v, cyg_uint16 d, cyg_uint32 c, void *p ){#if DEBUG & 9    db_printf("PCI match vendor 0x%04x device 0x%04x\n", v, d);#endif    return (0x1022 == v) && (0x2000 == d);}static intpci_init_find_lancepci( void ){    cyg_pci_device_id devid;    cyg_pci_device dev_info;    cyg_uint16 cmd;    int device_index;    int found_devices = 0;    DEBUG_FUNCTION();#ifdef CYGARC_UNCACHED_ADDRESS    CYG_ASSERT( CYGARC_UNCACHED_ADDRESS((CYG_ADDRWORD)CYGMEM_SECTION_pci_window) ==                CYGHWR_AMD_LANCEPCI_PCI_MEM_MAP_BASE,      "PCI window configured does not match PCI memory section base" );#else    CYG_ASSERT( (CYG_ADDRWORD)CYGMEM_SECTION_pci_window ==                CYGHWR_AMD_LANCEPCI_PCI_MEM_MAP_BASE,      "PCI window configured does not match PCI memory section base" );#endif    CYG_ASSERT( CYGMEM_SECTION_pci_window_SIZE ==                CYGHWR_AMD_LANCEPCI_PCI_MEM_MAP_SIZE,        "PCI window configured does not match PCI memory section size" );    if (#ifdef CYGARC_UNCACHED_ADDRESS         CYGARC_UNCACHED_ADDRESS((CYG_ADDRWORD)CYGMEM_SECTION_pci_window) !=#else         (CYG_ADDRWORD)CYGMEM_SECTION_pci_window !=#endif         (CYG_ADDRWORD)CYGHWR_AMD_LANCEPCI_PCI_MEM_MAP_BASE         ||         CYGMEM_SECTION_pci_window_SIZE !=         CYGHWR_AMD_LANCEPCI_PCI_MEM_MAP_SIZE ) {#if DEBUG & 8        db_printf("pci_init_find_lancepci(): PCI window misconfigured\n");#endif        return 0;    }    // First initialize the heap in PCI window'd memory    lancepci_heap_size = CYGHWR_AMD_LANCEPCI_PCI_MEM_MAP_SIZE;    lancepci_heap_base = (cyg_uint8 *)CYGHWR_AMD_LANCEPCI_PCI_MEM_MAP_BASE;    lancepci_heap_free = lancepci_heap_base;#if DEBUG & 9    db_printf("pcimem : 0x%08x size: 0x%08x\n", lancepci_heap_base, lancepci_heap_size);#endif    cyg_pci_init();#if DEBUG & 8    db_printf("Finished cyg_pci_init();\n");#endif    devid = CYG_PCI_NULL_DEVID;    for (device_index = 0;         device_index < CYGNUM_DEVS_ETH_AMD_LANCEPCI_DEV_COUNT;         device_index++) {        struct lancepci_priv_data* cpd = lancepci_priv_array[device_index];        cpd->index = device_index;        // See above for find_lancepci_match_func - it selects any of several        // variants.  This is necessary in case we have multiple mixed-type        // devices on one board in arbitrary orders.        if (cyg_pci_find_matching( &find_lancepci_match_func, NULL, &devid )) {#if DEBUG & 8            db_printf("eth%d = lancepci\n", device_index);#endif            cyg_pci_get_device_info(devid, &dev_info);            cpd->interrupt_handle = 0; // Flag not attached.            if (cyg_pci_translate_interrupt(&dev_info, &cpd->interrupt)) {#if DEBUG & 8                db_printf(" Wired to HAL vector %d\n", cpd->interrupt);#endif                cyg_drv_interrupt_create(                    cpd->interrupt,                    1,                  // Priority - unused                    (cyg_addrword_t)cpd,// Data item passed to ISR & DSR                    lancepci_isr,          // ISR                    lancepci_dsr,          // DSR                    &cpd->interrupt_handle, // handle to intr obj                    &cpd->interrupt_object ); // space for int obj                cyg_drv_interrupt_attach(cpd->interrupt_handle);                // Don't unmask the interrupt yet, that could get us into a                // race.            }            else {                cpd->interrupt = 0;#if DEBUG & 8                db_printf(" Does not generate interrupts.\n");#endif            }            if (cyg_pci_configure_device(&dev_info)) {#if DEBUG & 8                int i;                db_printf("Found device on bus %d, devfn 0x%02x:\n",                          CYG_PCI_DEV_GET_BUS(devid),                          CYG_PCI_DEV_GET_DEVFN(devid));                if (dev_info.command & CYG_PCI_CFG_COMMAND_ACTIVE) {                    db_printf(" Note that board is active. Probed"                              " sizes and CPU addresses invalid!\n");                }                db_printf(" Vendor    0x%04x", dev_info.vendor);                db_printf("\n Device    0x%04x", dev_info.device);                db_printf("\n Command   0x%04x, Status 0x%04x\n",                          dev_info.command, dev_info.status);                db_printf(" Class/Rev 0x%08x", dev_info.class_rev);                db_printf("\n Header 0x%02x\n", dev_info.header_type);                db_printf(" SubVendor 0x%04x, Sub ID 0x%04x\n",                          dev_info.header.normal.sub_vendor,                          dev_info.header.normal.sub_id);                for(i = 0; i < CYG_PCI_MAX_BAR; i++) {                    db_printf(" BAR[%d]    0x%08x /", i, dev_info.base_address[i]);                    db_printf(" probed size 0x%08x / CPU addr 0x%08x\n",                              dev_info.base_size[i], dev_info.base_map[i]);                }                db_printf(" eth%d configured\n", device_index);#endif                found_devices++;                cpd->found = 1;                cpd->active = 0;                cpd->devid = devid;                cpd->base = (unsigned char*) dev_info.base_map[0];#if DEBUG & 8                db_printf(" I/O address = 0x%08x\n", cpd->base);#endif                // Don't use cyg_pci_set_device_info since it clears                // some of the fields we want to print out below.                cyg_pci_read_config_uint16(dev_info.devid,                                           CYG_PCI_CFG_COMMAND, &cmd);                cmd |= (CYG_PCI_CFG_COMMAND_IO         // enable I/O space                        | CYG_PCI_CFG_COMMAND_MEMORY   // enable memory space                        | CYG_PCI_CFG_COMMAND_MASTER); // enable bus master                cyg_pci_write_config_uint16(dev_info.devid,                                            CYG_PCI_CFG_COMMAND, cmd);                // This is the indicator for "uses an interrupt"                if (cpd->interrupt_handle != 0) {                    cyg_drv_interrupt_acknowledge(cpd->interrupt);                    cyg_drv_interrupt_unmask(cpd->interrupt);#if DEBUG & 8                    db_printf(" Enabled interrupt %d\n", cpd->interrupt);#endif                }#if DEBUG & 8                db_printf(" **** Device enabled for I/O and Memory "                            "and Bus Master\n");#endif            }            else {                cpd->found = 0;                cpd->active = 0;#if DEBUG & 8                db_printf("Failed to configure device %d\n", device_index);#endif            }

⌨️ 快捷键说明

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