From 44dd8a611657c4bc94513d12bb4903c3809a3f2a Mon Sep 17 00:00:00 2001 From: Joel Sherrill Date: Fri, 14 May 1999 16:23:42 +0000 Subject: Added 3COM 3C509 driver from Rosimildo DaSilva . --- c/src/lib/libbsp/i386/pc386/3c509/3c509.c | 1636 ++++++++++++++++++++++++ c/src/lib/libbsp/i386/pc386/3c509/3c509.h | 423 ++++++ c/src/lib/libbsp/i386/pc386/3c509/Makefile.in | 65 + c/src/lib/libbsp/i386/pc386/3c509/elink.c | 78 ++ c/src/lib/libbsp/i386/pc386/3c509/elink.h | 43 + c/src/lib/libbsp/i386/pc386/Makefile.in | 2 +- c/src/lib/libbsp/i386/pc386/wrapup/Makefile.in | 2 +- 7 files changed, 2247 insertions(+), 2 deletions(-) create mode 100644 c/src/lib/libbsp/i386/pc386/3c509/3c509.c create mode 100644 c/src/lib/libbsp/i386/pc386/3c509/3c509.h create mode 100644 c/src/lib/libbsp/i386/pc386/3c509/Makefile.in create mode 100644 c/src/lib/libbsp/i386/pc386/3c509/elink.c create mode 100644 c/src/lib/libbsp/i386/pc386/3c509/elink.h diff --git a/c/src/lib/libbsp/i386/pc386/3c509/3c509.c b/c/src/lib/libbsp/i386/pc386/3c509/3c509.c new file mode 100644 index 0000000000..e4c27d894f --- /dev/null +++ b/c/src/lib/libbsp/i386/pc386/3c509/3c509.c @@ -0,0 +1,1636 @@ +/********************************************************************************** + * $Header$ + * + * 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 + * 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$ + * + **********************************************************************************/ + +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +/* 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 short 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. + * + **********************************************************************************/ +static void _3c509_rxDaemon (void *arg) +{ + struct ep_softc *dp = (struct ep_softc *)&ep_softc[ 0 ]; + rtems_event_set events; + + printf ("3C509: RX Daemon is starting.\n"); + for( ;; ) + { + /* printk( "R-" ); */ + rtems_bsdnet_event_receive( INTERRUPT_EVENT, + RTEMS_WAIT | RTEMS_EVENT_ANY, + RTEMS_NO_TIMEOUT, + &events ); + /* printk( "R+" ); */ + ep_intr( dp ); + epstart( &dp->arpcom.ac_if ); + } + printf ("3C509: RX Daemon is finishing.\n"); +} + + +/********************************************************************************** + * + * DESCRIPTION: Driver transmit daemon + * + * RETURNS: + * + **********************************************************************************/ +static void _3c509_txDaemon (void *arg) +{ + struct ep_softc *sc = (struct ep_softc *)&ep_softc[0]; + struct ifnet *ifp = &sc->arpcom.ac_if; + rtems_event_set events; + + printf ("3C509: TX Daemon is starting.\n"); + for( ;; ) + { + /* + * Wait for packet + */ + /* printk( "T-\n" ); */ + rtems_bsdnet_event_receive( START_TRANSMIT_EVENT, + RTEMS_EVENT_ANY | RTEMS_WAIT, + RTEMS_NO_TIMEOUT, + &events ); + /* printk( "T+\n" ); */ + epstart( ifp ); + while( ifp->if_flags & IFF_OACTIVE ) + epstart( ifp ); + } + printf ("3C509: TX Daemon is finishing.\n"); +} + + +/********************************************************************************** + * + * DESCRIPTION: Activates the trabsmitter task... + * + * RETURNS: nothing. + * + **********************************************************************************/ +static void _3c509_start (struct ifnet *ifp) +{ + struct ep_softc *sc = ifp->if_softc; + /* printk ("S"); */ + ifp->if_flags |= IFF_OACTIVE; + rtems_event_send( sc->txDaemonTid, START_TRANSMIT_EVENT ); +} + +/********************************************************************************** + * + * DESCRIPTION: Initialize and start the device + * + * RETURNS: + * + **********************************************************************************/ +static void _3c509_init (void *arg) +{ + struct ep_softc *sc = arg; + struct ifnet *ifp = &sc->arpcom.ac_if; + + printf ("3C509: Initialization called.\n"); + if (sc->txDaemonTid == 0) { + + /* + * Set up WD hardware + */ + _3c509_initialize_hardware (sc); + printf ("3C509: starting network driver tasks..\n"); + /* + * Start driver tasks + */ + sc->txDaemonTid = rtems_bsdnet_newproc ("APtx", 4096, _3c509_txDaemon, sc); + sc->rxDaemonTid = rtems_bsdnet_newproc ("APrx", 4096, _3c509_rxDaemon, sc); + } + + /* + * Tell the world that we're running. + */ + ifp->if_flags |= IFF_RUNNING; +} + +/********************************************************************************** + * + * DESCRIPTION: Stop the device + * + * RETURNS: + * + **********************************************************************************/ +static void _3c509_stop (struct ep_softc *sc) +{ + struct ifnet *ifp = &sc->arpcom.ac_if; + ifp->if_flags &= ~IFF_RUNNING; + + printf ("3C509: stop() called.\n"); + /* + * Stop the transmitter + */ + outw(BASE + EP_COMMAND, RX_DISABLE); + outw(BASE + EP_COMMAND, RX_DISCARD_TOP_PACK); + while (inw(BASE + EP_STATUS) & S_COMMAND_IN_PROGRESS); + outw(BASE + EP_COMMAND, TX_DISABLE); + outw(BASE + EP_COMMAND, STOP_TRANSCEIVER); + outw(BASE + EP_COMMAND, RX_RESET); + outw(BASE + EP_COMMAND, TX_RESET); + while (inw(BASE + EP_STATUS) & S_COMMAND_IN_PROGRESS); + outw(BASE + EP_COMMAND, C_INTR_LATCH); + outw(BASE + EP_COMMAND, SET_RD_0_MASK); + outw(BASE + EP_COMMAND, SET_INTR_MASK); + outw(BASE + EP_COMMAND, SET_RX_FILTER); +} + + +/********************************************************************************** + * + * DESCRIPTION: Show interface statistics + * + * RETURNS: nothing. + * + **********************************************************************************/ +static void _3c509_stats (struct ep_softc *sc) +{ + struct ifnet *ifp = &sc->arpcom.ac_if; + printf ("3C509: stats() called.\n"); + printf("\tStat: %x\n", sc->stat); + printf("\tIpackets=%ld, Opackets=%ld\n", ifp->if_ipackets, ifp->if_opackets); + printf("\tNOF=%d, NOMB=%d, BPFD=%d, RXOF=%d, RXOL=%d, TXU=%d\n", + sc->rx_no_first, sc->rx_no_mbuf, sc->rx_bpf_disc, sc->rx_overrunf, + sc->rx_overrunl, sc->tx_underrun ); +} + +/********************************************************************************** + * + * DESCRIPTION: Driver ioctl handler + * + * RETURNS: + * + **********************************************************************************/ +static int _3c509_ioctl (struct ifnet *ifp, int command, caddr_t data) +{ + struct ep_softc *sc = ifp->if_softc; + int error = 0; + + printf ("3C509: ioctl() called.\n"); + switch (command) { + case SIOCGIFADDR: + case SIOCSIFADDR: + ether_ioctl (ifp, command, data); + break; + + case SIOCSIFFLAGS: + switch (ifp->if_flags & (IFF_UP | IFF_RUNNING)) { + case IFF_RUNNING: + _3c509_stop (sc); + break; + + case IFF_UP: + _3c509_init (sc); + break; + + case IFF_UP | IFF_RUNNING: + _3c509_stop (sc); + _3c509_init (sc); + break; + + default: + break; + } + break; + + case SIO_RTEMS_SHOW_STATS: + _3c509_stats( sc ); + break; + + /* + * FIXME: All sorts of multicast commands need to be added here! + */ + default: + error = EINVAL; + break; + } + return error; +} + +/********************************************************************************** + * + * DESCRIPTION: + * Attaches this network driver to the system. This function is called by the network + * interface during the initialization of the system. + * + * RETURNS: - 1 - success; 0 - fail to initialize + * + **********************************************************************************/ +int rtems_3c509_driver_attach (struct rtems_bsdnet_ifconfig *config ) +{ + struct ep_softc *sc; + struct ifnet *ifp; + int mtu; + int i; + + printf ("3C509: attach() called.\n"); + + /* + * init some variables + */ + overrun = 0; + resend = 0; + ep_unit = 0; + ep_boards = 0; + + /* + * Find a free driver + */ + for (i = 0 ; i < NWDDRIVER ; i++) { + sc = &ep_softc[i]; + ifp = &sc->arpcom.ac_if; + if (ifp->if_softc == NULL) + break; + } + if (i >= NWDDRIVER) + { + printf ("Too many 3C509 drivers.\n"); + return 0; + } + + /* + * Process options + */ + if( config->hardware_address ) + { + memcpy (sc->arpcom.ac_enaddr, config->hardware_address, ETHER_ADDR_LEN); + } + else + { + /* set it to something ... */ + memset (sc->arpcom.ac_enaddr, 0x08,ETHER_ADDR_LEN); + } + if (config->mtu) + mtu = config->mtu; + else + mtu = ETHERMTU; + + if (config->irno) + sc->irqInfo.name = config->irno; + else + sc->irqInfo.name = 10; + + if (config->port) + sc->ep_io_addr = config->port; + else + sc->ep_io_addr = 0x300; + + sc->acceptBroadcast = !config->ignore_broadcast; + + printf ("3C509: isa_probe() looking for a card...\n"); + if( !ep_isa_probe( &isa_dev[ 0 ] ) ) + { + printf ("3C509: isa_probe() fail to find a board.\n"); + return 0; + } + + /* A board has been found, so proceed with the installation of the driver */ + ep_isa_attach( &isa_dev[ 0 ] ); + /* + * Set up network interface values + */ + + ifp->if_softc = sc; + ifp->if_unit = i; + ifp->if_name = NET_DRIVER_NAME; + ifp->if_mtu = mtu; + ifp->if_init = _3c509_init; + ifp->if_ioctl = _3c509_ioctl; + ifp->if_start = _3c509_start; + ifp->if_output = ether_output; + ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; + if( ifp->if_snd.ifq_maxlen == 0 ) + { + ifp->if_snd.ifq_maxlen = ifqmaxlen; + } + /* + * Attach the interface + */ + if_attach (ifp); + ether_ifattach (ifp); + printf ("3C509: attach() is complete.\n"); + return 1; +} + + +/********************************************************************************** + * + * DESCRIPTION: + * This function looks for a 3COM card 3c5x9 in an isa bus. If a board is found, it + * returns a structure describing the caracteristics of the card. It returns zero when + * card can not be found. + * + * RETURNS: 0 - fail - could not find a card... + * <> description of the card. + * + **********************************************************************************/ +static struct ep_board *ep_look_for_board_at( struct isa_device *is ) +{ + int data, i, j, id_port = ELINK_ID_PORT; + int count = 0; + + if(ep_current_tag == (EP_LAST_TAG + 1) ) + { + /* Come here just one time */ + ep_current_tag--; + + /* Look for the ISA boards. Init and leave them actived */ + outb(id_port, 0); + outb(id_port, 0); + + elink_idseq(0xCF); + elink_reset(); + Wait_X_ms( 10 ); /* RPS: assuming delay in miliseconds */ + for (i = 0; i < EP_MAX_BOARDS; i++) + { + outb(id_port, 0); + outb(id_port, 0); + elink_idseq(0xCF); + + data = get_eeprom_data(id_port, EEPROM_MFG_ID); + if (data != MFG_ID) + break; + + /* resolve contention using the Ethernet address */ + for (j = 0; j < 3; j++) + get_eeprom_data(id_port, j); + + /* and save this address for later use */ + + for (j = 0; j < 3; j++) + ep_board[ep_boards].eth_addr[j] = get_eeprom_data(id_port, j); + + ep_board[ep_boards].res_cfg = get_eeprom_data(id_port, EEPROM_RESOURCE_CFG); + ep_board[ep_boards].prod_id = get_eeprom_data(id_port, EEPROM_PROD_ID); + ep_board[ep_boards].epb_used = 0; +#ifdef PC98 + ep_board[ep_boards].epb_addr = + (get_eeprom_data(id_port, EEPROM_ADDR_CFG) & 0x1f) * 0x100 + 0x40d0; +#else + ep_board[ep_boards].epb_addr = + (get_eeprom_data(id_port, EEPROM_ADDR_CFG) & 0x1f) * 0x10 + 0x200; + if (ep_board[ep_boards].epb_addr > 0x3E0) + /* Board in EISA configuration mode */ + continue; +#endif /* PC98 */ + + outb(id_port, ep_current_tag); /* tags board */ + outb(id_port, ACTIVATE_ADAPTER_TO_CONFIG); + ep_boards++; + count++; + ep_current_tag--; + } + ep_board[ep_boards].epb_addr = 0; + if( count ) + { + printf("%d 3C5x9 board(s) on ISA found at", count); + for (j = 0; ep_board[j].epb_addr; j++) + if( ep_board[j].epb_addr <= 0x3E0 ) + printf(" 0x%x", ep_board[j].epb_addr ); + printf("\n"); + } + } + + /* we have two cases: + * + * 1. Device was configured with 'port ?' + * In this case we search for the first unused card in list + * + * 2. Device was configured with 'port xxx' + * In this case we search for the unused card with that address + * + */ + + if (IS_BASE == -1) + { /* port? */ + for (i = 0; ep_board[i].epb_addr && ep_board[i].epb_used; i++) ; + if (ep_board[i].epb_addr == 0) + return 0; + + IS_BASE = ep_board[i].epb_addr; + ep_board[i].epb_used = 1; + return &ep_board[ i ]; + } + else + { + for (i = 0; ep_board[i].epb_addr && ep_board[i].epb_addr != IS_BASE; i++ ) ; + if (ep_board[i].epb_used || ep_board[i].epb_addr != IS_BASE) + return 0; + if (inw(IS_BASE + EP_W0_EEPROM_COMMAND) & EEPROM_TST_MODE) + { + printf("ep%d: 3c5x9 at 0x%x in PnP mode. Disable PnP mode!\n", + is->id_unit, IS_BASE ); + } + ep_board[i].epb_used = 1; + return &ep_board[i]; + } +} + + + +/********************************************************************************** + * + * DESCRIPTION: + * This routine checks if there card installed on the machine. + * + * RETURNS: 0 - no card founded. + * 16 - size of the IO range for the card. + * + **********************************************************************************/ +static int ep_isa_probe( struct isa_device *is ) +{ + struct ep_softc *sc; + struct ep_board *epb; + u_short k; + + /* try to find a 3COM 3c5x9 .... */ + if( (epb = ep_look_for_board_at(is)) == 0 ) + return (0); + + sc = &ep_softc[ 0 ]; + sc->ep_io_addr = epb->epb_addr; + sc->epb = epb; + + /* + * The iobase was found and MFG_ID was 0x6d50. PROD_ID should be + * 0x9[0-f]50 (IBM-PC) + * 0x9[0-f]5[0-f] (PC-98) + */ + GO_WINDOW(0); + k = sc->epb->prod_id; +#ifdef PC98 + if ((k & 0xf0f0) != (PROD_ID & 0xf0f0)) + { +#else + if ((k & 0xf0ff) != (PROD_ID & 0xf0ff)) + { +#endif + printf("ep_isa_probe: ignoring model %04x\n", k ); +/* ep_unit--; */ + return (0); + } + k = sc->epb->res_cfg; + k >>= 12; + + /* Now we have two cases again: + * + * 1. Device was configured with 'irq?' + * In this case we use irq read from the board + * + * 2. Device was configured with 'irq xxx' + * In this case we set up the board to use specified interrupt + * + */ + + if (is->id_irq == 0) + { /* irq? */ + is->id_irq = ( k == 2 ) ? 9 : k; + } + + sc->stat = 0; /* 16 bit access */ + + /* By now, the adapter is already activated */ + + return (EP_IOSIZE); /* 16 bytes of I/O space used. */ +} + + + +/********************************************************************************** + * + * DESCRIPTION: + * This routine attaches this network driver and the network interface routines. + * + * RETURNS: 0 - failed to attach + * 1 - success + * + **********************************************************************************/ +static int ep_isa_attach( struct isa_device *is ) +{ + struct ep_softc *sc = &ep_softc[ 0 ]; + u_short config; + int irq; + + sc->ep_connectors = 0; + config = inw( IS_BASE + EP_W0_CONFIG_CTRL ); + if (config & IS_AUI) + { + sc->ep_connectors |= AUI; + } + if (config & IS_BNC) + { + sc->ep_connectors |= BNC; + } + if (config & IS_UTP) + { + sc->ep_connectors |= UTP; + } + if( !(sc->ep_connectors & 7) ) + printf( "no connectors!" ); + sc->ep_connector = inw(BASE + EP_W0_ADDRESS_CFG) >> ACF_CONNECTOR_BITS; + + /* + * Write IRQ value to board + */ + + irq = is->id_irq; + /* update the interrupt line number to registered with kernel */ + sc->irqInfo.name = irq; + + GO_WINDOW( 0 ); + SET_IRQ( BASE, irq ); + + printf( "3C509: I/O=0x%x, IRQ=%d, CONNECTOR=%s, ", + sc->ep_io_addr, sc->irqInfo.name,ep_conn_type[ sc->ep_connector ] ); + + ep_attach( sc ); + return 1; +} + +/********************************************************************************** + * + * DESCRIPTION: Completes the initialization/attachement of the driver. + * + * RETURNS: 0 - ok. + * + **********************************************************************************/ +static int ep_attach( struct ep_softc *sc ) +{ + u_short *p; + int i; + + /* + * Setup the station address + */ + p = (u_short *) &sc->arpcom.ac_enaddr; + GO_WINDOW(2); + printf("ADDRESS=" ); + for (i = 0; i < 3; i++) + { + p[i] = htons( sc->epb->eth_addr[i] ); + outw( BASE + EP_W2_ADDR_0 + (i * 2), ntohs( p[i] ) ); + printf("%04x ", (u_short)ntohs( p[i] ) ); + } + printf("\n" ); + + sc->rx_no_first = sc->rx_no_mbuf = + sc->rx_bpf_disc = sc->rx_overrunf = sc->rx_overrunl = + sc->tx_underrun = 0; + + ep_fset( F_RX_FIRST ); + sc->top = sc->mcur = 0; + return 0; +} + + +/********************************************************************************** + * + * DESCRIPTION: + * Initializes the card. + * The order in here seems important. Otherwise we may not receive interrupts. ?! + * + * RETURNS: nothing. + * + **********************************************************************************/ +static void epinit( struct ep_softc *sc ) +{ + register struct ifnet *ifp = &sc->arpcom.ac_if; + int i, j; + + while( inw(BASE + EP_STATUS) & S_COMMAND_IN_PROGRESS ) ; + GO_WINDOW(0); + outw(BASE + EP_COMMAND, STOP_TRANSCEIVER); + GO_WINDOW(4); + outw(BASE + EP_W4_MEDIA_TYPE, DISABLE_UTP); + GO_WINDOW(0); + + /* Disable the card */ + outw(BASE + EP_W0_CONFIG_CTRL, 0); + + /* Enable the card */ + outw(BASE + EP_W0_CONFIG_CTRL, ENABLE_DRQ_IRQ); + + GO_WINDOW(2); + + /* Reload the ether_addr. */ + for (i = 0; i < 6; i++) + outb(BASE + EP_W2_ADDR_0 + i, sc->arpcom.ac_enaddr[i]); + + outw(BASE + EP_COMMAND, RX_RESET); + outw(BASE + EP_COMMAND, TX_RESET); + while (inw(BASE + EP_STATUS) & S_COMMAND_IN_PROGRESS); + + /* Window 1 is operating window */ + GO_WINDOW(1); + for (i = 0; i < 31; i++) + inb(BASE + EP_W1_TX_STATUS); + + /* get rid of stray intr's */ + outw(BASE + EP_COMMAND, ACK_INTR | 0xff); + + outw(BASE + EP_COMMAND, SET_RD_0_MASK | S_5_INTS); + + outw(BASE + EP_COMMAND, SET_INTR_MASK | S_5_INTS); + + if (ifp->if_flags & IFF_PROMISC) + outw(BASE + EP_COMMAND, SET_RX_FILTER | FIL_INDIVIDUAL | + FIL_GROUP | FIL_BRDCST | FIL_ALL); + else + outw(BASE + EP_COMMAND, SET_RX_FILTER | FIL_INDIVIDUAL | FIL_GROUP | FIL_BRDCST); + + /* + * S.B. + * + * Now behavior was slightly changed: + * + * if any of flags link[0-2] is used and its connector is + * physically present the following connectors are used: + * + * link0 - AUI * highest precedence + * link1 - BNC + * link2 - UTP * lowest precedence + * + * If none of them is specified then + * connector specified in the EEPROM is used + * (if present on card or AUI if not). + * + */ + + /* Set the xcvr. */ + if (ifp->if_flags & IFF_LINK0 && sc->ep_connectors & AUI) + { + i = ACF_CONNECTOR_AUI; + } + else if (ifp->if_flags & IFF_LINK1 && sc->ep_connectors & BNC) + { + i = ACF_CONNECTOR_BNC; + } + else if (ifp->if_flags & IFF_LINK2 && sc->ep_connectors & UTP) + { + i = ACF_CONNECTOR_UTP; + } + else + { + i = sc->ep_connector; + } + GO_WINDOW(0); + j = inw(BASE + EP_W0_ADDRESS_CFG) & 0x3fff; + outw(BASE + EP_W0_ADDRESS_CFG, j | (i << ACF_CONNECTOR_BITS)); + + switch(i) + { + case ACF_CONNECTOR_UTP: + if (sc->ep_connectors & UTP) + { + GO_WINDOW(4); + outw(BASE + EP_W4_MEDIA_TYPE, ENABLE_UTP); + } + break; + + case ACF_CONNECTOR_BNC: + if (sc->ep_connectors & BNC) + { + outw(BASE + EP_COMMAND, START_TRANSCEIVER); + Wait_X_ms( 1 ); + } + break; + + case ACF_CONNECTOR_AUI: + /* nothing to do */ + break; + + default: + printf("ep%d: strange connector type in EEPROM: assuming AUI\n", sc->unit); + break; + } + + outw(BASE + EP_COMMAND, RX_ENABLE); + outw(BASE + EP_COMMAND, TX_ENABLE); + + ifp->if_flags |= IFF_RUNNING; + ifp->if_flags &= ~IFF_OACTIVE; /* just in case */ + + + sc->rx_no_first = sc->rx_no_mbuf = + sc->rx_bpf_disc = sc->rx_overrunf = sc->rx_overrunl = + sc->tx_underrun = 0; + + ep_fset(F_RX_FIRST); + if( sc->top ) + { + m_freem( sc->top ); + sc->top = sc->mcur = 0; + } + outw(BASE + EP_COMMAND, SET_RX_EARLY_THRESH | RX_INIT_EARLY_THRESH); + outw(BASE + EP_COMMAND, SET_TX_START_THRESH | 16); + + /* + * Store up a bunch of mbuf's for use later. (MAX_MBS). First we free up + * any that we had in case we're being called from intr or somewhere + * else. + */ + + GO_WINDOW(1); +} + + +static const char padmap[] = {0, 3, 2, 1}; + +/********************************************************************************** + * + * DESCRIPTION: Routine to transmit frames to the card. + * + * RETURNS: nothing. + * + **********************************************************************************/ +static void epstart( struct ifnet *ifp ) +{ + register struct ep_softc *sc = ifp->if_softc; + register u_int len; + register struct mbuf *m; + struct mbuf *top; + int pad; + + while( inw(BASE + EP_STATUS) & S_COMMAND_IN_PROGRESS ) + ; +startagain: + /* printk( "S-" ); */ + + /* Sneak a peek at the next packet */ + m = ifp->if_snd.ifq_head; + if (m == 0) + { + ifp->if_flags &= ~IFF_OACTIVE; + return; + } + + for( len = 0, top = m; m; m = m->m_next ) + len += m->m_len; + + pad = padmap[ len & 3 ]; + + /* + * The 3c509 automatically pads short packets to minimum ethernet length, + * but we drop packets that are too large. Perhaps we should truncate + * them instead? + */ + if( len + pad > ETHER_MAX_LEN ) + { + /* packet is obviously too large: toss it */ + ++ifp->if_oerrors; + IF_DEQUEUE( &ifp->if_snd, m ); + m_freem( m ); + goto readcheck; + } + if (inw(BASE + EP_W1_FREE_TX) < len + pad + 4) + { + /* no room in FIFO */ + outw(BASE + EP_COMMAND, SET_TX_AVAIL_THRESH | (len + pad + 4)); + /* make sure */ + if (inw(BASE + EP_W1_FREE_TX) < len + pad + 4) + { + ifp->if_flags |= IFF_OACTIVE; + return; + } + } + IF_DEQUEUE( &ifp->if_snd, m ); + outw(BASE + EP_W1_TX_PIO_WR_1, len); + outw(BASE + EP_W1_TX_PIO_WR_1, 0x0); /* Second dword meaningless */ + + for (top = m; m != 0; m = m->m_next) + { + if( ep_ftst(F_ACCESS_32_BITS ) ) + { + outsl( BASE + EP_W1_TX_PIO_WR_1, mtod(m, caddr_t), m->m_len / 4 ); + if( m->m_len & 3 ) + outsb(BASE + EP_W1_TX_PIO_WR_1, mtod(m, caddr_t) + (m->m_len & (~3)), m->m_len & 3 ); + } + else + { + outsw( BASE + EP_W1_TX_PIO_WR_1, mtod(m, caddr_t), m->m_len / 2 ); + if( m->m_len & 1 ) + outb( BASE + EP_W1_TX_PIO_WR_1, *(mtod(m, caddr_t) + m->m_len - 1) ); + } + } + while( pad-- ) + { + outb(BASE + EP_W1_TX_PIO_WR_1, 0); /* Padding */ + } + ifp->if_timer = 2; + ifp->if_opackets++; + m_freem(top); + +/* goto startagain; */ + /* + * Is another packet coming in? We don't want to overflow the tiny RX + * fifo. + */ +readcheck: + if( inw(BASE + EP_W1_RX_STATUS) & RX_BYTES_MASK ) + { + /* + * we check if we have packets left, in that case we prepare to come + * back later + */ + if( ifp->if_snd.ifq_head ) + { + outw(BASE + EP_COMMAND, SET_TX_AVAIL_THRESH | 8); + } + return; + } + goto startagain; +} + + + +/********************************************************************************** + * + * DESCRIPTION: Routine to read frames from the card. + * + * RETURNS: nothing. + * + **********************************************************************************/ +static void epread( register struct ep_softc *sc ) +{ + struct ether_header *eh; + struct mbuf *top, *mcur, *m; + struct ifnet *ifp; + int lenthisone; + + short rx_fifo2, status; + register short rx_fifo; + + ifp = &sc->arpcom.ac_if; + status = inw( BASE + EP_W1_RX_STATUS ); + +read_again: + + if (status & ERR_RX) + { + ++ifp->if_ierrors; + if( status & ERR_RX_OVERRUN ) + { + /* + * we can think the rx latency is actually greather than we + * expect + */ + if( ep_ftst(F_RX_FIRST) ) + sc->rx_overrunf++; + else + sc->rx_overrunl++; + + } + goto out; + } + rx_fifo = rx_fifo2 = status & RX_BYTES_MASK; + + if( ep_ftst( F_RX_FIRST ) ) + { + MGETHDR( m, M_DONTWAIT, MT_DATA ); + if( !m ) + goto out; + if( rx_fifo >= MINCLSIZE ) + MCLGET( m, M_DONTWAIT ); + sc->top = sc->mcur = top = m; +#define EROUND ((sizeof(struct ether_header) + 3) & ~3) +#define EOFF (EROUND - sizeof(struct ether_header)) + top->m_data += EOFF; + + /* Read what should be the header. */ + insw(BASE + EP_W1_RX_PIO_RD_1, mtod(top, caddr_t), sizeof(struct ether_header) / 2); + top->m_len = sizeof(struct ether_header); + rx_fifo -= sizeof(struct ether_header); + sc->cur_len = rx_fifo2; + } + else + { + /* come here if we didn't have a complete packet last time */ + top = sc->top; + m = sc->mcur; + sc->cur_len += rx_fifo2; + } + + /* Reads what is left in the RX FIFO */ + while (rx_fifo > 0) + { + lenthisone = min( rx_fifo, M_TRAILINGSPACE(m) ); + if( lenthisone == 0 ) + { /* no room in this one */ + mcur = m; + MGET(m, M_WAIT, MT_DATA); + if (!m) + goto out; + if (rx_fifo >= MINCLSIZE) + MCLGET(m, M_WAIT); + m->m_len = 0; + mcur->m_next = m; + lenthisone = min(rx_fifo, M_TRAILINGSPACE(m)); + } + if( ep_ftst( F_ACCESS_32_BITS ) ) + { /* default for EISA configured cards*/ + insl( BASE + EP_W1_RX_PIO_RD_1, mtod(m, caddr_t) + m->m_len, lenthisone / 4); + m->m_len += (lenthisone & ~3); + if (lenthisone & 3) + insb(BASE + EP_W1_RX_PIO_RD_1, mtod(m, caddr_t) + m->m_len, lenthisone & 3); + m->m_len += (lenthisone & 3); + } + else + { + insw(BASE + EP_W1_RX_PIO_RD_1, mtod(m, caddr_t) + m->m_len, lenthisone / 2); + m->m_len += lenthisone; + if( lenthisone & 1 ) + *(mtod(m, caddr_t) + m->m_len - 1) = inb(BASE + EP_W1_RX_PIO_RD_1); + } + rx_fifo -= lenthisone; + } + + if( status & ERR_RX_INCOMPLETE) + { /* we haven't received the complete packet */ + sc->mcur = m; + sc->rx_no_first++; /* to know how often we come here */ + ep_frst( F_RX_FIRST ); + if( !((status = inw(BASE + EP_W1_RX_STATUS)) & ERR_RX_INCOMPLETE) ) + { + /* we see if by now, the packet has completly arrived */ + goto read_again; + } + outw(BASE + EP_COMMAND, SET_RX_EARLY_THRESH | RX_NEXT_EARLY_THRESH); + return; + } + outw(BASE + EP_COMMAND, RX_DISCARD_TOP_PACK); + ++ifp->if_ipackets; + ep_fset(F_RX_FIRST); + top->m_pkthdr.rcvif = &sc->arpcom.ac_if; + top->m_pkthdr.len = sc->cur_len; + + eh = mtod(top, struct ether_header *); + m_adj(top, sizeof(struct ether_header)); + ether_input(ifp, eh, top); + sc->top = 0; + while (inw(BASE + EP_STATUS) & S_COMMAND_IN_PROGRESS) + ; + outw(BASE + EP_COMMAND, SET_RX_EARLY_THRESH | RX_INIT_EARLY_THRESH); + return; + +out: + outw(BASE + EP_COMMAND, RX_DISCARD_TOP_PACK); + if (sc->top) + { + m_freem(sc->top); + sc->top = 0; + sc->rx_no_mbuf++; + } + ep_fset(F_RX_FIRST); + while (inw(BASE + EP_STATUS) & S_COMMAND_IN_PROGRESS) ; + outw(BASE + EP_COMMAND, SET_RX_EARLY_THRESH | RX_INIT_EARLY_THRESH); +} + + + +/********************************************************************************** + * + * DESCRIPTION: + * This routine handles interrupts. It is called from the "RX" task whenever + * the ISR post an event to the task. + * This is basically the "isr" from the FreeBSD driver. + * + * RETURNS: nothing. + * + **********************************************************************************/ +static void ep_intr( struct ep_softc *sc ) +{ + register int status; + struct ifnet *ifp; + ifp = &sc->arpcom.ac_if; + +rescan: + + /* printk( "I-" ); */ + while( ( status = inw(BASE + EP_STATUS)) & S_5_INTS ) + { + /* first acknowledge all interrupt sources */ + outw( BASE + EP_COMMAND, ACK_INTR | ( status & S_MASK ) ); + + if( status & ( S_RX_COMPLETE | S_RX_EARLY ) ) + { + epread( sc ); + continue; + } + if (status & S_TX_AVAIL) + { + /* we need ACK */ + ifp->if_timer = 0; + ifp->if_flags &= ~IFF_OACTIVE; + GO_WINDOW(1); + inw(BASE + EP_W1_FREE_TX); + epstart(ifp); + } + if (status & S_CARD_FAILURE) + { + ifp->if_timer = 0; + printf("\nep%d:\n\tStatus: %x\n", sc->unit, status); + GO_WINDOW(4); + printf("\tFIFO Diagnostic: %x\n", inw(BASE + EP_W4_FIFO_DIAG)); + printf("\tStat: %x\n", sc->stat); + printf("\tIpackets=%ld, Opackets=%ld\n", ifp->if_ipackets, ifp->if_opackets); + printf("\tNOF=%d, NOMB=%d, BPFD=%d, RXOF=%d, RXOL=%d, TXU=%d\n", + sc->rx_no_first, sc->rx_no_mbuf, sc->rx_bpf_disc, sc->rx_overrunf, + sc->rx_overrunl, sc->tx_underrun); + + printf("ep%d: Status: %x (input buffer overflow)\n", sc->unit, status); + ++ifp->if_ierrors; + epinit(sc); + return; + } + if (status & S_TX_COMPLETE) + { + ifp->if_timer = 0; + /* we need ACK. we do it at the end */ + /* + * We need to read TX_STATUS until we get a 0 status in order to + * turn off the interrupt flag. + */ + while ((status = inb(BASE + EP_W1_TX_STATUS)) & TXS_COMPLETE) + { + if (status & TXS_SUCCES_INTR_REQ) + ; + else if( status & (TXS_UNDERRUN | TXS_JABBER | TXS_MAX_COLLISION ) ) + { + outw(BASE + EP_COMMAND, TX_RESET); + if (status & TXS_UNDERRUN) + { + sc->tx_underrun++; + } + else + { + if( status & TXS_JABBER ) + ; + else /* TXS_MAX_COLLISION - we shouldn't get here */ + ++ifp->if_collisions; + } + ++ifp->if_oerrors; + outw(BASE + EP_COMMAND, TX_ENABLE); + /* + * To have a tx_avail_int but giving the chance to the + * Reception + */ + if( ifp->if_snd.ifq_head ) + { + outw(BASE + EP_COMMAND, SET_TX_AVAIL_THRESH | 8); + } + } + outb( BASE + EP_W1_TX_STATUS, 0x0 ); /* pops up the next status */ + } /* while */ + ifp->if_flags &= ~IFF_OACTIVE; + GO_WINDOW(1); + inw(BASE + EP_W1_FREE_TX); + epstart( ifp ); + } /* end TX_COMPLETE */ + } + outw(BASE + EP_COMMAND, C_INTR_LATCH); /* ACK int Latch */ + if( (status = inw(BASE + EP_STATUS) ) & S_5_INTS ) + goto rescan; + + /* re-enable Ints */ + outw( BASE + EP_COMMAND, SET_INTR_MASK | S_5_INTS ); + /* printk( "I+" ); */ +} diff --git a/c/src/lib/libbsp/i386/pc386/3c509/3c509.h b/c/src/lib/libbsp/i386/pc386/3c509/3c509.h new file mode 100644 index 0000000000..3c12e989a1 --- /dev/null +++ b/c/src/lib/libbsp/i386/pc386/3c509/3c509.h @@ -0,0 +1,423 @@ +/* + * Copyright (c) 1993 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. The name + * of the author 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. + * + * if_epreg.h,v 1.4 1994/11/13 10:12:37 gibbs Exp Modified by: + * + October 2, 1994 + + Modified by: Andres Vega Garcia + + INRIA - Sophia Antipolis, France + e-mail: avega@sophia.inria.fr + finger: avega@pax.inria.fr + + */ +/* + * $Id$ + * + * Promiscuous mode added and interrupt logic slightly changed + * to reduce the number of adapter failures. Transceiver select + * logic changed to use value from EEPROM. Autoconfiguration + * features added. + * Done by: + * Serge Babkin + * Chelindbank (Chelyabinsk, Russia) + * babkin@hq.icb.chel.su + */ + +/* + * Pccard support for 3C589 by: + * HAMADA Naoki + * nao@tom-yam.or.jp + */ + +/* +typedef unsigned short u_short; +typedef unsigned long u_long; +typedef unsigned char u_char; +*/ + +/* + * Some global constants + */ +#define F_RX_FIRST 0x1 +#define F_PROMISC 0x8 +#define F_ACCESS_32_BITS 0x100 + +#define TX_INIT_RATE 16 +#define TX_INIT_MAX_RATE 64 +#define RX_INIT_LATENCY 64 +#define RX_INIT_EARLY_THRESH 208 /* not less than MINCLSIZE */ +#define RX_NEXT_EARLY_THRESH 500 + +#define EEPROMSIZE 0x40 +#define MAX_EEPROMBUSY 1000 +#define EP_LAST_TAG 0xd7 +#define EP_MAX_BOARDS 16 +/* + * This `ID' port is a mere hack. There's currently no chance to register + * it with config's idea of the ports that are in use. + * + * "After the automatic configuration is completed, the IDS is in its initial + * state (ID-WAIT), and it monitors all write access to I/O port 01x0h, where + * 'x' is any hex digit. If a zero is written to any one of these ports, then + * that address is remembered and becomes the ID port. A second zero written + * to that port resets the ID sequence to its initial state. The IDS watches + * for the ID sequence to be written to the ID port." + * + * We prefer 0x110 over 0x100 so to not conflict with the Plaque&Pray + * ports. + */ +#define EP_ID_PORT 0x110 +#define EP_IOSIZE 16 /* 16 bytes of I/O space used. */ + +/* + * some macros to acces long named fields + */ +#define IS_BASE (is->id_iobase) +#define BASE (sc->ep_io_addr) + +/* + * Commands to read/write EEPROM trough EEPROM command register (Window 0, + * Offset 0xa) + */ +#define EEPROM_CMD_RD 0x0080 /* Read: Address required (5 bits) */ +#define EEPROM_CMD_WR 0x0040 /* Write: Address required (5 bits) */ +#define EEPROM_CMD_ERASE 0x00c0 /* Erase: Address required (5 bits) */ +#define EEPROM_CMD_EWEN 0x0030 /* Erase/Write Enable: No data required */ + +#define EEPROM_BUSY (1<<15) +#define EEPROM_TST_MODE (1<<14) + +/* + * Some short functions, worth to let them be a macro + */ +#define is_eeprom_busy(b) (inw((b)+EP_W0_EEPROM_COMMAND)&EEPROM_BUSY) +#define GO_WINDOW(x) outw(BASE+EP_COMMAND, WINDOW_SELECT|(x)) + +/************************************************************************** + * * + * These define the EEPROM data structure. They are used in the probe + * function to verify the existence of the adapter after having sent + * the ID_Sequence. + * + * There are others but only the ones we use are defined here. + * + **************************************************************************/ + +#define EEPROM_NODE_ADDR_0 0x0 /* Word */ +#define EEPROM_NODE_ADDR_1 0x1 /* Word */ +#define EEPROM_NODE_ADDR_2 0x2 /* Word */ +#define EEPROM_PROD_ID 0x3 /* 0x9[0-f]50 */ +#define EEPROM_MFG_ID 0x7 /* 0x6d50 */ +#define EEPROM_ADDR_CFG 0x8 /* Base addr */ +#define EEPROM_RESOURCE_CFG 0x9 /* IRQ. Bits 12-15 */ + +/************************************************************************** + * * + * These are the registers for the 3Com 3c509 and their bit patterns when * + * applicable. They have been taken out the the "EtherLink III Parallel * + * Tasking EISA and ISA Technical Reference" "Beta Draft 10/30/92" manual * + * from 3com. * + * * + **************************************************************************/ + +#define EP_COMMAND 0x0e /* Write. BASE+0x0e is always a + * command reg. */ +#define EP_STATUS 0x0e /* Read. BASE+0x0e is always status + * reg. */ +#define EP_WINDOW 0x0f /* Read. BASE+0x0f is always window + * reg. */ +/* + * Window 0 registers. Setup. + */ +/* Write */ +#define EP_W0_EEPROM_DATA 0x0c +#define EP_W0_EEPROM_COMMAND 0x0a +#define EP_W0_RESOURCE_CFG 0x08 +#define EP_W0_ADDRESS_CFG 0x06 +#define EP_W0_CONFIG_CTRL 0x04 +/* Read */ +#define EP_W0_PRODUCT_ID 0x02 +#define EP_W0_MFG_ID 0x00 + +/* + * Window 1 registers. Operating Set. + */ +/* Write */ +#define EP_W1_TX_PIO_WR_2 0x02 +#define EP_W1_TX_PIO_WR_1 0x00 +/* Read */ +#define EP_W1_FREE_TX 0x0c +#define EP_W1_TX_STATUS 0x0b /* byte */ +#define EP_W1_TIMER 0x0a /* byte */ +#define EP_W1_RX_STATUS 0x08 +#define EP_W1_RX_PIO_RD_2 0x02 +#define EP_W1_RX_PIO_RD_1 0x00 + +/* + * Window 2 registers. Station Address Setup/Read + */ +/* Read/Write */ +#define EP_W2_ADDR_5 0x05 +#define EP_W2_ADDR_4 0x04 +#define EP_W2_ADDR_3 0x03 +#define EP_W2_ADDR_2 0x02 +#define EP_W2_ADDR_1 0x01 +#define EP_W2_ADDR_0 0x00 + +/* + * Window 3 registers. FIFO Management. + */ +/* Read */ +#define EP_W3_FREE_TX 0x0c +#define EP_W3_FREE_RX 0x0a + +/* + * Window 4 registers. Diagnostics. + */ +/* Read/Write */ +#define EP_W4_MEDIA_TYPE 0x0a +#define EP_W4_CTRLR_STATUS 0x08 +#define EP_W4_NET_DIAG 0x06 +#define EP_W4_FIFO_DIAG 0x04 +#define EP_W4_HOST_DIAG 0x02 +#define EP_W4_TX_DIAG 0x00 + +/* + * Window 5 Registers. Results and Internal status. + */ +/* Read */ +#define EP_W5_READ_0_MASK 0x0c +#define EP_W5_INTR_MASK 0x0a +#define EP_W5_RX_FILTER 0x08 +#define EP_W5_RX_EARLY_THRESH 0x06 +#define EP_W5_TX_AVAIL_THRESH 0x02 +#define EP_W5_TX_START_THRESH 0x00 + +/* + * Window 6 registers. Statistics. + */ +/* Read/Write */ +#define TX_TOTAL_OK 0x0c +#define RX_TOTAL_OK 0x0a +#define TX_DEFERRALS 0x08 +#define RX_FRAMES_OK 0x07 +#define TX_FRAMES_OK 0x06 +#define RX_OVERRUNS 0x05 +#define TX_COLLISIONS 0x04 +#define TX_AFTER_1_COLLISION 0x03 +#define TX_AFTER_X_COLLISIONS 0x02 +#define TX_NO_SQE 0x01 +#define TX_CD_LOST 0x00 + +/**************************************** + * + * Register definitions. + * + ****************************************/ + +/* + * Command register. All windows. + * + * 16 bit register. + * 15-11: 5-bit code for command to be executed. + * 10-0: 11-bit arg if any. For commands with no args; + * this can be set to anything. + */ +#define GLOBAL_RESET (u_short) 0x0000 /* Wait at least 1ms + * after issuing */ +#define WINDOW_SELECT (u_short) (0x1<<11) +#define START_TRANSCEIVER (u_short) (0x2<<11) /* Read ADDR_CFG reg to + * determine whether + * this is needed. If + * so; wait 800 uSec + * before using trans- + * ceiver. */ +#define RX_DISABLE (u_short) (0x3<<11) /* state disabled on + * power-up */ +#define RX_ENABLE (u_short) (0x4<<11) +#define RX_RESET (u_short) (0x5<<11) +#define RX_DISCARD_TOP_PACK (u_short) (0x8<<11) +#define TX_ENABLE (u_short) (0x9<<11) +#define TX_DISABLE (u_short) (0xa<<11) +#define TX_RESET (u_short) (0xb<<11) +#define REQ_INTR (u_short) (0xc<<11) +#define SET_INTR_MASK (u_short) (0xe<<11) +#define SET_RD_0_MASK (u_short) (0xf<<11) +#define SET_RX_FILTER (u_short) (0x10<<11) +#define FIL_INDIVIDUAL (u_short) (0x1) +#define FIL_GROUP (u_short) (0x2) +#define FIL_BRDCST (u_short) (0x4) +#define FIL_ALL (u_short) (0x8) +#define SET_RX_EARLY_THRESH (u_short) (0x11<<11) +#define SET_TX_AVAIL_THRESH (u_short) (0x12<<11) +#define SET_TX_START_THRESH (u_short) (0x13<<11) +#define STATS_ENABLE (u_short) (0x15<<11) +#define STATS_DISABLE (u_short) (0x16<<11) +#define STOP_TRANSCEIVER (u_short) (0x17<<11) +/* + * The following C_* acknowledge the various interrupts. Some of them don't + * do anything. See the manual. + */ +#define ACK_INTR (u_short) (0x6800) +#define C_INTR_LATCH (u_short) (ACK_INTR|0x1) +#define C_CARD_FAILURE (u_short) (ACK_INTR|0x2) +#define C_TX_COMPLETE (u_short) (ACK_INTR|0x4) +#define C_TX_AVAIL (u_short) (ACK_INTR|0x8) +#define C_RX_COMPLETE (u_short) (ACK_INTR|0x10) +#define C_RX_EARLY (u_short) (ACK_INTR|0x20) +#define C_INT_RQD (u_short) (ACK_INTR|0x40) +#define C_UPD_STATS (u_short) (ACK_INTR|0x80) +#define C_MASK (u_short) 0xFF /* mask of C_* */ + +/* + * Status register. All windows. + * + * 15-13: Window number(0-7). + * 12: Command_in_progress. + * 11: reserved. + * 10: reserved. + * 9: reserved. + * 8: reserved. + * 7: Update Statistics. + * 6: Interrupt Requested. + * 5: RX Early. + * 4: RX Complete. + * 3: TX Available. + * 2: TX Complete. + * 1: Adapter Failure. + * 0: Interrupt Latch. + */ +#define S_INTR_LATCH (u_short) (0x1) +#define S_CARD_FAILURE (u_short) (0x2) +#define S_TX_COMPLETE (u_short) (0x4) +#define S_TX_AVAIL (u_short) (0x8) +#define S_RX_COMPLETE (u_short) (0x10) +#define S_RX_EARLY (u_short) (0x20) +#define S_INT_RQD (u_short) (0x40) +#define S_UPD_STATS (u_short) (0x80) +#define S_MASK (u_short) 0xFF /* mask of S_* */ +#define S_5_INTS (S_CARD_FAILURE|S_TX_COMPLETE|\ + S_TX_AVAIL|S_RX_COMPLETE|S_RX_EARLY) +#define S_COMMAND_IN_PROGRESS (u_short) (0x1000) + +/* Address Config. Register. + * Window 0/Port 06 + */ + +#define ACF_CONNECTOR_BITS 14 +#define ACF_CONNECTOR_UTP 0 +#define ACF_CONNECTOR_AUI 1 +#define ACF_CONNECTOR_BNC 3 + +/* Resource configuration register. + * Window 0/Port 08 + * + */ + +#define SET_IRQ(base,irq) outw((base) + EP_W0_RESOURCE_CFG, \ + ((inw((base) + EP_W0_RESOURCE_CFG) & 0x0fff) | \ + ((u_short)(irq)<<12)) ) /* set IRQ i */ + +/* + * FIFO Registers. + * RX Status. Window 1/Port 08 + * + * 15: Incomplete or FIFO empty. + * 14: 1: Error in RX Packet 0: Incomplete or no error. + * 13-11: Type of error. + * 1000 = Overrun. + * 1011 = Run Packet Error. + * 1100 = Alignment Error. + * 1101 = CRC Error. + * 1001 = Oversize Packet Error (>1514 bytes) + * 0010 = Dribble Bits. + * (all other error codes, no errors.) + * + * 10-0: RX Bytes (0-1514) + */ +#define ERR_RX_INCOMPLETE (u_short) (0x1<<15) +#define ERR_RX (u_short) (0x1<<14) +#define ERR_RX_OVERRUN (u_short) (0x8<<11) +#define ERR_RX_RUN_PKT (u_short) (0xb<<11) +#define ERR_RX_ALIGN (u_short) (0xc<<11) +#define ERR_RX_CRC (u_short) (0xd<<11) +#define ERR_RX_OVERSIZE (u_short) (0x9<<11) +#define ERR_RX_DRIBBLE (u_short) (0x2<<11) + +/* + * FIFO Registers. + * TX Status. Window 1/Port 0B + * + * Reports the transmit status of a completed transmission. Writing this + * register pops the transmit completion stack. + * + * Window 1/Port 0x0b. + * + * 7: Complete + * 6: Interrupt on successful transmission requested. + * 5: Jabber Error (TP Only, TX Reset required. ) + * 4: Underrun (TX Reset required. ) + * 3: Maximum Collisions. + * 2: TX Status Overflow. + * 1-0: Undefined. + * + */ +#define TXS_COMPLETE 0x80 +#define TXS_SUCCES_INTR_REQ 0x40 +#define TXS_JABBER 0x20 +#define TXS_UNDERRUN 0x10 +#define TXS_MAX_COLLISION 0x8 +#define TXS_STATUS_OVERFLOW 0x4 + +/* + * Configuration control register. + * Window 0/Port 04 + */ +/* Read */ +#define IS_AUI (1<<13) +#define IS_BNC (1<<12) +#define IS_UTP (1<<9) +/* Write */ +#define ENABLE_DRQ_IRQ 0x0001 +#define W0_P4_CMD_RESET_ADAPTER 0x4 +#define W0_P4_CMD_ENABLE_ADAPTER 0x1 +/* + * Media type and status. + * Window 4/Port 0A + */ +#define ENABLE_UTP 0xc0 +#define DISABLE_UTP 0x0 + +/* + * Misc defines for various things. + */ +#define ACTIVATE_ADAPTER_TO_CONFIG 0xff /* to the id_port */ +#define MFG_ID 0x6d50 /* in EEPROM and W0 ADDR_CONFIG */ +#define PROD_ID 0x9150 + +#define AUI 0x1 +#define BNC 0x2 +#define UTP 0x4 + +#define RX_BYTES_MASK (u_short) (0x07ff) + diff --git a/c/src/lib/libbsp/i386/pc386/3c509/Makefile.in b/c/src/lib/libbsp/i386/pc386/3c509/Makefile.in new file mode 100644 index 0000000000..6e926826dc --- /dev/null +++ b/c/src/lib/libbsp/i386/pc386/3c509/Makefile.in @@ -0,0 +1,65 @@ +# +# $Id$ +# + +@SET_MAKE@ +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +top_builddir = ../../../../../../.. +subdir = c/src/lib/libbsp/i386/pc386/3c509 + +INSTALL = @INSTALL@ + +RTEMS_ROOT = $(top_srcdir)/@RTEMS_TOPdir@ +PROJECT_ROOT = @PROJECT_ROOT@ + +VPATH = @srcdir@ + +PGM=${ARCH}/3c509.rel + +# C source names, if any, go here -- minus the .c +C_PIECES=3c509 elink +C_FILES=$(C_PIECES:%=%.c) +C_O_FILES=$(C_PIECES:%=${ARCH}/%.o) + +H_FILES= + +SRCS=$(C_FILES) $(H_FILES) +OBJS=$(C_O_FILES) + +include $(RTEMS_ROOT)/make/custom/${RTEMS_BSP}.cfg +include $(RTEMS_ROOT)/make/leaf.cfg + +# +# (OPTIONAL) Add local stuff here using += +# + +DEFINES += -D__INSIDE_RTEMS_BSD_TCPIP_STACK__ +CPPFLAGS += +CFLAGS += + +LD_PATHS += +LD_LIBS += +LDFLAGS += + +# +# Add your list of files to delete here. The config files +# already know how to delete some stuff, so you may want +# to just run 'make clean' first to see what gets missed. +# 'make clobber' already includes 'make clean' +# + +CLEAN_ADDITIONS += +CLOBBER_ADDITIONS += + +${PGM}: ${SRCS} ${OBJS} + $(make-rel) + +all: ${ARCH} $(SRCS) $(PGM) + +# the .rel file built here will be put into libbsp.a by ../wrapup/Makefile +install: all + +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + cd $(top_builddir) \ + && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status diff --git a/c/src/lib/libbsp/i386/pc386/3c509/elink.c b/c/src/lib/libbsp/i386/pc386/3c509/elink.c new file mode 100644 index 0000000000..064d747143 --- /dev/null +++ b/c/src/lib/libbsp/i386/pc386/3c509/elink.c @@ -0,0 +1,78 @@ +/* + * Copyright (c) 1994 Charles Hannum. 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 Charles Hannum. + * 4. The name of the author 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. + * + * $Id$ + */ + +/* + * Common code for dealing with 3COM ethernet cards. + */ + +#include + +#include "elink.h" + + +extern void outb( unsigned short io_addr, unsigned char out_data ); + +/* + * Issue a `global reset' to all cards. We have to be careful to do this only + * once during autoconfig, to prevent resetting boards that have already been + * configured. + */ +void +elink_reset() +{ + static int x = 0; + + if (x == 0) { + x = 1; + outb(ELINK_ID_PORT, ELINK_RESET); + } +} + +/* + * The `ID sequence' is really just snapshots of an 8-bit CRC register as 0 + * bits are shifted in. Different board types use different polynomials. + */ +void +elink_idseq(u_char p) +{ + register int i; + register u_char c; + + c = 0xff; + for (i = 255; i; i--) { + outb(ELINK_ID_PORT, c); + if (c & 0x80) { + c <<= 1; + c ^= p; + } else + c <<= 1; + } +} diff --git a/c/src/lib/libbsp/i386/pc386/3c509/elink.h b/c/src/lib/libbsp/i386/pc386/3c509/elink.h new file mode 100644 index 0000000000..66e099ecf3 --- /dev/null +++ b/c/src/lib/libbsp/i386/pc386/3c509/elink.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 1994 Charles Hannum. 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 Charles Hannum. + * 4. The name of the author 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. + * + * $Id$ + */ + +#ifdef PC98 +#define ELINK_ID_PORT 0x71d0 +#else +#define ELINK_ID_PORT 0x110 +#endif +#define ELINK_RESET 0xc0 + +#define ELINK_507_POLY 0xe7 +#define ELINK_509_POLY 0xcf + +extern void elink_reset ( void ); +extern void elink_idseq ( u_char p ); diff --git a/c/src/lib/libbsp/i386/pc386/Makefile.in b/c/src/lib/libbsp/i386/pc386/Makefile.in index f2215728c4..2827b729a4 100644 --- a/c/src/lib/libbsp/i386/pc386/Makefile.in +++ b/c/src/lib/libbsp/i386/pc386/Makefile.in @@ -19,7 +19,7 @@ include $(RTEMS_ROOT)/make/custom/${RTEMS_BSP}.cfg include $(RTEMS_ROOT)/make/directory.cfg # We only build the Network library if HAS_NETWORKING was defined -NETWORK_yes_V = dec21140 ne2000 wd8003 +NETWORK_yes_V = dec21140 ne2000 wd8003 3c509 NETWORK = $(NETWORK_$(HAS_NETWORKING)_V) # wrapup is the one that actually builds and installs the library diff --git a/c/src/lib/libbsp/i386/pc386/wrapup/Makefile.in b/c/src/lib/libbsp/i386/pc386/wrapup/Makefile.in index 9b5c8073e6..fce8c0c3e1 100644 --- a/c/src/lib/libbsp/i386/pc386/wrapup/Makefile.in +++ b/c/src/lib/libbsp/i386/pc386/wrapup/Makefile.in @@ -16,7 +16,7 @@ PROJECT_ROOT = @PROJECT_ROOT@ VPATH = @srcdir@ # We only build the Network library if HAS_NETWORKING was defined -NETWORK_yes_V = dec21140 ne2000 wd8003 +NETWORK_yes_V = dec21140 ne2000 wd8003 3c509 NETWORK = $(NETWORK_$(HAS_NETWORKING)_V) BSP_PIECES=startup clock console timer $(NETWORK) -- cgit v1.2.3