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

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


## diffname pc/devether.c 1992/0403
## diff -e /dev/null /n/bootesdump/1992/0403/sys/src/9/safari/devether.c
0a
/*
 * Western Digital ethernet adapter
 * BUGS:
 *	more than one controller
 *	fix for different controller types
 */
#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"

typedef struct Ctlr Ctlr;
typedef struct Pktype Pktype;

enum {
	IObase		= 0x360,

	EA		= 0x08,		/* Ethernet Address in ROM */
	ID		= 0x0E,		/* interface type */

	NIC		= 0x10,		/* National DP8390 Chip */
	Cr		= NIC+0x00,	/* Page [01] */

	Clda0		= NIC+0x01,	/* read */
	Pstart		= Clda0,	/* write */
	Clda1		= NIC+0x02,	/* read */
	Pstop		= Clda1,	/* write */
	Bnry		= NIC+0x03,	/* Page 0 */
	Tsr		= NIC+0x04,	/* read */
	Tpsr		= Tsr,		/* write */
	Ncr		= NIC+0x05,
	Isr		= NIC+0x07,
	Rbcr0		= NIC+0x0A,
	Rbcr1		= NIC+0x0B,
	Rsr		= NIC+0x0C,	/* read */
	Rcr		= Rsr,		/* write */
	Cntr0		= NIC+0x0D,	/* read */
	Tcr		= Cntr0,	/* write */
	Cntr1		= NIC+0x0E,	/* read */
	Dcr		= Cntr1,	/* write */
	Cntr2		= NIC+0x0F,	/* read */
	Imr		= Cntr2,	/* write */

	Par0		= NIC+0x01,	/* Page 1 */
	Curr		= NIC+0x07,
	Mar0		= NIC+0x08,
	Mar1		= NIC+0x09,
	Mar2		= NIC+0x0A,
	Mar3		= NIC+0x0B,
	Mar4		= NIC+0x0C,
	Mar5		= NIC+0x0D,
	Mar6		= NIC+0x0E,
	Mar7		= NIC+0x0F,

	RAMbase		= 0xC8000,

	Nctlr		= 1,
	NPktype		= 9,		/* types/interface */
};

/*
 * one per ethernet packet type
 */
struct Pktype {
	QLock;
	int	type;			/* ethernet type */
	int	prom;			/* promiscuous mode */
	Queue	*q;
	int	inuse;
	Ctlr	*ctlr;
};

/*
 *  per ethernet
 */
struct Ctlr {
	QLock;

	Rendez	rr;			/* rendezvous for an input buffer */
	Queue	rq;

	Qlock	xl;
	Rendez	xr;

	int	iobase;			/* I/O base address */

	Pktype	pktype[NPktype];
	uchar	ea[6];
	uchar	ba[6];

	uchar	prom;			/* true if promiscuous mode */
	uchar	kproc;			/* true if kproc started */
	char	name[NAMELEN];		/* name of kproc */
	Network	net;
	Netprot	prot[NPktype];

	int	inpackets;
	int	outpackets;
	int	crcs;			/* input crc errors */
	int	oerrs;			/* output errors */
	int	frames;			/* framing errors */
	int	overflows;		/* packet overflows */
	int	buffs;			/* buffering errors */
};
static Ctlr ctlr[Nctlr];

static void
etheroput(Queue *q, Block *bp)
{
	Ctlr *c;
	int len, n;
	Pktype *t;
	Etherpkt *p;
	Block *nbp;

	c = ((Pktype *)q->ptr)->ctlr;
	if(bp->type == M_CTL){
		t = q->ptr;
		if(streamparse("connect", bp))
			t->type = strtol((char *)bp->rptr, 0, 0);
		else if(streamparse("promiscuous", bp)) {
			t->prom = 1;
			qlock(c);
			c->prom++;
			if(c->prom == 1)
				outb(c->iobase+Rcr, 0x14);	/* PRO|AB */
			qunlock(c);
		}
		freeb(bp);
		return;
	}

	/*
	 * give packet a local address, return upstream if destined for
	 * this machine.
	 */
	if(BLEN(bp) < ETHERHDRSIZE){
		bp = pullup(bp, ETHERHDRSIZE);
		if(bp == 0)
			return;
	}
	p = (Etherpkt *)bp->rptr;
	memmove(p->s, c->ea, sizeof(c->ea));
	if(memcmp(c->ea, p->d, sizeof(c->ea)) == 0){
		len = blen(bp);
		bp = expandb(bp, len >= ETHERMINTU ? len: ETHERMINTU);
		if(bp){
			putq(&c->rq, bp);
			wakeup(&c->rr);
		}
		return;
	}
	if(memcmp(c->ba, p->d, sizeof(c->ba)) == 0){
		len = blen(bp);
		nbp = copyb(bp, len);
		nbp = expandb(nbp, len >= ETHERMINTU ? len: ETHERMINTU);
		if(nbp){
			nbp->wptr = nbp->rptr+len;
			putq(&c->rq, nbp);
			wakeup(&c->rr);
		}
	}

	/*
	 * only one transmitter at a time
	 */
	qlock(&c->xl);
	if(waserror()){
		qunlock(&c->xl);
		nexterror();
	}

	/*
	 *  Wait till we get an output buffer
	 */
	sleep(&c->xr, isobuf, c);
	p = enet.xn;

	/*
	 * copy message into buffer
	 */
	len = 0;
	for(nbp = bp; nbp; nbp = nbp->next){
		if(sizeof(Etherpkt) - len >= (n = BLEN(nbp))){
			memmove(((uchar *)p)+len, nbp->rptr, n);
			len += n;
		} else
			print("no room damn it\n");
		if(bp->flags & S_DELIM)
			break;
	}

	/*
	 *  pad the packet (zero the pad)
	 */
	if(len < ETHERMINTU){
		memset(((char*)p)+len, 0, ETHERMINTU-len);
		len = ETHERMINTU;
	}
	enet.xn->len = len;

	/*
	 *  give packet a local address
	 */
	memmove(p->s, enet.ea, sizeof(enet.ea));

	/*
	 *  give to Chip
	 */
	splhi();		/* sync with interrupt routine */
	enet.xn->owner = Chip;
	if(enet.xmting == 0)
		ethersend(enet.xn);
	spllo();

	/*
	 *  send
	 */
	enet.xn = XSUCC(enet.xn);
	freeb(bp);
	qunlock(&enet.xl);
	poperror();

	enet.outpackets++;
}

/*
 * open an ether line discipline
 *
 * the lock is to synchronize changing the ethertype with
 * sending packets up the stream on interrupts.
 */
static void
etherstopen(Queue *q, Stream *s)
{
	Ctlr *c = &ctlr[0];
	Pktype *t;

	t = &c->pktype[s->id];
	qlock(t);
	RD(q)->ptr = WR(q)->ptr = t;
	t->type = 0;
	t->q = RD(q);
	t->inuse = 1;
	t->ctlr = c;
	qunlock(t);
}

/*
 *  close ether line discipline
 *
 *  the lock is to synchronize changing the ethertype with
 *  sending packets up the stream on interrupts.
 */
static void
etherstclose(Queue *q)
{
	Pktype *t;

	t = (Pktype *)(q->ptr);
	if(t->prom){
		qlock(t->ctlr);
		t->ctlr->prom--;
		if(t->ctlr->prom == 0)
			/* turn off promiscuous mode here */;
		qunlock(t->ctlr);
	}
	qlock(t);
	t->type = 0;
	t->q = 0;
	t->prom = 0;
	t->inuse = 0;
	netdisown(&t->ctlr->net, t - t->ctlr->pktype);
	qunlock(t);
}

static Qinfo info = {
	nullput,
	etheroput,
	etherstopen,
	etherstclose,
	"ether"
};

static int
clonecon(Chan *chan)
{
	Ctlr *c = &ctlr[0];
	Pktype *t;

	for(t = c->pktype; t < &c->pktype[NPktype]; t++){
		qlock(t);
		if(t->inuse || t->q){
			qunlock(t);
			continue;
		}
		t->inuse = 1;
		netown(&c->net, t - c->pktype, u->p->user, 0);
		qunlock(t);
		return t - c->pktype;
	}
	exhausted("ether channels");
}

static void
statsfill(Chan *chan, char *p, int n)
{
	Ctlr *c = &ctlr[0];
	char buf[256];

	sprint(buf, "in: %d\nout: %d\ncrc errs %d\noverflows: %d\nframe errs %d\nbuff errs: %d\noerrs %d\naddr: %.02x:%.02x:%.02x:%.02x:%.02x:%.02x\n",
		c->inpackets, c->outpackets, c->crcs,
		c->overflows, c->frames, c->buffs, c->oerrs,
		c->ea[0], c->ea[1], c->ea[2], c->ea[3], c->ea[4], c->ea[5]);
	strncpy(p, buf, n);
}

static void
typefill(Chan *c, char *p, int n)
{
	char buf[16];
	Pktype *t;

	t = &ctlr[0].pktype[STREAMID(c->qid.path)];
	sprint(buf, "%d", t->type);
	strncpy(p, buf, n);
}

static void
intr(Ureg *ur)
{
	panic("ether intr\n");
}

/*
 * the following initialisation procedure
 * is mandatory
 * after this, the chip is still offline
 */
static void
init(Ctlr *c)
{
	int i;

	outb(c->iobase+Cr, 0x21);	/* Page0, RD2|STP */
	outb(c->iobase+Dcr, 0x48);	/* FT1|LS */
	outb(c->iobase+Rbcr0, 0);
	outb(c->iobase+Rbcr1, 0);
	outb(c->iobase+Rcr, 0x04);	/* AB */
	outb(c->iobase+Tcr, 0);
	outb(c->iobase+Bnry, 6);
	outb(c->iobase+Pstart, 6);	/* 6*256 */
	outb(c->iobase+Pstop, 32);	/* 8*1024/256 */
	outb(c->iobase+Isr, 0xFF);
	outb(c->iobase+Imr, 0x0F);	/* TXEE|RXEE|PTXE|PRXE */

	outb(c->iobase+Cr, 0x61);	/* Page1, RD2|STP */
	for(i = 0; i < sizeof(c->ea); i++)
		outb(c->iobase+Par0+i, c->ea[i]);
	outb(c->iobase+Curr, 6);	/* 6*256 */
}

void
etherreset(void)
{
	Ctlr *c = &ctlr[0];
	int i;

	c->iobase = IObase;
	init(c);
	setvec(Ethervec, intr);

	for(i = 0; i < sizeof(c->ea); i++)
		c->ea[i] = inb(c->iobase+EA+i);
	memset(c->ba, 0xFF, sizeof(c->ba));

	c->net.name = "ether";
	c->net.nconv = NPktype;
	c->net.devp = &info;
	c->net.protop = 0;
	c->net.listen = 0;
	c->net.clone = clonecon;
	c->net.ninfo = 2;
	c->net.prot = c->prot;
	c->net.info[0].name = "stats";
	c->net.info[0].fill = statsfill;
	c->net.info[1].name = "type";
	c->net.info[1].fill = typefill;
}

static int
isinput(void *arg)
{
	Ctlr *c = arg;

	return 0;
}

static void
etherkproc(void *arg)
{
	Ctlr *c = arg;

	if(waserror()){
		print("someone noted %s\n", c->name);
		c->kproc = 0;
		nexterror();
	}
	c->kproc = 1;
	for(;;){
		sleep(&c->rr, isinput, c);
	}
}

void
etherinit(void)
{
	int ctlrno = 0;

	/*
	 * put the receiver online
	 * and start the kproc
	 */
	outb(c->iobase+Cr, 0x22);	/* Page0, RD2|STA */
	outb(c->iobase+Tpsr, 0);
	if(ctlr[ctlrno].kproc == 0){
		sprint(ctlr[ctlrno].name, "ether%dkproc", ctlrno);
		kproc(ctlr[ctlrno].name, etherkproc, &ctlr[ctlrno]);
	}
}

Chan *
etherattach(char *spec)
{
	return devattach('l', spec);
}

Chan *
etherclone(Chan *c, Chan *nc)
{
	return devclone(c, nc);
}

int
etherwalk(Chan *c, char *name)
{
	return netwalk(c, name, &ctlr[0].net);
}

void
etherstat(Chan *c, char *dp)
{
	netstat(c, dp, &ctlr[0].net);
}

Chan *
etheropen(Chan *c, int omode)
{
	return netopen(c, omode, &ctlr[0].net);
}

void
ethercreate(Chan *c, char *name, int omode, ulong perm)
{
	error(Eperm);
}

void
etherremove(Chan *c)
{
	error(Eperm);
}

void
etherwstat(Chan *c, char *dp)
{
	netwstat(c, dp, &ctlr[0].net);
}

void
etherclose(Chan *c)
{
	if(c->stream)
		streamclose(c);
}

long
etherread(Chan *c, void *a, long n, ulong offset)
{
	return netread(c, a, n, offset, &ctlr[0].net);
}

long
etherwrite(Chan *c, char *a, long n, ulong offset)
{
	return streamwrite(c, a, n, 0);
}
.
## diffname pc/devether.c 1992/0404
## diff -e /n/bootesdump/1992/0403/sys/src/9/safari/devether.c /n/bootesdump/1992/0404/sys/src/9/safari/devether.c
428,429c
	outb(ctlr[ctlrno].iobase+Tcr, 0);
.
415c
		sleep(&cp->rr, isinput, cp);
		while(bp = getq(&cp->rq)){
			cp->inpackets++;
			etherup(cp, (Etherpkt*)bp->rptr, BLEN(bp));
			freeb(bp);
		}
#ifdef foo
			bnry = inb(cp->iobase+Bnry);
			while(bnry != cp->curr){
				rp = &((Ring *)RAMbase)[bnry];
			}
#endif
.
413c
	cp->kproc = 1;
.
409,410c
		print("%s noted\n", cp->name);
		init(cp);
		cp->kproc = 0;
.
406c
	Ctlr *cp = arg;
	Block *bp;
	uchar bnry, curr;
	Ring *rp;
.
400c
	return cp->bnry != cp->curr;
.
398c
	Ctlr *cp = arg;
.
394a
static void
etherup(Ctlr *cp, Etherpkt *p, int len)
{
	Block *bp;
	Pktype *pp;
	int t;

	t = (p->type[0]<<8) | p->type[1];
	for(pp = &cp->pktype[0]; pp < &cp->pktype[NPktype]; pp++){
		/*
		 *  check before locking just to save a lock
		 */
		if(pp->q == 0 || (t != pp->type && pp->type != -1))
			continue;

		/*
		 *  only a trace channel gets packets destined for other machines
		 */
		if(pp->type != -1 && p->d[0] != 0xFF && memcmp(p->d, cp->ea, sizeof(p->d)))
			continue;

		/*
		 *  check after locking to make sure things didn't
		 *  change under foot
		 */
		if(canqlock(pp) == 0)
			continue;
		if(pp->q == 0 || pp->q->next->len > Streamhi || (t != pp->type && pp->type != -1)){
			qunlock(pp);
			continue;
		}
		if(waserror() == 0){
			bp = allocb(len);
			memmove(bp->rptr, (uchar *)p, len);
			bp->wptr += len;
			bp->flags |= S_DELIM;
			PUTNEXT(pp->q, bp);
		}
		poperror();
		qunlock(pp);
	}
}

.
381,392c
	cp->net.name = "ether";
	cp->net.nconv = NPktype;
	cp->net.devp = &info;
	cp->net.protop = 0;
	cp->net.listen = 0;
	cp->net.clone = clonecon;
	cp->net.ninfo = 2;
	cp->net.prot = cp->prot;
	cp->net.info[0].name = "stats";
	cp->net.info[0].fill = statsfill;
	cp->net.info[1].name = "type";
	cp->net.info[1].fill = typefill;
.
377,379c
	for(i = 0; i < sizeof(cp->ea); i++)
		cp->ea[i] = inb(cp->iobase+EA+i);
	memset(cp->ba, 0xFF, sizeof(cp->ba));
.
373,374c
	cp->iobase = IObase;
	init(cp);
.
370c
	Ctlr *cp = &ctlr[0];
.
361,364c
	outb(cp->iobase+Cr, 0x61);		/* Page1, RD2|STP */
	for(i = 0; i < sizeof(cp->ea); i++)
		outb(cp->iobase+Par0+i, cp->ea[i]);
	outb(cp->iobase+Curr, 6);		/* 6*256 */
	cp->curr = 6;

	outb(cp->iobase+Cr, 0x22);		/* Page0, RD2|STA */
	outb(cp->iobase+Tpsr, 0);
.
349,359c
	outb(cp->iobase+Cr, 0x21);		/* Page0, RD2|STP */
	outb(cp->iobase+Dcr, 0x48);		/* FT1|LS */
	outb(cp->iobase+Rbcr0, 0);
	outb(cp->iobase+Rbcr1, 0);
	outb(cp->iobase+Rcr, 0x04);		/* AB */
	outb(cp->iobase+Tcr, 0x20);		/* LB0 */
	outb(cp->iobase+Bnry, 6);
	cp->bnry = 6;
	outb(cp->iobase+Pstart, 6);		/* 6*256 */
	outb(cp->iobase+Pstop, 32);		/* 8*1024/256 */
	outb(cp->iobase+Isr, 0xFF);
	outb(cp->iobase+Imr, 0x1F);		/* OVWE|TXEE|RXEE|PTXE|PRXE */
.
345c
init(Ctlr *cp)
.
342c
 * we leave the chip idling on internal loopback
.
336c
	Ctlr *cp = &ctlr[0];
	uchar isr, curr;

	outb(cp->iobase+Cr, 0x22);			/* Page0, RD2|STA */
	while(isr = inb(cp->iobase+Isr)){
		outb(cp->iobase+Isr, isr);
		if(isr & Txe)
			cp->oerrs++;
		if(isr & Rxe){
			cp->frames += inb(cp->iobase+Cntr0);
			cp->crcs += inb(cp->iobase+Cntr1);
			cp->buffs += inb(cp->iobase+Cntr2);
		}
		if(isr & Ptx)
			cp->outpackets++;
		if(isr & (Txe|Ptx)){
			panic("tx intr\n");
		}
		/*
		 * the receive ring is full.
		 * put the NIC into loopback mode to give
		 * kproc a chance to process some packets.
		 */
		if(isr & Ovw){
			outb(cp->iobase+Cr, 0x21);	/* Page0, RD2|STP */
			outb(cp->iobase+Rbcr0, 0);
			outb(cp->iobase+Rbcr1, 0);
			while((inb(cp->iobase+Isr) & Rst) == 0)
				delay(1);
			outb(cp->iobase+Tcr, 0x20);	/* LB0 */
			outb(cp->iobase+Cr, 0x22);	/* Page0, RD2|STA */
			cp->ovw = 1;
		}
		/*
		 * we have received packets.
		 * this is the only place, other than the init code,
		 * where we set the controller to Page1.
		 * we must be careful to reset it back to Page0 in case
		 * we interrupted some other part of this driver.
		 */
		if(isr & (Ovw|Prx)){
			outb(cp->iobase+Cr, 0x62);	/* Page1, RD2|STA */
			cp->curr = inb(cp->iobase+Curr);
			outb(cp->iobase+Cr, 0x22);	/* Page0, RD2|STA */
			wakeup(&cp->rr);
		}
	}
.
328,329c
	pp = &ctlr[0].pktype[STREAMID(c->qid.path)];
	sprint(buf, "%d", pp->type);
.
326c
	Pktype *pp;
.
316,318c
		cp->inpackets, cp->outpackets, cp->crcs,
		cp->overflows, cp->frames, cp->buffs, cp->oerrs,
		cp->ea[0], cp->ea[1], cp->ea[2], cp->ea[3], cp->ea[4], cp->ea[5]);
.
312c
	Ctlr *cp = &ctlr[0];
.
310c
statsfill(Chan *c, char *p, int n)
.
301,304c
		pp->inuse = 1;
		netown(&cp->net, pp - cp->pktype, u->p->user, 0);
		qunlock(pp);
		return pp - cp->pktype;
.
295,298c
	for(pp = cp->pktype; pp < &cp->pktype[NPktype]; pp++){
		qlock(pp);
		if(pp->inuse || pp->q){
			qunlock(pp);
.
292,293c
	Ctlr *cp = &ctlr[0];
	Pktype *pp;
.
290c
clonecon(Chan *c)
.
272,278c
	qlock(pp);
	pp->type = 0;
	pp->q = 0;
	pp->prom = 0;
	pp->inuse = 0;
	netdisown(&pp->ctlr->net, pp - pp->ctlr->pktype);
	qunlock(pp);
.
264,270c
	pp = (Pktype *)(q->ptr);
	if(pp->prom){
		qlock(pp->ctlr);
		pp->ctlr->prom--;
		if(pp->ctlr->prom == 0){
			outb(pp->ctlr->iobase+Cr, 0x22);/* Page0, RD2|STA */
			outb(pp->ctlr->iobase+Rcr, 0x04);/* AB */
		}
		qunlock(pp->ctlr);
.
262c
	Pktype *pp;
.
243,250c
	pp = &cp->pktype[s->id];
	qlock(pp);
	RD(q)->ptr = WR(q)->ptr = pp;
	pp->type = 0;
	pp->q = RD(q);
	pp->inuse = 1;
	pp->ctlr = cp;
	qunlock(pp);
.
240,241c
	Ctlr *cp = &ctlr[0];
	Pktype *pp;
.
228a
#endif
.
130a
			}
.
129c
			if(c->prom == 1){
				outb(t->ctlr->iobase+Cr, 0x22);	/* Page0, RD2|STA */
.
119a
panic("etheroput\n");
#ifdef notdef
.
86c
	QLock	xl;
.
83a
	uchar	bnry;
	uchar	curr;
	uchar	ovw;
.
61,62c
struct Ring {
	uchar	status;
	uchar	next;
	ushort	len;
	uchar	data[BUFsize-4];
.
59c
/*
 * some register bits
 */
enum {
	Prx		= 0x01,		/* Isr:	packet received */
	Ptx		= 0x02,		/*	packet transmitted */
	Rxe		= 0x04,		/*	receive error */
	Txe		= 0x08,		/*	transmit error */
	Ovw		= 0x10,		/*	overwrite warning */
	Rst		= 0x80,		/*	reset status */
};
.
50,57c
};
.
35c
	Tbcr0		= NIC+0x05,	/* write */
	Tbcr1		= NIC+0x06,	/* write */
.
28,32c
	Pstart		= NIC+0x01,	/* write */
	Pstop		= NIC+0x02,	/* write */
	Bnry		= NIC+0x03,
.
21a
	Nctlr		= 1,
	NPktype		= 9,		/* types/interface */
};

/*
 * register offsets from IObase
 */
enum {
.
20a
	RAMbase		= 0xC8000,
	RAMsize		= 8*1024,
	BUFsize		= 256,
.
17a
typedef struct Ring Ring;
.
4c
 *	no more than one controller
.
## diffname pc/devether.c 1992/0405
## diff -e /n/bootesdump/1992/0404/sys/src/9/safari/devether.c /n/bootesdump/1992/0405/sys/src/9/safari/devether.c
415a
 * and pointing to Page0.
.
414c
 * is mandatory.
.
400c
		 * we must be sure to reset it back to Page0 in case
.
366d
296d
293,294c
		if(pp->ctlr->prom == 0)
.
154d
151,152c
			if(c->prom == 1)
.
## diffname pc/devether.c 1992/0406
## diff -e /n/bootesdump/1992/0405/sys/src/9/safari/devether.c /n/bootesdump/1992/0406/sys/src/9/safari/devether.c
542,547c
		/*
		 * process any received packets
		 */
		bnry = inb(cp->iobase+Bnry);
		while(bnry != cp->curr){
			rp = &((Ring*)RAMbase)[bnry];
printpkt(bnry, rp->len, (Etherpkt*)rp->data);
			cp->inpackets++;
			etherup(cp, (Etherpkt*)rp->data, rp->len-4);
			bnry = rp->next;
			outb(cp->iobase+Bnry, bnry);
		}
		/*
		 * if we idled input because of overflow,
		 * restart
		 */
		if(cp->ovw){
			cp->ovw = 0;
			outb(cp->iobase+Tcr, 0);
		}
.
536a
		/*
		 * process any internal loopback packets
		 */
.
511a
static void
printpkt(uchar bnry, ushort len, Etherpkt *p)
{
	int i;

	print("%.2ux: %.4d d(%.2ux%.2ux%.2ux%.2ux%.2ux%.2ux)s(%.2ux%.2ux%.2ux%.2ux%.2ux%.2ux)t(%.2ux %.2ux)\n",
		bnry, len,
		p->d[0], p->d[1], p->d[2], p->d[3], p->d[4], p->d[5],
		p->s[0], p->s[1], p->s[2], p->s[3], p->s[4], p->s[5],
		p->type[0], p->type[1]);
}

.
189a
panic("etheroput\n");
#ifdef notdef
.
185,186c
			putq(&cp->rq, nbp);
			wakeup(&cp->rr);
.
182,183c
		if(nbp = expandb(nbp, len >= ETHERMINTU ? len: ETHERMINTU)){
.
179c
	if(memcmp(cp->ba, p->d, sizeof(cp->ba)) == 0){
.
172,175c
		if (bp = expandb(bp, len >= ETHERMINTU ? len: ETHERMINTU)){
			putq(&cp->rq, bp);
			wakeup(&cp->rr);
.
169,170c
	memmove(p->s, cp->ea, sizeof(cp->ea));
	if(memcmp(cp->ea, p->d, sizeof(cp->ea)) == 0){
.
163,167c
	if(BLEN(bp) < ETHERHDRSIZE && (bp = pullup(bp, ETHERHDRSIZE)) == 0)
		return;
.
148,153c
			pp->prom = 1;
			qlock(cp);
			cp->prom++;
			if(cp->prom == 1)
				outb(cp->iobase+Rcr, 0x14);	/* PRO|AB */
			qunlock(cp);
.
146c
			pp->type = strtol((char *)bp->rptr, 0, 0);
.
144c
		pp = q->ptr;
.
140,142c
	cp = ((Pktype *)q->ptr)->ctlr;
.
136c
	Pktype *pp;
.
134c
	Ctlr *cp;
.
5a
 *	output
 *	deal with stalling and restarting output on input overflow
 *	fix magic ring constants
.
4a
 * TODO:
.
## diffname pc/devether.c 1992/0407
## diff -e /n/bootesdump/1992/0406/sys/src/9/safari/devether.c /n/bootesdump/1992/0407/sys/src/9/safari/devether.c
574a
			wakeup(&cp->xr);
.
564,566c
			etherup(cp, (Etherpkt*)rp->data, ((rp->len1<<8)+rp->len0)-4);
			cp->bnry = rp->next;
			outb(cp->iobase+Bnry, cp->bnry);
.
559,562c
		cp->bnry = inb(cp->iobase+Bnry);
		while(cp->bnry != cp->curr){
			rp = &cp->ring[cp->bnry];
.
437a
	cp->xpkt = (Etherpkt*)(KZERO|RAMbase);
.
424a
	cp->ring = (Ring*)(KZERO|RAMbase);
.
373c
			cp->xbusy = 0;
			wakeup(&cp->xr);
.
248,250d
246c
	qunlock(&cp->xl);
.
241,244d
235,239c
	outb(cp->iobase+Tbcr0, len & 0xFF);
	outb(cp->iobase+Tbcr1, (len>>8) & 0xFF);
	outb(cp->iobase+Cr, 0x26);			/* Page0|TXP|STA */
	cp->xbusy = 1;
.
233c
	 * start the transmission
.
230c
	memmove(p->s, cp->ea, sizeof(cp->ea));
.
228c
	 * give packet a local address
.
225d
219c
	 * pad the packet (zero the pad)
.
201,202c
	sleep(&cp->xr, isxfree, cp);
	p = cp->xpkt;
.
199c
	 * Wait till we get an output buffer
.
194c
		qunlock(&cp->xl);
.
192c
	qlock(&cp->xl);
.
187,188d
134a
static int
isxfree(void *arg)
{
	Ctlr *cp = arg;

	return cp->xbusy == 0 && cp->ovw == 0;
}

.
111a
	uchar	xbusy;
.
109a
	Etherpkt *xpkt;
.
108d
104a
	Queue	rq;
.
103a
	Ring	*ring;
.
82c
	uchar	len0;
	uchar	len1;
.
9a
 *	rewrite per SMC doc
.
## diffname pc/devether.c 1992/0408
## diff -e /n/bootesdump/1992/0407/sys/src/9/safari/devether.c /n/bootesdump/1992/0408/sys/src/9/safari/devether.c
571a

.
569c
			bnry = rp->next;
			cp->bnry = PREV(bnry, 32);
.
564,566c
		bnry = NEXT(cp->bnry, 32);
		while(bnry != cp->curr){
			rp = &cp->ring[bnry];
.
560a

.
533c
	return NEXT(cp->bnry, 32) != cp->curr;
.
456a
	init(cp);
	setvec(Ethervec, intr);
.
452,454d
437,438c
	cp->curr = cp->bnry+1;
	outb(cp->iobase+Curr, cp->curr);
.
427a
	outb(cp->iobase+Bnry, cp->bnry);
.
426d
391a
			cp->overflows++;
.
34a
#define NEXT(x, l)	((((x)+1)%(l)) == 0 ? 6: (((x)+1)%(l)))
#define PREV(x, l)	(((x)-1) == 5 ? (l-1): ((x)-1))

.
## diffname pc/devether.c 1992/0409
## diff -e /n/bootesdump/1992/0408/sys/src/9/safari/devether.c /n/bootesdump/1992/0409/sys/src/9/safari/devether.c
670a
}

void
etherdump(void)
{
	Ctlr *cp = &ctlr[0];
	uchar bnry, curr, isr;
	int s;

	s = splhi();
	bnry = inb(cp->iobase+Bnry);
	outb(cp->iobase+Cr, 0x62);			/* Page1, RD2|STA */
	curr = inb(cp->iobase+Curr);
	outb(cp->iobase+Cr, 0x22);			/* Page0, RD2|STA */
	isr = inb(cp->iobase+Isr);
	print("b%d c%d x%d B%d C%d I%ux",
	    cp->bnry, cp->curr, cp->xbusy, bnry, curr, isr);
	print("\t%d %d %d %d %d %d %d\n", cp->inpackets, cp->opackets,
	    cp->crcs, cp->oerrs, cp->frames, cp->overflows, cp->buffs);
	splx(s);
.
577,586d
455a
	msr = 0x40|inb(cp->iobase);
	outb(cp->iobase, msr);
for(i = 0; i < 0x10; i++)
    print("#%2.2ux ", inb(cp->iobase+i));
print("\n");
.
453a
	uchar msr;
.
406a
if(cp->curr == 0)
    print("C0: b%d i%ux\n", cp->bnry, isr);
.
396d
381,394c
		if(isr & Ovw)
.
148c
	return cp->xbusy == 0;
.
114d
## diffname pc/devether.c 1992/0410
## diff -e /n/bootesdump/1992/0409/sys/src/9/safari/devether.c /n/bootesdump/1992/0410/sys/src/9/safari/devether.c
671c
	print("\t%d %d %d %d %d %d %d\n", cp->inpackets, cp->outpackets,
.
663a
debug++;
.
567c
			cp->bnry = PREV(bnry, RINGsize);
.
565c
			len0 = ((rp->len1<<8)+rp->len0)-4;
			len1 = 0;

			if(rp->data+len0 >= (uchar*)&cp->ring[RINGsize]){
				len1 = rp->data+len0 - (uchar*)&cp->ring[RINGsize];
				len0 = (uchar*)&cp->ring[RINGsize] - rp->data;
			}

			etherup(cp, rp->data, len0, (uchar*)&cp->ring[RINGbase], len1);



if(debug)
    print("K%d/%d/%d|", bnry, rp->next, PREV(rp->next, RINGsize));
.
561c
		bnry = NEXT(cp->bnry, RINGsize);
.
554c
			etherup(cp, bp->rptr, BLEN(bp), 0, 0);
.
538a
	int len0, len1;
.
529c
	return NEXT(cp->bnry, RINGsize) != cp->curr;
.
508c
		qunlock(tp);
.
505c
			PUTNEXT(tp->q, bp);
.
501,503c
			bp = allocb(len0+len1);
			memmove(bp->rptr, d0, len0);
			if(len1)
				memmove(bp->rptr+len0, d1, len1);
			bp->wptr += len0+len1;
.
496,497c
		if(tp->q == 0 || tp->q->next->len > Streamhi || (t != tp->type && tp->type != -1)){
			qunlock(tp);
.
494c
		if(canqlock(tp) == 0)
.
487c
		if(tp->type != -1 && p->d[0] != 0xFF && memcmp(p->d, cp->ea, sizeof(p->d)))
.
481c
		if(tp->q == 0 || (t != tp->type && tp->type != -1))
.
476,477c
	p = (Etherpkt*)d0;
	t = (p->type[0]<<8)|p->type[1];
	for(tp = &cp->type[0]; tp < &cp->type[NType]; tp++){
.
473c
	Type *tp;
.
471a
	Etherpkt *p;
.
470c
etherup(Ctlr *cp, uchar *d0, int len0, uchar *d1, int len1)
.
456c
	cp->net.nconv = NType;
.
448a
msr=0x40|inb(cp->iobase+0x05);
outb(cp->iobase+0x05, msr);
.
445a
msr=0x40|inb(cp->iobase+0x05);
outb(cp->iobase+0x05, msr);
.
420,421c
	outb(cp->iobase+Pstart, RINGbase);
	outb(cp->iobase+Pstop, RINGsize);
.
417c
	cp->bnry = RINGbase;
.
394a
if(debug)
    print("I%d/%d/%d|", isr, cp->curr, cp->bnry);
.
392,393d
389c
		if(isr & (Rxe|Prx)){
.
380,381c
		if(isr & Ovw){
			bnry = inb(cp->iobase+Bnry);
			outb(cp->iobase+bnry, bnry);
			cp->buffs++;
		}
.
372c
			cp->overflows += inb(cp->iobase+Cntr2);
.
363c
	uchar isr, bnry, curr;
.
354,355c
	tp = &ctlr[0].type[STREAMID(c->qid.path)];
	sprint(buf, "%d", tp->type);
.
352c
	Type *tp;
.
327,330c
		tp->inuse = 1;
		netown(&cp->net, tp - cp->type, u->p->user, 0);
		qunlock(tp);
		return tp - cp->type;
.
321,324c
	for(tp = cp->type; tp < &cp->type[NType]; tp++){
		qlock(tp);
		if(tp->inuse || tp->q){
			qunlock(tp);
.
319c
	Type *tp;
.
298,304c
	qlock(tp);
	tp->type = 0;
	tp->q = 0;
	tp->prom = 0;
	tp->inuse = 0;
	netdisown(&tp->ctlr->net, tp - tp->ctlr->type);
	qunlock(tp);
.
290,296c
	tp = (Type *)(q->ptr);
	if(tp->prom){
		qlock(tp->ctlr);
		tp->ctlr->prom--;
		if(tp->ctlr->prom == 0)
			outb(tp->ctlr->iobase+Rcr, 0x04);/* AB */
		qunlock(tp->ctlr);
.
288c
	Type *tp;
.
269,276c
	tp = &cp->type[s->id];
	qlock(tp);
	RD(q)->ptr = WR(q)->ptr = tp;
	tp->type = 0;
	tp->q = RD(q);
	tp->inuse = 1;
	tp->ctlr = cp;
	qunlock(tp);
.
267c
	Type *tp;
.
165c
			tp->prom = 1;
.
163c
			tp->type = strtol((char *)bp->rptr, 0, 0);
.
161c
		tp = q->ptr;
.
159c
	cp = ((Type *)q->ptr)->ctlr;
.
155c
	Type *tp;
.
130c
	Netprot	prot[NType];
.
122c
	Type	type[NType];
.
94c
struct Type {
.
80d
35,36c
#define NEXT(x, l)	((((x)+1)%(l)) == 0 ? RINGbase: (((x)+1)%(l)))
#define PREV(x, l)	(((x)-1) < RINGbase ? (l-1): ((x)-1))
.
32c
	NType		= 9,		/* types/interface */
.
30a
	RINGbase	= 6,		/* gak */
	RINGsize	= 32,		/* gak */

.
27c
	RAMbase		= 0xD0000,
.
22c
typedef struct Type Type;
.
20a
static int debug;

.
## diffname pc/devether.c 1992/0411
## diff -e /n/bootesdump/1992/0410/sys/src/9/safari/devether.c /n/bootesdump/1992/0411/sys/src/9/safari/devether.c
686c
consdebug(void)
.
517c
				xmemmove(bp->rptr+len0, d1, len1);
.
515c
			xmemmove(bp->rptr, d0, len0);
.
458,459d
451,454c
	reg = 0x40|inb(cp->iobase);
	outb(cp->iobase, reg);
	reg = 0x40|inb(cp->iobase+0x05);
	outb(cp->iobase+0x05, reg);
.
448c
	uchar reg;
.
246a
	xmemmove(cp->xpkt, p, len);
.
218,219c
	tsleep(&cp->xr, isxfree, cp, 1000);
	if(isxfree(cp) == 0)
		print("Tx wedged\n");
	p = &txpkt;
.
210a
		freeb(bp);
.
145a
static Etherpkt txpkt;

static void
xmemmove(void *to, void *from, long len)
{
	ushort *t, *f;
	int s;
	Ctlr *cp = &ctlr[0];
	uchar reg;

	t = to;
	f = from;
	len = (len+1)/2;
	s = splhi();
	reg = inb(cp->iobase+0x05);
	outb(cp->iobase+Imr, 0);
	outb(cp->iobase+0x05, 0x80|reg);
	while(len--)
		*t++ = *f++;
	outb(cp->iobase+0x05, reg);
	outb(cp->iobase+Imr, 0x1F);
	splx(s);
}

.
29c
	RAMbase		= 0xC8000,
.
## diffname pc/devether.c 1992/0424
## diff -e /n/bootesdump/1992/0411/sys/src/9/safari/devether.c /n/bootesdump/1992/0424/sys/src/9/safari/devether.c
714,729d
710a
static Hw wd8013 = {
	0x360,					/* I/O base address */
	KZERO|0xC8000,				/* shared memory address */
	8*1024,					/* shared memory size */
	wd8013reset,
	wd8013init,
	wd8013mode,
	wd8013online,
	wd8013receive,
	wd8013transmit,
	wd8013intr,
};

.
708c
	Ctlr *cp = &ctlr[0];
	Hw *hw = cp->hw;
	Buffer *tb;
	uchar isr;

	while(isr = IN(hw, r.isr)){
		OUT(hw, w.isr, isr);
		if(isr & 0x08)			/* Txe - transmit error */
			cp->oerrs++;
		if(isr & 0x04){			/* Rxe - receive error */
			cp->frames += IN(hw, r.cntr0);
			cp->crcs += IN(hw, r.cntr1);
			cp->buffs += IN(hw, r.cntr2);
		}
		if(isr & 0x02)			/* Ptx - packet transmitted */
			cp->outpackets++;
		/*
		 * a packet completed transmission, successfully or
		 * not. start transmission on the next buffered packet,
		 * and wake the output routine.
		 */
		if(isr & (0x08|0x02)){
			tb = &cp->tb[cp->ti];
			tb->owner = Host;
			tb->busy = 0;
			cp->ti = NEXT(cp->ti, Ntb);
			(*cp->hw->transmit)(cp);
			wakeup(&cp->tr);
		}
		if(isr & 0x10)			/* Ovw - overwrite warning */
			cp->overflows++;
		/*
		 * we have received packets.
		 */
		if(isr & (0x04|0x01)){		/* Rxe|Prx - packet received */
			(*cp->hw->receive)(cp);
			wakeup(&cp->rr);
		}
	}
.
705,706c
static void
wd8013intr(Ureg *ur)
.
702c
	Hw *hw;
	Buffer *tb;
	int s;

print("transmit\n");
	s = splhi();
	tb = &cp->tb[cp->ti];
	if(tb->busy == 0 && tb->owner == Interface){
		hw = cp->hw;
print("transmit memove %lux %lux, %d\n", hw->ram, &tb->pkt, tb->len);
		memmove(hw->ram, &tb->pkt, tb->len);
		OUT(hw, w.tbcr0, tb->len & 0xFF);
		OUT(hw, w.tbcr1, (tb->len>>8) & 0xFF);
		OUT(hw, w.cr, 0x26);		/* Page0|RD2|TXP|STA */
		tb->busy = 1;
	}
	splx(s);
print("transmit done\n");
.
699,700c
static void
wd8013transmit(Ctlr *cp)
.
695,696c
	Hw *hw = cp->hw;
	Buffer *rb;
	uchar bnry, curr, next;
	typedef struct Ring {
		uchar	status;
		uchar	next;
		uchar	len0;
		uchar	len1;
		uchar	data[256-4];
	} Ring;
	Ring *p;
	int len;

	bnry = IN(hw, r.bnry);
	next = NEXT(bnry, HOWMANY(hw->ramsz, 256));
	if(next == 0)
		next = HOWMANY(sizeof(Etherpkt), 256);
	for(;;){
		OUT(hw, w.cr, 0x62);		/* Page1|RD2|STA */
		curr = IN(hw, curr);
		OUT(hw, w.cr, 0x22);		/* Page0|RD2|STA */
		if(next == curr)
			break;
		cp->inpackets++;
		p = &((Ring*)hw->ram)[next];
		len = (p->len1<<8)|p->len0;

		rb = &cp->rb[cp->ri];
		if(rb->owner == Interface){
			rb->len = len;
			/*copy in packet*/
			rb->owner = Host;
			cp->ri = NEXT(cp->ri, Nrb);
		}

		next = p->next;
		bnry = next-1;
		if(bnry < HOWMANY(sizeof(Etherpkt), 256))
			bnry = HOWMANY(hw->ramsz, 256)-1;
		OUT(hw, w.bnry, bnry);
	}
.
692,693c
static void
wd8013receive(Ctlr *cp)
.
689c
	OUT(cp->hw, w.tcr, 0);
.
686,687c
static void
wd8013online(Ctlr *cp, int on)
.
683c
	qlock(cp);
	if(on){
		cp->prom++;
		if(cp->prom == 1)
			OUT(cp->hw, w.rcr, 0x14);/* PRO|AB */
	}
	else {
		cp->prom--;
		if(cp->prom == 0)
			OUT(cp->hw, w.rcr, 0x04);/* AB */
	}
	qunlock(cp);
.
681c
wd8013mode(Ctlr *cp, int on)
.
677c
	Hw *hw = cp->hw;
	int i;
	uchar bnry;

print("init %d %d\n", HOWMANY(sizeof(Etherpkt), 256), HOWMANY(hw->ramsz, 256));
	OUT(hw, w.cr, 0x21);			/* Page0|RD2|STP */
	OUT(hw, w.dcr, 0x48);			/* FT1|LS */
	OUT(hw, w.rbcr0, 0);
	OUT(hw, w.rbcr1, 0);
	OUT(hw, w.rcr, 0x04);			/* AB */
	OUT(hw, w.tcr, 0x20);			/* LB0 */

	bnry = HOWMANY(sizeof(Etherpkt), 256);
	OUT(hw, w.bnry, bnry);
	OUT(hw, w.pstart, bnry);
	OUT(hw, w.pstop, HOWMANY(hw->ramsz, 256));
	OUT(hw, w.isr, 0xFF);
	OUT(hw, w.imr, 0x1F);			/* OVWE|TXEE|RXEE|PTXE|PRXE */

	OUT(hw, w.cr, 0x61);			/* Page1|RD2|STP */
	for(i = 0; i < sizeof(cp->ea); i++)
		OUT(hw, par[i], cp->ea[i]);
	OUT(hw, curr, bnry+1);

	OUT(hw, w.cr, 0x22);			/* Page0|RD2|STA */
	OUT(hw, w.tpsr, 0);
.
674,675c
/*
 * we leave the chip idling on internal loopback
 * and pointing to Page0.
 */
static void
wd8013init(Ctlr *cp)
.
672a
print("\n");
}
	for(i = 0; i < sizeof(cp->ea); i++)
		cp->ea[i] = IN(hw, lan[i]);
	(*hw->init)(cp);
	setvec(Ethervec, hw->intr);
}
.
671c
int addr = hw->addr;

for(i = 0; i < 16; i++){
    print("#%2.2ux ", inb(addr));
    addr++;
.
668,669c
print("reset\n");
	cp->rb = ialloc(sizeof(Buffer)*Nrb, 0);
	cp->nrb = Nrb;
	cp->tb = ialloc(sizeof(Buffer)*Ntb, 0);
	cp->ntb = Ntb;

	msr = IN(hw, msr);
	OUT(hw, msr, 0x40|msr);
.
665,666c
	Hw *hw = cp->hw;
	int i;
	uchar msr;
.
662,663c
#define IN(hw, m)	inb((hw)->addr+OFFSETOF(Wd8013, m))
#define OUT(hw, m, x)	outb((hw)->addr+OFFSETOF(Wd8013, m), (x))

/*
 */
static void
wd8013reset(Ctlr *cp)
.
656,660c
	union {				/* DP8390/83C690 LAN controller */
		struct {			/* Page0, read */
			uchar	cr;
			uchar	clda0;
			uchar	clda1;
			uchar	bnry;
			uchar	tsr;
			uchar	ncr;
			uchar	fifo;
			uchar	isr;
			uchar	crda0;
			uchar	crda1;
			uchar	pad0x0A;
			uchar	pad0x0B;
			uchar	rsr;
			uchar	cntr0;
			uchar	cntr1;
			uchar	cntr2;
		} r;
		struct {			/* Page0, write */
			uchar	cr;
			uchar	pstart;
			uchar	pstop;
			uchar	bnry;
			uchar	tpsr;
			uchar	tbcr0;
			uchar	tbcr1;
			uchar	isr;
			uchar	rsar0;
			uchar	rsar1;
			uchar	rbcr0;
			uchar	rbcr1;
			uchar	rcr;
			uchar	tcr;
			uchar	dcr;
			uchar	imr;
		} w;
		struct {			/* Page1, read/write */
			uchar	cr;
			uchar	par[6];
			uchar	curr;
			uchar	mar[8];
		};
	};
} Wd8013;
.
650,654c
typedef struct {
	uchar	msr;			/* 83C584 bus interface */
	uchar	icr;
	uchar	iar;
	uchar	bio;
	uchar	irr;
	uchar	laar;
	uchar	ijr;
	uchar	gp2;
	uchar	lan[6];
	uchar	id;
	uchar	cksum;
.
642,646d
637,640c
	
	(*cp->hw->online)(cp, 1);
	if(cp->kproc == 0){
		sprint(cp->name, "ether%dkproc", ctlrno);
		kproc(cp->name, etherkproc, cp);
.
632a
	cp->rh = 0;
	cp->ri = 0;
	for(i = 0; i < cp->nrb; i++)
		cp->rb[i].owner = Interface;

	cp->th = 0;
	cp->ti = 0;
	for(i = 0; i < cp->ntb; i++)
		cp->tb[i].owner = Host;

.
631a
	Ctlr *cp = &ctlr[ctlrno];
	int i;
.
628,629c
Chan*
etherattach(char *spec)
.
619,625c
	cp->net.name = "ether";
	cp->net.nconv = NType;
	cp->net.devp = &info;
	cp->net.protop = 0;
	cp->net.listen = 0;
	cp->net.clone = clonecon;
	cp->net.ninfo = 2;
	cp->net.prot = cp->prot;
	cp->net.info[0].name = "stats";
	cp->net.info[0].fill = statsfill;
	cp->net.info[1].name = "type";
	cp->net.info[1].fill = typefill;
.
617a
	memset(cp->ba, 0xFF, sizeof(cp->ba));
.
616a
	cp->hw = &wd8013;
	(*cp->hw->reset)(cp);
.
615c
void
etherreset(void)
{
	Ctlr *cp = &ctlr[0];
.
610,613c
		qunlock(&cp->rlock);
		sleep(&cp->rr, isinput, cp);
	}
}
.
607,608c
			rb = &cp->rb[cp->rh];
			etherup(cp, &rb->pkt, rb->len);
			rb->owner = Interface;
			cp->rh = NEXT(cp->rh, Nrb);
		}
.
603,605c
		while(cp->rb[cp->rh].owner == Host){
.
596c
			etherup(cp, (Etherpkt*)bp->rptr, BLEN(bp));
.
594c
		while(bp = getq(&cp->lbq)){
.
590c
		qlock(&cp->rlock);

.
584c
		(*cp->hw->init)(cp);
.
578,580d
576a
	Buffer *rb;
.
570c
	return cp->lbq.first || cp->rb[cp->ri].owner == Host;
.
553,564d
540,544c
			bp = allocb(len);
			memmove(bp->rptr, p, len);
			bp->wptr += len;
.
514d
394,509d
392c
etherup(Ctlr *cp, Etherpkt *p, int len)
.
323,329c
	if(tp->prom)
		(*tp->ctlr->hw->mode)(tp->ctlr, 0);
.
285c
	qunlock(&cp->tlock);
print("oput done\n");
.
279,282c
	cp->outpackets++;
	tb->len = len;
	tb->owner = Interface;
	cp->th = NEXT(cp->th, cp->ntb);
	(*cp->hw->transmit)(cp);
.
276a
	 * set up the transmit buffer and 
.
274d
247a
	tb = &cp->tb[cp->th];
	p = &tb->pkt;

.
243,246c
print("oput sleep\n");
	sleep(&cp->tr, isobuf, cp);
.
241c
	 * wait till we get an output buffer.
	 * should try to restart.
.
236c
		qunlock(&cp->tlock);
.
233c
	qlock(&cp->tlock);
.
225c
			putq(&cp->lbq, nbp);
.
215c
			putq(&cp->lbq, bp);
.
203a
	cp = ((Type *)q->ptr)->ctlr;

.
194,198c
			(*tp->ctlr->hw->mode)(tp->ctlr, 1);
.
187d
184a
	Buffer *tb;
.
175c
	cp->tb[cp->th].owner == Host;
.
171c
isobuf(void *arg)
.
169a
long
etherwrite(Chan *c, char *a, long n, ulong offset)
{
	return streamwrite(c, a, n, 0);
}

void
etherremove(Chan *c)
{
	error(Eperm);
}

void
etherwstat(Chan *c, char *dp)
{
	netwstat(c, dp, &ctlr[0].net);
}

.
156,167c
int
etherwalk(Chan *c, char *name)
{
	return netwalk(c, name, &ctlr[0].net);
}

void
etherstat(Chan *c, char *dp)
{
	netstat(c, dp, &ctlr[0].net);
}

Chan*
etheropen(Chan *c, int omode)
{
	return netopen(c, omode, &ctlr[0].net);
}

void
ethercreate(Chan *c, char *name, int omode, ulong perm)
{
	error(Eperm);
}

void
etherclose(Chan *c)
{
	if(c->stream)
		streamclose(c);
}

long
etherread(Chan *c, void *a, long n, ulong offset)
{
	return netread(c, a, n, offset, &ctlr[0].net);
.
151,154c
	return devclone(c, nc);
}
.
148,149c
Chan*
etherclone(Chan *c, Chan *nc)
.
146c
void
etherinit(void)
{
}
.
138,142c
	int	crcs;		/* input crc errors */
	int	oerrs;		/* output errors */
	int	frames;		/* framing errors */
	int	overflows;	/* packet overflows */
	int	buffs;		/* buffering errors */
.
135a
	Queue	lbq;		/* software loopback packet queue */

.
130,132c
	Rendez	tr;		/* rendezvous for a transmit buffer */
	QLock	tlock;		/* semaphore on tc */
	ushort	th;		/* first transmit buffer belonging to host */	
	ushort	ti;		/* first transmit buffer belonging to interface */	

	Type	type[NType];
	uchar	prom;		/* true if promiscuous mode */
	uchar	kproc;		/* true if kproc started */
	char	name[NAMELEN];	/* name of kproc */
.
126,128c
	Rendez	rr;		/* rendezvous for a receive buffer */
	QLock	rlock;		/* semaphore on rc */
	ushort	rh;		/* first receive buffer belonging to host */
	ushort	ri;		/* first receive buffer belonging to interface */	
.
124c
	uchar	ea[6];		/* ethernet address */
	uchar	ba[6];		/* broadcast address */
.
119,122c
	ushort	nrb;		/* number of software receive buffers */
	ushort	ntb;		/* number of software transmit buffers */
	Buffer	*rb;		/* software receive buffers */
	Buffer	*tb;		/* software transmit buffers */
.
113,117c
	Hw	*hw;
.
108c
 * per ethernet
.
87,94d
80,84c
	Host		= 0,		/* buffer owned by host */
	Interface	= 1,		/* buffer owned by interface */
.
76,78d
72,73c
struct Buffer {
	uchar	owner;
	uchar	busy;
	ushort	len;
	Etherpkt pkt;
.
53,70c
#define NEXT(x, l)	(((x)+1)%(l))
#define OFFSETOF(t, m)	((unsigned)&(((t*)0)->m))
#define	HOWMANY(x, y)	(((x)+((y)-1))/(y))
#define ROUNDUP(x, y)	(HOWMANY((x), (y))*(y))
.
50,51c
	Nrb		= 16,		/* software receive buffers */
	Ntb		= 4,		/* software transmit buffers */
};
.
47,48c
	Nctlr		= 1,		/* even one of these is too many */
	NType		= 9,		/* types/interface */
.
40,45d
38a
static Hw wd8013;
.
27,37c
struct Hw {
	int	addr;			/* interface address */
	void	*ram;			/* interface shared memory address */
	int	ramsz;			/* interface shared memory size */
	void	(*reset)(Ctlr*);
	void	(*init)(Ctlr*);
	void	(*mode)(Ctlr*, int);
	void	(*online)(Ctlr*, int);
	void	(*receive)(Ctlr*);
	void	(*transmit)(Ctlr*);
	void	(*intr)(Ureg*);
.
25c
typedef struct Ctlr Ctlr;
.
21,23c
typedef struct Hw Hw;
typedef struct Buffer Buffer;
.
1,11d
## diffname pc/devether.c 1992/0425
## diff -e /n/bootesdump/1992/0424/sys/src/9/safari/devether.c /n/bootesdump/1992/0425/sys/src/9/safari/devether.c
727a
			if(p->data+len0 >= (uchar*)hw->ram+hw->ramsz){
				len1 = p->data+len0 - (uchar*)hw->ram+hw->ramsz;
				len0 = (uchar*)hw->ram+hw->ramsz - p->data;
			}
			memmove((uchar*)&rb->pkt, p->data, len0);
			if(len1)
				memmove((uchar*)&rb->pkt+len0,
					(uchar*)hw->ram+ROUNDUP(sizeof(Etherpkt), 256),
					len1);
.
726c
			rb->len = len0;
.
722c
		len0 = (p->len1<<8)|p->len0-4;
		len1 = 0;
.
708c
	int len0, len1;
.
613d
539d
512,513c
void
etherinit(void)
.
294d
249d
182c
	return cp->tb[cp->th].owner == Host;
.
113a
	return devattach('l', spec);
.
111,112c
Chan*
etherattach(char *spec)
.
## diffname pc/devether.c 1992/0501
## diff -e /n/bootesdump/1992/0425/sys/src/9/safari/devether.c /n/bootesdump/1992/0501/sys/src/9/safari/devether.c
829a
	Ctlr *cp = &ctlr[0];
	Hw *hw = cp->hw;
	Buffer *bp;
	uchar bnry, curr;

	print("th%d ti%d rh%d ri%d\n",
		cp->th, cp->ti, cp->rh, cp->ri);
	bp = &cp->tb[cp->ti];
	print("t: owner %d busy %d len %d\n",
		bp->owner, bp->busy, bp->len);
	bnry = IN(hw, r.bnry);
	OUT(hw, w.cr, 0x62);
	curr = IN(hw, curr);
	OUT(hw, w.cr, 0x22);
	print("bnry %d, curr %d\n", bnry, curr);
	print("in %d out %d crcs %d oerrs %d frames %d overflows %d buffs %d wraps %d\n",
		cp->inpackets, cp->outpackets, cp->crcs, cp->oerrs, cp->frames,
		cp->overflows, cp->buffs, wraps);
.
817c
	8*1024,
	0,
	HOWMANY(sizeof(Etherpkt), 256),
	HOWMANY(8*1024, 256),
.
767d
759,760c
tb->len = tb->len+1 & ~1;
		memmove(hw->ram, tb->pkt, tb->len);
.
754d
741,742c
		if(bnry < hw->pstart)
			bnry = hw->pstop-1;
.
738a
p->status = 0;
.
730,734c
			memmove(rb->pkt, p->data, len);
.
726,728c
			if(p->data+len >= hw->ram+hw->size){
wraps++;
				len = hw->ram+hw->size - p->data;
				memmove(rb->pkt+len,
					&((Ring*)hw->ram)[hw->pstart],
					p->data+rb->len - hw->ram+hw->size);
.
724c
			rb->len = len;
.
719,720c
		len = (p->len1<<8)|p->len0-4;
if(len > sizeof(Etherpkt))
    print("!");
.
708,710c
	next = bnry+1;
	if(next >= hw->pstop)
		next = hw->pstart;
.
705c
	int len;
.
697,703d
690a
static ulong wraps;

.
662c
	OUT(hw, curr, hw->pstart+1);
.
652,655c
	OUT(hw, w.bnry, hw->pstart);
	OUT(hw, w.pstart, hw->pstart);
	OUT(hw, w.pstop, hw->pstop);
.
644d
642d
628a

.
621,626d
618,619d
614a
	cp->rb = ialloc(sizeof(Buffer)*Nrb, 1);
	cp->nrb = Nrb;
.
611,613c
	cp->tb = ialloc(sizeof(Buffer)*Ntb, 1);
.
601a
typedef struct {
	uchar	status;
	uchar	next;
	uchar	len0;
	uchar	len1;
	uchar	data[256-4];
} Ring;

.
531,532c
	 */	
.
477c
			etherup(cp, rb->pkt, rb->len);
.
467c
			etherup(cp, bp->rptr, BLEN(bp));
.
400a
	p = data;
.
399a
	Type *tp;
	Block *bp;
.
397,398c
	Etherpkt *p;
.
395c
etherup(Ctlr *cp, void *data, int len)
.
278,282d
273c
		memset(tb->pkt+len, 0, ETHERMINTU-len);
.
261c
			memmove(tb->pkt+len, nbp->rptr, n);
.
253d
46c
	uchar	pkt[sizeof(Etherpkt)];
.
17,18c
	uchar	*ram;			/* interface shared memory address */
	int	size;
	uchar	tstart;
	uchar	pstart;
	uchar	pstop;
.
## diffname pc/devether.c 1992/0502
## diff -e /n/bootesdump/1992/0501/sys/src/9/safari/devether.c /n/bootesdump/1992/0502/sys/src/9/safari/devether.c
823,840d
788c
			cp->ti = NEXT(cp->ti, cp->ntb);
.
750d
730c
		p->status = 0;
.
727c
			cp->ri = NEXT(cp->ri, cp->nrb);
.
723c
					(p->data+rb->len) - (hw->ram+hw->size));
.
717,719c
			if((p->data+len) >= (hw->ram+hw->size)){
.
711,712d
687,688d
620a
	cp->tb = ialloc(sizeof(Buffer)*Ntb, 1);
	cp->ntb = Ntb;
.
617,618d
478c
			cp->rh = NEXT(cp->rh, cp->nrb);
.
## diffname pc/devether.c 1992/0503
## diff -e /n/bootesdump/1992/0502/sys/src/9/safari/devether.c /n/bootesdump/1992/0503/sys/src/9/safari/devether.c
714c
				len = (hw->ram+hw->size) - p->data;
.
## diffname pc/devether.c 1992/0505
## diff -e /n/bootesdump/1992/0503/sys/src/9/safari/devether.c /n/bootesdump/1992/0505/sys/src/9/safari/devether.c
708c
		len = ((p->len1<<8)|p->len0)-4;
		if(p->next < hw->pstart || p->next >= hw->pstop || len < 60){
			print("%d: #%2.2ux #%2.2ux  #%2.2ux #%2.2ux\n", next,
				p->status, p->next, p->len0, p->len1);
			dp8390rinit(cp);
			return;
		}
.
631a
static void
dp8390rinit(Ctlr *cp)
{
	Hw *hw = cp->hw;

	OUT(hw, w.cr, 0x21);			/* Page0|RD2|STP */
	OUT(hw, w.bnry, hw->pstart);
	OUT(hw, w.cr, 0x61);			/* Page1|RD2|STP */
	OUT(hw, curr, hw->pstart+1);
	OUT(hw, w.cr, 0x22);			/* Page0|RD2|STA */
}

.
480,482d
459c
		sleep(&cp->rr, isinput, cp);
.
335a
	tp->ctlr = 0;
.
91c
	QLock	tlock;		/* semaphore on th */
.
86d
## diffname pc/devether.c 1992/0506
## diff -e /n/bootesdump/1992/0505/sys/src/9/safari/devether.c /n/bootesdump/1992/0506/sys/src/9/safari/devether.c
720a
			panic("receive");
.
719c
			print("%d/%d : #%2.2ux #%2.2ux  #%2.2ux #%2.2ux\n", next, len,
.
## diffname pc/devether.c 1992/0625
## diff -e /n/bootesdump/1992/0506/sys/src/9/safari/devether.c /n/bootesdump/1992/0625/sys/src/9/safari/devether.c
616c
	cp->tb = xspanalloc(sizeof(Buffer)*Ntb, BY2PG, 0);
.
614c
	cp->rb = xspanalloc(sizeof(Buffer)*Nrb, BY2PG, 0);
.
504a
	for(i = 0; i < NType; i++)
		netadd(&cp->net, &cp->type[i], i);
.
500d
487a
	cp = &ctlr[0];
.
486c
	int i;
	Ctlr *cp;
.
360c
		netown(tp, u->p->user, 0);
.
334c
	netdisown(tp);
.
99d
61a
	Netprot;			/* stat info */
.
## diffname pc/devether.c 1992/0711
## diff -e /n/bootesdump/1992/0625/sys/src/9/safari/devether.c /n/bootesdump/1992/0711/sys/src/9/safari/devether.c
779a
	USED(ur);
.
695a
	USED(on);
.
372a
	USED(c);
.
364a
	return 0;
.
352a
	USED(c);
.
170a
	USED(c);
.
164a
	USED(offset);
.
145a
	USED(c, name, omode, perm);
.
## diffname pc/devether.c 1992/0905
## diff -e /n/bootesdump/1992/0808/sys/src/9/safari/devether.c /n/bootesdump/1992/0905/sys/src/9/pc/devether.c
839,843d
826c
	KZERO|0xF0000,				/* shared memory address */
.
770c
		bmemmove(hw->ram, tb->pkt, tb->len);
.
756a
print(">");
.
751a
OUT(hw, laar, 0x01);
print("?");
.
745c
			bmemmove(rb->pkt, p->data, len);
.
741c
				bmemmove(rb->pkt+len,
.
733c
			break;
.
731c
OUT(hw, laar, 0x01);
.
726a
{ int ii; for(ii = 0; ii < 30; ii++) print("%2.2ux ", p->data[ii]); for(;;); }
.
725a
print("*");
OUT(hw, laar, 0xC1);
print("!");
.
706a
bmemmove(void *a, void *b, int n)
{
	uchar *to, *from;

	to = a;
	from = b;
	while(n-- > 0)
		*to++ = *from++;
}

static void
.
633a
	/* get configuration info from card */
	ram = (IN(hw, msr) & 0x3f) << 13;
	ram |= KZERO|0x80000;
	hw->ram = (uchar*)ram;
print("ether ram is at %lux\n", ram);

.
629c
	OUT(hw, msr, MENB|msr);
.
621a
	ulong ram;
.
613a

static void
wd8013dumpregs(Hw *hw)
{
	print("msr=#%2.2ux\n", IN(hw, msr));
	print("icr=#%2.2ux\n", IN(hw, icr));
	print("iar=#%2.2ux\n", IN(hw, iar));
	print("bio=#%2.2ux\n", IN(hw, bio));
	print("irr=#%2.2ux\n", IN(hw, irr));
	print("laar=#%2.2ux\n", IN(hw, laar));
	print("ijr=#%2.2ux\n", IN(hw, ijr));
	print("gp2=#%2.2ux\n", IN(hw, gp2));
	print("lan0=#%2.2ux\n", IN(hw, lan[0]));
	print("lan1=#%2.2ux\n", IN(hw, lan[1]));
	print("lan2=#%2.2ux\n", IN(hw, lan[2]));
	print("lan3=#%2.2ux\n", IN(hw, lan[3]));
	print("lan4=#%2.2ux\n", IN(hw, lan[4]));
	print("lan5=#%2.2ux\n", IN(hw, lan[5]));
	print("id=#%2.2ux\n", IN(hw, id));
}

.
602a
enum {
	MENB		= 0x40,			/* memory enable */

	L16EN		= 0x40,			/* enable 16-bit LAN operation */
	M16EN		= 0x80,			/* enable 16-bit memory access */
};

.
## diffname pc/devether.c 1992/0906
## diff -e /n/bootesdump/1992/0905/sys/src/9/pc/devether.c /n/bootesdump/1992/0906/sys/src/9/pc/devether.c
883c
	0,
.
881a
	0,
	0,
	0,
	0,
.
879,880d
822,823c
		memmove(hw->ram, tb->pkt, tb->len);
.
819a
	hw = cp->hw;
.
809d
802,803d
795c
			memmove(rb->pkt, p->data, len);
.
791c
				memmove(rb->pkt+len,
.
781d
776d
772,774d
742,752d
696c
	if(hw->bt16)
		OUT(hw, w.dcr, 0x49);		/* 16 bit interface, DMA burst size 8 */
	else
		OUT(hw, w.dcr, 0x48);		/* FT1|LS */
.
670c
	setvec(Int0vec + hw->lvl, hw->intr);
.
668a
	/* interrupt level */
	hw->lvl = intrmap[((irr>>5) & 0x3) | (icr & 0x4)];

	/* ram size */
	if(icr&(1<<3))
		hw->size = 32*1024;
	else
		hw->size = 8*1024;
	if(hw->bt16)
		hw->size <<= 1;
	hw->pstop = HOWMANY(hw->size, 256);

print("ether width %d addr %lux size %d lvl %d\n", hw->bt16?16:8,
	hw->ram, hw->size, hw->lvl);

	/* enable interface RAM, set interface width */
	OUT(hw, msr, MENB|msr);
	if(hw->bt16)
		OUT(hw, laar, laar|L16EN|M16EN);

.
667d
663,665c
	/* 16 bit operation? */
	hw->bt16 = icr & 0x1;

	/* address of interface RAM */
	ram = KZERO | ((msr & 0x3f) << 13);
	if(hw->bt16)
		ram |= (laar & 0x3f)<<19;
	else
		ram |= 0x80000;
.
659a
	/* ethernet address */
.
658c
	icr = IN(hw, icr);
	irr = IN(hw, irr);
	laar = IN(hw, laar);
.
649a
	uchar icr;
	uchar laar;
	uchar irr;
.
642a
 *  get configuration parameters, enable memory
.
641a
/* mapping from configuration bits to interrupt level */
int intrmap[] =
{
	9, 3, 5, 7, 10, 11, 15, 4,
};

.
17a
	int	bt16;			/* true if a 16 bit interface */
	int	lvl;			/* interrupt level */
.
## diffname pc/devether.c 1992/0909
## diff -e /n/bootesdump/1992/0906/sys/src/9/pc/devether.c /n/bootesdump/1992/0909/sys/src/9/pc/devether.c
916a
	wd8013tweek,
	0x360,					/* I/O base address */
.
911c
	dp8390init,
.
901,909c
static Hw wd8013 =
{
.
898a
	if(hw->bt16){
		OUT(hw, laar, laar);
		OUT(hw, w.imr, 0x1F);
	}
.
863a
	if(hw->bt16){
		laar = IN(hw, laar);
		OUT(hw, w.imr, 0x0);
		OUT(hw, laar, laar|M16EN);
	}
.
862c
	uchar isr, laar;
.
851a
		if(hw->bt16 && (laar&M16EN)==0){
			OUT(hw, laar, laar);
			OUT(hw, w.imr, 0x1F);
		}
.
846a
		if(hw->bt16){
			OUT(hw, w.imr, 0x0);
			laar = IN(hw, laar);
			OUT(hw, laar, laar|M16EN);
		}
.
841a
	uchar laar;
.
808c
				p->status, p->next, p->len0, p->len1);/**/
.
730c
dp8390init(Ctlr *cp)
.
713a
wd8013tweek(Ctlr *cp)
{
	uchar laar, msr;
	Hw *hw = cp->hw;
	Buffer *tb;
	int s;

	s = splhi();
	msr = IN(hw, msr);
	if(msr & MENB){
		splx(s);
		return;
	}
	print("TWEEK\n");
	delay(500);

	/* reset the hardware */
	OUT(hw, msr, MENB|msr);
	laar = IN(hw, laar);
	if(hw->bt16)
		OUT(hw, laar, laar|L16EN);
	(*hw->init)(cp);
	(*cp->hw->online)(cp, 1);

	/* retransmit the current packet */
	tb = &cp->tb[cp->ti];
	if(tb->owner == Interface){
		tb->busy = 0;
		(*cp->hw->transmit)(cp);
	}
	splx(s);
}

static void
.
707c
		OUT(hw, laar, laar|L16EN);
.
698a
	hw->pstart = HOWMANY(sizeof(Etherpkt), 256);
.
623d
467c
		tsleep(&cp->rr, isinput, cp, 1000);
		(*cp->hw->tweek)(cp);
.
24,30d
15a
	void	(*reset)(Ctlr*);
	void	(*init)(Ctlr*);
	void	(*mode)(Ctlr*, int);
	void	(*online)(Ctlr*, int);
	void	(*receive)(Ctlr*);
	void	(*transmit)(Ctlr*);
	void	(*intr)(Ureg*);
	void	(*tweek)(Ctlr*);
.
## diffname pc/devether.c 1992/0913
## diff -e /n/bootesdump/1992/0909/sys/src/9/pc/devether.c /n/bootesdump/1992/0913/sys/src/9/pc/devether.c
965d
716,749d
468,469c
		sleep(&cp->rr, isinput, cp);
.
23d
## diffname pc/devether.c 1992/0915
## diff -e /n/bootesdump/1992/0913/sys/src/9/pc/devether.c /n/bootesdump/1992/0915/sys/src/9/pc/devether.c
928a
	wd8013tweek,
.
914,917d
874,878d
872c
	uchar isr;
.
858,861d
848,852d
842d
832a
		break;
.
808a
			delay(100);
.
807c
/*			print("%d/%d : #%2.2ux #%2.2ux  #%2.2ux #%2.2ux\n", next, len,
.
784a
wd8013tweek(Ctlr *cp)
{
	uchar msr;
	Hw *hw = cp->hw;
	int s;

	s = splhi();
	msr = IN(hw, msr);
	if((msr & MENB) == 0){
		/* board has reset itself, start again */
		delay(100);

		(*hw->reset)(cp);
		etherinit();

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

static void
.
742c
	if(cp->prom)
		OUT(hw, w.rcr, 0x14);		/* PRO|AB */
	else
		OUT(hw, w.rcr, 0x04);		/* AB */
.
737c
		OUT(hw, w.dcr, 0x61);		/* 16 bit interface */
.
707c
		OUT(hw, laar, laar|L16EN|M16EN);
.
701,702c
/* print("ether width %d addr %lux size %d lvl %d\n", hw->bt16?16:8,
	hw->ram, hw->size, hw->lvl);/**/
.
663,666c
	if(cp->rb == 0){
		cp->rb = xspanalloc(sizeof(Buffer)*Nrb, BY2PG, 0);
		cp->nrb = Nrb;
		cp->tb = xspanalloc(sizeof(Buffer)*Ntb, BY2PG, 0);
		cp->ntb = Ntb;
	}
.
467c
		tsleep(&cp->rr, isinput, cp, 500);
		(*cp->hw->tweek)(cp);
.
22a
	void	(*tweek)(Ctlr*);
.
## diffname pc/devether.c 1992/0916
## diff -e /n/bootesdump/1992/0915/sys/src/9/pc/devether.c /n/bootesdump/1992/0916/sys/src/9/pc/devether.c
741c
		OUT(hw, w.dcr, 0x01);		/* 16 bit interface */
.
## diffname pc/devether.c 1992/0917
## diff -e /n/bootesdump/1992/0916/sys/src/9/pc/devether.c /n/bootesdump/1992/0917/sys/src/9/pc/devether.c
919,927d
897a
		/*
		 * we have received packets.
		 */
		if(isr & (0x04|0x01)){		/* Rxe|Prx - packet received */
			(*cp->hw->receive)(cp);
			wakeup(&cp->rr);
		}
		if(isr & 0x10)			/* Ovw - overwrite warning */
			cp->overflows++;
.
881c
		OUT(hw, w.cr, Page0|RD2|TXP|STA);
.
863d
856d
842d
838d
836c
			/*print("%d/%d : #%2.2ux #%2.2ux  #%2.2ux #%2.2ux\n", next, len,
.
831a
		waitfordma(hw);
.
829c
		OUT(hw, w.cr, Page0|RD2|STA);
.
826,827c
	for(i = 0; ; i++){
		OUT(hw, w.cr, Page1|RD2|STA);
.
820c
	int i, len;
.
812a
/*
 *  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 DMA registers and, if they are changing, wait.
 */
void
waitfordma(Hw *hw)
{
	uchar a,b,c;

	for(;;delay(10)){
		a = IN(hw, r.clda0);
		b = IN(hw, r.clda0);
		if(a != b)
			continue;
		c = IN(hw, r.clda0);
		if(c != b)
			continue;
		break;
	}
}

.
763c
	OUT(hw, w.cr, Page0|RD2|STA);
.
758c
	OUT(hw, w.cr, Page1|RD2|STP);
.
741c
		OUT(hw, w.dcr, (1<<0)|(3<<5));	/* 16 bit interface, 12 byte DMA burst */
.
739c
	OUT(hw, w.cr, Page0|RD2|STP);
.
726c
	OUT(hw, w.cr, Page0|RD2|STA);
.
724c
	OUT(hw, w.cr, Page1|RD2|STP);
.
722c
	OUT(hw, w.cr, Page0|RD2|STP);
.
714a
	return 0;
.
711c
		OUT(hw, laar, laar|L16EN|M16EN|ZeroWS16);
.
672,676d
664a
	msr = IN(hw, msr);
	icr = IN(hw, icr);
	irr = IN(hw, irr);
	laar = IN(hw, laar);

	if(msr == 0xff || icr == 0xff || irr == 0xff || laar == 0xff)
		return -1;

.
654c
static int
.
650a

.
610,611c
	/* bit definitions for laar */
	ZeroWS16	= (1<<5),		/* zero wait states for 16-bit ops */
	L16EN		= (1<<6),		/* enable 16-bit LAN operation */
	M16EN		= (1<<7),		/* enable 16-bit memory access */

	/* bit defintitions for DP8390/83C690 cr */
	Page0		= (0<<6),
	Page1		= (1<<6),
	Page2		= (2<<6),
	RD2		= (4<<3),
	TXP		= (1<<2),
	STA		= (1<<1),
	STP		= (1<<0),
.
603a
		struct {			/* Page2, read */
			uchar	cr;
			uchar	pstart;
			uchar	pstop;
			uchar	dummy1[1];
			uchar	tstart;
			uchar	next;
			uchar	block;
			uchar	enh;
			uchar	dummy2[4];
			uchar	rcon;
			uchar	tcon;
			uchar	dcon;
			uchar	intmask;
		} r2;
		struct {			/* Page2, write */
			uchar	cr;
			uchar	trincrl;
			uchar	trincrh;
			uchar	dummy1[2];
			uchar	next;
			uchar	block;
			uchar	enh;
		} w2;
.
526a
	if(cp->present == 0)
		return;

.
501c
	if((*cp->hw->reset)(cp) < 0){
		cp->present = 0;
		return;
	}
	cp->present = 1;
.
118a
	if(ctlr[0].present == 0)
		error(Enodev);
.
79a
	int	present;
.
16c
	int	(*reset)(Ctlr*);
.
## diffname pc/devether.c 1992/0918
## diff -e /n/bootesdump/1992/0917/sys/src/9/pc/devether.c /n/bootesdump/1992/0918/sys/src/9/pc/devether.c
1012d
905c
		if(strcmp(machtype, "NCRD.0") == 0)
			waitfordma(hw);
.
754c
print("elite at %lux width %d addr %lux size %d lvl %d\n", hw->addr, hw->bt16?16:8,
.
726,729d
716c
		/* ethernet address */
		for(i = 0; i < sizeof(cp->ea); i++)
			cp->ea[i] = IN(hw, lan[i]);

		/* look for an elite ether address */
		if(cp->ea[0] == 0x00 && cp->ea[1] == 0x00 && cp->ea[2] == 0xC0)
			break;
	}
	if(hw->addr >= 0x400)
.
711,714c
	/* find the ineterface */
	SET(msr, icr, irr, laar);
	for(hw->addr = 0x200; hw->addr < 0x400; hw->addr += 0x20){
		msr = IN(hw, msr);
		icr = IN(hw, icr);
		irr = IN(hw, irr);
		laar = IN(hw, laar);
		if((msr&0x80) || (icr&0xf0) || irr == 0xff || laar == 0xff)
			continue;	/* nothing there */
.
705,708c
	uchar msr, icr, laar, irr;
.
696d
## diffname pc/devether.c 1992/0922
## diff -e /n/bootesdump/1992/0918/sys/src/9/pc/devether.c /n/bootesdump/1992/0922/sys/src/9/pc/devether.c
557,1018d
531c
	EtherCtlr *cp = &ctlr[ctlrno];
.
508c
	if(cp->present == 0)
		return;
.
503,506c
	for(hw = etherhw; *hw; hw++){
		cp->hw = *hw;
		if((*cp->hw->reset)(cp) == 0){
			cp->present = 1;
			setvec(Int0vec + cp->hw->irq, etherintr);
			break;
		}
.
500d
498a
	EtherCtlr *cp;
	EtherHw **hw;
.
495a
static void
etherintr(Ureg *ur)
{
	EtherCtlr *cp = &ctlr[0];

	USED(ur);
	(*cp->hw->intr)(cp);
}

.
472c
		if(cp->hw->tweak)
			(*cp->hw->tweak)(cp);
.
465c
		if(cp->hw->init)
			(*cp->hw->init)(cp);
.
459,460c
	EtherCtlr *cp = arg;
	EtherBuf *rb;
.
451c
	EtherCtlr *cp = arg;
.
408c
	EtherType *tp;
.
404c
etherup(EtherCtlr *cp, void *data, int len)
.
396c
	EtherType *tp;
.
381c
	EtherCtlr *cp = &ctlr[0];
.
359,360c
	EtherCtlr *cp = &ctlr[0];
	EtherType *tp;
.
335c
	tp = (EtherType*)(q->ptr);
.
333c
	EtherType *tp;
.
311,312c
	EtherCtlr *cp = &ctlr[0];
	EtherType *tp;
.
227c
	p = (Etherpkt*)bp->rptr;
.
219c
	cp = ((EtherType*)q->ptr)->ctlr;
.
210c
			tp->type = strtol((char*)bp->rptr, 0, 0);
.
204c
	EtherBuf *tb;
	int len, n;
.
200,202c
	EtherCtlr *cp;
	EtherType *tp;
.
192c
	EtherCtlr *cp = arg;
.
48,116d
42a
static struct EtherCtlr ctlr[Nctlr];

.
36,40c
	Nctlr		= 1,
.
33d
15,31c
static EtherHw *etherhw[] = {
	&ether509,
	&ether80x3,
	0
.
10,13c
/*
 * Half-arsed attempt at a general top-level
 * ethernet driver. Needs work:
 *	handle multiple controllers
 *	much tidying
 *	set ethernet address
 */
extern EtherHw ether509;
extern EtherHw ether80x3;
.
## diffname pc/devether.c 1992/0925
## diff -e /n/bootesdump/1992/0922/sys/src/9/pc/devether.c /n/bootesdump/1992/0925/sys/src/9/pc/devether.c
373c
	return cp->lbq.first || cp->rb[cp->rh].owner == Host;
.
## diffname pc/devether.c 1992/1015
## diff -e /n/bootesdump/1992/0925/sys/src/9/pc/devether.c /n/bootesdump/1992/1015/sys/src/9/pc/devether.c
363d
361a
			poperror();
.
356c
		if(!waserror()){
.
## diffname pc/devether.c 1992/1222
## diff -e /n/bootesdump/1992/1015/sys/src/9/pc/devether.c /n/bootesdump/1992/1222/sys/src/9/pc/devether.c
491a
	return devattach('l', spec);
.
487,490c
	(*ctlr->board->attach)(ctlr);
	if(ctlr->kproc == 0){
		sprint(ctlr->name, "ether%dkproc", ctlrno);
		ctlr->kproc = 1;
		kproc(ctlr->name, etherkproc, ctlr);
.
484,485c
	 * Enable the interface
	 * and start the kproc.
.
482a
Chan*
etherattach(char *spec)
{
	int ctlrno = 0;
	Ctlr *ctlr = softctlr[ctlrno];

	if(ctlr->present == 0)
		error(Enodev);

.
478,481c
	ctlr->th = 0;
	ctlr->ti = 0;
	for(i = 0; i < ctlr->ntb; i++)
		ctlr->tb[i].owner = Host;
}
.
473,476c
	ctlr->rh = 0;
	ctlr->ri = 0;
	for(i = 0; i < ctlr->nrb; i++)
		ctlr->rb[i].owner = Interface;
.
470c
	if(ctlr->present == 0)
.
467c
	Ctlr *ctlr = softctlr[ctlrno];
.
460c
		netadd(&ctlr->net, &ctlr->type[i], i);
.
448,458c
	memset(ctlr->ba, 0xFF, sizeof(ctlr->ba));

	ctlr->net.name = "ether";
	ctlr->net.nconv = NType;
	ctlr->net.devp = &info;
	ctlr->net.protop = 0;
	ctlr->net.listen = 0;
	ctlr->net.clone = clonecon;
	ctlr->net.ninfo = 2;
	ctlr->net.info[0].name = "stats";
	ctlr->net.info[0].fill = statsfill;
	ctlr->net.info[1].name = "type";
	ctlr->net.info[1].fill = typefill;
.
446c
	if(ctlr->nrb == 0)
		ctlr->nrb = Nrb;
	ctlr->rb = xalloc(sizeof(RingBuf)*ctlr->nrb);
	if(ctlr->ntb == 0)
		ctlr->ntb = Ntb;
	ctlr->tb = xalloc(sizeof(RingBuf)*ctlr->ntb);
.
444a
	nctlr++;
.
443c
	if(ctlr->present == 0)
.
434,439c
	if(softctlr[nctlr] == 0)
		softctlr[nctlr] = xalloc(sizeof(Ctlr));
	ctlr = softctlr[nctlr];
	for(board = boards; *board; board++){
		ctlr->board = *board;
		if((*ctlr->board->reset)(ctlr) == 0){
			ctlr->present = 1;

			/*
			 * IRQ2 doesn't really exist, it's used to gang the interrupt
			 * controllers together. A device set to IRQ2 will appear on
			 * the second interrupt controller as IRQ9.
			 */
			if(ctlr->board->irq == 2)
				ctlr->board->irq = 9;
			setvec(Int0vec + ctlr->board->irq, etherintr);
.
430,431c
	Ctlr *ctlr;
	Board **board;
.
424c
	(*ctlr->board->intr)(ctlr);
.
421c
	Ctlr *ctlr = softctlr[0];
.
414a

		/*
		 * Close Types requesting it.
		 */
		if(ctlr->clist){
			lock(&ctlr->clock);
			for(type = ctlr->clist; type; type = type->clist){
				type->q = 0;
				wakeup(&type->cr);
			}
			ctlr->clist = 0;
			unlock(&ctlr->clock);
		}
.
408,413c
		while(ctlr->rb[ctlr->rh].owner == Host){
			ctlr->inpackets++;
			ring = &ctlr->rb[ctlr->rh];
			etherup(ctlr, (Etherpkt*)ring->pkt, ring->len);
			ring->owner = Interface;
			ctlr->rh = NEXT(ctlr->rh, ctlr->nrb);
.
406c
		 * Process any received packets.
.
399,401c
		while(bp = getq(&ctlr->lbq)){
			ctlr->inpackets++;
			etherup(ctlr, (Etherpkt*)bp->rptr, BLEN(bp));
.
397c
		 * Process any internal loopback packets.
.
392,394c
		tsleep(&ctlr->rr, isinput, ctlr, 500);
		if(ctlr->board->watch)
			(*ctlr->board->watch)(ctlr);
.
390c

.
384,387c
		print("%s noted\n", ctlr->name);
		/* fix
		if(ctlr->board->reset)
			(*ctlr->board->reset)(ctlr);
		 */
		ctlr->kproc = 0;
.
381a
	Type *type;
.
379,380c
	Ctlr *ctlr = arg;
	RingBuf *ring;
.
373c
	return ctlr->lbq.first || ctlr->rb[ctlr->rh].owner == Host || ctlr->clist;
.
371c
	Ctlr *ctlr = arg;
.
364d
361c
			PUTNEXT(type->q, bp);
.
358c
			memmove(bp->rptr, pkt, len);
.
352,356c

		if(waserror() == 0){
.
350c
		if(type->type != -1 && pkt->d[0] != 0xFF
		  && (*pkt->d != *ctlr->ea || memcmp(pkt->d, ctlr->ea, sizeof(pkt->d))))
.
347,348c
		 * Only a trace channel gets packets destined for other machines.
.
344a
		if(t != type->type && type->type != -1)
			continue;
		if(type->q->next->len > Streamhi)
			continue;
.
343c
		if(type->q == 0)
.
341c
		 * Check for open, the right type, and flow control.
.
331,338c
	t = (pkt->type[0]<<8)|pkt->type[1];
	for(type = &ctlr->type[0]; type < &ctlr->type[NType]; type++){
.
328c
	Type *type;
.
326d
324c
etherup(Ctlr *ctlr, Etherpkt *pkt, int len)
.
318,319c
	type = &softctlr[0]->type[STREAMID(c->qid.path)];
	sprint(buf, "%d", type->type);
.
316c
	Type *type;
.
306,308c
		ctlr->inpackets, ctlr->outpackets, ctlr->crcs,
		ctlr->overflows, ctlr->frames, ctlr->buffs, ctlr->oerrs,
		ctlr->ea[0], ctlr->ea[1], ctlr->ea[2],
		ctlr->ea[3], ctlr->ea[4], ctlr->ea[5]);
.
301c
	Ctlr *ctlr = softctlr[0];
.
289,292c
		type->inuse = 1;
		netown(type, u->p->user, 0);
		qunlock(type);
		return type - ctlr->type;
.
283,286c
	for(type = ctlr->type; type < &ctlr->type[NType]; type++){
		qlock(type);
		if(type->inuse || type->q){
			qunlock(type);
.
279,280c
	Ctlr *ctlr = softctlr[0];
	Type *type;
.
255,265c
	if(type->prom){
		qlock(ctlr);
		ctlr->prom--;
		if(ctlr->prom == 0)
			(*ctlr->board->mode)(ctlr, 0);
		qunlock(ctlr);
	}
	if(type->type == -1){
		qlock(ctlr);
		ctlr->all--;
		qunlock(ctlr);
	}

	/*
	 * Mark as closing and wait for kproc
	 * to close us.
	 */
	lock(&ctlr->clock);
	type->clist = ctlr->clist;
	ctlr->clist = type;
	unlock(&ctlr->clock);
	wakeup(&ctlr->rr);
	sleep(&type->cr, isclosed, type);

	type->type = 0;
	type->prom = 0;
	type->inuse = 0;
	netdisown(type);
	type->ctlr = 0;
.
253c
	Type *type = (Type*)(q->ptr);
	Ctlr *ctlr = type->ctlr;
.
249a
static int
isclosed(void *arg)
{
	return ((Type*)arg)->q == 0;
}

.
247,248c
 * The locking is to synchronize changing the ethertype with
 * sending packets up the stream on interrupts.
.
245c
 * Close ether line discipline.
.
234,241c
	type = &ctlr->type[s->id];
	RD(q)->ptr = WR(q)->ptr = type;
	type->type = 0;
	type->q = RD(q);
	type->inuse = 1;
	type->ctlr = ctlr;
.
231,232c
	Ctlr *ctlr = softctlr[0];
	Type *type;
.
223,226c
 * Open an ether line discipline.
.
218c
	qunlock(&ctlr->tlock);
.
211,215c
	ctlr->outpackets++;
	ring->len = len;
	ring->owner = Interface;
	ctlr->th = NEXT(ctlr->th, ctlr->ntb);
	(*ctlr->board->transmit)(ctlr);
.
208,209c
	 * Set up the transmit buffer and 
	 * start the transmission.
.
203c
		memset(ring->pkt+len, 0, ETHERMINTU-len);
.
200c
	 * Pad the packet (zero the pad).
.
193,194c
		}
.
191c
			memmove(ring->pkt+len, nbp->rptr, n);
.
186c
	 * Copy message into buffer.
.
183c
	ring = &ctlr->tb[ctlr->th];
.
181c
	sleep(&ctlr->tr, isobuf, ctlr);
.
178c
	 * Wait till we get an output buffer.
.
173c
		qunlock(&ctlr->tlock);
.
170c
	qlock(&ctlr->tlock);
.
168c
	 * Only one transmitter at a time.
.
162,163c
			putq(&ctlr->lbq, nbp);
			wakeup(&ctlr->rr);
.
157c
	if(memcmp(ctlr->ba, pkt->d, sizeof(ctlr->ba)) == 0 || ctlr->prom || ctlr->all){
.
151,153c
		if(bp = expandb(bp, len >= ETHERMINTU ? len: ETHERMINTU)){
			putq(&ctlr->lbq, bp);
			wakeup(&ctlr->rr);
.
147,149c
	pkt = (Etherpkt*)bp->rptr;
	memmove(pkt->s, ctlr->ea, sizeof(ctlr->ea));
	if(memcmp(ctlr->ea, pkt->d, sizeof(ctlr->ea)) == 0){
.
142c
	 * Give packet a local address, return upstream if destined for
.
139,140d
134a
		qunlock(ctlr);
.
132,133c
			type->prom = 1;
			ctlr->prom++;
			if(ctlr->prom == 1)
				(*ctlr->board->mode)(ctlr, 1);
.
128,130c
		qlock(ctlr);
		if(streamparse("connect", bp)){
			if(type->type == -1)
				ctlr->all--;
			type->type = strtol((char*)bp->rptr, 0, 0);
			if(type->type == -1)
				ctlr->all++;
		}
.
126a
	type = q->ptr;
	ctlr = type->ctlr;
.
120,123c
	Ctlr *ctlr;
	Type *type;
	Etherpkt *pkt;
	RingBuf *ring;
.
114c
	return ctlr->tb[ctlr->th].owner == Host;
.
112c
	Ctlr *ctlr = arg;
.
106c
	netwstat(c, dp, &softctlr[0]->net);
.
86c
	return netread(c, a, n, offset, &softctlr[0]->net);
.
66c
	return netopen(c, omode, &softctlr[0]->net);
.
60c
	netstat(c, dp, &softctlr[0]->net);
.
54c
	return netwalk(c, name, &softctlr[0]->net);
.
38,45d
32,36d
30c
static struct Ctlr *softctlr[NCtlr];
static int nctlr;
.
27c
	NCtlr		= 1,
.
22d
20c
/*
 * The ordering here is important for those boards
 * using the DP8390 (WD8003, 3COM503 and NE2000) as
 * attempting to determine if a board is a NE2000
 * cannot be done passively, so it must be last to
 * prevent scrogging one of the others.
 */
static Board *boards[] = {
	&ether8003,
	&ether503,
	&ether2000,

.
17,18c
extern Board ether8003;
extern Board ether503;
extern Board ether2000;
extern Board ether509;
.
9a
#include "ether.h"

.
## diffname pc/devether.c 1993/0212
## diff -e /n/bootesdump/1992/1222/sys/src/9/pc/devether.c /n/bootesdump/1993/0212/sys/src/9/pc/devether.c
554c
	(*ctlr->card.attach)(ctlr);
.
493a

	print("ether%d: %s: I/O addr %lux width %d addr %lux size %d irq %d:",
		nctlr, ctlr->card.id,
		ctlr->card.io, ctlr->card.bit16 ? 16: 8, ctlr->card.ramstart,
		ctlr->card.ramstop-ctlr->card.ramstart, ctlr->card.irq);
	for(i = 0; i < sizeof(ctlr->ea); i++)
		print(" %2.2ux", ctlr->ea[i]);
	print("\n");

.
486,488c
			if(ctlr->card.irq == 2)
				ctlr->card.irq = 9;
			setvec(Int0vec + ctlr->card.irq, etherintr);
.
476,478c
	for(card = cards; *card; card++){
		memset(ctlr, 0, sizeof(Ctlr));
		ctlr->card = **card;
		if((*ctlr->card.reset)(ctlr) == 0){
.
472a
	if(nctlr >= NCtlr)
		return;
.
470c
	Card **card;
.
463c
	(*ctlr->card.intr)(ctlr);
.
419,420c
		if(ctlr->card.watch)
			(*ctlr->card.watch)(ctlr);
.
410,411c
		if(ctlr->card.reset)
			(*ctlr->card.reset)(ctlr);
.
270c
			(*ctlr->card.mode)(ctlr, 0);
.
227a
	freeb(bp);
.
226d
224c
	(*ctlr->card.transmit)(ctlr);
	splx(s);
.
220c
	s = splhi();
.
191c
	if(isobuf(ctlr) == 0){
		tsleep(&ctlr->tr, isobuf, ctlr, 3*1000);
		if(isobuf(ctlr) == 0){
			qunlock(&ctlr->tlock);
			freeb(bp);
			poperror();
			return;
		}
	}
.
183a
		freeb(bp);
.
182d
144c
				(*ctlr->card.mode)(ctlr, 1);
.
126c
	int len, n, s;
.
44c
/*static */struct Ctlr *softctlr[NCtlr];
.
31c
static Card *cards[] = {
.
25,27c
 * The ordering here is important for those cards
 * using the DP8390 (WD8003, 3Com503 and NE2000) as
 * attempting to determine if a card is a NE2000
.
19,22c
extern Card ether8003, ether503, ether2000;
extern Card ether509;
.
17a
 *	need a ctl file passed down to card drivers
 *	  so we can set options.
.
## diffname pc/devether.c 1993/1113
## diff -e /n/bootesdump/1993/0212/sys/src/9/pc/devether.c /n/fornaxdump/1993/1113/sys/src/brazil/pc/devether.c
581c
	if(ctlr)
		free(ctlr);
.
517,579c
			ether[ctlrno] = ctlr;
			ctlr = 0;
		}
.
515c
			netifinit(ctlr, "ether", Ntypes, 32*1024);
			ctlr->alen = Eaddrlen;
			memmove(ctlr->addr, ctlr->ea, sizeof(ctlr->ea));
			memmove(ctlr->bcast, etherbcast, sizeof(etherbcast));
.
507,513c
			print("ether%d: %s: port %lux irq %d addr %lux size %d:",
				ctlrno, ctlr->type, ctlr->port, ctlr->irq, ctlr->mem, ctlr->size);
			for(i = 0; i < sizeof(ctlr->ea); i++)
				print(" %2.2ux", ctlr->ea[i]);
			print("\n");
.
498,505c
			if(ctlr->irq == 2)
				ctlr->irq = 9;
			if((irqmask & (1<<ctlr->irq)) == 0){
				setvec(Int0vec+ctlr->irq, etherintr);
				irqmask |= 1<<ctlr->irq;
			}
.
496a
			 * If there are multiple controllers on the same IRQ, only
			 * call setvec() for one of them, etherintr() will scan through
			 * all the controllers looking for those at the IRQ it was
			 * called with. This is a hack, see the comments in etherintr().
.
482,491c
	irqmask = 0;
	for(ctlr = 0, ctlrno = 0; ctlrno < MaxEther; ctlrno++){
		if(ctlr == 0)
			ctlr = malloc(sizeof(Ether));
		memset(ctlr, 0, sizeof(Ether));
		if(isaconfig("ether", ctlrno, ctlr) == 0)
			continue;
		for(n = 0; cards[n].type; n++){
			if(strcmp(cards[n].type, ctlr->type))
				continue;
			if((*cards[n].reset)(ctlr))
				break;
.
478,480c
	Ether *ctlr;
	int i, n, ctlrno;
	ulong irqmask;
.
362,474d
357,359c
	if(ncard == NCARD)
		panic("too many ether cards");
	cards[ncard].type = t;
	cards[ncard].reset = r;
	ncard++;
.
354,355c
	static int ncard;
.
342,352c
void
addethercard(char *t, int (*r)(Ether*))
.
336,340c
#define NCARD 32
static struct {
	char	*type;
	int	(*reset)(Ether*);
} cards[NCARD+1];
.
332,333d
292,330c
	irq = ur->trap-Int0vec;
	for(i = 0; i < MaxEther; i++){
		if(ether[i] && ether[i]->irq == irq)
			(*ether[i]->interrupt)(ether[i]);
.
289,290c
	 * Call all ethernet interrupt routines on this IRQ.
	 * Might be better if setvec() took an argument which
	 * was passed down to the interrupt routine when
	 * called. This would let us easily distinguish multiple
	 * controllers. A hack by any other name...
.
275,287d
272,273c
	int i, irq;
.
270c
etherintr(Ureg *ur)
.
257,268d
240,254c
	return n;
.
238c
	qunlock(&ctlr->tlock);
.
186,236c
	n = (*ctlr->write)(ctlr, buf, n);
.
183d
129,179d
119,127c
	if(NETTYPE(c->qid.path) != Ndataqid)
		return netifwrite(ctlr, c, buf, n);
.
116,117c
	USED(offset);
	if(n > ETHERMAXTU)
		error(Ebadarg);
	ctlr = ether[c->dev];
.
114c
	Ether *ctlr;
.
111,112c
long
etherwrite(Chan *c, void *buf, long n, ulong offset)
.
108c
	netifwstat(ether[c->dev], c, dp);
.
102d
91,97d
88c
	return netifread(ether[c->dev], c, buf, n, offset);
.
86c
etherread(Chan *c, void *buf, long n, ulong offset)
.
81,82c
	netifclose(ether[c->dev], c);
.
75d
68c
	return netifopen(ether[c->dev], c, omode);
.
62c
	netifstat(ether[c->dev], c, dp);
.
56c
	return netifwalk(ether[c->dev], c, name);
.
44,45c
	c = devattach('l', spec);
	c->dev = ctlrno;
	if(ether[ctlrno]->attach)
		(*ether[ctlrno]->attach)(ether[ctlrno]);
	return c;
}
.
40,42c
	ctlrno = 0;
	if(spec && *spec){
		ctlrno = strtoul(spec, &p, 0);
		if((ctlrno == 0 && p == spec) || *p || (ctlrno >= MaxEther))
			error(Ebadarg);
	}
	if(ether[ctlrno] == 0)
		error(Enodev);
.
36,38c
Chan*
etherattach(char *spec)
{
	ulong ctlrno;
	char *p;
	Chan *c;
.
24,34c
void
etherinit(void)
{
}
.
12,22c
static Ether *ether[MaxEther];
.
10c
#include "etherif.h"
.
8c
#include "ureg.h"
#include "../port/error.h"
#include "../port/netif.h"
.
6d
## diffname pc/devether.c 1993/1119
## diff -e /n/fornaxdump/1993/1113/sys/src/brazil/pc/devether.c /n/fornaxdump/1993/1119/sys/src/brazil/pc/devether.c
152c
	if(ncard == MaxEther)
.
145c
} cards[MaxEther+1];
.
141d
## diffname pc/devether.c 1993/1120
## diff -e /n/fornaxdump/1993/1119/sys/src/brazil/pc/devether.c /n/fornaxdump/1993/1120/sys/src/brazil/pc/devether.c
206a
			break;
.
109a
	if(etherwloop(ctlr, buf, n))
		return n;

.
96a
void
etherrloop(Ether *ctlr, Etherpkt *pkt, long len)
{
	ushort type;
	Netfile *f, **fp, **ep;

	type = (pkt->type[0]<<8)|pkt->type[1];
	ep = &ctlr->f[Ntypes];
	for(fp = ctlr->f; fp < ep; fp++){
		f = *fp;
		if(f && (f->type == type || f->type < 0)){
			switch(qproduce(f->in, pkt->d, len)){

			case -1:
				print("etherrloop overflow\n");
				break;

			case -2:
				print("etherrloop memory\n");
				break;
			}
		}
	}
}

static int
etherwloop(Ether *ctlr, Etherpkt *pkt, long len)
{
	int s, different;

	different = memcmp(pkt->d, pkt->s, sizeof(pkt->s));
	if(different && memcmp(pkt->d, ctlr->bcast, sizeof(pkt->d)))
		return 0;

	s = splhi();
	etherrloop(ctlr, pkt, len);
	splx(s);
	return !different;
}

.
## diffname pc/devether.c 1993/1124
## diff -e /n/fornaxdump/1993/1120/sys/src/brazil/pc/devether.c /n/fornaxdump/1993/1124/sys/src/brazil/pc/devether.c
233c
				setvec(Int0vec+ctlr->irq, ctlr->interrupt, ctlr);
.
225,228d
165,183d
## diffname pc/devether.c 1994/0202
## diff -e /n/fornaxdump/1993/1124/sys/src/brazil/pc/devether.c /n/fornaxdump/1994/0202/sys/src/brazil/pc/devether.c
106,118c
		if((f = *fp) && (f->type == type || f->type < 0))
			qproduce(f->in, pkt->d, len);
.
## diffname pc/devether.c 1994/0629
## diff -e /n/fornaxdump/1994/0202/sys/src/brazil/pc/devether.c /n/fornaxdump/1994/0629/sys/src/brazil/pc/devether.c
117c
	if(different && memcmp(pkt->d, ctlr->bcast, sizeof(pkt->d))
	&& ctlr->prom==0 && ctlr->all==0)
.
## diffname pc/devether.c 1994/0702
## diff -e /n/fornaxdump/1994/0629/sys/src/brazil/pc/devether.c /n/fornaxdump/1994/0702/sys/src/brazil/pc/devether.c
124c

	return tome;
.
122c
	etherrloop(ctlr, pkt, len, tome||bcast);
.
116,118c
	tome = memcmp(pkt->d, ctlr->ea, sizeof(pkt->d)) == 0;
	bcast = memcmp(pkt->d, ctlr->bcast, sizeof(pkt->d)) == 0;
	if(!tome && !bcast && ctlr->prom==0 && ctlr->all==0)
.
114c
	int s, tome, bcast;
.
106c
		if((f = *fp) && ((tome && f->type==type) || f->type < 0))
.
98c
etherrloop(Ether *ctlr, Etherpkt *pkt, long len, int tome)
.
## diffname pc/devether.c 1994/0713
## diff -e /n/fornaxdump/1994/0702/sys/src/brazil/pc/devether.c /n/fornaxdump/1994/0713/sys/src/brazil/pc/devether.c
200,203c
			setvec(Int0vec+ctlr->irq, ctlr->interrupt, ctlr);
.
180d
178d
## diffname pc/devether.c 1995/0108
## diff -e /n/fornaxdump/1994/0713/sys/src/brazil/pc/devether.c /n/fornaxdump/1995/0108/sys/src/brazil/pc/devether.c
153a
}

long
etherbwrite(Chan *c, Block *bp, ulong offset)
{
	return devbwrite(c, bp, offset);
.
84a
Block*
etherbread(Chan *c, long n, ulong offset)
{
	return devbread(c, n, offset);
}

.
## diffname pc/devether.c 1995/0504
## diff -e /n/fornaxdump/1995/0108/sys/src/brazil/pc/devether.c /n/fornaxdump/1995/0504/sys/src/brazil/pc/devether.c
212,213c
			print("ether%d: %s: port 0x%lux irq %d",
				ctlrno, ctlr->type, ctlr->port, ctlr->irq);
			if(ctlr->mem)
				print(" addr 0x%lux", ctlr->mem);
			if(ctlr->mem)
				print(" size %d", ctlr->size);
			print(": ea");
.
## diffname pc/devether.c 1995/0505
## diff -e /n/fornaxdump/1995/0504/sys/src/brazil/pc/devether.c /n/fornaxdump/1995/0505/sys/src/brazil/pc/devether.c
218c
			print(":");
.
216c
			if(ctlr->size)
.
## diffname pc/devether.c 1995/0511
## diff -e /n/fornaxdump/1995/0505/sys/src/brazil/pc/devether.c /n/fornaxdump/1995/0511/sys/src/brazil/pc/devether.c
217c
				print(" size 0x%lux", ctlr->size);
.
215c
				print(" addr 0x%lux", ctlr->mem & ~KZERO);
.
## diffname pc/devether.c 1995/0513
## diff -e /n/fornaxdump/1995/0511/sys/src/brazil/pc/devether.c /n/fornaxdump/1995/0513/sys/src/brazil/pc/devether.c
220c
				print(" %2.2uX", ctlr->ea[i]);
.
217c
				print(" size 0x%luX", ctlr->size);
.
215c
				print(" addr 0x%luX", ctlr->mem & ~KZERO);
.
212c
			print("ether%d: %s: port 0x%luX irq %d",
.
## diffname pc/devether.c 1995/0711
## diff -e /n/fornaxdump/1995/0513/sys/src/brazil/pc/devether.c /n/fornaxdump/1995/0711/sys/src/brazil/pc/devether.c
113c
			if(qproduce(f->in, pkt->d, len) < 0)
				ctlr->soverflows++;
.
## diffname pc/devether.c 1995/0713
## diff -e /n/fornaxdump/1995/0711/sys/src/brazil/pc/devether.c /n/fornaxdump/1995/0713/sys/src/brazil/pc/devether.c
112,114c
		if((f = *fp) && ((tome && f->type==type) || f->type < 0)){
			if(f->type > -2){
				if(qproduce(f->in, pkt->d, len) < 0)
					ctlr->soverflows++;
			} else {
				if(qwindow(f->in) <= 0)
					continue;
				if(len > 60)
					len = 60;
				bp = iallocb(len);
				if(bp == 0)
					continue;
				memmove(bp->wp, pkt->d, len);
				i = TK2MS(m->ticks);
				bp->wp[60] = i>>24;
				bp->wp[61] = i>>16;
				bp->wp[62] = i>>8;
				bp->wp[63] = i;
				bp->wp += 64;
				qpass(f->in, bp);
			}
		}
.
106a
	int i;
.
105a
	Block *bp;
.
## diffname pc/devether.c 1995/0721
## diff -e /n/fornaxdump/1995/0713/sys/src/brazil/pc/devether.c /n/fornaxdump/1995/0721/sys/src/brazil/pc/devether.c
153c
	return different == 0;
.
150c
	etherrloop(ctlr, pkt, len);
.
144,146c
	different = memcmp(pkt->d, ctlr->ea, sizeof(pkt->d));
	if(different && memcmp(pkt->d, ctlr->bcast, sizeof(pkt->d)))
.
142c
	int s, different;
.
114c
		if((f = *fp) && (f->type == type || f->type < 0)){
.
104c
etherrloop(Ether *ctlr, Etherpkt *pkt, long len)
.
## diffname pc/devether.c 1995/0725
## diff -e /n/fornaxdump/1995/0721/sys/src/brazil/pc/devether.c /n/fornaxdump/1995/0725/sys/src/brazil/pc/devether.c
248a
			ctlr->ctlrno = ctlrno;
.
## diffname pc/devether.c 1995/0726
## diff -e /n/fornaxdump/1995/0725/sys/src/brazil/pc/devether.c /n/fornaxdump/1995/0726/sys/src/brazil/pc/devether.c
70d
68c
ethercreate(Chan*, char*, int, ulong)
.
## diffname pc/devether.c 1995/0731
## diff -e /n/fornaxdump/1995/0726/sys/src/brazil/pc/devether.c /n/fornaxdump/1995/0731/sys/src/brazil/pc/devether.c
144c
	if(!ctlr->prom && different && memcmp(pkt->d, ctlr->bcast, sizeof(pkt->d)))
.
126a
				bp->wp[58] = len>>8;
				bp->wp[59] = len;
.
## diffname pc/devether.c 1995/0801
## diff -e /n/fornaxdump/1995/0731/sys/src/brazil/pc/devether.c /n/fornaxdump/1995/0801/sys/src/brazil/pc/devether.c
125c
				memmove(bp->wp, pkt->d, n);
.
120,122c
				if(len > 64)
					n = 64;
				else
					n = len;
				bp = iallocb(n);
.
107c
	int i, n;
.
## diffname pc/devether.c 1995/0822
## diff -e /n/fornaxdump/1995/0801/sys/src/brazil/pc/devether.c /n/fornaxdump/1995/0822/sys/src/brazil/pc/devether.c
181a
	poperror();
.
180d
163d
159c
etherwrite(Chan *c, void *buf, long n, ulong)
.
148c
	if(different && memcmp(pkt->d, ctlr->bcast, sizeof(pkt->d)))
.
93d
91c
etherremove(Chan*)
.
## diffname pc/devether.c 1995/1004
## diff -e /n/fornaxdump/1995/0822/sys/src/brazil/pc/devether.c /n/fornaxdump/1995/1004/sys/src/brazil/pc/devether.c
147c
	if(different && memcmp(pkt->d, ctlr->bcast, sizeof(pkt->d)) && ctlr->prom == 0)
.
## diffname pc/devether.c 1996/0601
## diff -e /n/fornaxdump/1995/1004/sys/src/brazil/pc/devether.c /n/fornaxdump/1996/0601/sys/src/brazil/pc/devether.c
250d
245c
			if(ctlr->mbps == 100)
				netifinit(ctlr, "ether", Ntypes, 100*1024);
			else
				netifinit(ctlr, "ether", Ntypes, 32*1024);
.
242c
				print("%2.2uX", ctlr->ea[i]);
.
240c
			print(": ");
.
234,235c
			print("ether%d: %s: %dMbps port 0x%luX irq %d",
				ctlrno, ctlr->type, ctlr->mbps, ctlr->port, ctlr->irq);
.
216a
		ctlr->ctlrno = ctlrno;
		ctlr->mbps = 10;
.
## diffname pc/devether.c 1996/0607
## diff -e /n/fornaxdump/1996/0601/sys/src/brazil/pc/devether.c /n/fornaxdump/1996/0607/sys/src/brazil/pc/devether.c
248c
				netifinit(ctlr, "ether", Ntypes, 128*1024);
.
236c
			print("ether#%d: %s: %dMbps port 0x%luX irq %d",
.
81c
	Ether *ctlr;

	ctlr = ether[c->dev];
	if((c->qid.path & CHDIR) == 0 && ctlr->ifstat){
		/*
		 * With some controllers it is necessary to reach
		 * into the chip to extract statistics.
		 */
		if(NETTYPE(c->qid.path) == Nifstatqid)
			return (*ctlr->ifstat)(ctlr, buf, n, offset);
		else if(NETTYPE(c->qid.path) == Nstatqid)
			(*ctlr->ifstat)(ctlr, buf, 0, offset);
	}

	return netifread(ctlr, c, buf, n, offset);
.
## diffname pc/devether.c 1997/0327
## diff -e /n/fornaxdump/1996/0607/sys/src/brazil/pc/devether.c /n/emeliedump/1997/0327/sys/src/brazil/pc/devether.c
276a

Dev etherdevtab = {
	etherreset,
	devinit,
	etherattach,
	devclone,
	etherwalk,
	etherstat,
	etheropen,
	ethercreate,
	etherclose,
	etherread,
	etherbread,
	etherwrite,
	etherbwrite,
	etherremove,
	etherwstat,
};
.
274,275c
	if(ether)
		free(ether);
.
269,270c
			etherxx[ctlrno] = ether;
			ether = 0;
.
261,267c
			snprint(name, sizeof(name), "ether%d", ctlrno);
			if(ether->mbps == 100){
				netifinit(ether, name, Ntypes, 256*1024);
				if(ether->oq == 0)
					ether->oq = qopen(256*1024, 1, 0, 0);
			}
			else{
				netifinit(ether, name, Ntypes, 32*1024);
				if(ether->oq == 0)
					ether->oq = qopen(64*1024, 1, 0, 0);
			}
			ether->alen = Eaddrlen;
			memmove(ether->addr, ether->ea, Eaddrlen);
			memset(ether->bcast, 0xFF, Eaddrlen);
.
250,259c
			i = sprint(buf, "#l%d: %s: %dMbps port 0x%luX irq %d",
				ctlrno, ether->type, ether->mbps, ether->port, ether->irq);
			if(ether->mem)
				i += sprint(buf+i, " addr 0x%luX", ether->mem & ~KZERO);
			if(ether->size)
				i += sprint(buf+i, " size 0x%luX", ether->size);
			i += sprint(buf+i, ": %2.2uX%2.2uX%2.2uX%2.2uX%2.2uX%2.2uX",
				ether->ea[0], ether->ea[1], ether->ea[2],
				ether->ea[3], ether->ea[4], ether->ea[5]);
			sprint(buf+i, "\n");
			print(buf);
.
246,248c
			if(ether->irq == 2)
				ether->irq = 9;
			intrenable(VectorPIC+ether->irq, ether->interrupt, ether, ether->tbdf);
.
238c
			for(i = 0; i < ether->nopt; i++){
				if(strncmp(ether->opt[i], "ea=", 3))
					continue;
				if(parseether(ether->ea, &ether->opt[i][3]) == -1)
					memset(ether->ea, 0, Eaddrlen);
			}	
			if(cards[n].reset(ether))
.
236c
			if(cistrcmp(cards[n].type, ether->type))
.
227,233c
	for(ether = 0, ctlrno = 0; ctlrno < MaxEther; ctlrno++){
		if(ether == 0)
			ether = malloc(sizeof(Ether));
		memset(ether, 0, sizeof(Ether));
		ether->ctlrno = ctlrno;
		ether->tbdf = BUSUNKNOWN;
		ether->mbps = 10;
		if(isaconfig("ether", ctlrno, ether) == 0)
.
225a
	char name[NAMELEN], buf[128];
.
224c
	Ether *ether;
.
221c
int
parseether(uchar *to, char *from)
{
	char nip[4];
	char *p;
	int i;

	p = from;
	for(i = 0; i < 6; i++){
		if(*p == 0)
			return -1;
		nip[0] = *p++;
		if(*p == 0)
			return -1;
		nip[1] = *p++;
		nip[2] = 0;
		to[i] = strtoul(nip, 0, 16);
		if(*p == ':')
			p++;
	}
	return 0;
}

static void
.
210c
addethercard(char* t, int (*r)(Ether*))
.
205c
	char*	type;
.
201c
	Ether *ether;
	long n;

	n = BLEN(bp);
	if(n > ETHERMAXTU){
		freeb(bp);
		error(Ebadarg);
	}

	ether = etherxx[chan->dev];
	if(NETTYPE(chan->qid.path) != Ndataqid){
		n = netifwrite(ether, chan, bp->rp, n);
		freeb(bp);
		return n;
	}

	return etheroq(ether, bp);
.
198,199c
static long
etherbwrite(Chan* chan, Block* bp, ulong)
.
195c
	return etheroq(ether, bp);
.
193a
	bp->wp += n;
.
191,192c
	memmove(bp->rp, buf, n);
	memmove(bp->rp+Eaddrlen, ether->ea, Eaddrlen);
.
188c
		freeb(bp);
.
183,186c
	bp = allocb(n);
.
180,181c
	ether = etherxx[chan->dev];
	if(NETTYPE(chan->qid.path) != Ndataqid)
		return netifwrite(ether, chan, buf, n);
.
178d
174c
	Ether *ether;
	Block *bp;
.
171,172c
static long
etherwrite(Chan* chan, void* buf, long n, ulong)
.
168c
	if(!loopback){
		qbwrite(ether->oq, bp);
		ether->transmit(ether);
	}

	return len;
.
164,166c
	/*
	 * Check if the packet has to be placed back onto the input queue,
	 * i.e. if it's a loopback or broadcast packet or the interface is
	 * in promiscuous mode.
	 * If it's a loopback packet indicate to etheriq that the data isn't
	 * needed and return, etheriq will pass-on or free the block.
	 */
	pkt = (Etherpkt*)bp->rp;
	len = BLEN(bp);
	loopback = !memcmp(pkt->d, ether->ea, sizeof(pkt->d));
	if(loopback || !memcmp(pkt->d, ether->bcast, sizeof(pkt->d)) || ether->prom){
		s = splhi();
		etheriq(ether, bp, loopback);
		splx(s);
	}
.
160,162c
	ether->outpackets++;
.
158c
	int len, loopback, s;
	Etherpkt *pkt;
.
156c
etheroq(Ether* ether, Block* bp)
.
152a

	if(fx){
		qpass(fx->in, bp);
		return 0;
	}
	if(freebp){
		freeb(bp);
		return 0;
	}

	return bp;
.
150a
			else
				etherrtrace(f, pkt, len);
.
136,149c
					ether->soverflows++;
.
128,134c
				if(freebp && fx == 0)
					fx = f;
				else if(xbp = iallocb(len)){
					memmove(xbp->wp, pkt, len);
					xbp->wp += len;
					qpass(f->in, xbp);
				}
.
124,125c
	fx = 0;
	ep = &ether->f[Ntypes];

	/*
	 * Multiplex the packet to all the connections which want it.
	 * If the packet is not to be used subsequently (freebp != 0),
	 * attempt to simply pass it into one of the connections, thereby
	 * saving a copy of the data (usual case hopefully).
	 */
	for(fp = ether->f; fp < ep; fp++){
.
122a
	ether->inpackets++;

	pkt = (Etherpkt*)bp->rp;
	len = BLEN(bp);
.
120,121c
	int len;
	Netfile **ep, *f, **fp, *fx;
	Block *xbp;
.
118a

	if(qwindow(f->in) <= 0)
		return;
	if(len > 64)
		n = 64;
	else
		n = len;
	bp = iallocb(n);
	if(bp == 0)
		return;
	memmove(bp->wp, pkt->d, n);
	i = TK2MS(m->ticks);
	bp->wp[58] = len>>8;
	bp->wp[59] = len;
	bp->wp[60] = i>>24;
	bp->wp[61] = i>>16;
	bp->wp[62] = i>>8;
	bp->wp[63] = i;
	bp->wp += 64;
	qpass(f->in, bp);
}

Block*
etheriq(Ether* ether, Block* bp, int freebp)
{
	Etherpkt *pkt;
.
117a
	int i, n;
.
115,116c
static void
etherrtrace(Netfile* f, Etherpkt* pkt, int len)
.
112c
	netifwstat(etherxx[chan->dev], chan, dp);
.
109,110c
static void
etherwstat(Chan* chan, char* dp)
.
104c
static void
.
101c
	return netifbread(etherxx[chan->dev], chan, n, offset);
.
98,99c
static Block*
etherbread(Chan* chan, long n, ulong offset)
.
95c
	return netifread(ether, chan, buf, n, offset);
.
89,92c
		if(NETTYPE(chan->qid.path) == Nifstatqid)
			return ether->ifstat(ether, buf, n, offset);
		else if(NETTYPE(chan->qid.path) == Nstatqid)
			ether->ifstat(ether, buf, 0, offset);
.
83,84c
	ether = etherxx[chan->dev];
	if((chan->qid.path & CHDIR) == 0 && ether->ifstat){
.
81c
	Ether *ether;
.
78,79c
static long
etherread(Chan* chan, void* buf, long n, ulong offset)
.
75c
	netifclose(etherxx[chan->dev], chan);
.
72,73c
static void
etherclose(Chan* chan)
.
61,67c
static void
.
58c
	return netifopen(etherxx[chan->dev], chan, omode);
.
55,56c
static Chan*
etheropen(Chan* chan, int omode)
.
52c
	netifstat(etherxx[chan->dev], chan, dp);
.
49,50c
static void
etherstat(Chan* chan, char* dp)
.
46c
	return netifwalk(etherxx[chan->dev], chan, name);
.
43,44c
static int
etherwalk(Chan* chan, char* name)
.
36,40c
	chan = devattach('l', spec);
	chan->dev = ctlrno;
	if(etherxx[ctlrno]->attach)
		etherxx[ctlrno]->attach(etherxx[ctlrno]);
	return chan;
.
33c
	if(etherxx[ctlrno] == 0)
.
25c
	Chan *chan;
.
21c
etherattach(char* spec)
.
15,19d
13c
static Ether *etherxx[MaxEther];
.
## diffname pc/devether.c 1997/0404
## diff -e /n/emeliedump/1997/0327/sys/src/brazil/pc/devether.c /n/emeliedump/1997/0404/sys/src/brazil/pc/devether.c
147a
	/* check for valid multcast addresses */
	if((pkt->d[0] & 1) && memcmp(pkt->d, ether->bcast, sizeof(pkt->d)) != 0 && ether->prom == 0){
		if(!activemulti(ether, pkt->d, sizeof(pkt->d))){
			if(freebp){
				freeb(bp);
				bp = 0;
			}
			return bp;
		}
	}

.
## diffname pc/devether.c 1997/0408
## diff -e /n/emeliedump/1997/0404/sys/src/brazil/pc/devether.c /n/emeliedump/1997/0408/sys/src/brazil/pc/devether.c
388a
	'l',
	"ether",

.
## diffname pc/devether.c 1997/0415
## diff -e /n/emeliedump/1997/0408/sys/src/brazil/pc/devether.c /n/emeliedump/1997/0415/sys/src/brazil/pc/devether.c
387a
#define POLY 0xedb88320

/* really slow 32 bit crc for ethers */
ulong
ethercrc(uchar *p, int len)
{
	int i, j;
	ulong crc, b;

	crc = 0xffffffff;
	for(i = 0; i < len; i++){
		b = *p++;
		for(j = 0; j < 8; j++){
			crc = (crc>>1);
			if((crc^b) & 1)
				crc ^= POLY;
			b >>= 1;
		}
	}
	return crc;
}

.
## diffname pc/devether.c 1997/0418
## diff -e /n/emeliedump/1997/0415/sys/src/brazil/pc/devether.c /n/emeliedump/1997/0418/sys/src/brazil/pc/devether.c
401,403c
			crc = (crc>>1) ^ (((crc^b) & 1) ? POLY : 0);
.
## diffname pc/devether.c 1997/0808
## diff -e /n/emeliedump/1997/0418/sys/src/brazil/pc/devether.c /n/emeliedump/1997/0808/sys/src/brazil/pc/devether.c
212,213c
	loopback = (memcmp(pkt->d, ether->ea, sizeof(pkt->d)) == 0);
	if(loopback || memcmp(pkt->d, ether->bcast, sizeof(pkt->d)) == 0 || ether->prom){
.
149c
	if((pkt->d[0] & 1) && memcmp(pkt->d, ether->bcast, sizeof(pkt->d)) && ether->prom == 0){
.
120c
	i = TK2MS(MACHP(0)->ticks);
.
## diffname pc/devether.c 1997/1101
## diff -e /n/emeliedump/1997/0808/sys/src/brazil/pc/devether.c /n/emeliedump/1997/1101/sys/src/brazil/pc/devether.c
355c
				i += sprint(buf+i, " addr 0x%luX", PADDR(ether->mem));
.
271a
	if(n > ETHERMAXTU){
		freeb(bp);
		error(Ebadarg);
	}
	if(n < ETHERMINTU){
		freeb(bp);
		error(Etoosmall);
	}

.
260,264d
239a
	if(n > ETHERMAXTU)
		error(Etoobig);
	if(n < ETHERMINTU)
		error(Etoosmall);

.
233,235d
## diffname pc/devether.c 1997/1105
## diff -e /n/emeliedump/1997/1101/sys/src/brazil/pc/devether.c /n/emeliedump/1997/1105/sys/src/brazil/pc/devether.c
380a
			if(ether->oq == 0)
				panic("etherreset %s", name);
.
## diffname pc/devether.c 1998/0218
## diff -e /n/emeliedump/1997/1105/sys/src/brazil/pc/devether.c /n/emeliedump/1998/0218/sys/src/brazil/pc/devether.c
379c
					ether->oq = qopen(65*1024, 1, 0, 0);
.
377c
				netifinit(ether, name, Ntypes, 65*1024);
.
## diffname pc/devether.c 1998/0319
## diff -e /n/emeliedump/1998/0218/sys/src/brazil/pc/devether.c /n/emeliedump/1998/0319/sys/src/brazil/pc/devether.c
228c
etherwrite(Chan* chan, void* buf, long n, vlong)
.
70a
	ulong offset = off;
.
68c
etherread(Chan* chan, void* buf, long n, vlong off)
.
## diffname pc/devether.c 1998/0825
## diff -e /n/emeliedump/1998/0319/sys/src/brazil/pc/devether.c /n/emeliedump/1998/0825/sys/src/brazil/pc/devether.c
359c
			i = sprint(buf, "#l%d: %s: %dMbps port 0x%luX irq %lud",
.
## diffname pc/devether.c 1998/0910
## diff -e /n/emeliedump/1998/0825/sys/src/brazil/pc/devether.c /n/emeliedump/1998/0910/sys/src/brazil/pc/devether.c
357c
			intrenable(ether->irq, ether->interrupt, ether, ether->tbdf);
.
## diffname pc/devether.c 1998/1013
## diff -e /n/emeliedump/1998/0910/sys/src/brazil/pc/devether.c /n/emeliedump/1998/1013/sys/src/brazil/pc/devether.c
185c
		if(qpass(fx->in, bp) < 0)
			ether->soverflows++;
.
## diffname pc/devether.c 1999/0316
## diff -e /n/emeliedump/1998/1013/sys/src/brazil/pc/devether.c /n/emeliedump/1999/0316/sys/src/brazil/pc/devether.c
214a
	mine = memcmp(pkt->s, ether->ea, sizeof(pkt->s)) == 0;
	if(mine)
.
210a
	 * To enable bridging to work, only packets that were originated
	 * by this interface are feedback
.
200c
	int len, loopback, s, mine;
.
167c
		if((f = *fp) && (f->type == type || f->type < 0) && (forme || multi || f->prom)){
.
159a
	// is it for me?
	forme = memcmp(pkt->d, ether->ea, sizeof(pkt->d)) == 0;

.
150c
	if(multi && memcmp(pkt->d, ether->bcast, sizeof(pkt->d)) && ether->prom == 0){
.
148a
	multi = pkt->d[0] & 1;
.
137c
	int len, multi, forme;
.
## diffname pc/devether.c 1999/0402
## diff -e /n/emeliedump/1999/0316/sys/src/brazil/pc/devether.c /n/emeliedump/1999/0402/sys/src/brazil/pc/devether.c
216c
	 * by this interface are fed back.
.
## diffname pc/devether.c 1999/0625
## diff -e /n/emeliedump/1999/0402/sys/src/brazil/pc/devether.c /n/emeliedump/1999/0625/sys/src/brazil/pc/devether.c
232c
	} else
		freeb(bp);
.
225c
		etheriq(ether, bp, 0);
.
220,222c
	loopback = memcmp(pkt->d, ether->ea, sizeof(pkt->d)) == 0;
.
204c
	int len, loopback, s;
.
193c
	if(fromwire){
.
171,173c
		if(f = *fp)
		if(f->type == type || f->type < 0)
		if(tome || multi || f->prom){
			/* Don't want to hear bridged packets */
			if(f->bridge && !fromwire && !fromme)
				continue;
			if(!f->headersonly){
				if(fromwire && fx == 0)
.
166c
	 * If the packet is not to be used subsequently (fromwire != 0),
.
161,162c
	/* is it for me? */
	tome = memcmp(pkt->d, ether->ea, sizeof(pkt->d)) == 0;
	fromme = memcmp(pkt->s, ether->ea, sizeof(pkt->s)) == 0;
.
153c
			if(fromwire){
.
137c
	int len, multi, tome, fromme;
.
133c
etheriq(Ether* ether, Block* bp, int fromwire)
.
## diffname pc/devether.c 1999/0819
## diff -e /n/emeliedump/1999/0625/sys/src/brazil/pc/devether.c /n/emeliedump/1999/0819/sys/src/brazil/pc/devether.c
385d
371c
			snprint(name, sizeof(name), "ether%d", ctlrno);
			intrenable(ether->irq, ether->interrupt, ether, ether->tbdf, name);
.
## diffname pc/devether.c 2000/0713
## diff -e /n/emeliedump/1999/0819/sys/src/brazil/pc/devether.c /n/emeliedump/2000/0713/sys/src/9/pc/devether.c
117,118c
	bp = iallocb(64);
	if(bp == nil)
.
113,114c
	if(len > 58)
		n = 58;
.
## diffname pc/devether.c 2000/0817
## diff -e /n/emeliedump/2000/0713/sys/src/9/pc/devether.c /n/emeliedump/2000/0817/sys/src/9/pc/devether.c
372c

			/* If ether->irq is less than 0, it is a hack to indicate no interrupt
			 * used for the seocnd logical ethernet for the wavelan card
			 */
			if(ether->irq >= 0)
				intrenable(ether->irq, ether->interrupt, ether, ether->tbdf, name);
.
282a
	ether = etherxx[chan->dev];
.
279c
		if(waserror()) {
			freeb(bp);
			nexterror();
		}
		n = etherwrite(chan, bp->rp, n, 0);
.
277d
264d
258,261d
251a
		if(ether->ctl!=nil)
			return ether->ctl(ether,buf,n);
			
		error(Ebadctl);
	}

.
249,250c
	if(NETTYPE(chan->qid.path) != Ndataqid) {
		nn = netifwrite(ether, chan, buf, n);
		if(nn >= 0)
			return nn;
.
246a
	int nn;
.
## diffname pc/devether.c 2000/0921
## diff -e /n/emeliedump/2000/0817/sys/src/9/pc/devether.c /n/emeliedump/2000/0921/sys/src/9/pc/devether.c
399c
			if(ether->mbps >= 100){
.
357a
		ether->minmtu = ETHERMINTU;
		ether->maxmtu = ETHERMAXTU;
.
296c
	if(n < ether->minmtu){
.
294c
		error(Etoobig);
.
292c
	if(n > ether->maxmtu){
.
286a
		poperror();
.
263c
	if(n < ether->minmtu)
.
261c
	if(n > ether->maxmtu)
.
## diffname pc/devether.c 2000/1110
## diff -e /n/emeliedump/2000/0921/sys/src/9/pc/devether.c /n/emeliedump/2000/1110/sys/src/9/pc/devether.c
385c
			 * used for the second logical ethernet for the wavelan card
.
## diffname pc/devether.c 2001/0203
## diff -e /n/emeliedump/2000/1110/sys/src/9/pc/devether.c /n/emeliedump/2001/0203/sys/src/9/pc/devether.c
124,128c
	bp->wp[60] = ts>>56;
	bp->wp[61] = ts>>48;
	bp->wp[62] = ts>>40;
	bp->wp[63] = ts>>32;
	bp->wp[64] = ts>>24;
	bp->wp[65] = ts>>16;
	bp->wp[66] = ts>>8;
	bp->wp[67] = ts;
	bp->wp += 68;
.
121c
	ts = fastticks(nil);
.
117c
	bp = iallocb(68);
.
109a
	uvlong ts;
.
108c
	int n;
.
## diffname pc/devether.c 2001/0504
## diff -e /n/emeliedump/2001/0203/sys/src/9/pc/devether.c /n/emeliedump/2001/0504/sys/src/9/pc/devether.c
273a
	poperror();
.
271a
	if(waserror()){
		freeb(bp);
		nexterror();
	}
.
251c
	Block *volatile bp;
.
## diffname pc/devether.c 2001/0527
## diff -e /n/emeliedump/2001/0504/sys/src/9/pc/devether.c /n/emeliedump/2001/0527/sys/src/9/pc/devether.c
464d
360c
	char name[32], buf[128];
.
251c
	Block *bp;
.
125,133c
	bp->wp[60] = i>>24;
	bp->wp[61] = i>>16;
	bp->wp[62] = i>>8;
	bp->wp[63] = i;
	bp->wp += 64;
.
122c
	i = TK2MS(MACHP(0)->ticks);
.
118c
	bp = iallocb(64);
.
110d
108c
	int i, n;
.
102c
	return netifwstat(etherxx[chan->dev], chan, dp, n);
.
99,100c
static int
etherwstat(Chan* chan, uchar* dp, int n)
.
74c
	if((chan->qid.type & QTDIR) == 0 && ether->ifstat){
.
47c
	return netifstat(etherxx[chan->dev], chan, dp, n);
.
44,45c
static int
etherstat(Chan* chan, uchar* dp, int n)
.
41c
	return netifwalk(etherxx[chan->dev], chan, nchan, name, nname);
.
38,39c
static Walkqid*
etherwalk(Chan* chan, Chan* nchan, char** name, int nname)
.
## diffname pc/devether.c 2001/0622
## diff -e /n/emeliedump/2001/0527/sys/src/9/pc/devether.c /n/emeliedump/2001/0622/sys/src/9/pc/devether.c
356a
	print("Searching for ethernet devices\n"); 
.
## diffname pc/devether.c 2001/0626
## diff -e /n/emeliedump/2001/0622/sys/src/9/pc/devether.c /n/emeliedump/2001/0626/sys/src/9/pc/devether.c
357d
## diffname pc/devether.c 2001/1130
## diff -e /n/emeliedump/2001/0626/sys/src/9/pc/devether.c /n/emeliedump/2001/1130/sys/src/9/pc/devether.c
392c
			if(ether->irq > 0)
.
389,390c
			/*
			 * If ether->irq is 0, it is a hack to indicate no interrupt
			 * used by ethersink.
.
## diffname pc/devether.c 2001/1204
## diff -e /n/emeliedump/2001/1130/sys/src/9/pc/devether.c /n/emeliedump/2001/1204/sys/src/9/pc/devether.c
469c
	devremove,
.
94,98d
## diffname pc/devether.c 2002/0109
## diff -e /n/emeliedump/2001/1204/sys/src/9/pc/devether.c /n/emeliedump/2002/0109/sys/src/9/pc/devether.c
453a
	ethershutdown,
.
427a
static void
ethershutdown(void)
{
	Ether *ether;
	int i;

	for(i = 0; i < MaxEther; i++){
		ether = etherxx[i];
		if(ether == nil)
			continue;
		if(ether->shutdown == nil) {
			print("#l%d: no shutdown fuction\n", i);
			continue;
		}
		(*ether->shutdown)(ether);
	}
}


.
## diffname pc/devether.c 2002/0314
## diff -e /n/emeliedump/2002/0109/sys/src/9/pc/devether.c /n/emeliedump/2002/0314/sys/src/9/pc/devether.c
179c
					if(qpass(f->in, xbp) < 0)
						ether->soverflows++;
.
## diffname pc/devether.c 2002/0403
## diff -e /n/emeliedump/2002/0314/sys/src/9/pc/devether.c /n/emeliedump/2002/0403/sys/src/9/pc/devether.c
425,426d
423a
		if((ether = etherprobe(cardno, ctlrno)) == nil){
			cardno++;
			continue;
		}
		etherxx[ctlrno] = ether;
		ctlrno++;
.
420,422c
	if(ether->mbps >= 100){
		netifinit(ether, name, Ntypes, 256*1024);
		if(ether->oq == 0)
			ether->oq = qopen(256*1024, 1, 0, 0);
	}
	else{
		netifinit(ether, name, Ntypes, 65*1024);
		if(ether->oq == 0)
			ether->oq = qopen(65*1024, 1, 0, 0);
	}
	if(ether->oq == 0)
		panic("etherreset %s", name);
	ether->alen = Eaddrlen;
	memmove(ether->addr, ether->ea, Eaddrlen);
	memset(ether->bcast, 0xFF, Eaddrlen);

	return ether;
}

static void
etherreset(void)
{
	Ether *ether;
	int cardno, ctlrno;

	for(ctlrno = 0; ctlrno < MaxEther; ctlrno++){
		if((ether = etherprobe(-1, ctlrno)) == nil)
			continue;
		etherxx[ctlrno] = ether;
	}

	cardno = ctlrno = 0;
	while(cards[cardno].type != nil && ctlrno < MaxEther){
		if(etherxx[ctlrno] != nil){
			ctlrno++;
			continue;
.
404,418c
	i = sprint(buf, "#l%d: %s: %dMbps port 0x%luX irq %lud",
		ctlrno, cards[cardno].type, ether->mbps, ether->port, ether->irq);
	if(ether->mem)
		i += sprint(buf+i, " addr 0x%luX", PADDR(ether->mem));
	if(ether->size)
		i += sprint(buf+i, " size 0x%luX", ether->size);
	i += sprint(buf+i, ": %2.2uX%2.2uX%2.2uX%2.2uX%2.2uX%2.2uX",
		ether->ea[0], ether->ea[1], ether->ea[2],
		ether->ea[3], ether->ea[4], ether->ea[5]);
	sprint(buf+i, "\n");
	print(buf);
.
392,402c
	/*
	 * If ether->irq is 0, it is a hack to indicate no interrupt
	 * used by ethersink.
	 */
	if(ether->irq > 0)
		intrenable(ether->irq, ether->interrupt, ether, ether->tbdf, name);
.
385,390c
	/*
	 * IRQ2 doesn't really exist, it's used to gang the interrupt
	 * controllers together. A device set to IRQ2 will appear on
	 * the second interrupt controller as IRQ9.
	 */
	if(ether->irq == 2)
		ether->irq = 9;
	snprint(name, sizeof(name), "ether%d", ctlrno);
.
376,383c
	if(cardno >= MaxEther || cards[cardno].type == nil){
		free(ether);
		return nil;
	}
	if(cards[cardno].reset(ether) < 0){
		free(ether);
		return nil;
	}
.
372,374c
			}
			break;
		}
	}
.
370c
				if(parseether(ether->ea, &ether->opt[i][3]))
.
353,365c
	ether = malloc(sizeof(Ether));
	memset(ether, 0, sizeof(Ether));
	ether->ctlrno = ctlrno;
	ether->tbdf = BUSUNKNOWN;
	ether->mbps = 10;
	ether->minmtu = ETHERMINTU;
	ether->maxmtu = ETHERMAXTU;

	if(cardno < 0){
		if(isaconfig("ether", ctlrno, ether) == 0){
			free(ether);
			return nil;
		}
		for(cardno = 0; cards[cardno].type; cardno++){
			if(cistrcmp(cards[cardno].type, ether->type))
.
350,351c
	char buf[128], name[32];
.
348a
	int i;
.
346,347c
static Ether*
etherprobe(int cardno, int ctlrno)
.
## diffname pc/devether.c 2002/0502
## diff -e /n/emeliedump/2002/0403/sys/src/9/pc/devether.c /n/emeliedump/2002/0502/sys/src/9/pc/devether.c
446a
	if(getconf("*noetherprobe"))
		return;

.
## diffname pc/devether.c 2002/0703
## diff -e /n/emeliedump/2002/0502/sys/src/9/pc/devether.c /n/emeliedump/2002/0703/sys/src/9/pc/devether.c
331c
	for(i = 0; i < Eaddrlen; i++){
.
## diffname pc/devether.c 2002/0710
## diff -e /n/emeliedump/2002/0703/sys/src/9/pc/devether.c /n/emeliedump/2002/0710/sys/src/9/pc/devether.c
424c
			ether->oq = qopen(128*1024, 1, 0, 0);
.
422c
		netifinit(ether, name, Ntypes, 128*1024);
.
417c
		netifinit(ether, name, Ntypes, 512*1024);
.
## diffname pc/devether.c 2002/0711
## diff -e /n/emeliedump/2002/0710/sys/src/9/pc/devether.c /n/emeliedump/2002/0711/sys/src/9/pc/devether.c
424c
			ether->oq = qopen(128*1024, Qmsg, 0, 0);
.
419c
			ether->oq = qopen(256*1024, Qmsg, 0, 0);
.
## diffname pc/devether.c 2002/0712
## diff -e /n/emeliedump/2002/0711/sys/src/9/pc/devether.c /n/emeliedump/2002/0712/sys/src/9/pc/devether.c
417c
		netifinit(ether, name, Ntypes, 256*1024);
.
250c
		if(n == sizeof("nonblocking")-1 && strncmp((char*)buf, "nonblocking", n) == 0){
			qnoblock(ether->oq, 1);
			return n;
		}
.
## diffname pc/devether.c 2002/1123
## diff -e /n/emeliedump/2002/0712/sys/src/9/pc/devether.c /n/emeliedump/2002/1123/sys/src/9/pc/devether.c
231c
		if(ether->transmit != nil)
			ether->transmit(ether);
.
## diffname pc/devether.c 2003/0301
## diff -e /n/emeliedump/2002/1123/sys/src/9/pc/devether.c /n/emeliedump/2003/0301/sys/src/9/pc/devether.c
408c
	i = sprint(buf, "#l%d: %s: %dMbps port 0x%luX irq %d",
.
405c
	if(ether->irq >= 0)
.
402c
	 * If ether->irq is <0, it is a hack to indicate no interrupt
.
## diffname pc/devether.c 2003/0312
## diff -e /n/emeliedump/2003/0301/sys/src/9/pc/devether.c /n/emeliedump/2003/0312/sys/src/9/pc/devether.c
254a
		free(cb);
.
251,252c
		cb = parsecmd(buf, n);
		if(strcmp(cb->f[0], "nonblocking") == 0){
			if(cb->nf <= 1)
				onoff = 1;
			else
				onoff = atoi(cb->f[1]);
			qnoblock(ether->oq, onoff);
			free(cb);
.
244c
	int nn, onoff;
	Cmdbuf *cb;
.

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.