summaryrefslogtreecommitdiffstats
path: root/bsps/i386/pc386/net/3c509.c
diff options
context:
space:
mode:
Diffstat (limited to 'bsps/i386/pc386/net/3c509.c')
-rw-r--r--bsps/i386/pc386/net/3c509.c1538
1 files changed, 0 insertions, 1538 deletions
diff --git a/bsps/i386/pc386/net/3c509.c b/bsps/i386/pc386/net/3c509.c
deleted file mode 100644
index b30ad03573..0000000000
--- a/bsps/i386/pc386/net/3c509.c
+++ /dev/null
@@ -1,1538 +0,0 @@
-/*
- * 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
- */
-
-#include <machine/rtems-bsd-kernel-space.h>
-
-#include <bsp.h>
-
-#include <stdio.h>
-#include <stdarg.h>
-#include <errno.h>
-#include <rtems/error.h>
-#include <rtems/rtems_bsdnet.h>
-#include <assert.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 <bsp/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_id rxDaemonTid;
- rtems_id txDaemonTid;
- rtems_vector_number name;
-
- 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, uint8_t *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, uint8_t *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, uint8_t *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, uint8_t *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, uint8_t *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, uint8_t *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.
- *
- **********************************************************************************/
-static __inline void outb( unsigned short io_addr, uint8_t out_data )
-{
- outport_byte( io_addr, out_data );
-}
-
-/**********************************************************************************
- *
- * DESCRIPTION: Routine to read a word as defined in FreeBSD.
- *
- * RETURNS: byte read.
- *
- **********************************************************************************/
-static __inline uint8_t inb( unsigned short io_addr )
-{
- uint8_t 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:
- * Driver interrupt handler. This routine is called by the RTEMS kernel when this
- * interrupt is raised.
- *
- * RETURNS: nothing.
- *
- **********************************************************************************/
-static rtems_isr ap_interrupt_handler(void *arg)
-{
- struct ep_softc *sc = (struct ep_softc *)arg;
-
- /* 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_bsdnet_event_send( sc->rxDaemonTid, INTERRUPT_EVENT );
-}
-
-/**********************************************************************************
- *
- * DESCRIPTION:
- * Initializes the ethernet hardware.
- *
- * RETURNS: nothing.
- *
- **********************************************************************************/
-static void _3c509_initialize_hardware (struct ep_softc *sc)
-{
- rtems_status_code status;
-
- epinit( sc );
-
- /*
- * Set up interrupts
- */
- printf ("3c509: IRQ with Kernel: %d\n", (int)sc->name );
- status = rtems_interrupt_handler_install(
- sc->name,
- "3c509",
- RTEMS_INTERRUPT_UNIQUE,
- ap_interrupt_handler,
- sc
- );
- assert(status == RTEMS_SUCCESSFUL);
-}
-
-/**********************************************************************************
- *
- * 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_bsdnet_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, ioctl_command_t 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->name = config->irno;
- else
- sc->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->name = irq;
-
- GO_WINDOW( 0 );
- SET_IRQ( BASE, irq );
-
- printf( "3C509: I/O=0x%x, IRQ=%d, CONNECTOR=%s, ",
- sc->ep_io_addr, (int)sc->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, uint8_t *), m->m_len / 4 );
- if( m->m_len & 3 )
- outsb(BASE + EP_W1_TX_PIO_WR_1, mtod(m, uint8_t *) + (m->m_len & (~3)), m->m_len & 3 );
- }
- else
- {
- outsw( BASE + EP_W1_TX_PIO_WR_1, mtod(m, uint8_t *), m->m_len / 2 );
- if( m->m_len & 1 )
- outb( BASE + EP_W1_TX_PIO_WR_1, *(mtod(m, uint8_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, uint8_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, uint8_t *) + m->m_len, lenthisone / 4);
- m->m_len += (lenthisone & ~3);
- if (lenthisone & 3)
- insb(BASE + EP_W1_RX_PIO_RD_1, mtod(m, uint8_t *) + m->m_len, lenthisone & 3);
- m->m_len += (lenthisone & 3);
- }
- else
- {
- insw(BASE + EP_W1_RX_PIO_RD_1, mtod(m, uint8_t *) + m->m_len, lenthisone / 2);
- m->m_len += lenthisone;
- if( lenthisone & 1 )
- *(mtod(m, uint8_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+" ); */
-}