~kris/9p

9hist

21f299faa09da03b4e9a1620e705048941df1a22 — David du Colombier 34 years ago 3d6715f
Plan 9 from Bell Labs 1992-04-24
3 files changed, 467 insertions(+), 400 deletions(-)

M pc/devether.c
M pc/devhard.c
M pc/vga.c
M pc/devether.c => pc/devether.c +459 -366
@@ 1,14 1,3 @@
/*
 * Western Digital ethernet adapter
 * BUGS:
 *	no more than one controller
 * TODO:
 *	fix for different controller types
 *	output
 *	deal with stalling and restarting output on input overflow
 *	fix magic ring constants
 *	rewrite per SMC doc
 */
#include "u.h"
#include "../port/lib.h"
#include "mem.h"


@@ 18,78 7,48 @@
#include "io.h"
#include "devtab.h"

static int debug;

typedef struct Ctlr Ctlr;
typedef struct Hw Hw;
typedef struct Buffer Buffer;
typedef struct Type Type;
typedef struct Ring Ring;

enum {
	IObase		= 0x360,
	RAMbase		= 0xC8000,
	RAMsize		= 8*1024,
	BUFsize		= 256,
typedef struct Ctlr Ctlr;

	RINGbase	= 6,		/* gak */
	RINGsize	= 32,		/* gak */
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*);
};
static Hw wd8013;

	Nctlr		= 1,
enum {
	Nctlr		= 1,		/* even one of these is too many */
	NType		= 9,		/* types/interface */

	Nrb		= 16,		/* software receive buffers */
	Ntb		= 4,		/* software transmit buffers */
};

#define NEXT(x, l)	((((x)+1)%(l)) == 0 ? RINGbase: (((x)+1)%(l)))
#define PREV(x, l)	(((x)-1) < RINGbase ? (l-1): ((x)-1))
#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))

/*
 * register offsets from IObase
 */
enum {
	EA		= 0x08,		/* Ethernet Address in ROM */
	ID		= 0x0E,		/* interface type */

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

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

	Par0		= NIC+0x01,	/* Page 1 */
	Curr		= NIC+0x07,
struct Buffer {
	uchar	owner;
	uchar	busy;
	ushort	len;
	Etherpkt pkt;
};

/*
 * 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 */
};

struct Ring {
	uchar	status;
	uchar	next;
	uchar	len0;
	uchar	len1;
	uchar	data[BUFsize-4];
	Host		= 0,		/* buffer owned by host */
	Interface	= 1,		/* buffer owned by interface */
};

/*


@@ 105,74 64,122 @@ struct Type {
};

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

	Ring	*ring;
	Rendez	rr;			/* rendezvous for an input buffer */
	Queue	rq;
	uchar	bnry;
	uchar	curr;
	Hw	*hw;

	Etherpkt *xpkt;
	QLock	xl;
	Rendez	xr;
	uchar	xbusy;
	ushort	nrb;		/* number of software receive buffers */
	ushort	ntb;		/* number of software transmit buffers */
	Buffer	*rb;		/* software receive buffers */
	Buffer	*tb;		/* software transmit buffers */

	int	iobase;			/* I/O base address */
	uchar	ea[6];		/* ethernet address */
	uchar	ba[6];		/* broadcast address */

	Type	type[NType];
	uchar	ea[6];
	uchar	ba[6];
	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 */	

	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 */	

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

	Queue	lbq;		/* software loopback packet queue */

	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 */
	int	crcs;		/* input crc errors */
	int	oerrs;		/* output errors */
	int	frames;		/* framing errors */
	int	overflows;	/* packet overflows */
	int	buffs;		/* buffering errors */
};
static Ctlr ctlr[Nctlr];

static Etherpkt txpkt;
void
etherinit(void)
{
}

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

	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);
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);
}

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);
}

static int
isxfree(void *arg)
isobuf(void *arg)
{
	Ctlr *cp = arg;

	return cp->xbusy == 0;
	cp->tb[cp->th].owner == Host;
}

static void


@@ 182,25 189,23 @@ etheroput(Queue *q, Block *bp)
	int len, n;
	Type *tp;
	Etherpkt *p;
	Buffer *tb;
	Block *nbp;

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

	cp = ((Type *)q->ptr)->ctlr;

	/*
	 * give packet a local address, return upstream if destined for
	 * this machine.


@@ 212,7 217,7 @@ etheroput(Queue *q, Block *bp)
	if(memcmp(cp->ea, p->d, sizeof(cp->ea)) == 0){
		len = blen(bp);
		if (bp = expandb(bp, len >= ETHERMINTU ? len: ETHERMINTU)){
			putq(&cp->rq, bp);
			putq(&cp->lbq, bp);
			wakeup(&cp->rr);
		}
		return;


@@ 222,7 227,7 @@ etheroput(Queue *q, Block *bp)
		nbp = copyb(bp, len);
		if(nbp = expandb(nbp, len >= ETHERMINTU ? len: ETHERMINTU)){
			nbp->wptr = nbp->rptr+len;
			putq(&cp->rq, nbp);
			putq(&cp->lbq, nbp);
			wakeup(&cp->rr);
		}
	}


@@ 230,20 235,22 @@ etheroput(Queue *q, Block *bp)
	/*
	 * only one transmitter at a time
	 */
	qlock(&cp->xl);
	qlock(&cp->tlock);
	if(waserror()){
		freeb(bp);
		qunlock(&cp->xl);
		qunlock(&cp->tlock);
		nexterror();
	}

	/*
	 * Wait till we get an output buffer
	 * wait till we get an output buffer.
	 * should try to restart.
	 */
	tsleep(&cp->xr, isxfree, cp, 1000);
	if(isxfree(cp) == 0)
		print("Tx wedged\n");
	p = &txpkt;
print("oput sleep\n");
	sleep(&cp->tr, isobuf, cp);

	tb = &cp->tb[cp->th];
	p = &tb->pkt;

	/*
	 * copy message into buffer


@@ 271,18 278,20 @@ etheroput(Queue *q, Block *bp)
	 * give packet a local address
	 */
	memmove(p->s, cp->ea, sizeof(cp->ea));
	xmemmove(cp->xpkt, p, len);

	/*
	 * set up the transmit buffer and 
	 * start the transmission
	 */
	outb(cp->iobase+Tbcr0, len & 0xFF);
	outb(cp->iobase+Tbcr1, (len>>8) & 0xFF);
	outb(cp->iobase+Cr, 0x26);			/* Page0|TXP|STA */
	cp->xbusy = 1;
	cp->outpackets++;
	tb->len = len;
	tb->owner = Interface;
	cp->th = NEXT(cp->th, cp->ntb);
	(*cp->hw->transmit)(cp);

	freeb(bp);
	qunlock(&cp->xl);
	qunlock(&cp->tlock);
print("oput done\n");
	poperror();
}



@@ 320,13 329,8 @@ etherstclose(Queue *q)
	Type *tp;

	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);
	}
	if(tp->prom)
		(*tp->ctlr->hw->mode)(tp->ctlr, 0);
	qlock(tp);
	tp->type = 0;
	tp->q = 0;


@@ 389,129 393,12 @@ typefill(Chan *c, char *p, int n)
}

static void
intr(Ureg *ur)
{
	Ctlr *cp = &ctlr[0];
	uchar isr, bnry, curr;

	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->overflows += inb(cp->iobase+Cntr2);
		}
		if(isr & Ptx)
			cp->outpackets++;
		if(isr & (Txe|Ptx)){
			cp->xbusy = 0;
			wakeup(&cp->xr);
		}
		if(isr & Ovw){
			bnry = inb(cp->iobase+Bnry);
			outb(cp->iobase+bnry, bnry);
			cp->buffs++;
		}
		/*
		 * we have received packets.
		 * this is the only place, other than the init code,
		 * where we set the controller to Page1.
		 * we must be sure to reset it back to Page0 in case
		 * we interrupted some other part of this driver.
		 */
		if(isr & (Rxe|Prx)){
			outb(cp->iobase+Cr, 0x62);	/* Page1, RD2|STA */
			cp->curr = inb(cp->iobase+Curr);
			outb(cp->iobase+Cr, 0x22);	/* Page0, RD2|STA */
if(debug)
    print("I%d/%d/%d|", isr, cp->curr, cp->bnry);
			wakeup(&cp->rr);
		}
	}
}

/*
 * the following initialisation procedure
 * is mandatory.
 * we leave the chip idling on internal loopback
 * and pointing to Page0.
 */
static void
init(Ctlr *cp)
{
	int i;

	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 */
	cp->bnry = RINGbase;
	outb(cp->iobase+Bnry, cp->bnry);
	cp->ring = (Ring*)(KZERO|RAMbase);
	outb(cp->iobase+Pstart, RINGbase);
	outb(cp->iobase+Pstop, RINGsize);
	outb(cp->iobase+Isr, 0xFF);
	outb(cp->iobase+Imr, 0x1F);		/* OVWE|TXEE|RXEE|PTXE|PRXE */

	outb(cp->iobase+Cr, 0x61);		/* Page1, RD2|STP */
	for(i = 0; i < sizeof(cp->ea); i++)
		outb(cp->iobase+Par0+i, cp->ea[i]);
	cp->curr = cp->bnry+1;
	outb(cp->iobase+Curr, cp->curr);

	outb(cp->iobase+Cr, 0x22);		/* Page0, RD2|STA */
	outb(cp->iobase+Tpsr, 0);
	cp->xpkt = (Etherpkt*)(KZERO|RAMbase);
}

void
etherreset(void)
etherup(Ctlr *cp, Etherpkt *p, int len)
{
	Ctlr *cp = &ctlr[0];
	int i;
	uchar reg;

	cp->iobase = IObase;
	reg = 0x40|inb(cp->iobase);
	outb(cp->iobase, reg);
	reg = 0x40|inb(cp->iobase+0x05);
	outb(cp->iobase+0x05, reg);
for(i = 0; i < 0x10; i++)
    print("#%2.2ux ", inb(cp->iobase+i));
print("\n");
	for(i = 0; i < sizeof(cp->ea); i++)
		cp->ea[i] = inb(cp->iobase+EA+i);
	init(cp);
	setvec(Ethervec, intr);
	memset(cp->ba, 0xFF, sizeof(cp->ba));

	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;
}

static void
etherup(Ctlr *cp, uchar *d0, int len0, uchar *d1, int len1)
{
	Etherpkt *p;
	Block *bp;
	Type *tp;
	int t;

	p = (Etherpkt*)d0;
	t = (p->type[0]<<8)|p->type[1];
	for(tp = &cp->type[0]; tp < &cp->type[NType]; tp++){
		/*


@@ 537,11 424,9 @@ etherup(Ctlr *cp, uchar *d0, int len0, uchar *d1, int len1)
			continue;
		}
		if(waserror() == 0){
			bp = allocb(len0+len1);
			xmemmove(bp->rptr, d0, len0);
			if(len1)
				xmemmove(bp->rptr+len0, d1, len1);
			bp->wptr += len0+len1;
			bp = allocb(len);
			memmove(bp->rptr, p, len);
			bp->wptr += len;
			bp->flags |= S_DELIM;
			PUTNEXT(tp->q, bp);
		}


@@ 550,181 435,389 @@ etherup(Ctlr *cp, uchar *d0, int len0, uchar *d1, int len1)
	}
}

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]);
}

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

	return NEXT(cp->bnry, RINGsize) != cp->curr;
	return cp->lbq.first || cp->rb[cp->ri].owner == Host;
}

static void
etherkproc(void *arg)
{
	Ctlr *cp = arg;
	Buffer *rb;
	Block *bp;
	uchar bnry, curr;
	Ring *rp;
	int len0, len1;

	if(waserror()){
		print("%s noted\n", cp->name);
		init(cp);
		(*cp->hw->init)(cp);
		cp->kproc = 0;
		nexterror();
	}
	cp->kproc = 1;
	for(;;){
		sleep(&cp->rr, isinput, cp);
		qlock(&cp->rlock);

		/*
		 * process any internal loopback packets
		 */
		while(bp = getq(&cp->rq)){
		while(bp = getq(&cp->lbq)){
			cp->inpackets++;
			etherup(cp, bp->rptr, BLEN(bp), 0, 0);
			etherup(cp, (Etherpkt*)bp->rptr, BLEN(bp));
			freeb(bp);
		}

		/*
		 * process any received packets
		 */
		bnry = NEXT(cp->bnry, RINGsize);
		while(bnry != cp->curr){
			rp = &cp->ring[bnry];
		while(cp->rb[cp->rh].owner == Host){
			cp->inpackets++;
			len0 = ((rp->len1<<8)+rp->len0)-4;
			len1 = 0;
			rb = &cp->rb[cp->rh];
			etherup(cp, &rb->pkt, rb->len);
			rb->owner = Interface;
			cp->rh = NEXT(cp->rh, Nrb);
		}

			if(rp->data+len0 >= (uchar*)&cp->ring[RINGsize]){
				len1 = rp->data+len0 - (uchar*)&cp->ring[RINGsize];
				len0 = (uchar*)&cp->ring[RINGsize] - rp->data;
			}
		qunlock(&cp->rlock);
		sleep(&cp->rr, isinput, cp);
	}
}

			etherup(cp, rp->data, len0, (uchar*)&cp->ring[RINGbase], len1);
void
etherreset(void)
{
	Ctlr *cp = &ctlr[0];

	cp->hw = &wd8013;
	(*cp->hw->reset)(cp);

	memset(cp->ba, 0xFF, sizeof(cp->ba));

if(debug)
    print("K%d/%d/%d|", bnry, rp->next, PREV(rp->next, RINGsize));
			bnry = rp->next;
			cp->bnry = PREV(bnry, RINGsize);
			outb(cp->iobase+Bnry, cp->bnry);
		}
	}
	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;
}

void
etherinit(void)
Chan*
etherattach(char *spec)
{
	int ctlrno = 0;
	Ctlr *cp = &ctlr[ctlrno];
	int i;

	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;

	/*
	 * put the receiver online
	 * and start the kproc
	 */
	outb(ctlr[ctlrno].iobase+Tcr, 0);
	if(ctlr[ctlrno].kproc == 0){
		sprint(ctlr[ctlrno].name, "ether%dkproc", ctlrno);
		kproc(ctlr[ctlrno].name, etherkproc, &ctlr[ctlrno]);
	
	(*cp->hw->online)(cp, 1);
	if(cp->kproc == 0){
		sprint(cp->name, "ether%dkproc", ctlrno);
		kproc(cp->name, etherkproc, cp);
	}
}

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

Chan *
etherclone(Chan *c, Chan *nc)
{
	return devclone(c, nc);
}
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;

	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;

#define IN(hw, m)	inb((hw)->addr+OFFSETOF(Wd8013, m))
#define OUT(hw, m, x)	outb((hw)->addr+OFFSETOF(Wd8013, m), (x))

int
etherwalk(Chan *c, char *name)
/*
 */
static void
wd8013reset(Ctlr *cp)
{
	return netwalk(c, name, &ctlr[0].net);
}
	Hw *hw = cp->hw;
	int i;
	uchar msr;

void
etherstat(Chan *c, char *dp)
{
	netstat(c, dp, &ctlr[0].net);
}
print("reset\n");
	cp->rb = ialloc(sizeof(Buffer)*Nrb, 0);
	cp->nrb = Nrb;
	cp->tb = ialloc(sizeof(Buffer)*Ntb, 0);
	cp->ntb = Ntb;

Chan *
etheropen(Chan *c, int omode)
	msr = IN(hw, msr);
	OUT(hw, msr, 0x40|msr);
{
	return netopen(c, omode, &ctlr[0].net);
int addr = hw->addr;

for(i = 0; i < 16; i++){
    print("#%2.2ux ", inb(addr));
    addr++;
}
print("\n");
}
	for(i = 0; i < sizeof(cp->ea); i++)
		cp->ea[i] = IN(hw, lan[i]);
	(*hw->init)(cp);
	setvec(Ethervec, hw->intr);
}

void
ethercreate(Chan *c, char *name, int omode, ulong perm)
/*
 * we leave the chip idling on internal loopback
 * and pointing to Page0.
 */
static void
wd8013init(Ctlr *cp)
{
	error(Eperm);
	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);
}

void
etherremove(Chan *c)
wd8013mode(Ctlr *cp, int on)
{
	error(Eperm);
	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);
}

void
etherwstat(Chan *c, char *dp)
static void
wd8013online(Ctlr *cp, int on)
{
	netwstat(c, dp, &ctlr[0].net);
	OUT(cp->hw, w.tcr, 0);
}

void
etherclose(Chan *c)
static void
wd8013receive(Ctlr *cp)
{
	if(c->stream)
		streamclose(c);
	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);
	}
}

long
etherread(Chan *c, void *a, long n, ulong offset)
static void
wd8013transmit(Ctlr *cp)
{
	return netread(c, a, n, offset, &ctlr[0].net);
	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");
}

long
etherwrite(Chan *c, char *a, long n, ulong offset)
static void
wd8013intr(Ureg *ur)
{
	return streamwrite(c, a, n, 0);
	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);
		}
	}
}

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,
};

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

	s = splhi();
debug++;
	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->outpackets,
	    cp->crcs, cp->oerrs, cp->frames, cp->overflows, cp->buffs);
	splx(s);
}

M pc/devhard.c => pc/devhard.c +8 -7
@@ 242,13 242,10 @@ hardattach(char *spec)
				break;
			default:	/* others: we hope this works */
				if (drivecomment) {
					print("unknown hard disk type, magic=%04x\n",
					print("unknown hard disk type, magic=%04x",
						dp->id.magic);
					print(" lcyls=%d lheads=%d sectors=%d\n",
					print("  cyl=%d h=%d sec=%d\n",
						dp->id.lcyls, dp->id.lheads, dp->id.ls2t);
					print(" ncyls=%d nheads=%d dlcyls=%d dlheads=%d\n",
						dp->id.ncyls, dp->id.nheads, dp->id.dlcyls,
						dp->id.dlheads);
				}
				dp->cyl = dp->id.lcyls;
				dp->heads = dp->id.lheads;


@@ 724,9 721,13 @@ hardintr(Ureg *ur)
		cp->cmd = 0;
		wakeup(&cp->r);
		break;
	case 0:	/*
		 * These don't seem to mean anything.  Should we wakeup?
		 */
		break;
	default:
		print("weird disk interrupt, cmd=%02x\n",
			cp->cmd);
		print("weird disk interrupt, cmd=%02x, status=%02x\n",
			cp->cmd, cp->status);
		break;
	}
}

M pc/vga.c => pc/vga.c +0 -27
@@ 66,30 66,6 @@ struct VGAmode
	uchar	attribute[0x15];
};

#ifdef ORIGINALSAFARI
/*
 *  640x480 display, 16 bit color
 */
VGAmode mode12 = 
{
	/* general */
	0xe3, 0x00, /* 0x70, 0x04, these are read-only */
	/* sequence */
	0x03, 0x01, 0x0f, 0x00, 0x06,
	/* crt */
	0x5f, 0x4f, 0x50, 0x82, 0x54, 0x80, 0x0b, 0x3e,
	0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x59,
	0xea, 0x0c, 0xdf, 0x28, 0x00, 0xe7, 0x04, 0xe3,
	0xff,
	/* graphics */
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x0f,
	0xff,
	/* attribute */
	0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07,
	0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
	0x01, 0x00, 0x0f, 0x00, 0x00,
};
#else
/*
 *  640x480 display, 16 bit color - attempt at SVGA version...ches
 */


@@ 112,9 88,6 @@ VGAmode mode12 =
	0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x3f,
	0x01, 0x10, 0x0f, 0x00, 0x00,
};
#endif

#define TESTDELAY	1

void
genout(int reg, int val)