Plan 9 from Bell Labs’s /usr/web/sources/extra/9hist/pc/ether509.c

Copyright © 2021 Plan 9 Foundation.
Distributed under the MIT License.
Download the Plan 9 distribution.


## diffname pc/ether509.c 1992/0922
## diff -e /dev/null /n/bootesdump/1992/0922/sys/src/9/pc/ether509.c
0a
#include "u.h"
#include "../port/lib.h"
#include "mem.h"
#include "dat.h"
#include "fns.h"
#include "../port/error.h"
#include "io.h"
#include "devtab.h"

#define NEXT(x, l)	(((x)+1)%(l))
#define OFFSETOF(t, m)	((unsigned)&(((t*)0)->m))
#define	HOWMANY(x, y)	(((x)+((y)-1))/(y))
#define ROUNDUP(x, y)	(HOWMANY((x), (y))*(y))

enum {
	Nrb		= 16,		/* software receive buffers */
	Ntb		= 4,		/* software transmit buffers */
};

enum {
	IDport		= 0x0100,	/* anywhere between 0x0100 and 0x01F0 */

					/* Commands */
	SelectWindow	= 0x01,		/* SelectWindow command */
	StartCoax	= 0x02,		/* Start Coaxial Transceiver */
	RxDisable	= 0x03,		/* RX Disable */
	RxEnable	= 0x04,		/* RX Enable */
	RxDiscard	= 0x08,		/* RX Discard Top Packet */
	TxEnable	= 0x09,		/* TX Enable */
	TxDisable	= 0x0A,		/* TX Disable */
	AckIntr		= 0x0D,		/* Acknowledge Interrupt */
	SetIntrMask	= 0x0E,		/* Set Interrupt Mask */
	SetReadZeroMask	= 0x0F,		/* Set Read Zero Mask */
	SetRxFilter	= 0x10,		/* Set RX Filter */
	SetTxAvailable	= 0x12,		/* Set TX Available Threshold */

					/* RX Filter Command Bits */
	MyEtherAddr	= 0x01,		/* Individual address */
	Multicast	= 0x02,		/* Group (multicast) addresses */
	Broadcast	= 0x04,		/* Broadcast address */
	Promiscuous	= 0x08,		/* All addresses (promiscuous mode */

					/* Window Register Offsets */
	Command		= 0x0E,		/* all windows */
	Status		= 0x0E,

	EEPROMdata	= 0x0C,		/* window 0 */
	EEPROMcmd	= 0x0A,
	ResourceConfig	= 0x08,
	ConfigControl	= 0x04,

	TxFreeBytes	= 0x0C,		/* window 1 */
	TxStatus	= 0x0B,
	RxStatus	= 0x08,
	Fifo		= 0x00,

					/* Status/Interrupt Bits */
	Latch		= 0x0001,	/* Interrupt Latch */
	TxComplete	= 0x0004,	/* TX Complete */
	TxAvailable	= 0x0008,	/* TX Available */
	RxComplete	= 0x0010,	/* RX Complete */
	AllIntr		= 0x00FE,	/* All Interrupt Bits */
	CmdInProgress	= 0x1000,	/* Command In Progress */

					/* RxStatus Bits */
	RxByteMask	= 0x07FF,	/* RX Bytes (0-1514) */
	RxErrMask	= 0x3800,	/* Type of Error: */
	RxErrOverrun	= 0x0000,	/*   Overrrun */
	RxErrOversize	= 0x0800,	/*   Oversize Packet (>1514) */
	RxErrDribble	= 0x1000,	/*   Dribble Bit(s) */
	RxErrRunt	= 0x1800,	/*   Runt Packet */
	RxErrFraming	= 0x2000,	/*   Alignment (Framing) */
	RxErrCRC	= 0x2800,	/*   CRC */
	RxError		= 0x4000,	/* Error */
	RxEmpty		= 0x8000,	/* Incomplete or FIFO empty */
};

#define COMMAND(hw, cmd, a)	outs(hw->addr+Command, ((cmd)<<11)|(a))

/*
 * get configuration parameters
 */
static int
reset(EtherCtlr *cp)
{
	EtherHw *hw = cp->hw;
	int i, ea;
	ushort acr;
	uchar al;

	cp->rb = xspanalloc(sizeof(EtherBuf)*Nrb, BY2PG, 0);
	cp->nrb = Nrb;
	cp->tb = xspanalloc(sizeof(EtherBuf)*Ntb, BY2PG, 0);
	cp->ntb = Ntb;

	/*
	 * Do the little configuration dance. We only look
	 * at the first board that responds, if we ever have more
	 * than one we'll need to modify this sequence.
	 *
	 * 2. Write two 0 bytes then the ID sequence to the IDport.
	 */
	outb(IDport, 0);
	outb(IDport, 0);
	outb(IDport, 0xc0);
	delay(100)
	outb(IDport, 0);
	outb(IDport, 0);
	for(al = 0xFF, i = 0; i < 255; i++){
		outb(IDport, al);
		if(al & 0x80){
			al <<= 1;
			al ^= 0xCF;
		}
		else
			al <<= 1;
	}

	/*
	 * 3. Read the Product ID from the EEPROM.
	 *    This is done by writing the IDPort with 0x83 (0x80
	 *    is the 'read EEPROM command, 0x03 is the offset of
	 *    the Product ID field in the EEPROM).
	 *    The data comes back 1 bit at a time.
	 *    We seem to need a delay here between reading the bits.
	 *
	 * If the ID doesn't match the 3C509 ID code, the adapter
	 * probably isn't there, so barf.
	 */
	outb(IDport, 0x83);
	for(acr = 0, i = 0; i < 16; i++){
		delay(5);
		acr <<= 1;
		acr |= inb(IDport) & 0x01;
	}
	if((acr & 0xF0FF) != 0x9050)
		return -1;

	/*
	 * 3. Read the Address Configuration from the EEPROM.
	 *    The Address Configuration field is at offset 0x08 in the EEPROM).
	 * 6. Activate the adapter by writing the Activate command
	 *    (0xFF).
	 */
	outb(IDport, 0x88);
	for(acr = 0, i = 0; i < 16; i++){
		delay(20);
		acr <<= 1;
		acr |= inb(IDport) & 0x01;
	}
	outb(IDport, 0xFF);

	/*
	 * 8. Now we can talk to the adapter's I/O base addresses.
	 *    We get the I/O base address from the acr just read.
	 *
	 *    Enable the adapter. 
	 */
	hw->addr = (acr & 0x1F)*0x10 + 0x200;
	outb(hw->addr+ConfigControl, 0x01);

	/*
	 * Read the IRQ from the Resource Configuration Register
	 * and the ethernet address from the EEPROM.
	 * The EEPROM command is 8bits, the lower 6 bits being
	 * the address offset.
	 */
	hw->irq = (ins(hw->addr+ResourceConfig)>>12) & 0x0F;
	for(ea = 0, i = 0; i < 3; i++, ea += 2){
		while(ins(hw->addr+EEPROMcmd) & 0x8000)
			;
		outs(hw->addr+EEPROMcmd, (2<<6)|i);
		while(ins(hw->addr+EEPROMcmd) & 0x8000)
			;
		acr = ins(hw->addr+EEPROMdata);
		cp->ea[ea] = (acr>>8) & 0xFF;
		cp->ea[ea+1] = acr & 0xFF;
	}

	/*
	 * Finished with window 0. Now set the ethernet address
	 * in window 2.
	 * Commands have the format 'CCCCCAAAAAAAAAAA' where C
	 * is a bit in the command and A is a bit in the argument.
	 */
	COMMAND(hw, SelectWindow, 2);
	for(i = 0; i < 6; i++)
		outb(hw->addr+i, cp->ea[i]);

	/*
	 * Finished with window 2.
	 * Set window 1 for normal operation.
	 */
	COMMAND(hw, SelectWindow, 1);

	/*
	 * If we have a 10BASE2 transceiver, start the DC-DC
	 * converter. Wait > 800 microseconds.
	 */
	if(((acr>>14) & 0x03) == 0x03){
		COMMAND(hw, StartCoax, 0);
		delay(1);
	}

	print("3C509 I/O addr %lux irq %d:", hw->addr, hw->irq);
	for(i = 0; i < sizeof(cp->ea); i++)
		print(" %2.2ux", cp->ea[i]);
	print("\n");

	return 0;
}

static void
mode(EtherCtlr *cp, int on)
{
	EtherHw *hw = cp->hw;

	qlock(cp);
	if(on){
		cp->prom++;
		if(cp->prom == 1)
			COMMAND(hw, SetRxFilter, Promiscuous|Broadcast|MyEtherAddr);
	}
	else{
		cp->prom--;
		if(cp->prom == 0)
			COMMAND(hw, SetRxFilter, Broadcast|MyEtherAddr);
	}
	qunlock(cp);
}

static void
online(EtherCtlr *cp, int on)
{
	EtherHw *hw = cp->hw;

	USED(on);					/* BUG */
	/*
	 * Set the receiver packet filter for our own and
	 * and broadcast addresses, set the interrupt masks
	 * for all interrupts, and enable the receiver and transmitter.
	 * The only interrupt we should see under normal conditions
	 * is the receiver interrupt. If the transmit FIFO fills up,
	 * we will also see TxAvailable interrupts.
	 */
	COMMAND(hw, SetRxFilter, Broadcast|MyEtherAddr);
	COMMAND(hw, SetReadZeroMask, AllIntr|Latch);
	COMMAND(hw, SetIntrMask, AllIntr|Latch);
	COMMAND(hw, RxEnable, 0);
	COMMAND(hw, TxEnable, 0);
}


static int
getdiag(EtherHw *hw)
{
	int bytes;

	COMMAND(hw, SelectWindow, 4);
	bytes = ins(hw->addr+0x04);
	COMMAND(hw, SelectWindow, 1);
	return bytes & 0xFFFF;
}

static void
receive(EtherCtlr *cp)
{
	EtherHw *hw = cp->hw;
	ushort status;
	EtherBuf *rb;
	int len;

	while(((status = ins(hw->addr+RxStatus)) & RxEmpty) == 0){

		/*
		 * If we had an error, log it and continue
		 * without updating the ring.
		 */
		if(status & RxError){
			print("error #%ux, #%ux\n", status, getdiag(hw));
			switch(status & RxErrMask){

			case RxErrOverrun:	/* Overrrun */
				cp->overflows++;
				break;

			case RxErrOversize:	/* Oversize Packet (>1514) */
			case RxErrRunt:		/* Runt Packet */
				cp->buffs++;
				break;
			case RxErrFraming:	/* Alignment (Framing) */
				cp->frames++;
				break;

			case RxErrCRC:		/* CRC */
				cp->crcs++;
				break;
			}
		}
		else {
			/*
			 * We have a packet. Read it into the next
			 * free ring buffer, if any.
			 * The CRC is already stripped off.
			 */
			rb = &cp->rb[cp->ri];
			if(rb->owner == Interface){
				len = (status & RxByteMask);
				rb->len = len;
	
				/*
				 * Must read len bytes padded to a
				 * doubleword. We can pick them out 16-bits
				 * at a time (can try 32-bits at a time
				 * later).
				insl(hw->addr+Fifo, rb->pkt, HOWMANY(len, 4));
				 */
				inss(hw->addr+Fifo, rb->pkt, HOWMANY(len, 2));

				/*
				 * Update the ring.
				 */
				rb->owner = Host;
				cp->ri = NEXT(cp->ri, cp->nrb);
			}
		}
		/*
		 * Discard the packet as we're done with it.
		 * Wait for discard to complete.
		 */
		COMMAND(hw, RxDiscard, 0);
		while(ins(hw->addr+Status) & CmdInProgress)
			;
	}
}

static void
transmit(EtherCtlr *cp)
{
	EtherHw *hw = cp->hw;
	EtherBuf *tb;
	int s;
	ushort len;

	s = splhi();
	for(tb = &cp->tb[cp->ti]; tb->owner == Interface; tb = &cp->tb[cp->ti]){

		/*
		 * If there's no room in the FIFO for this packet,
		 * set up an interrupt for when space becomes available.
		 */
		if(tb->len > ins(hw->addr+TxFreeBytes)){
			COMMAND(hw, SetTxAvailable, tb->len);
			break;
		}

		/*
		 * There's room, copy the packet to the FIFO and free
		 * the buffer back to the host.
		 * Output packet muat be a multiple of 4 in length.
		 */
		len = ROUNDUP(tb->len, 4)/2;
		outs(hw->addr+Fifo, tb->len);
		outs(hw->addr+Fifo, 0);
		outss(hw->addr+Fifo, tb->pkt, len);
		tb->owner = Host;
		cp->ti = NEXT(cp->ti, cp->ntb);
	}
	splx(s);
}

static void
interrupt(EtherCtlr *cp)
{
	EtherHw *hw = cp->hw;
	ushort status;

	status = ins(hw->addr+Status);

	if(status & RxComplete){
		(*cp->hw->receive)(cp);
		wakeup(&cp->rr);
		status &= ~RxComplete;
	}

	if(status & TxComplete){
		/*
		 * Needs work here.
		 */
		print("txstat %ux\n", inb(hw->addr+TxStatus));
	}

	if(status & TxAvailable){
		(*cp->hw->transmit)(cp);
		wakeup(&cp->tr);
		status &= ~TxAvailable;
	}

	/*
	 * Panic if there are any interrupt bits on we haven't
	 * dealt with other than Latch.
	 */
	if(status & AllIntr)
		panic("ether509 interrupt: #%lux, #%ux\n", status, getdiag(hw));

	/*
	 * Acknowledge the interrupt.
	 */
	COMMAND(hw, AckIntr, Latch);
}

EtherHw ether509 = {
	reset,
	0,					/* init */
	mode,
	online,
	receive,
	transmit,
	interrupt,
	0,					/* tweak */
	0,					/* I/O base address */
};
.
## diffname pc/ether509.c 1992/0923
## diff -e /n/bootesdump/1992/0922/sys/src/9/pc/ether509.c /n/bootesdump/1992/0923/sys/src/9/pc/ether509.c
175,177c
		x = ins(hw->addr+EEPROMdata);
		cp->ea[ea] = (x>>8) & 0xFF;
		cp->ea[ea+1] = x & 0xFF;
.
136c
	if((x & 0xF0FF) != 0x9050)
.
133,134c
		x <<= 1;
		x |= inb(IDport) & 0x01;
.
131c
	for(x = 0, i = 0; i < 16; i++){
.
103,117c
	idseq();
	outb(IDport, 0xC1);
	delay(2);
	idseq();
.
101c
	 * 2. get to cammand state, reset, then return to command state
.
88,89c
	ushort x, acr;
.
80a
 *  Write two 0 bytes to idnetify the IDport and them reset the
 *  ID sequence.  Then send the ID sequenced to the card to get
 *  the card it into command state.
 */
void
idseq(void)
{
	int i;
	uchar al;

	outb(IDport, 0);
	outb(IDport, 0);
	for(al = 0xFF, i = 0; i < 255; i++){
		outb(IDport, al);
		if(al & 0x80){
			al <<= 1;
			al ^= 0xCF;
		}
		else
			al <<= 1;
	}
}

/*
.
## diffname pc/ether509.c 1992/0924
## diff -e /n/bootesdump/1992/0923/sys/src/9/pc/ether509.c /n/bootesdump/1992/0924/sys/src/9/pc/ether509.c
408c
		status &= ~(TxAvailable|TxComplete);
.
405c
	if(status & (TxAvailable|TxComplete)){
.
402c
		txstatus = 0;
		while(ins(hw->addr+Status) & TxComplete){
			txstatus |= inb(hw->addr+TxStatus);
			outb(hw->addr+TxStatus, 0);
		}
		if(txstatus & (TxJabber|TxUnderrun))
			COMMAND(hw, TxReset, 0);
		COMMAND(hw, TxEnable, 0);
.
400c
		 * Pop the TX Status stack, accumulating errors.
		 * If there was a Jabber or Underrun error, reset
		 * the transmitter. For all conditions enable
		 * the transmitter.
.
388a
	uchar txstatus;
.
64a
					/* TxStatus Bits */
	TxJabber	= 0x20,		/* Jabber Error */
	TxUnderrun	= 0x10,		/* Underrun */
	TxMaxColl	= 0x08,		/* Maximum Collisions */

.
30a
	TxReset		= 0x0B,		/* TX Reset */
.
## diffname pc/ether509.c 1992/0925
## diff -e /n/bootesdump/1992/0924/sys/src/9/pc/ether509.c /n/bootesdump/1992/0925/sys/src/9/pc/ether509.c
419a
		cp->oerrs++;
.
## diffname pc/ether509.c 1992/0926
## diff -e /n/bootesdump/1992/0925/sys/src/9/pc/ether509.c /n/bootesdump/1992/0926/sys/src/9/pc/ether509.c
378c
		 * Output packet must be a multiple of 4 in length.
.
## diffname pc/ether509.c 1992/1015
## diff -e /n/bootesdump/1992/0926/sys/src/9/pc/ether509.c /n/bootesdump/1992/1015/sys/src/9/pc/ether509.c
414,415c
			x = inb(hw->addr+TxStatus);
			if(x)
				outb(hw->addr+TxStatus, 0);
			txstatus |= x;
.
395c
	uchar txstatus, x;
.
298d
## diffname pc/ether509.c 1992/1016
## diff -e /n/bootesdump/1992/1015/sys/src/9/pc/ether509.c /n/bootesdump/1992/1016/sys/src/9/pc/ether509.c
424a
		/*
		 * Reset the Tx FIFO threshold.
		 */
		if(status & TxAvailable)
			COMMAND(hw, AckIntr, TxAvailable);
.
417c
		}while(ins(hw->addr+Status) & TxComplete);
.
412,414c
		do{
			if(x = inb(hw->addr+TxStatus))
.
## diffname pc/ether509.c 1992/1102
## diff -e /n/bootesdump/1992/1016/sys/src/9/pc/ether509.c /n/bootesdump/1992/1102/sys/src/9/pc/ether509.c
87c
 *  Write two 0 bytes to identify the IDport and them reset the
.
## diffname pc/ether509.c 1992/1222
## diff -e /n/bootesdump/1992/1102/sys/src/9/pc/ether509.c /n/bootesdump/1992/1222/sys/src/9/pc/ether509.c
455,456c
	0,			/* watch */
.
451,452c
	0,			/* receive */
.
449c
	0,			/* init */
	attach,
.
447c
Board ether509 = {
.
441,444c
	COMMAND(board, AckIntr, Latch);
.
439c
		panic("ether509 interrupt: #%lux, #%ux\n", status, getdiag(board));
.
436a
	 * Otherwise, acknowledge the interrupt.
.
428,430c
			COMMAND(board, AckIntr, TxAvailable);
		transmit(ctlr);
		wakeup(&ctlr->tr);
.
418,420c
			COMMAND(board, TxReset, 0);
		COMMAND(board, TxEnable, 0);
		ctlr->oerrs++;
.
416c
		}while(ins(board->io+Status) & TxComplete);

.
413,414c
			if(x = inb(board->io+TxStatus))
				outb(board->io+TxStatus, 0);
.
399,400c
		receive(ctlr);
		wakeup(&ctlr->rr);
.
396c
	status = ins(board->io+Status);
.
392c
	Board *board = ctlr->board;
.
390c
interrupt(Ctlr *ctlr)
.
384c
		ctlr->ti = NEXT(ctlr->ti, ctlr->ntb);
.
380,382c
		outs(board->io+Fifo, tb->len);
		outs(board->io+Fifo, 0);
		outss(board->io+Fifo, tb->pkt, len);
.
369,370c
		if(tb->len > ins(board->io+TxFreeBytes)){
			COMMAND(board, SetTxAvailable, tb->len);
.
363,364c
	for(tb = &ctlr->tb[ctlr->ti]; tb->owner == Interface; tb = &ctlr->tb[ctlr->ti]){
.
357,358c
	Board *board = ctlr->board;
	RingBuf *tb;
.
355c
transmit(Ctlr *ctlr)
.
348,349c
		COMMAND(board, RxDiscard, 0);
		while(ins(board->io+Status) & CmdInProgress)
.
343a

.
341c
				ctlr->ri = NEXT(ctlr->ri, ctlr->nrb);
.
335c
				inss(board->io+Fifo, rb->pkt, HOWMANY(len, 2));
.
333c
				insl(board->io+Fifo, rb->pkt, HOWMANY(len, 4));
.
323c
			rb = &ctlr->rb[ctlr->ri];
.
313c
				ctlr->crcs++;
.
309c
				ctlr->frames++;
.
306c
				ctlr->buffs++;
.
301c
				ctlr->overflows++;
.
291,292c
	while(((status = ins(board->io+RxStatus)) & RxEmpty) == 0){
.
288c
	RingBuf *rb;
.
286c
	Board *board = ctlr->board;
.
284c
receive(Ctlr *ctlr)
.
277,279c
	COMMAND(board, SelectWindow, 4);
	bytes = ins(board->io+0x04);
	COMMAND(board, SelectWindow, 1);
.
273c
getdiag(Board *board)
.
271a
	if(on)
		COMMAND(board, SetRxFilter, Promiscuous|Broadcast|MyEtherAddr);
	else
		COMMAND(board, SetRxFilter, Broadcast|MyEtherAddr);
}

.
270a
static void
mode(Ctlr *ctlr, int on)
{
	Board *board = ctlr->board;
.
264,268c
	COMMAND(board, SetRxFilter, Broadcast|MyEtherAddr);
	COMMAND(board, SetReadZeroMask, AllIntr|Latch);
	COMMAND(board, SetIntrMask, AllIntr|Latch);
	COMMAND(board, RxEnable, 0);
	COMMAND(board, TxEnable, 0);
.
236,255d
234c
	Board *board = ctlr->board;
.
232c
attach(Ctlr *ctlr)
.
223,225c
	print("3C509 I/O addr %lux irq %d:", board->io, board->irq);
	for(i = 0; i < sizeof(ctlr->ea); i++)
		print(" %2.2ux", ctlr->ea[i]);
.
219c
		COMMAND(board, StartCoax, 0);
.
212c
	COMMAND(board, SelectWindow, 1);
.
206c
		outb(board->io+i, ctlr->ea[i]);
.
204c
	COMMAND(board, SelectWindow, 2);
.
193,195c
		x = ins(board->io+EEPROMdata);
		ctlr->ea[ea] = (x>>8) & 0xFF;
		ctlr->ea[ea+1] = x & 0xFF;
.
190,191c
		outs(board->io+EEPROMcmd, (2<<6)|i);
		while(ins(board->io+EEPROMcmd) & 0x8000)
.
188c
		while(ins(board->io+EEPROMcmd) & 0x8000)
.
186c
	board->irq = (ins(board->io+ResourceConfig)>>12) & 0x0F;
.
177,178c
	board->io = (acr & 0x1F)*0x10 + 0x200;
	outb(board->io+ConfigControl, 0x01);
.
130c
	 * 2. get to command state, reset, then return to command state
.
120,124d
116c
	Board *board = ctlr->board;
.
114c
reset(Ctlr *ctlr)
.
111c
 * Get configuration parameters.
.
91c
static void
.
87,89c
 * Write two 0 bytes to identify the IDport and then reset the
 * ID sequence. Then send the ID sequence to the card to get
 * the card into command state.
.
84c
#define COMMAND(board, cmd, a)	outs(board->io+Command, ((cmd)<<11)|(a))
.
16,20d
10,13c
#include "ether.h"
.
## diffname pc/ether509.c 1993/0123
## diff -e /n/bootesdump/1992/1222/sys/src/9/pc/ether509.c /n/bootesdump/1993/0123/sys/src/9/pc/ether509.c
372a

	if(status & Failure){
		/*
		 * Adapter failure, try to find out why.
		 * Reset if necessary.
		 * What happens if Tx is active and we reset,
		 * need to retransmit?
		 * This probably isn't right.
		 */
		diag = getdiag(board);
		print("ether509: status #%ux, diag #%ux\n", status, diag);

		if(diag & TxOverrun){
			COMMAND(board, TxReset, 0);
			COMMAND(board, TxEnable, 0);
		}

		if(diag & RxUnderrun){
			COMMAND(board, RxReset, 0);
			attach(ctlr);
		}

		if(diag & TxOverrun)
			transmit(ctlr);

		return;
	}
.
369c
	ushort status, diag;
.
358c
		outss(board->io+Fifo, tb->pkt, len/2);
.
355d
353d
345,346c
		len = ROUNDUP(tb->len, 4);
		if(len > ins(board->io+TxFreeBytes)+4){
			COMMAND(board, SetTxAvailable, len);
.
343a
		 * Output packet must be a multiple of 4 in length and
		 * we need 4 bytes for the preamble.
.
255c
	bytes = ins(board->io+FIFOdiag);
.
73a

	FIFOdiag	= 0x04,		/* window 4 */

					/* FIFOdiag bits */
	TxOverrun	= 0x0400,	/* TX Overrrun */
	RxOverrun	= 0x0800,	/* RX Overrun */
	RxStatusOverrun	= 0x1000,	/* RX Status Overrun */
	RxUnderrun	= 0x2000,	/* RX Underrun */
	RxReceiving	= 0x8000,	/* RX Receiving */
.
51a
	Failure		= 0x0002,	/* Adapter Failure */
.
19a
	RxReset		= 0x05,		/* RX Reset */
.
## diffname pc/ether509.c 1993/0212
## diff -e /n/bootesdump/1993/0123/sys/src/9/pc/ether509.c /n/bootesdump/1993/0212/sys/src/9/pc/ether509.c
461,469c
Card ether509 = {
	"3Com509",			/* ident */

	reset,				/* reset */
	0,				/* init */
	attach,				/* attach */
	mode,				/* mode */

	0,				/* read */
	0,				/* write */

	0,				/* receive */
	transmit,			/* transmit */
	interrupt,			/* interrupt */
	0,				/* watch */
	0,				/* overflow */
.
458c
	COMMAND(ctlr, AckIntr, Latch);
.
456c
		panic("ether509 interrupt: #%lux, #%ux\n", status, getdiag(ctlr));
.
444c
			COMMAND(ctlr, AckIntr, TxAvailable);
.
434,435c
			COMMAND(ctlr, TxReset, 0);
		COMMAND(ctlr, TxEnable, 0);
.
431c
		}while(ins(ctlr->card.io+Status) & TxComplete);
.
428,429c
			if(x = inb(ctlr->card.io+TxStatus))
				outb(ctlr->card.io+TxStatus, 0);
.
403c
			COMMAND(ctlr, RxReset, 0);
.
398,399c
			COMMAND(ctlr, TxReset, 0);
			COMMAND(ctlr, TxEnable, 0);
.
394c
		diag = getdiag(ctlr);
.
384c
	status = ins(ctlr->card.io+Status);
.
380d
376a
static ushort
getdiag(Ctlr *ctlr)
{
	ushort bytes;

	COMMAND(ctlr, SelectWindow, 4);
	bytes = ins(ctlr->card.io+FIFOdiag);
	COMMAND(ctlr, SelectWindow, 1);
	return bytes & 0xFFFF;
}

.
374d
368,370c
		outs(ctlr->card.io+Fifo, tb->len);
		outs(ctlr->card.io+Fifo, 0);
		outss(ctlr->card.io+Fifo, tb->pkt, len/2);
.
359,360c
		if(len > ins(ctlr->card.io+TxFreeBytes)+4){
			COMMAND(ctlr, SetTxAvailable, len);
.
350d
347d
345d
336,337c
		COMMAND(ctlr, RxDiscard, 0);
		while(ins(ctlr->card.io+Status) & CmdInProgress)
.
322c
				inss(ctlr->card.io+Fifo, rb->pkt, HOWMANY(len, 2));
.
320c
				insl(ctlr->card.io+Fifo, rb->pkt, HOWMANY(len, 4));
.
279c
	while(((status = ins(ctlr->card.io+RxStatus)) & RxEmpty) == 0){
.
274d
260,270d
257c
		COMMAND(ctlr, SetRxFilter, Broadcast|MyEtherAddr);
.
255c
		COMMAND(ctlr, SetRxFilter, Promiscuous|Broadcast|MyEtherAddr);
.
252,253d
242,246c
	COMMAND(ctlr, SetRxFilter, Broadcast|MyEtherAddr);
	COMMAND(ctlr, SetReadZeroMask, AllIntr|Latch);
	COMMAND(ctlr, SetIntrMask, AllIntr|Latch);
	COMMAND(ctlr, RxEnable, 0);
	COMMAND(ctlr, TxEnable, 0);
.
232,233d
221,225d
217c
		COMMAND(ctlr, StartCoax, 0);
.
210c
	COMMAND(ctlr, SelectWindow, 1);
.
204c
		outb(ctlr->card.io+i, ctlr->ea[i]);
.
202c
	COMMAND(ctlr, SelectWindow, 2);
.
191c
		x = ins(ctlr->card.io+EEPROMdata);
.
188,189c
		outs(ctlr->card.io+EEPROMcmd, (2<<6)|i);
		while(ins(ctlr->card.io+EEPROMcmd) & 0x8000)
.
186c
		while(ins(ctlr->card.io+EEPROMcmd) & 0x8000)
.
184c
	ctlr->card.irq = (ins(ctlr->card.io+ResourceConfig)>>12) & 0x0F;
.
175,176c
	ctlr->card.io = (acr & 0x1F)*0x10 + 0x200;
	outb(ctlr->card.io+ConfigControl, 0x01);
.
125c
	 * at the first card that responds, if we ever have more
.
119d
87c
#define COMMAND(ctlr, cmd, a)	outs(ctlr->card.io+Command, ((cmd)<<11)|(a))
.
## diffname pc/ether509.c 1993/0427
## diff -e /n/bootesdump/1993/0212/sys/src/9/pc/ether509.c /n/bootesdump/1993/0427/sys/src/9/pc/ether509.c
334c
		if(len+4 > ins(ctlr->card.io+TxFreeBytes)){
.
## diffname pc/ether509.c 1993/0915
## diff -e /n/bootesdump/1993/0427/sys/src/9/pc/ether509.c /n/fornaxdump/1993/0915/sys/src/brazil/pc/ether509.c
456,461c
	/*
	 * Do the little configuration dance. We only look
	 * at the first card that responds, if we ever have more
	 * than one we'll need to modify this sequence.
	 *
	 * 2. get to command state, reset, then return to command state
	 */
	idseq();
	outb(IDport, 0xC1);
	delay(2);
	idseq();

	/*
	 * 3. Read the Product ID from the EEPROM.
	 *    This is done by writing the IDPort with 0x83 (0x80
	 *    is the 'read EEPROM command, 0x03 is the offset of
	 *    the Product ID field in the EEPROM).
	 *    The data comes back 1 bit at a time.
	 *    We seem to need a delay here between reading the bits.
	 *
	 * If the ID doesn't match the 3C509 ID code, the adapter
	 * probably isn't there, so barf.
	 */
	outb(IDport, 0x83);
	for(x = 0, i = 0; i < 16; i++){
		delay(5);
		x <<= 1;
		x |= inb(IDport) & 0x01;
	}
	if((x & 0xF0FF) != 0x9050)
		return -1;

	/*
	 * 3. Read the Address Configuration from the EEPROM.
	 *    The Address Configuration field is at offset 0x08 in the EEPROM).
	 * 6. Activate the adapter by writing the Activate command
	 *    (0xFF).
	 */
	outb(IDport, 0x88);
	for(acr = 0, i = 0; i < 16; i++){
		delay(20);
		acr <<= 1;
		acr |= inb(IDport) & 0x01;
	}
	outb(IDport, 0xFF);

	/*
	 * 8. Now we can talk to the adapter's I/O base addresses.
	 *    We get the I/O base address from the acr just read.
	 *
	 *    Enable the adapter. 
	 */
	ctlr->card.port = (acr & 0x1F)*0x10 + 0x200;
	port = ctlr->card.port;
	outb(port+ConfigControl, 0x01);

	/*
	 * Read the IRQ from the Resource Configuration Register
	 * and the ethernet address from the EEPROM.
	 * The EEPROM command is 8bits, the lower 6 bits being
	 * the address offset.
	 */
	ctlr->card.irq = (ins(port+ResourceConfig)>>12) & 0x0F;
	for(ea = 0, i = 0; i < 3; i++, ea += 2){
		while(ins(port+EEPROMcmd) & 0x8000)
			;
		outs(port+EEPROMcmd, (2<<6)|i);
		while(ins(port+EEPROMcmd) & 0x8000)
			;
		x = ins(port+EEPROMdata);
		ctlr->ea[ea] = (x>>8) & 0xFF;
		ctlr->ea[ea+1] = x & 0xFF;
	}

	/*
	 * Finished with window 0. Now set the ethernet address
	 * in window 2.
	 * Commands have the format 'CCCCCAAAAAAAAAAA' where C
	 * is a bit in the command and A is a bit in the argument.
	 */
	COMMAND(port, SelectWindow, 2);
	for(i = 0; i < 6; i++)
		outb(port+i, ctlr->ea[i]);

	/*
	 * Finished with window 2.
	 * Set window 1 for normal operation.
	 */
	COMMAND(port, SelectWindow, 1);

	/*
	 * If we have a 10BASE2 transceiver, start the DC-DC
	 * converter. Wait > 800 microseconds.
	 */
	if(((acr>>14) & 0x03) == 0x03){
		COMMAND(port, StartCoax, 0);
		delay(1);
	}

	/*
	 * Set up the software configuration.
	 */
	ctlr->card.reset = ccc509reset;
	ctlr->card.attach = attach;
	ctlr->card.mode = mode;
	ctlr->card.transmit = transmit;
	ctlr->card.intr = interrupt;
	ctlr->card.bit16 = 1;

	return 0;
}

void
ether509link(void)
{
	addethercard("3C509",  ccc509reset);
}
.
453,454c
/*
 * Get configuration parameters.
 */
int
ccc509reset(Ctlr *ctlr)
{
	int i, ea;
	ushort x, acr;
	ulong port;
.
448,451c
	outb(IDport, 0);
	outb(IDport, 0);
	for(al = 0xFF, i = 0; i < 255; i++){
		outb(IDport, al);
		if(al & 0x80){
			al <<= 1;
			al ^= 0xCF;
		}
		else
			al <<= 1;
	}
}
.
445,446c
/*
 * Write two 0 bytes to identify the IDport and then reset the
 * ID sequence. Then send the ID sequence to the card to get
 * the card into command state.
 */
static void
idseq(void)
{
	int i;
	uchar al;
.
442c
	COMMAND(port, AckIntr, Latch);
.
428c
			COMMAND(port, AckIntr, TxAvailable);
.
418,419c
			COMMAND(port, TxReset, 0);
		COMMAND(port, TxEnable, 0);
.
415c
		}while(ins(port+Status) & TxComplete);
.
412,413c
			if(x = inb(port+TxStatus))
				outb(port+TxStatus, 0);
.
387c
			COMMAND(port, RxReset, 0);
.
382,383c
			COMMAND(port, TxReset, 0);
			COMMAND(port, TxEnable, 0);
.
368c
	port = ctlr->card.port;
	status = ins(port+Status);
.
366a
	ulong port;
.
356,358c
	port = ctlr->card.port;
	COMMAND(port, SelectWindow, 4);
	bytes = ins(port+FIFOdiag);
	COMMAND(port, SelectWindow, 1);
.
354a
	ulong port;
.
343,345c
		outs(port+Fifo, tb->len);
		outs(port+Fifo, 0);
		outss(port+Fifo, tb->pkt, len/2);
.
334,335c
		if(len+4 > ins(port+TxFreeBytes)){
			COMMAND(port, SetTxAvailable, len);
.
325a
	port = ctlr->card.port;
.
324a
	ulong port;
.
314,315c
		COMMAND(port, RxDiscard, 0);
		while(ins(port+Status) & CmdInProgress)
.
300c
				inss(port+Fifo, rb->pkt, HOWMANY(len, 2));
.
298c
				insl(port+Fifo, rb->pkt, HOWMANY(len, 4));
.
257c
	port = ctlr->card.port;
	while(((status = ins(port+RxStatus)) & RxEmpty) == 0){
.
255a
	ulong port;
.
247c
		COMMAND(port, SetRxFilter, Broadcast|MyEtherAddr);
.
245c
		COMMAND(port, SetRxFilter, Promiscuous|Broadcast|MyEtherAddr);
.
243a
	ulong port;

	port = ctlr->card.port;
.
234,238c
	COMMAND(port, SetRxFilter, Broadcast|MyEtherAddr);
	COMMAND(port, SetReadZeroMask, AllIntr|Latch);
	COMMAND(port, SetIntrMask, AllIntr|Latch);
	COMMAND(port, RxEnable, 0);
	COMMAND(port, TxEnable, 0);
.
123,226d
100,121c
	port = ctlr->card.port;
.
97,98c
	ulong port;
.
95c
attach(Ctlr *ctlr)
.
89,93d
87c
#define COMMAND(port, cmd, a)	outs(port+Command, ((cmd)<<11)|(a))
.
## diffname pc/ether509.c 1993/1113
## diff -e /n/fornaxdump/1993/0915/sys/src/brazil/pc/ether509.c /n/fornaxdump/1993/1113/sys/src/brazil/pc/ether509.c
474c
	addethercard("3C509",  reset);
.
467a
	ether->promiscuous = promiscuous;
	ether->arg = ether;

.
461,466c
	ether->attach = attach;
	ether->write = write;
	ether->interrupt = interrupt;
.
441c
		outb(port+i, ether->ea[i]);
.
429,430c
		ether->ea[ea] = (x>>8) & 0xFF;
		ether->ea[ea+1] = x & 0xFF;
.
421c
	ether->irq = (ins(port+ResourceConfig)>>12) & 0x0F;
.
411,412c
	ether->port = (acr & 0x1F)*0x10 + 0x200;
	port = ether->port;
.
360,362c
	 * Do the little configuration dance:
.
352,353c
static int
reset(Ether *ether)
.
320c
		panic("ether509 interrupt: #%lux, #%ux\n", status, getdiag(ether));
.
309,310c
			wakeup(&ether->tr);
		}
.
307c
		if(status & TxAvailable){
.
300c
		ether->oerrs++;
.
278,279c
		receive(ether);
.
271,273d
268c
			attach(ether);
.
263a
			wakeup(&ether->tr);
.
258c
		diag = getdiag(ether);
.
249a
print("I%2.2ux|", status);
.
247c
	port = ether->port;
.
241c
interrupt(Ether *ether)
.
233c
	port = ether->port;
.
228c
getdiag(Ether *ether)
.
224a
	/*
	 * We know there's room, copy the packet to the FIFO.
	 * To save copying the packet into a local buffer just
	 * so we can set the source address, stuff the packet
	 * into the FIFO in 3 pieces.
	 * Transmission won't start until the entire packet is
	 * in the FIFO, so it's OK to fault here.
	 */
	outs(port+Fifo, ether->tlen);
	outs(port+Fifo, 0);
	outss(port+Fifo, buf, Eaddrlen/2);
	outss(port+Fifo, ether->ea, Eaddrlen/2);
	outss(port+Fifo, (uchar*)buf+2*Eaddrlen, (len-2*Eaddrlen)/2);
	return n;
.
215,223c
static long
write(Ether *ether, void *buf, long n)
{
	ushort len;
	ulong port;

print("W|");
	port = ether->port;
	ether->tlen = n;
	len = ROUNDUP(ether->tlen, 4);
	tsleep(&ether->tr, istxfifo, ether, 10000);
	if(len+4 > ins(port+TxFreeBytes)){
		print("ether509: transmitter jammed\n");
		return 0;
.
201,213c
	ether = arg;
	port = ether->port;
	/*
	 * If there's no room in the FIFO for this packet,
	 * set up an interrupt for when space becomes available.
	 * Output packet must be a multiple of 4 in length and
	 * we need 4 bytes for the preamble.
	 * Assume here that when we are called (via tsleep) that
	 * we are safe from interrupts.
	 */
	len = ROUNDUP(ether->tlen, 4);
	if(len+4 > ins(port+TxFreeBytes)){
		COMMAND(port, SetTxAvailable, len);
		return 0;
	}
	return 1;
}
.
197c
	Ether *ether;
.
194,195c
static int
istxfifo(void *arg)
.
176,180c
			/*
			 * Copy the packet to whoever wants it.
			 */
			type = (ether->rpkt.type[0]<<8)|ether->rpkt.type[1];
			ep = &ether->f[Ntypes];
			for(fp = ether->f; fp < ep; fp++) {
				f = *fp;
				if(f && (f->type == type || f->type < 0))
					qproduce(f->in, &ether->rpkt, len);
.
162,174c
			len = (status & RxByteMask);
			inss(port+Fifo, &ether->rpkt, HOWMANY(len, 2));
.
158,160c
			 * We have a packet. Read it into the
			 * buffer. The CRC is already stripped off.
			 * Must read len bytes padded to a
			 * doubleword. We can pick them out 16-bits
			 * at a time (can try 32-bits at a time
			 * later).
			insl(port+Fifo, ether->rpkt, HOWMANY(len, 4));
.
152c
				ether->crcs++;
.
148c
				ether->frames++;
.
145c
				ether->buffs++;
.
140c
				ether->overflows++;
.
130c
	port = ether->port;
.
128a
	Netfile *f, **fp, **ep;
.
125,126c
	ushort status, type;
.
123c
receive(Ether *ether)
.
115c
	port = ((Ether*)arg)->port;
.
111c
promiscuous(void *arg, int on)
.
94c
	port = ether->port;
.
90c
attach(Ether *ether)
.
10c
#include "etherif.h"
.
8c
#include "../port/error.h"
#include "../port/netif.h"
.
6d
## diffname pc/ether509.c 1993/1116
## diff -e /n/fornaxdump/1993/1113/sys/src/brazil/pc/ether509.c /n/fornaxdump/1993/1116/sys/src/brazil/pc/ether509.c
270d
222d
## diffname pc/ether509.c 1993/1118
## diff -e /n/fornaxdump/1993/1116/sys/src/brazil/pc/ether509.c /n/fornaxdump/1993/1118/sys/src/brazil/pc/ether509.c
242a

	poperror();
	qunlock(&ether->tlock);

.
228,229c

.
226c
	if(len+4 > ins(port+TxFreeBytes))
.
222a

	qlock(&ether->tlock);
	if(waserror()) {
		qunlock(&ether->tlock);
		nexterror();
	}

.
## diffname pc/ether509.c 1993/1119
## diff -e /n/fornaxdump/1993/1118/sys/src/brazil/pc/ether509.c /n/fornaxdump/1993/1119/sys/src/brazil/pc/ether509.c
249,251d
234a
		return 0;
	}
.
233c
	if(len+4 > ins(port+TxFreeBytes)){
.
224,229d
## diffname pc/ether509.c 1993/1124
## diff -e /n/fornaxdump/1993/1119/sys/src/brazil/pc/ether509.c /n/fornaxdump/1993/1124/sys/src/brazil/pc/ether509.c
269a

.
268a
	USED(ur);

	ether = arg;
.
267a
	Ether *ether;
.
263c
interrupt(Ureg *ur, void *arg)
.
## diffname pc/ether509.c 1994/0202
## diff -e /n/fornaxdump/1993/1124/sys/src/brazil/pc/ether509.c /n/fornaxdump/1994/0202/sys/src/brazil/pc/ether509.c
172,178c
			etherrloop(ether, &ether->rpkt, len);
.
128d
125c
	ushort status;
.
## diffname pc/ether509.c 1994/0205
## diff -e /n/fornaxdump/1994/0202/sys/src/brazil/pc/ether509.c /n/fornaxdump/1994/0205/sys/src/brazil/pc/ether509.c
468c
	if((acr & XcvrTypeMask) == XcvrBNC){
.
455c
	for(i = 0; i < Eaddrlen; i++)
.
453a
	if((ether->ea[0]|ether->ea[1]|ether->ea[2]|ether->ea[3]|ether->ea[4]|ether->ea[5]) == 0){
		for(i = 0; i < sizeof(ether->ea); i++)
			ether->ea[i] = ea[i];
	}
.
446a
	acr = ins(port+AddressConfig);
.
444,445c
		ea[eax] = (x>>8) & 0xFF;
		ea[eax+1] = x & 0xFF;
.
437c
	for(eax = 0, i = 0; i < 3; i++, eax += 2){
.
431,432c
	 * Read the IRQ from the Resource Configuration Register,
	 * the ethernet address from the EEPROM, and the address configuration.
.
428d
426a
	outb(ether->port+ConfigControl, 0x01);

	return 0;
}

/*
 * Get configuration parameters.
 */
static int
reset(Ether *ether)
{
	int i, eax;
	uchar ea[Eaddrlen];
	ushort x, acr;
	ulong port;

	/*
	 * Switch out to 509 activation code if a port is supplied and is
	 * not in the EISA slot space, otherwise check the EISA card is there.
	 */
	if(ether->port < 0x1000 && activate(ether) < 0)
		return -1;
	else if((ins(ether->port+ProductID) & 0xF0FF) != 0x9050)
		return -1;

.
374d
372c
	int i;
.
366,370c
static ulong
activate(Ether *ether)
.
237c
	outsl(port+Fifo, (uchar*)buf+2*Eaddrlen, (len-2*Eaddrlen)/4);
	ether->outpackets++;
.
166c
			insl(port+Fifo, &ether->rpkt, HOWMANY(len, 4));
.
164a
			ether->inpackets++;
.
160,163c
			 * doubleword. We can pick them out 32-bits
			 * at a time.
.
132,133c
		 * If we had an error, log it and continue.
.
45a
					/* AddressConfig Bits */
	XcvrTypeMask	= 0xC000,	/* Transceiver Type Select */
	Xcvr10BaseT	= 0x0000,
	XcvrAUI		= 0x4000,
	XcvrBNC		= 0xC000,

.
44a
	ProductID	= 0x02,
	ManufacturerID	= 0x00,
.
43a
	AddressConfig	= 0x06,
.
## diffname pc/ether509.c 1994/0209
## diff -e /n/fornaxdump/1994/0205/sys/src/brazil/pc/ether509.c /n/fornaxdump/1994/0209/sys/src/brazil/pc/ether509.c
475a

	port = ether->port;
.
456,457d
453,454d
451c
	if(ether->port < 0x1000){
		if((port = activate(ether)) < 0)
			return -1;
	}
	else if(ins(ether->port+ManufacturerID) == 0x6D50)
		port = ether->port+0xC80;
	else
.
449a
	 * Port is set to either the newly activated ISA card address or
	 * the EISA slot configuration info where Window0 is always mapped.
.
433c
	return ether->port;
.
407c
	if((x & 0xF0FF) != 0x6D50)
.
401c
	outb(IDport, 0x87);
.
391,394c
	 * 3. Read the Manufacturer ID from the EEPROM.
	 *    This is done by writing the IDPort with 0x87 (0x80
	 *    is the 'read EEPROM command, 0x07 is the offset of
	 *    the Manufacturer ID field in the EEPROM).
.
56a
	Timer		= 0x0A,
.
## diffname pc/ether509.c 1994/0211
## diff -e /n/fornaxdump/1994/0209/sys/src/brazil/pc/ether509.c /n/fornaxdump/1994/0211/sys/src/brazil/pc/ether509.c
511a

	ether->port = port;
.
482,483d
458,460c
	if(port == 0)
		port = tcm579(ether);
	if(port == 0)
		port = tcm509(ether);
	if(port == 0)
.
454,456c
	port = 0;
	for(app = &adapter, ap = *app; ap; app = &ap->next, ap = ap->next){
		if(ether->port == 0 || ether->port == ap->port){
			port = ap->port;
			*app = ap->next;
			free(ap);
			break;
		}
.
449,452c
	 * Any adapter matches if no ether->port is supplied,
	 * otherwise the ports must match.
	 * See if we've already found an adapter that fits
	 * the bill.
	 * If no match then try for an EISA card and finally
	 * for an ISA card.
.
446a
	Adapter *ap, **app;
.
436a
static ulong
tcm509(Ether *ether)
{
	USED(ether);
	return 0;
}

static ulong
tcm579(Ether *ether)
{
	static int slot = 1;
	ulong port;
	Adapter *ap;

	if(slot == 1 && strncmp((char*)(KZERO|0xFFFD9), "EISA", 4))
		return 0;
	while(slot < 8){
		port = slot++*0x1000;
		if(ins(port+0xC80+ManufacturerID) != 0x6D50)
			continue;
		COMMAND(port+0xC80, GlobalReset, 0);
		delay(1000);
		outb(port+0xC80+ConfigControl, 0x01);
		COMMAND(port+0xC80, SelectWindow, 0);
		if(ether->port == 0 || ether->port == port)
			return port;

		ap = malloc(sizeof(Adapter));
		ap->port = port;
		ap->next = adapter;
		adapter = ap;
	}

	return 0;
}

.
399c
	 * If the ID doesn't match, the adapter
.
350a
typedef struct Adapter Adapter;
struct Adapter {
	Adapter	*next;
	ulong	port;
};
static Adapter *adapter;

.
15a
	GlobalReset	= 0x00,		/* Global Reset */
.
## diffname pc/ether509.c 1994/0212
## diff -e /n/fornaxdump/1994/0211/sys/src/brazil/pc/ether509.c /n/fornaxdump/1994/0212/sys/src/brazil/pc/ether509.c
461c
	while(slot < 16){
.
442c
	return port;
.
439,440c
	port = (acr & 0x1F)*0x10 + 0x200;
	outb(port+ConfigControl, 0x01);
.
416,417c
	if(x != 0x6D50)
		return 0;
.
402c
	 *    is the 'read EEPROM' command, 0x07 is the offset of
.
395,397d
392c
	 * 2. write the ID sequence to get to command state.
.
387a
	ulong port;
.
384c
activate(void)
.
## diffname pc/ether509.c 1994/0213
## diff -e /n/fornaxdump/1994/0212/sys/src/brazil/pc/ether509.c /n/fornaxdump/1994/0213/sys/src/brazil/pc/ether509.c
447a

#ifdef notdef
	ulong port;
	Adapter *ap;

	while(port = activate()){
	}

	return 0;
#endif /* notdef */
.
## diffname pc/ether509.c 1994/0215
## diff -e /n/fornaxdump/1994/0213/sys/src/brazil/pc/ether509.c /n/fornaxdump/1994/0215/sys/src/brazil/pc/ether509.c
475c
		outs(port+0xC80+ConfigControl, Ena);
.
457d
453a
		if(ether->port == 0 || ether->port == port)
			return port;

		ap = malloc(sizeof(Adapter));
		ap->port = port;
		ap->next = adapter;
		adapter = ap;
.
452a
	/*
	 * One time only:
	 *	write ID sequence to get the attention of all adapters;
	 *	global-reset all adapters;
	 *	untag all adapters.
	 */
	if(reset == 0){
		idseq();
		outb(IDport, 0xC0);
		delay(2);
		outb(IDport, 0xD0);
		reset = 1;
	}

	/*
	 * Attempt to activate adapters until one matches our
	 * address criteria.
	 */
.
446,449c
	static int reset;
.
438c
	outs(port+ConfigControl, Ena);
.
428a
	outb(IDport, 0xD1);
.
419a
	 * 6. Tag the adapter so it won't respond in future.
.
405,406c
	 * If the ID doesn't match, there are no more adapters.
.
55a
					/* ConfigControl */
	Rst		= 0x04,		/* Reset Adapter */
	Ena		= 0x01,		/* Enable Adapter */

.
48c
	ConfigControl	= 0x04,
	AddressConfig	= 0x06,
	ResourceConfig	= 0x08,
	EEPROMcmd	= 0x0A,
	EEPROMdata	= 0x0C,
.
42,46c
	ManufacturerID	= 0x00,		/* window 0 */
.
13,14c
	IDport		= 0x0110,	/* anywhere between 0x0100 and 0x01F0 */
.
## diffname pc/ether509.c 1994/0216
## diff -e /n/fornaxdump/1994/0215/sys/src/brazil/pc/ether509.c /n/fornaxdump/1994/0216/sys/src/brazil/pc/ether509.c
587a
	while(inb(port+TxStatus))
		outb(port+TxStatus, 0);
.
585a
	 * Clear out any lingering Tx status.
.
553c
	 * The EEPROM command is 8 bits, the lower 6 bits being
.
547a
		port = tcm589(ether);
	if(port == 0)
.
531,532c
	 * If no match then try for an EISA card, an ISA card
	 * and finally for a PCMCIA card.
.
513a
static ulong
tcm589(Ether *ether)
{
	USED(ether);
	return 0;
}

.
498,501c
		x = ins(port+0xC80+ProductID);
		if((x & 0xF0FF) != 0x9050/* || (x != 0x9350 && x != 0x9250)*/)
			continue;

		COMMAND(port, SelectWindow, 0);
		outs(port+ConfigControl, Ena);

		COMMAND(port, TxReset, 0);
		COMMAND(port, RxReset, 0);
		COMMAND(port, AckIntr, 0xFF);

.
493a

	/*
	 * Continue through the EISA slots looking for a match on both
	 * 3COM as the manufacturer and 3C579 or 3C579-TP as the product.
	 * If we find an adapter, select window 0, enable it and clear
	 * out any lingering status and interrupts.
	 * Trying to do a GlobalReset here to re-init the card (as in the
	 * 509 code) doesn't seem to work.
	 */
.
491a
	/*
	 * First time through, check if this is an EISA machine.
	 * If not, nothing to do.
	 */
.
488a
	ushort x;
.
472c
	while(port = activate(0)){
		if(port == 0x3F0){
			outb(IDport, 0xD1);
			continue;
		}
		outb(IDport, 0xC0);
		if(activate(1) != port)
			print("activate %d\n");
		
.
470c
	 * address criteria. If adapter is set for EISA mode,
	 * tag it and ignore. Otherwise, reset the adapter and
	 * activate it fully.
.
465c
		untag = 1;
.
462,463d
460c
	if(untag == 0){
.
458a
	 * If we do a global reset here on all adapters we'll confuse any
	 * ISA cards configured for EISA mode.
.
457d
450c
	static int untag;
.
443a
	if(tag){
		/*
		 * 6. Tag the adapter so it won't respond in future.
		 * 6. Activate the adapter by writing the Activate command
		 *    (0xFF).
		 */
		outb(IDport, 0xD1);
		outb(IDport, 0xFF);

		/*
		 * 8. Now we can talk to the adapter's I/O base addresses.
		 *    We get the I/O base address from the acr just read.
		 *
		 *    Enable the adapter.
		 */
		outs(port+ConfigControl, Ena);
	}

.
442d
432,440d
422,424d
387c
activate(int tag)
.
## diffname pc/ether509.c 1994/0218
## diff -e /n/fornaxdump/1994/0216/sys/src/brazil/pc/ether509.c /n/fornaxdump/1994/0218/sys/src/brazil/pc/ether509.c
485c
			print("tcm509: activate\n");
.
483a
		delay(2);
.
## diffname pc/ether509.c 1994/0628
## diff -e /n/fornaxdump/1994/0218/sys/src/brazil/pc/ether509.c /n/fornaxdump/1994/0628/sys/src/brazil/pc/ether509.c
636,644d
629c
	 * Enable the transceiver if necessary.
	 */
	switch(acr & XcvrTypeMask){

	case Xcvr10BaseT:
		/*
		 * Enable Link Beat and Jabber to start the
		 * transceiver.
		 */
		COMMAND(port, SelectWindow, 4);
		outb(port+MediaStatus, LinkBeatEna|JabberEna);
		break;

	case XcvrBNC:
		/*
		 * Start the DC-DC converter.
		 * Wait > 800 microseconds.
		 */
		COMMAND(port, StartCoax, 0);
		delay(1);
		break;
	}

	/*
.
98a

					/* MediaStatus bits */
	JabberEna	= 0x0040,	/* Jabber Enabled (writeable) */
	LinkBeatEna	= 0x0080,	/* Link Beat Enabled (writeable) */
.
91a
	MediaStatus	= 0x0A,
.
## diffname pc/ether509.c 1994/0715
## diff -e /n/fornaxdump/1994/0628/sys/src/brazil/pc/ether509.c /n/fornaxdump/1994/0715/sys/src/brazil/pc/ether509.c
188c
			etherrloop(ether, &ether->rpkt, len, 1);
.
## diffname pc/ether509.c 1994/1124
## diff -e /n/fornaxdump/1994/0715/sys/src/brazil/pc/ether509.c /n/fornaxdump/1994/1124/sys/src/brazil/pc/ether509.c
63c
	Timer		= 0x0A,
	TxStatus	= 0x0B,
	TxFreeBytes	= 0x0C,
.
59,61c
	Fifo		= 0x00,		/* window 1 */
.
## diffname pc/ether509.c 1994/1207
## diff -e /n/fornaxdump/1994/1124/sys/src/brazil/pc/ether509.c /n/fornaxdump/1994/1207/sys/src/brazil/pc/ether509.c
35c
	Promiscuous	= 0x08,		/* All addresses (promiscuous mode) */
.
## diffname pc/ether509.c 1995/0331
## diff -e /n/fornaxdump/1994/1207/sys/src/brazil/pc/ether509.c /n/fornaxdump/1995/0331/sys/src/brazil/pc/ether509.c
683c
	addethercard("3C509",  ether509reset);
.
606c
	if(strcmp(ether->type, "3C589") != 0)
		ether->irq = (ins(port+ResourceConfig)>>12) & 0x0F;
.
596,597d
590a
	if(strcmp(ether->type, "3C589") == 0)
		port = ether->port;
.
565,566c
int
ether509reset(Ether *ether)
.
555,561d
282d
## diffname pc/ether509.c 1995/0401
## diff -e /n/fornaxdump/1995/0331/sys/src/brazil/pc/ether509.c /n/fornaxdump/1995/0401/sys/src/brazil/pc/ether509.c
584c
		port = ether->card.port;
.
## diffname pc/ether509.c 1995/0403
## diff -e /n/fornaxdump/1995/0401/sys/src/brazil/pc/ether509.c /n/fornaxdump/1995/0403/sys/src/brazil/pc/ether509.c
584c
		port = ether->port;
.
## diffname pc/ether509.c 1995/0419
## diff -e /n/fornaxdump/1995/0403/sys/src/brazil/pc/ether509.c /n/fornaxdump/1995/0419/sys/src/brazil/pc/ether509.c
350c
	 * dealt with other than Latch. Should deal with UP (Update
	 * Statistics) for happier coexistence with Windows drivers.
.
## diffname pc/ether509.c 1995/0504
## diff -e /n/fornaxdump/1995/0419/sys/src/brazil/pc/ether509.c /n/fornaxdump/1995/0504/sys/src/brazil/pc/ether509.c
70a
	Update		= 0x0080,	/* Update Statistics */
.
## diffname pc/ether509.c 1995/0506
## diff -e /n/fornaxdump/1995/0504/sys/src/brazil/pc/ether509.c /n/fornaxdump/1995/0506/sys/src/brazil/pc/ether509.c
346,358d
325,344c
		if(status & AllIntr)
			panic("ether509 interrupt: #%lux, #%ux\n", status, getdiag(ether));
.
320,323c
		 * Panic if there are any interrupt bits on we haven't
		 * dealt with. Should deal with UP (Update Statistics)
		 * for happier coexistence with Windows drivers.
.
309,318c
	
.
304,307c
	
		if(status & (TxAvailable|TxComplete)){
			/*
			 * Reset the Tx FIFO threshold.
			 */
			if(status & TxAvailable){
				COMMAND(port, AckIntr, TxAvailable);
				wakeup(&ether->tr);
			}
			status &= ~(TxAvailable|TxComplete);
.
302c
			ether->oerrs++;
.
296,300c
		COMMAND(port, AckIntr, Latch);
		status = ins(port+Status);
		if((status & AllIntr) == 0)
			break;
	
		if(status & Failure){
			/*
			 * Adapter failure, try to find out why.
			 * Reset if necessary.
			 * What happens if Tx is active and we reset,
			 * need to retransmit?
			 * This probably isn't right.
			 */
			diag = getdiag(ether);
			print("ether509: status #%ux, diag #%ux\n", status, diag);
	
			if(diag & TxOverrun){
				COMMAND(port, TxReset, 0);
				COMMAND(port, TxEnable, 0);
				wakeup(&ether->tr);
			}
	
			if(diag & RxUnderrun){
				COMMAND(port, RxReset, 0);
				attach(ether);
			}
	
			return;
		}
	
		if(status & RxComplete){
			receive(ether);
			status &= ~RxComplete;
		}
	
		if(status & TxComplete){
			/*
			 * Pop the TX Status stack, accumulating errors.
			 * If there was a Jabber or Underrun error, reset
			 * the transmitter. For all conditions enable
			 * the transmitter.
			 */
			txstatus = 0;
			do{
				if(x = inb(port+TxStatus))
					outb(port+TxStatus, 0);
				txstatus |= x;
			}while(ins(port+Status) & TxComplete);
	
			if(txstatus & (TxJabber|TxUnderrun))
				COMMAND(port, TxReset, 0);
.
290,294c
		 * Clear the interrupt latch.
		 * It's possible to receive a packet and for another
		 * to become complete before we exit the interrupt
		 * handler so this must be done first to ensure another
		 * interrupt will occur.
.
286,288c
	for(;;){
.
## diffname pc/ether509.c 1995/0509
## diff -e /n/fornaxdump/1995/0506/sys/src/brazil/pc/ether509.c /n/fornaxdump/1995/0509/sys/src/brazil/pc/ether509.c
367c
	}
.
## diffname pc/ether509.c 1995/0517
## diff -e /n/fornaxdump/1995/0509/sys/src/brazil/pc/ether509.c /n/fornaxdump/1995/0517/sys/src/brazil/pc/ether509.c
621c
	if(pcicfg == 0)
		acr = ins(port+AddressConfig);
	else{
		ether->irq = pcicfg->irq;
		acr = Xcvr10BaseT;
		COMMAND(port, SelectWindow, 3);
		print("internal config = 0x%8.8luX\n", inl(port+0x00));
		free(pcicfg);
	}
.
609c
	if(strcmp(ether->type, "3C589") != 0 && pcicfg == 0)
.
595a
	if(port == 0 && (pcicfg = tcm590(ether)))
		port = pcicfg->baseaddr[0] & ~0x01;
.
588a
			pcicfg = ap->pcicfg;
.
585a
	pcicfg = 0;
.
575a
	PCIcfg *pcicfg;
.
564a
static PCIcfg*
tcm590(Ether *ether)
{
	PCIcfg* pcicfg;
	static uchar devno = 0;
	ulong port;
	Adapter *ap;

	pcicfg = malloc(sizeof(PCIcfg));
	while(devno < 16){
		pcicfg->vid = 0x10B7;
		pcicfg->did = 0;
		if(pcimatch(0, devno++, pcicfg) == 0)
			continue;

		port = pcicfg->baseaddr[0] & ~0x01;
		if(ether->port == 0 || ether->port == port)
			return pcicfg;

		ap = malloc(sizeof(Adapter));
		ap->pcicfg = pcicfg;
		pcicfg = malloc(sizeof(PCIcfg));
		ap->port = port;
		ap->next = adapter;
		adapter = ap;
	}
	free(pcicfg);

	return 0;
}

.
372,373c
	Adapter*	next;
	ulong		port;
	PCIcfg*		pcicfg;
.
## diffname pc/ether509.c 1995/0518
## diff -e /n/fornaxdump/1995/0517/sys/src/brazil/pc/ether509.c /n/fornaxdump/1995/0518/sys/src/brazil/pc/ether509.c
581a
		COMMAND(port, GlobalReset, 0);
		while(ins(port+Status) & CmdInProgress)
			;

.
## diffname pc/ether509.c 1995/0519
## diff -e /n/fornaxdump/1995/0518/sys/src/brazil/pc/ether509.c /n/fornaxdump/1995/0519/sys/src/brazil/pc/ether509.c
696,697c
		outs(port+MediaStatus, x|LinkBeatEna|JabberEna);
.
688a
	COMMAND(port, SelectWindow, 4);
	x = ins(port+MediaStatus) & ~(LinkBeatEna|JabberEna);
	outs(port+MediaStatus, x);
.
682d
677a
	COMMAND(port, SelectWindow, 2);
.
668c
		l = inl(port+InternalCgf);
		l &= ~0x700000;
		outl(port+InternalCgf, l);
.
649a
	COMMAND(port, SelectWindow, 0);
.
610c
	ulong l, port;
.
594a

		pcicfg = malloc(sizeof(PCIcfg));
.
591d
539c
	while(slot < MaxEISA){
.
91a
	InternalCgf	= 0x00,		/* window 3 */

.
## diffname pc/ether509.c 1995/0627
## diff -e /n/fornaxdump/1995/0519/sys/src/brazil/pc/ether509.c /n/fornaxdump/1995/0627/sys/src/brazil/pc/ether509.c
106a
	LinkBeatOk	= 0x0800,	/* Valid link beat detected (ro) */
.
## diffname pc/ether509.c 1995/0706
## diff -e /n/fornaxdump/1995/0627/sys/src/brazil/pc/ether509.c /n/fornaxdump/1995/0706/sys/src/brazil/pc/ether509.c
127,128c
	COMMAND(port, SetReadZeroMask, (AllIntr|Latch) & ~Update);
	COMMAND(port, SetIntrMask, (AllIntr|Latch) & ~Update);
.
124a
	 * Disable Update interrupts for now.
.
## diffname pc/ether509.c 1995/0721
## diff -e /n/fornaxdump/1995/0706/sys/src/brazil/pc/ether509.c /n/fornaxdump/1995/0721/sys/src/brazil/pc/ether509.c
582,583c
		if((devno = pcimatch(0, devno, pcicfg)) == -1)
			break;
.
579c
	for(;;){
.
574,575c
	static int devno = 0;
	int port;
.
193c
			etherrloop(ether, &ether->rpkt, len);
.
## diffname pc/ether509.c 1995/0801
## diff -e /n/fornaxdump/1995/0721/sys/src/brazil/pc/ether509.c /n/fornaxdump/1995/0801/sys/src/brazil/pc/ether509.c
127c
	x = Broadcast|MyEtherAddr;
	if(ether->prom)
		x |= Promiscuous;
	COMMAND(port, SetRxFilter, x);
.
115a
	int x;
.
## diffname pc/ether509.c 1995/1018
## diff -e /n/fornaxdump/1995/0801/sys/src/brazil/pc/ether509.c /n/fornaxdump/1995/1018/sys/src/brazil/pc/ether509.c
682a
	else
		acr = ins(port+AddressConfig);
.
679,680c
		switch(l & 0x700000){

		case 0x000000:
			acr = Xcvr10BaseT;
			break;

		case 0x300000:
			acr = XcvrBNC;
			break;
		}
.
677a
		acr = XcvrAUI;
.
676d
672,674c
	if(pcicfg){
.
## diffname pc/ether509.c 1995/1019
## diff -e /n/fornaxdump/1995/1018/sys/src/brazil/pc/ether509.c /n/fornaxdump/1995/1019/sys/src/brazil/pc/ether509.c
642,643c
	if(port == 0)
		port = tcm589(ether);
.
609a
static ulong
tcm589(ISAConf *isa)
{
	if(strcmp(isa->type, "3C589") != 0)
		return 0;

	/*
	 *  The 3com manual register description says that this a noop for
	 *  PCMCIA but the flow chart at the end shows it.
	 */
	COMMAND(isa->port, SelectWindow, 0);
	outs(isa->port+ConfigControl, Ena);
	return isa->port;
}

.
## diffname pc/ether509.c 1996/0227
## diff -e /n/fornaxdump/1995/1019/sys/src/brazil/pc/ether509.c /n/fornaxdump/1996/0227/sys/src/brazil/pc/ether509.c
506,510c

		/*
		 * 6. Activate the adapter by writing the Activate command
		 *    (0xFF).
		 */
		outb(IDport, 0xFF);
		delay(20);

		/*
		 * 8. Now we can talk to the adapter's I/O base addresses.
		 *    Use the I/O base address from the acr just read.
		 *
		 *    Enable the adapter.
		 */
		while(ins(port+Status) & CmdInProgress)
			;
		COMMAND(port, SelectWindow, 0);
		outs(port+ConfigControl, Ena);

		COMMAND(port, TxReset, 0);
		COMMAND(port, RxReset, 0);
		COMMAND(port, AckIntr, 0xFF);
.
502,504c
	while(port = activate()){
		/*
		 * 6. Tag the adapter so it won't respond in future.
		 */
		outb(IDport, 0xD1);
		if(port == 0x3F0)
.
497,500c
	 * Attempt to activate adapters until one matches the
	 * address criteria. If adapter is set for EISA mode (0x3F0),
	 * tag it and ignore. Otherwise, activate it fully.
.
455,473c
	return (acr & 0x1F)*0x10 + 0x200;
.
453d
436c
		delay(20);
.
434a
	delay(20);
.
415d
411c
activate(void)
.
407a

	/*
	 * One time only:
	 *	write ID sequence to get the attention of all adapters;
	 *	untag all adapters.
	 * If we do a global reset here on all adapters we'll confuse any
	 * ISA cards configured for EISA mode.
	 */
	if(untag == 0){
		outb(IDport, 0xD0);
		untag = 1;
	}
.
396a
	/*
	 * One time only:
	 *	reset any adapters listening
	 */
	if(reset == 0){
		outb(IDport, 0);
		outb(IDport, 0);
		outb(IDport, 0xC0);
		delay(20);
		reset = 1;
	}

.
395a
	static int reset, untag;
.
## diffname pc/ether509.c 1996/0228
## diff -e /n/fornaxdump/1996/0227/sys/src/brazil/pc/ether509.c /n/fornaxdump/1996/0228/sys/src/brazil/pc/ether509.c
523c
		 * 8. Can now talk to the adapter's I/O base addresses.
.
490,502d
485d
## diffname pc/ether509.c 1996/0607 # deleted
## diff -e /n/fornaxdump/1996/0228/sys/src/brazil/pc/ether509.c /n/fornaxdump/1996/0607/sys/src/brazil/pc/ether509.c
1,785d

Bell Labs OSI certified Powered by Plan 9

(Return to Plan 9 Home Page)

Copyright © 2021 Plan 9 Foundation. All Rights Reserved.
Comments to [email protected].