📄 3c509.c
字号:
/********************************************************************************** * $Header: /usr1/CVS/rtems/c/src/lib/libbsp/i386/pc386/3c509/3c509.c,v 1.2 1999/12/13 21:21:31 joel Exp $ * * Ported by Rosimildo da Silva. * ConnectTel,Inc. * e-mail: rdasilva@connecttel.com * * MODULE DESCRIPTION: * RTEMS driver for 3COM 3C509 Ethernet Card. * The driver has been tested on PC with a single network card. * * * This driver was based on the FreeBSD implementation( if_ep.c ) of the 3c5x9 * family and on the network framework of the RTEMS network driver. * ( WD80x3 by Eric Norum ). * See notes below: * ****************************************************************************** * Copyright (c) 1994 Herb Peyerl <hpeyerl@novatel.ca> * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Herb Peyerl. * 4. The name of Herb Peyerl may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ******************************************************************************* * * RTEMS driver for M68360 WD1 Ethernet * * W. Eric Norum * Saskatchewan Accelerator Laboratory * University of Saskatchewan * Saskatoon, Saskatchewan, CANADA * eric@skatter.usask.ca ******************************************************************************* * * * MODIFICATION/HISTORY: * $Log: 3c509.c,v $ * Revision 1.2 1999/12/13 21:21:31 joel * Warning removal patch from Philip A. Prindeville <philipp@zembu.com>. * * Revision 1.1 1999/05/14 16:23:42 joel * Added 3COM 3C509 driver from Rosimildo DaSilva <rdasilva@connecttel.com>. * * **********************************************************************************/#include <bsp.h>#include <stdio.h>#include <stdarg.h>#include <rtems/error.h>#include <rtems/rtems_bsdnet.h>#include <sys/param.h>#include <sys/mbuf.h>#include <sys/socket.h>#include <sys/sockio.h>#include <sys/libkern.h>#include <net/if.h>#include <netinet/in.h>#include <netinet/if_ether.h>#include <irq.h>/* Local includes */#include "3c509.h"#include "elink.h"/* #define ET_MINLEN 60 */ /* minimum message length *//* * Number of WDs supported by this driver */#define NWDDRIVER 1/* * Default number of buffer descriptors set aside for this driver. * The number of transmit buffer descriptors has to be quite large * since a single frame often uses four or more buffer descriptors. *//*#define RX_BUF_COUNT 15#define TX_BUF_COUNT 4#define TX_BD_PER_BUF 4*//* * RTEMS event used by interrupt handler to signal driver tasks. * This must not be any of the events used by the network task synchronization. */#define INTERRUPT_EVENT RTEMS_EVENT_1/* * RTEMS event used to start transmit daemon. * This must not be the same as INTERRUPT_EVENT. */#define START_TRANSMIT_EVENT RTEMS_EVENT_2/* * Receive buffer size -- Allow for a full ethernet packet including CRC *//*#define RBUF_SIZE 1520#if (MCLBYTES < RBUF_SIZE)# error "Driver must have MCLBYTES > RBUF_SIZE"#endif*//* network driver name */#define NET_DRIVER_NAME "ep"/* * Per device structure. * * XXX Note: id_conflicts should either become an array of things we're * specifically allowed to conflict with or be subsumed into some * more powerful mechanism for detecting and dealing with multiple types * of non-fatal conflict. -jkh XXX */struct isa_device { int id_id; /* device id */ int id_unit; /* unit number */ int id_iobase; /* base i/o address */ u_int id_irq; /* interrupt request */};struct ep_board { int epb_addr; /* address of this board */ char epb_used; /* was this entry already used for configuring ? */ /* data from EEPROM for later use */ u_short eth_addr[3]; /* Ethernet address */ u_short prod_id; /* product ID */ u_short res_cfg; /* resource configuration */};/* * Ethernet software status per interface. */struct ep_softc { struct arpcom arpcom; /* Ethernet common part */ int ep_io_addr; /* i/o bus address */ struct mbuf *top, *mcur; short cur_len; u_short ep_connectors; /* Connectors on this card. */ u_char ep_connector; /* Configured connector. */ int stat; /* some flags */ struct ep_board *epb; int unit; rtems_irq_connect_data irqInfo; rtems_id rxDaemonTid; rtems_id txDaemonTid; int acceptBroadcast; short tx_underrun; short rx_no_first; short rx_no_mbuf; short rx_bpf_disc; short rx_overrunf; short rx_overrunl;};/* static unsigned long loopc; */static volatile unsigned long overrun;static volatile unsigned long resend;static struct ep_softc ep_softc[ NWDDRIVER ];static struct isa_device isa_dev[ NWDDRIVER ] = { { 0, /* device id */ 0, /* unit number */ -1, /* base i/o address ??? */ 0 /* interrupt request ??? */ }};static u_long ep_unit;static int ep_boards;struct ep_board ep_board[ EP_MAX_BOARDS + 1];static int ep_current_tag = EP_LAST_TAG + 1;static char *ep_conn_type[] = {"UTP", "AUI", "???", "BNC"};#define ep_ftst(f) (sc->stat&(f))#define ep_fset(f) (sc->stat|=(f))#define ep_frst(f) (sc->stat&=~(f))/* forward declarations for functions */static int ep_attach( struct ep_softc *sc );static int ep_isa_probe( struct isa_device *is );static void epinit( struct ep_softc *sc );static void epread( register struct ep_softc *sc );static void epstart( struct ifnet *ifp );static void epread( register struct ep_softc *sc );static int ep_isa_attach( struct isa_device *is );static int get_eeprom_data( int id_port, int offset );static void ep_intr( struct ep_softc *sc );/* external functions */extern void Wait_X_ms( unsigned int timeToWait ); /* timer.c ??? *//********************************************************************************** * * DESCRIPTION: Writes a buffer of data to the I/O port. The data is sent to the * port as 32 bits units( 4 bytes ). * * RETURNS: nothing. * **********************************************************************************/static __inline void outsl( unsigned short io_addr, unsigned char *out_data, int len ){ u_long *pl = ( u_long *)out_data; while( len-- ) { outport_long( io_addr, *pl ); pl++; }}/********************************************************************************** * * DESCRIPTION: Writes a buffer of data to the I/O port. The data is sent to the * port as 16 bits units( 2 bytes ). * * RETURNS: * **********************************************************************************/static __inline void outsw( unsigned short io_addr, unsigned char *out_data, int len ){ u_short *ps = ( u_short *)out_data; while( len-- ) { outport_word( io_addr, *ps ); ps++; }}/********************************************************************************** * * DESCRIPTION: Writes a buffer of data to the I/O port. The data is sent to the * port as 8 bits units( 1 byte ). * * RETURNS: nothing * **********************************************************************************/static __inline void outsb( unsigned short io_addr, unsigned char *out_data, int len ){ while( len-- ) { outport_byte( io_addr, *out_data ); out_data++; }}/********************************************************************************** * * DESCRIPTION: Read a buffer of data from an I/O port. The data is read as 16 bits * units or 2 bytes. * * RETURNS: nothing. * **********************************************************************************/static __inline void insw( unsigned short io_addr, unsigned char *in_data, int len ){ u_short *ps = ( u_short *)in_data; while( len-- ) { inport_word( io_addr, *ps ); ps++; }}/********************************************************************************** * * DESCRIPTION: Read a buffer of data from an I/O port. The data is read as 32 bits * units or 4 bytes. * * RETURNS: nothing. * **********************************************************************************/static __inline void insl( unsigned short io_addr, unsigned char *in_data, int len ){ u_long *pl = ( u_long *)in_data; while( len-- ) { inport_long( io_addr, *pl ); pl++; }}/********************************************************************************** * * DESCRIPTION: Read a buffer of data from an I/O port. The data is read as 8 bits * units or 1 bytes. * * RETURNS: nothing. * **********************************************************************************/static __inline void insb( unsigned short io_addr, unsigned char *in_data, int len ){ while( len-- ) { inport_byte( io_addr, *in_data++ ); }}/********************************************************************************** * * DESCRIPTION: Writes a word to the I/O port. * * RETURNS: nothing. * **********************************************************************************//* * Routine to output a word as defined in FreeBSD. */static __inline void outw( unsigned short io_addr, unsigned short out_data ){ outport_word( io_addr, out_data );}/********************************************************************************** * * DESCRIPTION: Routine to read a word as defined in FreeBSD. * * RETURNS: nothing * **********************************************************************************/static __inline unsigned short inw( unsigned short io_addr ){ unsigned short in_data; inport_word( io_addr, in_data ); return in_data;}/********************************************************************************** * * DESCRIPTION: Routine to output a word as defined in FreeBSD. * * RETURNS: nothing. * **********************************************************************************/void __inline outb( unsigned short io_addr, unsigned char out_data ){ outport_byte( io_addr, out_data );}/********************************************************************************** * * DESCRIPTION: Routine to read a word as defined in FreeBSD. * * RETURNS: byte read. * **********************************************************************************/static __inline unsigned char inb( unsigned short io_addr ){ unsigned char in_data; inport_byte( io_addr, in_data ); return in_data;}/********************************************************************************** * * DESCRIPTION: * We get eeprom data from the id_port given an offset into the eeprom. * Basically; after the ID_sequence is sent to all of the cards; they enter * the ID_CMD state where they will accept command requests. 0x80-0xbf loads * the eeprom data. We then read the port 16 times and with every read; the * cards check for contention (ie: if one card writes a 0 bit and another * writes a 1 bit then the host sees a 0. At the end of the cycle; each card * compares the data on the bus; if there is a difference then that card goes * into ID_WAIT state again). In the meantime; one bit of data is returned in * the AX register which is conveniently returned to us by inb(). Hence; we * read 16 times getting one bit of data with each read. * * RETURNS: 16 bit word from the EEPROM * **********************************************************************************/static int get_eeprom_data( int id_port, int offset ){ int i, data = 0; outb(id_port, 0x80 + offset); Wait_X_ms( 1 ); for (i = 0; i < 16; i++) data = (data << 1) | (inw(id_port) & 1); return( data );}/********************************************************************************** * * DESCRIPTION: Waits until the EEPROM of the card is ready to be accessed. * * RETURNS: 0 - not ready; 1 - ok * **********************************************************************************/static int eeprom_rdy( struct ep_softc *sc ){ int i; for (i = 0; is_eeprom_busy(BASE) && i < MAX_EEPROMBUSY; i++) continue; if (i >= MAX_EEPROMBUSY) { printf("ep%d: eeprom failed to come ready.\n", sc->unit); return (0); } return (1);}/********************************************************************************** * * DESCRIPTION: * get_e: gets a 16 bits word from the EEPROM. * We must have set the window before call this routine. * * RETURNS: data from EEPROM * **********************************************************************************/u_short get_e( struct ep_softc *sc, int offset ){ if( !eeprom_rdy(sc) ) return (0xffff); outw(BASE + EP_W0_EEPROM_COMMAND, EEPROM_CMD_RD | offset ); if( !eeprom_rdy(sc) ) return( 0xffff ); return( inw( BASE + EP_W0_EEPROM_DATA ) );}/********************************************************************************** * * DESCRIPTION: * Driver interrupt handler. This routine is called by the RTEMS kernel when this * interrupt is raised. * * RETURNS: nothing. * **********************************************************************************/static rtems_isr ap_interrupt_handler( rtems_vector_number v ){ struct ep_softc *sc = (struct ep_softc *)&ep_softc[ 0 ]; /* de-activate any pending interrrupt, and sent and event to interrupt task * to process all events required by this interrupt. */ outw( BASE + EP_COMMAND, SET_INTR_MASK ); /* disable all Ints */ rtems_event_send( sc->rxDaemonTid, INTERRUPT_EVENT ); }/********************************************************************************** * * DESCRIPTION: * * RETURNS: * **********************************************************************************/static void nopOn(const rtems_irq_connect_data* notUsed){ /* does nothing */}/********************************************************************************** * * DESCRIPTION: * * RETURNS: * **********************************************************************************/static int _3c509_IsOn(const rtems_irq_connect_data* irq){ return BSP_irq_enabled_at_i8259s (irq->name);}/********************************************************************************** * * DESCRIPTION: * Initializes the ethernet hardware. * * RETURNS: nothing. * **********************************************************************************/static void _3c509_initialize_hardware (struct ep_softc *sc){ rtems_status_code st; epinit( sc ); /* * Set up interrupts */ sc->irqInfo.hdl = ( rtems_irq_hdl )ap_interrupt_handler; sc->irqInfo.on = nopOn; sc->irqInfo.off = nopOn; sc->irqInfo.isOn = _3c509_IsOn; printf ("3c509: IRQ with Kernel: %d\n", sc->irqInfo.name ); st = BSP_install_rtems_irq_handler( &sc->irqInfo ); if( !st ) { rtems_panic ("Can't attach WD interrupt handler for irq %d\n", sc->irqInfo.name ); }}/********************************************************************************** * * DESCRIPTION: Driver interrupt daemon. * * RETURNS: nothing.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -