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

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


## diffname pc/ether8390.c 1992/1222
## diff -e /dev/null /n/bootesdump/1992/1222/sys/src/9/pc/ether8390.c
0a
/*
 * National Semiconductor DP8390
 * and SMC 83C90
 * Network Interface Controller.
 */
#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"

#include "ether.h"

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

	Stp		= 0x01,		/* stop */
	Sta		= 0x02,		/* start */
	Txp		= 0x04,		/* transmit packet */
	RDMAread	= (1<<3),	/* remote DMA read */
	RDMAwrite	= (2<<3),	/* remote DMA write */
	RDMAsend	= (3<<3),	/* remote DMA send packet */
	RDMAabort	= (4<<3),	/* abort/complete remote DMA */
	Page0		= (0x00<<6),	/* page select */
	Page1		= (0x01<<6),
	Page2		= (0x02<<6),
};

enum {					/* Page 0, read */
	Clda0		= 0x01,		/* current local DMA address 0 */
	Clda1		= 0x02,		/* current local DMA address 1 */
	Bnry		= 0x03,		/* boundary pointer (R/W) */
	Tsr		= 0x04,		/* transmit status register */
	Ncr		= 0x05,		/* number of collisions register */
	Fifo		= 0x06,		/* FIFO */
	Isr		= 0x07,		/* interrupt status register (R/W) */
	Crda0		= 0x08,		/* current remote DMA address 0 */
	Crda1		= 0x08,		/* current remote DMA address 1 */
	Rsr		= 0x0C,		/* receive status register */
	Cntr0		= 0x0D,		/* frame alignment errors */
	Cntr1		= 0x0E,		/* CRC errors */
	Cntr2		= 0x0F,		/* missed packet errors */
};

enum {					/* Page 0, write */
	Pstart		= 0x01,		/* page start register */
	Pstop		= 0x02,		/* page stop register */
	Tpsr		= 0x04,		/* transmit page start address */
	Tbcr0		= 0x05,		/* transmit byte count register 0 */
	Tbcr1		= 0x06,		/* transmit byte count register 1 */
	Rsar0		= 0x08,		/* remote start address register 0 */
	Rsar1		= 0x09,		/* remote start address register 1 */
	Rbcr0		= 0x0A,		/* remote byte count register 0 */
	Rbcr1		= 0x0B,		/* remote byte count register 1 */
	Rcr		= 0x0C,		/* receive configuration register */
	Tcr		= 0x0D,		/* transmit configuration register */
	Dcr		= 0x0E,		/* data configuration register */
	Imr		= 0x0F,		/* interrupt mask */
};

enum {					/* Page 1, read/write */
	Par0		= 0x01,		/* physical address register 0 */
	Curr		= 0x07,		/* current page register */
	Mar0		= 0x08,		/* multicast address register 0 */
};

enum {					/* Interrupt Status Register */
	Prx		= 0x01,		/* packet received */
	Ptx		= 0x02,		/* packet transmitted */
	Rxe		= 0x04,		/* receive error */
	Txe		= 0x08,		/* transmit error */
	Ovw		= 0x10,		/* overwrite warning */
	Cnt		= 0x20,		/* counter overflow */
	Rdc		= 0x40,		/* remote DMA complete */
	Rst		= 0x80,		/* reset status */
};

enum {					/* Interrupt Mask Register */
	Prxe		= 0x01,		/* packet received interrupt enable */
	Ptxe		= 0x02,		/* packet transmitted interrupt enable */
	Rxee		= 0x04,		/* receive error interrupt enable */
	Txee		= 0x08,		/* transmit error interrupt enable */
	Ovwe		= 0x10,		/* overwrite warning interrupt enable */
	Cnte		= 0x20,		/* counter overflow interrupt enable */
	Rdce		= 0x40,		/* DMA complete interrupt enable */
};

enum {					/* Data Configuration register */
	Wts		= 0x01,		/* word transfer select */
	Bos		= 0x02,		/* byte order select */
	Las		= 0x04,		/* long address select */
	Ls		= 0x08,		/* loopback select */
	Arm		= 0x10,		/* auto-initialise remote */
	Ft1		= (0x00<<5),	/* FIFO threshhold select 1 byte/word */
	Ft2		= (0x01<<5),	/* FIFO threshhold select 2 bytes/words */
	Ft4		= (0x02<<5),	/* FIFO threshhold select 4 bytes/words */
	Ft6		= (0x03<<5),	/* FIFO threshhold select 6 bytes/words */
};

enum {					/* Transmit Configuration Register */
	Crc		= 0x01,		/* inhibit CRC */
	Lb		= 0x02,		/* internal loopback */
	Atd		= 0x08,		/* auto transmit disable */
	Ofst		= 0x10,		/* collision offset enable */
};

enum {					/* Transmit Status Register */
	Ptxok		= 0x01,		/* packet transmitted */
	Col		= 0x04,		/* transmit collided */
	Abt		= 0x08,		/* tranmit aborted */
	Crs		= 0x10,		/* carrier sense lost */
	Fu		= 0x20,		/* FIFO underrun */
	Cdh		= 0x40,		/* CD heartbeat */
	Owc		= 0x80,		/* out of window collision */
};

enum {					/* Receive Configuration Register */
	Sep		= 0x01,		/* save errored packets */
	Ar		= 0x02,		/* accept runt packets */
	Ab		= 0x04,		/* accept broadcast */
	Am		= 0x08,		/* accept multicast */
	Pro		= 0x10,		/* promiscuous physical */
	Mon		= 0x20,		/* monitor mode */
};

enum {					/* Receive Status Register */
	Prxok		= 0x01,		/* packet received intact */
	Crce		= 0x02,		/* CRC error */
	Fae		= 0x04,		/* frame alignment error */
	Fo		= 0x08,		/* FIFO overrun */
	Mpa		= 0x10,		/* missed packet */
	Phy		= 0x20,		/* physical/multicast address */
	Dis		= 0x40,		/* receiver disabled */
	Dfr		= 0x80,		/* deferring */
};

typedef struct {
	uchar	status;
	uchar	next;
	uchar	len0;
	uchar	len1;
} Hdr;

typedef struct {
	Hdr;
	uchar	data[Dp8390BufSz-sizeof(Hdr)];
} Buf;

static void
dp8390disable(Ctlr *ctlr)
{
	Board *board = ctlr->board;
	int timo;

	/*
	 * Stop the chip. Set the Stp bit and wait for the chip
	 * to finish whatever was on its tiny mind before it sets
	 * the Rst bit.
	 * We need the timeout because there may not be a real
	 * chip there if this is called when probing for a device
	 * at boot.
	 */
	outb(board->dp8390+Cr, Page0|RDMAabort|Stp);
	for(timo = 10000; (inb(board->dp8390+Isr) & Rst) == 0 && timo; timo--)
			;
}

void
dp8390reset(Ctlr *ctlr)
{
	Board *board = ctlr->board;

	/*
	 * This is the initialisation procedure described
	 * as 'mandatory' in the datasheet.
	 */ 
	dp8390disable(ctlr);
	if(board->bit16)
		outb(board->dp8390+Dcr, Ft4|Ls|Wts);
	else
		outb(board->dp8390+Dcr, Ft4|Ls);

	outb(board->dp8390+Rbcr0, 0);
	outb(board->dp8390+Rbcr1, 0);

	outb(board->dp8390+Rcr, Ab);
	outb(board->dp8390+Tcr, Lb);

	outb(board->dp8390+Bnry, board->pstart);
	outb(board->dp8390+Pstart, board->pstart);
	outb(board->dp8390+Pstop, board->pstop);

	outb(board->dp8390+Isr, 0xFF);
	outb(board->dp8390+Imr, Ovwe|Txee|Rxee|Ptxe|Prxe);

	outb(board->dp8390+Cr, Page1|RDMAabort|Stp);

	/*
	 * Can't initialise ethernet address as we may
	 * not know it yet.
	 */
	outb(board->dp8390+Curr, board->pstart+1);

	/*
	 * Leave the chip initialised,
	 * but in internal loopback mode.
	 */
	outb(board->dp8390+Cr, Page0|RDMAabort|Sta);

	outb(board->dp8390+Tpsr, board->tstart);
}

void
dp8390attach(Ctlr *ctlr)
{
	/*
	 * Enable the chip for transmit/receive.
	 * The init routine leaves the chip in internal
	 * loopback.
	 */
	outb(ctlr->board->dp8390+Tcr, 0);
}

void
dp8390mode(Ctlr *ctlr, int on)
{
	if(on)
		outb(ctlr->board->dp8390+Rcr, Pro|Ab);
	else
		outb(ctlr->board->dp8390+Rcr, Ab);
}

void
dp8390setea(Ctlr *ctlr)
{
	Board *board = ctlr->board;
	uchar cr;
	int i;

	/*
	 * Set the ethernet address into the chip.
	 * Take care to restore the command register
	 * afterwards. We don't care about multicast
	 * addresses as we never set the multicast
	 * enable.
	 */
	cr = inb(board->dp8390+Cr);
	outb(board->dp8390+Cr, Page1|(~Page0 & cr));
	for(i = 0; i < sizeof(ctlr->ea); i++)
		outb(board->dp8390+Par0+i, ctlr->ea[i]);
	outb(board->dp8390+Cr, cr);
}

void*
dp8390read(Ctlr *ctlr, void *to, ulong from, ulong len)
{
	Board *board = ctlr->board;
	uchar cr;
	int timo;

	/*
	 * If the interface has shared memory, just
	 * do a memmove.
	 * In this case, 'from' is an index into the shared memory.
	 */
	if(board->ram){
		memmove(to, (void*)(board->ramstart+from), len);
		return to;
	}

	/*
	 * Read some data at offset 'from' in the board's memory
	 * using the DP8390 remote DMA facility, and place it at
	 * 'to' in main memory, via the I/O data port.
	 */
	cr = inb(board->dp8390+Cr);
	outb(board->dp8390+Cr, Page0|RDMAabort|Sta);
	outb(board->dp8390+Isr, Rdc);

	/*
	 * Set up the remote DMA address and count.
	 */
	if(board->bit16)
		len = ROUNDUP(len, 2);
	outb(board->dp8390+Rbcr0, len & 0xFF);
	outb(board->dp8390+Rbcr1, (len>>8) & 0xFF);
	outb(board->dp8390+Rsar0, from & 0xFF);
	outb(board->dp8390+Rsar1, (from>>8) & 0xFF);

	/*
	 * Start the remote DMA read and suck the data
	 * out of the I/O port.
	 */
	outb(board->dp8390+Cr, Page0|RDMAread|Sta);
	if(board->bit16)
		inss(board->data, to, len/2);
	else
		insb(board->data, to, len);

	/*
	 * Wait for the remote DMA to complete. The timeout
	 * is necessary because we may call this routine on
	 * a non-existent chip during initialisation and, due
	 * to the miracles of the bus, we could get this far
	 * and still be talking to a slot full of nothing.
	 */
	for(timo = 10000; (inb(board->dp8390+Isr) & Rdc) == 0 && timo; timo--)
			;

	outb(board->dp8390+Isr, Rdc);
	outb(board->dp8390+Cr, cr);
	return to;
}

void*
dp8390write(Ctlr *ctlr, ulong to, void *from, ulong len)
{
	Board *board = ctlr->board;
	uchar cr;

	/*
	 * If the interface has shared memory, just
	 * do a memmove.
	 * In this case, 'to' is an index into the shared memory.
	 */
	if(board->ram){
		memmove((void*)(board->ramstart+to), from, len);
		return (void*)to;
	}

	/*
	 * Write some data to offset 'to' in the board's memory
	 * using the DP8390 remote DMA facility, reading it at
	 * 'from' in main memory, via the I/O data port.
	 */
	cr = inb(board->dp8390+Cr);
	outb(board->dp8390+Cr, Page0|RDMAabort|Sta);
	outb(board->dp8390+Isr, Rdc);

	/*
	 * Set up the remote DMA address and count.
	 * This is straight from the datasheet, hence
	 * the initial write to Rbcr0 and Cr.
	 */
	outb(board->dp8390+Rbcr0, 0xFF);
	outb(board->dp8390+Cr, Page0|RDMAread|Sta);

	if(board->bit16)
		len = ROUNDUP(len, 2);
	outb(board->dp8390+Rbcr0, len & 0xFF);
	outb(board->dp8390+Rbcr1, (len>>8) & 0xFF);
	outb(board->dp8390+Rsar0, to & 0xFF);
	outb(board->dp8390+Rsar1, (to>>8) & 0xFF);

	/*
	 * Start the remote DMA write and pump the data
	 * into the I/O port.
	 */
	outb(board->dp8390+Cr, Page0|RDMAwrite|Sta);
	if(board->bit16)
		outss(board->data, from, len/2);
	else
		outsb(board->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((inb(board->dp8390+Isr) & Rdc) == 0)
			;

	outb(board->dp8390+Isr, Rdc);
	outb(board->dp8390+Cr, cr);
	return (void*)to;
}

void
dp8390receive(Ctlr *ctlr)
{
	Board *board = ctlr->board;
	RingBuf *ring;
	uchar bnry, curr, next;
	Hdr hdr;
	ulong data;
	int i, len;

	bnry = inb(board->dp8390+Bnry);
	next = bnry+1;
	if(next >= board->pstop)
		next = board->pstart;

	for(i = 0; ; i++){
		outb(board->dp8390+Cr, Page1|RDMAabort|Sta);
		curr = inb(board->dp8390+Curr);
		outb(board->dp8390+Cr, Page0|RDMAabort|Sta);
		if(next == curr)
			break;

		/*
		 * Hack to keep away from the card's memory while it is receiving
		 * a packet. This is only a problem on the NCR 3170 Safari.
		 *
		 * We peek at the current local DMA registers and, if they are
		 * changing, wait.
		 */
		if(strcmp(arch->id, "NCRD.0") == 0){
			uchar a, b, c;
		
			for(;;delay(10)){
				a = inb(board->dp8390+Clda0);
				b = inb(board->dp8390+Clda0);
				if(a != b)
					continue;
				c = inb(board->dp8390+Clda0);
				if(c != b)
					continue;
				break;
			}
		}

		ctlr->inpackets++;

		data = next*Dp8390BufSz;
		dp8390read(ctlr, &hdr, data, sizeof(Hdr));
		len = ((hdr.len1<<8)|hdr.len0)-4;

		/*
		 * Chip is badly scrogged, reinitialise it.
		 * dp8390reset() calls the disable function.
		 * There's no need to reload the ethernet
		 * address.
		 *
		 * Untested.
		 */
		if(hdr.next < board->pstart || hdr.next >= board->pstop || len < 60){
print("scrogged\n");
			dp8390reset(ctlr);
			dp8390attach(ctlr);
			return;
		}

		ring = &ctlr->rb[ctlr->ri];
		if(ring->owner == Interface){
			ring->len = len;
			data += sizeof(Hdr);
			if((data+len) >= board->pstop*Dp8390BufSz){
				len = board->pstop*Dp8390BufSz - data;
				dp8390read(ctlr, ring->pkt+len, board->pstart*Dp8390BufSz,
					(data+ring->len) - board->pstop*Dp8390BufSz);
			}
			dp8390read(ctlr, ring->pkt, data, len);
			ring->owner = Host;
			ctlr->ri = NEXT(ctlr->ri, ctlr->nrb);
		}

		next = hdr.next;
		bnry = next-1;
		if(bnry < board->pstart)
			bnry = board->pstop-1;
		outb(board->dp8390+Bnry, bnry);
	}
}

void
dp8390transmit(Ctlr *ctlr)
{
	Board *board;
	RingBuf *ring;
	int s;

	s = splhi();
	board = ctlr->board;
	ring = &ctlr->tb[ctlr->ti];
	if(ring->busy == 0 && ring->owner == Interface){
		dp8390write(ctlr, board->tstart*Dp8390BufSz, ring->pkt, ring->len);
		outb(board->dp8390+Tbcr0, ring->len & 0xFF);
		outb(board->dp8390+Tbcr1, (ring->len>>8) & 0xFF);
		outb(board->dp8390+Cr, Page0|RDMAabort|Txp|Sta);
		ring->busy = 1;
	}
	splx(s);
}

void
dp8390intr(Ctlr *ctlr)
{
	Board *board = ctlr->board;
	RingBuf *ring;
	uchar isr;

	/*
	 * While there is something of interest,
	 * clear all the interrupts and process.
	 */
	while(isr = inb(board->dp8390+Isr)){
		outb(board->dp8390+Isr, isr);

		if(isr & Ovw){
			/*
			 * Need to do some work here:
			 *   stop the chip;
			 *   clear out the ring;
			 *   re-enable the chip.
			 * The procedure to put the chip back on
			 * an active network is to first put it
			 * into internal loopback mode, enable it,
			 * then take it out of loopback.
			 *
			 * Untested.
			 */
			ctlr->overflows++;

			dp8390disable(ctlr);
			(*ctlr->board->receive)(ctlr);
			outb(board->dp8390+Tcr, Lb);
			outb(board->dp8390+Cr, Page0|RDMAabort|Sta);
			dp8390attach(ctlr);
		}

		/*
		 * We have received packets.
		 * Take a spin round the ring and
		 * wakeup the kproc.
		 */
		if(isr & (Rxe|Prx)){
			(*ctlr->board->receive)(ctlr);
			wakeup(&ctlr->rr);
		}

		/*
		 * Log errors and successful transmissions.
		 */
		if(isr & Txe)
			ctlr->oerrs++;
		if(isr & Rxe){
			ctlr->frames += inb(board->dp8390+Cntr0);
			ctlr->crcs += inb(board->dp8390+Cntr1);
			ctlr->buffs += inb(board->dp8390+Cntr2);
		}
		if(isr & Ptx)
			ctlr->outpackets++;

		/*
		 * A packet completed transmission, successfully or
		 * not. Start transmission on the next buffered packet,
		 * and wake the output routine.
		 */
		if(isr & (Txe|Ptx)){
			ring = &ctlr->tb[ctlr->ti];
			ring->owner = Host;
			ring->busy = 0;
			ctlr->ti = NEXT(ctlr->ti, ctlr->ntb);
			(*ctlr->board->transmit)(ctlr);
			wakeup(&ctlr->tr);
		}
	}
}
.
## diffname pc/ether8390.c 1993/0212
## diff -e /n/bootesdump/1992/1222/sys/src/9/pc/ether8390.c /n/bootesdump/1993/0212/sys/src/9/pc/ether8390.c
560a
	dp8390outb(ctlr->card.dp8390+Imr, Cnte|Ovwe|Txee|Rxee|Ptxe|Prxe);
.
559a

		if(isr & Cnt){
			ctlr->frames += dp8390inb(ctlr->card.dp8390+Cntr0);
			ctlr->crcs += dp8390inb(ctlr->card.dp8390+Cntr1);
			ctlr->buffs += dp8390inb(ctlr->card.dp8390+Cntr2);
			dp8390outb(ctlr->card.dp8390+Isr, Cnt);
		}
.
557c
			(*ctlr->card.transmit)(ctlr);
.
555c
			ctlr->tbusy = 0;
.
552a
			r = dp8390inb(ctlr->card.dp8390+Tsr);
			if(isr & Txe){
				if((r & (Cdh|Fu|Crs|Abt)) && ctlr->debug)
					print("Tsr#%2.2ux|", r);
				ctlr->oerrs++;
			}

			dp8390outb(ctlr->card.dp8390+Isr, Txe|Ptx);

			if(isr & Ptx)
				ctlr->outpackets++;

.
535,547d
530c
			(*ctlr->card.receive)(ctlr);
			dp8390outb(ctlr->card.dp8390+Isr, Rxe|Prx);
.
516,521d
503,514c
			if(ctlr->card.overflow)
				(*ctlr->card.overflow)(ctlr);
			dp8390outb(ctlr->card.dp8390+Isr, Ovw);
.
499,500c
	dp8390outb(ctlr->card.dp8390+Imr, 0x00);
	while(isr = dp8390inb(ctlr->card.dp8390+Isr)){
.
493c
	uchar isr, r;
.
491d
476,483c
	if(ctlr->tbusy){
		ctlr->tbusy++;
		if(ctlr->tbusy > 1 && ctlr->debug)
			print("TB%d|", ctlr->tbusy);
.
474a
	/*
	 * Stub watchdog routine.
	 * Whine if a transmit takes too long.
	 */
.
472a

	ring = &ctlr->tb[ctlr->ti];
	if(ctlr->tbusy == 0 && ring->owner == Interface){
		(*ctlr->card.write)(ctlr, ctlr->card.tstart*Dp8390BufSz, ring->pkt, ring->len);
		dp8390outb(ctlr->card.dp8390+Tbcr0, ring->len & 0xFF);
		dp8390outb(ctlr->card.dp8390+Tbcr1, (ring->len>>8) & 0xFF);
		dp8390outb(ctlr->card.dp8390+Cr, Page0|RDMAabort|Txp|Sta);
		ctlr->tbusy = 1;
	}
}

void
dp8390overflow(Ctlr *ctlr)
{
	uchar txp;
	int resend;

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

	resend = 0;
	if(txp && (dp8390inb(ctlr->card.dp8390+Isr) & (Txe|Ptx)) == 0)
		resend = 1;

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

	if(resend)
		dp8390outb(ctlr->card.dp8390+Cr, Page0|RDMAabort|Txp|Sta);
}

void
dp8390watch(Ctlr *ctlr)
{
.
471d
467a
/*
 * Initiate a transmission. Must be called splhi().
 */
.
460,464c
		/*
		 * Finished woth this packet, update the
		 * hardware and software ring pointers.
		 */
		ctlr->card.nxtpkt = hdr.next;

		hdr.next--;
		if(hdr.next < ctlr->card.pstart)
			hdr.next = ctlr->card.pstop-1;
		dp8390outb(ctlr->card.dp8390+Bnry, hdr.next);
.
455c
			if(len)
				(*ctlr->card.read)(ctlr, pkt, data, len);

.
450,453c
			ring->len = len;

			if((data+len) >= ctlr->card.pstop*Dp8390BufSz){
				ulong count = ctlr->card.pstop*Dp8390BufSz - data;

				(*ctlr->card.read)(ctlr, pkt, data, count);
				pkt += count;
				data = ctlr->card.pstart*Dp8390BufSz;
				len -= count;
.
447,448c
		if((hdr.status & (Fo|Fae|Crce|Prxok)) == Prxok && ring->owner == Interface){
			pkt = ring->pkt;
.
445a
		/*
		 * If it's a good packet and we have a place to put it,
		 * read it in to the software ring.
		 * If the packet wraps round the hardware ring, read it
		 * in two pieces.
		 */
.
439,442c
		if(hdr.next > ctlr->card.nxtpkt)
			len1 = hdr.next - ctlr->card.nxtpkt - 1;
		else
			len1 = (ctlr->card.pstop-ctlr->card.nxtpkt) + (hdr.next-ctlr->card.pstart) - 1;
		if(hdr.len0 > (Dp8390BufSz-sizeof(Hdr)))
			len1--;

		len = ((len1<<8)|hdr.len0)-4;

		/*
		 * Chip is badly scrogged, reinitialise the ring.
		 */
		if(hdr.next < ctlr->card.pstart || hdr.next >= ctlr->card.pstop
		  || len < 60 || len > sizeof(Etherpkt)){
			print("H#%2.2ux#%2.2ux#%2.2ux#%2.2ux,%d|",
				hdr.status, hdr.next, hdr.len0, hdr.len1, len);
			dp8390outb(ctlr->card.dp8390+Cr, Page0|RDMAabort|Stp);
			dp8390ring(ctlr);
			dp8390outb(ctlr->card.dp8390+Cr, Page0|RDMAabort|Sta);
.
432,437c
		 * Don't believe the upper byte count, work it
		 * out from the software next-page pointer and
		 * the current next-page pointer.
.
427,429c
		data = ctlr->card.nxtpkt*Dp8390BufSz;
		(*ctlr->card.read)(ctlr, &hdr, data, sizeof(Hdr));
.
418c
				c = dp8390inb(ctlr->card.dp8390+Clda0);
.
414,415c
				a = dp8390inb(ctlr->card.dp8390+Clda0);
				b = dp8390inb(ctlr->card.dp8390+Clda0);
.
391,402c
	for(curr = getcurr(ctlr); ctlr->card.nxtpkt != curr; curr = getcurr(ctlr)){
.
388,389c
	ulong data, len;
.
386c
	uchar curr, len1, *pkt;
.
384d
380a
static uchar
getcurr(Ctlr *ctlr)
{
	uchar cr, curr;

	cr = dp8390inb(ctlr->card.dp8390+Cr) & ~Txp;
	dp8390outb(ctlr->card.dp8390+Cr, Page1|(~(Ps1|Ps0) & cr));
	curr = dp8390inb(ctlr->card.dp8390+Curr);
	dp8390outb(ctlr->card.dp8390+Cr, cr);
	return curr;
}

.
376,377c
	dp8390outb(ctlr->card.dp8390+Isr, Rdc);
	dp8390outb(ctlr->card.dp8390+Cr, cr);
.
373c
	while((dp8390inb(ctlr->card.dp8390+Isr) & Rdc) == 0)
.
366c
		outsb(ctlr->card.data, from, len);
.
362,364c
	if(ctlr->card.bit16)
		outss(ctlr->card.data, from, len/2);
.
359,360c
	 * Pump the data into the I/O port.
.
357a
			crda = dp8390inb(ctlr->card.dp8390+Crda0);
			crda |= dp8390inb(ctlr->card.dp8390+Crda1)<<8;
			if(crda != to)
				panic("crda write %d to %d\n", crda, to);

			break;
		}
	}

.
351,356c
	for(;;){
		crda = dp8390inb(ctlr->card.dp8390+Crda0);
		crda |= dp8390inb(ctlr->card.dp8390+Crda1)<<8;
		if(crda == to){
			/*
			 * Start the remote DMA write and make sure
			 * the registers are correct.
			 */
			dp8390outb(ctlr->card.dp8390+Cr, Page0|RDMAwrite|Sta);
.
348,349c
	crda = to-1-ctlr->card.bit16;
	dp8390outb(ctlr->card.dp8390+Rbcr0, (len+1+ctlr->card.bit16) & 0xFF);
	dp8390outb(ctlr->card.dp8390+Rbcr1, ((len+1+ctlr->card.bit16)>>8) & 0xFF);
	dp8390outb(ctlr->card.dp8390+Rsar0, crda & 0xFF);
	dp8390outb(ctlr->card.dp8390+Rsar1, (crda>>8) & 0xFF);
	dp8390outb(ctlr->card.dp8390+Cr, Page0|RDMAread|Sta);
.
345,346c
	 * This is straight from the DP8390[12D] datasheet, hence
	 * the initial set up for read.
.
342a
	if(ctlr->card.bit16)
		len = ROUNDUP(len, 2);

.
339,341c
	cr = dp8390inb(ctlr->card.dp8390+Cr) & ~Txp;
	dp8390outb(ctlr->card.dp8390+Cr, Page0|RDMAabort|Sta);
	dp8390outb(ctlr->card.dp8390+Isr, Rdc);
.
325,335c
	 * Write some data to offset 'to' in the card's memory
.
322a
	ulong crda;
.
321d
313,314c
	dp8390outb(ctlr->card.dp8390+Isr, Rdc);
	dp8390outb(ctlr->card.dp8390+Cr, cr);
.
310c
	for(timo = 10000; (dp8390inb(ctlr->card.dp8390+Isr) & Rdc) == 0 && timo; timo--)
.
301c
		insb(ctlr->card.data, to, len);
.
297,299c
	dp8390outb(ctlr->card.dp8390+Cr, Page0|RDMAread|Sta);
	if(ctlr->card.bit16)
		inss(ctlr->card.data, to, len/2);
.
288,291c
	dp8390outb(ctlr->card.dp8390+Rbcr0, len & 0xFF);
	dp8390outb(ctlr->card.dp8390+Rbcr1, (len>>8) & 0xFF);
	dp8390outb(ctlr->card.dp8390+Rsar0, from & 0xFF);
	dp8390outb(ctlr->card.dp8390+Rsar1, (from>>8) & 0xFF);
.
286c
	if(ctlr->card.bit16)
.
279,281c
	cr = dp8390inb(ctlr->card.dp8390+Cr) & ~Txp;
	dp8390outb(ctlr->card.dp8390+Cr, Page0|RDMAabort|Sta);
	dp8390outb(ctlr->card.dp8390+Isr, Rdc);
.
265,275c
	 * Read some data at offset 'from' in the card's memory
.
260d
253,254c
		dp8390outb(ctlr->card.dp8390+Par0+i, ctlr->ea[i]);
	dp8390outb(ctlr->card.dp8390+Cr, cr);
.
250,251c
	cr = dp8390inb(ctlr->card.dp8390+Cr) & ~Txp;
	dp8390outb(ctlr->card.dp8390+Cr, Page1|(~(Ps1|Ps0) & cr));
.
239d
233c
		dp8390outb(ctlr->card.dp8390+Rcr, Ab);
.
231c
		dp8390outb(ctlr->card.dp8390+Rcr, Pro|Ab);
.
229a
	/*
	 * Set/reset promiscuous mode.
	 */
.
224c
	dp8390outb(ctlr->card.dp8390+Rcr, Ab);
.
221,222c
	 * The init routine leaves the chip in monitor
	 * mode.
.
211,213c
	dp8390outb(ctlr->card.dp8390+Cr, Page0|RDMAabort|Sta);
.
206a
	dp8390outb(ctlr->card.dp8390+Isr, 0xFF);
	dp8390outb(ctlr->card.dp8390+Imr, Cnte|Ovwe|Txee|Rxee|Ptxe|Prxe);

.
205c
	dp8390ring(ctlr);
	dp8390outb(ctlr->card.dp8390+Tpsr, ctlr->card.tstart);
.
202,203c
	 * Init the ring hardware and software ring pointers.
	 * Can't initialise ethernet address as we may not know
	 * it yet.
.
192,200d
189,190c
	dp8390outb(ctlr->card.dp8390+Tcr, 0);
	dp8390outb(ctlr->card.dp8390+Rcr, Mon);
.
186,187c
	dp8390outb(ctlr->card.dp8390+Rbcr0, 0);
	dp8390outb(ctlr->card.dp8390+Rbcr1, 0);
.
184c
		dp8390outb(ctlr->card.dp8390+Dcr, Ft4|Ls);
.
181,182c
	if(ctlr->card.bit16)
		dp8390outb(ctlr->card.dp8390+Dcr, Ft4|Ls|Wts);
.
178c
	 * as 'mandatory' in the datasheet, with references
	 * to the 3Com503 technical reference manual.
.
174,175d
170a
static void
dp8390ring(Ctlr *ctlr)
{
	dp8390outb(ctlr->card.dp8390+Pstart, ctlr->card.pstart);
	dp8390outb(ctlr->card.dp8390+Pstop, ctlr->card.pstop);
	dp8390outb(ctlr->card.dp8390+Bnry, ctlr->card.pstop-1);

	dp8390outb(ctlr->card.dp8390+Cr, Page1|RDMAabort|Stp);
	dp8390outb(ctlr->card.dp8390+Curr, ctlr->card.pstart);
	dp8390outb(ctlr->card.dp8390+Cr, Page0|RDMAabort|Stp);

	ctlr->card.nxtpkt = ctlr->card.pstart;
}

.
166,167c
	dp8390outb(ctlr->card.dp8390+Cr, Page0|RDMAabort|Stp);
	dp8390outb(ctlr->card.dp8390+Rbcr0, 0);
	dp8390outb(ctlr->card.dp8390+Rbcr1, 0);
	for(timo = 10000; (dp8390inb(ctlr->card.dp8390+Isr) & Rst) == 0 && timo; timo--)
.
155d
147,151d
41c
	Crda1		= 0x09,		/* current remote DMA address 1 */
.
27,29c
	Ps0		= 0x40,		/* page select */
	Ps1		= 0x80,		/* page select */
	Page0		= 0x00,
	Page1		= Ps0,
	Page2		= Ps1,
.
## diffname pc/ether8390.c 1993/0213
## diff -e /n/bootesdump/1993/0212/sys/src/9/pc/ether8390.c /n/bootesdump/1993/0213/sys/src/9/pc/ether8390.c
513d
509a

.
508a

		ctlr->tbusy = 1;

.
405,425c
		if(strcmp(arch->id, "NCRD.0") == 0)
			cldaquiet(ctlr);
.
395a
static void
cldaquiet(Ctlr *ctlr)
{
	uchar a, b, c;

	/*
	 * Hack to keep away from the card's memory while it is receiving
	 * a packet. This is only a problem on the NCR 3170 Safari.
	 *
	 * We peek at the current local DMA registers and, if they are
	 * changing, wait.
	 */
	
	for(;;delay(10)){
		a = dp8390inb(ctlr->card.dp8390+Clda0);
		b = dp8390inb(ctlr->card.dp8390+Clda0);
		if(a != b)
			continue;
		c = dp8390inb(ctlr->card.dp8390+Clda0);
		if(c != b)
			continue;
		break;
	}
}

.
229a
	dp8390inb(ctlr->card.dp8390+Cntr2);
.
227c
	 * mode. Clear the missed-packet counter, it
	 * increments while in monitor mode.
.
216c
	 * but in monitor mode.
.
## diffname pc/ether8390.c 1993/0915
## diff -e /n/bootesdump/1993/0213/sys/src/9/pc/ether8390.c /n/fornaxdump/1993/0915/sys/src/brazil/pc/ether8390.c
641c
	dp8390outb(dp8390+Imr, Cnte|Ovwe|Txee|Rxee|Ptxe|Prxe);
.
635,638c
			ctlr->frames += dp8390inb(dp8390+Cntr0);
			ctlr->crcs += dp8390inb(dp8390+Cntr1);
			ctlr->buffs += dp8390inb(dp8390+Cntr2);
			dp8390outb(dp8390+Isr, Cnt);
.
621c
			dp8390outb(dp8390+Isr, Txe|Ptx);
.
614c
			r = dp8390inb(dp8390+Tsr);
.
604c
			dp8390outb(dp8390+Isr, Rxe|Prx);
.
593c
			dp8390outb(dp8390+Isr, Ovw);
.
587,588c
	dp8390outb(dp8390+Imr, 0x00);
	while(isr = dp8390inb(dp8390+Isr)){
.
582a
	dp8390 = ctlr->card.dp8390;
.
579a
	ulong dp8390;
.
556c
		dp8390outb(dp8390+Cr, Page0|RDMAabort|Txp|Sta);
.
553c
	dp8390outb(dp8390+Tcr, 0);
.
551c
	dp8390outb(dp8390+Isr, Ovw);
.
548,549c
	dp8390outb(dp8390+Tcr, Lb);
	dp8390outb(dp8390+Cr, Page0|RDMAabort|Sta);
.
545c
	if(txp && (dp8390inb(dp8390+Isr) & (Txe|Ptx)) == 0)
.
541,542c
	dp8390outb(dp8390+Rbcr0, 0);
	dp8390outb(dp8390+Rbcr1, 0);
.
538,539c
	txp = dp8390inb(dp8390+Cr) & Txp;
	dp8390outb(dp8390+Cr, Page0|RDMAabort|Stp);
.
533a
	dp8390 = ctlr->card.dp8390;
.
530a
	ulong dp8390;
.
522,524c
		dp8390outb(dp8390+Tbcr0, ring->len & 0xFF);
		dp8390outb(dp8390+Tbcr1, (ring->len>>8) & 0xFF);
		dp8390outb(dp8390+Cr, Page0|RDMAabort|Txp|Sta);
.
514a
	dp8390 = ctlr->card.dp8390;
.
512a
	ulong dp8390;
.
503c
		dp8390outb(dp8390+Bnry, hdr.next);
.
463c
			dp8390outb(dp8390+Cr, Page0|RDMAabort|Sta);
.
461c
			dp8390outb(dp8390+Cr, Page0|RDMAabort|Stp);
.
433c
			cldaquiet(dp8390);
.
431c
	dp8390 = ctlr->card.dp8390;
	for(curr = getcurr(dp8390); ctlr->card.nxtpkt != curr; curr = getcurr(dp8390)){
.
429c
	ulong dp8390, data, len;
.
416c
		c = dp8390inb(dp8390+Clda0);
.
412,413c
		a = dp8390inb(dp8390+Clda0);
		b = dp8390inb(dp8390+Clda0);
.
399c
cldaquiet(ulong dp8390)
.
391,394c
	cr = dp8390inb(dp8390+Cr) & ~Txp;
	dp8390outb(dp8390+Cr, Page1|(~(Ps1|Ps0) & cr));
	curr = dp8390inb(dp8390+Curr);
	dp8390outb(dp8390+Cr, cr);
.
387c
getcurr(ulong dp8390)
.
381,382c
	dp8390outb(dp8390+Isr, Rdc);
	dp8390outb(dp8390+Cr, cr);
.
378c
	while((dp8390inb(dp8390+Isr) & Rdc) == 0)
.
356,357c
			crda = dp8390inb(dp8390+Crda0);
			crda |= dp8390inb(dp8390+Crda1)<<8;
.
354c
			dp8390outb(dp8390+Cr, Page0|RDMAwrite|Sta);
.
347,348c
		crda = dp8390inb(dp8390+Crda0);
		crda |= dp8390inb(dp8390+Crda1)<<8;
.
340,344c
	dp8390outb(dp8390+Rbcr0, (len+1+ctlr->card.bit16) & 0xFF);
	dp8390outb(dp8390+Rbcr1, ((len+1+ctlr->card.bit16)>>8) & 0xFF);
	dp8390outb(dp8390+Rsar0, crda & 0xFF);
	dp8390outb(dp8390+Rsar1, (crda>>8) & 0xFF);
	dp8390outb(dp8390+Cr, Page0|RDMAread|Sta);
.
327,329c
	cr = dp8390inb(dp8390+Cr) & ~Txp;
	dp8390outb(dp8390+Cr, Page0|RDMAabort|Sta);
	dp8390outb(dp8390+Isr, Rdc);
.
321a
	dp8390 = ctlr->card.dp8390;
.
320d
318a
	ulong dp8390, crda;
.
311,312c
	dp8390outb(dp8390+Isr, Rdc);
	dp8390outb(dp8390+Cr, cr);
.
308c
	for(timo = 10000; (dp8390inb(dp8390+Isr) & Rdc) == 0 && timo; timo--)
.
295c
	dp8390outb(dp8390+Cr, Page0|RDMAread|Sta);
.
286,289c
	dp8390outb(dp8390+Rbcr0, len & 0xFF);
	dp8390outb(dp8390+Rbcr1, (len>>8) & 0xFF);
	dp8390outb(dp8390+Rsar0, from & 0xFF);
	dp8390outb(dp8390+Rsar1, (from>>8) & 0xFF);
.
277,279c
	cr = dp8390inb(dp8390+Cr) & ~Txp;
	dp8390outb(dp8390+Cr, Page0|RDMAabort|Sta);
	dp8390outb(dp8390+Isr, Rdc);
.
271a
	dp8390 = ctlr->card.dp8390;
.
268a
	ulong dp8390;
.
265a
void
dp8390getea(Ctlr *ctlr)
{
	ulong dp8390;
	uchar cr;
	int i;

	dp8390 = ctlr->card.dp8390;
	/*
	 * Set the ethernet address into the chip.
	 * Take care to restore the command register
	 * afterwards. We don't care about multicast
	 * addresses as we never set the multicast
	 * enable.
	 */
	cr = dp8390inb(dp8390+Cr) & ~Txp;
	dp8390outb(dp8390+Cr, Page1|(~(Ps1|Ps0) & cr));
	for(i = 0; i < sizeof(ctlr->ea); i++)
		ctlr->ea[i] = dp8390inb(dp8390+Par0+i);
	dp8390outb(dp8390+Cr, cr);
}

.
262,263c
		dp8390outb(dp8390+Par0+i, ctlr->ea[i]);
	dp8390outb(dp8390+Cr, cr);
.
259,260c
	cr = dp8390inb(dp8390+Cr) & ~Txp;
	dp8390outb(dp8390+Cr, Page1|(~(Ps1|Ps0) & cr));
.
251a
	dp8390 = ctlr->card.dp8390;
.
248a
	ulong dp8390;
.
218c
	dp8390outb(dp8390+Cr, Page0|RDMAabort|Sta);
.
211,212c
	dp8390outb(dp8390+Isr, 0xFF);
	dp8390outb(dp8390+Imr, Cnte|Ovwe|Txee|Rxee|Ptxe|Prxe);
.
209c
	dp8390outb(dp8390+Tpsr, ctlr->card.tstart);
.
200,201c
	dp8390outb(dp8390+Tcr, 0);
	dp8390outb(dp8390+Rcr, Mon);
.
197,198c
	dp8390outb(dp8390+Rbcr0, 0);
	dp8390outb(dp8390+Rbcr1, 0);
.
195c
		dp8390outb(dp8390+Dcr, Ft4|Ls);
.
193c
		dp8390outb(dp8390+Dcr, Ft4|Ls|Wts);
.
185a
	ulong dp8390;

	dp8390 = ctlr->card.dp8390;
.
179a
	dp8390outb(dp8390+Cr, Page1|RDMAabort|Stp);
	dp8390outb(dp8390+Curr, ctlr->card.pstart);
	dp8390outb(dp8390+Cr, Page0|RDMAabort|Stp);

.
176,178c
	dp8390 = ctlr->card.dp8390;
	dp8390outb(dp8390+Pstart, ctlr->card.pstart);
	dp8390outb(dp8390+Pstop, ctlr->card.pstop);
	dp8390outb(dp8390+Bnry, ctlr->card.pstop-1);
.
172,174c
	ulong dp8390;
.
162,165c
	dp8390outb(dp8390+Cr, Page0|RDMAabort|Stp);
	dp8390outb(dp8390+Rbcr0, 0);
	dp8390outb(dp8390+Rbcr1, 0);
	for(timo = 10000; (dp8390inb(dp8390+Isr) & Rst) == 0 && timo; timo--)
.
153a
	dp8390 = ctlr->card.dp8390;
.
151a
	ulong dp8390;
.
## diffname pc/ether8390.c 1993/1116
## diff -e /n/fornaxdump/1993/0915/sys/src/brazil/pc/ether8390.c /n/fornaxdump/1993/1116/sys/src/brazil/pc/ether8390.c
683a
}

static void
promiscuous(Ether *ether, int on)
{
	/*
	 * Set/reset promiscuous mode.
	 */
	if(on)
		dp8390outb(ether->dp8390+Rcr, Pro|Ab);
	else
		dp8390outb(ether->dp8390+Rcr, Ab);
}

void
dp8390attach(Ether *ether)
{
	/*
	 * 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);
}

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

	dp8390 = ether->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);
	else
		dp8390outb(dp8390+Dcr, Ft4|Ls);

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

	dp8390outb(dp8390+Tcr, 0);
	dp8390outb(dp8390+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);

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

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

	/*
	 * Set up the software configuration.
	 */
	ether->attach = attach;
	ether->write = write;
	ether->interrupt = interrupt;

	ether->promiscuous = promiscuous;
	ether->arg = ether;

	return 0;
.
677,679c
			ether->frames += dp8390inb(dp8390+Cntr0);
			ether->crcs += dp8390inb(dp8390+Cntr1);
			ether->buffs += dp8390inb(dp8390+Cntr2);
.
666,673c
				ether->outpackets++;
			wakeup(&ether->tr);
.
660c
				ether->oerrs++;
.
658c
				if((r & (Cdh|Fu|Crs|Abt)) && ether->debug)
.
647d
645c
			receive(ether);
.
641,642c
		 * Take a spin round the ring. and
.
636c
			ether->overflows++;
.
633,634c
			overflow(ether);
.
624c
	dp8390 = ether->dp8390;
.
621d
602,619d
599,600c
static void
interrupt(Ether *ether)
.
592c
	wakeup(&ether->rr);
.
590c
	(*ether->receive)(ether);
.
573c
	dp8390 = ether->dp8390;
.
566,567c
static void
overflow(Ether *ether)
.
558c
		(*ether->write)(ctlr, ether->tstart*Dp8390BufSz, ring->pkt, ring->len);
.
556c
		ether->tbusy = 1;
.
552,554c
	dp8390 = ether->dp8390;
	ring = &ether->tb[ether->ti];
	if(ether->tbusy == 0 && ring->owner == Interface){
.
547c
dp8390transmit(Ether *ether)
.
537,538c
		if(hdr.next < ether->pstart)
			hdr.next = ether->pstop-1;
.
534c
		ether->nxtpkt = hdr.next;
.
526,527c
			/*
			 * 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);
			}
.
524c
				(*ether->read)(ctlr, pkt, data, len);
.
520c
				data = ether->pstart*Dp8390BufSz;
.
518c
				(*ether->read)(ctlr, pkt, data, count);
.
515,516c
			if((data+len) >= ether->pstop*Dp8390BufSz){
				ulong count = ether->pstop*Dp8390BufSz - data;
.
509,511c
		if((hdr.status & (Fo|Fae|Crce|Prxok)) == Prxok){
			pkt = ether->rpkt;
.
504,507c
		 * If it's a good packet read it in to the software buffer.
		 * If the packet wraps round the hardware ring, read it in two pieces.
.
498c
			dp8390ring(ether);
.
493c
		if(hdr.next < ether->pstart || hdr.next >= ether->pstop
.
484c
			len1 = (ether->pstop-ether->nxtpkt) + (hdr.next-ether->pstart) - 1;
.
481,482c
		if(hdr.next > ether->nxtpkt)
			len1 = hdr.next - ether->nxtpkt - 1;
.
473,475d
471c
		data = ether->nxtpkt*Dp8390BufSz;
		(*ether->read)(ctlr, &hdr, data, sizeof(Hdr));
.
466,469c
	dp8390 = ether->dp8390;
	for(curr = getcurr(dp8390); ether->nxtpkt != curr; curr = getcurr(dp8390)){
		ether->inpackets++;
.
464a
	ushort type;
	Netfile *f, **fp, **ep;
.
436,461d
434c
receive(Ether *ether)
.
406c
		outsb(ether->data, from, len);
.
403,404c
	if(ether->bit16)
		outss(ether->data, from, len/2);
.
374,376c
	crda = to-1-ether->bit16;
	dp8390outb(dp8390+Rbcr0, (len+1+ether->bit16) & 0xFF);
	dp8390outb(dp8390+Rbcr1, ((len+1+ether->bit16)>>8) & 0xFF);
.
366c
	if(ether->bit16)
.
356c
	dp8390 = ether->dp8390;
.
350,351c
static void*
dp8390write(Ether *ether, ulong to, void *from, ulong len)
.
333c
		insb(ether->data, to, len);
.
330,331c
	if(ether->bit16)
		inss(ether->data, to, len/2);
.
318c
	if(ether->bit16)
.
305c
	dp8390 = ether->dp8390;
.
298,299c
static void*
dp8390read(Ether *ether, void *to, ulong from, ulong len)
.
293,294c
	for(i = 0; i < sizeof(ether->ea); i++)
		ether->ea[i] = dp8390inb(dp8390+Par0+i);
.
285c
	 * Get the ethernet address from the chip.
.
283c
	dp8390 = ether->dp8390;
.
277c
dp8390getea(Ether *ether)
.
271,272c
	for(i = 0; i < sizeof(ether->ea); i++)
		dp8390outb(dp8390+Par0+i, ether->ea[i]);
.
261c
	dp8390 = ether->dp8390;
.
192,257d
189c
dp8390setea(Ether *ether)
.
185c
	ether->nxtpkt = ether->pstart;
.
182c
	dp8390outb(dp8390+Curr, ether->pstart);
.
176,179c
	dp8390 = ether->dp8390;
	dp8390outb(dp8390+Pstart, ether->pstart);
	dp8390outb(dp8390+Pstop, ether->pstop);
	dp8390outb(dp8390+Bnry, ether->pstop-1);
.
172c
dp8390ring(Ether *ether)
.
155c
	dp8390 = ether->dp8390;
.
150c
dp8390disable(Ether *ether)
.
15c
#include "etherif.h"
.
13c
#include "../port/error.h"
#include "../port/netif.h"
.
11d
## diffname pc/ether8390.c 1993/1117
## diff -e /n/fornaxdump/1993/1116/sys/src/brazil/pc/ether8390.c /n/fornaxdump/1993/1117/sys/src/brazil/pc/ether8390.c
600c
	dp8390 = ((Dp8390*)ether->private)->dp8390;
.
584a
	ulong dp8390;

	dp8390 = ((Dp8390*)ether->private)->dp8390;
.
572a
	ulong dp8390;

	dp8390 = ((Dp8390*)ether->private)->dp8390;
.
517c
	dp8390 = ((Dp8390*)ether->private)->dp8390;
.
485c
	dp8390 = ((Dp8390*)ether->private)->dp8390;
.
464c
	dp8390 = ((Dp8390*)ether->private)->dp8390;
.
376c
	dp8390 = ((Dp8390*)ether->private)->dp8390;
.
290c
	dp8390 = ((Dp8390*)ether->private)->dp8390;
.
279,280c
	dp8390outb(port+Isr, Rdc);
	dp8390outb(port+Cr, cr);
.
276c
	for(timo = 10000; (dp8390inb(port+Isr) & Rdc) == 0 && timo; timo--)
.
267c
		insb(dp8390->data, to, len);
.
263,265c
	dp8390outb(port+Cr, Page0|RDMAread|Sta);
	if(dp8390->bit16)
		inss(dp8390->data, to, len/2);
.
254,257c
	dp8390outb(port+Rbcr0, len & 0xFF);
	dp8390outb(port+Rbcr1, (len>>8) & 0xFF);
	dp8390outb(port+Rsar0, from & 0xFF);
	dp8390outb(port+Rsar1, (from>>8) & 0xFF);
.
252c
	if(dp8390->bit16)
.
245,247c
	cr = dp8390inb(port+Cr) & ~Txp;
	dp8390outb(port+Cr, Page0|RDMAabort|Sta);
	dp8390outb(port+Isr, Rdc);
.
239c
	port = dp8390->dp8390;
.
235c
	ulong port;
.
233c
dp8390read(Dp8390 *dp8390, void *to, ulong from, ulong len)
.
228,229c
		ether->ea[i] = dp8390inb(port+Par0+i);
	dp8390outb(port+Cr, cr);
.
225,226c
	cr = dp8390inb(port+Cr) & ~Txp;
	dp8390outb(port+Cr, Page1|(~(Ps1|Ps0) & cr));
.
217c
	port = ((Dp8390*)ether->private)->dp8390;
.
213c
	ulong port;
.
206,207c
		dp8390outb(port+Par0+i, ether->ea[i]);
	dp8390outb(port+Cr, cr);
.
203,204c
	cr = dp8390inb(port+Cr) & ~Txp;
	dp8390outb(port+Cr, Page1|(~(Ps1|Ps0) & cr));
.
195c
	port = ((Dp8390*)ether->private)->dp8390;
.
191c
	ulong port;
.
185c
	dp8390->nxtpkt = dp8390->pstart;
.
181,183c
	dp8390outb(port+Cr, Page1|RDMAabort|Stp);
	dp8390outb(port+Curr, dp8390->pstart);
	dp8390outb(port+Cr, Page0|RDMAabort|Stp);
.
176,179c
	port = dp8390->dp8390;
	dp8390outb(port+Pstart, dp8390->pstart);
	dp8390outb(port+Pstop, dp8390->pstop);
	dp8390outb(port+Bnry, dp8390->pstop-1);
.
174c
	ulong port;
.
172c
dp8390ring(Dp8390 *dp8390)
.
164,167c
	dp8390outb(port+Cr, Page0|RDMAabort|Stp);
	dp8390outb(port+Rbcr0, 0);
	dp8390outb(port+Rbcr1, 0);
	for(timo = 10000; (dp8390inb(port+Isr) & Rst) == 0 && timo; timo--)
.
155c
	port = dp8390->dp8390;
.
152c
	ulong port;
.
150c
dp8390disable(Dp8390 *dp8390)
.
## diffname pc/ether8390.c 1993/1118
## diff -e /n/fornaxdump/1993/1117/sys/src/brazil/pc/ether8390.c /n/fornaxdump/1993/1118/sys/src/brazil/pc/ether8390.c
639c
	dp8390outb(port+Cr, Page0|RDMAabort|Sta);
.
632,633c
	dp8390outb(port+Isr, 0xFF);
	dp8390outb(port+Imr, Cnte|Ovwe|Txee|Rxee|Ptxe|Prxe);
.
629,630c
	dp8390ring(dp8390);
	dp8390outb(port+Tpsr, dp8390->tstart);
.
621,622c
	dp8390outb(port+Tcr, 0);
	dp8390outb(port+Rcr, Mon);
.
618,619c
	dp8390outb(port+Rbcr0, 0);
	dp8390outb(port+Rbcr1, 0);
.
616c
		dp8390outb(port+Dcr, Ft4|Ls);
.
612,614c
	dp8390disable(dp8390);
	if(dp8390->bit16)
		dp8390outb(port+Dcr, Ft4|Ls|Wts);
.
606c
	dp8390 = ether->private;
	port = dp8390->dp8390;

.
604c
	Dp8390 *dp8390;
	ulong port;
.
601c
int
.
597,598c
	dp8390outb(dp8390->dp8390+Rcr, Ab);
	dp8390inb(dp8390->dp8390+Cntr2);
.
590d
588c
	Dp8390 *dp8390 = ether->private;
.
585,586c
static void
attach(Ether *ether)
.
582c
		dp8390outb(dp8390->dp8390+Rcr, Ab);
.
580c
		dp8390outb(dp8390->dp8390+Rcr, Pro|Ab);
.
575d
573c
	Dp8390 *dp8390 = ((Ether*)arg)->private;
.
571c
promiscuous(void *arg, int on)
.
567c
	dp8390outb(port+Imr, Cnte|Ovwe|Txee|Rxee|Ptxe|Prxe);
.
561,564c
			ether->frames += dp8390inb(port+Cntr0);
			ether->crcs += dp8390inb(port+Cntr1);
			ether->buffs += dp8390inb(port+Cntr2);
			dp8390outb(port+Isr, Cnt);
.
556a
			dp8390->busy = 0;
.
553c
			dp8390outb(port+Isr, Txe|Ptx);
.
548,549c
				if((r & (Cdh|Fu|Crs|Abt)))
					print("dp8390: Tsr#%2.2ux\n", r);
.
546c
			r = dp8390inb(port+Tsr);
.
537c
			dp8390outb(port+Isr, Rxe|Prx);
.
527c
			dp8390outb(port+Isr, Ovw);
.
522,523c
	dp8390outb(port+Imr, 0x00);
	while(isr = dp8390inb(port+Isr)){
.
517c
	dp8390 = ether->private;
	port = dp8390->dp8390;

.
514c
	Dp8390 *dp8390;
	ulong port;
.
508c
		dp8390outb(port+Cr, Page0|RDMAabort|Txp|Sta);
.
500,505c
	dp8390outb(port+Tcr, Lb);
	dp8390outb(port+Cr, Page0|RDMAabort|Sta);
	receive(ether);
	dp8390outb(port+Isr, Ovw);
	dp8390outb(port+Tcr, 0);
.
497c
	if(txp && (dp8390inb(port+Isr) & (Txe|Ptx)) == 0)
.
493,494c
	dp8390outb(port+Rbcr0, 0);
	dp8390outb(port+Rbcr1, 0);
.
490,491c
	txp = dp8390inb(port+Cr) & Txp;
	dp8390outb(port+Cr, Page0|RDMAabort|Stp);
.
485c
	dp8390 = ether->private;
	port = dp8390->dp8390;

.
481c
	Dp8390 *dp8390;
	ulong port;
.
475a

	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;
.
470,474c
	qlock(&ether->tlock);
	if(waserror()) {
		qunlock(&ether->tlock);
		nexterror();
.
468c
	dp8390 = ether->private;
	port = dp8390->dp8390;
.
464,466c
static long
write(Ether *ether, void *buf, long n)
{
	Dp8390 *dp8390;
	ulong port;
.
461,462c
	return ((Dp8390*)arg)->busy == 0;
}
.
455,459c
static int
istxbusy(void *arg)
.
449,451c
		if(hdr.next < dp8390->pstart)
			hdr.next = dp8390->pstop-1;
		dp8390outb(port+Bnry, hdr.next);
.
446c
		dp8390->nxtpkt = hdr.next;
.
443c
		 * Finished with this packet, update the
.
427,428c
			if(len1){
				if(dp8390->ram)
					memmove(pkt, (void*)(ether->mem+data), len1);
				else
					dp8390read(dp8390, pkt, data, len1);
			}
.
424,425c
				data = dp8390->pstart*Dp8390BufSz;
				len1 -= count;
.
422c
				if(dp8390->ram)
					memmove(pkt, (void*)(ether->mem+data), count);
				else
					dp8390read(dp8390, pkt, data, count);
.
419,420c
			if((data+len1) >= dp8390->pstop*Dp8390BufSz){
				ulong count = dp8390->pstop*Dp8390BufSz - data;
.
417c
			len1 = len;
.
415c
			pkt = (uchar*)&ether->rpkt;
.
404,406c
			dp8390outb(port+Cr, Page0|RDMAabort|Stp);
			dp8390ring(dp8390);
			dp8390outb(port+Cr, Page0|RDMAabort|Sta);
.
402c
			print("dp8390: H#%2.2ux#%2.2ux#%2.2ux#%2.2ux,%d\n",
.
400c
		if(hdr.next < dp8390->pstart || hdr.next >= dp8390->pstop
.
391c
			len1 = (dp8390->pstop-dp8390->nxtpkt) + (hdr.next-dp8390->pstart) - 1;
.
388,389c
		if(hdr.next > dp8390->nxtpkt)
			len1 = hdr.next - dp8390->nxtpkt - 1;
.
380,381c
		data = dp8390->nxtpkt*Dp8390BufSz;
		if(dp8390->ram)
			memmove(&hdr, (void*)(ether->mem+data), sizeof(Hdr));
		else
			dp8390read(dp8390, &hdr, data, sizeof(Hdr));
.
376,377c
	dp8390 = ether->private;
	port = dp8390->dp8390;
	for(curr = getcurr(dp8390); dp8390->nxtpkt != curr; curr = getcurr(dp8390)){
.
372c
	ulong port, data, len, len1;
.
370c
	Dp8390 *dp8390;
	uchar curr, *pkt;
.
360,363c
	cr = dp8390inb(port+Cr) & ~Txp;
	dp8390outb(port+Cr, Page1|(~(Ps1|Ps0) & cr));
	curr = dp8390inb(port+Curr);
	dp8390outb(port+Cr, cr);
.
357a
	ulong port = dp8390->dp8390;
.
356c
getcurr(Dp8390 *dp8390)
.
350,351c
	dp8390outb(port+Isr, Rdc);
	dp8390outb(port+Cr, cr);
.
347c
	while((dp8390inb(port+Isr) & Rdc) == 0)
.
340c
		outsb(dp8390->data, from, len);
.
337,338c
	if(dp8390->bit16)
		outss(dp8390->data, from, len/2);
.
325,326c
			crda = dp8390inb(port+Crda0);
			crda |= dp8390inb(port+Crda1)<<8;
.
323c
			dp8390outb(port+Cr, Page0|RDMAwrite|Sta);
.
316,317c
		crda = dp8390inb(port+Crda0);
		crda |= dp8390inb(port+Crda1)<<8;
.
308,313c
	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);
.
300c
	if(dp8390->bit16)
.
296,298c
	cr = dp8390inb(port+Cr) & ~Txp;
	dp8390outb(port+Cr, Page0|RDMAabort|Sta);
	dp8390outb(port+Isr, Rdc);
.
290d
287c
	ulong port = dp8390->dp8390;
	ulong crda;
.
285c
dp8390write(Dp8390 *dp8390, ulong to, void *from, ulong len)
.
239d
235c
	ulong port = dp8390->dp8390;
.
217d
213c
	ulong port = ((Dp8390*)ether->private)->dp8390;
.
195d
191c
	ulong port = ((Dp8390*)ether->private)->dp8390;
.
176d
174c
	ulong port = dp8390->dp8390;
.
155d
152c
	ulong port = dp8390->dp8390;
.
16a
extern int dp8390inb(ulong);
extern void dp8390outb(ulong, uchar);

.
## diffname pc/ether8390.c 1993/1119
## diff -e /n/fornaxdump/1993/1118/sys/src/brazil/pc/ether8390.c /n/fornaxdump/1993/1119/sys/src/brazil/pc/ether8390.c
591c
			ether->tlen = 0;
.
557a
print("I%2.2ux|", isr);
.
501,503d
487,491d
485a
	ether->tlen = n;
.
481,484c
	tsleep(&ether->tr, istxavail, ether, 10000);
	if(ether->tlen){
		print("dp8390: transmitter jammed\n");
		return 0;
.
469c
	return ((Ether*)arg)->tlen == 0;
.
467c
istxavail(void *arg)
.
449a
}
.
448a
{
print("Q%d|", len);
.
## diffname pc/ether8390.c 1993/1120
## diff -e /n/fornaxdump/1993/1119/sys/src/brazil/pc/ether8390.c /n/fornaxdump/1993/1120/sys/src/brazil/pc/ether8390.c
554d
500c
	return len;
.
496,497c
	/*
	 * Give the packet a source address and make sure it
	 * is of minimum length.
	 */
	memmove(pkt->s, ether->ea, sizeof(ether->ea));
	if(len < ETHERMINTU){
		memset(pkt->d+len, 0, ETHERMINTU-len);
		len = ETHERMINTU;
	}

	if(dp8390->ram == 0)
		dp8390write(dp8390, dp8390->tstart*Dp8390BufSz, pkt, len);

	dp8390outb(port+Tbcr0, len & 0xFF);
	dp8390outb(port+Tbcr1, (len>>8) & 0xFF);
.
494c
		pkt = &ether->tpkt;
	memmove(pkt, buf, len);
.
492c
		pkt = (Etherpkt*)(ether->mem+dp8390->tstart*Dp8390BufSz);
.
490a
	/*
	 * If it's a shared-memory interface, copy the packet
	 * directly to the shared-memory area. Otherwise, copy
	 * it to a staging buffer so the I/O-port write can be
	 * done in one.
	 */
.
489c
	ether->tlen = len;
.
479a
	Etherpkt *pkt;
.
476c
write(Ether *ether, void *buf, long len)
.
452d
449,450d
## diffname pc/ether8390.c 1993/1124
## diff -e /n/fornaxdump/1993/1120/sys/src/brazil/pc/ether8390.c /n/fornaxdump/1993/1124/sys/src/brazil/pc/ether8390.c
562a
	USED(ur);

	ether = arg;
.
558a
	Ether *ether;
.
557c
interrupt(Ureg *ur, void *arg)
.
## diffname pc/ether8390.c 1994/0128
## diff -e /n/fornaxdump/1993/1124/sys/src/brazil/pc/ether8390.c /n/fornaxdump/1994/0128/sys/src/brazil/pc/ether8390.c
282c
void*
.
231c
void*
.
## diffname pc/ether8390.c 1994/0130
## diff -e /n/fornaxdump/1994/0128/sys/src/brazil/pc/ether8390.c /n/fornaxdump/1994/0130/sys/src/brazil/pc/ether8390.c
693c
	slowoutb(port+Cr, Page0|RDMAabort|Sta);
.
686,687c
	slowoutb(port+Isr, 0xFF);
	slowoutb(port+Imr, Cnte|Ovwe|Txee|Rxee|Ptxe|Prxe);
.
684c
	slowoutb(port+Tpsr, dp8390->tstart);
.
675,676c
	slowoutb(port+Tcr, 0);
	slowoutb(port+Rcr, Mon);
.
672,673c
	slowoutb(port+Rbcr0, 0);
	slowoutb(port+Rbcr1, 0);
.
670c
		slowoutb(port+Dcr, Ft4|Ls);
.
668c
		slowoutb(port+Dcr, Ft4|Ls|Wts);
.
648,649c
	slowoutb(dp8390->dp8390+Rcr, Ab);
	slowinb(dp8390->dp8390+Cntr2);
.
634c
		slowoutb(dp8390->dp8390+Rcr, Ab);
.
632c
		slowoutb(dp8390->dp8390+Rcr, Pro|Ab);
.
620c
	slowoutb(port+Imr, Cnte|Ovwe|Txee|Rxee|Ptxe|Prxe);
.
614,617c
			ether->frames += slowinb(port+Cntr0);
			ether->crcs += slowinb(port+Cntr1);
			ether->buffs += slowinb(port+Cntr2);
			slowoutb(port+Isr, Cnt);
.
605c
			slowoutb(port+Isr, Txe|Ptx);
.
598c
			r = slowinb(port+Tsr);
.
589c
			slowoutb(port+Isr, Rxe|Prx);
.
579c
			slowoutb(port+Isr, Ovw);
.
574,575c
	slowoutb(port+Imr, 0x00);
	while(isr = slowinb(port+Isr)){
.
553c
		slowoutb(port+Cr, Page0|RDMAabort|Txp|Sta);
.
549,550c
	slowoutb(port+Isr, Ovw);
	slowoutb(port+Tcr, 0);
.
546,547c
	slowoutb(port+Tcr, Lb);
	slowoutb(port+Cr, Page0|RDMAabort|Sta);
.
543c
	if(txp && (slowinb(port+Isr) & (Txe|Ptx)) == 0)
.
539,540c
	slowoutb(port+Rbcr0, 0);
	slowoutb(port+Rbcr1, 0);
.
536,537c
	txp = slowinb(port+Cr) & Txp;
	slowoutb(port+Cr, Page0|RDMAabort|Stp);
.
514,516c
	slowoutb(port+Tbcr0, len & 0xFF);
	slowoutb(port+Tbcr1, (len>>8) & 0xFF);
	slowoutb(port+Cr, Page0|RDMAabort|Txp|Sta);
.
462c
		slowoutb(port+Bnry, hdr.next);
.
410c
			slowoutb(port+Cr, Page0|RDMAabort|Sta);
.
408c
			slowoutb(port+Cr, Page0|RDMAabort|Stp);
.
359,362c
	cr = slowinb(port+Cr) & ~Txp;
	slowoutb(port+Cr, Page1|(~(Ps1|Ps0) & cr));
	curr = slowinb(port+Curr);
	slowoutb(port+Cr, cr);
.
348,349c
	slowoutb(port+Isr, Rdc);
	slowoutb(port+Cr, cr);
.
345c
	while((slowinb(port+Isr) & Rdc) == 0)
.
323,324c
			crda = slowinb(port+Crda0);
			crda |= slowinb(port+Crda1)<<8;
.
321c
			slowoutb(port+Cr, Page0|RDMAwrite|Sta);
.
314,315c
		crda = slowinb(port+Crda0);
		crda |= slowinb(port+Crda1)<<8;
.
307,311c
	slowoutb(port+Rbcr0, (len+1+dp8390->bit16) & 0xFF);
	slowoutb(port+Rbcr1, ((len+1+dp8390->bit16)>>8) & 0xFF);
	slowoutb(port+Rsar0, crda & 0xFF);
	slowoutb(port+Rsar1, (crda>>8) & 0xFF);
	slowoutb(port+Cr, Page0|RDMAread|Sta);
.
294,296c
	cr = slowinb(port+Cr) & ~Txp;
	slowoutb(port+Cr, Page0|RDMAabort|Sta);
	slowoutb(port+Isr, Rdc);
.
277,278c
	slowoutb(port+Isr, Rdc);
	slowoutb(port+Cr, cr);
.
274c
	for(timo = 10000; (slowinb(port+Isr) & Rdc) == 0 && timo; timo--)
.
261c
	slowoutb(port+Cr, Page0|RDMAread|Sta);
.
252,255c
	slowoutb(port+Rbcr0, len & 0xFF);
	slowoutb(port+Rbcr1, (len>>8) & 0xFF);
	slowoutb(port+Rsar0, from & 0xFF);
	slowoutb(port+Rsar1, (from>>8) & 0xFF);
.
243,245c
	cr = slowinb(port+Cr) & ~Txp;
	slowoutb(port+Cr, Page0|RDMAabort|Sta);
	slowoutb(port+Isr, Rdc);
.
227,228c
		ether->ea[i] = slowinb(port+Par0+i);
	slowoutb(port+Cr, cr);
.
224,225c
	cr = slowinb(port+Cr) & ~Txp;
	slowoutb(port+Cr, Page1|(~(Ps1|Ps0) & cr));
.
206,207c
		slowoutb(port+Par0+i, ether->ea[i]);
	slowoutb(port+Cr, cr);
.
203,204c
	cr = slowinb(port+Cr) & ~Txp;
	slowoutb(port+Cr, Page1|(~(Ps1|Ps0) & cr));
.
182,184c
	slowoutb(port+Cr, Page1|RDMAabort|Stp);
	slowoutb(port+Curr, dp8390->pstart);
	slowoutb(port+Cr, Page0|RDMAabort|Stp);
.
178,180c
	slowoutb(port+Pstart, dp8390->pstart);
	slowoutb(port+Pstop, dp8390->pstop);
	slowoutb(port+Bnry, dp8390->pstop-1);
.
166,169c
	slowoutb(port+Cr, Page0|RDMAabort|Stp);
	slowoutb(port+Rbcr0, 0);
	slowoutb(port+Rbcr1, 0);
	for(timo = 10000; (slowinb(port+Isr) & Rst) == 0 && timo; timo--)
.
17,18c
extern int slowinb(ulong);
extern void slowoutb(ulong, uchar);
.
## diffname pc/ether8390.c 1994/0201
## diff -e /n/fornaxdump/1994/0130/sys/src/brazil/pc/ether8390.c /n/fornaxdump/1994/0201/sys/src/brazil/pc/ether8390.c
346c
		if(tries++ >= 10000000){
			print("dp8390write whoops\n");
			break;
		}
.
344a
	tries = 0;
.
338a
	splx(s);
.
288a
	s = splhi();
.
287a
	int s, tries;
.
## diffname pc/ether8390.c 1994/0202
## diff -e /n/fornaxdump/1994/0201/sys/src/brazil/pc/ether8390.c /n/fornaxdump/1994/0202/sys/src/brazil/pc/ether8390.c
451,457c
			etherrloop(ether, &ether->rpkt, len);
.
423a
		 *
		 * We could conceivably remove the copy into rpkt here by wrapping
		 * this up with the etherrloop code.
.
380,381d
356a
	splx(s);

.
353a
	}
.
349,351c
	while((slowinb(port+Isr) & Rdc) == 0){
		if(tries++ >= 100000){
			print("dp8390write dma timed out\n");
.
344,346c
	 * Wait for the remote DMA to finish. It should
	 * be almost immediate.
.
341d
290a

.
289a
	/*
	 * Keep out interrupts since reading and writing
	 * use the same DMA engine.
	 */
.
## diffname pc/ether8390.c 1994/0715
## diff -e /n/fornaxdump/1994/0202/sys/src/brazil/pc/ether8390.c /n/fornaxdump/1994/0715/sys/src/brazil/pc/ether8390.c
458c
			etherrloop(ether, &ether->rpkt, len, 1);
.
## diffname pc/ether8390.c 1995/0408
## diff -e /n/fornaxdump/1994/0715/sys/src/brazil/pc/ether8390.c /n/fornaxdump/1995/0408/sys/src/brazil/pc/ether8390.c
701c
	dp8390outb(port+Cr, Page0|RDMAabort|Sta);
.
694,695c
	dp8390outb(port+Isr, 0xFF);
	dp8390outb(port+Imr, Cnte|Ovwe|Txee|Rxee|Ptxe|Prxe);
.
692c
	dp8390outb(port+Tpsr, dp8390->tstart);
.
683,684c
	dp8390outb(port+Tcr, 0);
	dp8390outb(port+Rcr, Mon);
.
680,681c
	dp8390outb(port+Rbcr0, 0);
	dp8390outb(port+Rbcr1, 0);
.
678c
		dp8390outb(port+Dcr, Ft4|Ls);
.
676c
		dp8390outb(port+Dcr, Ft4|Ls|Wts);
.
656,657c
	dp8390outb(dp8390->dp8390+Rcr, Ab);
	dp8390inb(dp8390->dp8390+Cntr2);
.
642c
		dp8390outb(dp8390->dp8390+Rcr, Ab);
.
640c
		dp8390outb(dp8390->dp8390+Rcr, Pro|Ab);
.
628c
	dp8390outb(port+Imr, Cnte|Ovwe|Txee|Rxee|Ptxe|Prxe);
.
622,625c
			ether->frames += dp8390inb(port+Cntr0);
			ether->crcs += dp8390inb(port+Cntr1);
			ether->buffs += dp8390inb(port+Cntr2);
			dp8390outb(port+Isr, Cnt);
.
613c
			dp8390outb(port+Isr, Txe|Ptx);
.
606c
			r = dp8390inb(port+Tsr);
.
597c
			dp8390outb(port+Isr, Rxe|Prx);
.
587c
			dp8390outb(port+Isr, Ovw);
.
582,583c
	dp8390outb(port+Imr, 0x00);
	while(isr = dp8390inb(port+Isr)){
.
561c
		dp8390outb(port+Cr, Page0|RDMAabort|Txp|Sta);
.
557,558c
	dp8390outb(port+Isr, Ovw);
	dp8390outb(port+Tcr, 0);
.
554,555c
	dp8390outb(port+Tcr, Lb);
	dp8390outb(port+Cr, Page0|RDMAabort|Sta);
.
551c
	if(txp && (dp8390inb(port+Isr) & (Txe|Ptx)) == 0)
.
547,548c
	dp8390outb(port+Rbcr0, 0);
	dp8390outb(port+Rbcr1, 0);
.
544,545c
	txp = dp8390inb(port+Cr) & Txp;
	dp8390outb(port+Cr, Page0|RDMAabort|Stp);
.
522,524c
	dp8390outb(port+Tbcr0, len & 0xFF);
	dp8390outb(port+Tbcr1, (len>>8) & 0xFF);
	dp8390outb(port+Cr, Page0|RDMAabort|Txp|Sta);
.
470c
		dp8390outb(port+Bnry, hdr.next);
.
421c
			dp8390outb(port+Cr, Page0|RDMAabort|Sta);
.
419c
			dp8390outb(port+Cr, Page0|RDMAabort|Stp);
.
372,375c
	cr = dp8390inb(port+Cr) & ~Txp;
	dp8390outb(port+Cr, Page1|(~(Ps1|Ps0) & cr));
	curr = dp8390inb(port+Curr);
	dp8390outb(port+Cr, cr);
.
359,360c
	dp8390outb(port+Isr, Rdc);
	dp8390outb(port+Cr, cr);
.
352c
	while((dp8390inb(port+Isr) & Rdc) == 0){
.
330,331c
			crda = dp8390inb(port+Crda0);
			crda |= dp8390inb(port+Crda1)<<8;
.
328c
			dp8390outb(port+Cr, Page0|RDMAwrite|Sta);
.
321,322c
		crda = dp8390inb(port+Crda0);
		crda |= dp8390inb(port+Crda1)<<8;
.
314,318c
	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);
.
301,303c
	cr = dp8390inb(port+Cr) & ~Txp;
	dp8390outb(port+Cr, Page0|RDMAabort|Sta);
	dp8390outb(port+Isr, Rdc);
.
277,278c
	dp8390outb(port+Isr, Rdc);
	dp8390outb(port+Cr, cr);
.
274c
	for(timo = 10000; (dp8390inb(port+Isr) & Rdc) == 0 && timo; timo--)
.
261c
	dp8390outb(port+Cr, Page0|RDMAread|Sta);
.
252,255c
	dp8390outb(port+Rbcr0, len & 0xFF);
	dp8390outb(port+Rbcr1, (len>>8) & 0xFF);
	dp8390outb(port+Rsar0, from & 0xFF);
	dp8390outb(port+Rsar1, (from>>8) & 0xFF);
.
243,245c
	cr = dp8390inb(port+Cr) & ~Txp;
	dp8390outb(port+Cr, Page0|RDMAabort|Sta);
	dp8390outb(port+Isr, Rdc);
.
227,228c
		ether->ea[i] = dp8390inb(port+Par0+i);
	dp8390outb(port+Cr, cr);
.
224,225c
	cr = dp8390inb(port+Cr) & ~Txp;
	dp8390outb(port+Cr, Page1|(~(Ps1|Ps0) & cr));
.
206,207c
		dp8390outb(port+Par0+i, ether->ea[i]);
	dp8390outb(port+Cr, cr);
.
203,204c
	cr = dp8390inb(port+Cr) & ~Txp;
	dp8390outb(port+Cr, Page1|(~(Ps1|Ps0) & cr));
.
182,184c
	dp8390outb(port+Cr, Page1|RDMAabort|Stp);
	dp8390outb(port+Curr, dp8390->pstart);
	dp8390outb(port+Cr, Page0|RDMAabort|Stp);
.
178,180c
	dp8390outb(port+Pstart, dp8390->pstart);
	dp8390outb(port+Pstop, dp8390->pstop);
	dp8390outb(port+Bnry, dp8390->pstop-1);
.
166,169c
	dp8390outb(port+Cr, Page0|RDMAabort|Stp);
	dp8390outb(port+Rbcr0, 0);
	dp8390outb(port+Rbcr1, 0);
	for(timo = 10000; (dp8390inb(port+Isr) & Rst) == 0 && timo; timo--)
.
151a
/*
 *  the 8390 register accesses must not be too close together
 */
void
dp8390outb(ulong port, uchar x)
{
	outb(port, x);
	microdelay(0);
}

long
dp8390inb(ulong port)
{
	long x;

	x = inb(port);
	microdelay(0);
	return x;
}

.
17,19d
## diffname pc/ether8390.c 1995/0409
## diff -e /n/fornaxdump/1995/0408/sys/src/brazil/pc/ether8390.c /n/fornaxdump/1995/0409/sys/src/brazil/pc/ether8390.c
718c
	slowoutb(port+Cr, Page0|RDMAabort|Sta);
.
711,712c
	slowoutb(port+Isr, 0xFF);
	slowoutb(port+Imr, Cnte|Ovwe|Txee|Rxee|Ptxe|Prxe);
.
709c
	slowoutb(port+Tpsr, dp8390->tstart);
.
700,701c
	slowoutb(port+Tcr, 0);
	slowoutb(port+Rcr, Mon);
.
697,698c
	slowoutb(port+Rbcr0, 0);
	slowoutb(port+Rbcr1, 0);
.
695c
		slowoutb(port+Dcr, Ft4|Ls);
.
693c
		slowoutb(port+Dcr, Ft4|Ls|Wts);
.
673,674c
	slowoutb(dp8390->dp8390+Rcr, Ab);
	slowinb(dp8390->dp8390+Cntr2);
.
659c
		slowoutb(dp8390->dp8390+Rcr, Ab);
.
657c
		slowoutb(dp8390->dp8390+Rcr, Pro|Ab);
.
645c
	slowoutb(port+Imr, Cnte|Ovwe|Txee|Rxee|Ptxe|Prxe);
.
639,642c
			ether->frames += slowinb(port+Cntr0);
			ether->crcs += slowinb(port+Cntr1);
			ether->buffs += slowinb(port+Cntr2);
			slowoutb(port+Isr, Cnt);
.
630c
			slowoutb(port+Isr, Txe|Ptx);
.
623c
			r = slowinb(port+Tsr);
.
614c
			slowoutb(port+Isr, Rxe|Prx);
.
604c
			slowoutb(port+Isr, Ovw);
.
599,600c
	slowoutb(port+Imr, 0x00);
	while(isr = slowinb(port+Isr)){
.
578c
		slowoutb(port+Cr, Page0|RDMAabort|Txp|Sta);
.
574,575c
	slowoutb(port+Isr, Ovw);
	slowoutb(port+Tcr, 0);
.
571,572c
	slowoutb(port+Tcr, Lb);
	slowoutb(port+Cr, Page0|RDMAabort|Sta);
.
568c
	if(txp && (slowinb(port+Isr) & (Txe|Ptx)) == 0)
.
564,565c
	slowoutb(port+Rbcr0, 0);
	slowoutb(port+Rbcr1, 0);
.
561,562c
	txp = slowinb(port+Cr) & Txp;
	slowoutb(port+Cr, Page0|RDMAabort|Stp);
.
539,541c
	slowoutb(port+Tbcr0, len & 0xFF);
	slowoutb(port+Tbcr1, (len>>8) & 0xFF);
	slowoutb(port+Cr, Page0|RDMAabort|Txp|Sta);
.
487c
		slowoutb(port+Bnry, hdr.next);
.
438c
			slowoutb(port+Cr, Page0|RDMAabort|Sta);
.
436c
			slowoutb(port+Cr, Page0|RDMAabort|Stp);
.
389,392c
	cr = slowinb(port+Cr) & ~Txp;
	slowoutb(port+Cr, Page1|(~(Ps1|Ps0) & cr));
	curr = slowinb(port+Curr);
	slowoutb(port+Cr, cr);
.
376,377c
	slowoutb(port+Isr, Rdc);
	slowoutb(port+Cr, cr);
.
369c
	while((slowinb(port+Isr) & Rdc) == 0){
.
347,348c
			crda = slowinb(port+Crda0);
			crda |= slowinb(port+Crda1)<<8;
.
345c
			slowoutb(port+Cr, Page0|RDMAwrite|Sta);
.
338,339c
		crda = slowinb(port+Crda0);
		crda |= slowinb(port+Crda1)<<8;
.
331,335c
	slowoutb(port+Rbcr0, (len+1+dp8390->bit16) & 0xFF);
	slowoutb(port+Rbcr1, ((len+1+dp8390->bit16)>>8) & 0xFF);
	slowoutb(port+Rsar0, crda & 0xFF);
	slowoutb(port+Rsar1, (crda>>8) & 0xFF);
	slowoutb(port+Cr, Page0|RDMAread|Sta);
.
318,320c
	cr = slowinb(port+Cr) & ~Txp;
	slowoutb(port+Cr, Page0|RDMAabort|Sta);
	slowoutb(port+Isr, Rdc);
.
294,295c
	slowoutb(port+Isr, Rdc);
	slowoutb(port+Cr, cr);
.
291c
	for(timo = 10000; (slowinb(port+Isr) & Rdc) == 0 && timo; timo--)
.
278c
	slowoutb(port+Cr, Page0|RDMAread|Sta);
.
269,272c
	slowoutb(port+Rbcr0, len & 0xFF);
	slowoutb(port+Rbcr1, (len>>8) & 0xFF);
	slowoutb(port+Rsar0, from & 0xFF);
	slowoutb(port+Rsar1, (from>>8) & 0xFF);
.
260,262c
	cr = slowinb(port+Cr) & ~Txp;
	slowoutb(port+Cr, Page0|RDMAabort|Sta);
	slowoutb(port+Isr, Rdc);
.
244,245c
		ether->ea[i] = slowinb(port+Par0+i);
	slowoutb(port+Cr, cr);
.
241,242c
	cr = slowinb(port+Cr) & ~Txp;
	slowoutb(port+Cr, Page1|(~(Ps1|Ps0) & cr));
.
223,224c
		slowoutb(port+Par0+i, ether->ea[i]);
	slowoutb(port+Cr, cr);
.
220,221c
	cr = slowinb(port+Cr) & ~Txp;
	slowoutb(port+Cr, Page1|(~(Ps1|Ps0) & cr));
.
199,201c
	slowoutb(port+Cr, Page1|RDMAabort|Stp);
	slowoutb(port+Curr, dp8390->pstart);
	slowoutb(port+Cr, Page0|RDMAabort|Stp);
.
195,197c
	slowoutb(port+Pstart, dp8390->pstart);
	slowoutb(port+Pstop, dp8390->pstop);
	slowoutb(port+Bnry, dp8390->pstop-1);
.
183,186c
	slowoutb(port+Cr, Page0|RDMAabort|Stp);
	slowoutb(port+Rbcr0, 0);
	slowoutb(port+Rbcr1, 0);
	for(timo = 10000; (slowinb(port+Isr) & Rst) == 0 && timo; timo--)
.
149,168d
16a
extern int slowinb(ulong);
extern void slowoutb(ulong, uchar);

.
## diffname pc/ether8390.c 1995/0721
## diff -e /n/fornaxdump/1995/0409/sys/src/brazil/pc/ether8390.c /n/fornaxdump/1995/0721/sys/src/brazil/pc/ether8390.c
666c
	dp8390 = ether->ctlr;
.
648c
	Dp8390 *dp8390 = ether->ctlr;
.
634c
	Dp8390 *dp8390 = ((Ether*)arg)->ctlr;
.
575c
	dp8390 = ether->ctlr;
.
537c
	dp8390 = ether->ctlr;
.
487c
	dp8390 = ether->ctlr;
.
458c
			etherrloop(ether, &ether->rpkt, len);
.
387c
	dp8390 = ether->ctlr;
.
213c
	ulong port = ((Dp8390*)ether->ctlr)->dp8390;
.
192c
	ulong port = ((Dp8390*)ether->ctlr)->dp8390;
.
## diffname pc/ether8390.c 1995/0801
## diff -e /n/fornaxdump/1995/0721/sys/src/brazil/pc/ether8390.c /n/fornaxdump/1995/0801/sys/src/brazil/pc/ether8390.c
655a
	x = Ab;
	if(ether->prom)
		x |= Pro;
.
648a
	int x;
.
## diffname pc/ether8390.c 1995/0829
## diff -e /n/fornaxdump/1995/0801/sys/src/brazil/pc/ether8390.c /n/fornaxdump/1995/0829/sys/src/brazil/pc/ether8390.c
660c
	slowoutb(dp8390->dp8390+Rcr, x);
.
583c
	while(isr = (slowinb(port+Isr) & (Cnte|Ovwe|Txee|Rxee|Ptxe|Prxe))){
.
572,573d
565c
interrupt(Ureg*, void *arg)
.
## diffname pc/ether8390.c 1996/0420
## diff -e /n/fornaxdump/1995/0829/sys/src/brazil/pc/ether8390.c /n/fornaxdump/1996/0420/sys/src/brazil/pc/ether8390.c
210,230d
## diffname pc/ether8390.c 1997/0327
## diff -e /n/fornaxdump/1996/0420/sys/src/brazil/pc/ether8390.c /n/emeliedump/1997/0327/sys/src/brazil/pc/ether8390.c
689a
	ether->ifstat = 0;
.
688c
	ether->transmit = transmit;
.
682c
	regw(ctlr, Cr, Page0|RdABORT|Sta);
.
675,676c
	regw(ctlr, Isr, 0xFF);
	regw(ctlr, Imr, Cnt|Ovw|Txe|Rxe|Ptx|Prx);
.
672,673c
	ringinit(ctlr);
	regw(ctlr, Tpsr, ctlr->tstart);
.
669,670c
	 * Can't initialise ethernet address as it may not be
	 * known yet.
.
664,665c
	regw(ctlr, Tcr, 0);
	regw(ctlr, Rcr, Mon);
.
661,662c
	regw(ctlr, Rbcr0, 0);
	regw(ctlr, Rbcr1, 0);
.
659c
		regw(ctlr, Dcr, Ft4WORD|Ls);
.
655,657c
	disable(ctlr);
	if(ctlr->width != 1)
		regw(ctlr, Dcr, Ft4WORD|Ls|Wts);
.
653c
	 * to the 3C503 technical reference manual.
.
647,648c
	ctlr = ether->ctlr;
.
644,645c
	Dp8390 *ctlr;
.
642c
dp8390reset(Ether* ether)
.
640a
static void
disable(Dp8390* ctlr)
{
	int timo;

	/*
	 * Stop the chip. Set the Stp bit and wait for the chip
	 * to finish whatever was on its tiny mind before it sets
	 * the Rst bit.
	 * The timeout is needed because there may not be a real
	 * chip there if this is called when probing for a device
	 * at boot.
	 */
	regw(ctlr, Cr, Page0|RdABORT|Stp);
	regw(ctlr, Rbcr0, 0);
	regw(ctlr, Rbcr1, 0);
	for(timo = 10000; (regr(ctlr, Isr) & Rst) == 0 && timo; timo--)
			;
}

.
636,638c
		r |= Pro;
	ilock(ctlr);
	regw(ctlr, Rcr, r);
	r = regr(ctlr, Cntr2);
	iunlock(ctlr);
	USED(r);
.
634c
	r = Ab;
.
627a
	ctlr = ether->ctlr;

.
625,626c
	Dp8390 *ctlr;
	uchar r;
.
623c
attach(Ether* ether)
.
617,619c
		r |= Pro;
	ilock(ctlr);
	regw(ctlr, Rcr, r);
	iunlock(ctlr);
.
615a
	r = Ab;
.
612a
	ether = arg;
	ctlr = ether->ctlr;

.
611c
	Ether *ether;
	Dp8390 *ctlr;
	uchar r;
.
605c
	regw(ctlr, Imr, Cnt|Ovw|Txe|Rxe|Ptx|Prx);
	unlock(ctlr);
.
599,602c
			ether->frames += regr(ctlr, Cntr0);
			ether->crcs += regr(ctlr, Cntr1);
			ether->buffs += regr(ctlr, Cntr2);
			regw(ctlr, Isr, Cnt);
.
594,595c
			ctlr->txbusy = 0;
			txstart(ether);
.
590c
			regw(ctlr, Isr, Txe|Ptx);
.
583,586c
			r = regr(ctlr, Tsr);
			if((isr & Txe) && (r & (Cdh|Fu|Crs|Abt))){
				print("dp8390: Tsr#%2.2ux|", r);
.
574c
			regw(ctlr, Isr, Rxe|Prx);
.
569,570c
		 * Packets have been received.
		 * Take a spin round the ring.
.
564c
			regw(ctlr, Isr, Ovw);
.
559,561c
	lock(ctlr);
	regw(ctlr, Imr, 0x00);
	while(isr = (regr(ctlr, Isr) & (Cnt|Ovw|Txe|Rxe|Ptx|Prx))){
.
552,553c
	ctlr = ether->ctlr;
.
547,548c
	Dp8390 *ctlr;
.
544c
interrupt(Ureg*, void* arg)
.
540c
		regw(ctlr, Cr, Page0|RdABORT|Txp|Sta);
.
536,537c
	regw(ctlr, Isr, Ovw);
	regw(ctlr, Tcr, 0);
.
533,534c
	regw(ctlr, Tcr, LpbkNIC);
	regw(ctlr, Cr, Page0|RdABORT|Sta);
.
530c
	if(txp && (regr(ctlr, Isr) & (Txe|Ptx)) == 0)
.
526,527c
	regw(ctlr, Rbcr0, 0);
	regw(ctlr, Rbcr1, 0);
.
523,524c
	txp = regr(ctlr, Cr) & Txp;
	regw(ctlr, Cr, Page0|RdABORT|Stp);
.
516,517c
	ctlr = ether->ctlr;
.
511,512c
	Dp8390 *ctlr;
.
508a
transmit(Ether* ether)
{
	Dp8390 *ctlr;

	ctlr = ether->ctlr;

	ilock(ctlr);
	txstart(ether);
	iunlock(ctlr);
}

static void
.
505c
	ether->outpackets++;
	ctlr->txbusy = 1;
.
501,503c
	regw(ctlr, Tbcr0, len & 0xFF);
	regw(ctlr, Tbcr1, (len>>8) & 0xFF);
	regw(ctlr, Cr, Page0|RdABORT|Txp|Sta);
.
498,499c
	if(ctlr->ram)
		memmove((void*)(ether->mem+ctlr->tstart*Dp8390BufSz), rp, len);
	else
		dp8390write(ctlr, ctlr->tstart*Dp8390BufSz, rp, len);
	freeb(bp);
.
494c
		rp = minpkt;
		memmove(rp, bp->rp, len);
		memset(rp+len, 0, ETHERMINTU-len);
.
492c
	len = BLEN(bp);
	rp = bp->rp;
.
489,490c
	 * Make sure the packet is of minimum length;
	 * copy it to the card's memory by the appropriate means;
	 * start the transmission.
.
482,486c
	if(ctlr->txbusy)
		return;
	bp = qget(ether->oq);
	if(bp == nil)
		return;
.
477,480c
	 * This routine is called both from the top level and from interrupt
	 * level and expects to be called with ctlr already locked.
.
466,475d
459,464c
	ctlr = ether->ctlr;
.
456,457c
	int len;
	Dp8390 *ctlr;
	Block *bp;
	uchar minpkt[ETHERMINTU], *rp;
.
453,454c
static void
txstart(Ether* ether)
.
447,449c
		if(hdr.next < ctlr->pstart)
			hdr.next = ctlr->pstop-1;
		regw(ctlr, Bnry, hdr.next);
.
444c
		ctlr->nxtpkt = hdr.next;
.
437c
			etheriq(ether, bp, 1);
.
431c
					_dp8390read(ctlr, p, data, len);
.
427,429c
			if(len){
				if(ctlr->ram)
					memmove(p, (void*)(ether->mem+data), len);
.
422,425c
					_dp8390read(ctlr, p, data, count);
				p += count;
				data = ctlr->pstart*Dp8390BufSz;
				len -= count;
.
416,420c
			if((data+len) >= ctlr->pstop*Dp8390BufSz){
				count = ctlr->pstop*Dp8390BufSz - data;
				if(ctlr->ram)
					memmove(p, (void*)(ether->mem+data), count);
.
414d
411,412c
		if((hdr.status & (Fo|Fae|Crce|Prxok)) == Prxok && (bp = iallocb(len))){
			p = bp->rp;
			bp->wp = p+len;
.
406,409c
		 * If the packet wraps round the hardware ring, read it in
		 * two pieces.
.
398,400c
			regw(ctlr, Cr, Page0|RdABORT|Stp);
			ringinit(ctlr);
			regw(ctlr, Cr, Page0|RdABORT|Sta);

.
394c
		if(hdr.next < ctlr->pstart || hdr.next >= ctlr->pstop
.
389c
		len = ((len<<8)|hdr.len0)-4;
.
387c
			len--;
.
385c
			len = (ctlr->pstop-ctlr->nxtpkt) + (hdr.next-ctlr->pstart) - 1;
.
382,383c
		if(hdr.next > ctlr->nxtpkt)
			len = hdr.next - ctlr->nxtpkt - 1;
.
375c
			_dp8390read(ctlr, &hdr, data, sizeof(Hdr));
.
366,372c
	ctlr = ether->ctlr;
	for(curr = getcurr(ctlr); ctlr->nxtpkt != curr; curr = getcurr(ctlr)){
		data = ctlr->nxtpkt*Dp8390BufSz;
		if(ctlr->ram)
.
364c
	ulong count, data, len;
	Block *bp;
.
361,362c
	Dp8390 *ctlr;
	uchar curr, *p;
.
359c
receive(Ether* ether)
.
351,354c
	cr = regr(ctlr, Cr) & ~Txp;
	regw(ctlr, Cr, Page1|(~(Ps1|Ps0) & cr));
	curr = regr(ctlr, Curr);
	regw(ctlr, Cr, cr);

.
348d
346c
getcurr(Dp8390* ctlr)
.
344a
static void
ringinit(Dp8390* ctlr)
{
	regw(ctlr, Pstart, ctlr->pstart);
	regw(ctlr, Pstop, ctlr->pstop);
	regw(ctlr, Bnry, ctlr->pstop-1);

	regw(ctlr, Cr, Page1|RdABORT|Stp);
	regw(ctlr, Curr, ctlr->pstart);
	regw(ctlr, Cr, Page0|RdABORT|Stp);

	ctlr->nxtpkt = ctlr->pstart;
}

.
338,341d
326,336c
	regw(ctlr, Isr, Rdc);
	regw(ctlr, Cr, cr);
.
321,324c
	rdwrite(ctlr, from, len);
	for(timo = 10000; (regr(ctlr, Isr) & Rdc) == 0 && timo; timo--)
			;
.
319c
	 * Pump the data into the I/O port
	 * then wait for the remote DMA to finish.
.
316a
	else{
		regw(ctlr, Rsar0, to & 0xFF);
		regw(ctlr, Rsar1, (to>>8) & 0xFF);
		regw(ctlr, Rbcr0, len & 0xFF);
		regw(ctlr, Rbcr1, (len>>8) & 0xFF);
		regw(ctlr, Cr, Page0|RdWRITE|Sta);
	}
.
292,314c
	if(ctlr->dummyrr && (ctlr->width == 1 || ctlr->width == 2)){
		if(ctlr->width == 2)
			width = 1;
		else
			width = 0;
		crda = to-1-width;
		regw(ctlr, Rbcr0, (len+1+width) & 0xFF);
		regw(ctlr, Rbcr1, ((len+1+width)>>8) & 0xFF);
		regw(ctlr, Rsar0, crda & 0xFF);
		regw(ctlr, Rsar1, (crda>>8) & 0xFF);
		regw(ctlr, Cr, Page0|RdREAD|Sta);
	
		for(;;){
			crda = regr(ctlr, Crda0);
			crda |= regr(ctlr, Crda1)<<8;
			if(crda == to){
				/*
				 * Start the remote DMA write and make sure
				 * the registers are correct.
				 */
				regw(ctlr, Cr, Page0|RdWRITE|Sta);
	
				crda = regr(ctlr, Crda0);
				crda |= regr(ctlr, Crda1)<<8;
				if(crda != to)
					panic("crda write %d to %d\n", crda, to);
	
				break;
			}
.
289,290c
	 * This is straight from the DP8390[12D] datasheet,
	 * hence the initial set up for read.
	 * Assumption here that the A7000 EtherV card will
	 * never need a dummyrr.
.
284,285c
	len = ROUNDUP(len, ctlr->width);
.
280,282c
	cr = regr(ctlr, Cr) & ~Txp;
	regw(ctlr, Cr, Page0|RdABORT|Sta);
	regw(ctlr, Isr, Rdc);
.
270,275d
267c
	int timo, width;
.
264c
	void *v;

	ilock(ctlr);
	v = dp8390read(ctlr, to, from, len);
	iunlock(ctlr);

	return v;
}

static void*
dp8390write(Dp8390* ctlr, ulong to, void* from, ulong len)
{
.
262c
dp8390read(Dp8390* ctlr, void* to, ulong from, ulong len)
.
256,257c
	regw(ctlr, Isr, Rdc);
	regw(ctlr, Cr, cr);

.
253c
	for(timo = 10000; (regr(ctlr, Isr) & Rdc) == 0 && timo; timo--)
.
250,251c
	 * to the miracles of the bus, it's possible to get this
	 * far and still be talking to a slot full of nothing.
.
248c
	 * is necessary because this routine may be called on
.
240,244c
	regw(ctlr, Cr, Page0|RdREAD|Sta);
	rdread(ctlr, to, len);
.
229,234c
	len = ROUNDUP(len, ctlr->width);
	regw(ctlr, Rbcr0, len & 0xFF);
	regw(ctlr, Rbcr1, (len>>8) & 0xFF);
	regw(ctlr, Rsar0, from & 0xFF);
	regw(ctlr, Rsar1, (from>>8) & 0xFF);
.
222,224c
	cr = regr(ctlr, Cr) & ~Txp;
	regw(ctlr, Cr, Page0|RdABORT|Sta);
	regw(ctlr, Isr, Rdc);
.
213d
210,211c
static void*
_dp8390read(Dp8390* ctlr, void* to, ulong from, ulong len)
.
203,207c
	ilock(ctlr);
	cr = regr(ctlr, Cr) & ~Txp;
	regw(ctlr, Cr, Page1|(~(Ps1|Ps0) & cr));
	for(i = 0; i < Eaddrlen; i++)
		regw(ctlr, Par0+i, ether->ea[i]);
	regw(ctlr, Cr, cr);
	iunlock(ctlr);
.
199,201c
	 * afterwards. Don't care about multicast
	 * addresses as multicast is never enabled
	 * (currently).
.
195a
	ctlr = ether->ctlr;

.
194a
	uchar cr;
	Dp8390 *ctlr;
.
192,193d
190c
dp8390setea(Ether* ether)
.
173,188d
166,170c
	ilock(ctlr);
	cr = regr(ctlr, Cr) & ~Txp;
	regw(ctlr, Cr, Page1|(~(Ps1|Ps0) & cr));
	for(i = 0; i < Eaddrlen; i++)
		ea[i] = regr(ctlr, Par0+i);
	regw(ctlr, Cr, cr);
	iunlock(ctlr);
.
159,164c
	 * Get the ethernet address from the chip.
	 * Take care to restore the command register
	 * afterwards.
.
157a
	ctlr = ether->ctlr;

.
155,156c
	Dp8390 *ctlr;
	uchar cr;
	int i;
.
152,153c
void
dp8390getea(Ether* ether, uchar* ea)
.
134c
enum {					/* Rsr */
.
125c
enum {					/* Rcr */
.
115c
enum {					/* Tsr */
.
110c
	Lb0		= 0x02,		/* encoded loopback control */
	Lb1		= 0x04,
	LpbkNORMAL	= 0x00,		/* normal operation */
	LpbkNIC		= Lb0,		/* internal NIC module loopback */
	LpbkENDEC	= Lb1,		/* internal ENDEC module loopback */
	LpbkEXTERNAL	= Lb1|Lb0,	/* external loopback */
.
108c
enum {					/* Tcr */
.
102,105c
	Ft0		= 0x20,		/* FIFO threshold select */
	Ft1		= 0x40,
	Ft1WORD		= 0x00,
	Ft2WORD		= Ft0,
	Ft4WORD		= Ft1,
	Ft6WORD		= Ft1|Ft0,
.
86,96c
enum {					/* Dcr */
.
75c
enum {					/* Cr */
	Stp		= 0x01,		/* stop */
	Sta		= 0x02,		/* start */
	Txp		= 0x04,		/* transmit packet */
	Rd0		= 0x08,		/* remote DMA command */
	Rd1		= 0x10,	
	Rd2		= 0x20,
	RdREAD		= Rd0,		/* remote read */
	RdWRITE		= Rd1,		/* remote write */
	RdSEND		= Rd1|Rd0,	/* send packet */
	RdABORT		= Rd2,		/* abort/complete remote DMA */
	Ps0		= 0x40,		/* page select */
	Ps1		= 0x80,
	Page0		= 0x00,
	Page1		= Ps0,
	Page2		= Ps1,
};

enum {					/* Isr/Imr */
.
69c
					/* Page 1, read/write */
.
67d
53c
					/* Page 0, write */
.
51d
23,37c
					/* Page 0, read */
.
17,20c
enum {					/* NIC core registers */
.
15a
#include "ether8390.h"
.
2,3c
 * National Semiconductor DP8390 and clone
.
## diffname pc/ether8390.c 1997/0415
## diff -e /n/emeliedump/1997/0327/sys/src/brazil/pc/ether8390.c /n/emeliedump/1997/0415/sys/src/brazil/pc/ether8390.c
721a
	ether->multicast = multicast;
.
644a
	if(ether->nmaddr)
		r |= Am;
.
628a
multicast(void* arg, uchar *addr, int on)
{
	Ether *ether;
	Dp8390 *ctlr;
	uchar r, cr;
	int i;
	ulong h;

	USED(addr, on);

	ether = arg;
	ctlr = ether->ctlr;

	/*
	 *  change filter bits
	 */
	h = ethercrc(addr, 6);
	h = h>>(32-6);
	i = h/8;
	h = h%8;
	ilock(ctlr);
	cr = regr(ctlr, Cr) & ~Txp;
	regw(ctlr, Cr, Page1|(~(Ps1|Ps0) & cr));
	r = regr(ctlr, Mar0+i);
	if(on){
		if(++(ctlr->mref[h]) == 1)
			r |= 1<<h;
	} else {
		if(--(ctlr->mref[h]) <= 0){
			ctlr->mref[h] = 0;
			r &= ~(1<<h);
		}
	}	
	regw(ctlr, Mar0+i, r);
	regw(ctlr, Cr, cr);
	iunlock(ctlr);

	/*
	 * Set/reset promiscuous mode.
	 */
	r = Ab;
	if(ether->nmaddr)
		r |= Am;
	if(ether->prom)
		r |= Pro;
	ilock(ctlr);
	regw(ctlr, Rcr, r);
	iunlock(ctlr);
}

static void
.
622a
	if(ether->nmaddr)
		r |= Am;
.
## diffname pc/ether8390.c 1997/0418
## diff -e /n/emeliedump/1997/0415/sys/src/brazil/pc/ether8390.c /n/emeliedump/1997/0418/sys/src/brazil/pc/ether8390.c
652,677c
	setbit(ctlr, reverse[h&0x3f], on);
	setfilter(ether, ctlr);
.
648,650d
642a
	if(reverse[1] == 0){
		for(i = 0; i < 64; i++)
			reverse[i] = ((i&1)<<5) | ((i&2)<<3) | ((i&4)<<1)
					| ((i&8)>>1) | ((i&16)>>3) | ((i&32)>>5);
	}
.
639c
	USED(on);
.
635d
630a
setbit(Dp8390 *ctlr, int bit, int on)
{
	int i, h;

	i = bit/8;
	h = bit%8;
	if(on){
		if(++(ctlr->mref[bit]) == 1)
			ctlr->mar[i] |= 1<<h;
	} else {
		if(--(ctlr->mref[bit]) <= 0){
			ctlr->mref[bit] = 0;
			ctlr->mar[i] &= ~(1<<h);
		}
	}
}

static uchar reverse[64];

static void
.
626c
	setfilter(ether, ctlr);
.
617,624d
613a
	USED(on);

.
612d
607a
setfilter(Ether *ether, Dp8390 *ctlr)
{
	uchar r, cr;
	int i;
	uchar *mar;

	r = Ab;
	mar = 0;
	if(ether->prom){
		r |= Pro|Am;
		mar = allmar;
	} else if(ether->nmaddr){
		r |= Am;
		mar = ctlr->mar;
	}
	if(mar){
		cr = regr(ctlr, Cr) & ~Txp;
		regw(ctlr, Cr, Page1|(~(Ps1|Ps0) & cr));
		for(i = 0; i < 8; i++)
			regw(ctlr, Mar0+i, *(mar++));
		regw(ctlr, Cr, cr);
	}
	regw(ctlr, Rcr, r);
}

static void
.
606a
static uchar allmar[8] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };

.
## diffname pc/ether8390.c 1998/0129
## diff -e /n/emeliedump/1997/0418/sys/src/brazil/pc/ether8390.c /n/emeliedump/1998/0129/sys/src/brazil/pc/ether8390.c
249c
	v = _dp8390read(ctlr, to, from, len);
.
## diffname pc/ether8390.c 1998/0319
## diff -e /n/emeliedump/1998/0129/sys/src/brazil/pc/ether8390.c /n/emeliedump/1998/0319/sys/src/brazil/pc/ether8390.c
678,679d
641,642d
636c
promiscuous(void *arg, int )
.
## diffname pc/ether8390.c 1998/0825
## diff -e /n/emeliedump/1998/0319/sys/src/brazil/pc/ether8390.c /n/emeliedump/1998/0825/sys/src/brazil/pc/ether8390.c
396c
			print("dp8390: H#%2.2ux#%2.2ux#%2.2ux#%2.2ux,%lud\n",
.
## diffname pc/ether8390.c 2000/0604
## diff -e /n/emeliedump/1998/0825/sys/src/brazil/pc/ether8390.c /n/emeliedump/2000/0604/sys/src/9/pc/ether8390.c
774c
	regw(ctlr, Imr, 0);
.
772a
	/*
	 * Clear any pending interrupts and mask then all off.
	 */
.
762c
	regw(ctlr, Tcr, LpbkNIC);
.
716a
	regw(ctlr, Tcr, LpbkNORMAL);
.
714a
	regw(ctlr, Isr, 0xFF);
	regw(ctlr, Imr, Cnt|Ovw|Txe|Rxe|Ptx|Prx);
.
707a
	 * Sometimes there's an interrupt pending at this
	 * point but there's nothing in the Isr, so
	 * any pending interrupts are cleared and the
	 * mask of acceptable interrupts is enabled here.
.
604c
	iunlock(ctlr);
.
558c
	ilock(ctlr);
.
538c
	regw(ctlr, Tcr, LpbkNORMAL);
.
## diffname pc/ether8390.c 2002/0114
## diff -e /n/emeliedump/2000/0604/sys/src/9/pc/ether8390.c /n/emeliedump/2002/0114/sys/src/9/pc/ether8390.c
305c
					panic("crda write %lud to %lud\n", crda, to);
.

Bell Labs OSI certified Powered by Plan 9

(Return to Plan 9 Home Page)

Copyright © 2021 Plan 9 Foundation. All Rights Reserved.
Comments to webmaster@9p.io.