plan 9 kernel history: overview | file list | diff list

2000/0817/pc/devether.c (diff list | history)

1992/0403/sys/src/9/pc/devether.c:1,71992/0404/sys/src/9/pc/devether.c:1,7 (short | long)
1992/0403    
/* 
 * Western Digital ethernet adapter 
 * BUGS: 
 *	more than one controller 
1992/0404    
 *	no more than one controller 
1992/0403    
 *	fix for different controller types 
 */ 
#include "u.h" 
1992/0403/sys/src/9/pc/devether.c:15,241992/0404/sys/src/9/pc/devether.c:15,36
1992/0403    
 
typedef struct Ctlr Ctlr; 
typedef struct Pktype Pktype; 
1992/0404    
typedef struct Ring Ring; 
1992/0403    
 
enum { 
	IObase		= 0x360, 
1992/0404    
	RAMbase		= 0xC8000, 
	RAMsize		= 8*1024, 
	BUFsize		= 256, 
1992/0403    
 
1992/0404    
	Nctlr		= 1, 
	NPktype		= 9,		/* types/interface */ 
}; 
 
/* 
 * register offsets from IObase 
 */ 
enum { 
1992/0403    
	EA		= 0x08,		/* Ethernet Address in ROM */ 
	ID		= 0x0E,		/* interface type */ 
 
1992/0403/sys/src/9/pc/devether.c:25,381992/0404/sys/src/9/pc/devether.c:37,49
1992/0403    
	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 */ 
1992/0404    
	Pstart		= NIC+0x01,	/* write */ 
	Pstop		= NIC+0x02,	/* write */ 
	Bnry		= NIC+0x03, 
1992/0403    
	Tsr		= NIC+0x04,	/* read */ 
	Tpsr		= Tsr,		/* write */ 
	Ncr		= NIC+0x05, 
1992/0404    
	Tbcr0		= NIC+0x05,	/* write */ 
	Tbcr1		= NIC+0x06,	/* write */ 
1992/0403    
	Isr		= NIC+0x07, 
	Rbcr0		= NIC+0x0A, 
	Rbcr1		= NIC+0x0B, 
1992/0403/sys/src/9/pc/devether.c:47,651992/0404/sys/src/9/pc/devether.c:58,82
1992/0403    
 
	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, 
1992/0404    
}; 
1992/0403    
 
	RAMbase		= 0xC8000, 
1992/0404    
/* 
 * 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 */ 
}; 
1992/0403    
 
	Nctlr		= 1, 
	NPktype		= 9,		/* types/interface */ 
1992/0404    
struct Ring { 
	uchar	status; 
	uchar	next; 
	ushort	len; 
	uchar	data[BUFsize-4]; 
1992/0403    
}; 
 
/* 
1992/0403/sys/src/9/pc/devether.c:81,891992/0404/sys/src/9/pc/devether.c:98,109
1992/0403    
	QLock; 
 
	Rendez	rr;			/* rendezvous for an input buffer */ 
1992/0404    
	uchar	bnry; 
	uchar	curr; 
	uchar	ovw; 
1992/0403    
	Queue	rq; 
 
	Qlock	xl; 
1992/0404    
	QLock	xl; 
1992/0403    
	Rendez	xr; 
 
	int	iobase;			/* I/O base address */ 
1992/0403/sys/src/9/pc/devether.c:117,1221992/0404/sys/src/9/pc/devether.c:137,144
1992/0403    
	Etherpkt *p; 
	Block *nbp; 
 
1992/0404    
panic("etheroput\n"); 
#ifdef notdef 
1992/0403    
	c = ((Pktype *)q->ptr)->ctlr; 
	if(bp->type == M_CTL){ 
		t = q->ptr; 
1992/0403/sys/src/9/pc/devether.c:126,1331992/0404/sys/src/9/pc/devether.c:148,157
1992/0403    
			t->prom = 1; 
			qlock(c); 
			c->prom++; 
			if(c->prom == 1) 
1992/0404    
			if(c->prom == 1){ 
				outb(t->ctlr->iobase+Cr, 0x22);	/* Page0, RD2|STA */ 
1992/0403    
				outb(c->iobase+Rcr, 0x14);	/* PRO|AB */ 
1992/0404    
			} 
1992/0403    
			qunlock(c); 
		} 
		freeb(bp); 
1992/0403/sys/src/9/pc/devether.c:226,2311992/0404/sys/src/9/pc/devether.c:250,256
1992/0403    
	poperror(); 
 
	enet.outpackets++; 
1992/0404    
#endif 
1992/0403    
} 
 
/* 
1992/0403/sys/src/9/pc/devether.c:237,2531992/0404/sys/src/9/pc/devether.c:262,278
1992/0403    
static void 
etherstopen(Queue *q, Stream *s) 
{ 
	Ctlr *c = &ctlr[0]; 
	Pktype *t; 
1992/0404    
	Ctlr *cp = &ctlr[0]; 
	Pktype *pp; 
1992/0403    
 
	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); 
1992/0404    
	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); 
1992/0403    
} 
 
/* 
1992/0403/sys/src/9/pc/devether.c:259,2811992/0404/sys/src/9/pc/devether.c:284,308
1992/0403    
static void 
etherstclose(Queue *q) 
{ 
	Pktype *t; 
1992/0404    
	Pktype *pp; 
1992/0403    
 
	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); 
1992/0404    
	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); 
1992/0403    
	} 
	qlock(t); 
	t->type = 0; 
	t->q = 0; 
	t->prom = 0; 
	t->inuse = 0; 
	netdisown(&t->ctlr->net, t - t->ctlr->pktype); 
	qunlock(t); 
1992/0404    
	qlock(pp); 
	pp->type = 0; 
	pp->q = 0; 
	pp->prom = 0; 
	pp->inuse = 0; 
	netdisown(&pp->ctlr->net, pp - pp->ctlr->pktype); 
	qunlock(pp); 
1992/0403    
} 
 
static Qinfo info = { 
1992/0403/sys/src/9/pc/devether.c:287,3211992/0404/sys/src/9/pc/devether.c:314,348
1992/0403    
}; 
 
static int 
clonecon(Chan *chan) 
1992/0404    
clonecon(Chan *c) 
1992/0403    
{ 
	Ctlr *c = &ctlr[0]; 
	Pktype *t; 
1992/0404    
	Ctlr *cp = &ctlr[0]; 
	Pktype *pp; 
1992/0403    
 
	for(t = c->pktype; t < &c->pktype[NPktype]; t++){ 
		qlock(t); 
		if(t->inuse || t->q){ 
			qunlock(t); 
1992/0404    
	for(pp = cp->pktype; pp < &cp->pktype[NPktype]; pp++){ 
		qlock(pp); 
		if(pp->inuse || pp->q){ 
			qunlock(pp); 
1992/0403    
			continue; 
		} 
		t->inuse = 1; 
		netown(&c->net, t - c->pktype, u->p->user, 0); 
		qunlock(t); 
		return t - c->pktype; 
1992/0404    
		pp->inuse = 1; 
		netown(&cp->net, pp - cp->pktype, u->p->user, 0); 
		qunlock(pp); 
		return pp - cp->pktype; 
1992/0403    
	} 
	exhausted("ether channels"); 
} 
 
static void 
statsfill(Chan *chan, char *p, int n) 
1992/0404    
statsfill(Chan *c, char *p, int n) 
1992/0403    
{ 
	Ctlr *c = &ctlr[0]; 
1992/0404    
	Ctlr *cp = &ctlr[0]; 
1992/0403    
	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]); 
1992/0404    
		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]); 
1992/0403    
	strncpy(p, buf, n); 
} 
 
1992/0403/sys/src/9/pc/devether.c:323,3321992/0404/sys/src/9/pc/devether.c:350,359
1992/0403    
typefill(Chan *c, char *p, int n) 
{ 
	char buf[16]; 
	Pktype *t; 
1992/0404    
	Pktype *pp; 
1992/0403    
 
	t = &ctlr[0].pktype[STREAMID(c->qid.path)]; 
	sprint(buf, "%d", t->type); 
1992/0404    
	pp = &ctlr[0].pktype[STREAMID(c->qid.path)]; 
	sprint(buf, "%d", pp->type); 
1992/0403    
	strncpy(p, buf, n); 
} 
 
1992/0403/sys/src/9/pc/devether.c:333,4181992/0404/sys/src/9/pc/devether.c:360,554
1992/0403    
static void 
intr(Ureg *ur) 
{ 
	panic("ether intr\n"); 
1992/0404    
	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); 
		} 
	} 
1992/0403    
} 
 
/* 
 * the following initialisation procedure 
 * is mandatory 
 * after this, the chip is still offline 
1992/0404    
 * we leave the chip idling on internal loopback 
1992/0403    
 */ 
static void 
init(Ctlr *c) 
1992/0404    
init(Ctlr *cp) 
1992/0403    
{ 
	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 */ 
1992/0404    
	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 */ 
1992/0403    
 
	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 */ 
1992/0404    
	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); 
1992/0403    
} 
 
void 
etherreset(void) 
{ 
	Ctlr *c = &ctlr[0]; 
1992/0404    
	Ctlr *cp = &ctlr[0]; 
1992/0403    
	int i; 
 
	c->iobase = IObase; 
	init(c); 
1992/0404    
	cp->iobase = IObase; 
	init(cp); 
1992/0403    
	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)); 
1992/0404    
	for(i = 0; i < sizeof(cp->ea); i++) 
		cp->ea[i] = inb(cp->iobase+EA+i); 
	memset(cp->ba, 0xFF, sizeof(cp->ba)); 
1992/0403    
 
	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; 
1992/0404    
	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; 
1992/0403    
} 
 
1992/0404    
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); 
	} 
} 
 
1992/0403    
static int 
isinput(void *arg) 
{ 
	Ctlr *c = arg; 
1992/0404    
	Ctlr *cp = arg; 
1992/0403    
 
	return 0; 
1992/0404    
	return cp->bnry != cp->curr; 
1992/0403    
} 
 
static void 
etherkproc(void *arg) 
{ 
	Ctlr *c = arg; 
1992/0404    
	Ctlr *cp = arg; 
	Block *bp; 
	uchar bnry, curr; 
	Ring *rp; 
1992/0403    
 
	if(waserror()){ 
		print("someone noted %s\n", c->name); 
		c->kproc = 0; 
1992/0404    
		print("%s noted\n", cp->name); 
		init(cp); 
		cp->kproc = 0; 
1992/0403    
		nexterror(); 
	} 
	c->kproc = 1; 
1992/0404    
	cp->kproc = 1; 
1992/0403    
	for(;;){ 
		sleep(&c->rr, isinput, c); 
1992/0404    
		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 
1992/0403    
	} 
} 
 
1992/0403/sys/src/9/pc/devether.c:425,4321992/0404/sys/src/9/pc/devether.c:561,567
1992/0403    
	 * put the receiver online 
	 * and start the kproc 
	 */ 
	outb(c->iobase+Cr, 0x22);	/* Page0, RD2|STA */ 
	outb(c->iobase+Tpsr, 0); 
1992/0404    
	outb(ctlr[ctlrno].iobase+Tcr, 0); 
1992/0403    
	if(ctlr[ctlrno].kproc == 0){ 
		sprint(ctlr[ctlrno].name, "ether%dkproc", ctlrno); 
		kproc(ctlr[ctlrno].name, etherkproc, &ctlr[ctlrno]); 
1992/0404/sys/src/9/pc/devether.c:148,1571992/0405/sys/src/9/pc/devether.c:148,155 (short | long)
1992/0403    
			t->prom = 1; 
			qlock(c); 
			c->prom++; 
1992/0404    
			if(c->prom == 1){ 
				outb(t->ctlr->iobase+Cr, 0x22);	/* Page0, RD2|STA */ 
1992/0405    
			if(c->prom == 1) 
1992/0403    
				outb(c->iobase+Rcr, 0x14);	/* PRO|AB */ 
1992/0404    
			} 
1992/0403    
			qunlock(c); 
		} 
		freeb(bp); 
1992/0404/sys/src/9/pc/devether.c:290,2991992/0405/sys/src/9/pc/devether.c:288,295
1992/0404    
	if(pp->prom){ 
		qlock(pp->ctlr); 
		pp->ctlr->prom--; 
		if(pp->ctlr->prom == 0){ 
			outb(pp->ctlr->iobase+Cr, 0x22);/* Page0, RD2|STA */ 
1992/0405    
		if(pp->ctlr->prom == 0) 
1992/0404    
			outb(pp->ctlr->iobase+Rcr, 0x04);/* AB */ 
		} 
		qunlock(pp->ctlr); 
1992/0403    
	} 
1992/0404    
	qlock(pp); 
1992/0404/sys/src/9/pc/devether.c:363,3691992/0405/sys/src/9/pc/devether.c:359,364
1992/0404    
	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) 
1992/0404/sys/src/9/pc/devether.c:397,4031992/0405/sys/src/9/pc/devether.c:392,398
1992/0404    
		 * 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 
1992/0405    
		 * we must be sure to reset it back to Page0 in case 
1992/0404    
		 * we interrupted some other part of this driver. 
		 */ 
		if(isr & (Ovw|Prx)){ 
1992/0404/sys/src/9/pc/devether.c:411,4181992/0405/sys/src/9/pc/devether.c:406,414
1992/0403    
 
/* 
 * the following initialisation procedure 
 * is mandatory 
1992/0405    
 * is mandatory. 
1992/0404    
 * we leave the chip idling on internal loopback 
1992/0405    
 * and pointing to Page0. 
1992/0403    
 */ 
static void 
1992/0404    
init(Ctlr *cp) 
1992/0405/sys/src/9/pc/devether.c:2,81992/0406/sys/src/9/pc/devether.c:2,12 (short | long)
1992/0403    
 * Western Digital ethernet adapter 
 * BUGS: 
1992/0404    
 *	no more than one controller 
1992/0406    
 * TODO: 
1992/0403    
 *	fix for different controller types 
1992/0406    
 *	output 
 *	deal with stalling and restarting output on input overflow 
 *	fix magic ring constants 
1992/0403    
 */ 
#include "u.h" 
#include "../port/lib.h" 
1992/0405/sys/src/9/pc/devether.c:131,1561992/0406/sys/src/9/pc/devether.c:135,158
1992/0403    
static void 
etheroput(Queue *q, Block *bp) 
{ 
	Ctlr *c; 
1992/0406    
	Ctlr *cp; 
1992/0403    
	int len, n; 
	Pktype *t; 
1992/0406    
	Pktype *pp; 
1992/0403    
	Etherpkt *p; 
	Block *nbp; 
 
1992/0404    
panic("etheroput\n"); 
#ifdef notdef 
1992/0403    
	c = ((Pktype *)q->ptr)->ctlr; 
1992/0406    
	cp = ((Pktype *)q->ptr)->ctlr; 
1992/0403    
	if(bp->type == M_CTL){ 
		t = q->ptr; 
1992/0406    
		pp = q->ptr; 
1992/0403    
		if(streamparse("connect", bp)) 
			t->type = strtol((char *)bp->rptr, 0, 0); 
1992/0406    
			pp->type = strtol((char *)bp->rptr, 0, 0); 
1992/0403    
		else if(streamparse("promiscuous", bp)) { 
			t->prom = 1; 
			qlock(c); 
			c->prom++; 
1992/0405    
			if(c->prom == 1) 
1992/0403    
				outb(c->iobase+Rcr, 0x14);	/* PRO|AB */ 
			qunlock(c); 
1992/0406    
			pp->prom = 1; 
			qlock(cp); 
			cp->prom++; 
			if(cp->prom == 1) 
				outb(cp->iobase+Rcr, 0x14);	/* PRO|AB */ 
			qunlock(cp); 
1992/0403    
		} 
		freeb(bp); 
		return; 
1992/0405/sys/src/9/pc/devether.c:160,1921992/0406/sys/src/9/pc/devether.c:162,191
1992/0403    
	 * give packet a local address, return upstream if destined for 
	 * this machine. 
	 */ 
	if(BLEN(bp) < ETHERHDRSIZE){ 
		bp = pullup(bp, ETHERHDRSIZE); 
		if(bp == 0) 
			return; 
	} 
1992/0406    
	if(BLEN(bp) < ETHERHDRSIZE && (bp = pullup(bp, ETHERHDRSIZE)) == 0) 
		return; 
1992/0403    
	p = (Etherpkt *)bp->rptr; 
	memmove(p->s, c->ea, sizeof(c->ea)); 
	if(memcmp(c->ea, p->d, sizeof(c->ea)) == 0){ 
1992/0406    
	memmove(p->s, cp->ea, sizeof(cp->ea)); 
	if(memcmp(cp->ea, p->d, sizeof(cp->ea)) == 0){ 
1992/0403    
		len = blen(bp); 
		bp = expandb(bp, len >= ETHERMINTU ? len: ETHERMINTU); 
		if(bp){ 
			putq(&c->rq, bp); 
			wakeup(&c->rr); 
1992/0406    
		if (bp = expandb(bp, len >= ETHERMINTU ? len: ETHERMINTU)){ 
			putq(&cp->rq, bp); 
			wakeup(&cp->rr); 
1992/0403    
		} 
		return; 
	} 
	if(memcmp(c->ba, p->d, sizeof(c->ba)) == 0){ 
1992/0406    
	if(memcmp(cp->ba, p->d, sizeof(cp->ba)) == 0){ 
1992/0403    
		len = blen(bp); 
		nbp = copyb(bp, len); 
		nbp = expandb(nbp, len >= ETHERMINTU ? len: ETHERMINTU); 
		if(nbp){ 
1992/0406    
		if(nbp = expandb(nbp, len >= ETHERMINTU ? len: ETHERMINTU)){ 
1992/0403    
			nbp->wptr = nbp->rptr+len; 
			putq(&c->rq, nbp); 
			wakeup(&c->rr); 
1992/0406    
			putq(&cp->rq, nbp); 
			wakeup(&cp->rr); 
1992/0403    
		} 
	} 
 
1992/0406    
panic("etheroput\n"); 
#ifdef notdef 
1992/0403    
	/* 
	 * only one transmitter at a time 
	 */ 
1992/0405/sys/src/9/pc/devether.c:509,5141992/0406/sys/src/9/pc/devether.c:508,525
1992/0404    
	} 
} 
 
1992/0406    
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]); 
} 
 
1992/0403    
static int 
isinput(void *arg) 
{ 
1992/0405/sys/src/9/pc/devether.c:534,5501992/0406/sys/src/9/pc/devether.c:545,578
1992/0404    
	cp->kproc = 1; 
1992/0403    
	for(;;){ 
1992/0404    
		sleep(&cp->rr, isinput, cp); 
1992/0406    
		/* 
		 * process any internal loopback packets 
		 */ 
1992/0404    
		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 
1992/0406    
		/* 
		 * 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); 
		} 
1992/0403    
	} 
} 
 
1992/0406/sys/src/9/pc/devether.c:7,121992/0407/sys/src/9/pc/devether.c:7,13 (short | long)
1992/0406    
 *	output 
 *	deal with stalling and restarting output on input overflow 
 *	fix magic ring constants 
1992/0407    
 *	rewrite per SMC doc 
1992/0403    
 */ 
#include "u.h" 
#include "../port/lib.h" 
1992/0406/sys/src/9/pc/devether.c:79,851992/0407/sys/src/9/pc/devether.c:80,87
1992/0404    
struct Ring { 
	uchar	status; 
	uchar	next; 
	ushort	len; 
1992/0407    
	uchar	len0; 
	uchar	len1; 
1992/0404    
	uchar	data[BUFsize-4]; 
1992/0403    
}; 
 
1992/0406/sys/src/9/pc/devether.c:101,1141992/0407/sys/src/9/pc/devether.c:103,119
1992/0403    
struct Ctlr { 
	QLock; 
 
1992/0407    
	Ring	*ring; 
1992/0403    
	Rendez	rr;			/* rendezvous for an input buffer */ 
1992/0407    
	Queue	rq; 
1992/0404    
	uchar	bnry; 
	uchar	curr; 
	uchar	ovw; 
1992/0403    
	Queue	rq; 
 
1992/0407    
	Etherpkt *xpkt; 
1992/0404    
	QLock	xl; 
1992/0403    
	Rendez	xr; 
1992/0407    
	uchar	xbusy; 
1992/0403    
 
	int	iobase;			/* I/O base address */ 
 
1992/0406/sys/src/9/pc/devether.c:132,1371992/0407/sys/src/9/pc/devether.c:137,150
1992/0403    
}; 
static Ctlr ctlr[Nctlr]; 
 
1992/0407    
static int 
isxfree(void *arg) 
{ 
	Ctlr *cp = arg; 
 
	return cp->xbusy == 0 && cp->ovw == 0; 
} 
 
1992/0403    
static void 
etheroput(Queue *q, Block *bp) 
{ 
1992/0406/sys/src/9/pc/devether.c:184,2051992/0407/sys/src/9/pc/devether.c:197,216
1992/0403    
		} 
	} 
 
1992/0406    
panic("etheroput\n"); 
#ifdef notdef 
1992/0403    
	/* 
	 * only one transmitter at a time 
	 */ 
	qlock(&c->xl); 
1992/0407    
	qlock(&cp->xl); 
1992/0403    
	if(waserror()){ 
		qunlock(&c->xl); 
1992/0407    
		qunlock(&cp->xl); 
1992/0403    
		nexterror(); 
	} 
 
	/* 
	 *  Wait till we get an output buffer 
1992/0407    
	 * Wait till we get an output buffer 
1992/0403    
	 */ 
	sleep(&c->xr, isobuf, c); 
	p = enet.xn; 
1992/0407    
	sleep(&cp->xr, isxfree, cp); 
	p = cp->xpkt; 
1992/0403    
 
	/* 
	 * copy message into buffer 
1992/0406/sys/src/9/pc/devether.c:216,2531992/0407/sys/src/9/pc/devether.c:227,255
1992/0403    
	} 
 
	/* 
	 *  pad the packet (zero the pad) 
1992/0407    
	 * pad the packet (zero the pad) 
1992/0403    
	 */ 
	if(len < ETHERMINTU){ 
		memset(((char*)p)+len, 0, ETHERMINTU-len); 
		len = ETHERMINTU; 
	} 
	enet.xn->len = len; 
 
	/* 
	 *  give packet a local address 
1992/0407    
	 * give packet a local address 
1992/0403    
	 */ 
	memmove(p->s, enet.ea, sizeof(enet.ea)); 
1992/0407    
	memmove(p->s, cp->ea, sizeof(cp->ea)); 
1992/0403    
 
	/* 
	 *  give to Chip 
1992/0407    
	 * start the transmission 
1992/0403    
	 */ 
	splhi();		/* sync with interrupt routine */ 
	enet.xn->owner = Chip; 
	if(enet.xmting == 0) 
		ethersend(enet.xn); 
	spllo(); 
1992/0407    
	outb(cp->iobase+Tbcr0, len & 0xFF); 
	outb(cp->iobase+Tbcr1, (len>>8) & 0xFF); 
	outb(cp->iobase+Cr, 0x26);			/* Page0|TXP|STA */ 
	cp->xbusy = 1; 
1992/0403    
 
	/* 
	 *  send 
	 */ 
	enet.xn = XSUCC(enet.xn); 
	freeb(bp); 
	qunlock(&enet.xl); 
1992/0407    
	qunlock(&cp->xl); 
1992/0403    
	poperror(); 
                 
	enet.outpackets++; 
1992/0404    
#endif 
1992/0403    
} 
 
/* 
1992/0406/sys/src/9/pc/devether.c:370,3761992/0407/sys/src/9/pc/devether.c:372,379
1992/0404    
		if(isr & Ptx) 
			cp->outpackets++; 
		if(isr & (Txe|Ptx)){ 
			panic("tx intr\n"); 
1992/0407    
			cp->xbusy = 0; 
			wakeup(&cp->xr); 
1992/0404    
		} 
		/* 
		 * the receive ring is full. 
1992/0406/sys/src/9/pc/devether.c:422,4271992/0407/sys/src/9/pc/devether.c:425,431
1992/0404    
	outb(cp->iobase+Tcr, 0x20);		/* LB0 */ 
	outb(cp->iobase+Bnry, 6); 
	cp->bnry = 6; 
1992/0407    
	cp->ring = (Ring*)(KZERO|RAMbase); 
1992/0404    
	outb(cp->iobase+Pstart, 6);		/* 6*256 */ 
	outb(cp->iobase+Pstop, 32);		/* 8*1024/256 */ 
	outb(cp->iobase+Isr, 0xFF); 
1992/0406/sys/src/9/pc/devether.c:435,4401992/0407/sys/src/9/pc/devether.c:439,445
1992/0404    
 
	outb(cp->iobase+Cr, 0x22);		/* Page0, RD2|STA */ 
	outb(cp->iobase+Tpsr, 0); 
1992/0407    
	cp->xpkt = (Etherpkt*)(KZERO|RAMbase); 
1992/0403    
} 
 
void 
1992/0406/sys/src/9/pc/devether.c:556,5691992/0407/sys/src/9/pc/devether.c:561,573
1992/0406    
		/* 
		 * process any received packets 
		 */ 
		bnry = inb(cp->iobase+Bnry); 
		while(bnry != cp->curr){ 
			rp = &((Ring*)RAMbase)[bnry]; 
printpkt(bnry, rp->len, (Etherpkt*)rp->data); 
1992/0407    
		cp->bnry = inb(cp->iobase+Bnry); 
		while(cp->bnry != cp->curr){ 
			rp = &cp->ring[cp->bnry]; 
1992/0406    
			cp->inpackets++; 
			etherup(cp, (Etherpkt*)rp->data, rp->len-4); 
			bnry = rp->next; 
			outb(cp->iobase+Bnry, bnry); 
1992/0407    
			etherup(cp, (Etherpkt*)rp->data, ((rp->len1<<8)+rp->len0)-4); 
			cp->bnry = rp->next; 
			outb(cp->iobase+Bnry, cp->bnry); 
1992/0406    
		} 
		/* 
		 * if we idled input because of overflow, 
1992/0406/sys/src/9/pc/devether.c:572,5771992/0407/sys/src/9/pc/devether.c:576,582
1992/0406    
		if(cp->ovw){ 
			cp->ovw = 0; 
			outb(cp->iobase+Tcr, 0); 
1992/0407    
			wakeup(&cp->xr); 
1992/0406    
		} 
1992/0403    
	} 
} 
1992/0407/sys/src/9/pc/devether.c:32,371992/0408/sys/src/9/pc/devether.c:32,40 (short | long)
1992/0404    
	NPktype		= 9,		/* types/interface */ 
}; 
 
1992/0408    
#define NEXT(x, l)	((((x)+1)%(l)) == 0 ? 6: (((x)+1)%(l))) 
#define PREV(x, l)	(((x)-1) == 5 ? (l-1): ((x)-1)) 
 
1992/0404    
/* 
 * register offsets from IObase 
 */ 
1992/0407/sys/src/9/pc/devether.c:389,3941992/0408/sys/src/9/pc/devether.c:392,398
1992/0404    
			outb(cp->iobase+Tcr, 0x20);	/* LB0 */ 
			outb(cp->iobase+Cr, 0x22);	/* Page0, RD2|STA */ 
			cp->ovw = 1; 
1992/0408    
			cp->overflows++; 
1992/0404    
		} 
		/* 
		 * we have received packets. 
1992/0407/sys/src/9/pc/devether.c:423,4301992/0408/sys/src/9/pc/devether.c:427,434
1992/0404    
	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; 
1992/0408    
	outb(cp->iobase+Bnry, cp->bnry); 
1992/0407    
	cp->ring = (Ring*)(KZERO|RAMbase); 
1992/0404    
	outb(cp->iobase+Pstart, 6);		/* 6*256 */ 
	outb(cp->iobase+Pstop, 32);		/* 8*1024/256 */ 
1992/0407/sys/src/9/pc/devether.c:434,4411992/0408/sys/src/9/pc/devether.c:438,445
1992/0404    
	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; 
1992/0408    
	cp->curr = cp->bnry+1; 
	outb(cp->iobase+Curr, cp->curr); 
1992/0404    
 
	outb(cp->iobase+Cr, 0x22);		/* Page0, RD2|STA */ 
	outb(cp->iobase+Tpsr, 0); 
1992/0407/sys/src/9/pc/devether.c:449,4591992/0408/sys/src/9/pc/devether.c:453,462
1992/0403    
	int i; 
 
1992/0404    
	cp->iobase = IObase; 
	init(cp); 
1992/0403    
	setvec(Ethervec, intr); 
                 
1992/0404    
	for(i = 0; i < sizeof(cp->ea); i++) 
		cp->ea[i] = inb(cp->iobase+EA+i); 
1992/0408    
	init(cp); 
	setvec(Ethervec, intr); 
1992/0404    
	memset(cp->ba, 0xFF, sizeof(cp->ba)); 
1992/0403    
 
1992/0404    
	cp->net.name = "ether"; 
1992/0407/sys/src/9/pc/devether.c:530,5361992/0408/sys/src/9/pc/devether.c:533,539
1992/0403    
{ 
1992/0404    
	Ctlr *cp = arg; 
1992/0403    
 
1992/0404    
	return cp->bnry != cp->curr; 
1992/0408    
	return NEXT(cp->bnry, 32) != cp->curr; 
1992/0403    
} 
 
static void 
1992/0407/sys/src/9/pc/devether.c:558,5741992/0408/sys/src/9/pc/devether.c:561,580
1992/0404    
			etherup(cp, (Etherpkt*)bp->rptr, BLEN(bp)); 
			freeb(bp); 
		} 
1992/0408    
 
1992/0406    
		/* 
		 * process any received packets 
		 */ 
1992/0407    
		cp->bnry = inb(cp->iobase+Bnry); 
		while(cp->bnry != cp->curr){ 
			rp = &cp->ring[cp->bnry]; 
1992/0408    
		bnry = NEXT(cp->bnry, 32); 
		while(bnry != cp->curr){ 
			rp = &cp->ring[bnry]; 
1992/0406    
			cp->inpackets++; 
1992/0407    
			etherup(cp, (Etherpkt*)rp->data, ((rp->len1<<8)+rp->len0)-4); 
			cp->bnry = rp->next; 
1992/0408    
			bnry = rp->next; 
			cp->bnry = PREV(bnry, 32); 
1992/0407    
			outb(cp->iobase+Bnry, cp->bnry); 
1992/0406    
		} 
1992/0408    
 
1992/0406    
		/* 
		 * if we idled input because of overflow, 
		 * restart 
1992/0408/sys/src/9/pc/devether.c:111,1171992/0409/sys/src/9/pc/devether.c:111,116 (short | long)
1992/0407    
	Queue	rq; 
1992/0404    
	uchar	bnry; 
	uchar	curr; 
	uchar	ovw; 
1992/0403    
 
1992/0407    
	Etherpkt *xpkt; 
1992/0404    
	QLock	xl; 
1992/0408/sys/src/9/pc/devether.c:145,1511992/0409/sys/src/9/pc/devether.c:144,150
1992/0407    
{ 
	Ctlr *cp = arg; 
 
	return cp->xbusy == 0 && cp->ovw == 0; 
1992/0409    
	return cp->xbusy == 0; 
1992/0407    
} 
 
1992/0403    
static void 
1992/0408/sys/src/9/pc/devether.c:378,3991992/0409/sys/src/9/pc/devether.c:377,384
1992/0407    
			cp->xbusy = 0; 
			wakeup(&cp->xr); 
1992/0404    
		} 
		/* 
		 * 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; 
1992/0409    
		if(isr & Ovw) 
1992/0408    
			cp->overflows++; 
1992/0404    
		} 
		/* 
		 * we have received packets. 
		 * this is the only place, other than the init code, 
1992/0408/sys/src/9/pc/devether.c:404,4091992/0409/sys/src/9/pc/devether.c:389,396
1992/0404    
		if(isr & (Ovw|Prx)){ 
			outb(cp->iobase+Cr, 0x62);	/* Page1, RD2|STA */ 
			cp->curr = inb(cp->iobase+Curr); 
1992/0409    
if(cp->curr == 0) 
    print("C0: b%d i%ux\n", cp->bnry, isr); 
1992/0404    
			outb(cp->iobase+Cr, 0x22);	/* Page0, RD2|STA */ 
			wakeup(&cp->rr); 
		} 
1992/0408/sys/src/9/pc/devether.c:451,4581992/0409/sys/src/9/pc/devether.c:438,451
1992/0403    
{ 
1992/0404    
	Ctlr *cp = &ctlr[0]; 
1992/0403    
	int i; 
1992/0409    
	uchar msr; 
1992/0403    
 
1992/0404    
	cp->iobase = IObase; 
1992/0409    
	msr = 0x40|inb(cp->iobase); 
	outb(cp->iobase, msr); 
for(i = 0; i < 0x10; i++) 
    print("#%2.2ux ", inb(cp->iobase+i)); 
print("\n"); 
1992/0404    
	for(i = 0; i < sizeof(cp->ea); i++) 
		cp->ea[i] = inb(cp->iobase+EA+i); 
1992/0408    
	init(cp); 
1992/0408/sys/src/9/pc/devether.c:574,5891992/0409/sys/src/9/pc/devether.c:567,572
1992/0408    
			cp->bnry = PREV(bnry, 32); 
1992/0407    
			outb(cp->iobase+Bnry, cp->bnry); 
1992/0406    
		} 
1992/0408    
                 
1992/0406    
		/* 
		 * if we idled input because of overflow, 
		 * restart 
		 */ 
		if(cp->ovw){ 
			cp->ovw = 0; 
			outb(cp->iobase+Tcr, 0); 
1992/0407    
			wakeup(&cp->xr); 
1992/0406    
		} 
1992/0403    
	} 
} 
 
1992/0408/sys/src/9/pc/devether.c:668,6711992/0409/sys/src/9/pc/devether.c:651,674
1992/0403    
etherwrite(Chan *c, char *a, long n, ulong offset) 
{ 
	return streamwrite(c, a, n, 0); 
1992/0409    
} 
 
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); 
1992/0403    
} 
1992/0409/sys/src/9/pc/devether.c:18,391992/0410/sys/src/9/pc/devether.c:18,44 (short | long)
1992/0403    
#include "io.h" 
#include "devtab.h" 
 
1992/0410    
static int debug; 
 
1992/0403    
typedef struct Ctlr Ctlr; 
typedef struct Pktype Pktype; 
1992/0410    
typedef struct Type Type; 
1992/0404    
typedef struct Ring Ring; 
1992/0403    
 
enum { 
	IObase		= 0x360, 
1992/0404    
	RAMbase		= 0xC8000, 
1992/0410    
	RAMbase		= 0xD0000, 
1992/0404    
	RAMsize		= 8*1024, 
	BUFsize		= 256, 
1992/0403    
 
1992/0410    
	RINGbase	= 6,		/* gak */ 
	RINGsize	= 32,		/* gak */ 
 
1992/0404    
	Nctlr		= 1, 
	NPktype		= 9,		/* types/interface */ 
1992/0410    
	NType		= 9,		/* types/interface */ 
1992/0404    
}; 
 
1992/0408    
#define NEXT(x, l)	((((x)+1)%(l)) == 0 ? 6: (((x)+1)%(l))) 
#define PREV(x, l)	(((x)-1) == 5 ? (l-1): ((x)-1)) 
1992/0410    
#define NEXT(x, l)	((((x)+1)%(l)) == 0 ? RINGbase: (((x)+1)%(l))) 
#define PREV(x, l)	(((x)-1) < RINGbase ? (l-1): ((x)-1)) 
1992/0408    
 
1992/0404    
/* 
 * register offsets from IObase 
1992/0409/sys/src/9/pc/devether.c:77,831992/0410/sys/src/9/pc/devether.c:82,87
1992/0404    
	Rxe		= 0x04,		/*	receive error */ 
	Txe		= 0x08,		/*	transmit error */ 
	Ovw		= 0x10,		/*	overwrite warning */ 
	Rst		= 0x80,		/*	reset status */ 
}; 
1992/0403    
 
1992/0404    
struct Ring { 
1992/0409/sys/src/9/pc/devether.c:91,971992/0410/sys/src/9/pc/devether.c:95,101
1992/0403    
/* 
 * one per ethernet packet type 
 */ 
struct Pktype { 
1992/0410    
struct Type { 
1992/0403    
	QLock; 
	int	type;			/* ethernet type */ 
	int	prom;			/* promiscuous mode */ 
1992/0409/sys/src/9/pc/devether.c:119,1251992/0410/sys/src/9/pc/devether.c:123,129
1992/0403    
 
	int	iobase;			/* I/O base address */ 
 
	Pktype	pktype[NPktype]; 
1992/0410    
	Type	type[NType]; 
1992/0403    
	uchar	ea[6]; 
	uchar	ba[6]; 
 
1992/0409/sys/src/9/pc/devether.c:127,1331992/0410/sys/src/9/pc/devether.c:131,137
1992/0403    
	uchar	kproc;			/* true if kproc started */ 
	char	name[NAMELEN];		/* name of kproc */ 
	Network	net; 
	Netprot	prot[NPktype]; 
1992/0410    
	Netprot	prot[NType]; 
1992/0403    
 
	int	inpackets; 
	int	outpackets; 
1992/0409/sys/src/9/pc/devether.c:152,1681992/0410/sys/src/9/pc/devether.c:156,172
1992/0403    
{ 
1992/0406    
	Ctlr *cp; 
1992/0403    
	int len, n; 
1992/0406    
	Pktype *pp; 
1992/0410    
	Type *tp; 
1992/0403    
	Etherpkt *p; 
	Block *nbp; 
 
1992/0406    
	cp = ((Pktype *)q->ptr)->ctlr; 
1992/0410    
	cp = ((Type *)q->ptr)->ctlr; 
1992/0403    
	if(bp->type == M_CTL){ 
1992/0406    
		pp = q->ptr; 
1992/0410    
		tp = q->ptr; 
1992/0403    
		if(streamparse("connect", bp)) 
1992/0406    
			pp->type = strtol((char *)bp->rptr, 0, 0); 
1992/0410    
			tp->type = strtol((char *)bp->rptr, 0, 0); 
1992/0403    
		else if(streamparse("promiscuous", bp)) { 
1992/0406    
			pp->prom = 1; 
1992/0410    
			tp->prom = 1; 
1992/0406    
			qlock(cp); 
			cp->prom++; 
			if(cp->prom == 1) 
1992/0409/sys/src/9/pc/devether.c:264,2791992/0410/sys/src/9/pc/devether.c:268,283
1992/0403    
etherstopen(Queue *q, Stream *s) 
{ 
1992/0404    
	Ctlr *cp = &ctlr[0]; 
	Pktype *pp; 
1992/0410    
	Type *tp; 
1992/0403    
 
1992/0404    
	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); 
1992/0410    
	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); 
1992/0403    
} 
 
/* 
1992/0409/sys/src/9/pc/devether.c:285,3071992/0410/sys/src/9/pc/devether.c:289,311
1992/0403    
static void 
etherstclose(Queue *q) 
{ 
1992/0404    
	Pktype *pp; 
1992/0410    
	Type *tp; 
1992/0403    
 
1992/0404    
	pp = (Pktype *)(q->ptr); 
	if(pp->prom){ 
		qlock(pp->ctlr); 
		pp->ctlr->prom--; 
1992/0405    
		if(pp->ctlr->prom == 0) 
1992/0404    
			outb(pp->ctlr->iobase+Rcr, 0x04);/* AB */ 
		qunlock(pp->ctlr); 
1992/0410    
	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); 
1992/0403    
	} 
1992/0404    
	qlock(pp); 
	pp->type = 0; 
	pp->q = 0; 
	pp->prom = 0; 
	pp->inuse = 0; 
	netdisown(&pp->ctlr->net, pp - pp->ctlr->pktype); 
	qunlock(pp); 
1992/0410    
	qlock(tp); 
	tp->type = 0; 
	tp->q = 0; 
	tp->prom = 0; 
	tp->inuse = 0; 
	netdisown(&tp->ctlr->net, tp - tp->ctlr->type); 
	qunlock(tp); 
1992/0403    
} 
 
static Qinfo info = { 
1992/0409/sys/src/9/pc/devether.c:316,3331992/0410/sys/src/9/pc/devether.c:320,337
1992/0404    
clonecon(Chan *c) 
1992/0403    
{ 
1992/0404    
	Ctlr *cp = &ctlr[0]; 
	Pktype *pp; 
1992/0410    
	Type *tp; 
1992/0403    
 
1992/0404    
	for(pp = cp->pktype; pp < &cp->pktype[NPktype]; pp++){ 
		qlock(pp); 
		if(pp->inuse || pp->q){ 
			qunlock(pp); 
1992/0410    
	for(tp = cp->type; tp < &cp->type[NType]; tp++){ 
		qlock(tp); 
		if(tp->inuse || tp->q){ 
			qunlock(tp); 
1992/0403    
			continue; 
		} 
1992/0404    
		pp->inuse = 1; 
		netown(&cp->net, pp - cp->pktype, u->p->user, 0); 
		qunlock(pp); 
		return pp - cp->pktype; 
1992/0410    
		tp->inuse = 1; 
		netown(&cp->net, tp - cp->type, u->p->user, 0); 
		qunlock(tp); 
		return tp - cp->type; 
1992/0403    
	} 
	exhausted("ether channels"); 
} 
1992/0409/sys/src/9/pc/devether.c:349,3581992/0410/sys/src/9/pc/devether.c:353,362
1992/0403    
typefill(Chan *c, char *p, int n) 
{ 
	char buf[16]; 
1992/0404    
	Pktype *pp; 
1992/0410    
	Type *tp; 
1992/0403    
 
1992/0404    
	pp = &ctlr[0].pktype[STREAMID(c->qid.path)]; 
	sprint(buf, "%d", pp->type); 
1992/0410    
	tp = &ctlr[0].type[STREAMID(c->qid.path)]; 
	sprint(buf, "%d", tp->type); 
1992/0403    
	strncpy(p, buf, n); 
} 
 
1992/0409/sys/src/9/pc/devether.c:360,3661992/0410/sys/src/9/pc/devether.c:364,370
1992/0403    
intr(Ureg *ur) 
{ 
1992/0404    
	Ctlr *cp = &ctlr[0]; 
	uchar isr, curr; 
1992/0410    
	uchar isr, bnry, curr; 
1992/0404    
 
	while(isr = inb(cp->iobase+Isr)){ 
		outb(cp->iobase+Isr, isr); 
1992/0409/sys/src/9/pc/devether.c:369,3751992/0410/sys/src/9/pc/devether.c:373,379
1992/0404    
		if(isr & Rxe){ 
			cp->frames += inb(cp->iobase+Cntr0); 
			cp->crcs += inb(cp->iobase+Cntr1); 
			cp->buffs += inb(cp->iobase+Cntr2); 
1992/0410    
			cp->overflows += inb(cp->iobase+Cntr2); 
1992/0404    
		} 
		if(isr & Ptx) 
			cp->outpackets++; 
1992/0409/sys/src/9/pc/devether.c:377,3841992/0410/sys/src/9/pc/devether.c:381,391
1992/0407    
			cp->xbusy = 0; 
			wakeup(&cp->xr); 
1992/0404    
		} 
1992/0409    
		if(isr & Ovw) 
1992/0408    
			cp->overflows++; 
1992/0410    
		if(isr & Ovw){ 
			bnry = inb(cp->iobase+Bnry); 
			outb(cp->iobase+bnry, bnry); 
			cp->buffs++; 
		} 
1992/0404    
		/* 
		 * we have received packets. 
		 * this is the only place, other than the init code, 
1992/0409/sys/src/9/pc/devether.c:386,3971992/0410/sys/src/9/pc/devether.c:393,404
1992/0405    
		 * we must be sure to reset it back to Page0 in case 
1992/0404    
		 * we interrupted some other part of this driver. 
		 */ 
		if(isr & (Ovw|Prx)){ 
1992/0410    
		if(isr & (Rxe|Prx)){ 
1992/0404    
			outb(cp->iobase+Cr, 0x62);	/* Page1, RD2|STA */ 
			cp->curr = inb(cp->iobase+Curr); 
1992/0409    
if(cp->curr == 0) 
    print("C0: b%d i%ux\n", cp->bnry, isr); 
1992/0404    
			outb(cp->iobase+Cr, 0x22);	/* Page0, RD2|STA */ 
1992/0410    
if(debug) 
    print("I%d/%d/%d|", isr, cp->curr, cp->bnry); 
1992/0404    
			wakeup(&cp->rr); 
		} 
	} 
1992/0409/sys/src/9/pc/devether.c:414,4241992/0410/sys/src/9/pc/devether.c:421,431
1992/0404    
	outb(cp->iobase+Rbcr1, 0); 
	outb(cp->iobase+Rcr, 0x04);		/* AB */ 
	outb(cp->iobase+Tcr, 0x20);		/* LB0 */ 
	cp->bnry = 6; 
1992/0410    
	cp->bnry = RINGbase; 
1992/0408    
	outb(cp->iobase+Bnry, cp->bnry); 
1992/0407    
	cp->ring = (Ring*)(KZERO|RAMbase); 
1992/0404    
	outb(cp->iobase+Pstart, 6);		/* 6*256 */ 
	outb(cp->iobase+Pstop, 32);		/* 8*1024/256 */ 
1992/0410    
	outb(cp->iobase+Pstart, RINGbase); 
	outb(cp->iobase+Pstop, RINGsize); 
1992/0404    
	outb(cp->iobase+Isr, 0xFF); 
	outb(cp->iobase+Imr, 0x1F);		/* OVWE|TXEE|RXEE|PTXE|PRXE */ 
1992/0403    
 
1992/0409/sys/src/9/pc/devether.c:443,4511992/0410/sys/src/9/pc/devether.c:450,462
1992/0404    
	cp->iobase = IObase; 
1992/0409    
	msr = 0x40|inb(cp->iobase); 
	outb(cp->iobase, msr); 
1992/0410    
msr=0x40|inb(cp->iobase+0x05); 
outb(cp->iobase+0x05, msr); 
1992/0409    
for(i = 0; i < 0x10; i++) 
    print("#%2.2ux ", inb(cp->iobase+i)); 
print("\n"); 
1992/0410    
msr=0x40|inb(cp->iobase+0x05); 
outb(cp->iobase+0x05, msr); 
1992/0404    
	for(i = 0; i < sizeof(cp->ea); i++) 
		cp->ea[i] = inb(cp->iobase+EA+i); 
1992/0408    
	init(cp); 
1992/0409/sys/src/9/pc/devether.c:453,4591992/0410/sys/src/9/pc/devether.c:464,470
1992/0404    
	memset(cp->ba, 0xFF, sizeof(cp->ba)); 
1992/0403    
 
1992/0404    
	cp->net.name = "ether"; 
	cp->net.nconv = NPktype; 
1992/0410    
	cp->net.nconv = NType; 
1992/0404    
	cp->net.devp = &info; 
	cp->net.protop = 0; 
	cp->net.listen = 0; 
1992/0409/sys/src/9/pc/devether.c:467,4901992/0410/sys/src/9/pc/devether.c:478,503
1992/0403    
} 
 
1992/0404    
static void 
etherup(Ctlr *cp, Etherpkt *p, int len) 
1992/0410    
etherup(Ctlr *cp, uchar *d0, int len0, uchar *d1, int len1) 
1992/0404    
{ 
1992/0410    
	Etherpkt *p; 
1992/0404    
	Block *bp; 
	Pktype *pp; 
1992/0410    
	Type *tp; 
1992/0404    
	int t; 
 
	t = (p->type[0]<<8) | p->type[1]; 
	for(pp = &cp->pktype[0]; pp < &cp->pktype[NPktype]; pp++){ 
1992/0410    
	p = (Etherpkt*)d0; 
	t = (p->type[0]<<8)|p->type[1]; 
	for(tp = &cp->type[0]; tp < &cp->type[NType]; tp++){ 
1992/0404    
		/* 
		 *  check before locking just to save a lock 
		 */ 
		if(pp->q == 0 || (t != pp->type && pp->type != -1)) 
1992/0410    
		if(tp->q == 0 || (t != tp->type && tp->type != -1)) 
1992/0404    
			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))) 
1992/0410    
		if(tp->type != -1 && p->d[0] != 0xFF && memcmp(p->d, cp->ea, sizeof(p->d))) 
1992/0404    
			continue; 
 
		/* 
1992/0409/sys/src/9/pc/devether.c:491,5111992/0410/sys/src/9/pc/devether.c:504,526
1992/0404    
		 *  check after locking to make sure things didn't 
		 *  change under foot 
		 */ 
		if(canqlock(pp) == 0) 
1992/0410    
		if(canqlock(tp) == 0) 
1992/0404    
			continue; 
		if(pp->q == 0 || pp->q->next->len > Streamhi || (t != pp->type && pp->type != -1)){ 
			qunlock(pp); 
1992/0410    
		if(tp->q == 0 || tp->q->next->len > Streamhi || (t != tp->type && tp->type != -1)){ 
			qunlock(tp); 
1992/0404    
			continue; 
		} 
		if(waserror() == 0){ 
			bp = allocb(len); 
			memmove(bp->rptr, (uchar *)p, len); 
			bp->wptr += len; 
1992/0410    
			bp = allocb(len0+len1); 
			memmove(bp->rptr, d0, len0); 
			if(len1) 
				memmove(bp->rptr+len0, d1, len1); 
			bp->wptr += len0+len1; 
1992/0404    
			bp->flags |= S_DELIM; 
			PUTNEXT(pp->q, bp); 
1992/0410    
			PUTNEXT(tp->q, bp); 
1992/0404    
		} 
		poperror(); 
		qunlock(pp); 
1992/0410    
		qunlock(tp); 
1992/0404    
	} 
} 
 
1992/0409/sys/src/9/pc/devether.c:526,5321992/0410/sys/src/9/pc/devether.c:541,547
1992/0403    
{ 
1992/0404    
	Ctlr *cp = arg; 
1992/0403    
 
1992/0408    
	return NEXT(cp->bnry, 32) != cp->curr; 
1992/0410    
	return NEXT(cp->bnry, RINGsize) != cp->curr; 
1992/0403    
} 
 
static void 
1992/0409/sys/src/9/pc/devether.c:536,5411992/0410/sys/src/9/pc/devether.c:551,557
1992/0404    
	Block *bp; 
	uchar bnry, curr; 
	Ring *rp; 
1992/0410    
	int len0, len1; 
1992/0403    
 
	if(waserror()){ 
1992/0404    
		print("%s noted\n", cp->name); 
1992/0409/sys/src/9/pc/devether.c:551,5571992/0410/sys/src/9/pc/devether.c:567,573
1992/0406    
		 */ 
1992/0404    
		while(bp = getq(&cp->rq)){ 
			cp->inpackets++; 
			etherup(cp, (Etherpkt*)bp->rptr, BLEN(bp)); 
1992/0410    
			etherup(cp, bp->rptr, BLEN(bp), 0, 0); 
1992/0404    
			freeb(bp); 
		} 
1992/0408    
 
1992/0409/sys/src/9/pc/devether.c:558,5701992/0410/sys/src/9/pc/devether.c:574,599
1992/0406    
		/* 
		 * process any received packets 
		 */ 
1992/0408    
		bnry = NEXT(cp->bnry, 32); 
1992/0410    
		bnry = NEXT(cp->bnry, RINGsize); 
1992/0408    
		while(bnry != cp->curr){ 
			rp = &cp->ring[bnry]; 
1992/0406    
			cp->inpackets++; 
1992/0407    
			etherup(cp, (Etherpkt*)rp->data, ((rp->len1<<8)+rp->len0)-4); 
1992/0410    
			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)); 
1992/0408    
			bnry = rp->next; 
			cp->bnry = PREV(bnry, 32); 
1992/0410    
			cp->bnry = PREV(bnry, RINGsize); 
1992/0407    
			outb(cp->iobase+Bnry, cp->bnry); 
1992/0406    
		} 
1992/0403    
	} 
1992/0409/sys/src/9/pc/devether.c:661,6661992/0410/sys/src/9/pc/devether.c:690,696
1992/0409    
	int s; 
 
	s = splhi(); 
1992/0410    
debug++; 
1992/0409    
	bnry = inb(cp->iobase+Bnry); 
	outb(cp->iobase+Cr, 0x62);			/* Page1, RD2|STA */ 
	curr = inb(cp->iobase+Curr); 
1992/0409/sys/src/9/pc/devether.c:668,6741992/0410/sys/src/9/pc/devether.c:698,704
1992/0409    
	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, 
1992/0410    
	print("\t%d %d %d %d %d %d %d\n", cp->inpackets, cp->outpackets, 
1992/0409    
	    cp->crcs, cp->oerrs, cp->frames, cp->overflows, cp->buffs); 
	splx(s); 
1992/0403    
} 
1992/0410/sys/src/9/pc/devether.c:26,321992/0411/sys/src/9/pc/devether.c:26,32 (short | long)
1992/0403    
 
enum { 
	IObase		= 0x360, 
1992/0410    
	RAMbase		= 0xD0000, 
1992/0411    
	RAMbase		= 0xC8000, 
1992/0404    
	RAMsize		= 8*1024, 
	BUFsize		= 256, 
1992/0403    
 
1992/0410/sys/src/9/pc/devether.c:143,1481992/0411/sys/src/9/pc/devether.c:143,172
1992/0403    
}; 
static Ctlr ctlr[Nctlr]; 
 
1992/0411    
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); 
} 
 
1992/0407    
static int 
isxfree(void *arg) 
{ 
1992/0410/sys/src/9/pc/devether.c:208,2131992/0411/sys/src/9/pc/devether.c:232,238
1992/0403    
	 */ 
1992/0407    
	qlock(&cp->xl); 
1992/0403    
	if(waserror()){ 
1992/0411    
		freeb(bp); 
1992/0407    
		qunlock(&cp->xl); 
1992/0403    
		nexterror(); 
	} 
1992/0410/sys/src/9/pc/devether.c:215,2221992/0411/sys/src/9/pc/devether.c:240,249
1992/0403    
	/* 
1992/0407    
	 * Wait till we get an output buffer 
1992/0403    
	 */ 
1992/0407    
	sleep(&cp->xr, isxfree, cp); 
	p = cp->xpkt; 
1992/0411    
	tsleep(&cp->xr, isxfree, cp, 1000); 
	if(isxfree(cp) == 0) 
		print("Tx wedged\n"); 
	p = &txpkt; 
1992/0403    
 
	/* 
	 * copy message into buffer 
1992/0410/sys/src/9/pc/devether.c:244,2491992/0411/sys/src/9/pc/devether.c:271,277
1992/0407    
	 * give packet a local address 
1992/0403    
	 */ 
1992/0407    
	memmove(p->s, cp->ea, sizeof(cp->ea)); 
1992/0411    
	xmemmove(cp->xpkt, p, len); 
1992/0403    
 
	/* 
1992/0407    
	 * start the transmission 
1992/0410/sys/src/9/pc/devether.c:445,4621992/0411/sys/src/9/pc/devether.c:473,488
1992/0403    
{ 
1992/0404    
	Ctlr *cp = &ctlr[0]; 
1992/0403    
	int i; 
1992/0409    
	uchar msr; 
1992/0411    
	uchar reg; 
1992/0403    
 
1992/0404    
	cp->iobase = IObase; 
1992/0409    
	msr = 0x40|inb(cp->iobase); 
	outb(cp->iobase, msr); 
1992/0410    
msr=0x40|inb(cp->iobase+0x05); 
outb(cp->iobase+0x05, msr); 
1992/0411    
	reg = 0x40|inb(cp->iobase); 
	outb(cp->iobase, reg); 
	reg = 0x40|inb(cp->iobase+0x05); 
	outb(cp->iobase+0x05, reg); 
1992/0409    
for(i = 0; i < 0x10; i++) 
    print("#%2.2ux ", inb(cp->iobase+i)); 
print("\n"); 
1992/0410    
msr=0x40|inb(cp->iobase+0x05); 
outb(cp->iobase+0x05, msr); 
1992/0404    
	for(i = 0; i < sizeof(cp->ea); i++) 
		cp->ea[i] = inb(cp->iobase+EA+i); 
1992/0408    
	init(cp); 
1992/0410/sys/src/9/pc/devether.c:512,5201992/0411/sys/src/9/pc/devether.c:538,546
1992/0404    
		} 
		if(waserror() == 0){ 
1992/0410    
			bp = allocb(len0+len1); 
			memmove(bp->rptr, d0, len0); 
1992/0411    
			xmemmove(bp->rptr, d0, len0); 
1992/0410    
			if(len1) 
				memmove(bp->rptr+len0, d1, len1); 
1992/0411    
				xmemmove(bp->rptr+len0, d1, len1); 
1992/0410    
			bp->wptr += len0+len1; 
1992/0404    
			bp->flags |= S_DELIM; 
1992/0410    
			PUTNEXT(tp->q, bp); 
1992/0410/sys/src/9/pc/devether.c:683,6891992/0411/sys/src/9/pc/devether.c:709,715
1992/0409    
} 
 
void 
etherdump(void) 
1992/0411    
consdebug(void) 
1992/0409    
{ 
	Ctlr *cp = &ctlr[0]; 
	uchar bnry, curr, isr; 
1992/0411/sys/src/9/pc/devether.c:1,141992/0424/sys/src/9/pc/devether.c:1,3 (short | long)
1992/0403    
/* 
 * Western Digital ethernet adapter 
 * BUGS: 
1992/0404    
 *	no more than one controller 
1992/0406    
 * TODO: 
1992/0403    
 *	fix for different controller types 
1992/0406    
 *	output 
 *	deal with stalling and restarting output on input overflow 
 *	fix magic ring constants 
1992/0407    
 *	rewrite per SMC doc 
1992/0403    
 */ 
#include "u.h" 
#include "../port/lib.h" 
#include "mem.h" 
1992/0411/sys/src/9/pc/devether.c:18,971992/0424/sys/src/9/pc/devether.c:7,56
1992/0403    
#include "io.h" 
#include "devtab.h" 
 
1992/0410    
static int debug; 
                 
1992/0403    
typedef struct Ctlr Ctlr; 
1992/0424    
typedef struct Hw Hw; 
typedef struct Buffer Buffer; 
1992/0410    
typedef struct Type Type; 
1992/0404    
typedef struct Ring Ring; 
1992/0424    
typedef struct Ctlr Ctlr; 
1992/0403    
 
enum { 
	IObase		= 0x360, 
1992/0411    
	RAMbase		= 0xC8000, 
1992/0404    
	RAMsize		= 8*1024, 
	BUFsize		= 256, 
1992/0403    
                 
1992/0410    
	RINGbase	= 6,		/* gak */ 
	RINGsize	= 32,		/* gak */ 
                 
1992/0404    
	Nctlr		= 1, 
1992/0410    
	NType		= 9,		/* types/interface */ 
1992/0424    
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*); 
1992/0404    
}; 
1992/0424    
static Hw wd8013; 
1992/0404    
 
1992/0410    
#define NEXT(x, l)	((((x)+1)%(l)) == 0 ? RINGbase: (((x)+1)%(l))) 
#define PREV(x, l)	(((x)-1) < RINGbase ? (l-1): ((x)-1)) 
1992/0408    
                 
1992/0404    
/* 
 * register offsets from IObase 
 */ 
enum { 
1992/0403    
	EA		= 0x08,		/* Ethernet Address in ROM */ 
	ID		= 0x0E,		/* interface type */ 
1992/0424    
	Nctlr		= 1,		/* even one of these is too many */ 
	NType		= 9,		/* types/interface */ 
1992/0403    
 
	NIC		= 0x10,		/* National DP8390 Chip */ 
	Cr		= NIC+0x00,	/* Page [01] */ 
1992/0424    
	Nrb		= 16,		/* software receive buffers */ 
	Ntb		= 4,		/* software transmit buffers */ 
}; 
1992/0403    
 
1992/0404    
	Pstart		= NIC+0x01,	/* write */ 
	Pstop		= NIC+0x02,	/* write */ 
	Bnry		= NIC+0x03, 
1992/0403    
	Tsr		= NIC+0x04,	/* read */ 
	Tpsr		= Tsr,		/* write */ 
1992/0404    
	Tbcr0		= NIC+0x05,	/* write */ 
	Tbcr1		= NIC+0x06,	/* write */ 
1992/0403    
	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 */ 
1992/0424    
#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)) 
1992/0403    
 
	Par0		= NIC+0x01,	/* Page 1 */ 
	Curr		= NIC+0x07, 
1992/0424    
struct Buffer { 
	uchar	owner; 
	uchar	busy; 
	ushort	len; 
	Etherpkt pkt; 
1992/0404    
}; 
1992/0403    
 
1992/0404    
/* 
 * 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 */ 
1992/0424    
	Host		= 0,		/* buffer owned by host */ 
	Interface	= 1,		/* buffer owned by interface */ 
1992/0404    
}; 
1992/0403    
 
1992/0404    
struct Ring { 
	uchar	status; 
	uchar	next; 
1992/0407    
	uchar	len0; 
	uchar	len1; 
1992/0404    
	uchar	data[BUFsize-4]; 
1992/0403    
}; 
                 
/* 
 * one per ethernet packet type 
 */ 
1992/0411/sys/src/9/pc/devether.c:105,1781992/0424/sys/src/9/pc/devether.c:64,185
1992/0403    
}; 
 
/* 
 *  per ethernet 
1992/0424    
 * per ethernet 
1992/0403    
 */ 
struct Ctlr { 
	QLock; 
 
1992/0407    
	Ring	*ring; 
1992/0403    
	Rendez	rr;			/* rendezvous for an input buffer */ 
1992/0407    
	Queue	rq; 
1992/0404    
	uchar	bnry; 
	uchar	curr; 
1992/0424    
	Hw	*hw; 
1992/0403    
 
1992/0407    
	Etherpkt *xpkt; 
1992/0404    
	QLock	xl; 
1992/0403    
	Rendez	xr; 
1992/0407    
	uchar	xbusy; 
1992/0424    
	ushort	nrb;		/* number of software receive buffers */ 
	ushort	ntb;		/* number of software transmit buffers */ 
	Buffer	*rb;		/* software receive buffers */ 
	Buffer	*tb;		/* software transmit buffers */ 
1992/0403    
 
	int	iobase;			/* I/O base address */ 
1992/0424    
	uchar	ea[6];		/* ethernet address */ 
	uchar	ba[6];		/* broadcast address */ 
1992/0403    
 
1992/0410    
	Type	type[NType]; 
1992/0403    
	uchar	ea[6]; 
	uchar	ba[6]; 
1992/0424    
	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 */	 
1992/0403    
 
	uchar	prom;			/* true if promiscuous mode */ 
	uchar	kproc;			/* true if kproc started */ 
	char	name[NAMELEN];		/* name of kproc */ 
1992/0424    
	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 */ 
1992/0403    
	Network	net; 
1992/0410    
	Netprot	prot[NType]; 
1992/0403    
 
1992/0424    
	Queue	lbq;		/* software loopback packet queue */ 
 
1992/0403    
	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 */ 
1992/0424    
	int	crcs;		/* input crc errors */ 
	int	oerrs;		/* output errors */ 
	int	frames;		/* framing errors */ 
	int	overflows;	/* packet overflows */ 
	int	buffs;		/* buffering errors */ 
1992/0403    
}; 
static Ctlr ctlr[Nctlr]; 
 
1992/0411    
static Etherpkt txpkt; 
1992/0424    
void 
etherinit(void) 
{ 
} 
1992/0411    
 
static void 
xmemmove(void *to, void *from, long len) 
1992/0424    
Chan* 
etherclone(Chan *c, Chan *nc) 
1992/0411    
{ 
	ushort *t, *f; 
	int s; 
	Ctlr *cp = &ctlr[0]; 
	uchar reg; 
1992/0424    
	return devclone(c, nc); 
} 
1992/0411    
 
	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); 
1992/0424    
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); 
1992/0411    
} 
 
1992/0424    
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); 
} 
 
1992/0407    
static int 
isxfree(void *arg) 
1992/0424    
isobuf(void *arg) 
1992/0407    
{ 
	Ctlr *cp = arg; 
 
1992/0409    
	return cp->xbusy == 0; 
1992/0424    
	cp->tb[cp->th].owner == Host; 
1992/0407    
} 
 
1992/0403    
static void 
1992/0411/sys/src/9/pc/devether.c:182,1901992/0424/sys/src/9/pc/devether.c:189,197
1992/0403    
	int len, n; 
1992/0410    
	Type *tp; 
1992/0403    
	Etherpkt *p; 
1992/0424    
	Buffer *tb; 
1992/0403    
	Block *nbp; 
 
1992/0410    
	cp = ((Type *)q->ptr)->ctlr; 
1992/0403    
	if(bp->type == M_CTL){ 
1992/0410    
		tp = q->ptr; 
1992/0403    
		if(streamparse("connect", bp)) 
1992/0411/sys/src/9/pc/devether.c:191,2061992/0424/sys/src/9/pc/devether.c:198,211
1992/0410    
			tp->type = strtol((char *)bp->rptr, 0, 0); 
1992/0403    
		else if(streamparse("promiscuous", bp)) { 
1992/0410    
			tp->prom = 1; 
1992/0406    
			qlock(cp); 
			cp->prom++; 
			if(cp->prom == 1) 
				outb(cp->iobase+Rcr, 0x14);	/* PRO|AB */ 
			qunlock(cp); 
1992/0424    
			(*tp->ctlr->hw->mode)(tp->ctlr, 1); 
1992/0403    
		} 
		freeb(bp); 
		return; 
	} 
 
1992/0424    
	cp = ((Type *)q->ptr)->ctlr; 
 
1992/0403    
	/* 
	 * give packet a local address, return upstream if destined for 
	 * this machine. 
1992/0411/sys/src/9/pc/devether.c:212,2181992/0424/sys/src/9/pc/devether.c:217,223
1992/0406    
	if(memcmp(cp->ea, p->d, sizeof(cp->ea)) == 0){ 
1992/0403    
		len = blen(bp); 
1992/0406    
		if (bp = expandb(bp, len >= ETHERMINTU ? len: ETHERMINTU)){ 
			putq(&cp->rq, bp); 
1992/0424    
			putq(&cp->lbq, bp); 
1992/0406    
			wakeup(&cp->rr); 
1992/0403    
		} 
		return; 
1992/0411/sys/src/9/pc/devether.c:222,2281992/0424/sys/src/9/pc/devether.c:227,233
1992/0403    
		nbp = copyb(bp, len); 
1992/0406    
		if(nbp = expandb(nbp, len >= ETHERMINTU ? len: ETHERMINTU)){ 
1992/0403    
			nbp->wptr = nbp->rptr+len; 
1992/0406    
			putq(&cp->rq, nbp); 
1992/0424    
			putq(&cp->lbq, nbp); 
1992/0406    
			wakeup(&cp->rr); 
1992/0403    
		} 
	} 
1992/0411/sys/src/9/pc/devether.c:230,2501992/0424/sys/src/9/pc/devether.c:235,257
1992/0403    
	/* 
	 * only one transmitter at a time 
	 */ 
1992/0407    
	qlock(&cp->xl); 
1992/0424    
	qlock(&cp->tlock); 
1992/0403    
	if(waserror()){ 
1992/0411    
		freeb(bp); 
1992/0407    
		qunlock(&cp->xl); 
1992/0424    
		qunlock(&cp->tlock); 
1992/0403    
		nexterror(); 
	} 
 
	/* 
1992/0407    
	 * Wait till we get an output buffer 
1992/0424    
	 * wait till we get an output buffer. 
	 * should try to restart. 
1992/0403    
	 */ 
1992/0411    
	tsleep(&cp->xr, isxfree, cp, 1000); 
	if(isxfree(cp) == 0) 
		print("Tx wedged\n"); 
	p = &txpkt; 
1992/0424    
print("oput sleep\n"); 
	sleep(&cp->tr, isobuf, cp); 
1992/0403    
 
1992/0424    
	tb = &cp->tb[cp->th]; 
	p = &tb->pkt; 
 
1992/0403    
	/* 
	 * copy message into buffer 
	 */ 
1992/0411/sys/src/9/pc/devether.c:271,2881992/0424/sys/src/9/pc/devether.c:278,297
1992/0407    
	 * give packet a local address 
1992/0403    
	 */ 
1992/0407    
	memmove(p->s, cp->ea, sizeof(cp->ea)); 
1992/0411    
	xmemmove(cp->xpkt, p, len); 
1992/0403    
 
	/* 
1992/0424    
	 * set up the transmit buffer and  
1992/0407    
	 * start the transmission 
1992/0403    
	 */ 
1992/0407    
	outb(cp->iobase+Tbcr0, len & 0xFF); 
	outb(cp->iobase+Tbcr1, (len>>8) & 0xFF); 
	outb(cp->iobase+Cr, 0x26);			/* Page0|TXP|STA */ 
	cp->xbusy = 1; 
1992/0424    
	cp->outpackets++; 
	tb->len = len; 
	tb->owner = Interface; 
	cp->th = NEXT(cp->th, cp->ntb); 
	(*cp->hw->transmit)(cp); 
1992/0403    
 
	freeb(bp); 
1992/0407    
	qunlock(&cp->xl); 
1992/0424    
	qunlock(&cp->tlock); 
print("oput done\n"); 
1992/0403    
	poperror(); 
} 
 
1992/0411/sys/src/9/pc/devether.c:320,3321992/0424/sys/src/9/pc/devether.c:329,336
1992/0410    
	Type *tp; 
1992/0403    
 
1992/0410    
	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); 
1992/0403    
	} 
1992/0424    
	if(tp->prom) 
		(*tp->ctlr->hw->mode)(tp->ctlr, 0); 
1992/0410    
	qlock(tp); 
	tp->type = 0; 
	tp->q = 0; 
1992/0411/sys/src/9/pc/devether.c:389,5171992/0424/sys/src/9/pc/devether.c:393,404
1992/0403    
} 
 
static void 
intr(Ureg *ur) 
1992/0424    
etherup(Ctlr *cp, Etherpkt *p, int len) 
1992/0403    
{ 
1992/0404    
	Ctlr *cp = &ctlr[0]; 
1992/0410    
	uchar isr, bnry, curr; 
1992/0404    
                 
	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); 
1992/0410    
			cp->overflows += inb(cp->iobase+Cntr2); 
1992/0404    
		} 
		if(isr & Ptx) 
			cp->outpackets++; 
		if(isr & (Txe|Ptx)){ 
1992/0407    
			cp->xbusy = 0; 
			wakeup(&cp->xr); 
1992/0404    
		} 
1992/0410    
		if(isr & Ovw){ 
			bnry = inb(cp->iobase+Bnry); 
			outb(cp->iobase+bnry, bnry); 
			cp->buffs++; 
		} 
1992/0404    
		/* 
		 * we have received packets. 
		 * this is the only place, other than the init code, 
		 * where we set the controller to Page1. 
1992/0405    
		 * we must be sure to reset it back to Page0 in case 
1992/0404    
		 * we interrupted some other part of this driver. 
		 */ 
1992/0410    
		if(isr & (Rxe|Prx)){ 
1992/0404    
			outb(cp->iobase+Cr, 0x62);	/* Page1, RD2|STA */ 
			cp->curr = inb(cp->iobase+Curr); 
			outb(cp->iobase+Cr, 0x22);	/* Page0, RD2|STA */ 
1992/0410    
if(debug) 
    print("I%d/%d/%d|", isr, cp->curr, cp->bnry); 
1992/0404    
			wakeup(&cp->rr); 
		} 
	} 
1992/0403    
} 
                 
/* 
 * the following initialisation procedure 
1992/0405    
 * is mandatory. 
1992/0404    
 * we leave the chip idling on internal loopback 
1992/0405    
 * and pointing to Page0. 
1992/0403    
 */ 
static void 
1992/0404    
init(Ctlr *cp) 
1992/0403    
{ 
	int i; 
                 
1992/0404    
	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 */ 
1992/0410    
	cp->bnry = RINGbase; 
1992/0408    
	outb(cp->iobase+Bnry, cp->bnry); 
1992/0407    
	cp->ring = (Ring*)(KZERO|RAMbase); 
1992/0410    
	outb(cp->iobase+Pstart, RINGbase); 
	outb(cp->iobase+Pstop, RINGsize); 
1992/0404    
	outb(cp->iobase+Isr, 0xFF); 
	outb(cp->iobase+Imr, 0x1F);		/* OVWE|TXEE|RXEE|PTXE|PRXE */ 
1992/0403    
                 
1992/0404    
	outb(cp->iobase+Cr, 0x61);		/* Page1, RD2|STP */ 
	for(i = 0; i < sizeof(cp->ea); i++) 
		outb(cp->iobase+Par0+i, cp->ea[i]); 
1992/0408    
	cp->curr = cp->bnry+1; 
	outb(cp->iobase+Curr, cp->curr); 
1992/0404    
                 
	outb(cp->iobase+Cr, 0x22);		/* Page0, RD2|STA */ 
	outb(cp->iobase+Tpsr, 0); 
1992/0407    
	cp->xpkt = (Etherpkt*)(KZERO|RAMbase); 
1992/0403    
} 
                 
void 
etherreset(void) 
{ 
1992/0404    
	Ctlr *cp = &ctlr[0]; 
1992/0403    
	int i; 
1992/0411    
	uchar reg; 
1992/0403    
                 
1992/0404    
	cp->iobase = IObase; 
1992/0411    
	reg = 0x40|inb(cp->iobase); 
	outb(cp->iobase, reg); 
	reg = 0x40|inb(cp->iobase+0x05); 
	outb(cp->iobase+0x05, reg); 
1992/0409    
for(i = 0; i < 0x10; i++) 
    print("#%2.2ux ", inb(cp->iobase+i)); 
print("\n"); 
1992/0404    
	for(i = 0; i < sizeof(cp->ea); i++) 
		cp->ea[i] = inb(cp->iobase+EA+i); 
1992/0408    
	init(cp); 
	setvec(Ethervec, intr); 
1992/0404    
	memset(cp->ba, 0xFF, sizeof(cp->ba)); 
1992/0403    
                 
1992/0404    
	cp->net.name = "ether"; 
1992/0410    
	cp->net.nconv = NType; 
1992/0404    
	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; 
1992/0403    
} 
                 
1992/0404    
static void 
1992/0410    
etherup(Ctlr *cp, uchar *d0, int len0, uchar *d1, int len1) 
1992/0404    
{ 
1992/0410    
	Etherpkt *p; 
1992/0404    
	Block *bp; 
1992/0410    
	Type *tp; 
1992/0404    
	int t; 
 
1992/0410    
	p = (Etherpkt*)d0; 
	t = (p->type[0]<<8)|p->type[1]; 
	for(tp = &cp->type[0]; tp < &cp->type[NType]; tp++){ 
1992/0404    
		/* 
1992/0411/sys/src/9/pc/devether.c:537,5471992/0424/sys/src/9/pc/devether.c:424,432
1992/0404    
			continue; 
		} 
		if(waserror() == 0){ 
1992/0410    
			bp = allocb(len0+len1); 
1992/0411    
			xmemmove(bp->rptr, d0, len0); 
1992/0410    
			if(len1) 
1992/0411    
				xmemmove(bp->rptr+len0, d1, len1); 
1992/0410    
			bp->wptr += len0+len1; 
1992/0424    
			bp = allocb(len); 
			memmove(bp->rptr, p, len); 
			bp->wptr += len; 
1992/0404    
			bp->flags |= S_DELIM; 
1992/0410    
			PUTNEXT(tp->q, bp); 
1992/0404    
		} 
1992/0411/sys/src/9/pc/devether.c:550,5731992/0424/sys/src/9/pc/devether.c:435,446
1992/0404    
	} 
} 
 
1992/0406    
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]); 
} 
                 
1992/0403    
static int 
isinput(void *arg) 
{ 
1992/0404    
	Ctlr *cp = arg; 
1992/0403    
 
1992/0410    
	return NEXT(cp->bnry, RINGsize) != cp->curr; 
1992/0424    
	return cp->lbq.first || cp->rb[cp->ri].owner == Host; 
1992/0403    
} 
 
static void 
1992/0411/sys/src/9/pc/devether.c:574,5991992/0424/sys/src/9/pc/devether.c:447,471
1992/0403    
etherkproc(void *arg) 
{ 
1992/0404    
	Ctlr *cp = arg; 
1992/0424    
	Buffer *rb; 
1992/0404    
	Block *bp; 
	uchar bnry, curr; 
	Ring *rp; 
1992/0410    
	int len0, len1; 
1992/0403    
 
	if(waserror()){ 
1992/0404    
		print("%s noted\n", cp->name); 
		init(cp); 
1992/0424    
		(*cp->hw->init)(cp); 
1992/0404    
		cp->kproc = 0; 
1992/0403    
		nexterror(); 
	} 
1992/0404    
	cp->kproc = 1; 
1992/0403    
	for(;;){ 
1992/0404    
		sleep(&cp->rr, isinput, cp); 
1992/0424    
		qlock(&cp->rlock); 
 
1992/0406    
		/* 
		 * process any internal loopback packets 
		 */ 
1992/0404    
		while(bp = getq(&cp->rq)){ 
1992/0424    
		while(bp = getq(&cp->lbq)){ 
1992/0404    
			cp->inpackets++; 
1992/0410    
			etherup(cp, bp->rptr, BLEN(bp), 0, 0); 
1992/0424    
			etherup(cp, (Etherpkt*)bp->rptr, BLEN(bp)); 
1992/0404    
			freeb(bp); 
		} 
1992/0408    
 
1992/0411/sys/src/9/pc/devether.c:600,7301992/0424/sys/src/9/pc/devether.c:472,823
1992/0406    
		/* 
		 * process any received packets 
		 */ 
1992/0410    
		bnry = NEXT(cp->bnry, RINGsize); 
1992/0408    
		while(bnry != cp->curr){ 
			rp = &cp->ring[bnry]; 
1992/0424    
		while(cp->rb[cp->rh].owner == Host){ 
1992/0406    
			cp->inpackets++; 
1992/0410    
			len0 = ((rp->len1<<8)+rp->len0)-4; 
			len1 = 0; 
1992/0424    
			rb = &cp->rb[cp->rh]; 
			etherup(cp, &rb->pkt, rb->len); 
			rb->owner = Interface; 
			cp->rh = NEXT(cp->rh, Nrb); 
		} 
1992/0410    
 
			if(rp->data+len0 >= (uchar*)&cp->ring[RINGsize]){ 
				len1 = rp->data+len0 - (uchar*)&cp->ring[RINGsize]; 
				len0 = (uchar*)&cp->ring[RINGsize] - rp->data; 
			} 
1992/0424    
		qunlock(&cp->rlock); 
		sleep(&cp->rr, isinput, cp); 
	} 
} 
1992/0410    
 
			etherup(cp, rp->data, len0, (uchar*)&cp->ring[RINGbase], len1); 
1992/0424    
void 
etherreset(void) 
{ 
	Ctlr *cp = &ctlr[0]; 
1992/0410    
 
1992/0424    
	cp->hw = &wd8013; 
	(*cp->hw->reset)(cp); 
1992/0410    
 
1992/0424    
	memset(cp->ba, 0xFF, sizeof(cp->ba)); 
1992/0410    
 
if(debug) 
    print("K%d/%d/%d|", bnry, rp->next, PREV(rp->next, RINGsize)); 
1992/0408    
			bnry = rp->next; 
1992/0410    
			cp->bnry = PREV(bnry, RINGsize); 
1992/0407    
			outb(cp->iobase+Bnry, cp->bnry); 
1992/0406    
		} 
1992/0403    
	} 
1992/0424    
	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; 
1992/0403    
} 
 
void 
etherinit(void) 
1992/0424    
Chan* 
etherattach(char *spec) 
1992/0403    
{ 
	int ctlrno = 0; 
1992/0424    
	Ctlr *cp = &ctlr[ctlrno]; 
	int i; 
1992/0403    
 
1992/0424    
	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; 
 
1992/0403    
	/* 
	 * put the receiver online 
	 * and start the kproc 
	 */ 
1992/0404    
	outb(ctlr[ctlrno].iobase+Tcr, 0); 
1992/0403    
	if(ctlr[ctlrno].kproc == 0){ 
		sprint(ctlr[ctlrno].name, "ether%dkproc", ctlrno); 
		kproc(ctlr[ctlrno].name, etherkproc, &ctlr[ctlrno]); 
1992/0424    
	 
	(*cp->hw->online)(cp, 1); 
	if(cp->kproc == 0){ 
		sprint(cp->name, "ether%dkproc", ctlrno); 
		kproc(cp->name, etherkproc, cp); 
1992/0403    
	} 
} 
                 
Chan * 
etherattach(char *spec) 
{ 
	return devattach('l', spec); 
} 
 
Chan * 
etherclone(Chan *c, Chan *nc) 
{ 
	return devclone(c, nc); 
} 
1992/0424    
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; 
1992/0403    
 
int 
etherwalk(Chan *c, char *name) 
{ 
	return netwalk(c, name, &ctlr[0].net); 
} 
1992/0424    
	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; 
1992/0403    
 
void 
etherstat(Chan *c, char *dp) 
1992/0424    
#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) 
1992/0403    
{ 
	netstat(c, dp, &ctlr[0].net); 
} 
1992/0424    
	Hw *hw = cp->hw; 
	int i; 
	uchar msr; 
1992/0403    
 
Chan * 
etheropen(Chan *c, int omode) 
1992/0424    
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); 
1992/0403    
{ 
	return netopen(c, omode, &ctlr[0].net); 
1992/0424    
int addr = hw->addr; 
 
for(i = 0; i < 16; i++){ 
    print("#%2.2ux ", inb(addr)); 
    addr++; 
1992/0403    
} 
1992/0424    
print("\n"); 
} 
	for(i = 0; i < sizeof(cp->ea); i++) 
		cp->ea[i] = IN(hw, lan[i]); 
	(*hw->init)(cp); 
	setvec(Ethervec, hw->intr); 
} 
1992/0403    
 
void 
ethercreate(Chan *c, char *name, int omode, ulong perm) 
1992/0424    
/* 
 * we leave the chip idling on internal loopback 
 * and pointing to Page0. 
 */ 
static void 
wd8013init(Ctlr *cp) 
1992/0403    
{ 
	error(Eperm); 
1992/0424    
	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); 
1992/0403    
} 
 
void 
etherremove(Chan *c) 
1992/0424    
wd8013mode(Ctlr *cp, int on) 
1992/0403    
{ 
	error(Eperm); 
1992/0424    
	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); 
1992/0403    
} 
 
void 
etherwstat(Chan *c, char *dp) 
1992/0424    
static void 
wd8013online(Ctlr *cp, int on) 
1992/0403    
{ 
	netwstat(c, dp, &ctlr[0].net); 
1992/0424    
	OUT(cp->hw, w.tcr, 0); 
1992/0403    
} 
 
void 
etherclose(Chan *c) 
1992/0424    
static void 
wd8013receive(Ctlr *cp) 
1992/0403    
{ 
	if(c->stream) 
		streamclose(c); 
1992/0424    
	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); 
	} 
1992/0403    
} 
 
long 
etherread(Chan *c, void *a, long n, ulong offset) 
1992/0424    
static void 
wd8013transmit(Ctlr *cp) 
1992/0403    
{ 
	return netread(c, a, n, offset, &ctlr[0].net); 
1992/0424    
	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"); 
1992/0403    
} 
 
long 
etherwrite(Chan *c, char *a, long n, ulong offset) 
1992/0424    
static void 
wd8013intr(Ureg *ur) 
1992/0403    
{ 
	return streamwrite(c, a, n, 0); 
1992/0424    
	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); 
		} 
	} 
1992/0409    
} 
 
1992/0424    
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, 
}; 
 
1992/0409    
void 
1992/0411    
consdebug(void) 
1992/0409    
{ 
	Ctlr *cp = &ctlr[0]; 
	uchar bnry, curr, isr; 
	int s; 
                 
	s = splhi(); 
1992/0410    
debug++; 
1992/0409    
	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); 
1992/0410    
	print("\t%d %d %d %d %d %d %d\n", cp->inpackets, cp->outpackets, 
1992/0409    
	    cp->crcs, cp->oerrs, cp->frames, cp->overflows, cp->buffs); 
	splx(s); 
1992/0403    
} 
1992/0424/sys/src/9/pc/devether.c:108,1161992/0425/sys/src/9/pc/devether.c:108,117 (short | long)
1992/0403    
}; 
static Ctlr ctlr[Nctlr]; 
 
1992/0424    
void 
etherinit(void) 
1992/0425    
Chan* 
etherattach(char *spec) 
1992/0424    
{ 
1992/0425    
	return devattach('l', spec); 
1992/0424    
} 
1992/0411    
 
1992/0424    
Chan* 
1992/0424/sys/src/9/pc/devether.c:179,1851992/0425/sys/src/9/pc/devether.c:180,186
1992/0407    
{ 
	Ctlr *cp = arg; 
 
1992/0424    
	cp->tb[cp->th].owner == Host; 
1992/0425    
	return cp->tb[cp->th].owner == Host; 
1992/0407    
} 
 
1992/0403    
static void 
1992/0424/sys/src/9/pc/devether.c:246,2521992/0425/sys/src/9/pc/devether.c:247,252
1992/0424    
	 * wait till we get an output buffer. 
	 * should try to restart. 
1992/0403    
	 */ 
1992/0424    
print("oput sleep\n"); 
	sleep(&cp->tr, isobuf, cp); 
1992/0403    
 
1992/0424    
	tb = &cp->tb[cp->th]; 
1992/0424/sys/src/9/pc/devether.c:291,2971992/0425/sys/src/9/pc/devether.c:291,296
1992/0403    
 
	freeb(bp); 
1992/0424    
	qunlock(&cp->tlock); 
print("oput done\n"); 
1992/0403    
	poperror(); 
} 
 
1992/0424/sys/src/9/pc/devether.c:509,5161992/0425/sys/src/9/pc/devether.c:508,515
1992/0424    
	cp->net.info[1].fill = typefill; 
1992/0403    
} 
 
1992/0424    
Chan* 
etherattach(char *spec) 
1992/0425    
void 
etherinit(void) 
1992/0403    
{ 
	int ctlrno = 0; 
1992/0424    
	Ctlr *cp = &ctlr[ctlrno]; 
1992/0424/sys/src/9/pc/devether.c:536,5421992/0425/sys/src/9/pc/devether.c:535,540
1992/0424    
		sprint(cp->name, "ether%dkproc", ctlrno); 
		kproc(cp->name, etherkproc, cp); 
1992/0403    
	} 
	return devattach('l', spec); 
} 
 
1992/0424    
typedef struct { 
1992/0424/sys/src/9/pc/devether.c:610,6161992/0425/sys/src/9/pc/devether.c:608,613
1992/0424    
	int i; 
	uchar msr; 
1992/0403    
 
1992/0424    
print("reset\n"); 
	cp->rb = ialloc(sizeof(Buffer)*Nrb, 0); 
	cp->nrb = Nrb; 
	cp->tb = ialloc(sizeof(Buffer)*Ntb, 0); 
1992/0424/sys/src/9/pc/devether.c:705,7111992/0425/sys/src/9/pc/devether.c:702,708
1992/0424    
		uchar	data[256-4]; 
	} Ring; 
	Ring *p; 
	int len; 
1992/0425    
	int len0, len1; 
1992/0424    
 
	bnry = IN(hw, r.bnry); 
	next = NEXT(bnry, HOWMANY(hw->ramsz, 256)); 
1992/0424/sys/src/9/pc/devether.c:719,7301992/0425/sys/src/9/pc/devether.c:716,737
1992/0424    
			break; 
		cp->inpackets++; 
		p = &((Ring*)hw->ram)[next]; 
		len = (p->len1<<8)|p->len0; 
1992/0425    
		len0 = (p->len1<<8)|p->len0-4; 
		len1 = 0; 
1992/0424    
 
		rb = &cp->rb[cp->ri]; 
		if(rb->owner == Interface){ 
			rb->len = len; 
1992/0425    
			rb->len = len0; 
1992/0424    
			/*copy in packet*/ 
1992/0425    
			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); 
1992/0424    
			rb->owner = Host; 
			cp->ri = NEXT(cp->ri, Nrb); 
		} 
1992/0425/sys/src/9/pc/devether.c:14,211992/0501/sys/src/9/pc/devether.c:14,24 (short | long)
1992/0403    
 
1992/0424    
struct Hw { 
	int	addr;			/* interface address */ 
	void	*ram;			/* interface shared memory address */ 
	int	ramsz;			/* interface shared memory size */ 
1992/0501    
	uchar	*ram;			/* interface shared memory address */ 
	int	size; 
	uchar	tstart; 
	uchar	pstart; 
	uchar	pstop; 
1992/0424    
	void	(*reset)(Ctlr*); 
	void	(*init)(Ctlr*); 
	void	(*mode)(Ctlr*, int); 
1992/0425/sys/src/9/pc/devether.c:43,491992/0501/sys/src/9/pc/devether.c:46,52
1992/0424    
	uchar	owner; 
	uchar	busy; 
	ushort	len; 
	Etherpkt pkt; 
1992/0501    
	uchar	pkt[sizeof(Etherpkt)]; 
1992/0404    
}; 
1992/0403    
 
1992/0404    
enum { 
1992/0425/sys/src/9/pc/devether.c:250,2561992/0501/sys/src/9/pc/devether.c:253,258
1992/0424    
	sleep(&cp->tr, isobuf, cp); 
1992/0403    
 
1992/0424    
	tb = &cp->tb[cp->th]; 
	p = &tb->pkt; 
 
1992/0403    
	/* 
	 * copy message into buffer 
1992/0425/sys/src/9/pc/devether.c:258,2641992/0501/sys/src/9/pc/devether.c:260,266
1992/0403    
	len = 0; 
	for(nbp = bp; nbp; nbp = nbp->next){ 
		if(sizeof(Etherpkt) - len >= (n = BLEN(nbp))){ 
			memmove(((uchar *)p)+len, nbp->rptr, n); 
1992/0501    
			memmove(tb->pkt+len, nbp->rptr, n); 
1992/0403    
			len += n; 
		} else 
			print("no room damn it\n"); 
1992/0425/sys/src/9/pc/devether.c:270,2851992/0501/sys/src/9/pc/devether.c:272,282
1992/0407    
	 * pad the packet (zero the pad) 
1992/0403    
	 */ 
	if(len < ETHERMINTU){ 
		memset(((char*)p)+len, 0, ETHERMINTU-len); 
1992/0501    
		memset(tb->pkt+len, 0, ETHERMINTU-len); 
1992/0403    
		len = ETHERMINTU; 
	} 
 
	/* 
1992/0407    
	 * give packet a local address 
1992/0403    
	 */ 
1992/0407    
	memmove(p->s, cp->ea, sizeof(cp->ea)); 
1992/0403    
                 
	/* 
1992/0424    
	 * set up the transmit buffer and  
1992/0407    
	 * start the transmission 
1992/0403    
	 */ 
1992/0425/sys/src/9/pc/devether.c:392,4031992/0501/sys/src/9/pc/devether.c:389,402
1992/0403    
} 
 
static void 
1992/0424    
etherup(Ctlr *cp, Etherpkt *p, int len) 
1992/0501    
etherup(Ctlr *cp, void *data, int len) 
1992/0403    
{ 
1992/0404    
	Block *bp; 
1992/0410    
	Type *tp; 
1992/0501    
	Etherpkt *p; 
1992/0404    
	int t; 
1992/0501    
	Type *tp; 
	Block *bp; 
1992/0404    
 
1992/0501    
	p = data; 
1992/0410    
	t = (p->type[0]<<8)|p->type[1]; 
	for(tp = &cp->type[0]; tp < &cp->type[NType]; tp++){ 
1992/0404    
		/* 
1992/0425/sys/src/9/pc/devether.c:464,4701992/0501/sys/src/9/pc/devether.c:463,469
1992/0406    
		 */ 
1992/0424    
		while(bp = getq(&cp->lbq)){ 
1992/0404    
			cp->inpackets++; 
1992/0424    
			etherup(cp, (Etherpkt*)bp->rptr, BLEN(bp)); 
1992/0501    
			etherup(cp, bp->rptr, BLEN(bp)); 
1992/0404    
			freeb(bp); 
		} 
1992/0408    
 
1992/0425/sys/src/9/pc/devether.c:474,4801992/0501/sys/src/9/pc/devether.c:473,479
1992/0424    
		while(cp->rb[cp->rh].owner == Host){ 
1992/0406    
			cp->inpackets++; 
1992/0424    
			rb = &cp->rb[cp->rh]; 
			etherup(cp, &rb->pkt, rb->len); 
1992/0501    
			etherup(cp, rb->pkt, rb->len); 
1992/0424    
			rb->owner = Interface; 
			cp->rh = NEXT(cp->rh, Nrb); 
		} 
1992/0425/sys/src/9/pc/devether.c:528,5351992/0501/sys/src/9/pc/devether.c:527,533
1992/0403    
	/* 
	 * put the receiver online 
	 * and start the kproc 
	 */ 
1992/0424    
	                 
1992/0501    
	 */	 
1992/0424    
	(*cp->hw->online)(cp, 1); 
	if(cp->kproc == 0){ 
		sprint(cp->name, "ether%dkproc", ctlrno); 
1992/0425/sys/src/9/pc/devether.c:599,6041992/0501/sys/src/9/pc/devether.c:597,610
1992/0424    
#define IN(hw, m)	inb((hw)->addr+OFFSETOF(Wd8013, m)) 
#define OUT(hw, m, x)	outb((hw)->addr+OFFSETOF(Wd8013, m), (x)) 
 
1992/0501    
typedef struct { 
	uchar	status; 
	uchar	next; 
	uchar	len0; 
	uchar	len1; 
	uchar	data[256-4]; 
} Ring; 
 
1992/0424    
/* 
 */ 
static void 
1992/0425/sys/src/9/pc/devether.c:608,6311992/0501/sys/src/9/pc/devether.c:614,630
1992/0424    
	int i; 
	uchar msr; 
1992/0403    
 
1992/0424    
	cp->rb = ialloc(sizeof(Buffer)*Nrb, 0); 
	cp->nrb = Nrb; 
	cp->tb = ialloc(sizeof(Buffer)*Ntb, 0); 
1992/0501    
	cp->tb = ialloc(sizeof(Buffer)*Ntb, 1); 
1992/0424    
	cp->ntb = Ntb; 
1992/0501    
	cp->rb = ialloc(sizeof(Buffer)*Nrb, 1); 
	cp->nrb = Nrb; 
1992/0424    
 
	msr = IN(hw, msr); 
	OUT(hw, msr, 0x40|msr); 
1992/0403    
{ 
1992/0424    
int addr = hw->addr; 
 
for(i = 0; i < 16; i++){ 
    print("#%2.2ux ", inb(addr)); 
    addr++; 
1992/0403    
} 
1992/0424    
print("\n"); 
} 
	for(i = 0; i < sizeof(cp->ea); i++) 
		cp->ea[i] = IN(hw, lan[i]); 
1992/0501    
 
1992/0424    
	(*hw->init)(cp); 
	setvec(Ethervec, hw->intr); 
} 
1992/0425/sys/src/9/pc/devether.c:639,6471992/0501/sys/src/9/pc/devether.c:638,644
1992/0403    
{ 
1992/0424    
	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); 
1992/0425/sys/src/9/pc/devether.c:649,6581992/0501/sys/src/9/pc/devether.c:646,654
1992/0424    
	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)); 
1992/0501    
	OUT(hw, w.bnry, hw->pstart); 
	OUT(hw, w.pstart, hw->pstart); 
	OUT(hw, w.pstop, hw->pstop); 
1992/0424    
	OUT(hw, w.isr, 0xFF); 
	OUT(hw, w.imr, 0x1F);			/* OVWE|TXEE|RXEE|PTXE|PRXE */ 
 
1992/0425/sys/src/9/pc/devether.c:659,6651992/0501/sys/src/9/pc/devether.c:655,661
1992/0424    
	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); 
1992/0501    
	OUT(hw, curr, hw->pstart+1); 
1992/0424    
 
	OUT(hw, w.cr, 0x22);			/* Page0|RD2|STA */ 
	OUT(hw, w.tpsr, 0); 
1992/0425/sys/src/9/pc/devether.c:688,6931992/0501/sys/src/9/pc/devether.c:684,691
1992/0424    
	OUT(cp->hw, w.tcr, 0); 
1992/0403    
} 
 
1992/0501    
static ulong wraps; 
 
1992/0424    
static void 
wd8013receive(Ctlr *cp) 
1992/0403    
{ 
1992/0425/sys/src/9/pc/devether.c:694,7131992/0501/sys/src/9/pc/devether.c:692,704
1992/0424    
	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; 
1992/0425    
	int len0, len1; 
1992/0501    
	int len; 
1992/0424    
 
	bnry = IN(hw, r.bnry); 
	next = NEXT(bnry, HOWMANY(hw->ramsz, 256)); 
	if(next == 0) 
		next = HOWMANY(sizeof(Etherpkt), 256); 
1992/0501    
	next = bnry+1; 
	if(next >= hw->pstop) 
		next = hw->pstart; 
1992/0424    
	for(;;){ 
		OUT(hw, w.cr, 0x62);		/* Page1|RD2|STA */ 
		curr = IN(hw, curr); 
1992/0425/sys/src/9/pc/devether.c:716,7451992/0501/sys/src/9/pc/devether.c:707,737
1992/0424    
			break; 
		cp->inpackets++; 
		p = &((Ring*)hw->ram)[next]; 
1992/0425    
		len0 = (p->len1<<8)|p->len0-4; 
		len1 = 0; 
1992/0501    
		len = (p->len1<<8)|p->len0-4; 
if(len > sizeof(Etherpkt)) 
    print("!"); 
1992/0424    
 
		rb = &cp->rb[cp->ri]; 
		if(rb->owner == Interface){ 
1992/0425    
			rb->len = len0; 
1992/0501    
			rb->len = len; 
1992/0424    
			/*copy in packet*/ 
1992/0425    
			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; 
1992/0501    
			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); 
1992/0425    
			} 
			memmove((uchar*)&rb->pkt, p->data, len0); 
			if(len1) 
				memmove((uchar*)&rb->pkt+len0, 
					(uchar*)hw->ram+ROUNDUP(sizeof(Etherpkt), 256), 
					len1); 
1992/0501    
			memmove(rb->pkt, p->data, len); 
1992/0424    
			rb->owner = Host; 
			cp->ri = NEXT(cp->ri, Nrb); 
		} 
 
1992/0501    
p->status = 0; 
1992/0424    
		next = p->next; 
		bnry = next-1; 
		if(bnry < HOWMANY(sizeof(Etherpkt), 256)) 
			bnry = HOWMANY(hw->ramsz, 256)-1; 
1992/0501    
		if(bnry < hw->pstart) 
			bnry = hw->pstop-1; 
1992/0424    
		OUT(hw, w.bnry, bnry); 
	} 
1992/0403    
} 
1992/0425/sys/src/9/pc/devether.c:751,7631992/0501/sys/src/9/pc/devether.c:743,754
1992/0424    
	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); 
1992/0501    
tb->len = tb->len+1 & ~1; 
		memmove(hw->ram, tb->pkt, tb->len); 
1992/0424    
		OUT(hw, w.tbcr0, tb->len & 0xFF); 
		OUT(hw, w.tbcr1, (tb->len>>8) & 0xFF); 
		OUT(hw, w.cr, 0x26);		/* Page0|RD2|TXP|STA */ 
1992/0425/sys/src/9/pc/devether.c:764,7701992/0501/sys/src/9/pc/devether.c:755,760
1992/0424    
		tb->busy = 1; 
	} 
	splx(s); 
print("transmit done\n"); 
1992/0403    
} 
 
1992/0424    
static void 
1992/0425/sys/src/9/pc/devether.c:814,8201992/0501/sys/src/9/pc/devether.c:804,813
1992/0424    
static Hw wd8013 = { 
	0x360,					/* I/O base address */ 
	KZERO|0xC8000,				/* shared memory address */ 
	8*1024,					/* shared memory size */ 
1992/0501    
	8*1024, 
	0, 
	HOWMANY(sizeof(Etherpkt), 256), 
	HOWMANY(8*1024, 256), 
1992/0424    
	wd8013reset, 
	wd8013init, 
	wd8013mode, 
1992/0425/sys/src/9/pc/devether.c:827,8301992/0501/sys/src/9/pc/devether.c:820,841
1992/0409    
void 
1992/0411    
consdebug(void) 
1992/0409    
{ 
1992/0501    
	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); 
1992/0403    
} 
1992/0501/sys/src/9/pc/devether.c:475,4811992/0502/sys/src/9/pc/devether.c:475,481 (short | long)
1992/0424    
			rb = &cp->rb[cp->rh]; 
1992/0501    
			etherup(cp, rb->pkt, rb->len); 
1992/0424    
			rb->owner = Interface; 
			cp->rh = NEXT(cp->rh, Nrb); 
1992/0502    
			cp->rh = NEXT(cp->rh, cp->nrb); 
1992/0424    
		} 
1992/0410    
 
1992/0424    
		qunlock(&cp->rlock); 
1992/0501/sys/src/9/pc/devether.c:614,6231992/0502/sys/src/9/pc/devether.c:614,623
1992/0424    
	int i; 
	uchar msr; 
1992/0403    
 
1992/0501    
	cp->tb = ialloc(sizeof(Buffer)*Ntb, 1); 
1992/0424    
	cp->ntb = Ntb; 
1992/0501    
	cp->rb = ialloc(sizeof(Buffer)*Nrb, 1); 
	cp->nrb = Nrb; 
1992/0502    
	cp->tb = ialloc(sizeof(Buffer)*Ntb, 1); 
	cp->ntb = Ntb; 
1992/0424    
 
	msr = IN(hw, msr); 
	OUT(hw, msr, 0x40|msr); 
1992/0501/sys/src/9/pc/devether.c:684,6911992/0502/sys/src/9/pc/devether.c:684,689
1992/0424    
	OUT(cp->hw, w.tcr, 0); 
1992/0403    
} 
 
1992/0501    
static ulong wraps; 
                 
1992/0424    
static void 
wd8013receive(Ctlr *cp) 
1992/0403    
{ 
1992/0501/sys/src/9/pc/devether.c:708,7331992/0502/sys/src/9/pc/devether.c:706,727
1992/0424    
		cp->inpackets++; 
		p = &((Ring*)hw->ram)[next]; 
1992/0501    
		len = (p->len1<<8)|p->len0-4; 
if(len > sizeof(Etherpkt)) 
    print("!"); 
1992/0424    
 
		rb = &cp->rb[cp->ri]; 
		if(rb->owner == Interface){ 
1992/0501    
			rb->len = len; 
1992/0424    
			/*copy in packet*/ 
1992/0501    
			if(p->data+len >= hw->ram+hw->size){ 
wraps++; 
1992/0502    
			if((p->data+len) >= (hw->ram+hw->size)){ 
1992/0501    
				len = hw->ram+hw->size - p->data; 
				memmove(rb->pkt+len, 
					&((Ring*)hw->ram)[hw->pstart], 
					p->data+rb->len - hw->ram+hw->size); 
1992/0502    
					(p->data+rb->len) - (hw->ram+hw->size)); 
1992/0425    
			} 
1992/0501    
			memmove(rb->pkt, p->data, len); 
1992/0424    
			rb->owner = Host; 
			cp->ri = NEXT(cp->ri, Nrb); 
1992/0502    
			cp->ri = NEXT(cp->ri, cp->nrb); 
1992/0424    
		} 
 
1992/0501    
p->status = 0; 
1992/0502    
		p->status = 0; 
1992/0424    
		next = p->next; 
		bnry = next-1; 
1992/0501    
		if(bnry < hw->pstart) 
1992/0501/sys/src/9/pc/devether.c:747,7531992/0502/sys/src/9/pc/devether.c:741,746
1992/0424    
	tb = &cp->tb[cp->ti]; 
	if(tb->busy == 0 && tb->owner == Interface){ 
		hw = cp->hw; 
1992/0501    
tb->len = tb->len+1 & ~1; 
		memmove(hw->ram, tb->pkt, tb->len); 
1992/0424    
		OUT(hw, w.tbcr0, tb->len & 0xFF); 
		OUT(hw, w.tbcr1, (tb->len>>8) & 0xFF); 
1992/0501/sys/src/9/pc/devether.c:785,7911992/0502/sys/src/9/pc/devether.c:778,784
1992/0424    
			tb = &cp->tb[cp->ti]; 
			tb->owner = Host; 
			tb->busy = 0; 
			cp->ti = NEXT(cp->ti, Ntb); 
1992/0502    
			cp->ti = NEXT(cp->ti, cp->ntb); 
1992/0424    
			(*cp->hw->transmit)(cp); 
			wakeup(&cp->tr); 
		} 
1992/0501/sys/src/9/pc/devether.c:820,8411992/0502/sys/src/9/pc/devether.c:813,816
1992/0409    
void 
1992/0411    
consdebug(void) 
1992/0409    
{ 
1992/0501    
	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); 
1992/0403    
} 
1992/0502/sys/src/9/pc/devether.c:711,7171992/0503/sys/src/9/pc/devether.c:711,717 (short | long)
1992/0424    
		if(rb->owner == Interface){ 
1992/0501    
			rb->len = len; 
1992/0502    
			if((p->data+len) >= (hw->ram+hw->size)){ 
1992/0501    
				len = hw->ram+hw->size - p->data; 
1992/0503    
				len = (hw->ram+hw->size) - p->data; 
1992/0501    
				memmove(rb->pkt+len, 
					&((Ring*)hw->ram)[hw->pstart], 
1992/0502    
					(p->data+rb->len) - (hw->ram+hw->size)); 
1992/0503/sys/src/9/pc/devether.c:83,941992/0505/sys/src/9/pc/devether.c:83,93 (short | long)
1992/0424    
	uchar	ba[6];		/* broadcast address */ 
1992/0403    
 
1992/0424    
	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 */	 
1992/0403    
 
1992/0424    
	Rendez	tr;		/* rendezvous for a transmit buffer */ 
	QLock	tlock;		/* semaphore on tc */ 
1992/0505    
	QLock	tlock;		/* semaphore on th */ 
1992/0424    
	ushort	th;		/* first transmit buffer belonging to host */	 
	ushort	ti;		/* first transmit buffer belonging to interface */	 
 
1992/0503/sys/src/9/pc/devether.c:333,3381992/0505/sys/src/9/pc/devether.c:332,338
1992/0410    
	tp->prom = 0; 
	tp->inuse = 0; 
	netdisown(&tp->ctlr->net, tp - tp->ctlr->type); 
1992/0505    
	tp->ctlr = 0; 
1992/0410    
	qunlock(tp); 
1992/0403    
} 
 
1992/0503/sys/src/9/pc/devether.c:456,4621992/0505/sys/src/9/pc/devether.c:456,462
1992/0403    
	} 
1992/0404    
	cp->kproc = 1; 
1992/0403    
	for(;;){ 
1992/0424    
		qlock(&cp->rlock); 
1992/0505    
		sleep(&cp->rr, isinput, cp); 
1992/0424    
 
1992/0406    
		/* 
		 * process any internal loopback packets 
1992/0503/sys/src/9/pc/devether.c:477,4851992/0505/sys/src/9/pc/devether.c:477,482
1992/0424    
			rb->owner = Interface; 
1992/0502    
			cp->rh = NEXT(cp->rh, cp->nrb); 
1992/0424    
		} 
1992/0410    
                 
1992/0424    
		qunlock(&cp->rlock); 
		sleep(&cp->rr, isinput, cp); 
	} 
} 
1992/0410    
 
1992/0503/sys/src/9/pc/devether.c:629,6341992/0505/sys/src/9/pc/devether.c:626,643
1992/0424    
	setvec(Ethervec, hw->intr); 
} 
1992/0403    
 
1992/0505    
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 */ 
} 
 
1992/0424    
/* 
 * we leave the chip idling on internal loopback 
 * and pointing to Page0. 
1992/0503/sys/src/9/pc/devether.c:705,7111992/0505/sys/src/9/pc/devether.c:714,726
1992/0424    
			break; 
		cp->inpackets++; 
		p = &((Ring*)hw->ram)[next]; 
1992/0501    
		len = (p->len1<<8)|p->len0-4; 
1992/0505    
		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; 
		} 
1992/0424    
 
		rb = &cp->rb[cp->ri]; 
		if(rb->owner == Interface){ 
1992/0505/sys/src/9/pc/devether.c:716,7231992/0506/sys/src/9/pc/devether.c:716,724 (short | long)
1992/0424    
		p = &((Ring*)hw->ram)[next]; 
1992/0505    
		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, 
1992/0506    
			print("%d/%d : #%2.2ux #%2.2ux  #%2.2ux #%2.2ux\n", next, len, 
1992/0505    
				p->status, p->next, p->len0, p->len1); 
1992/0506    
			panic("receive"); 
1992/0505    
			dp8390rinit(cp); 
			return; 
		} 
1992/0506/sys/src/9/pc/devether.c:59,641992/0625/sys/src/9/pc/devether.c:59,65 (short | long)
1992/0403    
 */ 
1992/0410    
struct Type { 
1992/0403    
	QLock; 
1992/0625    
	Netprot;			/* stat info */ 
1992/0403    
	int	type;			/* ethernet type */ 
	int	prom;			/* promiscuous mode */ 
	Queue	*q; 
1992/0506/sys/src/9/pc/devether.c:96,1021992/0625/sys/src/9/pc/devether.c:97,102
1992/0424    
	uchar	kproc;		/* true if kproc started */ 
	char	name[NAMELEN];	/* name of kproc */ 
1992/0403    
	Network	net; 
1992/0410    
	Netprot	prot[NType]; 
1992/0403    
 
1992/0424    
	Queue	lbq;		/* software loopback packet queue */ 
 
1992/0506/sys/src/9/pc/devether.c:331,3371992/0625/sys/src/9/pc/devether.c:331,337
1992/0410    
	tp->q = 0; 
	tp->prom = 0; 
	tp->inuse = 0; 
	netdisown(&tp->ctlr->net, tp - tp->ctlr->type); 
1992/0625    
	netdisown(tp); 
1992/0505    
	tp->ctlr = 0; 
1992/0410    
	qunlock(tp); 
1992/0403    
} 
1992/0506/sys/src/9/pc/devether.c:357,3631992/0625/sys/src/9/pc/devether.c:357,363
1992/0403    
			continue; 
		} 
1992/0410    
		tp->inuse = 1; 
		netown(&cp->net, tp - cp->type, u->p->user, 0); 
1992/0625    
		netown(tp, u->p->user, 0); 
1992/0410    
		qunlock(tp); 
		return tp - cp->type; 
1992/0403    
	} 
1992/0506/sys/src/9/pc/devether.c:483,4901992/0625/sys/src/9/pc/devether.c:483,492
1992/0424    
void 
etherreset(void) 
{ 
	Ctlr *cp = &ctlr[0]; 
1992/0625    
	int i; 
	Ctlr *cp; 
1992/0410    
 
1992/0625    
	cp = &ctlr[0]; 
1992/0424    
	cp->hw = &wd8013; 
	(*cp->hw->reset)(cp); 
1992/0410    
 
1992/0506/sys/src/9/pc/devether.c:497,5071992/0625/sys/src/9/pc/devether.c:499,510
1992/0424    
	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; 
1992/0625    
	for(i = 0; i < NType; i++) 
		netadd(&cp->net, &cp->type[i], i); 
1992/0403    
} 
 
1992/0425    
void 
1992/0506/sys/src/9/pc/devether.c:611,6191992/0625/sys/src/9/pc/devether.c:614,622
1992/0424    
	int i; 
	uchar msr; 
1992/0403    
 
1992/0501    
	cp->rb = ialloc(sizeof(Buffer)*Nrb, 1); 
1992/0625    
	cp->rb = xspanalloc(sizeof(Buffer)*Nrb, BY2PG, 0); 
1992/0501    
	cp->nrb = Nrb; 
1992/0502    
	cp->tb = ialloc(sizeof(Buffer)*Ntb, 1); 
1992/0625    
	cp->tb = xspanalloc(sizeof(Buffer)*Ntb, BY2PG, 0); 
1992/0502    
	cp->ntb = Ntb; 
1992/0424    
 
	msr = IN(hw, msr); 
1992/0625/sys/src/9/pc/devether.c:143,1481992/0711/sys/src/9/pc/devether.c:143,149 (short | long)
1992/0424    
void 
ethercreate(Chan *c, char *name, int omode, ulong perm) 
{ 
1992/0711    
	USED(c, name, omode, perm); 
1992/0424    
	error(Eperm); 
} 
 
1992/0625/sys/src/9/pc/devether.c:162,1671992/0711/sys/src/9/pc/devether.c:163,169
1992/0424    
long 
etherwrite(Chan *c, char *a, long n, ulong offset) 
{ 
1992/0711    
	USED(offset); 
1992/0424    
	return streamwrite(c, a, n, 0); 
} 
 
1992/0625/sys/src/9/pc/devether.c:168,1731992/0711/sys/src/9/pc/devether.c:170,176
1992/0424    
void 
etherremove(Chan *c) 
{ 
1992/0711    
	USED(c); 
1992/0424    
	error(Eperm); 
} 
 
1992/0625/sys/src/9/pc/devether.c:350,3551992/0711/sys/src/9/pc/devether.c:353,359
1992/0404    
	Ctlr *cp = &ctlr[0]; 
1992/0410    
	Type *tp; 
1992/0403    
 
1992/0711    
	USED(c); 
1992/0410    
	for(tp = cp->type; tp < &cp->type[NType]; tp++){ 
		qlock(tp); 
		if(tp->inuse || tp->q){ 
1992/0625/sys/src/9/pc/devether.c:362,3671992/0711/sys/src/9/pc/devether.c:366,372
1992/0410    
		return tp - cp->type; 
1992/0403    
	} 
	exhausted("ether channels"); 
1992/0711    
	return 0; 
1992/0403    
} 
 
static void 
1992/0625/sys/src/9/pc/devether.c:370,3751992/0711/sys/src/9/pc/devether.c:375,381
1992/0404    
	Ctlr *cp = &ctlr[0]; 
1992/0403    
	char buf[256]; 
 
1992/0711    
	USED(c); 
1992/0403    
	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", 
1992/0404    
		cp->inpackets, cp->outpackets, cp->crcs, 
		cp->overflows, cp->frames, cp->buffs, cp->oerrs, 
1992/0625/sys/src/9/pc/devether.c:693,6981992/0711/sys/src/9/pc/devether.c:699,705
1992/0424    
static void 
wd8013online(Ctlr *cp, int on) 
1992/0403    
{ 
1992/0711    
	USED(on); 
1992/0424    
	OUT(cp->hw, w.tcr, 0); 
1992/0403    
} 
 
1992/0625/sys/src/9/pc/devether.c:777,7821992/0711/sys/src/9/pc/devether.c:784,790
1992/0424    
	Buffer *tb; 
	uchar isr; 
 
1992/0711    
	USED(ur); 
1992/0424    
	while(isr = IN(hw, r.isr)){ 
		OUT(hw, w.isr, isr); 
		if(isr & 0x08)			/* Txe - transmit error */ 
1992/0711/sys/src/9/pc/devether.c:600,6051992/0905/sys/src/9/pc/devether.c:600,612 (short | long)
1992/0424    
	}; 
} Wd8013; 
1992/0403    
 
1992/0905    
enum { 
	MENB		= 0x40,			/* memory enable */ 
 
	L16EN		= 0x40,			/* enable 16-bit LAN operation */ 
	M16EN		= 0x80,			/* enable 16-bit memory access */ 
}; 
 
1992/0424    
#define IN(hw, m)	inb((hw)->addr+OFFSETOF(Wd8013, m)) 
#define OUT(hw, m, x)	outb((hw)->addr+OFFSETOF(Wd8013, m), (x)) 
 
1992/0711/sys/src/9/pc/devether.c:611,6161992/0905/sys/src/9/pc/devether.c:618,644
1992/0501    
	uchar	data[256-4]; 
} Ring; 
 
1992/0905    
 
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)); 
} 
 
1992/0424    
/* 
 */ 
static void 
1992/0711/sys/src/9/pc/devether.c:619,6241992/0905/sys/src/9/pc/devether.c:647,653
1992/0424    
	Hw *hw = cp->hw; 
	int i; 
	uchar msr; 
1992/0905    
	ulong ram; 
1992/0403    
 
1992/0625    
	cp->rb = xspanalloc(sizeof(Buffer)*Nrb, BY2PG, 0); 
1992/0501    
	cp->nrb = Nrb; 
1992/0711/sys/src/9/pc/devether.c:626,6361992/0905/sys/src/9/pc/devether.c:655,671
1992/0502    
	cp->ntb = Ntb; 
1992/0424    
 
	msr = IN(hw, msr); 
	OUT(hw, msr, 0x40|msr); 
1992/0905    
	OUT(hw, msr, MENB|msr); 
1992/0424    
 
	for(i = 0; i < sizeof(cp->ea); i++) 
		cp->ea[i] = IN(hw, lan[i]); 
1992/0501    
 
1992/0905    
	/* 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); 
 
1992/0424    
	(*hw->init)(cp); 
	setvec(Ethervec, hw->intr); 
} 
1992/0711/sys/src/9/pc/devether.c:704,7091992/0905/sys/src/9/pc/devether.c:739,755
1992/0403    
} 
 
1992/0424    
static void 
1992/0905    
bmemmove(void *a, void *b, int n) 
{ 
	uchar *to, *from; 
 
	to = a; 
	from = b; 
	while(n-- > 0) 
		*to++ = *from++; 
} 
 
static void 
1992/0424    
wd8013receive(Ctlr *cp) 
1992/0403    
{ 
1992/0424    
	Hw *hw = cp->hw; 
1992/0711/sys/src/9/pc/devether.c:723,7361992/0905/sys/src/9/pc/devether.c:769,786
1992/0424    
		if(next == curr) 
			break; 
		cp->inpackets++; 
1992/0905    
print("*"); 
OUT(hw, laar, 0xC1); 
print("!"); 
1992/0424    
		p = &((Ring*)hw->ram)[next]; 
1992/0905    
{ int ii; for(ii = 0; ii < 30; ii++) print("%2.2ux ", p->data[ii]); for(;;); } 
1992/0505    
		len = ((p->len1<<8)|p->len0)-4; 
		if(p->next < hw->pstart || p->next >= hw->pstop || len < 60){ 
1992/0506    
			print("%d/%d : #%2.2ux #%2.2ux  #%2.2ux #%2.2ux\n", next, len, 
1992/0505    
				p->status, p->next, p->len0, p->len1); 
1992/0506    
			panic("receive"); 
1992/0905    
OUT(hw, laar, 0x01); 
1992/0505    
			dp8390rinit(cp); 
			return; 
1992/0905    
			break; 
1992/0505    
		} 
1992/0424    
 
		rb = &cp->rb[cp->ri]; 
1992/0711/sys/src/9/pc/devether.c:738,7481992/0905/sys/src/9/pc/devether.c:788,798
1992/0501    
			rb->len = len; 
1992/0502    
			if((p->data+len) >= (hw->ram+hw->size)){ 
1992/0503    
				len = (hw->ram+hw->size) - p->data; 
1992/0501    
				memmove(rb->pkt+len, 
1992/0905    
				bmemmove(rb->pkt+len, 
1992/0501    
					&((Ring*)hw->ram)[hw->pstart], 
1992/0502    
					(p->data+rb->len) - (hw->ram+hw->size)); 
1992/0425    
			} 
1992/0501    
			memmove(rb->pkt, p->data, len); 
1992/0905    
			bmemmove(rb->pkt, p->data, len); 
1992/0424    
			rb->owner = Host; 
1992/0502    
			cp->ri = NEXT(cp->ri, cp->nrb); 
1992/0424    
		} 
1992/0711/sys/src/9/pc/devether.c:749,7591992/0905/sys/src/9/pc/devether.c:799,812
1992/0424    
 
1992/0502    
		p->status = 0; 
1992/0424    
		next = p->next; 
1992/0905    
OUT(hw, laar, 0x01); 
print("?"); 
1992/0424    
		bnry = next-1; 
1992/0501    
		if(bnry < hw->pstart) 
			bnry = hw->pstop-1; 
1992/0424    
		OUT(hw, w.bnry, bnry); 
	} 
1992/0905    
print(">"); 
1992/0403    
} 
 
1992/0424    
static void 
1992/0711/sys/src/9/pc/devether.c:767,7731992/0905/sys/src/9/pc/devether.c:820,826
1992/0424    
	tb = &cp->tb[cp->ti]; 
	if(tb->busy == 0 && tb->owner == Interface){ 
		hw = cp->hw; 
1992/0501    
		memmove(hw->ram, tb->pkt, tb->len); 
1992/0905    
		bmemmove(hw->ram, tb->pkt, tb->len); 
1992/0424    
		OUT(hw, w.tbcr0, tb->len & 0xFF); 
		OUT(hw, w.tbcr1, (tb->len>>8) & 0xFF); 
		OUT(hw, w.cr, 0x26);		/* Page0|RD2|TXP|STA */ 
1992/0711/sys/src/9/pc/devether.c:823,8291992/0905/sys/src/9/pc/devether.c:876,882
1992/0409    
 
1992/0424    
static Hw wd8013 = { 
	0x360,					/* I/O base address */ 
	KZERO|0xC8000,				/* shared memory address */ 
1992/0905    
	KZERO|0xF0000,				/* shared memory address */ 
1992/0501    
	8*1024, 
	0, 
	HOWMANY(sizeof(Etherpkt), 256), 
1992/0711/sys/src/9/pc/devether.c:836,8431992/0905/sys/src/9/pc/devether.c:889,891
1992/0424    
	wd8013transmit, 
	wd8013intr, 
}; 
                 
1992/0409    
void 
1992/0411    
consdebug(void) 
1992/0409    
{ 
1992/0403    
} 
1992/0905/sys/src/9/pc/devether.c:15,201992/0906/sys/src/9/pc/devether.c:15,22 (short | long)
1992/0424    
struct Hw { 
	int	addr;			/* interface address */ 
1992/0501    
	uchar	*ram;			/* interface shared memory address */ 
1992/0906    
	int	bt16;			/* true if a 16 bit interface */ 
	int	lvl;			/* interrupt level */ 
1992/0501    
	int	size; 
	uchar	tstart; 
	uchar	pstart; 
1992/0905/sys/src/9/pc/devether.c:639,6451992/0906/sys/src/9/pc/devether.c:641,654
1992/0905    
	print("id=#%2.2ux\n", IN(hw, id)); 
} 
 
1992/0906    
/* mapping from configuration bits to interrupt level */ 
int intrmap[] = 
{ 
	9, 3, 5, 7, 10, 11, 15, 4, 
}; 
 
1992/0424    
/* 
1992/0906    
 *  get configuration parameters, enable memory 
1992/0424    
 */ 
static void 
wd8013reset(Ctlr *cp) 
1992/0905/sys/src/9/pc/devether.c:647,6521992/0906/sys/src/9/pc/devether.c:656,664
1992/0424    
	Hw *hw = cp->hw; 
	int i; 
	uchar msr; 
1992/0906    
	uchar icr; 
	uchar laar; 
	uchar irr; 
1992/0905    
	ulong ram; 
1992/0403    
 
1992/0625    
	cp->rb = xspanalloc(sizeof(Buffer)*Nrb, BY2PG, 0); 
1992/0905/sys/src/9/pc/devether.c:655,6731992/0906/sys/src/9/pc/devether.c:667,713
1992/0502    
	cp->ntb = Ntb; 
1992/0424    
 
	msr = IN(hw, msr); 
1992/0905    
	OUT(hw, msr, MENB|msr); 
1992/0906    
	icr = IN(hw, icr); 
	irr = IN(hw, irr); 
	laar = IN(hw, laar); 
1992/0424    
 
1992/0906    
	/* ethernet address */ 
1992/0424    
	for(i = 0; i < sizeof(cp->ea); i++) 
		cp->ea[i] = IN(hw, lan[i]); 
1992/0501    
 
1992/0905    
	/* get configuration info from card */ 
	ram = (IN(hw, msr) & 0x3f) << 13; 
	ram |= KZERO|0x80000; 
1992/0906    
	/* 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; 
1992/0905    
	hw->ram = (uchar*)ram; 
print("ether ram is at %lux\n", ram); 
 
1992/0906    
	/* 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); 
 
1992/0424    
	(*hw->init)(cp); 
	setvec(Ethervec, hw->intr); 
1992/0906    
	setvec(Int0vec + hw->lvl, hw->intr); 
1992/0424    
} 
1992/0403    
 
1992/0505    
static void 
1992/0905/sys/src/9/pc/devether.c:693,6991992/0906/sys/src/9/pc/devether.c:733,742
1992/0424    
	int i; 
 
	OUT(hw, w.cr, 0x21);			/* Page0|RD2|STP */ 
	OUT(hw, w.dcr, 0x48);			/* FT1|LS */ 
1992/0906    
	if(hw->bt16) 
		OUT(hw, w.dcr, 0x49);		/* 16 bit interface, DMA burst size 8 */ 
	else 
		OUT(hw, w.dcr, 0x48);		/* FT1|LS */ 
1992/0424    
	OUT(hw, w.rbcr0, 0); 
	OUT(hw, w.rbcr1, 0); 
	OUT(hw, w.rcr, 0x04);			/* AB */ 
1992/0905/sys/src/9/pc/devether.c:739,7551992/0906/sys/src/9/pc/devether.c:782,787
1992/0403    
} 
 
1992/0424    
static void 
1992/0905    
bmemmove(void *a, void *b, int n) 
{ 
	uchar *to, *from; 
                 
	to = a; 
	from = b; 
	while(n-- > 0) 
		*to++ = *from++; 
} 
                 
static void 
1992/0424    
wd8013receive(Ctlr *cp) 
1992/0403    
{ 
1992/0424    
	Hw *hw = cp->hw; 
1992/0905/sys/src/9/pc/devether.c:769,7841992/0906/sys/src/9/pc/devether.c:801,811
1992/0424    
		if(next == curr) 
			break; 
		cp->inpackets++; 
1992/0905    
print("*"); 
OUT(hw, laar, 0xC1); 
print("!"); 
1992/0424    
		p = &((Ring*)hw->ram)[next]; 
1992/0905    
{ int ii; for(ii = 0; ii < 30; ii++) print("%2.2ux ", p->data[ii]); for(;;); } 
1992/0505    
		len = ((p->len1<<8)|p->len0)-4; 
		if(p->next < hw->pstart || p->next >= hw->pstop || len < 60){ 
1992/0506    
			print("%d/%d : #%2.2ux #%2.2ux  #%2.2ux #%2.2ux\n", next, len, 
1992/0505    
				p->status, p->next, p->len0, p->len1); 
1992/0905    
OUT(hw, laar, 0x01); 
1992/0505    
			dp8390rinit(cp); 
1992/0905    
			break; 
1992/0505    
		} 
1992/0905/sys/src/9/pc/devether.c:788,7981992/0906/sys/src/9/pc/devether.c:815,825
1992/0501    
			rb->len = len; 
1992/0502    
			if((p->data+len) >= (hw->ram+hw->size)){ 
1992/0503    
				len = (hw->ram+hw->size) - p->data; 
1992/0905    
				bmemmove(rb->pkt+len, 
1992/0906    
				memmove(rb->pkt+len, 
1992/0501    
					&((Ring*)hw->ram)[hw->pstart], 
1992/0502    
					(p->data+rb->len) - (hw->ram+hw->size)); 
1992/0425    
			} 
1992/0905    
			bmemmove(rb->pkt, p->data, len); 
1992/0906    
			memmove(rb->pkt, p->data, len); 
1992/0424    
			rb->owner = Host; 
1992/0502    
			cp->ri = NEXT(cp->ri, cp->nrb); 
1992/0424    
		} 
1992/0905/sys/src/9/pc/devether.c:799,8121992/0906/sys/src/9/pc/devether.c:826,836
1992/0424    
 
1992/0502    
		p->status = 0; 
1992/0424    
		next = p->next; 
1992/0905    
OUT(hw, laar, 0x01); 
print("?"); 
1992/0424    
		bnry = next-1; 
1992/0501    
		if(bnry < hw->pstart) 
			bnry = hw->pstop-1; 
1992/0424    
		OUT(hw, w.bnry, bnry); 
	} 
1992/0905    
print(">"); 
1992/0403    
} 
 
1992/0424    
static void 
1992/0905/sys/src/9/pc/devether.c:817,8261992/0906/sys/src/9/pc/devether.c:841,850
1992/0424    
	int s; 
 
	s = splhi(); 
1992/0906    
	hw = cp->hw; 
1992/0424    
	tb = &cp->tb[cp->ti]; 
	if(tb->busy == 0 && tb->owner == Interface){ 
		hw = cp->hw; 
1992/0905    
		bmemmove(hw->ram, tb->pkt, tb->len); 
1992/0906    
		memmove(hw->ram, tb->pkt, tb->len); 
1992/0424    
		OUT(hw, w.tbcr0, tb->len & 0xFF); 
		OUT(hw, w.tbcr1, (tb->len>>8) & 0xFF); 
		OUT(hw, w.cr, 0x26);		/* Page0|RD2|TXP|STA */ 
1992/0905/sys/src/9/pc/devether.c:876,8861992/0906/sys/src/9/pc/devether.c:900,912
1992/0409    
 
1992/0424    
static Hw wd8013 = { 
	0x360,					/* I/O base address */ 
1992/0905    
	KZERO|0xF0000,				/* shared memory address */ 
1992/0501    
	8*1024, 
	0, 
1992/0906    
	0, 
	0, 
	0, 
	0, 
1992/0501    
	HOWMANY(sizeof(Etherpkt), 256), 
	HOWMANY(8*1024, 256), 
1992/0906    
	0, 
1992/0424    
	wd8013reset, 
	wd8013init, 
	wd8013mode, 
1992/0906/sys/src/9/pc/devether.c:13,181992/0909/sys/src/9/pc/devether.c:13,26 (short | long)
1992/0424    
typedef struct Ctlr Ctlr; 
1992/0403    
 
1992/0424    
struct Hw { 
1992/0909    
	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*); 
1992/0424    
	int	addr;			/* interface address */ 
1992/0501    
	uchar	*ram;			/* interface shared memory address */ 
1992/0906    
	int	bt16;			/* true if a 16 bit interface */ 
1992/0906/sys/src/9/pc/devether.c:21,331992/0909/sys/src/9/pc/devether.c:29,34
1992/0501    
	uchar	tstart; 
	uchar	pstart; 
	uchar	pstop; 
1992/0424    
	void	(*reset)(Ctlr*); 
	void	(*init)(Ctlr*); 
	void	(*mode)(Ctlr*, int); 
	void	(*online)(Ctlr*, int); 
	void	(*receive)(Ctlr*); 
	void	(*transmit)(Ctlr*); 
	void	(*intr)(Ureg*); 
1992/0404    
}; 
1992/0424    
static Hw wd8013; 
1992/0404    
 
1992/0906/sys/src/9/pc/devether.c:464,4701992/0909/sys/src/9/pc/devether.c:465,472
1992/0403    
	} 
1992/0404    
	cp->kproc = 1; 
1992/0403    
	for(;;){ 
1992/0505    
		sleep(&cp->rr, isinput, cp); 
1992/0909    
		tsleep(&cp->rr, isinput, cp, 1000); 
		(*cp->hw->tweek)(cp); 
1992/0424    
 
1992/0406    
		/* 
		 * process any internal loopback packets 
1992/0906/sys/src/9/pc/devether.c:620,6261992/0909/sys/src/9/pc/devether.c:622,627
1992/0501    
	uchar	data[256-4]; 
} Ring; 
 
1992/0905    
                 
static void 
wd8013dumpregs(Hw *hw) 
{ 
1992/0906/sys/src/9/pc/devether.c:696,7011992/0909/sys/src/9/pc/devether.c:697,703
1992/0906    
		hw->size = 8*1024; 
	if(hw->bt16) 
		hw->size <<= 1; 
1992/0909    
	hw->pstart = HOWMANY(sizeof(Etherpkt), 256); 
1992/0906    
	hw->pstop = HOWMANY(hw->size, 256); 
 
print("ether width %d addr %lux size %d lvl %d\n", hw->bt16?16:8, 
1992/0906/sys/src/9/pc/devether.c:704,7101992/0909/sys/src/9/pc/devether.c:706,712
1992/0906    
	/* enable interface RAM, set interface width */ 
	OUT(hw, msr, MENB|msr); 
	if(hw->bt16) 
		OUT(hw, laar, laar|L16EN|M16EN); 
1992/0909    
		OUT(hw, laar, laar|L16EN); 
1992/0906    
 
1992/0424    
	(*hw->init)(cp); 
1992/0906    
	setvec(Int0vec + hw->lvl, hw->intr); 
1992/0906/sys/src/9/pc/devether.c:711,7161992/0909/sys/src/9/pc/devether.c:713,752
1992/0424    
} 
1992/0403    
 
1992/0505    
static void 
1992/0909    
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 
1992/0505    
dp8390rinit(Ctlr *cp) 
{ 
	Hw *hw = cp->hw; 
1992/0906/sys/src/9/pc/devether.c:727,7331992/0909/sys/src/9/pc/devether.c:763,769
1992/0424    
 * and pointing to Page0. 
 */ 
static void 
wd8013init(Ctlr *cp) 
1992/0909    
dp8390init(Ctlr *cp) 
1992/0403    
{ 
1992/0424    
	Hw *hw = cp->hw; 
	int i; 
1992/0906/sys/src/9/pc/devether.c:805,8111992/0909/sys/src/9/pc/devether.c:841,847
1992/0505    
		len = ((p->len1<<8)|p->len0)-4; 
		if(p->next < hw->pstart || p->next >= hw->pstop || len < 60){ 
1992/0506    
			print("%d/%d : #%2.2ux #%2.2ux  #%2.2ux #%2.2ux\n", next, len, 
1992/0505    
				p->status, p->next, p->len0, p->len1); 
1992/0909    
				p->status, p->next, p->len0, p->len1);/**/ 
1992/0505    
			dp8390rinit(cp); 
1992/0905    
			break; 
1992/0505    
		} 
1992/0906/sys/src/9/pc/devether.c:839,8541992/0909/sys/src/9/pc/devether.c:875,900
1992/0424    
	Hw *hw; 
	Buffer *tb; 
	int s; 
1992/0909    
	uchar laar; 
1992/0424    
 
	s = splhi(); 
1992/0906    
	hw = cp->hw; 
1992/0424    
	tb = &cp->tb[cp->ti]; 
	if(tb->busy == 0 && tb->owner == Interface){ 
1992/0909    
		if(hw->bt16){ 
			OUT(hw, w.imr, 0x0); 
			laar = IN(hw, laar); 
			OUT(hw, laar, laar|M16EN); 
		} 
1992/0906    
		memmove(hw->ram, tb->pkt, tb->len); 
1992/0424    
		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; 
1992/0909    
		if(hw->bt16 && (laar&M16EN)==0){ 
			OUT(hw, laar, laar); 
			OUT(hw, w.imr, 0x1F); 
		} 
1992/0424    
	} 
	splx(s); 
1992/0403    
} 
1992/0906/sys/src/9/pc/devether.c:859,8661992/0909/sys/src/9/pc/devether.c:905,917
1992/0424    
	Ctlr *cp = &ctlr[0]; 
	Hw *hw = cp->hw; 
	Buffer *tb; 
	uchar isr; 
1992/0909    
	uchar isr, laar; 
1992/0424    
 
1992/0909    
	if(hw->bt16){ 
		laar = IN(hw, laar); 
		OUT(hw, w.imr, 0x0); 
		OUT(hw, laar, laar|M16EN); 
	} 
1992/0711    
	USED(ur); 
1992/0424    
	while(isr = IN(hw, r.isr)){ 
		OUT(hw, w.isr, isr); 
1992/0906/sys/src/9/pc/devether.c:896,9171992/0909/sys/src/9/pc/devether.c:947,967
1992/0424    
			wakeup(&cp->rr); 
		} 
	} 
1992/0909    
	if(hw->bt16){ 
		OUT(hw, laar, laar); 
		OUT(hw, w.imr, 0x1F); 
	} 
1992/0409    
} 
 
1992/0424    
static Hw wd8013 = { 
	0x360,					/* I/O base address */ 
1992/0501    
	0, 
1992/0906    
	0, 
	0, 
	0, 
	0, 
1992/0501    
	HOWMANY(sizeof(Etherpkt), 256), 
1992/0906    
	0, 
1992/0909    
static Hw wd8013 = 
{ 
1992/0424    
	wd8013reset, 
	wd8013init, 
1992/0909    
	dp8390init, 
1992/0424    
	wd8013mode, 
	wd8013online, 
	wd8013receive, 
	wd8013transmit, 
	wd8013intr, 
1992/0909    
	wd8013tweek, 
	0x360,					/* I/O base address */ 
1992/0424    
}; 
1992/0909/sys/src/9/pc/devether.c:20,261992/0913/sys/src/9/pc/devether.c:20,25 (short | long)
1992/0909    
	void	(*receive)(Ctlr*); 
	void	(*transmit)(Ctlr*); 
	void	(*intr)(Ureg*); 
	void	(*tweek)(Ctlr*); 
1992/0424    
	int	addr;			/* interface address */ 
1992/0501    
	uchar	*ram;			/* interface shared memory address */ 
1992/0906    
	int	bt16;			/* true if a 16 bit interface */ 
1992/0909/sys/src/9/pc/devether.c:465,4721992/0913/sys/src/9/pc/devether.c:464,470
1992/0403    
	} 
1992/0404    
	cp->kproc = 1; 
1992/0403    
	for(;;){ 
1992/0909    
		tsleep(&cp->rr, isinput, cp, 1000); 
		(*cp->hw->tweek)(cp); 
1992/0913    
		sleep(&cp->rr, isinput, cp); 
1992/0424    
 
1992/0406    
		/* 
		 * process any internal loopback packets 
1992/0909/sys/src/9/pc/devether.c:713,7521992/0913/sys/src/9/pc/devether.c:711,716
1992/0424    
} 
1992/0403    
 
1992/0505    
static void 
1992/0909    
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 
1992/0505    
dp8390rinit(Ctlr *cp) 
{ 
	Hw *hw = cp->hw; 
1992/0909/sys/src/9/pc/devether.c:962,9671992/0913/sys/src/9/pc/devether.c:926,930
1992/0424    
	wd8013receive, 
	wd8013transmit, 
	wd8013intr, 
1992/0909    
	wd8013tweek, 
	0x360,					/* I/O base address */ 
1992/0424    
}; 
1992/0913/sys/src/9/pc/devether.c:20,251992/0915/sys/src/9/pc/devether.c:20,26 (short | long)
1992/0909    
	void	(*receive)(Ctlr*); 
	void	(*transmit)(Ctlr*); 
	void	(*intr)(Ureg*); 
1992/0915    
	void	(*tweek)(Ctlr*); 
1992/0424    
	int	addr;			/* interface address */ 
1992/0501    
	uchar	*ram;			/* interface shared memory address */ 
1992/0906    
	int	bt16;			/* true if a 16 bit interface */ 
1992/0913/sys/src/9/pc/devether.c:464,4701992/0915/sys/src/9/pc/devether.c:465,472
1992/0403    
	} 
1992/0404    
	cp->kproc = 1; 
1992/0403    
	for(;;){ 
1992/0913    
		sleep(&cp->rr, isinput, cp); 
1992/0915    
		tsleep(&cp->rr, isinput, cp, 500); 
		(*cp->hw->tweek)(cp); 
1992/0424    
 
1992/0406    
		/* 
		 * process any internal loopback packets 
1992/0913/sys/src/9/pc/devether.c:660,6691992/0915/sys/src/9/pc/devether.c:662,673
1992/0906    
	uchar irr; 
1992/0905    
	ulong ram; 
1992/0403    
 
1992/0625    
	cp->rb = xspanalloc(sizeof(Buffer)*Nrb, BY2PG, 0); 
1992/0501    
	cp->nrb = Nrb; 
1992/0625    
	cp->tb = xspanalloc(sizeof(Buffer)*Ntb, BY2PG, 0); 
1992/0502    
	cp->ntb = Ntb; 
1992/0915    
	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; 
	} 
1992/0424    
 
	msr = IN(hw, msr); 
1992/0906    
	icr = IN(hw, icr); 
1992/0913/sys/src/9/pc/devether.c:698,7101992/0915/sys/src/9/pc/devether.c:702,714
1992/0909    
	hw->pstart = HOWMANY(sizeof(Etherpkt), 256); 
1992/0906    
	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); 
1992/0915    
/* print("ether width %d addr %lux size %d lvl %d\n", hw->bt16?16:8, 
	hw->ram, hw->size, hw->lvl);/**/ 
1992/0906    
 
	/* enable interface RAM, set interface width */ 
	OUT(hw, msr, MENB|msr); 
	if(hw->bt16) 
1992/0909    
		OUT(hw, laar, laar|L16EN); 
1992/0915    
		OUT(hw, laar, laar|L16EN|M16EN); 
1992/0906    
 
1992/0424    
	(*hw->init)(cp); 
1992/0906    
	setvec(Int0vec + hw->lvl, hw->intr); 
1992/0913/sys/src/9/pc/devether.c:734,7451992/0915/sys/src/9/pc/devether.c:738,752
1992/0424    
 
	OUT(hw, w.cr, 0x21);			/* Page0|RD2|STP */ 
1992/0906    
	if(hw->bt16) 
		OUT(hw, w.dcr, 0x49);		/* 16 bit interface, DMA burst size 8 */ 
1992/0915    
		OUT(hw, w.dcr, 0x61);		/* 16 bit interface */ 
1992/0906    
	else 
		OUT(hw, w.dcr, 0x48);		/* FT1|LS */ 
1992/0424    
	OUT(hw, w.rbcr0, 0); 
	OUT(hw, w.rbcr1, 0); 
	OUT(hw, w.rcr, 0x04);			/* AB */ 
1992/0915    
	if(cp->prom) 
		OUT(hw, w.rcr, 0x14);		/* PRO|AB */ 
	else 
		OUT(hw, w.rcr, 0x04);		/* AB */ 
1992/0424    
	OUT(hw, w.tcr, 0x20);			/* LB0 */ 
 
1992/0501    
	OUT(hw, w.bnry, hw->pstart); 
1992/0913/sys/src/9/pc/devether.c:782,7871992/0915/sys/src/9/pc/devether.c:789,816
1992/0403    
} 
 
1992/0424    
static void 
1992/0915    
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 
1992/0424    
wd8013receive(Ctlr *cp) 
1992/0403    
{ 
1992/0424    
	Hw *hw = cp->hw; 
1992/0913/sys/src/9/pc/devether.c:804,8111992/0915/sys/src/9/pc/devether.c:833,841
1992/0424    
		p = &((Ring*)hw->ram)[next]; 
1992/0505    
		len = ((p->len1<<8)|p->len0)-4; 
		if(p->next < hw->pstart || p->next >= hw->pstop || len < 60){ 
1992/0506    
			print("%d/%d : #%2.2ux #%2.2ux  #%2.2ux #%2.2ux\n", next, len, 
1992/0915    
/*			print("%d/%d : #%2.2ux #%2.2ux  #%2.2ux #%2.2ux\n", next, len, 
1992/0909    
				p->status, p->next, p->len0, p->len1);/**/ 
1992/0915    
			delay(100); 
1992/0505    
			dp8390rinit(cp); 
1992/0905    
			break; 
1992/0505    
		} 
1992/0913/sys/src/9/pc/devether.c:830,8351992/0915/sys/src/9/pc/devether.c:860,866
1992/0501    
		if(bnry < hw->pstart) 
			bnry = hw->pstop-1; 
1992/0424    
		OUT(hw, w.bnry, bnry); 
1992/0915    
		break; 
1992/0424    
	} 
1992/0403    
} 
 
1992/0913/sys/src/9/pc/devether.c:839,8641992/0915/sys/src/9/pc/devether.c:870,885
1992/0424    
	Hw *hw; 
	Buffer *tb; 
	int s; 
1992/0909    
	uchar laar; 
1992/0424    
 
	s = splhi(); 
1992/0906    
	hw = cp->hw; 
1992/0424    
	tb = &cp->tb[cp->ti]; 
	if(tb->busy == 0 && tb->owner == Interface){ 
1992/0909    
		if(hw->bt16){ 
			OUT(hw, w.imr, 0x0); 
			laar = IN(hw, laar); 
			OUT(hw, laar, laar|M16EN); 
		} 
1992/0906    
		memmove(hw->ram, tb->pkt, tb->len); 
1992/0424    
		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; 
1992/0909    
		if(hw->bt16 && (laar&M16EN)==0){ 
			OUT(hw, laar, laar); 
			OUT(hw, w.imr, 0x1F); 
		} 
1992/0424    
	} 
	splx(s); 
1992/0403    
} 
1992/0913/sys/src/9/pc/devether.c:869,8811992/0915/sys/src/9/pc/devether.c:890,897
1992/0424    
	Ctlr *cp = &ctlr[0]; 
	Hw *hw = cp->hw; 
	Buffer *tb; 
1992/0909    
	uchar isr, laar; 
1992/0915    
	uchar isr; 
1992/0424    
 
1992/0909    
	if(hw->bt16){ 
		laar = IN(hw, laar); 
		OUT(hw, w.imr, 0x0); 
		OUT(hw, laar, laar|M16EN); 
	} 
1992/0711    
	USED(ur); 
1992/0424    
	while(isr = IN(hw, r.isr)){ 
		OUT(hw, w.isr, isr); 
1992/0913/sys/src/9/pc/devether.c:911,9201992/0915/sys/src/9/pc/devether.c:927,932
1992/0424    
			wakeup(&cp->rr); 
		} 
	} 
1992/0909    
	if(hw->bt16){ 
		OUT(hw, laar, laar); 
		OUT(hw, w.imr, 0x1F); 
	} 
1992/0409    
} 
 
1992/0909    
static Hw wd8013 = 
1992/0913/sys/src/9/pc/devether.c:926,9301992/0915/sys/src/9/pc/devether.c:938,943
1992/0424    
	wd8013receive, 
	wd8013transmit, 
	wd8013intr, 
1992/0915    
	wd8013tweek, 
1992/0909    
	0x360,					/* I/O base address */ 
1992/0424    
}; 
1992/0915/sys/src/9/pc/devether.c:738,7441992/0916/sys/src/9/pc/devether.c:738,744 (short | long)
1992/0424    
 
	OUT(hw, w.cr, 0x21);			/* Page0|RD2|STP */ 
1992/0906    
	if(hw->bt16) 
1992/0915    
		OUT(hw, w.dcr, 0x61);		/* 16 bit interface */ 
1992/0916    
		OUT(hw, w.dcr, 0x01);		/* 16 bit interface */ 
1992/0906    
	else 
		OUT(hw, w.dcr, 0x48);		/* FT1|LS */ 
1992/0424    
	OUT(hw, w.rbcr0, 0); 
1992/0916/sys/src/9/pc/devether.c:13,191992/0917/sys/src/9/pc/devether.c:13,19 (short | long)
1992/0424    
typedef struct Ctlr Ctlr; 
1992/0403    
 
1992/0424    
struct Hw { 
1992/0909    
	void	(*reset)(Ctlr*); 
1992/0917    
	int	(*reset)(Ctlr*); 
1992/0909    
	void	(*init)(Ctlr*); 
	void	(*mode)(Ctlr*, int); 
	void	(*online)(Ctlr*, int); 
1992/0916/sys/src/9/pc/devether.c:77,821992/0917/sys/src/9/pc/devether.c:77,83
1992/0403    
	QLock; 
 
1992/0424    
	Hw	*hw; 
1992/0917    
	int	present; 
1992/0403    
 
1992/0424    
	ushort	nrb;		/* number of software receive buffers */ 
	ushort	ntb;		/* number of software transmit buffers */ 
1992/0916/sys/src/9/pc/devether.c:116,1211992/0917/sys/src/9/pc/devether.c:117,124
1992/0425    
Chan* 
etherattach(char *spec) 
1992/0424    
{ 
1992/0917    
	if(ctlr[0].present == 0) 
		error(Enodev); 
1992/0425    
	return devattach('l', spec); 
1992/0424    
} 
1992/0411    
 
1992/0916/sys/src/9/pc/devether.c:498,5041992/0917/sys/src/9/pc/devether.c:501,511
1992/0410    
 
1992/0625    
	cp = &ctlr[0]; 
1992/0424    
	cp->hw = &wd8013; 
	(*cp->hw->reset)(cp); 
1992/0917    
	if((*cp->hw->reset)(cp) < 0){ 
		cp->present = 0; 
		return; 
	} 
	cp->present = 1; 
1992/0410    
 
1992/0424    
	memset(cp->ba, 0xFF, sizeof(cp->ba)); 
1992/0410    
 
1992/0916/sys/src/9/pc/devether.c:524,5291992/0917/sys/src/9/pc/devether.c:531,539
1992/0424    
	Ctlr *cp = &ctlr[ctlrno]; 
	int i; 
1992/0403    
 
1992/0917    
	if(cp->present == 0) 
		return; 
 
1992/0424    
	cp->rh = 0; 
	cp->ri = 0; 
	for(i = 0; i < cp->nrb; i++) 
1992/0916/sys/src/9/pc/devether.c:601,6061992/0917/sys/src/9/pc/devether.c:611,640
1992/0424    
			uchar	curr; 
			uchar	mar[8]; 
		}; 
1992/0917    
		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; 
1992/0424    
	}; 
} Wd8013; 
1992/0403    
 
1992/0916/sys/src/9/pc/devether.c:607,6141992/0917/sys/src/9/pc/devether.c:641,659
1992/0905    
enum { 
	MENB		= 0x40,			/* memory enable */ 
 
	L16EN		= 0x40,			/* enable 16-bit LAN operation */ 
	M16EN		= 0x80,			/* enable 16-bit memory access */ 
1992/0917    
	/* 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), 
1992/0905    
}; 
 
1992/0424    
#define IN(hw, m)	inb((hw)->addr+OFFSETOF(Wd8013, m)) 
1992/0916/sys/src/9/pc/devether.c:648,6571992/0917/sys/src/9/pc/devether.c:693,703
1992/0906    
	9, 3, 5, 7, 10, 11, 15, 4, 
}; 
 
1992/0917    
 
1992/0424    
/* 
1992/0906    
 *  get configuration parameters, enable memory 
1992/0424    
 */ 
static void 
1992/0917    
static int 
1992/0424    
wd8013reset(Ctlr *cp) 
1992/0403    
{ 
1992/0424    
	Hw *hw = cp->hw; 
1992/0916/sys/src/9/pc/devether.c:662,6671992/0917/sys/src/9/pc/devether.c:708,721
1992/0906    
	uchar irr; 
1992/0905    
	ulong ram; 
1992/0403    
 
1992/0917    
	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; 
 
1992/0915    
	if(cp->rb == 0){ 
		cp->rb = xspanalloc(sizeof(Buffer)*Nrb, BY2PG, 0); 
		cp->nrb = Nrb; 
1992/0916/sys/src/9/pc/devether.c:669,6791992/0917/sys/src/9/pc/devether.c:723,728
1992/0915    
		cp->ntb = Ntb; 
	} 
1992/0424    
 
	msr = IN(hw, msr); 
1992/0906    
	icr = IN(hw, icr); 
	irr = IN(hw, irr); 
	laar = IN(hw, laar); 
1992/0424    
                 
1992/0906    
	/* ethernet address */ 
1992/0424    
	for(i = 0; i < sizeof(cp->ea); i++) 
		cp->ea[i] = IN(hw, lan[i]); 
1992/0916/sys/src/9/pc/devether.c:708,7171992/0917/sys/src/9/pc/devether.c:757,767
1992/0906    
	/* enable interface RAM, set interface width */ 
	OUT(hw, msr, MENB|msr); 
	if(hw->bt16) 
1992/0915    
		OUT(hw, laar, laar|L16EN|M16EN); 
1992/0917    
		OUT(hw, laar, laar|L16EN|M16EN|ZeroWS16); 
1992/0906    
 
1992/0424    
	(*hw->init)(cp); 
1992/0906    
	setvec(Int0vec + hw->lvl, hw->intr); 
1992/0917    
	return 0; 
1992/0424    
} 
1992/0403    
 
1992/0505    
static void 
1992/0916/sys/src/9/pc/devether.c:719,7291992/0917/sys/src/9/pc/devether.c:769,779
1992/0505    
{ 
	Hw *hw = cp->hw; 
 
	OUT(hw, w.cr, 0x21);			/* Page0|RD2|STP */ 
1992/0917    
	OUT(hw, w.cr, Page0|RD2|STP); 
1992/0505    
	OUT(hw, w.bnry, hw->pstart); 
	OUT(hw, w.cr, 0x61);			/* Page1|RD2|STP */ 
1992/0917    
	OUT(hw, w.cr, Page1|RD2|STP); 
1992/0505    
	OUT(hw, curr, hw->pstart+1); 
	OUT(hw, w.cr, 0x22);			/* Page0|RD2|STA */ 
1992/0917    
	OUT(hw, w.cr, Page0|RD2|STA); 
1992/0505    
} 
 
1992/0424    
/* 
1992/0916/sys/src/9/pc/devether.c:736,7441992/0917/sys/src/9/pc/devether.c:786,794
1992/0424    
	Hw *hw = cp->hw; 
	int i; 
 
	OUT(hw, w.cr, 0x21);			/* Page0|RD2|STP */ 
1992/0917    
	OUT(hw, w.cr, Page0|RD2|STP); 
1992/0906    
	if(hw->bt16) 
1992/0916    
		OUT(hw, w.dcr, 0x01);		/* 16 bit interface */ 
1992/0917    
		OUT(hw, w.dcr, (1<<0)|(3<<5));	/* 16 bit interface, 12 byte DMA burst */ 
1992/0906    
	else 
		OUT(hw, w.dcr, 0x48);		/* FT1|LS */ 
1992/0424    
	OUT(hw, w.rbcr0, 0); 
1992/0916/sys/src/9/pc/devether.c:755,7661992/0917/sys/src/9/pc/devether.c:805,816
1992/0424    
	OUT(hw, w.isr, 0xFF); 
	OUT(hw, w.imr, 0x1F);			/* OVWE|TXEE|RXEE|PTXE|PRXE */ 
 
	OUT(hw, w.cr, 0x61);			/* Page1|RD2|STP */ 
1992/0917    
	OUT(hw, w.cr, Page1|RD2|STP); 
1992/0424    
	for(i = 0; i < sizeof(cp->ea); i++) 
		OUT(hw, par[i], cp->ea[i]); 
1992/0501    
	OUT(hw, curr, hw->pstart+1); 
1992/0424    
 
	OUT(hw, w.cr, 0x22);			/* Page0|RD2|STA */ 
1992/0917    
	OUT(hw, w.cr, Page0|RD2|STA); 
1992/0424    
	OUT(hw, w.tpsr, 0); 
1992/0403    
} 
 
1992/0916/sys/src/9/pc/devether.c:810,8151992/0917/sys/src/9/pc/devether.c:860,888
1992/0915    
	splx(s); 
} 
 
1992/0917    
/* 
 *  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; 
	} 
} 
 
1992/0915    
static void 
1992/0424    
wd8013receive(Ctlr *cp) 
1992/0403    
{ 
1992/0916/sys/src/9/pc/devether.c:817,8451992/0917/sys/src/9/pc/devether.c:890,917
1992/0424    
	Buffer *rb; 
	uchar bnry, curr, next; 
	Ring *p; 
1992/0501    
	int len; 
1992/0917    
	int i, len; 
1992/0424    
 
	bnry = IN(hw, r.bnry); 
1992/0501    
	next = bnry+1; 
	if(next >= hw->pstop) 
		next = hw->pstart; 
1992/0424    
	for(;;){ 
		OUT(hw, w.cr, 0x62);		/* Page1|RD2|STA */ 
1992/0917    
	for(i = 0; ; i++){ 
		OUT(hw, w.cr, Page1|RD2|STA); 
1992/0424    
		curr = IN(hw, curr); 
		OUT(hw, w.cr, 0x22);		/* Page0|RD2|STA */ 
1992/0917    
		OUT(hw, w.cr, Page0|RD2|STA); 
1992/0424    
		if(next == curr) 
			break; 
1992/0917    
		waitfordma(hw); 
1992/0424    
		cp->inpackets++; 
		p = &((Ring*)hw->ram)[next]; 
1992/0505    
		len = ((p->len1<<8)|p->len0)-4; 
		if(p->next < hw->pstart || p->next >= hw->pstop || len < 60){ 
1992/0915    
/*			print("%d/%d : #%2.2ux #%2.2ux  #%2.2ux #%2.2ux\n", next, len, 
1992/0917    
			/*print("%d/%d : #%2.2ux #%2.2ux  #%2.2ux #%2.2ux\n", next, len, 
1992/0909    
				p->status, p->next, p->len0, p->len1);/**/ 
1992/0915    
			delay(100); 
1992/0505    
			dp8390rinit(cp); 
1992/0905    
			break; 
1992/0505    
		} 
1992/0424    
                 
		rb = &cp->rb[cp->ri]; 
		if(rb->owner == Interface){ 
1992/0501    
			rb->len = len; 
1992/0916/sys/src/9/pc/devether.c:853,8591992/0917/sys/src/9/pc/devether.c:925,930
1992/0424    
			rb->owner = Host; 
1992/0502    
			cp->ri = NEXT(cp->ri, cp->nrb); 
1992/0424    
		} 
                 
1992/0502    
		p->status = 0; 
1992/0424    
		next = p->next; 
		bnry = next-1; 
1992/0916/sys/src/9/pc/devether.c:860,8661992/0917/sys/src/9/pc/devether.c:931,936
1992/0501    
		if(bnry < hw->pstart) 
			bnry = hw->pstop-1; 
1992/0424    
		OUT(hw, w.bnry, bnry); 
1992/0915    
		break; 
1992/0424    
	} 
1992/0403    
} 
 
1992/0916/sys/src/9/pc/devether.c:878,8841992/0917/sys/src/9/pc/devether.c:948,954
1992/0906    
		memmove(hw->ram, tb->pkt, tb->len); 
1992/0424    
		OUT(hw, w.tbcr0, tb->len & 0xFF); 
		OUT(hw, w.tbcr1, (tb->len>>8) & 0xFF); 
		OUT(hw, w.cr, 0x26);		/* Page0|RD2|TXP|STA */ 
1992/0917    
		OUT(hw, w.cr, Page0|RD2|TXP|STA); 
1992/0424    
		tb->busy = 1; 
	} 
	splx(s); 
1992/0916/sys/src/9/pc/devether.c:895,9001992/0917/sys/src/9/pc/devether.c:965,979
1992/0711    
	USED(ur); 
1992/0424    
	while(isr = IN(hw, r.isr)){ 
		OUT(hw, w.isr, isr); 
1992/0917    
		/* 
		 * 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++; 
1992/0424    
		if(isr & 0x08)			/* Txe - transmit error */ 
			cp->oerrs++; 
		if(isr & 0x04){			/* Rxe - receive error */ 
1992/0916/sys/src/9/pc/devether.c:916,9301992/0917/sys/src/9/pc/devether.c:995,1000
1992/0502    
			cp->ti = NEXT(cp->ti, cp->ntb); 
1992/0424    
			(*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); 
		} 
	} 
1992/0409    
} 
1992/0917/sys/src/9/pc/devether.c:693,6991992/0918/sys/src/9/pc/devether.c:693,698 (short | long)
1992/0906    
	9, 3, 5, 7, 10, 11, 15, 4, 
}; 
 
1992/0917    
                 
1992/0424    
/* 
1992/0906    
 *  get configuration parameters, enable memory 
1992/0424    
 */ 
1992/0917/sys/src/9/pc/devether.c:702,7191992/0918/sys/src/9/pc/devether.c:701,728
1992/0403    
{ 
1992/0424    
	Hw *hw = cp->hw; 
	int i; 
	uchar msr; 
1992/0906    
	uchar icr; 
	uchar laar; 
	uchar irr; 
1992/0918    
	uchar msr, icr, laar, irr; 
1992/0905    
	ulong ram; 
1992/0403    
 
1992/0917    
	msr = IN(hw, msr); 
	icr = IN(hw, icr); 
	irr = IN(hw, irr); 
	laar = IN(hw, laar); 
1992/0918    
	/* 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 */ 
1992/0917    
 
	if(msr == 0xff || icr == 0xff || irr == 0xff || laar == 0xff) 
1992/0918    
		/* 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) 
1992/0917    
		return -1; 
 
1992/0915    
	if(cp->rb == 0){ 
1992/0917/sys/src/9/pc/devether.c:723,7321992/0918/sys/src/9/pc/devether.c:732,737
1992/0915    
		cp->ntb = Ntb; 
	} 
1992/0424    
 
1992/0906    
	/* ethernet address */ 
1992/0424    
	for(i = 0; i < sizeof(cp->ea); i++) 
		cp->ea[i] = IN(hw, lan[i]); 
1992/0501    
                 
1992/0906    
	/* 16 bit operation? */ 
	hw->bt16 = icr & 0x1; 
 
1992/0917/sys/src/9/pc/devether.c:751,7571992/0918/sys/src/9/pc/devether.c:756,762
1992/0909    
	hw->pstart = HOWMANY(sizeof(Etherpkt), 256); 
1992/0906    
	hw->pstop = HOWMANY(hw->size, 256); 
 
1992/0915    
/* print("ether width %d addr %lux size %d lvl %d\n", hw->bt16?16:8, 
1992/0918    
print("elite at %lux width %d addr %lux size %d lvl %d\n", hw->addr, hw->bt16?16:8, 
1992/0915    
	hw->ram, hw->size, hw->lvl);/**/ 
1992/0906    
 
	/* enable interface RAM, set interface width */ 
1992/0917/sys/src/9/pc/devether.c:902,9081992/0918/sys/src/9/pc/devether.c:907,914
1992/0917    
		OUT(hw, w.cr, Page0|RD2|STA); 
1992/0424    
		if(next == curr) 
			break; 
1992/0917    
		waitfordma(hw); 
1992/0918    
		if(strcmp(machtype, "NCRD.0") == 0) 
			waitfordma(hw); 
1992/0424    
		cp->inpackets++; 
		p = &((Ring*)hw->ram)[next]; 
1992/0505    
		len = ((p->len1<<8)|p->len0)-4; 
1992/0917/sys/src/9/pc/devether.c:1009,10131992/0918/sys/src/9/pc/devether.c:1015,1018
1992/0424    
	wd8013transmit, 
	wd8013intr, 
1992/0915    
	wd8013tweek, 
1992/0909    
	0x360,					/* I/O base address */ 
1992/0424    
}; 
Too many diffs (26 > 25). Stopping.


source code copyright © 1990-2005 Lucent Technologies; see license
Plan 9 distribution
comments to russ cox (rsc@swtch.com)