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

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

pc/devether.c on 1992/0403
1992/0403    
#include "u.h" 
#include "../port/lib.h" 
#include "mem.h" 
#include "dat.h" 
#include "fns.h" 
#include "../port/error.h" 
#include "io.h" 
#include "devtab.h" 
 
1992/0424    
typedef struct Hw Hw; 
typedef struct Buffer Buffer; 
1992/0410    
typedef struct Type Type; 
1992/0424    
typedef struct Ctlr Ctlr; 
1992/0403    
 
1992/0424    
struct Hw { 
	int	addr;			/* interface address */ 
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); 
	void	(*online)(Ctlr*, int); 
	void	(*receive)(Ctlr*); 
	void	(*transmit)(Ctlr*); 
	void	(*intr)(Ureg*); 
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/0403    
 
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/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/0425    
	return devattach('l', spec); 
1992/0424    
} 
1992/0411    
 
1992/0424    
Chan* 
etherclone(Chan *c, Chan *nc) 
1992/0411    
{ 
1992/0424    
	return devclone(c, nc); 
} 
1992/0411    
 
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) 
{ 
1992/0711    
	USED(c, name, omode, perm); 
1992/0424    
	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) 
{ 
1992/0711    
	USED(offset); 
1992/0424    
	return streamwrite(c, a, n, 0); 
} 
 
void 
etherremove(Chan *c) 
{ 
1992/0711    
	USED(c); 
1992/0424    
	error(Eperm); 
} 
 
void 
etherwstat(Chan *c, char *dp) 
{ 
	netwstat(c, dp, &ctlr[0].net); 
} 
 
1992/0407    
static int 
1992/0424    
isobuf(void *arg) 
1992/0407    
{ 
	Ctlr *cp = arg; 
 
1992/0425    
	return cp->tb[cp->th].owner == Host; 
1992/0407    
} 
 
1992/0403    
static void 
etheroput(Queue *q, Block *bp) 
{ 
1992/0406    
	Ctlr *cp; 
1992/0403    
	int len, n; 
1992/0410    
	Type *tp; 
1992/0403    
	Etherpkt *p; 
1992/0424    
	Buffer *tb; 
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/0403    
		else if(streamparse("promiscuous", bp)) { 
1992/0410    
			tp->prom = 1; 
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/0406    
	if(BLEN(bp) < ETHERHDRSIZE && (bp = pullup(bp, ETHERHDRSIZE)) == 0) 
		return; 
1992/0403    
	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/0406    
		if (bp = expandb(bp, len >= ETHERMINTU ? len: ETHERMINTU)){ 
1992/0424    
			putq(&cp->lbq, bp); 
1992/0406    
			wakeup(&cp->rr); 
1992/0403    
		} 
		return; 
	} 
1992/0406    
	if(memcmp(cp->ba, p->d, sizeof(cp->ba)) == 0){ 
1992/0403    
		len = blen(bp); 
		nbp = copyb(bp, len); 
1992/0406    
		if(nbp = expandb(nbp, len >= ETHERMINTU ? len: ETHERMINTU)){ 
1992/0403    
			nbp->wptr = nbp->rptr+len; 
1992/0424    
			putq(&cp->lbq, nbp); 
1992/0406    
			wakeup(&cp->rr); 
1992/0403    
		} 
	} 
 
	/* 
	 * only one transmitter at a time 
	 */ 
1992/0424    
	qlock(&cp->tlock); 
1992/0403    
	if(waserror()){ 
1992/0411    
		freeb(bp); 
1992/0424    
		qunlock(&cp->tlock); 
1992/0403    
		nexterror(); 
	} 
 
	/* 
1992/0424    
	 * wait till we get an output buffer. 
	 * should try to restart. 
1992/0403    
	 */ 
1992/0424    
	sleep(&cp->tr, isobuf, cp); 
1992/0403    
 
1992/0424    
	tb = &cp->tb[cp->th]; 
 
1992/0403    
	/* 
	 * copy message into buffer 
	 */ 
	len = 0; 
	for(nbp = bp; nbp; nbp = nbp->next){ 
		if(sizeof(Etherpkt) - len >= (n = BLEN(nbp))){ 
1992/0501    
			memmove(tb->pkt+len, nbp->rptr, n); 
1992/0403    
			len += n; 
		} else 
			print("no room damn it\n"); 
		if(bp->flags & S_DELIM) 
			break; 
	} 
 
	/* 
1992/0407    
	 * pad the packet (zero the pad) 
1992/0403    
	 */ 
	if(len < ETHERMINTU){ 
1992/0501    
		memset(tb->pkt+len, 0, ETHERMINTU-len); 
1992/0403    
		len = ETHERMINTU; 
	} 
 
	/* 
1992/0424    
	 * set up the transmit buffer and  
1992/0407    
	 * start the transmission 
1992/0403    
	 */ 
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/0424    
	qunlock(&cp->tlock); 
1992/0403    
	poperror(); 
} 
 
/* 
 * open an ether line discipline 
 * 
 * the lock is to synchronize changing the ethertype with 
 * sending packets up the stream on interrupts. 
 */ 
static void 
etherstopen(Queue *q, Stream *s) 
{ 
1992/0404    
	Ctlr *cp = &ctlr[0]; 
1992/0410    
	Type *tp; 
1992/0403    
 
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    
} 
 
/* 
 *  close ether line discipline 
 * 
 *  the lock is to synchronize changing the ethertype with 
 *  sending packets up the stream on interrupts. 
 */ 
static void 
etherstclose(Queue *q) 
{ 
1992/0410    
	Type *tp; 
1992/0403    
 
1992/0410    
	tp = (Type *)(q->ptr); 
1992/0424    
	if(tp->prom) 
		(*tp->ctlr->hw->mode)(tp->ctlr, 0); 
1992/0410    
	qlock(tp); 
	tp->type = 0; 
	tp->q = 0; 
	tp->prom = 0; 
	tp->inuse = 0; 
1992/0625    
	netdisown(tp); 
1992/0505    
	tp->ctlr = 0; 
1992/0410    
	qunlock(tp); 
1992/0403    
} 
 
static Qinfo info = { 
	nullput, 
	etheroput, 
	etherstopen, 
	etherstclose, 
	"ether" 
}; 
 
static int 
1992/0404    
clonecon(Chan *c) 
1992/0403    
{ 
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){ 
			qunlock(tp); 
1992/0403    
			continue; 
		} 
1992/0410    
		tp->inuse = 1; 
1992/0625    
		netown(tp, u->p->user, 0); 
1992/0410    
		qunlock(tp); 
		return tp - cp->type; 
1992/0403    
	} 
	exhausted("ether channels"); 
1992/0711    
	return 0; 
1992/0403    
} 
 
static void 
1992/0404    
statsfill(Chan *c, char *p, int n) 
1992/0403    
{ 
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, 
		cp->ea[0], cp->ea[1], cp->ea[2], cp->ea[3], cp->ea[4], cp->ea[5]); 
1992/0403    
	strncpy(p, buf, n); 
} 
 
static void 
typefill(Chan *c, char *p, int n) 
{ 
	char buf[16]; 
1992/0410    
	Type *tp; 
1992/0403    
 
1992/0410    
	tp = &ctlr[0].type[STREAMID(c->qid.path)]; 
	sprint(buf, "%d", tp->type); 
1992/0403    
	strncpy(p, buf, n); 
} 
 
static void 
1992/0501    
etherup(Ctlr *cp, void *data, int len) 
1992/0403    
{ 
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    
		/* 
		 *  check before locking just to save a lock 
		 */ 
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 
		 */ 
1992/0410    
		if(tp->type != -1 && p->d[0] != 0xFF && memcmp(p->d, cp->ea, sizeof(p->d))) 
1992/0404    
			continue; 
 
		/* 
		 *  check after locking to make sure things didn't 
		 *  change under foot 
		 */ 
1992/0410    
		if(canqlock(tp) == 0) 
1992/0404    
			continue; 
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){ 
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    
		} 
		poperror(); 
1992/0410    
		qunlock(tp); 
1992/0404    
	} 
} 
 
1992/0403    
static int 
isinput(void *arg) 
{ 
1992/0404    
	Ctlr *cp = arg; 
1992/0403    
 
1992/0424    
	return cp->lbq.first || cp->rb[cp->ri].owner == Host; 
1992/0403    
} 
 
static void 
etherkproc(void *arg) 
{ 
1992/0404    
	Ctlr *cp = arg; 
1992/0424    
	Buffer *rb; 
1992/0404    
	Block *bp; 
1992/0403    
 
	if(waserror()){ 
1992/0404    
		print("%s noted\n", cp->name); 
1992/0424    
		(*cp->hw->init)(cp); 
1992/0404    
		cp->kproc = 0; 
1992/0403    
		nexterror(); 
	} 
1992/0404    
	cp->kproc = 1; 
1992/0403    
	for(;;){ 
1992/0505    
		sleep(&cp->rr, isinput, cp); 
1992/0424    
 
1992/0406    
		/* 
		 * process any internal loopback packets 
		 */ 
1992/0424    
		while(bp = getq(&cp->lbq)){ 
1992/0404    
			cp->inpackets++; 
1992/0501    
			etherup(cp, bp->rptr, BLEN(bp)); 
1992/0404    
			freeb(bp); 
		} 
1992/0408    
 
1992/0406    
		/* 
		 * process any received packets 
		 */ 
1992/0424    
		while(cp->rb[cp->rh].owner == Host){ 
1992/0406    
			cp->inpackets++; 
1992/0424    
			rb = &cp->rb[cp->rh]; 
1992/0501    
			etherup(cp, rb->pkt, rb->len); 
1992/0424    
			rb->owner = Interface; 
1992/0502    
			cp->rh = NEXT(cp->rh, cp->nrb); 
1992/0424    
		} 
	} 
} 
1992/0410    
 
1992/0424    
void 
etherreset(void) 
{ 
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/0424    
	memset(cp->ba, 0xFF, sizeof(cp->ba)); 
1992/0410    
 
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.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 
etherinit(void) 
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/0501    
	 */	 
1992/0424    
	(*cp->hw->online)(cp, 1); 
	if(cp->kproc == 0){ 
		sprint(cp->name, "ether%dkproc", ctlrno); 
		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]; 
		}; 
	}; 
} Wd8013; 
1992/0403    
 
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 
wd8013reset(Ctlr *cp) 
1992/0403    
{ 
1992/0424    
	Hw *hw = cp->hw; 
	int i; 
	uchar msr; 
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/0424    
 
	msr = IN(hw, msr); 
	OUT(hw, msr, 0x40|msr); 
 
	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/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. 
 */ 
static void 
wd8013init(Ctlr *cp) 
1992/0403    
{ 
1992/0424    
	Hw *hw = cp->hw; 
	int i; 
 
	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 */ 
 
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 */ 
 
	OUT(hw, w.cr, 0x61);			/* Page1|RD2|STP */ 
	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 */ 
	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 
wd8013receive(Ctlr *cp) 
1992/0403    
{ 
1992/0424    
	Hw *hw = cp->hw; 
	Buffer *rb; 
	uchar bnry, curr, next; 
	Ring *p; 
1992/0501    
	int 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 */ 
		curr = IN(hw, curr); 
		OUT(hw, w.cr, 0x22);		/* Page0|RD2|STA */ 
		if(next == curr) 
			break; 
		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/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/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/0501    
				memmove(rb->pkt+len, 
					&((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/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(); 
	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/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; 
	} 
	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; 
	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 */ 
			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); 
		} 
		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 */ 
1992/0501    
	8*1024, 
	0, 
	HOWMANY(sizeof(Etherpkt), 256), 
	HOWMANY(8*1024, 256), 
1992/0424    
	wd8013reset, 
	wd8013init, 
	wd8013mode, 
	wd8013online, 
	wd8013receive, 
	wd8013transmit, 
	wd8013intr, 
}; 
 
1992/0409    
void 
1992/0411    
consdebug(void) 
1992/0409    
{ 
1992/0403    
} 


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