~kris/9p

9hist

2abcf0371dfd89ff01b61afb02b23be736daa96d — David du Colombier 32 years ago 2c75537
Plan 9 from Bell Labs 1993-11-18
4 files changed, 251 insertions(+), 249 deletions(-)

M pc/ether509.c
M pc/ether8003.c
M pc/ether8390.c
M pc/etherif.h
M pc/ether509.c => pc/ether509.c +13 -3
@@ 220,13 220,19 @@ write(Ether *ether, void *buf, long n)
	ulong port;

	port = ether->port;

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

	ether->tlen = n;
	len = ROUNDUP(ether->tlen, 4);
	tsleep(&ether->tr, istxfifo, ether, 10000);
	if(len+4 > ins(port+TxFreeBytes)){
	if(len+4 > ins(port+TxFreeBytes))
		print("ether509: transmitter jammed\n");
		return 0;
	}

	/*
	 * We know there's room, copy the packet to the FIFO.
	 * To save copying the packet into a local buffer just


@@ 240,6 246,10 @@ write(Ether *ether, void *buf, long n)
	outss(port+Fifo, buf, Eaddrlen/2);
	outss(port+Fifo, ether->ea, Eaddrlen/2);
	outss(port+Fifo, (uchar*)buf+2*Eaddrlen, (len-2*Eaddrlen)/2);

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

	return n;
}


M pc/ether8003.c => pc/ether8003.c +54 -106
@@ 57,61 57,18 @@ static int intrmap[] = {
	9, 3, 5, 7, 10, 11, 15, 4,
};

static void*
read(Ctlr *ctlr, void *to, ulong from, ulong len)
{
	/*
	 * In this case, 'from' is an index into the shared memory.
	 */
	memmove(to, (void*)(ctlr->card.mem+from), len);
	return to;
}

static void*
write(Ctlr *ctlr, ulong to, void *from, ulong len)
{
	/*
	 * In this case, 'to' is an index into the shared memory.
	 */
	memmove((void*)(ctlr->card.mem+to), from, len);
	return (void*)to;
}

static void
watch(Ctlr *ctlr)
{
	uchar msr;
	int s;

	s = splhi();
	msr = inb(ctlr->card.port+Msr);
	/*
	 * If the card has reset itself,
	 * start again.
	 */
	if((msr & Menb) == 0){
		delay(100);

		dp8390reset(ctlr);
		etherinit();

		wakeup(&ctlr->tr);
		wakeup(&ctlr->rr);
	}
	splx(s);
}

/*
 * Get configuration parameters, enable memory.
 * There are opportunities here for buckets of code.
 * We'll try to resist.
 */
int
wd8003reset(Ctlr *ctlr)
static int
reset(Ether *ether)
{
	int i;
	uchar ic[8], sum;
	ulong wd8003;
	ulong port;
	Dp8390 *dp8390;

	/*
	 * Set up the software configuration.


@@ 119,27 76,15 @@ wd8003reset(Ctlr *ctlr)
	 * Defaults are set for the dumb 8003E which can't be
	 * autoconfigured.
	 */
	if(ctlr->card.port == 0)
		ctlr->card.port = 0x280;
	if(ctlr->card.irq == 0)
		ctlr->card.irq = 3;
	if(ctlr->card.mem == 0)
		ctlr->card.mem = 0xD0000;
	if(ctlr->card.size == 0)
		ctlr->card.size = 8*1024;

	ctlr->card.reset = wd8003reset;
	ctlr->card.attach = dp8390attach;
	ctlr->card.mode = dp8390mode;
	ctlr->card.read = read;
	ctlr->card.write = write;
	ctlr->card.receive = dp8390receive;
	ctlr->card.transmit = dp8390transmit;
	ctlr->card.intr = dp8390intr;
	ctlr->card.watch = watch;
	ctlr->card.ram = 1;

	wd8003 = ctlr->card.port;
	if(ether->port == 0)
		ether->port = 0x280;
	if(ether->irq == 0)
		ether->irq = 3;
	if(ether->mem == 0)
		ether->mem = 0xD0000;
	if(ether->size == 0)
		ether->size = 8*1024;

	/*
	 * Look for the interface. We read the LAN address ROM
	 * and validate the checksum - the sum of all 8 bytes


@@ 147,17 92,22 @@ wd8003reset(Ctlr *ctlr)
	 * While we're at it, get the (possible) interface chip
	 * registers, we'll use them to check for aliasing later.
	 */
	port = ether->port;
	sum = 0;
	for(i = 0; i < sizeof(ctlr->ea); i++){
		ctlr->ea[i] = inb(wd8003+Lar+i);
		sum += ctlr->ea[i];
		ic[i] = inb(wd8003+i);
	for(i = 0; i < sizeof(ether->ea); i++){
		ether->ea[i] = inb(port+Lar+i);
		sum += ether->ea[i];
		ic[i] = inb(port+i);
	}
	sum += inb(wd8003+Id);
	sum += inb(wd8003+Cksum);
	sum += inb(port+Id);
	sum += inb(port+Cksum);
	if(sum != 0xFF)
		return -1;

	ether->private = malloc(sizeof(Dp8390));
	dp8390 = ether->private;
	dp8390->ram = 1;

	/*
	 * Check for old, dumb 8003E, which doesn't have an interface
	 * chip. Only the msr exists out of the 1st eight registers, reads


@@ 167,10 117,9 @@ wd8003reset(Ctlr *ctlr)
	 * 8003EBT, 8003S, 8003SH or 8003WT, we don't care), in which
	 * case the default irq gets used.
	 */
	if(memcmp(&ctlr->ea[1], &ic[1], 5) == 0){
	if(memcmp(&ether->ea[1], &ic[1], 5) == 0){
		memset(ic, 0, sizeof(ic));
		ic[Msr] = (((ulong)ctlr->card.mem)>>13) & 0x3F;
		ctlr->card.watch = 0;
		ic[Msr] = (((ulong)ether->mem)>>13) & 0x3F;
	}
	else{
		/*


@@ 178,65 127,64 @@ wd8003reset(Ctlr *ctlr)
		 * the 83C584 interface chip, but has 2 real registers, write Gp2 and if
		 * it reads back the same, it's not an 8013EBT.
		 */
		outb(wd8003+Gp2, 0xAA);
		inb(wd8003+Msr);				/* wiggle bus */
		if(inb(wd8003+Gp2) != 0xAA){
		outb(port+Gp2, 0xAA);
		inb(port+Msr);				/* wiggle bus */
		if(inb(port+Gp2) != 0xAA){
			memset(ic, 0, sizeof(ic));
			ic[Msr] = (((ulong)ctlr->card.mem)>>13) & 0x3F;
			ctlr->card.watch = 0;
			ic[Msr] = (((ulong)ether->mem)>>13) & 0x3F;
		}
		else
			ctlr->card.irq = intrmap[((ic[Irr]>>5) & 0x3)|(ic[Icr] & 0x4)];
			ether->irq = intrmap[((ic[Irr]>>5) & 0x3)|(ic[Icr] & 0x4)];

		/*
		 * Check if 16-bit card.
		 * If Bit16 is read/write, then we have an 8-bit card.
		 * If Bit16 is set, we're in a 16-bit slot.
		 */
		outb(wd8003+Icr, ic[Icr]^Bit16);
		inb(wd8003+Msr);				/* wiggle bus */
		if((inb(wd8003+Icr) & Bit16) == (ic[Icr] & Bit16)){
			ctlr->card.bit16 = 1;
		outb(port+Icr, ic[Icr]^Bit16);
		inb(port+Msr);				/* wiggle bus */
		if((inb(port+Icr) & Bit16) == (ic[Icr] & Bit16)){
			dp8390->bit16 = 1;
			ic[Icr] &= ~Bit16;
		}
		outb(wd8003+Icr, ic[Icr]);
		outb(port+Icr, ic[Icr]);

		if(ctlr->card.bit16 && (inb(wd8003+Icr) & Bit16) == 0)
			ctlr->card.bit16 = 0;
		if(dp8390->bit16 && (inb(port+Icr) & Bit16) == 0)
			dp8390->bit16 = 0;
	}

	ctlr->card.mem = KZERO|((ic[Msr] & 0x3F)<<13);
	if(ctlr->card.bit16)
		ctlr->card.mem |= (ic[Laar] & 0x1F)<<19;
	ether->mem = KZERO|((ic[Msr] & 0x3F)<<13);
	if(dp8390->bit16)
		ether->mem |= (ic[Laar] & 0x1F)<<19;
	else
		ctlr->card.mem |= 0x80000;
		ether->mem |= 0x80000;

	if(ic[Icr] & (1<<3))
		ctlr->card.size = 32*1024;
	if(ctlr->card.bit16)
		ctlr->card.size <<= 1;
		ether->size = 32*1024;
	if(dp8390->bit16)
		ether->size <<= 1;

	/*
	 * Set the DP8390 ring addresses.
	 */
	ctlr->card.dp8390 = wd8003+0x10;
	ctlr->card.tstart = 0;
	ctlr->card.pstart = HOWMANY(sizeof(Etherpkt), Dp8390BufSz);
	ctlr->card.pstop = HOWMANY(ctlr->card.size, Dp8390BufSz);
	dp8390->dp8390 = port+0x10;
	dp8390->tstart = 0;
	dp8390->pstart = HOWMANY(sizeof(Etherpkt), Dp8390BufSz);
	dp8390->pstop = HOWMANY(ether->size, Dp8390BufSz);

	/*
	 * Enable interface RAM, set interface width.
	 */
	outb(wd8003+Msr, ic[Msr]|Menb);
	if(ctlr->card.bit16)
		outb(wd8003+Laar, ic[Laar]|L16en|M16en|ZeroWS16);
	outb(port+Msr, ic[Msr]|Menb);
	if(dp8390->bit16)
		outb(port+Laar, ic[Laar]|L16en|M16en|ZeroWS16);

	/*
	 * Finally, init the 8390 and set the
	 * ethernet address.
	 */
	dp8390reset(ctlr);
	dp8390setea(ctlr);
	dp8390reset(ether);
	dp8390setea(ether);

	return 0;
}

M pc/ether8390.c => pc/ether8390.c +175 -139
@@ 14,6 14,9 @@

#include "etherif.h"

extern int dp8390inb(ulong);
extern void dp8390outb(ulong, uchar);

enum {
	Cr		= 0x00,		/* command register, all pages */



@@ 149,10 152,9 @@ typedef struct {
static void
dp8390disable(Dp8390 *dp8390)
{
	ulong port;
	ulong port = dp8390->dp8390;
	int timo;

	port = dp8390->dp8390;
	/*
	 * Stop the chip. Set the Stp bit and wait for the chip
	 * to finish whatever was on its tiny mind before it sets


@@ 171,9 173,8 @@ dp8390disable(Dp8390 *dp8390)
static void
dp8390ring(Dp8390 *dp8390)
{
	ulong port;
	ulong port = dp8390->dp8390;

	port = dp8390->dp8390;
	dp8390outb(port+Pstart, dp8390->pstart);
	dp8390outb(port+Pstop, dp8390->pstop);
	dp8390outb(port+Bnry, dp8390->pstop-1);


@@ 188,11 189,10 @@ dp8390ring(Dp8390 *dp8390)
void
dp8390setea(Ether *ether)
{
	ulong port;
	ulong port = ((Dp8390*)ether->private)->dp8390;
	uchar cr;
	int i;

	port = ((Dp8390*)ether->private)->dp8390;
	/*
	 * Set the ethernet address into the chip.
	 * Take care to restore the command register


@@ 210,11 210,10 @@ dp8390setea(Ether *ether)
void
dp8390getea(Ether *ether)
{
	ulong port;
	ulong port = ((Dp8390*)ether->private)->dp8390;
	uchar cr;
	int i;

	port = ((Dp8390*)ether->private)->dp8390;
	/*
	 * Get the ethernet address from the chip.
	 * Take care to restore the command register


@@ 232,11 231,10 @@ dp8390getea(Ether *ether)
static void*
dp8390read(Dp8390 *dp8390, void *to, ulong from, ulong len)
{
	ulong port;
	ulong port = dp8390->dp8390;
	uchar cr;
	int timo;

	port = dp8390->dp8390;
	/*
	 * Read some data at offset 'from' in the card's memory
	 * using the DP8390 remote DMA facility, and place it at


@@ 282,22 280,22 @@ dp8390read(Dp8390 *dp8390, void *to, ulong from, ulong len)
}

static void*
dp8390write(Ether *ether, ulong to, void *from, ulong len)
dp8390write(Dp8390 *dp8390, ulong to, void *from, ulong len)
{
	ulong dp8390, crda;
	ulong port = dp8390->dp8390;
	ulong crda;
	uchar cr;

	dp8390 = ((Dp8390*)ether->private)->dp8390;
	/*
	 * Write some data to offset 'to' in the card's memory
	 * using the DP8390 remote DMA facility, reading it at
	 * 'from' in main memory, via the I/O data port.
	 */
	cr = dp8390inb(dp8390+Cr) & ~Txp;
	dp8390outb(dp8390+Cr, Page0|RDMAabort|Sta);
	dp8390outb(dp8390+Isr, Rdc);
	cr = dp8390inb(port+Cr) & ~Txp;
	dp8390outb(port+Cr, Page0|RDMAabort|Sta);
	dp8390outb(port+Isr, Rdc);

	if(ether->bit16)
	if(dp8390->bit16)
		len = ROUNDUP(len, 2);

	/*


@@ 305,25 303,25 @@ dp8390write(Ether *ether, ulong to, void *from, ulong len)
	 * This is straight from the DP8390[12D] datasheet, hence
	 * the initial set up for read.
	 */
	crda = to-1-ether->bit16;
	dp8390outb(dp8390+Rbcr0, (len+1+ether->bit16) & 0xFF);
	dp8390outb(dp8390+Rbcr1, ((len+1+ether->bit16)>>8) & 0xFF);
	dp8390outb(dp8390+Rsar0, crda & 0xFF);
	dp8390outb(dp8390+Rsar1, (crda>>8) & 0xFF);
	dp8390outb(dp8390+Cr, Page0|RDMAread|Sta);
	crda = to-1-dp8390->bit16;
	dp8390outb(port+Rbcr0, (len+1+dp8390->bit16) & 0xFF);
	dp8390outb(port+Rbcr1, ((len+1+dp8390->bit16)>>8) & 0xFF);
	dp8390outb(port+Rsar0, crda & 0xFF);
	dp8390outb(port+Rsar1, (crda>>8) & 0xFF);
	dp8390outb(port+Cr, Page0|RDMAread|Sta);

	for(;;){
		crda = dp8390inb(dp8390+Crda0);
		crda |= dp8390inb(dp8390+Crda1)<<8;
		crda = dp8390inb(port+Crda0);
		crda |= dp8390inb(port+Crda1)<<8;
		if(crda == to){
			/*
			 * Start the remote DMA write and make sure
			 * the registers are correct.
			 */
			dp8390outb(dp8390+Cr, Page0|RDMAwrite|Sta);
			dp8390outb(port+Cr, Page0|RDMAwrite|Sta);

			crda = dp8390inb(dp8390+Crda0);
			crda |= dp8390inb(dp8390+Crda1)<<8;
			crda = dp8390inb(port+Crda0);
			crda |= dp8390inb(port+Crda1)<<8;
			if(crda != to)
				panic("crda write %d to %d\n", crda, to);



@@ 334,61 332,67 @@ dp8390write(Ether *ether, ulong to, void *from, ulong len)
	/*
	 * Pump the data into the I/O port.
	 */
	if(ether->bit16)
		outss(ether->data, from, len/2);
	if(dp8390->bit16)
		outss(dp8390->data, from, len/2);
	else
		outsb(ether->data, from, len);
		outsb(dp8390->data, from, len);

	/*
	 * Wait for the remote DMA to finish. We'll need
	 * a timeout here if this ever gets called before
	 * we know there really is a chip there.
	 */
	while((dp8390inb(dp8390+Isr) & Rdc) == 0)
	while((dp8390inb(port+Isr) & Rdc) == 0)
			;

	dp8390outb(dp8390+Isr, Rdc);
	dp8390outb(dp8390+Cr, cr);
	dp8390outb(port+Isr, Rdc);
	dp8390outb(port+Cr, cr);
	return (void*)to;
}

static uchar
getcurr(ulong dp8390)
getcurr(Dp8390 *dp8390)
{
	ulong port = dp8390->dp8390;
	uchar cr, curr;

	cr = dp8390inb(dp8390+Cr) & ~Txp;
	dp8390outb(dp8390+Cr, Page1|(~(Ps1|Ps0) & cr));
	curr = dp8390inb(dp8390+Curr);
	dp8390outb(dp8390+Cr, cr);
	cr = dp8390inb(port+Cr) & ~Txp;
	dp8390outb(port+Cr, Page1|(~(Ps1|Ps0) & cr));
	curr = dp8390inb(port+Curr);
	dp8390outb(port+Cr, cr);
	return curr;
}

static void
receive(Ether *ether)
{
	uchar curr, len1, *pkt;
	Dp8390 *dp8390;
	uchar curr, *pkt;
	Hdr hdr;
	ulong dp8390, data, len;
	ulong port, data, len, len1;
	ushort type;
	Netfile *f, **fp, **ep;

	dp8390 = ((Dp8390*)ether->private)->dp8390;
	for(curr = getcurr(dp8390); ether->nxtpkt != curr; curr = getcurr(dp8390)){
	dp8390 = ether->private;
	port = dp8390->dp8390;
	for(curr = getcurr(dp8390); dp8390->nxtpkt != curr; curr = getcurr(dp8390)){
		ether->inpackets++;

		data = ether->nxtpkt*Dp8390BufSz;
		(*ether->read)(ctlr, &hdr, data, sizeof(Hdr));
		data = dp8390->nxtpkt*Dp8390BufSz;
		if(dp8390->ram)
			memmove(&hdr, (void*)(ether->mem+data), sizeof(Hdr));
		else
			dp8390read(dp8390, &hdr, data, sizeof(Hdr));

		/*
		 * Don't believe the upper byte count, work it
		 * out from the software next-page pointer and
		 * the current next-page pointer.
		 */
		if(hdr.next > ether->nxtpkt)
			len1 = hdr.next - ether->nxtpkt - 1;
		if(hdr.next > dp8390->nxtpkt)
			len1 = hdr.next - dp8390->nxtpkt - 1;
		else
			len1 = (ether->pstop-ether->nxtpkt) + (hdr.next-ether->pstart) - 1;
			len1 = (dp8390->pstop-dp8390->nxtpkt) + (hdr.next-dp8390->pstart) - 1;
		if(hdr.len0 > (Dp8390BufSz-sizeof(Hdr)))
			len1--;



@@ 397,13 401,13 @@ receive(Ether *ether)
		/*
		 * Chip is badly scrogged, reinitialise the ring.
		 */
		if(hdr.next < ether->pstart || hdr.next >= ether->pstop
		if(hdr.next < dp8390->pstart || hdr.next >= dp8390->pstop
		  || len < 60 || len > sizeof(Etherpkt)){
			print("H#%2.2ux#%2.2ux#%2.2ux#%2.2ux,%d|",
			print("dp8390: H#%2.2ux#%2.2ux#%2.2ux#%2.2ux,%d\n",
				hdr.status, hdr.next, hdr.len0, hdr.len1, len);
			dp8390outb(dp8390+Cr, Page0|RDMAabort|Stp);
			dp8390ring(ether);
			dp8390outb(dp8390+Cr, Page0|RDMAabort|Sta);
			dp8390outb(port+Cr, Page0|RDMAabort|Stp);
			dp8390ring(dp8390);
			dp8390outb(port+Cr, Page0|RDMAabort|Sta);
			return;
		}



@@ 412,20 416,27 @@ receive(Ether *ether)
		 * If the packet wraps round the hardware ring, read it in two pieces.
		 */
		if((hdr.status & (Fo|Fae|Crce|Prxok)) == Prxok){
			pkt = ether->rpkt;
			pkt = (uchar*)&ether->rpkt;
			data += sizeof(Hdr);
			ring->len = len;
			len1 = len;

			if((data+len) >= ether->pstop*Dp8390BufSz){
				ulong count = ether->pstop*Dp8390BufSz - data;
			if((data+len1) >= dp8390->pstop*Dp8390BufSz){
				ulong count = dp8390->pstop*Dp8390BufSz - data;

				(*ether->read)(ctlr, pkt, data, count);
				if(dp8390->ram)
					memmove(pkt, (void*)(ether->mem+data), count);
				else
					dp8390read(dp8390, pkt, data, count);
				pkt += count;
				data = ether->pstart*Dp8390BufSz;
				len -= count;
				data = dp8390->pstart*Dp8390BufSz;
				len1 -= count;
			}
			if(len1){
				if(dp8390->ram)
					memmove(pkt, (void*)(ether->mem+data), len1);
				else
					dp8390read(dp8390, pkt, data, len1);
			}
			if(len)
				(*ether->read)(ctlr, pkt, data, len);

			/*
			 * Copy the packet to whoever wants it.


@@ 440,91 451,114 @@ receive(Ether *ether)
		}

		/*
		 * Finished woth this packet, update the
		 * Finished with this packet, update the
		 * hardware and software ring pointers.
		 */
		ether->nxtpkt = hdr.next;
		dp8390->nxtpkt = hdr.next;

		hdr.next--;
		if(hdr.next < ether->pstart)
			hdr.next = ether->pstop-1;
		dp8390outb(dp8390+Bnry, hdr.next);
		if(hdr.next < dp8390->pstart)
			hdr.next = dp8390->pstop-1;
		dp8390outb(port+Bnry, hdr.next);
	}
}

/*
 * Initiate a transmission. Must be called splhi().
 */
void
dp8390transmit(Ether *ether)
static int
istxbusy(void *arg)
{
	ulong dp8390;
	RingBuf *ring;

	dp8390 = ((Dp8390*)ether->private)->dp8390;
	ring = &ether->tb[ether->ti];
	if(ether->tbusy == 0 && ring->owner == Interface){
	return ((Dp8390*)arg)->busy == 0;
}

		ether->tbusy = 1;
static long
write(Ether *ether, void *buf, long n)
{
	Dp8390 *dp8390;
	ulong port;

		(*ether->write)(ctlr, ether->tstart*Dp8390BufSz, ring->pkt, ring->len);
	dp8390 = ether->private;
	port = dp8390->dp8390;

		dp8390outb(dp8390+Tbcr0, ring->len & 0xFF);
		dp8390outb(dp8390+Tbcr1, (ring->len>>8) & 0xFF);
		dp8390outb(dp8390+Cr, Page0|RDMAabort|Txp|Sta);
	qlock(&ether->tlock);
	if(waserror()) {
		qunlock(&ether->tlock);
		nexterror();
	}

	tsleep(&ether->tr, istxbusy, dp8390, 10000);
	if(dp8390->busy)
		print("dp8390: transmitter jammed\n");
	dp8390->busy = 1;

	if(dp8390->ram)
		memmove((void*)(ether->mem+dp8390->tstart*Dp8390BufSz), buf, n);
	else
		dp8390write(dp8390, dp8390->tstart*Dp8390BufSz, buf, n);

	dp8390outb(port+Tbcr0, n & 0xFF);
	dp8390outb(port+Tbcr1, (n>>8) & 0xFF);
	dp8390outb(port+Cr, Page0|RDMAabort|Txp|Sta);

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

	return n;
}

static void
overflow(Ether *ether)
{
	ulong dp8390;
	Dp8390 *dp8390;
	ulong port;
	uchar txp;
	int resend;

	dp8390 = ((Dp8390*)ether->private)->dp8390;
	dp8390 = ether->private;
	port = dp8390->dp8390;

	/*
	 * The following procedure is taken from the DP8390[12D] datasheet,
	 * it seems pretty adamant that this is what has to be done.
	 */
	txp = dp8390inb(dp8390+Cr) & Txp;
	dp8390outb(dp8390+Cr, Page0|RDMAabort|Stp);
	txp = dp8390inb(port+Cr) & Txp;
	dp8390outb(port+Cr, Page0|RDMAabort|Stp);
	delay(2);
	dp8390outb(dp8390+Rbcr0, 0);
	dp8390outb(dp8390+Rbcr1, 0);
	dp8390outb(port+Rbcr0, 0);
	dp8390outb(port+Rbcr1, 0);

	resend = 0;
	if(txp && (dp8390inb(dp8390+Isr) & (Txe|Ptx)) == 0)
	if(txp && (dp8390inb(port+Isr) & (Txe|Ptx)) == 0)
		resend = 1;

	dp8390outb(dp8390+Tcr, Lb);
	dp8390outb(dp8390+Cr, Page0|RDMAabort|Sta);
	(*ether->receive)(ether);
	dp8390outb(dp8390+Isr, Ovw);
	wakeup(&ether->rr);
	dp8390outb(dp8390+Tcr, 0);
	dp8390outb(port+Tcr, Lb);
	dp8390outb(port+Cr, Page0|RDMAabort|Sta);
	receive(ether);
	dp8390outb(port+Isr, Ovw);
	dp8390outb(port+Tcr, 0);

	if(resend)
		dp8390outb(dp8390+Cr, Page0|RDMAabort|Txp|Sta);
		dp8390outb(port+Cr, Page0|RDMAabort|Txp|Sta);
}

static void
interrupt(Ether *ether)
{
	ulong dp8390;
	Dp8390 *dp8390;
	ulong port;
	uchar isr, r;

	dp8390 = ((Dp8390*)ether->private)->dp8390;
	dp8390 = ether->private;
	port = dp8390->dp8390;

	/*
	 * While there is something of interest,
	 * clear all the interrupts and process.
	 */
	dp8390outb(dp8390+Imr, 0x00);
	while(isr = dp8390inb(dp8390+Isr)){
	dp8390outb(port+Imr, 0x00);
	while(isr = dp8390inb(port+Isr)){

		if(isr & Ovw){
			overflow(ether);
			dp8390outb(dp8390+Isr, Ovw);
			dp8390outb(port+Isr, Ovw);
			ether->overflows++;
		}



@@ 534,7 568,7 @@ interrupt(Ether *ether)
		 */
		if(isr & (Rxe|Prx)){
			receive(ether);
			dp8390outb(dp8390+Isr, Rxe|Prx);
			dp8390outb(port+Isr, Rxe|Prx);
		}

		/*


@@ 543,100 577,102 @@ interrupt(Ether *ether)
		 * and wake the output routine.
		 */
		if(isr & (Txe|Ptx)){
			r = dp8390inb(dp8390+Tsr);
			r = dp8390inb(port+Tsr);
			if(isr & Txe){
				if((r & (Cdh|Fu|Crs|Abt)) && ether->debug)
					print("Tsr#%2.2ux|", r);
				if((r & (Cdh|Fu|Crs|Abt)))
					print("dp8390: Tsr#%2.2ux\n", r);
				ether->oerrs++;
			}

			dp8390outb(dp8390+Isr, Txe|Ptx);
			dp8390outb(port+Isr, Txe|Ptx);

			if(isr & Ptx)
				ether->outpackets++;
			dp8390->busy = 0;
			wakeup(&ether->tr);
		}

		if(isr & Cnt){
			ether->frames += dp8390inb(dp8390+Cntr0);
			ether->crcs += dp8390inb(dp8390+Cntr1);
			ether->buffs += dp8390inb(dp8390+Cntr2);
			dp8390outb(dp8390+Isr, Cnt);
			ether->frames += dp8390inb(port+Cntr0);
			ether->crcs += dp8390inb(port+Cntr1);
			ether->buffs += dp8390inb(port+Cntr2);
			dp8390outb(port+Isr, Cnt);
		}
	}
	dp8390outb(dp8390+Imr, Cnte|Ovwe|Txee|Rxee|Ptxe|Prxe);
	dp8390outb(port+Imr, Cnte|Ovwe|Txee|Rxee|Ptxe|Prxe);
}

static void
promiscuous(Ether *ether, int on)
promiscuous(void *arg, int on)
{
	ulong dp8390;
	Dp8390 *dp8390 = ((Ether*)arg)->private;

	dp8390 = ((Dp8390*)ether->private)->dp8390;
	/*
	 * Set/reset promiscuous mode.
	 */
	if(on)
		dp8390outb(ether->dp8390+Rcr, Pro|Ab);
		dp8390outb(dp8390->dp8390+Rcr, Pro|Ab);
	else
		dp8390outb(ether->dp8390+Rcr, Ab);
		dp8390outb(dp8390->dp8390+Rcr, Ab);
}

void
dp8390attach(Ether *ether)
static void
attach(Ether *ether)
{
	ulong dp8390;
	Dp8390 *dp8390 = ether->private;

	dp8390 = ((Dp8390*)ether->private)->dp8390;
	/*
	 * Enable the chip for transmit/receive.
	 * The init routine leaves the chip in monitor
	 * mode. Clear the missed-packet counter, it
	 * increments while in monitor mode.
	 */
	dp8390outb(ether->dp8390+Rcr, Ab);
	dp8390inb(ether->dp8390+Cntr2);
	dp8390outb(dp8390->dp8390+Rcr, Ab);
	dp8390inb(dp8390->dp8390+Cntr2);
}

static int
int
dp8390reset(Ether *ether)
{
	ulong dp8390;
	Dp8390 *dp8390;
	ulong port;

	dp8390 = ether->private;
	port = dp8390->dp8390;

	dp8390 = ((Dp8390*)ether->private)->dp8390;
	/*
	 * This is the initialisation procedure described
	 * as 'mandatory' in the datasheet, with references
	 * to the 3Com503 technical reference manual.
	 */ 
	dp8390disable(ether);
	if(ether->bit16)
		dp8390outb(dp8390+Dcr, Ft4|Ls|Wts);
	dp8390disable(dp8390);
	if(dp8390->bit16)
		dp8390outb(port+Dcr, Ft4|Ls|Wts);
	else
		dp8390outb(dp8390+Dcr, Ft4|Ls);
		dp8390outb(port+Dcr, Ft4|Ls);

	dp8390outb(dp8390+Rbcr0, 0);
	dp8390outb(dp8390+Rbcr1, 0);
	dp8390outb(port+Rbcr0, 0);
	dp8390outb(port+Rbcr1, 0);

	dp8390outb(dp8390+Tcr, 0);
	dp8390outb(dp8390+Rcr, Mon);
	dp8390outb(port+Tcr, 0);
	dp8390outb(port+Rcr, Mon);

	/*
	 * Init the ring hardware and software ring pointers.
	 * Can't initialise ethernet address as we may not know
	 * it yet.
	 */
	dp8390ring(ether);
	dp8390outb(dp8390+Tpsr, ether->tstart);
	dp8390ring(dp8390);
	dp8390outb(port+Tpsr, dp8390->tstart);

	dp8390outb(dp8390+Isr, 0xFF);
	dp8390outb(dp8390+Imr, Cnte|Ovwe|Txee|Rxee|Ptxe|Prxe);
	dp8390outb(port+Isr, 0xFF);
	dp8390outb(port+Imr, Cnte|Ovwe|Txee|Rxee|Ptxe|Prxe);

	/*
	 * Leave the chip initialised,
	 * but in monitor mode.
	 */
	dp8390outb(dp8390+Cr, Page0|RDMAabort|Sta);
	dp8390outb(port+Cr, Page0|RDMAabort|Sta);

	/*
	 * Set up the software configuration.

M pc/etherif.h => pc/etherif.h +9 -1
@@ 28,12 28,20 @@ typedef struct {

	ulong	dp8390;			/* I/O address of 8390 */
	ulong	data;			/* I/O data port if no shared memory */
	uchar	nxtpkt;			/* software bndry */

	uchar	nxtpkt;			/* receive: software bndry */
	uchar	busy;			/* transmit: busy */
	uchar	tstart;			/* 8390 ring addresses */
	uchar	pstart;
	uchar	pstop;
} Dp8390;

#define Dp8390BufSz	256

extern int dp8390reset(Ether*);
extern void dp8390getea(Ether*);
extern void dp8390setea(Ether*);

#define NEXT(x, l)	(((x)+1)%(l))
#define	HOWMANY(x, y)	(((x)+((y)-1))/(y))
#define ROUNDUP(x, y)	(HOWMANY((x), (y))*(y))