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

1992/0922/pc/devether.c (diff list | history)

1992/0918/sys/src/9/pc/devether.c:7,1191992/0922/sys/src/9/pc/devether.c:7,39 (short | long | prev | next)
1992/0403    
#include "io.h" 
#include "devtab.h" 
 
1992/0424    
typedef struct Hw Hw; 
typedef struct Buffer Buffer; 
1992/0410    
typedef struct Type Type; 
1992/0424    
typedef struct Ctlr Ctlr; 
1992/0922    
/* 
 * Half-arsed attempt at a general top-level 
 * ethernet driver. Needs work: 
 *	handle multiple controllers 
 *	much tidying 
 *	set ethernet address 
 */ 
extern EtherHw ether509; 
extern EtherHw ether80x3; 
1992/0403    
 
1992/0424    
struct Hw { 
1992/0917    
	int	(*reset)(Ctlr*); 
1992/0909    
	void	(*init)(Ctlr*); 
	void	(*mode)(Ctlr*, int); 
	void	(*online)(Ctlr*, int); 
	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 */ 
	int	lvl;			/* interrupt level */ 
1992/0501    
	int	size; 
	uchar	tstart; 
	uchar	pstart; 
	uchar	pstop; 
1992/0922    
static EtherHw *etherhw[] = { 
	ðer509, 
	ðer80x3, 
	0 
1992/0404    
}; 
1992/0424    
static Hw wd8013; 
1992/0404    
 
enum { 
1992/0424    
	Nctlr		= 1,		/* even one of these is too many */ 
	NType		= 9,		/* types/interface */ 
1992/0403    
                 
1992/0424    
	Nrb		= 16,		/* software receive buffers */ 
	Ntb		= 4,		/* software transmit buffers */ 
1992/0922    
	Nctlr		= 1, 
1992/0424    
}; 
1992/0403    
 
1992/0922    
static struct EtherCtlr ctlr[Nctlr]; 
 
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    
 
1992/0424    
struct Buffer { 
	uchar	owner; 
	uchar	busy; 
	ushort	len; 
1992/0501    
	uchar	pkt[sizeof(Etherpkt)]; 
1992/0404    
}; 
1992/0403    
                 
1992/0404    
enum { 
1992/0424    
	Host		= 0,		/* buffer owned by host */ 
	Interface	= 1,		/* buffer owned by interface */ 
1992/0404    
}; 
1992/0403    
                 
/* 
 * one per ethernet packet type 
 */ 
1992/0410    
struct Type { 
1992/0403    
	QLock; 
1992/0625    
	Netprot;			/* stat info */ 
1992/0403    
	int	type;			/* ethernet type */ 
	int	prom;			/* promiscuous mode */ 
	Queue	*q; 
	int	inuse; 
	Ctlr	*ctlr; 
}; 
                 
/* 
1992/0424    
 * per ethernet 
1992/0403    
 */ 
struct Ctlr { 
	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 */ 
	Buffer	*rb;		/* software receive buffers */ 
	Buffer	*tb;		/* software transmit buffers */ 
1992/0403    
                 
1992/0424    
	uchar	ea[6];		/* ethernet address */ 
	uchar	ba[6];		/* broadcast address */ 
1992/0403    
                 
1992/0424    
	Rendez	rr;		/* rendezvous for a receive buffer */ 
	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 */ 
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 */	 
                 
	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/0424    
	Queue	lbq;		/* software loopback packet queue */ 
                 
1992/0403    
	int	inpackets; 
	int	outpackets; 
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/0425    
Chan* 
etherattach(char *spec) 
1992/0424    
{ 
1992/0918/sys/src/9/pc/devether.c:189,1951992/0922/sys/src/9/pc/devether.c:109,115
1992/0407    
static int 
1992/0424    
isobuf(void *arg) 
1992/0407    
{ 
	Ctlr *cp = arg; 
1992/0922    
	EtherCtlr *cp = arg; 
1992/0407    
 
1992/0425    
	return cp->tb[cp->th].owner == Host; 
1992/0407    
} 
1992/0918/sys/src/9/pc/devether.c:197,2131992/0922/sys/src/9/pc/devether.c:117,133
1992/0403    
static void 
etheroput(Queue *q, Block *bp) 
{ 
1992/0406    
	Ctlr *cp; 
1992/0403    
	int len, n; 
1992/0410    
	Type *tp; 
1992/0922    
	EtherCtlr *cp; 
	EtherType *tp; 
1992/0403    
	Etherpkt *p; 
1992/0424    
	Buffer *tb; 
1992/0922    
	EtherBuf *tb; 
	int len, n; 
1992/0403    
	Block *nbp; 
 
	if(bp->type == M_CTL){ 
1992/0410    
		tp = q->ptr; 
1992/0403    
		if(streamparse("connect", bp)) 
1992/0410    
			tp->type = strtol((char *)bp->rptr, 0, 0); 
1992/0922    
			tp->type = strtol((char*)bp->rptr, 0, 0); 
1992/0403    
		else if(streamparse("promiscuous", bp)) { 
1992/0410    
			tp->prom = 1; 
1992/0424    
			(*tp->ctlr->hw->mode)(tp->ctlr, 1); 
1992/0918/sys/src/9/pc/devether.c:216,2221992/0922/sys/src/9/pc/devether.c:136,142
1992/0403    
		return; 
	} 
 
1992/0424    
	cp = ((Type *)q->ptr)->ctlr; 
1992/0922    
	cp = ((EtherType*)q->ptr)->ctlr; 
1992/0424    
 
1992/0403    
	/* 
	 * give packet a local address, return upstream if destined for 
1992/0918/sys/src/9/pc/devether.c:224,2301992/0922/sys/src/9/pc/devether.c:144,150
1992/0403    
	 */ 
1992/0406    
	if(BLEN(bp) < ETHERHDRSIZE && (bp = pullup(bp, ETHERHDRSIZE)) == 0) 
		return; 
1992/0403    
	p = (Etherpkt *)bp->rptr; 
1992/0922    
	p = (Etherpkt*)bp->rptr; 
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); 
1992/0918/sys/src/9/pc/devether.c:308,3151992/0922/sys/src/9/pc/devether.c:228,235
1992/0403    
static void 
etherstopen(Queue *q, Stream *s) 
{ 
1992/0404    
	Ctlr *cp = &ctlr[0]; 
1992/0410    
	Type *tp; 
1992/0922    
	EtherCtlr *cp = &ctlr[0]; 
	EtherType *tp; 
1992/0403    
 
1992/0410    
	tp = &cp->type[s->id]; 
	qlock(tp); 
1992/0918/sys/src/9/pc/devether.c:330,3381992/0922/sys/src/9/pc/devether.c:250,258
1992/0403    
static void 
etherstclose(Queue *q) 
{ 
1992/0410    
	Type *tp; 
1992/0922    
	EtherType *tp; 
1992/0403    
 
1992/0410    
	tp = (Type *)(q->ptr); 
1992/0922    
	tp = (EtherType*)(q->ptr); 
1992/0424    
	if(tp->prom) 
		(*tp->ctlr->hw->mode)(tp->ctlr, 0); 
1992/0410    
	qlock(tp); 
1992/0918/sys/src/9/pc/devether.c:356,3631992/0922/sys/src/9/pc/devether.c:276,283
1992/0403    
static int 
1992/0404    
clonecon(Chan *c) 
1992/0403    
{ 
1992/0404    
	Ctlr *cp = &ctlr[0]; 
1992/0410    
	Type *tp; 
1992/0922    
	EtherCtlr *cp = &ctlr[0]; 
	EtherType *tp; 
1992/0403    
 
1992/0711    
	USED(c); 
1992/0410    
	for(tp = cp->type; tp < &cp->type[NType]; tp++){ 
1992/0918/sys/src/9/pc/devether.c:378,3841992/0922/sys/src/9/pc/devether.c:298,304
1992/0403    
static void 
1992/0404    
statsfill(Chan *c, char *p, int n) 
1992/0403    
{ 
1992/0404    
	Ctlr *cp = &ctlr[0]; 
1992/0922    
	EtherCtlr *cp = &ctlr[0]; 
1992/0403    
	char buf[256]; 
 
1992/0711    
	USED(c); 
1992/0918/sys/src/9/pc/devether.c:393,3991992/0922/sys/src/9/pc/devether.c:313,319
1992/0403    
typefill(Chan *c, char *p, int n) 
{ 
	char buf[16]; 
1992/0410    
	Type *tp; 
1992/0922    
	EtherType *tp; 
1992/0403    
 
1992/0410    
	tp = &ctlr[0].type[STREAMID(c->qid.path)]; 
	sprint(buf, "%d", tp->type); 
1992/0918/sys/src/9/pc/devether.c:401,4111992/0922/sys/src/9/pc/devether.c:321,331
1992/0403    
} 
 
static void 
1992/0501    
etherup(Ctlr *cp, void *data, int len) 
1992/0922    
etherup(EtherCtlr *cp, void *data, int len) 
1992/0403    
{ 
1992/0501    
	Etherpkt *p; 
1992/0404    
	int t; 
1992/0501    
	Type *tp; 
1992/0922    
	EtherType *tp; 
1992/0501    
	Block *bp; 
1992/0404    
 
1992/0501    
	p = data; 
1992/0918/sys/src/9/pc/devether.c:448,4541992/0922/sys/src/9/pc/devether.c:368,374
1992/0403    
static int 
isinput(void *arg) 
{ 
1992/0404    
	Ctlr *cp = arg; 
1992/0922    
	EtherCtlr *cp = arg; 
1992/0403    
 
1992/0424    
	return cp->lbq.first || cp->rb[cp->ri].owner == Host; 
1992/0403    
} 
1992/0918/sys/src/9/pc/devether.c:456,4681992/0922/sys/src/9/pc/devether.c:376,389
1992/0403    
static void 
etherkproc(void *arg) 
{ 
1992/0404    
	Ctlr *cp = arg; 
1992/0424    
	Buffer *rb; 
1992/0922    
	EtherCtlr *cp = arg; 
	EtherBuf *rb; 
1992/0404    
	Block *bp; 
1992/0403    
 
	if(waserror()){ 
1992/0404    
		print("%s noted\n", cp->name); 
1992/0424    
		(*cp->hw->init)(cp); 
1992/0922    
		if(cp->hw->init) 
			(*cp->hw->init)(cp); 
1992/0404    
		cp->kproc = 0; 
1992/0403    
		nexterror(); 
	} 
1992/0918/sys/src/9/pc/devether.c:469,4751992/0922/sys/src/9/pc/devether.c:390,397
1992/0404    
	cp->kproc = 1; 
1992/0403    
	for(;;){ 
1992/0915    
		tsleep(&cp->rr, isinput, cp, 500); 
		(*cp->hw->tweek)(cp); 
1992/0922    
		if(cp->hw->tweak) 
			(*cp->hw->tweak)(cp); 
1992/0424    
 
1992/0406    
		/* 
		 * process any internal loopback packets 
1992/0918/sys/src/9/pc/devether.c:493,5111992/0922/sys/src/9/pc/devether.c:415,447
1992/0424    
	} 
} 
1992/0410    
 
1992/0922    
static void 
etherintr(Ureg *ur) 
{ 
	EtherCtlr *cp = &ctlr[0]; 
 
	USED(ur); 
	(*cp->hw->intr)(cp); 
} 
 
1992/0424    
void 
etherreset(void) 
{ 
1992/0922    
	EtherCtlr *cp; 
	EtherHw **hw; 
1992/0625    
	int i; 
	Ctlr *cp; 
1992/0410    
 
1992/0625    
	cp = &ctlr[0]; 
1992/0424    
	cp->hw = &wd8013; 
1992/0917    
	if((*cp->hw->reset)(cp) < 0){ 
		cp->present = 0; 
		return; 
1992/0922    
	for(hw = etherhw; *hw; hw++){ 
		cp->hw = *hw; 
		if((*cp->hw->reset)(cp) == 0){ 
			cp->present = 1; 
			setvec(Int0vec + cp->hw->irq, etherintr); 
			break; 
		} 
1992/0917    
	} 
	cp->present = 1; 
1992/0922    
	if(cp->present == 0) 
		return; 
1992/0410    
 
1992/0424    
	memset(cp->ba, 0xFF, sizeof(cp->ba)); 
1992/0410    
 
1992/0918/sys/src/9/pc/devether.c:528,5341992/0922/sys/src/9/pc/devether.c:464,470
1992/0425    
etherinit(void) 
1992/0403    
{ 
	int ctlrno = 0; 
1992/0424    
	Ctlr *cp = &ctlr[ctlrno]; 
1992/0922    
	EtherCtlr *cp = &ctlr[ctlrno]; 
1992/0424    
	int i; 
1992/0403    
 
1992/0917    
	if(cp->present == 0) 
1992/0918/sys/src/9/pc/devether.c:554,10181992/0922/sys/src/9/pc/devether.c:490,492
1992/0424    
		kproc(cp->name, etherkproc, cp); 
1992/0403    
	} 
} 
                 
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    
                 
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]; 
		}; 
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/0905    
enum { 
	MENB		= 0x40,			/* memory enable */ 
                 
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)) 
#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/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/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    
 */ 
1992/0917    
static int 
1992/0424    
wd8013reset(Ctlr *cp) 
1992/0403    
{ 
1992/0424    
	Hw *hw = cp->hw; 
	int i; 
1992/0918    
	uchar msr, icr, laar, irr; 
1992/0905    
	ulong ram; 
1992/0403    
                 
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    
                 
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){ 
		cp->rb = xspanalloc(sizeof(Buffer)*Nrb, BY2PG, 0); 
		cp->nrb = Nrb; 
		cp->tb = xspanalloc(sizeof(Buffer)*Ntb, BY2PG, 0); 
		cp->ntb = Ntb; 
	} 
1992/0424    
                 
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; 
                 
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; 
1992/0909    
	hw->pstart = HOWMANY(sizeof(Etherpkt), 256); 
1992/0906    
	hw->pstop = HOWMANY(hw->size, 256); 
                 
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 */ 
	OUT(hw, msr, MENB|msr); 
	if(hw->bt16) 
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 
dp8390rinit(Ctlr *cp) 
{ 
	Hw *hw = cp->hw; 
                 
1992/0917    
	OUT(hw, w.cr, Page0|RD2|STP); 
1992/0505    
	OUT(hw, w.bnry, hw->pstart); 
1992/0917    
	OUT(hw, w.cr, Page1|RD2|STP); 
1992/0505    
	OUT(hw, curr, hw->pstart+1); 
1992/0917    
	OUT(hw, w.cr, Page0|RD2|STA); 
1992/0505    
} 
                 
1992/0424    
/* 
 * we leave the chip idling on internal loopback 
 * and pointing to Page0. 
 */ 
static void 
1992/0909    
dp8390init(Ctlr *cp) 
1992/0403    
{ 
1992/0424    
	Hw *hw = cp->hw; 
	int i; 
                 
1992/0917    
	OUT(hw, w.cr, Page0|RD2|STP); 
1992/0906    
	if(hw->bt16) 
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); 
	OUT(hw, w.rbcr1, 0); 
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); 
	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/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    
                 
1992/0917    
	OUT(hw, w.cr, Page0|RD2|STA); 
1992/0424    
	OUT(hw, w.tpsr, 0); 
1992/0403    
} 
                 
void 
1992/0424    
wd8013mode(Ctlr *cp, int on) 
1992/0403    
{ 
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    
} 
                 
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/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); 
} 
                 
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/0424    
	Hw *hw = cp->hw; 
	Buffer *rb; 
	uchar bnry, curr, next; 
	Ring *p; 
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/0917    
	for(i = 0; ; i++){ 
		OUT(hw, w.cr, Page1|RD2|STA); 
1992/0424    
		curr = IN(hw, curr); 
1992/0917    
		OUT(hw, w.cr, Page0|RD2|STA); 
1992/0424    
		if(next == curr) 
			break; 
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; 
		if(p->next < hw->pstart || p->next >= hw->pstop || len < 60){ 
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/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/0502    
			if((p->data+len) >= (hw->ram+hw->size)){ 
1992/0503    
				len = (hw->ram+hw->size) - p->data; 
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/0906    
			memmove(rb->pkt, p->data, len); 
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/0501    
		if(bnry < hw->pstart) 
			bnry = hw->pstop-1; 
1992/0424    
		OUT(hw, w.bnry, bnry); 
	} 
1992/0403    
} 
                 
1992/0424    
static void 
wd8013transmit(Ctlr *cp) 
1992/0403    
{ 
1992/0424    
	Hw *hw; 
	Buffer *tb; 
	int s; 
                 
	s = splhi(); 
1992/0906    
	hw = cp->hw; 
1992/0424    
	tb = &cp->tb[cp->ti]; 
	if(tb->busy == 0 && tb->owner == Interface){ 
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); 
1992/0917    
		OUT(hw, w.cr, Page0|RD2|TXP|STA); 
1992/0424    
		tb->busy = 1; 
	} 
	splx(s); 
1992/0403    
} 
                 
1992/0424    
static void 
wd8013intr(Ureg *ur) 
1992/0403    
{ 
1992/0424    
	Ctlr *cp = &ctlr[0]; 
	Hw *hw = cp->hw; 
	Buffer *tb; 
1992/0915    
	uchar isr; 
1992/0424    
                 
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 */ 
			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; 
1992/0502    
			cp->ti = NEXT(cp->ti, cp->ntb); 
1992/0424    
			(*cp->hw->transmit)(cp); 
			wakeup(&cp->tr); 
		} 
	} 
1992/0409    
} 
                 
1992/0909    
static Hw wd8013 = 
{ 
1992/0424    
	wd8013reset, 
1992/0909    
	dp8390init, 
1992/0424    
	wd8013mode, 
	wd8013online, 
	wd8013receive, 
	wd8013transmit, 
	wd8013intr, 
1992/0915    
	wd8013tweek, 
1992/0424    
}; 


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