*BSD News Article 18751


Return to BSD News archive

Xref: sserve comp.os.386bsd.development:959 comp.os.386bsd.misc:617
Path: sserve!newshost.anu.edu.au!munnari.oz.au!news.Hawaii.Edu!ames!elroy.jpl.nasa.gov!swrinde!cs.utexas.edu!uwm.edu!ogicse!psgrain!agora!implode!davidg
From: davidg@implode.rain.com (David Greenman)
Newsgroups: comp.os.386bsd.development,comp.os.386bsd.misc
Subject: New ethernet device driver for WD/SMC 80x3 and 3Com 3c503
Message-ID: <CAL2KI.26o@implode.rain.com>
Date: 22 Jul 93 20:36:18 GMT
Article-I.D.: implode.CAL2KI.26o
Organization: Delta Systems, Portland, OR.
Lines: 2878


   What follows is the first 'production' release of my 'ed' device driver.
If you have any problems, please try hard to solve them yourself before
sending me email or posting to the net. This code has been quite thoroughly
tested, so if you have problems it is more than likely a problem with your
configuration than with the driver.
   Please read the release notes carefully, they should answer most of the
common questions. Hopefully this will be turned into a manual page sometime
in the near future.

David Greenman
davidg@implode.rain.com

----------------------------------------------------------------------------
# This is a shell archive.  Save it in a file, remove anything before
# this line, and then unpack it by entering "sh file".  Note, it may
# create directories; files and directories will be owned by you and
# have default permissions.
#
# This archive contains:
#
#	ed.relnotes
#	if_ed.c
#	if_edreg.h
#
echo x - ed.relnotes
sed 's/^X//' >ed.relnotes << 'END-of-ed.relnotes'
X
X		Release Notes for 'ed' Device Driver
X		    David Greenman, 24-May-1993
X		------------------------------------
X
XLast updated: 20-July-1993
X
XINTRODUCTION
X------------
X   The 'ed' device driver is a new, high performance device driver supporting
XWestern Digital/SMC 80x3 series (including 'EtherCard PLUS' 'Elite16') and the
X3Com 3c503. All of the ethernet controllers use the DS8390 or 83C690 Network
XInterface Controller (NIC). The differences between the boards are in their
Xmemory capacity, bus width (8/16 bits), and special logic (asic) used to
Xconfigure the shared memory and other things. Every effort has been made to
Xconform to the manufactures' specifications for the NIC and asic. This includes
Xboth normal operation and error recovery.
X
XPERFORMANCE
X-----------
X
Xtransmit
X--------
X   The 8390 doesn't provide a mechanism for chained write buffers, so it is
Xvery important for maximum performance to queue the next packet for
Xtransmission as soon as the current one has completed. On boards with 16k or
Xmore of memory, the shared memory is divided in a way that allows enough space
Xfor two full size packets to be buffered for transmission. When sufficient
Xdata is available for transmission, a packet is copied into the shared memory,
Xthe transmission is started, and then an additional packet is copied into the
Xshared memory (to a different memory area). As soon as the first packet has
Xcompleted, transmission of a second packet can then be started immediately -
Xin less time than the 9.6us interframe gap. This results in the highest
Xperformance possible from ethernet.
X
XPackets go out on the 'wire' with the following format:
X
Xpreamble  dest-addr  src-addr  type      data      FCS   intr-frame
X64bits     48bits     48bits  16bits   1500bytes  32bits   96bits
X
X   With 10Mbits/sec, each bit is 100ns in duration. All of the above fields,
Xexcept for data are of fixed length. With full sized packets (1500 bytes), the
Xmaximum unidirectional data rate can be calculated as: 6.4us + 4.8us + 4.8us +
X1.6us + 1200us + 3.2us + 9.6us = 1230.4us/packet = 812.74382 packets/second =
X1219115.7 (1190k) bytes/second. With TCP, there is a 40 byte overhead for the
XIP and TCP headers, so there is only 1460 bytes of data per packet. This
Xreduces the maximum data rate to 1186606 bytes/second. With TCP, there will
Xalso be periodic acknowledgments which will reduce this figure somewhat both
Xbecause of the additional traffic in the reverse direction and because of the
Xoccasional collisions that this will cause. Despite this, the data rate has
Xstill been consistantly measured at 1125000 (~1100k) bytes/second through a TCP
Xsocket. In these tests, the TCP window was set to 16384 bytes. With UDP, there
Xis less overhead for the headers, and with 1472 bytes of data per packet, a
Xdata rate of 1196358.9 (1168k) bytes/sec is possible. UDP performance hasn't
Xbeen precisely measured with this device driver, but less precise tests show
Xthis to be true (measured at around 1135k/second).
X
Xreceive
X-------
X   The 8390 implements a shared memory ring-buffer to store incoming packets.
XThe 8bit boards (3c503, and 8003) usually have only 8k bytes of shared memory.
XThis is only enough room for about 4 full size (1500 byte) packets. This can
Xsometimes be a problem, especially on the original WD8003E and 3c503. This is
Xbecause these boards' shared memory access speed is also quite slow compared
Xto newer boards - typically only about 1MB/second. The additional overhead of
Xthis slow memory access, and the fact that there is only room for 4 full-sized
Xpackets means that the ring-buffer will occassionally overflow. When this
Xhappens, the board must be reset to avoid a lockup problem in early revision
X8390's. Resetting the board will cause all of the data in the ring-buffer to
Xbe lost - requiring it to be re-transmitted/received...slowing things even
Xfurther. Because of these problems, maximum throughput on boards of this type
Xis only about 400-600k per second. The 16bit boards (8013 series), however,
Xhave 16k of memory as well as much faster memory access speed. Typical memory
Xaccess speed on these boards is about 4MB/second. These boards generally have
Xno problems keeping up with full ethernet speed. The only problem I've seen
Xwith these boards is related to the (slow) performance of 386BSD's malloc code
Xwhen additional mbufs must be added to the pool. This can sometimes increase
Xthe total time to remove a packet enough for a ring-buffer overflow to occur.
XThis tends to be highly transient, and quite rare on fast machines. I've only
Xseen this problem when doing tests with large amounts of UDP traffic without
Xany acknowledgments (uni-directional). Again, this has been very rare.
X
X   All of the above tests were done using a 486DX2/66, 486DX/33, 386DX/40,
X8-9Mhz ISA bus, with Bruce Evans' high speed spl()/interrupt modifications, a
Xhigh performance version of in_cksum.c from Bakul Shah, with tcp_sendspace/
Xtcp_recvspace set to 16k, and MCLBYTES set to 2048 (to allow full MTU sized
Xpackets). TCP tests were done with the 'ttcp' performance test utility, and
Xalso with FTP client/server. UDP tests were done with a modified version of
Xttcp (to work around a bug in 386BSD's UDP code related to queue depth), and
Xalso with NFS.
X
XKERNEL INSTALLATION
X-------------------
X   To 'install' this driver, the files if_ed.c and if_edreg.h must be copied
Xinto the i386/isa kernel source directory and the following line must be
Xadded into the file i386/conf/files.i386:
X
Xi386/isa/if_ed.c        optional ed device-driver
X
X   To build a kernel that includes this driver, first comment out any 'we'
Xor 'ec' devices in your kernel config file. Then, add a line similar to
Xthe following (modify to match your cards configuration):
X
Xdevice ed0 at isa? port 0x300 net irq 10 iomem 0xcc000 vector edintr
X
X   Note that the 'iosiz' option is not needed because the driver automatically
Xfigures this out. However, if you have problems with this, it can be specified
Xto force the use of the size you specify.
X   On 3Com boards, the tranceiver must be enabled in software (there is no
Xhardware default). In this driver, this is controlled using the "LLC0" link-
Xlevel control flag. The default for this flag can be set in your kernel config
Xfile by specifying 'flags 0x01' in the 'ed' device specification line (this
Xis necessary for diskless support). Otherwise, the tranceiver is easily enabled
Xand disabled with a command like "ifconfig ed0 -LLC0" to enable the tranceiver
Xor "ifconfig ed0 LLC0" to disable it; this assumes that you have the modified
Xifconfig(8) that originally appeared in the 386BSD patchkit. To specify the
X'flags' option, use a line similar to:
X
Xdevice ed0 at isa? port 0x300 net irq 10 flags 0x01 iomem 0xcc000 vector edintr
X
X   Flags can be similarly specified to force 8 or 16bit mode, and disabling
Xthe use of transmitter double buffering. The various supported flag values
Xare:
X
X	FORCE_8BIT_MODE			0x02
X	FORCE_16BIT_MODE		0x04
X	DISABLE_DOUBLE_BUFFERING	0x08
X
X   To use multiple flags, simply add the values together. Note that these
Xnumbers are in hexadecimal. If the FORCE_8BIT and FORCE_16BIT flags are
Xboth specified, the 8BIT flag has precedence.
X   The use of the above flags should only be necessary under exceptional
Xconditions where the probe routine incorrectly determines the board type. Or
Xwhere the high performance of the transmitter causes problems with other
Xvendors hardware.
X
X
XKNOWN PROBLEMS
X--------------
X
X1) Early revision DS8390B chips have problems. They lock-up whenever the
X	receive ring-buffer overflows. They occassionally switch the byte order
X	of the length field in the packet ring header (several different causes
X	of this related to an off-by-one byte alignment) - resulting in "shared
X	memory corrupt - invalid length NNNNN" messages. The board is reset
X	whenever these problems occur, but otherwise there is no problem with
X	recovering from these conditions.
X2) 16bit boards can conflict with 8bit BIOSs, BIOS extensions (like the VGA),
X	and 8bit devices with shared memory (again like the VGA, or perhaps a
X	second ethernet board). There is a work-around for this in the driver,
X	however. The problem is that the ethernet board stays in 16bit mode,
X	asserting its '16bit' signal on the ISA bus. This signal is shared by
X	other devices/ROMs in the same 128K memory segment as the ethernet card
X	- causing the CPU to read the 8bit ROMs as if they were 16bit wide.
X	The work-around involves setting the host access to the shared memory
X	to 16bits only when the memory is actually accessed, and setting it back
X	to 8bit mode all other times. Without this work-around, the machine will
X	hang whenever a reboot is attempted. This work-around also allows the
X	board to co-exist with other 8bit devices that have shared memory (like
X	8bit VGA boards or perhaps a second ethernet board). This has only been
X	implemented for SMC/WD boards, but I haven't seen this problem with
X	3Com boards (i.e. if you have a 3Com board, you might experiance the
X	above problem - I haven't specifically tested for it).
X3) 16bit 3c503 boards seem to have a memory contention problem between the NIC
X	and the on-board shared memory that causes periodic fifo-overruns. I'm
X	looking for a work-around, but haven't found one yet. When this problem
X	occurs, the 3c503 drops the packet. Other than re-tranmissions/reduced
X	performance, no other effects of this problem have been seen.
X4) The shared memory on 3Com boards is much slower than it is on SMC boards;
X	it's less than 2MB/second on the 16bit boards, and this can lead to
X	ring-buffer overruns resulting in additional lost data in heavy network
X	traffic. I'm working with 3Com on this problem too, but it looks pretty
X	hopeless.
X5) Because the 16bit 3Com boards bank switch their memory in 8k banks, the
X	double buffering has not been implemented in those boards. Doing so
X	would significantly complicate the code. Not really a bug, but rather
X	a limitation that might be removed in the future.
END-of-ed.relnotes
echo x - if_ed.c
sed 's/^X//' >if_ed.c << 'END-of-if_ed.c'
X/*
X * Device driver for National Semiconductor DS8390 based ethernet
X *   adapters. By David Greenman, 29-April-1993
X *
X * Copyright (C) 1993, David Greenman. This software may be used, modified,
X *   copied, distributed, and sold, in both source and binary form provided
X *   that the above copyright and these terms are retained. Under no
X *   circumstances is the author responsible for the proper functioning
X *   of this software, nor does the author assume any responsibility
X *   for damages incurred with its use.
X *
X * Currently supports the Western Digital/SMC 8003 and 8013 series
X *   and the 3Com 3c503
X */
X
X/*
X * Modification history
X *
X * $Log:	if_ed.c,v $
X * Revision 1.14  93/07/20  15:24:25  davidg
X * ommision for force 16bit case fixed from last patch
X * 
X * Revision 1.13  93/07/20  15:13:55  davidg
X * Added config file override for memsize by using 'iosiz'. Also added
X * config flags overrides to force 8/16bit mode and disable the use of
X * double xmit buffers.
X * 
X * Revision 1.12  93/07/07  06:27:44  davidg
X * moved call to bpfattach to after this drivers attach printf -
X * improves readability of startup messages.
X * 
X * Revision 1.11  93/06/27  03:07:01  davidg
X * fixed bugs in the 3Com part of the probe routine that were uncovered by
X * the previous fix.
X * 
X * Revision 1.10  93/06/25  19:23:19  davidg
X * fixed bug that caused erroneous 'Invalid irq configuration' message when
X * no board is present (during autoconfiguration).
X * 
X * Revision 1.9  93/06/23  03:48:14  davidg
X * fixed minor typo introduced when cleaning up probe routine
X * 
X * Revision 1.8  93/06/23  03:37:19  davidg
X * cleaned up/added some comments. Also improved readability of a part of
X * the probe routine.
X * 
X * Revision 1.7  93/06/22  04:45:01  davidg
X * (no additional changes) Second beta release
X * 
X * Revision 1.6  93/06/22  04:40:35  davidg
X * minor definition fix to ed_reset()
X * 
X * Revision 1.5  93/06/22  04:37:39  davidg
X * fixed some comments
X * 
X * Revision 1.4  93/06/22  04:34:34  davidg
X * added support to use the LLC0 'link-level control' flag
X * to disable the tranceiver for AUI operation on 3Com boards.
X * The default for this flag can be set in the kernel config
X * file - 'flags 0x01' sets the flag (disables the tranceiver).
X * 
X * Revision 1.3  93/06/17  03:57:28  davidg
X * fixed some printf's
X * 
X * Revision 1.2  93/06/17  03:26:49  davidg
X * fixed 3c503 code to determine 8/16bit board
X * changed attach printf to work with Interim-0.1.5 and NetBSD
X * 
X * Revision 1.1  93/06/14  22:21:24  davidg
X * Beta release of device driver for SMC/WD80x3 and 3C503 ethernet boards.
X * 
X * 
X */
X 
X#include "ed.h"
X#if	NED > 0
X#include "bpfilter.h"
X
X#include "param.h"
X#include "errno.h"
X#include "ioctl.h"
X#include "mbuf.h"
X#include "socket.h"
X#include "syslog.h"
X
X#include "net/if.h"
X#include "net/if_dl.h"
X#include "net/if_types.h"
X#include "net/netisr.h"
X
X#ifdef INET
X#include "netinet/in.h"
X#include "netinet/in_systm.h"
X#include "netinet/in_var.h"
X#include "netinet/ip.h"
X#include "netinet/if_ether.h"
X#endif
X
X#ifdef NS
X#include "netns/ns.h"
X#include "netns/ns_if.h"
X#endif
X
X#if NBPFILTER > 0
X#include "net/bpf.h"
X#include "net/bpfdesc.h"
X#endif
X
X#include "i386/isa/isa.h"
X#include "i386/isa/isa_device.h"
X#include "i386/isa/icu.h"
X#include "i386/isa/if_edreg.h"
X
X#include "i386/include/pio.h"
X
X 
X/*
X * ed_softc: per line info and status
X */
Xstruct	ed_softc {
X	struct	arpcom arpcom;	/* ethernet common */
X
X	char	*type_str;	/* pointer to type string */
X	u_char	vendor;		/* interface vendor */
X	u_char	type;		/* interface type code */
X
X	u_short	vector;		/* interrupt vector */
X	u_short	asic_addr;	/* ASIC I/O bus address */
X	u_short	nic_addr;	/* NIC (DS8390) I/O bus address */
X
X	caddr_t	smem_start;	/* shared memory start address */
X	caddr_t	smem_end;	/* shared memory end address */
X	u_long	smem_size;	/* total shared memory size */
X	caddr_t	smem_ring;	/* start of RX ring-buffer (in smem) */
X
X	caddr_t	bpf;		/* BPF "magic cookie" */
X
X	u_char	memwidth;	/* width of access to card mem 8 or 16 */
X	u_char	xmit_busy;	/* transmitter is busy */
X	u_char	txb_cnt;	/* Number of transmit buffers */
X	u_char	txb_next;	/* Pointer to next buffer ready to xmit */
X	u_short	txb_next_len;	/* next xmit buffer length */
X	u_char	data_buffered;	/* data has been buffered in interface memory */
X	u_char	tx_page_start;	/* first page of TX buffer area */
X
X	u_char	rec_page_start;	/* first page of RX ring-buffer */
X	u_char	rec_page_stop;	/* last page of RX ring-buffer */
X	u_char	next_packet;	/* pointer to next unread RX packet */
X} ed_softc[NED];
X
Xint	ed_attach(), ed_init(), edintr(), ed_ioctl(), ed_probe(),
X	ed_start(), ed_reset(), ed_watchdog();
X
Xstatic void ed_stop();
X
Xstatic inline void ed_rint();
Xstatic inline void ed_xmit();
Xstatic inline char *ed_ring_copy();
X
Xextern int ether_output();
X
Xstruct isa_driver eddriver = {
X	ed_probe,
X	ed_attach,
X	"ed"
X};
X/* 
X * Interrupt conversion table for WD/SMC ASIC
X * (IRQ* are defined in icu.h)
X */
Xstatic unsigned short ed_intr_mask[] = {
X	IRQ9,
X	IRQ3,
X	IRQ5,
X	IRQ7,
X	IRQ10,
X	IRQ11,
X	IRQ15,
X	IRQ4
X};
X	
X#define	ETHER_MIN_LEN	64
X#define ETHER_MAX_LEN	1518
X#define	ETHER_ADDR_LEN	6
X#define	ETHER_HDR_SIZE	14
X
X/*
X * Determine if the device is present
X *
X *   on entry:
X * 	a pointer to an isa_device struct
X *   on exit:
X *	NULL if device not found
X *	or # of i/o addresses used (if found)
X */
Xint
Xed_probe(isa_dev)
X	struct isa_device *isa_dev;
X{
X	struct ed_softc *sc = &ed_softc[isa_dev->id_unit];
X	int i, x;
X	u_int memsize;
X	u_char iptr, memwidth, sum, tmp;
X
X	/*
X	 * Setup initial i/o address for ASIC and NIC
X	 */
X	sc->asic_addr = isa_dev->id_iobase;
X	sc->vector = isa_dev->id_irq;
X	sc->smem_start = (caddr_t)isa_dev->id_maddr;
X 
X	/*
X	 * Attempt to do a checksum over the station address PROM.
X	 * This is mapped differently on the WD80x3 and 3C503, so if
X	 *	it fails, it might be a 3C503. There is a problem with
X	 *	this, though: some clone WD boards don't pass the
X	 *	checksum test. Danpex boards for one. We need to do
X	 *	additional checking for this case.
X	 */
X	for (sum = 0, i = 0; i < 8; ++i) {
X		sum += inb(sc->asic_addr + ED_WD_PROM + i);
X	}
X	
X	if (sum == ED_WD_ROM_CHECKSUM_TOTAL) {
X		goto type_WD80x3;
X	} else {
X		/*
X		 * Do additional checking to make sure its a 3Com and
X		 * not a broken WD clone
X		 */
X		goto type_3Com;
X	}
X
Xtype_WD80x3:
X	/*
X	 * Looks like a WD/SMC board
X	 */
X
X	sc->vendor = ED_VENDOR_WD_SMC;
X	sc->type = inb(sc->asic_addr + ED_WD_CARD_ID);
X
X	sc->nic_addr = sc->asic_addr + ED_WD_NIC_OFFSET;
X
X	/* reset card to force it into a known state. */
X	outb(sc->asic_addr + ED_WD_MSR, ED_WD_MSR_RST);
X	DELAY(100);
X	outb(sc->asic_addr + ED_WD_MSR, inb(sc->asic_addr + ED_WD_MSR) & ~ED_WD_MSR_RST);
X	/* wait in the case this card is reading it's EEROM */
X	DELAY(5000);
X
X	/*
X	 * Set initial values for width/size.
X	 */
X	switch (sc->type) {
X	case ED_TYPE_WD8003S:
X		sc->type_str = "WD8003S";
X		memsize = 8192;
X		memwidth = 8;
X		break;
X	case ED_TYPE_WD8003E:
X		sc->type_str = "WD8003E";
X		memsize = 8192;
X		memwidth = 8;
X		break;
X	case ED_TYPE_WD8013EBT:
X		sc->type_str = "WD8013EBT";
X		memsize = 16384;
X		memwidth = 16;
X		break;
X	case ED_TYPE_WD8013EB:		/* also WD8003EP */
X		if (inb(sc->asic_addr + ED_WD_ICR)
X			& ED_WD_ICR_16BIT) {
X			memwidth = 16;
X			memsize = 16384;
X			sc->type_str = "WD8013EB";
X		} else {
X			sc->type_str = "WD8003EP";
X			memsize = 8192;
X			memwidth = 8;
X		}
X		break;
X	case ED_TYPE_WD8013EBP:
X		sc->type_str = "WD8013EBP";
X		memsize = 16384;
X		memwidth = 16;
X		break;
X	case ED_TYPE_WD8013EPC:
X		sc->type_str = "WD8013EPC";
X		memsize = 16384;
X		memwidth = 16;
X		break;
X	default:
X		sc->type_str = "unknown";
X		memsize = 8192;
X		memwidth = 8;
X		break;
X	}
X	/*
X	 * Make some adjustments to initial values depending on what is
X	 *	found in the ICR.
X	 */
X	if ((memwidth==16)
X		&& ((inb(sc->asic_addr + ED_WD_ICR) & ED_WD_ICR_16BIT) == 0)) {
X		memwidth = 8;
X		memsize = 8192;
X	}
X	if (inb(sc->asic_addr + ED_WD_ICR) & ED_WD_ICR_MSZ) {
X		memsize = 32768;
X	}
X
X#if ED_DEBUG
X	printf("type=%s memwidth=%d memsize=%d id_msize=%d\n",
X		sc->type_str,memwidth,memsize,isa_dev->id_msize);
X	for (i=0; i<8; i++)
X		printf("%x -> %x\n", i, inb(sc->asic_addr + i));
X#endif
X	/*
X	 * Allow the user to override the autoconfiguration
X	 */
X	if (isa_dev->id_msize)
X		memsize = isa_dev->id_msize;
X	/*
X	 * (note that if the user specifies both of the following flags
X	 *	that '8bit' mode intentionally has precedence)
X	 */
X	if (isa_dev->id_flags & ED_FLAGS_FORCE_16BIT_MODE)
X		memwidth = 16;
X	if (isa_dev->id_flags & ED_FLAGS_FORCE_8BIT_MODE)
X		memwidth = 8;
X
X	/*
X	 * Check 83C584 interrupt configuration register if this board has one
X	 *	XXX - we could also check the IO address register. But why
X	 *		bother...if we get past this, it *has* to be correct.
X	 */
X	if (sc->type & ED_WD_SOFTCONFIG) {
X		/*
X		 * Assemble together the encoded interrupt number.
X		 */
X		iptr = (inb(isa_dev->id_iobase + ED_WD_ICR) & ED_WD_ICR_IR2) |
X			((inb(isa_dev->id_iobase + ED_WD_IRR) &
X				(ED_WD_IRR_IR0 | ED_WD_IRR_IR1)) >> 5);
X		/*
X		 * Translate it using translation table, and check for correctness.
X		 */
X		if (ed_intr_mask[iptr] != isa_dev->id_irq) {
X			printf("ed%d: kernel configured irq doesn't match board configured irq\n",
X				isa_dev->id_unit);
X			return(0);
X		}
X		/*
X		 * Enable the interrupt.
X		 */
X		outb(isa_dev->id_iobase + ED_WD_IRR,
X			inb(isa_dev->id_iobase + ED_WD_IRR) | ED_WD_IRR_IEN);
X	}
X
X	sc->memwidth = memwidth;
X	/*
X	 * allocate one xmit buffer if < 16k, two buffers otherwise
X	 */
X	if ((memsize < 16384) || (isa_dev->id_msize & ED_FLAGS_NO_DOUBLE_BUFFERING)) {
X		sc->smem_ring = sc->smem_start + (ED_PAGE_SIZE * ED_TXBUF_SIZE);
X		sc->txb_cnt = 1;
X		sc->rec_page_start = ED_TXBUF_SIZE;
X	} else {
X		sc->smem_ring = sc->smem_start + (ED_PAGE_SIZE * ED_TXBUF_SIZE * 2);
X		sc->txb_cnt = 2;
X		sc->rec_page_start = ED_TXBUF_SIZE * 2;
X	}
X	sc->smem_size = memsize;
X	sc->smem_end = sc->smem_start + memsize;
X	sc->rec_page_stop = memsize / ED_PAGE_SIZE;
X	sc->tx_page_start = ED_WD_PAGE_OFFSET;
X
X	/*
X	 * Get station address from on-board ROM
X	 */
X	for (i = 0; i < ETHER_ADDR_LEN; ++i)
X		sc->arpcom.ac_enaddr[i] = inb(sc->asic_addr + ED_WD_PROM + i);
X
X	/*
X	 * Set address and enable interface shared memory.
X	 */
X        outb(sc->asic_addr + ED_WD_MSR, ((kvtop(sc->smem_start) >> 13) &
X		ED_WD_MSR_ADDR) | ED_WD_MSR_MENB);
X
X	/*
X	 * Set upper address bits and 8/16 bit access to shared memory
X	 */
X	if (sc->type & ED_WD_SOFTCONFIG) {
X		if (memwidth == 8) {
X			outb(sc->asic_addr + ED_WD_LAAR,
X			((kvtop(sc->smem_start) >> 19) & ED_WD_LAAR_ADDRHI));
X		} else {
X			outb(sc->asic_addr + ED_WD_LAAR,
X				ED_WD_LAAR_L16EN | ED_WD_LAAR_M16EN |
X				((kvtop(sc->smem_start) >> 19) & ED_WD_LAAR_ADDRHI));
X		}
X	}
X
X	/*
X	 * Now zero memory and verify that it is clear
X	 */
X	bzero(sc->smem_start, memsize);
X
X	for (i = 0; i < memsize; ++i)
X		if (sc->smem_start[i]) {
X	        	printf("ed%d: failed to clear shared memory at %x - check configuration\n",
X				isa_dev->id_unit, sc->smem_start + i);
X
X			/*
X			 * Disable 16 bit access to shared memory
X			 */
X			if (memwidth == 16)
X				outb(sc->asic_addr + ED_WD_LAAR,
X					inb(sc->asic_addr + ED_WD_LAAR)
X					& ~ED_WD_LAAR_M16EN);
X
X			return(0);
X		}
X	
X	/*
X	 * Disable 16bit access to shared memory - we leave it disabled so
X	 *	that 1) machines reboot properly when the board is set
X	 *	16 bit mode and there are conflicting 8bit devices/ROMS
X	 *	in the same 128k address space as this boards shared
X	 *	memory. and 2) so that other 8 bit devices with shared
X	 *	memory can be used in this 128k region, too.
X	 */
X	if (memwidth == 16)
X		outb(sc->asic_addr + ED_WD_LAAR, inb(sc->asic_addr + ED_WD_LAAR)
X			& ~ED_WD_LAAR_M16EN);
X
X	isa_dev->id_msize = memsize;
X	return (ED_WD_IO_PORTS);
X
Xtype_3Com:
X	/*
X	 * Looks like a 3Com board
X	 */
X
X	sc->vendor = ED_VENDOR_3COM;
X	sc->asic_addr = isa_dev->id_iobase + ED_3COM_ASIC_OFFSET;
X	sc->nic_addr = isa_dev->id_iobase + ED_3COM_NIC_OFFSET;
X
X	sc->type_str = "3c503";
X
X	memsize = 8192;
X
X	/*
X	 * Verify that the kernel configured I/O address matches the board
X	 *	configured address
X	 */
X	switch (inb(sc->asic_addr + ED_3COM_BCFR)) {
X	case ED_3COM_BCFR_300:
X		if (isa_dev->id_iobase != 0x300)
X			return(0);
X		break;
X	case ED_3COM_BCFR_310:
X		if (isa_dev->id_iobase != 0x310)
X			return(0);
X		break;
X	case ED_3COM_BCFR_330:
X		if (isa_dev->id_iobase != 0x330)
X			return(0);
X		break;
X	case ED_3COM_BCFR_350:
X		if (isa_dev->id_iobase != 0x350)
X			return(0);
X		break;
X	case ED_3COM_BCFR_250:
X		if (isa_dev->id_iobase != 0x250)
X			return(0);
X		break;
X	case ED_3COM_BCFR_280:
X		if (isa_dev->id_iobase != 0x280)
X			return(0);
X		break;
X	case ED_3COM_BCFR_2A0:
X		if (isa_dev->id_iobase != 0x2a0)
X			return(0);
X		break;
X	case ED_3COM_BCFR_2E0:
X		if (isa_dev->id_iobase != 0x2e0)
X			return(0);
X		break;
X	default:
X		return(0);
X	}
X
X	/*
X	 * Verify that the kernel shared memory address matches the
X	 *	board configured address.
X	 */
X	switch (inb(sc->asic_addr + ED_3COM_PCFR)) {
X	case ED_3COM_PCFR_DC000:
X		if (kvtop(isa_dev->id_maddr) != 0xdc000)
X			return(0);
X		break;
X	case ED_3COM_PCFR_D8000:
X		if (kvtop(isa_dev->id_maddr) != 0xd8000)
X			return(0);
X		break;
X	case ED_3COM_PCFR_CC000:
X		if (kvtop(isa_dev->id_maddr) != 0xcc000)
X			return(0);
X		break;
X	case ED_3COM_PCFR_C8000:
X		if (kvtop(isa_dev->id_maddr) != 0xc8000)
X			return(0);
X		break;
X	default:
X		return(0);
X	}
X
X	/*
X	 * Reset NIC and ASIC
X	 */
X	outb(sc->asic_addr + ED_3COM_CR, ED_3COM_CR_RST);
X	/*
X	 * Wait for a while, then un-reset it
X	 */
X	DELAY(5000);
X	outb(sc->asic_addr + ED_3COM_CR, 0);
X
X	/*
X	 * Wait a bit for the NIC to recover from the reset
X	 */
X	DELAY(5000);
X
X	/*
X	 * The 3Com ASIC defaults to rather strange settings for the CR after
X	 *	a reset - it's important to set it so that the NIC I/O
X	 *	registers are mapped. The above setting of it to '0' only
X	 *	resets the reset condition - the CR is *not* set to zeros.
X	 */
X	outb(sc->asic_addr + ED_3COM_CR, 0);
X
X	/*
X	 * Determine if this is an 8bit or 16bit board
X	 */
X
X	/*
X	 * select page 0 registers
X	 */
X        outb(sc->nic_addr + ED_P0_CR, ED_CR_RD2|ED_CR_STP);
X
X	/*
X	 * Attempt to clear WTS bit. If it doesn't clear, then this is a
X	 *	16bit board.
X	 */
X	outb(sc->nic_addr + ED_P0_DCR, 0);
X
X	/*
X	 * select page 2 registers
X	 */
X	outb(sc->nic_addr + ED_P0_CR, ED_CR_PAGE_2|ED_CR_RD2|ED_CR_STP);
X
X	/*
X	 * The 3c503 forces the WTS bit to a one if this is a 16bit board
X	 */
X	if (inb(sc->nic_addr + ED_P2_DCR) & ED_DCR_WTS)
X		memwidth = 16;
X	else
X		memwidth = 8;
X
X	/*
X	 * select page 0 registers
X	 */
X        outb(sc->nic_addr + ED_P2_CR, ED_CR_RD2|ED_CR_STP);
X
X	sc->txb_cnt = 1;
X
X	sc->tx_page_start = ED_3COM_PAGE_OFFSET;
X	sc->rec_page_start = ED_TXBUF_SIZE + ED_3COM_PAGE_OFFSET;
X	sc->rec_page_stop = memsize / ED_PAGE_SIZE + ED_3COM_PAGE_OFFSET;
X
X	sc->smem_size = memsize;
X	sc->smem_end = sc->smem_start + memsize;
X	sc->smem_ring = sc->smem_start + (ED_PAGE_SIZE * ED_TXBUF_SIZE);
X
X	sc->memwidth = memwidth;
X
X	/*
X	 * Initialize GA page start/stop registers. Probably only needed
X	 *	if doing DMA, but what the hell.
X	 */
X	outb(sc->asic_addr + ED_3COM_PSTR, sc->rec_page_start);
X	outb(sc->asic_addr + ED_3COM_PSPR, sc->rec_page_stop);
X
X	/*
X	 * Set IRQ. 3c503 only allows a choice of irq 2-5.
X	 */
X	switch (isa_dev->id_irq) {
X	case IRQ2:
X		outb(sc->asic_addr + ED_3COM_IDCFR, ED_3COM_IDCFR_IRQ2);
X		break;
X	case IRQ3:
X		outb(sc->asic_addr + ED_3COM_IDCFR, ED_3COM_IDCFR_IRQ3);
X		break;
X	case IRQ4:
X		outb(sc->asic_addr + ED_3COM_IDCFR, ED_3COM_IDCFR_IRQ4);
X		break;
X	case IRQ5:
X		outb(sc->asic_addr + ED_3COM_IDCFR, ED_3COM_IDCFR_IRQ5);
X		break;
X	default:
X		printf("ed%d: Invalid irq configuration\n", isa_dev->id_unit);
X		return(0);
X	}
X
X	/*
X	 * Initialize GA configuration register. Set bank and enable smem.
X	 */
X	outb(sc->asic_addr + ED_3COM_GACFR, ED_3COM_GACFR_RSEL |
X		ED_3COM_GACFR_MBS0);
X
X	/*
X	 * Initialize "Vector Pointer" registers. These gawd-awful things
X	 *	are compared to 20 bits of the address on ISA, and if they
X	 *	match, the shared memory is disabled. We set them to
X	 *	0xffff0...allegedly the reset vector.
X	 */
X	outb(sc->asic_addr + ED_3COM_VPTR2, 0xff);
X	outb(sc->asic_addr + ED_3COM_VPTR1, 0xff);
X	outb(sc->asic_addr + ED_3COM_VPTR0, 0x00);
X
X	/*
X	 * Get station address from on-board ROM
X	 */
X	/*
X	 * First, map ethernet address PROM over the top of where the NIC
X	 *	registers normally appear.
X	 */
X	outb(sc->asic_addr + ED_3COM_CR, ED_3COM_CR_EALO);
X
X	for (i = 0; i < ETHER_ADDR_LEN; ++i)
X		sc->arpcom.ac_enaddr[i] = inb(sc->nic_addr + i);
X
X	/*
X	 * Unmap PROM - select NIC registers. Tranceiver remains disabled at
X	 *	this point. It's enabled in ed_init so that the attach code
X	 *	is given a chance to set the default based on a compile-time
X	 *	config option
X	 */
X	outb(sc->asic_addr + ED_3COM_CR, 0);
X
X#if 0
Xprintf("Starting write\n");
Xfor (i = 0; i < 8192; ++i)
X	bzero(sc->smem_start, 8192);
Xprintf("Done.\n");
X#endif
X#if 0
X{ char	test_buf[1024];
Xprintf("starting write\n");
X	for (i = 0; i < 8*8192; ++i)
X	bcopy(test_buf, sc->smem_start, 1024);
Xprintf("starting read\n");
X	for (i = 0; i < 8*8192; ++i)
X	bcopy(sc->smem_start, test_buf, 1024);
Xprintf("done.\n");
X}
X#endif
X
X	/*
X	 * Zero memory and verify that it is clear
X	 */
X	bzero(sc->smem_start, memsize);
X
X	for (i = 0; i < memsize; ++i)
X		if (sc->smem_start[i]) {
X	        	printf("ed%d: failed to clear shared memory at %x - check configuration\n",
X				isa_dev->id_unit, sc->smem_start + i);
X			return(0);
X		}
X
X	isa_dev->id_msize = memsize;
X	return(ED_3COM_IO_PORTS);
X}
X 
X/*
X * Install interface into kernel networking data structures
X */
Xint
Xed_attach(isa_dev)
X	struct isa_device *isa_dev;
X{
X	struct ed_softc *sc = &ed_softc[isa_dev->id_unit];
X	struct ifnet *ifp = &sc->arpcom.ac_if;
X	struct ifaddr *ifa;
X	struct sockaddr_dl *sdl;
X 
X	/*
X	 * Set interface to stopped condition (reset)
X	 */
X	ed_stop(isa_dev->id_unit);
X
X	/*
X	 * Initialize ifnet structure
X	 */
X	ifp->if_unit = isa_dev->id_unit;
X	ifp->if_name = "ed" ;
X	ifp->if_mtu = ETHERMTU;
X	ifp->if_init = ed_init;
X	ifp->if_output = ether_output;
X	ifp->if_start = ed_start;
X	ifp->if_ioctl = ed_ioctl;
X	ifp->if_reset = ed_reset;
X	ifp->if_watchdog = ed_watchdog;
X
X	/*
X	 * Set default state for LLC0 flag (used to disable the tranceiver
X	 *	for AUI operation), based on compile-time config option.
X	 */
X	if (isa_dev->id_flags & ED_FLAGS_DISABLE_TRANCEIVER)
X		ifp->if_flags = (IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS
X			| IFF_LLC0);
X	else
X		ifp->if_flags = (IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS);
X
X	/*
X	 * Attach the interface
X	 */
X	if_attach(ifp);
X
X	/*
X	 * Search down the ifa address list looking for the AF_LINK type entry
X	 */
X 	ifa = ifp->if_addrlist;
X	while ((ifa != 0) && (ifa->ifa_addr != 0) &&
X	    (ifa->ifa_addr->sa_family != AF_LINK))
X		ifa = ifa->ifa_next;
X	/*
X	 * If we find an AF_LINK type entry we fill in the hardware address.
X	 *	This is useful for netstat(1) to keep track of which interface
X	 *	is which.
X	 */
X	if ((ifa != 0) && (ifa->ifa_addr != 0)) {
X		/*
X		 * Fill in the link-level address for this interface
X		 */
X		sdl = (struct sockaddr_dl *)ifa->ifa_addr;
X		sdl->sdl_type = IFT_ETHER;
X		sdl->sdl_alen = ETHER_ADDR_LEN;
X		sdl->sdl_slen = 0;
X		bcopy(sc->arpcom.ac_enaddr, LLADDR(sdl), ETHER_ADDR_LEN);
X	}
X
X	/*
X	 * Print additional info when attached
X	 */
X	printf("ed%d: address %s, type %s (%dbit) %s\n", isa_dev->id_unit,
X		ether_sprintf(sc->arpcom.ac_enaddr), sc->type_str,
X		sc->memwidth, ((sc->vendor == ED_VENDOR_3COM) &&
X			(ifp->if_flags & IFF_LLC0)) ? "tranceiver disabled" : "");
X
X	/*
X	 * If BPF is in the kernel, call the attach for it
X	 */
X#if NBPFILTER > 0
X	bpfattach(&sc->bpf, ifp, DLT_EN10MB, sizeof(struct ether_header));
X#endif
X
X}
X 
X/*
X * Reset interface.
X */
Xint
Xed_reset(unit)
X	int unit;
X{
X	int s;
X
X	s = splnet();
X
X	/*
X	 * Stop interface and re-initialize.
X	 */
X	ed_stop(unit);
X	ed_init(unit);
X
X	s = splx(s);
X}
X 
X/*
X * Take interface offline.
X */
Xvoid
Xed_stop(unit)
X	int unit;
X{
X	struct ed_softc *sc = &ed_softc[unit];
X	int n = 5000;
X 
X	/*
X	 * Stop everything on the interface, and select page 0 registers.
X	 */
X	outb(sc->nic_addr + ED_P0_CR, ED_CR_RD2|ED_CR_STP);
X
X	/*
X	 * Wait for interface to enter stopped state, but limit # of checks
X	 *	to 'n' (about 5ms). It shouldn't even take 5us on modern
X	 *	DS8390's, but just in case it's an old one.
X	 */
X	while ((inb(sc->nic_addr + ED_P0_ISR) & ED_ISR_RST) == 0) {
X		if (--n == 0)
X			break;
X	}
X}
X
X/*
X * Device timeout/watchdog routine. Entered if the device neglects to
X *	generate an interrupt after a transmit has been started on it.
X */
Xint
Xed_watchdog(unit)
X	int unit;
X{
X	log(LOG_ERR, "ed%d: device timeout\n", unit);
X
X	ed_reset(unit);
X}
X
X/*
X * Initialize device. 
X */
Xed_init(unit)
X	int unit;
X{
X	struct ed_softc *sc = &ed_softc[unit];
X	struct ifnet *ifp = &sc->arpcom.ac_if;
X	int i, s;
X	u_char	command;
X
X
X	/* address not known */
X	if (ifp->if_addrlist == (struct ifaddr *)0) return;
X
X	/*
X	 * Initialize the NIC in the exact order outlined in the NS manual.
X	 *	This init procedure is "mandatory"...don't change what or when
X	 *	things happen.
X	 */
X	s = splnet();
X
X	/* reset transmitter flags */
X	sc->data_buffered = 0;
X	sc->xmit_busy = 0;
X	sc->arpcom.ac_if.if_timer = 0;
X
X	sc->txb_next = 0;
X
X	/* This variable is used below - don't move this assignment */
X	sc->next_packet = sc->rec_page_start + 1;
X
X	/*
X	 * Set interface for page 0, Remote DMA complete, Stopped
X	 */
X	outb(sc->nic_addr + ED_P0_CR, ED_CR_RD2|ED_CR_STP);
X
X	if (sc->memwidth == 16) {
X		/*
X		 * Set FIFO threshold to 8, No auto-init Remote DMA,
X		 *	byte order=80x86, word-wide DMA xfers
X		 */
X		outb(sc->nic_addr + ED_P0_DCR, ED_DCR_FT1|ED_DCR_WTS);
X	} else {
X		/*
X		 * Same as above, but byte-wide DMA xfers
X		 */
X		outb(sc->nic_addr + ED_P0_DCR, ED_DCR_FT1);
X	}
X
X	/*
X	 * Clear Remote Byte Count Registers
X	 */
X	outb(sc->nic_addr + ED_P0_RBCR0, 0);
X	outb(sc->nic_addr + ED_P0_RBCR1, 0);
X
X	/*
X	 * Enable reception of broadcast packets
X	 */
X	outb(sc->nic_addr + ED_P0_RCR, ED_RCR_AB);
X
X	/*
X	 * Place NIC in internal loopback mode
X	 */
X	outb(sc->nic_addr + ED_P0_TCR, ED_TCR_LB0);
X
X	/*
X	 * Initialize transmit/receive (ring-buffer) Page Start
X	 */
X	outb(sc->nic_addr + ED_P0_TPSR, sc->tx_page_start);
X	outb(sc->nic_addr + ED_P0_PSTART, sc->rec_page_start);
X
X	/*
X	 * Initialize Receiver (ring-buffer) Page Stop and Boundry
X	 */
X	outb(sc->nic_addr + ED_P0_PSTOP, sc->rec_page_stop);
X	outb(sc->nic_addr + ED_P0_BNRY, sc->rec_page_start);
X
X	/*
X	 * Clear all interrupts. A '1' in each bit position clears the
X	 *	corresponding flag.
X	 */
X	outb(sc->nic_addr + ED_P0_ISR, 0xff);
X
X	/*
X	 * Enable the following interrupts: receive/transmit complete,
X	 *	receive/transmit error, and Receiver OverWrite.
X	 *
X	 * Counter overflow and Remote DMA complete are *not* enabled.
X	 */
X	outb(sc->nic_addr + ED_P0_IMR,
X		ED_IMR_PRXE|ED_IMR_PTXE|ED_IMR_RXEE|ED_IMR_TXEE|ED_IMR_OVWE);
X
X	/*
X	 * Program Command Register for page 1
X	 */
X	outb(sc->nic_addr + ED_P0_CR, ED_CR_PAGE_1|ED_CR_RD2|ED_CR_STP);
X
X	/*
X	 * Copy out our station address
X	 */
X	for (i = 0; i < ETHER_ADDR_LEN; ++i)
X		outb(sc->nic_addr + ED_P1_PAR0 + i, sc->arpcom.ac_enaddr[i]);
X
X#if NBPFILTER > 0
X	/*
X	 * Initialize multicast address hashing registers to accept
X	 *	 all multicasts (only used when in promiscuous mode)
X	 */
X	for (i = 0; i < 8; ++i)
X		outb(sc->nic_addr + ED_P1_MAR0 + i, 0xff);
X#endif
X
X	/*
X	 * Set Current Page pointer to next_packet (initialized above)
X	 */
X	outb(sc->nic_addr + ED_P1_CURR, sc->next_packet);
X
X	/*
X	 * Set Command Register for page 0, Remote DMA complete,
X	 * 	and interface Start.
X	 */
X	outb(sc->nic_addr + ED_P1_CR, ED_CR_RD2|ED_CR_STA);
X
X	/*
X	 * Take interface out of loopback
X	 */
X	outb(sc->nic_addr + ED_P0_TCR, 0);
X
X	/*
X	 * If this is a 3Com board, the tranceiver must be software enabled
X	 *	(there is no settable hardware default).
X	 */
X	if ((sc->vendor == ED_VENDOR_3COM) && (ifp->if_flags & IFF_LLC0)) {
X		outb(sc->asic_addr + ED_3COM_CR, 0);
X	} else {
X		outb(sc->asic_addr + ED_3COM_CR, ED_3COM_CR_XSEL);
X	}
X
X	/*
X	 * Set 'running' flag, and clear output active flag.
X	 */
X	ifp->if_flags |= IFF_RUNNING;
X	ifp->if_flags &= ~IFF_OACTIVE;
X
X	/*
X	 * ...and attempt to start output
X	 */
X	ed_start(ifp);
X
X	(void) splx(s);
X}
X 
X/*
X * This routine actually starts the transmission on the interface
X */
Xstatic inline void ed_xmit(ifp)
X	struct ifnet *ifp;
X{
X	struct ed_softc *sc = &ed_softc[ifp->if_unit];
X	u_short len = sc->txb_next_len;
X
X	/*
X	 * Set NIC for page 0 register access
X	 */
X	outb(sc->nic_addr + ED_P0_CR, ED_CR_RD2|ED_CR_STA);
X
X	/*
X	 * Set TX buffer start page
X	 */
X	outb(sc->nic_addr + ED_P0_TPSR, sc->tx_page_start +
X		sc->txb_next * ED_TXBUF_SIZE);
X
X	/*
X	 * Set TX length
X	 */
X	outb(sc->nic_addr + ED_P0_TBCR0, len & 0xff);
X	outb(sc->nic_addr + ED_P0_TBCR1, len >> 8);
X
X	/*
X	 * Set page 0, Remote DMA complete, Transmit Packet, and *Start*
X	 */
X	outb(sc->nic_addr + ED_P0_CR, ED_CR_RD2|ED_CR_TXP|ED_CR_STA);
X
X	sc->xmit_busy = 1;
X	sc->data_buffered = 0;
X	
X	/*
X	 * Switch buffers if we are doing double-buffered transmits
X	 */
X	if ((sc->txb_next == 0) && (sc->txb_cnt > 1)) 
X		sc->txb_next = 1;
X	else
X		sc->txb_next = 0;
X
X	/*
X	 * Set a timer just in case we never hear from the board again
X	 */
X	ifp->if_timer = 2;
X}
X
X/*
X * Start output on interface.
X * We make two assumptions here:
X *  1) that the current priority is set to splnet _before_ this code
X *     is called *and* is returned to the appropriate priority after
X *     return
X *  2) that the IFF_OACTIVE flag is checked before this code is called
X *     (i.e. that the output part of the interface is idle)
X */
Xint
Xed_start(ifp)
X	struct ifnet *ifp;
X{
X	struct ed_softc *sc = &ed_softc[ifp->if_unit];
X	struct mbuf *m0, *m;
X	caddr_t buffer;
X	int len;
X	u_char laar_tmp;
X
Xoutloop:
X	/*
X	 * See if there is room to send more data (i.e. one or both of the
X	 *	buffers is empty).
X	 */
X	if (sc->data_buffered)
X		if (sc->xmit_busy) {
X			/*
X			 * No room. Indicate this to the outside world
X			 *	and exit.
X			 */
X			ifp->if_flags |= IFF_OACTIVE;
X			return;
X		} else {
X			/*
X			 * Data is buffered, but we're not transmitting, so
X			 *	start the xmit on the buffered data.
X			 * Note that ed_xmit() resets the data_buffered flag
X			 *	before returning.
X			 */
X			ed_xmit(ifp);
X		}
X
X	IF_DEQUEUE(&sc->arpcom.ac_if.if_snd, m);
X	if (m == 0) {
X	/*
X	 * The following isn't pretty; we are using the !OACTIVE flag to
X	 * indicate to the outside world that we can accept an additional
X	 * packet rather than that the transmitter is _actually_
X	 * active. Indeed, the transmitter may be active, but if we haven't
X	 * filled the secondary buffer with data then we still want to
X	 * accept more.
X	 * Note that it isn't necessary to test the data_buffered flag -
X	 * we wouldn't have tried to de-queue the packet in the first place
X	 * if it was set.
X	 */
X		ifp->if_flags &= ~IFF_OACTIVE;
X		return;
X	}
X
X	/*
X	 * Copy the mbuf chain into the transmit buffer
X	 */
X	/*
X	 * Enable 16bit access to shared memory on WD/SMC boards
X	 */
X	if (sc->memwidth == 16)
X		if (sc->vendor == ED_VENDOR_WD_SMC) {
X			laar_tmp = inb(sc->asic_addr + ED_WD_LAAR);
X			outb(sc->asic_addr + ED_WD_LAAR, laar_tmp | ED_WD_LAAR_M16EN);
X		}
X
X	buffer = sc->smem_start + (sc->txb_next * ED_TXBUF_SIZE * ED_PAGE_SIZE);
X	len = 0;
X	for (m0 = m; m != 0; m = m->m_next) {
X		bcopy(mtod(m, caddr_t), buffer, m->m_len);
X		buffer += m->m_len;
X        	len += m->m_len;
X	}
X
X	/*
X	 * Restore previous shared mem access type
X	 */
X	if (sc->memwidth == 16)
X		if (sc->vendor == ED_VENDOR_WD_SMC) {
X			outb(sc->asic_addr + ED_WD_LAAR, laar_tmp);
X		}
X
X	sc->txb_next_len = MAX(len, ETHER_MIN_LEN);
X
X	if (sc->txb_cnt > 1)
X		/*
X		 * only set 'buffered' flag if doing multiple buffers
X		 */
X		sc->data_buffered = 1;
X
X	if (sc->xmit_busy == 0)
X		ed_xmit(ifp);
X	/*
X	 * If there is BPF support in the configuration, tap off here.
X	 *   The following has support for converting trailer packets
X	 *   back to normal.
X	 */
X#if NBPFILTER > 0
X	if (sc->bpf) {
X		u_short etype;
X		int off, datasize, resid;
X		struct ether_header *eh;
X		struct trailer_header {
X			u_short ether_type;
X			u_short ether_residual;
X		} trailer_header;
X		char ether_packet[ETHER_MAX_LEN];
X		char *ep;
X
X		ep = ether_packet;
X
X		/*
X		 * We handle trailers below:
X		 * Copy ether header first, then residual data,
X		 * then data. Put all this in a temporary buffer
X		 * 'ether_packet' and send off to bpf. Since the
X		 * system has generated this packet, we assume
X		 * that all of the offsets in the packet are
X		 * correct; if they're not, the system will almost
X		 * certainly crash in m_copydata.
X		 * We make no assumptions about how the data is
X		 * arranged in the mbuf chain (i.e. how much
X		 * data is in each mbuf, if mbuf clusters are
X		 * used, etc.), which is why we use m_copydata
X		 * to get the ether header rather than assume
X		 * that this is located in the first mbuf.
X		 */
X		/* copy ether header */
X		m_copydata(m0, 0, sizeof(struct ether_header), ep);
X		eh = (struct ether_header *) ep;
X		ep += sizeof(struct ether_header);
X		etype = ntohs(eh->ether_type);
X		if (etype >= ETHERTYPE_TRAIL &&
X		    etype < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) {
X			datasize = ((etype - ETHERTYPE_TRAIL) << 9);
X			off = datasize + sizeof(struct ether_header);
X
X			/* copy trailer_header into a data structure */
X			m_copydata(m0, off, sizeof(struct trailer_header),
X				&trailer_header.ether_type);
X
X			/* copy residual data */
X			m_copydata(m0, off+sizeof(struct trailer_header),
X				resid = ntohs(trailer_header.ether_residual) -
X				sizeof(struct trailer_header), ep);
X			ep += resid;
X
X			/* copy data */
X			m_copydata(m0, sizeof(struct ether_header),
X				datasize, ep);
X			ep += datasize;
X
X			/* restore original ether packet type */
X			eh->ether_type = trailer_header.ether_type;
X
X			bpf_tap(sc->bpf, ether_packet, ep - ether_packet);
X		} else
X			bpf_mtap(sc->bpf, m0);
X	}
X#endif
X
X	m_freem(m0);
X
X	/*
X	 * If we are doing double-buffering, a buffer might be free to
X	 *	fill with another packet, so loop back to the top.
X	 */
X	if (sc->txb_cnt > 1)
X		goto outloop;
X	else {
X		ifp->if_flags |= IFF_OACTIVE;
X		return;
X	}
X}
X 
X/*
X * Ethernet interface receiver interrupt.
X */
Xstatic inline void /* only called from one place, so may as well integrate */
Xed_rint(unit)
X	int unit;
X{
X	register struct ed_softc *sc = &ed_softc[unit];
X	u_char boundry, current;
X	u_short len;
X	struct ed_ring *packet_ptr;
X
X	/*
X	 * Set NIC to page 1 registers to get 'current' pointer
X	 */
X	outb(sc->nic_addr + ED_P0_CR, ED_CR_PAGE_1|ED_CR_RD2|ED_CR_STA);
X
X	/*
X	 * 'sc->next_packet' is the logical beginning of the ring-buffer - i.e.
X	 *	it points to where new data has been buffered. The 'CURR'
X	 *	(current) register points to the logical end of the ring-buffer
X	 *	- i.e. it points to where additional new data will be added.
X	 *	We loop here until the logical beginning equals the logical
X	 *	end (or in other words, until the ring-buffer is empty).
X	 */
X	while (sc->next_packet != inb(sc->nic_addr + ED_P1_CURR)) {
X
X		/* get pointer to this buffer header structure */
X		packet_ptr = (struct ed_ring *)(sc->smem_ring +
X			 (sc->next_packet - sc->rec_page_start) * ED_PAGE_SIZE);
X
X		/*
X		 * The byte count includes the FCS - Frame Check Sequence (a
X		 *	32 bit CRC).
X		 */
X		len = packet_ptr->count;
X		if ((len >= ETHER_MIN_LEN) && (len <= ETHER_MAX_LEN)) {
X			/*
X			 * Go get packet. len - 4 removes CRC from length.
X			 * (packet_ptr + 1) points to data just after the packet ring
X			 *	header (+4 bytes)
X			 */
X			ed_get_packet(sc, (caddr_t)(packet_ptr + 1), len - 4);
X			++sc->arpcom.ac_if.if_ipackets;
X		} else {
X			/*
X			 * Really BAD...probably indicates that the ring pointers
X			 *	are corrupted. Also seen on early rev chips under
X			 *	high load - the byte order of the length gets switched.
X			 */
X			log(LOG_ERR,
X				"ed%d: shared memory corrupt - invalid packet length %d\n",
X				unit, len);
X			ed_reset(unit);
X			return;
X		}
X
X		/*
X		 * Update next packet pointer
X		 */
X		sc->next_packet = packet_ptr->next_packet;
X
X		/*
X		 * Update NIC boundry pointer - being careful to keep it
X		 *	one buffer behind. (as recommended by NS databook)
X		 */
X		boundry = sc->next_packet - 1;
X		if (boundry < sc->rec_page_start)
X			boundry = sc->rec_page_stop - 1;
X
X		/*
X		 * Set NIC to page 0 registers to update boundry register
X		 */
X		outb(sc->nic_addr + ED_P0_CR, ED_CR_RD2|ED_CR_STA);
X
X		outb(sc->nic_addr + ED_P0_BNRY, boundry);
X
X		/*
X		 * Set NIC to page 1 registers before looping to top (prepare to
X		 *	get 'CURR' current pointer)
X		 */
X		outb(sc->nic_addr + ED_P0_CR, ED_CR_PAGE_1|ED_CR_RD2|ED_CR_STA);
X	}
X}
X
X/*
X * Ethernet interface interrupt processor
X */
Xint
Xedintr(unit)
X	int unit;
X{
X	struct ed_softc *sc = &ed_softc[unit];
X	u_char isr;
X
X	/*
X	 * Set NIC to page 0 registers
X	 */
X	outb(sc->nic_addr + ED_P0_CR, ED_CR_RD2|ED_CR_STA);
X
X	/*
X	 * loop until there are no more new interrupts
X	 */
X	while (isr = inb(sc->nic_addr + ED_P0_ISR)) {
X
X		/*
X		 * reset all the bits that we are 'acknowleging'
X		 *	by writing a '1' to each bit position that was set
X		 * (writing a '1' *clears* the bit)
X		 */
X		outb(sc->nic_addr + ED_P0_ISR, isr);
X
X		/*
X		 * Transmit error. If a TX completed with an error, we end up
X		 *	throwing the packet away. Really the only error that is
X		 *	possible is excessive collisions, and in this case it is
X		 *	best to allow the automatic mechanisms of TCP to backoff
X		 *	the flow. Of course, with UDP we're screwed, but this is
X		 *	expected when a network is heavily loaded.
X		 */
X		if (isr & ED_ISR_TXE) {
X			u_char tsr = inb(sc->nic_addr + ED_P0_TSR);
X			u_char ncr = inb(sc->nic_addr + ED_P0_NCR);
X
X			/*
X			 * Excessive collisions (16)
X			 */
X			if ((tsr & ED_TSR_ABT) && (ncr == 0)) {
X				/*
X				 *    When collisions total 16, the P0_NCR will
X				 * indicate 0, and the TSR_ABT is set.
X				 */
X				sc->arpcom.ac_if.if_collisions += 16;
X			} else
X				sc->arpcom.ac_if.if_collisions += ncr;
X
X			/*
X			 * update output errors counter
X			 */
X			++sc->arpcom.ac_if.if_oerrors;
X
X			/*
X			 * reset tx busy and output active flags
X			 */
X			sc->xmit_busy = 0;
X			sc->arpcom.ac_if.if_flags &= ~IFF_OACTIVE;
X
X			/*
X			 * clear watchdog timer
X			 */
X			sc->arpcom.ac_if.if_timer = 0;
X		}
X				
X			
X		/*
X		 * Receiver Error. One or more of: CRC error, frame alignment error
X		 *	FIFO overrun, or missed packet.
X		 */
X		if (isr & ED_ISR_RXE) {
X			++sc->arpcom.ac_if.if_ierrors;
X#ifdef ED_DEBUG
X			printf("ed%d: receive error %x\n", unit,
X				inb(sc->nic_addr + ED_P0_RSR));
X#endif
X		}
X
X		/*
X		 * Overwrite warning. In order to make sure that a lockup
X		 *	of the local DMA hasn't occurred, we reset and
X		 *	re-init the NIC. The NSC manual suggests only a
X		 *	partial reset/re-init is necessary - but some
X		 *	chips seem to want more. The DMA lockup has been
X		 *	seen only with early rev chips - Methinks this
X		 *	bug was fixed in later revs. -DG
X		 */
X		if (isr & ED_ISR_OVW) {
X			++sc->arpcom.ac_if.if_ierrors;
X			log(LOG_WARNING,
X				"ed%d: warning - receiver ring buffer overrun\n",
X				unit);
X			/*
X			 * Stop/reset/re-init NIC
X			 */
X			ed_reset(unit);
X		}
X
X		/*
X		 * Transmission completed normally.
X		 */
X		if (isr & ED_ISR_PTX) {
X
X			/*
X			 * reset tx busy and output active flags
X			 */
X			sc->xmit_busy = 0;
X			sc->arpcom.ac_if.if_flags &= ~IFF_OACTIVE;
X
X			/*
X			 * clear watchdog timer
X			 */
X			sc->arpcom.ac_if.if_timer = 0;
X
X			/*
X			 * Update total number of successfully transmitted
X			 *	packets.
X			 */
X			++sc->arpcom.ac_if.if_opackets;
X
X			/*
X			 * Add in total number of collisions on last
X			 *	transmission.
X			 */
X			sc->arpcom.ac_if.if_collisions += inb(sc->nic_addr +
X				ED_P0_TBCR0);
X		}
X
X		/*
X		 * Receive Completion. Go and get the packet. 
X		 *	XXX - Doing this on an error is dubious because there
X		 *	   shouldn't be any data to get (we've configured the
X		 *	   interface to not accept packets with errors).
X		 */
X		if (isr & (ED_ISR_PRX|ED_ISR_RXE)) {
X			/*
X			 * Enable access to shared memory on WD/SMC boards
X			 */
X			if (sc->memwidth == 16)
X				if (sc->vendor == ED_VENDOR_WD_SMC) {
X					outb(sc->asic_addr + ED_WD_LAAR,
X						inb(sc->asic_addr + ED_WD_LAAR)
X						| ED_WD_LAAR_M16EN);
X				}
X
X			ed_rint (unit);
X
X			/*
X			 * Disable access to shared memory
X			 */
X			if (sc->memwidth == 16)
X				if (sc->vendor == ED_VENDOR_WD_SMC) {
X					outb(sc->asic_addr + ED_WD_LAAR,
X						inb(sc->asic_addr + ED_WD_LAAR)
X						& ~ED_WD_LAAR_M16EN);
X				}
X		}
X
X		/*
X		 * If it looks like the transmitter can take more data,
X		 *	attempt to start output on the interface. If data is
X		 *	already buffered and ready to go, send it first.
X		 */
X		if ((sc->arpcom.ac_if.if_flags & IFF_OACTIVE) == 0) {
X			if (sc->data_buffered)
X				ed_xmit(&sc->arpcom.ac_if);
X			ed_start(&sc->arpcom.ac_if);
X		}
X
X		/*
X		 * return NIC CR to standard state before looping back
X		 *	to top: page 0, remote DMA complete, start
X		 * (toggling the TXP bit off, even if was just set in the
X		 *	transmit routine, is *okay* - it is 'edge' triggered
X		 *	from low to high)
X		 */
X		outb(sc->nic_addr + ED_P0_CR, ED_CR_RD2|ED_CR_STA);
X	}
X}
X 
X/*
X * Process an ioctl request. This code needs some work - it looks
X *	pretty ugly.
X */
Xint
Xed_ioctl(ifp, command, data)
X	register struct ifnet *ifp;
X	int command;
X	caddr_t data;
X{
X	register struct ifaddr *ifa = (struct ifaddr *)data;
X	struct ed_softc *sc = &ed_softc[ifp->if_unit];
X	struct ifreq *ifr = (struct ifreq *)data;
X	int s, error = 0;
X
X	s = splnet();
X
X	switch (command) {
X
X	case SIOCSIFADDR:
X		ifp->if_flags |= IFF_UP;
X
X		switch (ifa->ifa_addr->sa_family) {
X#ifdef INET
X		case AF_INET:
X			ed_init(ifp->if_unit);	/* before arpwhohas */
X			/*
X			 * See if another station has *our* IP address.
X			 * i.e.: There is an address conflict! If a
X			 * conflict exists, a message is sent to the
X			 * console.
X			 */
X			((struct arpcom *)ifp)->ac_ipaddr =
X				IA_SIN(ifa)->sin_addr;
X			arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr);
X			break;
X#endif
X#ifdef NS
X		/*
X		 * XXX - This code is probably wrong
X		 */
X		case AF_NS:
X		    {
X			register struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr);
X
X			if (ns_nullhost(*ina))
X				ina->x_host =
X					*(union ns_host *)(sc->arpcom.ac_enaddr);
X			else {
X				/* 
X				 * 
X				 */
X				bcopy((caddr_t)ina->x_host.c_host,
X				    (caddr_t)sc->arpcom.ac_enaddr,
X					sizeof(sc->arpcom.ac_enaddr));
X			}
X			/*
X			 * Set new address
X			 */
X			ed_init(ifp->if_unit);
X			break;
X		    }
X#endif
X		default:
X			ed_init(ifp->if_unit);
X			break;
X		}
X		break;
X
X	case SIOCSIFFLAGS:
X		/*
X		 * If interface is marked down and it is running, then stop it
X		 */
X		if (((ifp->if_flags & IFF_UP) == 0) &&
X		    (ifp->if_flags & IFF_RUNNING)) {
X			ed_stop(ifp->if_unit);
X			ifp->if_flags &= ~IFF_RUNNING;
X		} else {
X		/*
X		 * If interface is marked up and it is stopped, then start it
X		 */
X			if ((ifp->if_flags & IFF_UP) &&
X		    	    ((ifp->if_flags & IFF_RUNNING) == 0))
X				ed_init(ifp->if_unit);
X		}
X#if NBPFILTER > 0
X		if (ifp->if_flags & IFF_PROMISC) {
X			/*
X			 * Set promiscuous mode on interface.
X			 *	XXX - for multicasts to work, we would need to
X			 *		write 1's in all bits of multicast
X			 *		hashing array. For now we assume that
X			 *		this was done in ed_init().
X			 */
X			outb(sc->nic_addr + ED_P0_RCR,
X				ED_RCR_PRO|ED_RCR_AM|ED_RCR_AB);
X		} else {
X			/*
X			 * XXX - for multicasts to work, we would need to
X			 *	rewrite the multicast hashing array with the
X			 *	proper hash (would have been destroyed above).
X			 */
X			outb(sc->nic_addr + ED_P0_RCR, ED_RCR_AB);
X		}
X#endif
X		/*
X		 * An unfortunate hack to provide the (required) software control
X		 *	of the tranceiver for 3Com boards. The LLC0 flag disables
X		 *	the tranceiver if set.
X		 */
X		if ((sc->vendor == ED_VENDOR_3COM) && (ifp->if_flags & IFF_LLC0)) {
X			outb(sc->asic_addr + ED_3COM_CR, 0);
X		} else {
X			outb(sc->asic_addr + ED_3COM_CR, ED_3COM_CR_XSEL);
X		}
X
X		break;
X
X	default:
X		error = EINVAL;
X	}
X	(void) splx(s);
X	return (error);
X}
X 
X/*
X * Macro to calculate a new address within shared memory when given an offset
X *	from an address, taking into account ring-wrap.
X */
X#define	ringoffset(sc, start, off, type) \
X	((type)( ((caddr_t)(start)+(off) >= (sc)->smem_end) ? \
X		(((caddr_t)(start)+(off))) - (sc)->smem_end \
X		+ (sc)->smem_ring: \
X		((caddr_t)(start)+(off)) ))
X
X/*
X * Retreive packet from shared memory and send to the next level up via
X *	ether_input(). If there is a BPF listener, give a copy to BPF, too.
X */
Xed_get_packet(sc, buf, len)
X	struct ed_softc *sc;
X	char *buf;
X	u_short len;
X{
X	struct ether_header *eh;
X    	struct mbuf *m, *head, *ed_ring_to_mbuf();
X	u_short off;
X	int resid;
X	u_short etype;
X	struct trailer_header {
X		u_short	trail_type;
X		u_short trail_residual;
X	} trailer_header;
X
X	/* Allocate a header mbuf */
X	MGETHDR(m, M_DONTWAIT, MT_DATA);
X	if (m == 0)
X		goto bad;
X	m->m_pkthdr.rcvif = &sc->arpcom.ac_if;
X	m->m_pkthdr.len = len;
X	m->m_len = 0;
X	head = m;
X
X	eh = (struct ether_header *)buf;
X
X	/* The following sillines is to make NFS happy */
X#define EROUND	((sizeof(struct ether_header) + 3) & ~3)
X#define EOFF	(EROUND - sizeof(struct ether_header))
X
X	/*
X	 * The following assumes there is room for
X	 * the ether header in the header mbuf
X	 */
X	head->m_data += EOFF;
X	bcopy(buf, mtod(head, caddr_t), sizeof(struct ether_header));
X	buf += sizeof(struct ether_header);
X	head->m_len += sizeof(struct ether_header);
X	len -= sizeof(struct ether_header);
X
X	etype = ntohs((u_short)eh->ether_type);
X
X	/*
X	 * Deal with trailer protocol:
X	 * If trailer protocol, calculate the datasize as 'off',
X	 * which is also the offset to the trailer header.
X	 * Set resid to the amount of packet data following the
X	 * trailer header.
X	 * Finally, copy residual data into mbuf chain.
X	 */
X	if (etype >= ETHERTYPE_TRAIL &&
X	    etype < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) {
X
X		off = (etype - ETHERTYPE_TRAIL) << 9;
X		if ((off + sizeof(struct trailer_header)) > len)
X			goto bad;	/* insanity */
X
X		eh->ether_type = *ringoffset(sc, buf, off, u_short *);
X		resid = ntohs(*ringoffset(sc, buf, off+2, u_short *));
X
X		if ((off + resid) > len) goto bad;	/* insanity */
X
X		resid -= sizeof(struct trailer_header);
X		if (resid < 0) goto bad;	/* insanity */
X
X		m = ed_ring_to_mbuf(sc, ringoffset(sc, buf, off+4, char *), head, resid);
X		if (m == 0) goto bad;
X
X		len = off;
X		head->m_pkthdr.len -= 4; /* subtract trailer header */
X	}
X
X	/*
X	 * Pull packet off interface. Or if this was a trailer packet,
X	 * the data portion is appended.
X	 */
X	m = ed_ring_to_mbuf(sc, buf, m, len);
X	if (m == 0) goto bad;
X
X#if NBPFILTER > 0
X	/*
X	 * Check if there's a BPF listener on this interface.
X	 * If so, hand off the raw packet to bpf. 
X	 */
X	if (sc->bpf) {
X		bpf_mtap(sc->bpf, head);
X
X		/*
X		 * Note that the interface cannot be in promiscuous mode if
X		 * there are no BPF listeners.  And if we are in promiscuous
X		 * mode, we have to check if this packet is really ours.
X		 *
X		 * XXX This test does not support multicasts.
X		 */
X		if ((sc->arpcom.ac_if.if_flags & IFF_PROMISC) &&
X			bcmp(eh->ether_dhost, sc->arpcom.ac_enaddr,
X				sizeof(eh->ether_dhost)) != 0 &&
X			bcmp(eh->ether_dhost, etherbroadcastaddr,
X				sizeof(eh->ether_dhost)) != 0) {
X
X			m_freem(head);
X			return;
X		}
X	}
X#endif
X
X	/*
X	 * Fix up data start offset in mbuf to point past ether header
X	 */
X	m_adj(head, sizeof(struct ether_header));
X
X	/*
X	 * silly ether_input routine needs 'type' in host byte order
X	 */
X	eh->ether_type = ntohs(eh->ether_type);
X
X	ether_input(&sc->arpcom.ac_if, eh, head);
X	return;
X
Xbad:	if (head)
X		m_freem(head);
X	return;
X}
X
X/*
X * Supporting routines
X */
X
X/*
X * Given a source and destination address, copy 'amount' of a packet from
X *	the ring buffer into a linear destination buffer. Takes into account
X *	ring-wrap.
X */
Xstatic inline char *
Xed_ring_copy(sc,src,dst,amount)
X	struct ed_softc *sc;
X	char	*src;
X	char	*dst;
X	u_short	amount;
X{
X	u_short	tmp_amount;
X
X	/* does copy wrap to lower addr in ring buffer? */
X	if (src + amount > sc->smem_end) {
X		tmp_amount = sc->smem_end - src;
X		bcopy(src,dst,tmp_amount); /* copy amount up to end of smem */
X		amount -= tmp_amount;
X		src = sc->smem_ring;
X		dst += tmp_amount;
X	}
X
X	bcopy(src, dst, amount);
X
X	return(src + amount);
X}
X
X/*
X * Copy data from receive buffer to end of mbuf chain
X * allocate additional mbufs as needed. return pointer
X * to last mbuf in chain.
X * sc = ed info (softc)
X * src = pointer in ed ring buffer
X * dst = pointer to last mbuf in mbuf chain to copy to
X * amount = amount of data to copy
X */
Xstruct mbuf *
Xed_ring_to_mbuf(sc,src,dst,total_len)
X	struct ed_softc *sc;
X	char *src;
X	struct mbuf *dst;
X	u_short total_len;
X{
X	register struct mbuf *m = dst;
X
X	while (total_len) {
X		register u_short amount = min(total_len, M_TRAILINGSPACE(m));
X
X		if (amount == 0) { /* no more data in this mbuf, alloc another */
X			/*
X			 * If there is enough data for an mbuf cluster, attempt
X			 * 	to allocate one of those, otherwise, a regular
X			 *	mbuf will do.
X			 * Note that a regular mbuf is always required, even if
X			 *	we get a cluster - getting a cluster does not
X			 *	allocate any mbufs, and one is needed to assign
X			 *	the cluster to. The mbuf that has a cluster
X			 *	extension can not be used to contain data - only
X			 *	the cluster can contain data.
X			 */ 
X			dst = m;
X			MGET(m, M_DONTWAIT, MT_DATA);
X			if (m == 0)
X				return (0);
X
X			if (total_len >= MINCLSIZE)
X				MCLGET(m, M_DONTWAIT);
X
X			m->m_len = 0;
X			dst->m_next = m;
X			amount = min(total_len, M_TRAILINGSPACE(m));
X		}
X
X		src = ed_ring_copy(sc, src, mtod(m, caddr_t) + m->m_len, amount);
X
X		m->m_len += amount;
X		total_len -= amount;
X
X	}
X	return (m);
X}
X#endif
X
END-of-if_ed.c
echo x - if_edreg.h
sed 's/^X//' >if_edreg.h << 'END-of-if_edreg.h'
X/*
X * National Semiconductor DS8390 NIC register definitions 
X *
X * $Log:	if_edreg.h,v $
X * Revision 1.3  93/07/20  15:25:25  davidg
X * added config flags for forcing 8/16bit mode and disabling double
X * xmit buffers.
X * 
X * Revision 1.2  93/06/23  03:03:05  davidg
X * added some additional definitions for the 83C584 bus interface
X * chip (SMC/WD boards)
X * 
X * Revision 1.1  93/06/23  03:01:07  davidg
X * Initial revision
X * 
X */
X
X/*
X * Page 0 register offsets
X */
X#define ED_P0_CR	0x00	/* Command Register */
X
X#define ED_P0_CLDA0	0x01	/* Current Local DMA Addr low (read) */
X#define ED_P0_PSTART	0x01	/* Page Start register (write) */
X
X#define ED_P0_CLDA1	0x02	/* Current Local DMA Addr high (read) */
X#define ED_P0_PSTOP	0x02	/* Page Stop register (write) */
X
X#define ED_P0_BNRY	0x03	/* Boundary Pointer */
X
X#define ED_P0_TSR	0x04	/* Transmit Status Register (read) */
X#define ED_P0_TPSR	0x04	/* Transmit Page Start (write) */
X
X#define ED_P0_NCR	0x05	/* Number of Collisions Reg (read) */
X#define ED_P0_TBCR0	0x05	/* Transmit Byte count, low (write) */
X
X#define ED_P0_FIFO	0x06	/* FIFO register (read) */
X#define ED_P0_TBCR1	0x06	/* Transmit Byte count, high (write) */
X
X#define ED_P0_ISR	0x07	/* Interrupt Status Register */
X
X#define ED_P0_CRDA0	0x08	/* Current Remote DMA Addr low (read) */
X#define ED_P0_RSAR0	0x08	/* Remote Start Address low (write) */
X
X#define ED_P0_CRDA1	0x09	/* Current Remote DMA Addr high (read) */
X#define ED_P0_RSAR1	0x09	/* Remote Start Address high (write) */
X
X#define ED_P0_RBCR0	0x0a	/* Remote Byte Count low (write) */
X
X#define ED_P0_RBCR1	0x0b	/* Remote Byte Count high (write) */
X
X#define ED_P0_RSR	0x0c	/* Receive Status (read) */
X#define ED_P0_RCR	0x0c	/* Receive Configuration Reg (write) */
X
X#define ED_P0_CNTR0	0x0d	/* frame alignment error counter (read) */
X#define ED_P0_TCR	0x0d	/* Transmit Configuration Reg (write) */
X
X#define ED_P0_CNTR1	0x0e	/* CRC error counter (read) */
X#define ED_P0_DCR	0x0e	/* Data Configuration Reg (write) */
X
X#define ED_P0_CNTR2	0x0f	/* missed packet counter (read) */
X#define ED_P0_IMR	0x0f	/* Interrupt Mask Register (write) */
X
X/*
X * Page 1 register offsets
X */
X#define ED_P1_CR	0x00	/* Command Register */
X#define ED_P1_PAR0	0x01	/* Physical Address Register 0 */
X#define ED_P1_PAR1	0x02	/* Physical Address Register 1 */
X#define ED_P1_PAR2	0x03	/* Physical Address Register 2 */
X#define ED_P1_PAR3	0x04	/* Physical Address Register 3 */
X#define ED_P1_PAR4	0x05	/* Physical Address Register 4 */
X#define ED_P1_PAR5	0x06	/* Physical Address Register 5 */
X#define ED_P1_CURR	0x07	/* Current RX ring-buffer page */
X#define ED_P1_MAR0	0x08	/* Multicast Address Register 0 */
X#define ED_P1_MAR1	0x09	/* Multicast Address Register 1 */
X#define ED_P1_MAR2	0x0a	/* Multicast Address Register 2 */
X#define ED_P1_MAR3	0x0b	/* Multicast Address Register 3 */
X#define ED_P1_MAR4	0x0c	/* Multicast Address Register 4 */
X#define ED_P1_MAR5	0x0d	/* Multicast Address Register 5 */
X#define ED_P1_MAR6	0x0e	/* Multicast Address Register 6 */
X#define ED_P1_MAR7	0x0f	/* Multicast Address Register 7 */
X
X/*
X * Page 2 register offsets
X */
X#define ED_P2_CR	0x00	/* Command Register */
X#define ED_P2_PSTART	0x01	/* Page Start (read) */
X#define ED_P2_CLDA0	0x01	/* Current Local DMA Addr 0 (write) */
X#define ED_P2_PSTOP	0x02	/* Page Stop (read) */
X#define ED_P2_CLDA1	0x02	/* Current Local DMA Addr 1 (write) */
X#define ED_P2_RNPP	0x03	/* Remote Next Packet Pointer */
X#define ED_P2_TPSR	0x04	/* Transmit Page Start (read) */
X#define ED_P2_LNPP	0x05	/* Local Next Packet Pointer */
X#define ED_P2_ACU	0x06	/* Address Counter Upper */
X#define ED_P2_ACL	0x07	/* Address Counter Lower */
X#define ED_P2_RCR	0x0c	/* Receive Configuration Register (read) */
X#define ED_P2_TCR	0x0d	/* Transmit Configuration Register (read) */
X#define ED_P2_DCR	0x0e	/* Data Configuration Register (read) */
X#define ED_P2_IMR	0x0f	/* Interrupt Mask Register (read) */
X
X/*
X *		Command Register (CR) definitions
X */
X
X/*
X * STP: SToP. Software reset command. Takes the controller offline. No
X *	packets will be received or transmitted. Any reception or
X *	transmission in progress will continue to completion before
X *	entering reset state. To exit this state, the STP bit must
X *	reset and the STA bit must be set. The software reset has
X *	executed only when indicated by the RST bit in the ISR being
X *	set.
X */
X#define ED_CR_STP	0x01
X
X/*
X * STA: STArt. This bit is used to activate the NIC after either power-up,
X *	or when the NIC has been put in reset mode by software command
X *	or error.
X */
X#define ED_CR_STA	0x02
X
X/*
X * TXP: Transmit Packet. This bit must be set to indicate transmission of
X *	a packet. TXP is internally reset either after the transmission is
X *	completed or aborted. This bit should be set only after the Transmit
X *	Byte Count and Transmit Page Start register have been programmed.
X */
X#define ED_CR_TXP	0x04
X
X/*
X * RD0, RD1, RD2: Remote DMA Command. These three bits control the operation
X *	of the remote DMA channel. RD2 can be set to abort any remote DMA
X *	command in progress. The Remote Byte Count registers should be cleared
X *	when a remote DMA has been aborted. The Remote Start Addresses are not
X *	restored to the starting address if the remote DMA is aborted.
X *
X *	RD2 RD1 RD0	function
X *	 0   0   0	not allowed
X *	 0   0   1	remote read
X *	 0   1   0	remote write
X *	 0   1   1	send packet
X *	 1   X   X	abort
X */
X#define ED_CR_RD0	0x08
X#define ED_CR_RD1	0x10
X#define ED_CR_RD2	0x20
X
X/*
X * PS0, PS1: Page Select. The two bits select which register set or 'page' to
X *	access.
X *
X *	PS1 PS0		page
X *	 0   0		0
X *	 0   1		1
X *	 1   0		2
X *	 1   1		reserved
X */
X#define ED_CR_PS0	0x40
X#define ED_CR_PS1	0x80
X/* bit encoded aliases */
X#define ED_CR_PAGE_0	0x00 /* (for consistency) */
X#define ED_CR_PAGE_1	0x40
X#define ED_CR_PAGE_2	0x80
X
X/*
X *		Interrupt Status Register (ISR) definitions
X */
X
X/*
X * PRX: Packet Received. Indicates packet received with no errors.
X */
X#define ED_ISR_PRX	0x01
X
X/*
X * PTX: Packet Transmitted. Indicates packet transmitted with no errors.
X */
X#define ED_ISR_PTX	0x02
X
X/*
X * RXE: Receive Error. Indicates that a packet was received with one or more
X *	the following errors: CRC error, frame alignment error, FIFO overrun,
X *	missed packet.
X */
X#define ED_ISR_RXE	0x04
X
X/*
X * TXE: Transmission Error. Indicates that an attempt to transmit a packet
X *	resulted in one or more of the following errors: excessive
X *	collisions, FIFO underrun.
X */
X#define ED_ISR_TXE	0x08
X
X/*
X * OVW: OverWrite. Indicates a receive ring-buffer overrun. Incoming network
X *	would exceed (has exceeded?) the boundry pointer, resulting in data
X *	that was previously received and not yet read from the buffer to be
X *	overwritten.
X */
X#define ED_ISR_OVW	0x10
X
X/*
X * CNT: Counter Overflow. Set when the MSB of one or more of the Network Talley
X *	Counters has been set.
X */
X#define ED_ISR_CNT	0x20
X
X/*
X * RDC: Remote Data Complete. Indicates that a Remote DMA operation has completed.
X */
X#define ED_ISR_RDC	0x40
X
X/*
X * RST: Reset status. Set when the NIC enters the reset state and cleared when a
X *	Start Command is issued to the CR. This bit is also set when a receive
X *	ring-buffer overrun (OverWrite) occurs and is cleared when one or more
X *	packets have been removed from the ring. This is a read-only bit.
X */
X#define ED_ISR_RST	0x80
X
X/*
X *		Interrupt Mask Register (IMR) definitions
X */
X
X/*
X * PRXE: Packet Received interrupt Enable. If set, a received packet will cause
X *	an interrupt.
X */
X#define ED_IMR_PRXE	0x01
X
X/*
X * PTXE: Packet Transmit interrupt Enable. If set, an interrupt is generated when
X *	a packet transmission completes.
X */
X#define ED_IMR_PTXE	0x02
X
X/*
X * RXEE: Receive Error interrupt Enable. If set, an interrupt will occur whenever a
X *	packet is received with an error.
X */
X#define ED_IMR_RXEE 	0x04
X
X/*
X * TXEE: Transmit Error interrupt Enable. If set, an interrupt will occur whenever
X *	a transmission results in an error.
X */
X#define ED_IMR_TXEE	0x08
X
X/*
X * OVWE: OverWrite error interrupt Enable. If set, an interrupt is generated whenever
X *	the receive ring-buffer is overrun. i.e. when the boundry pointer is exceeded.
X */
X#define ED_IMR_OVWE	0x10
X
X/*
X * CNTE: Counter overflow interrupt Enable. If set, an interrupt is generated whenever
X *	the MSB of one or more of the Network Statistics counters has been set.
X */
X#define ED_IMR_CNTE	0x20
X
X/*
X * RDCE: Remote DMA Complete interrupt Enable. If set, an interrupt is generated
X *	when a remote DMA transfer has completed.
X */
X#define ED_IMR_RDCE	0x40
X
X/*
X * bit 7 is unused/reserved
X */
X
X/*
X *		Data Configuration Register (DCR) definitions
X */
X
X/*
X * WTS: Word Transfer Select. WTS establishes byte or word transfers for
X *	both remote and local DMA transfers
X */
X#define ED_DCR_WTS	0x01
X
X/*
X * BOS: Byte Order Select. BOS sets the byte order for the host.
X *	Should be 0 for 80x86, and 1 for 68000 series processors
X */
X#define ED_DCR_BOS	0x02
X
X/*
X * LAS: Long Address Select. When LAS is 1, the contents of the remote
X *	DMA registers RSAR0 and RSAR1 are used to provide A16-A31
X */
X#define ED_DCR_LAS	0x04
X
X/*
X * LS: Loopback Select. When 0, loopback mode is selected. Bits D1 and D2
X *	of the TCR must also be programmed for loopback operation.
X *	When 1, normal operation is selected.
X */
X#define ED_DCR_LS	0x08
X
X/*
X * AR: Auto-initialize Remote. When 0, data must be removed from ring-buffer
X *	under program control. When 1, remote DMA is automatically initiated
X *	and the boundry pointer is automatically updated
X */
X#define ED_DCR_AR	0x10
X
X/*
X * FT0, FT1: Fifo Threshold select.
X *		FT1	FT0	Word-width	Byte-width
X *		 0	 0	1 word		2 bytes
X *		 0	 1	2 words		4 bytes
X *		 1	 0	4 words		8 bytes
X *		 1	 1	8 words		12 bytes
X *
X *	During transmission, the FIFO threshold indicates the number of bytes
X *	or words that the FIFO has filled from the local DMA before BREQ is
X *	asserted. The transmission threshold is 16 bytes minus the receiver
X *	threshold.
X */
X#define ED_DCR_FT0	0x20
X#define ED_DCR_FT1	0x40
X
X/*
X * bit 7 (0x80) is unused/reserved
X */
X
X/*
X *		Transmit Configuration Register (TCR) definitions
X */
X
X/*
X * CRC: Inhibit CRC. If 0, CRC will be appended by the transmitter, if 0, CRC
X *	is not appended by the transmitter.
X */
X#define ED_TCR_CRC	0x01
X
X/*
X * LB0, LB1: Loopback control. These two bits set the type of loopback that is
X *	to be performed.
X *
X *	LB1 LB0		mode
X *	 0   0		0 - normal operation (DCR_LS = 0)
X *	 0   1		1 - internal loopback (DCR_LS = 0)
X *	 1   0		2 - external loopback (DCR_LS = 1)
X *	 1   1		3 - external loopback (DCR_LS = 0)
X */
X#define ED_TCR_LB0	0x02
X#define ED_TCR_LB1	0x04
X
X/*
X * ATD: Auto Transmit Disable. Clear for normal operation. When set, allows
X *	another station to disable the NIC's transmitter by transmitting to
X *	a multicast address hashing to bit 62. Reception of a multicast address
X *	hashing to bit 63 enables the transmitter.
X */
X#define ED_TCR_ATD	0x08
X
X/*
X * OFST: Collision Offset enable. This bit when set modifies the backoff
X *	algorithm to allow prioritization of nodes.
X */
X#define ED_TCR_OFST	0x10
X 
X/*
X * bits 5, 6, and 7 are unused/reserved
X */
X
X/*
X *		Transmit Status Register (TSR) definitions
X */
X
X/*
X * PTX: Packet Transmitted. Indicates successful transmission of packet.
X */
X#define ED_TSR_PTX	0x01
X
X/*
X * bit 1 (0x02) is unused/reserved
X */
X
X/*
X * COL: Transmit Collided. Indicates that the transmission collided at least
X *	once with another station on the network.
X */
X#define ED_TSR_COL	0x04
X
X/*
X * ABT: Transmit aborted. Indicates that the transmission was aborted due to
X *	excessive collisions.
X */
X#define ED_TSR_ABT	0x08
X
X/*
X * CRS: Carrier Sense Lost. Indicates that carrier was lost during the
X *	transmission of the packet. (Transmission is not aborted because
X *	of a loss of carrier)
X */
X#define ED_TSR_CRS	0x10
X
X/*
X * FU: FIFO Underrun. Indicates that the NIC wasn't able to access bus/
X *	transmission memory before the FIFO emptied. Transmission of the
X *	packet was aborted.
X */
X#define ED_TSR_FU	0x20
X
X/*
X * CDH: CD Heartbeat. Indicates that the collision detection circuitry
X *	isn't working correctly during a collision heartbeat test.
X */
X#define ED_TSR_CDH	0x40
X
X/*
X * OWC: Out of Window Collision: Indicates that a collision occurred after
X *	a slot time (51.2us). The transmission is rescheduled just as in
X *	normal collisions.
X */
X#define ED_TSR_OWC	0x80
X
X/*
X *		Receiver Configuration Register (RCR) definitions
X */
X
X/*
X * SEP: Save Errored Packets. If 0, error packets are discarded. If set to 1,
X *	packets with CRC and frame errors are not discarded.
X */
X#define ED_RCR_SEP	0x01
X
X/*
X * AR: Accept Runt packet. If 0, packet with less than 64 byte are discarded.
X *	If set to 1, packets with less than 64 byte are not discarded.
X */
X#define ED_RCR_AR	0x02
X
X/*
X * AB: Accept Broadcast. If set, packets sent to the broadcast address will be
X *	accepted.
X */
X#define ED_RCR_AB	0x04
X
X/*
X * AM: Accept Multicast. If set, packets sent to a multicast address are checked
X *	for a match in the hashing array. If clear, multicast packets are ignored.
X */
X#define ED_RCR_AM	0x08
X
X/*
X * PRO: Promiscuous Physical. If set, all packets with a physical addresses are
X *	accepted. If clear, a physical destination address must match this
X *	station's address. Note: for full promiscuous mode, RCR_AB and RCR_AM
X *	must also be set. In addition, the multicast hashing array must be set
X *	to all 1's so that all multicast addresses are accepted.
X */
X#define ED_RCR_PRO	0x10
X
X/*
X * MON: Monitor Mode. If set, packets will be checked for good CRC and framing,
X *	but are not stored in the ring-buffer. If clear, packets are stored (normal
X *	operation).
X */
X#define ED_RCR_MON	0x20
X
X/*
X * bits 6 and 7 are unused/reserved.
X */
X
X/*
X *		Receiver Status Register (RSR) definitions
X */
X
X/*
X * PRX: Packet Received without error.
X */
X#define ED_RSR_PRX	0x01
X
X/*
X * CRC: CRC error. Indicates that a packet has a CRC error. Also set for frame
X *	alignment errors.
X */
X#define ED_RSR_CRC	0x02
X
X/*
X * FAE: Frame Alignment Error. Indicates that the incoming packet did not end on
X *	a byte boundry and the CRC did not match at the last byte boundry.
X */
X#define ED_RSR_FAE	0x04
X
X/*
X * FO: FIFO Overrun. Indicates that the FIFO was not serviced (during local DMA)
X *	causing it to overrun. Reception of the packet is aborted.
X */
X#define ED_RSR_FO	0x08
X
X/*
X * MPA: Missed Packet. Indicates that the received packet couldn't be stored in
X *	the ring-buffer because of insufficient buffer space (exceeding the
X *	boundry pointer), or because the transfer to the ring-buffer was inhibited
X *	by RCR_MON - monitor mode.
X */
X#define ED_RSR_MPA	0x10
X
X/*
X * PHY: Physical address. If 0, the packet received was sent to a physical address.
X *	If 1, the packet was accepted because of a multicast/broadcast address
X *	match.
X */
X#define ED_RSR_PHY	0x20
X
X/*
X * DIS: Receiver Disabled. Set to indicate that the receiver has enetered monitor
X *	mode. Cleared when the receiver exits monitor mode.
X */
X#define ED_RSR_DIS	0x40
X
X/*
X * DFR: Deferring. Set to indicate a 'jabber' condition. The CRS and COL inputs
X *	are active, and the transceiver has set the CD line as a result of the
X *	jabber.
X */
X#define ED_RSR_DFR	0x80
X
X/*
X * receive ring discriptor
X *
X * The National Semiconductor DS8390 Network interface controller uses
X * the following receive ring headers.  The way this works is that the
X * memory on the interface card is chopped up into 256 bytes blocks.
X * A contiguous portion of those blocks are marked for receive packets
X * by setting start and end block #'s in the NIC.  For each packet that
X * is put into the receive ring, one of these headers (4 bytes each) is
X * tacked onto the front.
X */
Xstruct ed_ring	{
X	struct edr_status {		/* received packet status	*/
X	    u_char rs_prx:1,		/* packet received intack	*/
X		   rs_crc:1,		/* crc error		*/
X	           rs_fae:1,		/* frame alignment error	*/
X	           rs_fo:1,		/* fifo overrun		*/
X	           rs_mpa:1,		/* packet received intack	*/
X	           rs_phy:1,		/* packet received intack	*/
X	           rs_dis:1,		/* packet received intack	*/
X	           rs_dfr:1;		/* packet received intack	*/
X	} ed_rcv_status;		/* received packet status	*/
X	u_char	next_packet;		/* pointer to next packet	*/
X	u_short	count;			/* bytes in packet (length + 4)	*/
X};
X
X/*
X * 				Common constants
X */
X#define ED_PAGE_SIZE		256		/* Size of RAM pages in bytes */
X#define ED_TXBUF_SIZE		6		/* Size of TX buffer in pages */
X
X/*
X * Vendor types
X */
X#define ED_VENDOR_WD_SMC	0x00		/* Western Digital/SMC */
X#define ED_VENDOR_3COM		0x01		/* 3Com */
X
X/*
X * Compile-time config flags
X */
X/*
X * this sets the default for enabling/disablng the tranceiver
X */
X#define ED_FLAGS_DISABLE_TRANCEIVER	0x01
X
X/*
X * This forces the board to be used in 8/16bit mode even if it
X *	autoconfigs differently
X */
X#define ED_FLAGS_FORCE_8BIT_MODE	0x02
X#define ED_FLAGS_FORCE_16BIT_MODE	0x04
X
X/*
X * This disables the use of double transmit buffers.
X */
X#define ED_FLAGS_NO_DOUBLE_BUFFERING	0x08
X
X/*
X *		Definitions for Western digital/SMC WD80x3 series ASIC
X */
X/*
X * Memory Select Register (MSR)
X */
X#define ED_WD_MSR	0
X
X#define ED_WD_MSR_ADDR	0x3f	/* Memory decode bits 18-13 */
X#define ED_WD_MSR_MENB	0x40	/* Memory enable */
X#define ED_WD_MSR_RST	0x80	/* Reset board */
X
X/*
X * Interface Configuration Register (ICR)
X */
X#define ED_WD_ICR	1
X
X#define ED_WD_ICR_16BIT	0x01	/* 16-bit interface */
X#define ED_WD_ICR_OAR	0x02	/* select register. 0=BIO 1=EAR */
X#define ED_WD_ICR_IR2	0x04	/* high order bit of encoded IRQ */
X#define ED_WD_ICR_MSZ	0x08	/* memory size (0=8k 1=32k) */
X#define ED_WD_ICR_RLA	0x10	/* recall LAN address */
X#define ED_WD_ICR_RX7	0x20	/* recall all but i/o and LAN address */
X#define	ED_WD_ICR_RIO	0x40	/* recall i/o address */
X#define ED_WD_ICR_STO	0x80	/* store to non-volatile memory */
X
X/*
X * IO Address Register (IAR)
X */
X#define ED_WD_IAR	2
X
X/*
X * EEROM Address Register
X */
X#define ED_WD_EAR	3
X
X/*
X * Interrupt Request Register (IRR)
X */
X#define ED_WD_IRR	4
X
X#define	ED_WD_IRR_0WS	0x01	/* use 0 wait-states on 8 bit bus */
X#define ED_WD_IRR_OUT1	0x02	/* WD83C584 pin 1 output */
X#define ED_WD_IRR_OUT2	0x04	/* WD83C584 pin 2 output */
X#define ED_WD_IRR_OUT3	0x08	/* WD83C584 pin 3 output */
X#define ED_WD_IRR_FLASH	0x10	/* Flash RAM is in the ROM socket */
X
X/*
X * The three bit of the encoded IRQ are decoded as follows:
X *
X *	IR2 IR1 IR0	IRQ
X *	 0   0   0	 2/9
X *	 0   0   1	 3
X *	 0   1   0	 5
X *	 0   1   1	 7
X *	 1   0   0	 10
X *	 1   0   1	 11
X *	 1   1   0	 15
X *	 1   1   1	 4
X */
X#define ED_WD_IRR_IR0	0x20	/* bit 0 of encoded IRQ */
X#define ED_WD_IRR_IR1	0x40	/* bit 1 of encoded IRQ */
X#define ED_WD_IRR_IEN	0x80	/* Interrupt enable */
X
X/*
X * LA Address Register (LAAR)
X */
X#define ED_WD_LAAR	5
X
X#define ED_WD_LAAR_ADDRHI	0x1f	/* bits 23-19 of RAM address */
X#define ED_WD_LAAR_0WS16	0x20	/* enable 0 wait-states on 16 bit bus */
X#define ED_WD_LAAR_L16EN	0x40	/* enable 16-bit operation */
X#define ED_WD_LAAR_M16EN	0x80	/* enable 16-bit memory access */
X
X/* i/o base offset to station address/card-ID PROM */
X#define ED_WD_PROM	8
X
X/* i/o base offset to CARD ID */
X#define ED_WD_CARD_ID	ED_WD_PROM+6
X
X#define ED_TYPE_WD8003S		0x02
X#define ED_TYPE_WD8003E		0x03
X#define ED_TYPE_WD8013EBT	0x05
X#define ED_TYPE_WD8013EB	0x27
X#define ED_TYPE_WD8013EBP	0x2c
X#define ED_TYPE_WD8013EPC	0x29
X
X/* Bit definitions in card ID */
X#define	ED_WD_REV_MASK		0x1f		/* Revision mask */
X#define	ED_WD_SOFTCONFIG	0x20		/* Soft config */
X#define	ED_WD_LARGERAM		0x40		/* Large RAM */
X#define	ED_MICROCHANEL		0x80		/* Microchannel bus (vs. isa) */
X
X/*
X * Checksum total. All 8 bytes in station address PROM will add up to this
X */
X#define ED_WD_ROM_CHECKSUM_TOTAL	0xFF
X
X#define ED_WD_NIC_OFFSET	0x10		/* I/O base offset to NIC */
X#define ED_WD_ASIC_OFFSET	0		/* I/O base offset to ASIC */
X#define ED_WD_IO_PORTS		32		/* # of i/o addresses used */
X
X#define ED_WD_PAGE_OFFSET	0	/* page offset for NIC access to mem */
X
X/*
X *			Definitions for 3Com 3c503
X */
X#define ED_3COM_NIC_OFFSET	0
X#define ED_3COM_ASIC_OFFSET	0x400		/* offset to nic i/o regs */
X
X/*
X * XXX - The I/O address range is fragmented in the 3c503; this is the
X *	number of regs at iobase.
X */
X#define ED_3COM_IO_PORTS	16		/* # of i/o addresses used */
X
X#define ED_3COM_PAGE_OFFSET	0x20		/* memory starts in second bank */
X
X/*
X *	Page Start Register. Must match PSTART in NIC
X */
X#define ED_3COM_PSTR		0
X
X/*
X *	Page Stop Register. Must match PSTOP in NIC
X */
X#define ED_3COM_PSPR		1
X
X/*
X *	Drq Timer Register. Determines number of bytes to be transfered during
X *		a DMA burst.
X */
X#define ED_3COM_DQTR		2
X
X/*
X *	Base Configuration Register. Read-only register which contains the
X *		board-configured I/O base address of the adapter. Bit encoded.
X */
X#define ED_3COM_BCFR		3
X
X#define ED_3COM_BCFR_2E0	0x01
X#define ED_3COM_BCFR_2A0	0x02
X#define ED_3COM_BCFR_280	0x04
X#define ED_3COM_BCFR_250	0x08
X#define ED_3COM_BCFR_350	0x10
X#define ED_3COM_BCFR_330	0x20
X#define ED_3COM_BCFR_310	0x40
X#define ED_3COM_BCFR_300	0x80
X
X/*
X *	EPROM Configuration Register. Read-only register which contains the
X *		board-configured memory base address. Bit encoded.
X */
X#define ED_3COM_PCFR		4
X
X#define ED_3COM_PCFR_C8000	0x10
X#define ED_3COM_PCFR_CC000	0x20
X#define ED_3COM_PCFR_D8000	0x40
X#define ED_3COM_PCFR_DC000	0x80
X
X/*
X *	GA Configuration Register. Gate-Array Configuration Register.
X */
X#define ED_3COM_GACFR		5
X
X/*
X * mbs2  mbs1  mbs0		start address
X *  0     0     0		0x0000
X *  0     0     1		0x2000
X *  0     1     0		0x4000
X *  0     1     1		0x6000
X *
X *	Note that with adapters with only 8K, the setting for 0x2000 must
X *		always be used.
X */
X#define ED_3COM_GACFR_MBS0	0x01
X#define ED_3COM_GACFR_MBS1	0x02
X#define ED_3COM_GACFR_MBS2	0x04
X
X#define ED_3COM_GACFR_RSEL	0x08	/* enable shared memory */
X#define ED_3COM_GACFR_TEST	0x10	/* for GA testing */
X#define ED_3COM_GACFR_OWS	0x20	/* select 0WS access to GA */
X#define ED_3COM_GACFR_TCM	0x40	/* Mask DMA interrupts */
X#define ED_3COM_GACFR_NIM	0x80	/* Mask NIC interrupts */
X
X/*
X *	Control Register. Miscellaneous control functions.
X */
X#define ED_3COM_CR		6
X
X#define ED_3COM_CR_RST		0x01	/* Reset GA and NIC */
X#define ED_3COM_CR_XSEL		0x02	/* Transceiver select. BNC=1(def) AUI=0 */
X#define ED_3COM_CR_EALO		0x04	/* window EA PROM 0-15 to I/O base */
X#define ED_3COM_CR_EAHI		0x08	/* window EA PROM 16-31 to I/O base */
X#define ED_3COM_CR_SHARE	0x10	/* select interrupt sharing option */
X#define ED_3COM_CR_DBSEL	0x20	/* Double buffer select */
X#define ED_3COM_CR_DDIR		0x40	/* DMA direction select */
X#define ED_3COM_CR_START	0x80	/* Start DMA controller */
X
X/*
X *	Status Register. Miscellaneous status information.
X */
X#define ED_3COM_STREG		7
X
X#define ED_3COM_STREG_REV	0x07	/* GA revision */
X#define ED_3COM_STREG_DIP	0x08	/* DMA in progress */
X#define ED_3COM_STREG_DTC	0x10	/* DMA terminal count */
X#define ED_3COM_STREG_OFLW	0x20	/* Overflow */
X#define ED_3COM_STREG_UFLW	0x40	/* Underflow */
X#define ED_3COM_STREG_DPRDY	0x80	/* Data port ready */
X
X/*
X *	Interrupt/DMA Configuration Register
X */
X#define ED_3COM_IDCFR		8
X
X#define ED_3COM_IDCFR_DRQ0	0x01	/* DMA request 1 select */
X#define ED_3COM_IDCFR_DRQ1	0x02	/* DMA request 2 select */
X#define ED_3COM_IDCFR_DRQ2	0x04	/* DMA request 3 select */
X#define ED_3COM_IDCFR_UNUSED	0x08	/* not used */
X#define ED_3COM_IDCFR_IRQ2	0x10	/* Interrupt request 2 select */
X#define ED_3COM_IDCFR_IRQ3	0x20	/* Interrupt request 3 select */
X#define ED_3COM_IDCFR_IRQ4	0x40	/* Interrupt request 4 select */
X#define ED_3COM_IDCFR_IRQ5	0x80	/* Interrupt request 5 select */
X
X/*
X *	DMA Address Register MSB
X */
X#define ED_3COM_DAMSB		9
X
X/*
X *	DMA Address Register LSB
X */
X#define ED_3COM_DALSB		0x0a
X
X/*
X *	Vector Pointer Register 2
X */
X#define ED_3COM_VPTR2		0x0b
X
X/*
X *	Vector Pointer Register 1
X */
X#define ED_3COM_VPTR1		0x0c
X
X/*
X *	Vector Pointer Register 0
X */
X#define ED_3COM_VPTR0		0x0d
X
X/*
X *	Register File Access MSB
X */
X#define ED_3COM_RFMSB		0x0e
X
X/*
X *	Register File Access LSB
X */
X#define ED_3COM_RFLSB		0x0f
END-of-if_edreg.h
exit