~kris/9p

9hist

d7b582866c93f46ce589eba871d9477b34b78cec — David du Colombier 32 years ago 8a03333
Plan 9 from Bell Labs 1993-11-16
10 files changed, 875 insertions(+), 631 deletions(-)

M pc/devvga.c
M pc/ether509.c
M pc/ether8003.c
M pc/ether8390.c
M pc/etherif.h
M pc/fns.h
M pc/kbd.c
M pc/l.s
M pc/trap.c
M port/error.h
M pc/devvga.c => pc/devvga.c +669 -406
@@ 8,42 8,70 @@

#include	<libg.h>
#include	<gnot.h>
#include	"screen.h"
#include	"vga.h"

#define	MINX	8

struct{
	Point	pos;
	int	bwid;
}out;
enum
{
	EMISCR=		0x3CC,		/* control sync polarity */
	EMISCW=		0x3C2,
	EFCW=		0x3DA,		/* feature control */
	EFCR=		0x3CA,
	GRX=		0x3CE,		/* index to graphics registers */
	GR=		0x3CF,		/* graphics registers */
	 Grms=		 0x04,		/*  read map select register */
	SRX=		0x3C4,		/* index to sequence registers */
	SR=		0x3C5,		/* sequence registers */
	 Smmask=	 0x02,		/*  map mask */
	CRX=		0x3D4,		/* index to crt registers */
	CR=		0x3D5,		/* crt registers */
	 Cvre=		 0x11,		/*  vertical retrace end */
	ARW=		0x3C0,		/* attribute registers (writing) */
	ARR=		0x3C1,		/* attribute registers (reading) */
	CMRX=		0x3C7,		/* color map read index */
	CMWX=		0x3C8,		/* color map write index */
	CM=		0x3C9,		/* color map data reg */
};

/* imported */
extern	GSubfont defont0;
extern	Cursor arrow;
extern	GBitmap cursorback;

/* exported */
GSubfont *defont;
int islittle = 1;		/* little endian bit ordering in bytes */
GBitmap	gscreen;

/* local */
static	Lock vgalock;
/* vga screen */
static	Lock	screenlock;
static	GBitmap	vgascreen;
static	ulong colormap[256][3];
static	int cga = 1;		/* true if in cga mode */
static	ulong	colormap[256][3];
static	Rectangle mbb;
static	Rectangle NULLMBB = {10000, 10000, -10000, -10000};

/* cga screen */
static	int	cga = 1;		/* true if in cga mode */

/* system window */
static	int	isscroll;
static	Rectangle window;
static	int	h, w;
static	Point	cursor;

/*
 *  screen dimensions
 */
#define	MINX	8
#define MAXX	640
#define MAXY	480
#define	CGAWIDTH	160
#define	CGAHEIGHT	24

/*
 *  'soft' screen bitmap
 *  screen memory addresses
 */
#define SCREENMEM	(0xA0000 | KZERO)
#define CGASCREEN	((uchar*)(0xB8000 | KZERO))

/*
 *  VGA modes
 */
typedef struct VGAmode	VGAmode;
struct VGAmode
{


@@ 100,12 128,6 @@ VGAmode mode13 =
	0x41, 0x10, 0x0f, 0x00, 0x00,
};

static	Rectangle mbb;
static	Rectangle NULLMBB = {10000, 10000, -10000, -10000};
static	void nopage(int), tsengpage(int), tridentpage(int), parapage(int);
static	void atipage(int), cirruspage(int);
static	void vgaupdate(void);

/*
 *  definitions of known cards
 */


@@ 113,7 135,7 @@ typedef struct Vgacard	Vgacard;
struct Vgacard
{
	char	*name;
	void	(*setpage)(int);
	void	(*setpage)(int);	/* routine to page though display memory */
};

enum


@@ 126,6 148,9 @@ enum
	Generic,
};

static void	nopage(int), tsengpage(int), tridentpage(int), parapage(int);
static void	atipage(int), cirruspage(int);

Vgacard vgachips[] =
{
[Ati]		{ "ati", atipage, },


@@ 139,8 164,29 @@ Vgacard vgachips[] =

Vgacard	*vgacard;	/* current vga card */

/* predefined for the stupid compiler */
static void	setscreen(int, int, int);
static uchar	srin(int);
static void	genout(int, int);
static void	srout(int, int);
static void	grout(int, int);
static void	arout(int, int);
static void	crout(int, int);
static void	setmode(VGAmode*);
static void	getmode(VGAmode*);
static void	printmode(VGAmode*);
static void	cgascreenputc(int);
static void	cgascreenputs(char*, int);
static void	screenputc(char*);
static void	scroll(void);
static ulong	x3to32(uchar);
static ulong	x6to32(uchar);
void	screenupdate(void);
void	pixreverse(uchar*, int, int);
void	mbbrect(Rectangle);

/*
 *  vga device directory
 *  vga device
 */
enum
{


@@ 148,12 194,14 @@ enum
	Qvgasize=	1,
	Qvgatype=	2,
	Qvgaport=	3,
	Nvga=		3,
	Qvgaportw=	4,
	Nvga=		4,
};
Dirtab vgadir[]={
	"vgasize",	{Qvgasize},	0,		0666,
	"vgatype",	{Qvgatype},	0,		0666,
	"vgaport",	{Qvgaport},	0,		0666,
	"vgaportw",	{Qvgaportw},	0,		0666,
};

void


@@ 214,8 262,9 @@ long
vgaread(Chan *c, void *buf, long n, ulong offset)
{
	int port;
	uchar *cp = buf;
	uchar *cp;
	char cbuf[64];
	ushort *sp;

	switch(c->qid.path&~CHDIR){
	case Qdir:


@@ 227,13 276,16 @@ vgaread(Chan *c, void *buf, long n, ulong offset)
	case Qvgatype:
		return readstr(offset, buf, n, vgacard->name);
	case Qvgaport:
		/* at the moment, I need freedom for the ATI card - ches
		if (offset + n >= 0x8000 || offset < 0x300)
			error(Ebadarg);
		*/
		for (port=offset; port<offset+n; port++)
		for (cp = buf, port=offset; port<offset+n; port++)
			*cp++ = inb(port);
		return n;
	case Qvgaportw:
		if((n & 01) || (offset & 01))
			error(Ebadarg);
		n /= 2;
		for (sp = buf, port=offset; port<offset+n; port+=2)
			*sp++ = ins(port);
		return n*2;
	}
	error(Eperm);
	return 0;


@@ 245,6 297,7 @@ vgawrite(Chan *c, void *buf, long n, ulong offset)
	char cbuf[64], *cp;
	Vgacard *vp;
	int port, maxx, maxy, ldepth;
	ushort *sp;

	switch(c->qid.path&~CHDIR){
	case Qdir:


@@ 294,20 347,19 @@ vgawrite(Chan *c, void *buf, long n, ulong offset)
		|| maxx > 1280 || maxy > 1024
		|| ldepth > 3 || ldepth < 0)
			error(Ebadarg);
		cursoroff(1);
		setscreen(maxx, maxy, ldepth);
		cursoron(1);
		return n;
	case Qvgaport:
		cp = buf;
		/*
		if (offset + n >= 0x8000 || offset < 0x300)
			error(Ebadarg);
		*/
		for (port=offset; port<offset+n; port++) {
		for (cp = buf, port=offset; port<offset+n; port++)
			outb(port, *cp++);
		}
		return n;
	case Qvgaportw:
		if((n & 01) || (offset & 01))
			error(Ebadarg);
		n /= 2;
		for (sp = buf, port=offset; port<offset+n; port+=2)
			outs(port, *sp++);
		return n*2;
	}
	error(Eperm);
	return 0;


@@ 327,160 379,38 @@ vgawstat(Chan *c, char *dp)
	error(Eperm);
}

uchar
srin(int i) {
	outb(SRX, i);
	return inb(SR);
}
void
genout(int reg, int val)
{
	if(reg == 0)
		outb(EMISCW, val);
	else if (reg == 1)
		outb(EFCW, val);
}
void
srout(int reg, int val)
{
	outb(SRX, reg);
	outb(SR, val);
}
void
grout(int reg, int val)
{
	outb(GRX, reg);
	outb(GR, val);
}
void
arout(int reg, int val)
{
	inb(0x3DA);
	if (reg <= 0xf) {
		outb(ARW, reg | 0x0);
		outb(ARW, val);
		inb(0x3DA);
		outb(ARW, reg | 0x20);
	} else {
		outb(ARW, reg | 0x20);
		outb(ARW, val);
	}
}

void
crout(int reg, int val)
{
	outb(CRX, reg);
	outb(CR, val);
}

/*
 *  start the screen in CGA mode.  Create the fonts for VGA.
 */
void
setmode(VGAmode *v)
screeninit(void)
{
	int i;
	ulong *l;

	/* turn screen off (to avoid damage) */
	srout(1, 0x21);

	for(i = 0; i < sizeof(v->general); i++)
		genout(i, v->general[i]);

	for(i = 0; i < sizeof(v->sequencer); i++)
		if(i == 1)
			srout(i, v->sequencer[i]|0x20);		/* avoid enabling screen */
		else
			srout(i, v->sequencer[i]);

	crout(Cvre, 0);	/* allow writes to CRT registers 0-7 */
	for(i = 0; i < sizeof(v->crt); i++)
		crout(i, v->crt[i]);

	for(i = 0; i < sizeof(v->graphics); i++)
		grout(i, v->graphics[i]);

	for(i = 0; i < sizeof(v->attribute); i++)
		arout(i, v->attribute[i]);

	/* turn screen on */
	srout(1, v->sequencer[1]);
}

void
getmode(VGAmode *v) {
	int i;
	v->general[0] = inb(0x3cc);
	v->general[1] = inb(0x3ca);
	for(i = 0; i < sizeof(v->sequencer); i++) {
		outb(SRX, i);
		v->sequencer[i] = inb(SR);
	}
	for(i = 0; i < sizeof(v->crt); i++) {
		outb(CRX, i);
		v->crt[i] = inb(CR);
	}
	for(i = 0; i < sizeof(v->graphics); i++) {
		outb(GRX, i);
		v->graphics[i] = inb(GR);
	}
	for(i = 0; i < sizeof(v->attribute); i++) {
		inb(0x3DA);
		outb(ARW, i | 0x20);
		v->attribute[i] = inb(ARR);
	}
}

void
printmode(VGAmode *v) {
	int i;
	print("g %2.2x %2x\n",
		v->general[0], v->general[1]);

	print("s ");
	for(i = 0; i < sizeof(v->sequencer); i++) {
		print(" %2.2x", v->sequencer[i]);
	}

	print("\nc ");
	for(i = 0; i < sizeof(v->crt); i++) {
		print(" %2.2x", v->crt[i]);
	}

	print("\ng ");
	for(i = 0; i < sizeof(v->graphics); i++) {
		print(" %2.2x", v->graphics[i]);
	}
	/*
	 *  swizzle the font longs.  we do both byte and bit swizzling
	 *  since the font is initialized with big endian longs.
	 */
	defont = &defont0;
	l = defont->bits->base;
	for(i = defont->bits->width*Dy(defont->bits->r); i > 0; i--, l++)
		*l = (*l<<24) | ((*l>>8)&0x0000ff00) | ((*l<<8)&0x00ff0000) | (*l>>24);
	pixreverse((uchar*)defont->bits->base,
		defont->bits->width*BY2WD*Dy(defont->bits->r), 0);

	print("\na ");
	for(i = 0; i < sizeof(v->attribute); i++) {
		print(" %2.2x", v->attribute[i]);
	}
	print("\n");
	/*
	 *  start in CGA mode
	 */
	cga = 1;
	crout(0x0a, 0xff);		/* turn off cursor */
	memset(CGASCREEN, 0, CGAWIDTH*CGAHEIGHT);
}

/*
 *  expand 3 and 6 bits of color to 32
 *  reconfigure screen shape
 */
static ulong
x3to32(uchar x)
{
	ulong y;

	x = x&7;
	x= (x<<3)|x;
	y = (x<<(32-6))|(x<<(32-12))|(x<<(32-18))|(x<<(32-24))|(x<<(32-30));
	return y;
}
static ulong
x6to32(uchar x)
{
	ulong y;

	x = x&0x3f;
	y = (x<<(32-6))|(x<<(32-12))|(x<<(32-18))|(x<<(32-24))|(x<<(32-30));
	return y;
}

void
static void
setscreen(int maxx, int maxy, int ldepth)
{
	int len, vgamaxy, width, i, x, s;


@@ 533,18 463,6 @@ setscreen(int maxx, int maxy, int ldepth)
		xfree(oldp);

	/*
	 *  set depth of cursor backup area
	 */
	bitdepth();

	/*
	 *  set string pointer to upper left
	 */
	out.pos.x = MINX;
	out.pos.y = 0;
	out.bwid = defont0.info[' '].width;

	/*
	 *  default color map
	 */
	switch(ldepth){


@@ 563,127 481,108 @@ setscreen(int maxx, int maxy, int ldepth)
		gscreen.ldepth = ldepth;
		break;
	}
	bbinit();
	cga = 0;

	/*
	 * clear screen
	 * display white window
	 */
	mbb = gscreen.r;
	vgaupdate();
}

void
screeninit(void)
{
	int i;
	ulong *l;
	screenupdate();

	/*
	 *  arrow is defined as a big endian
	 *  set up inset system window
	 */
	pixreverse(arrow.set, 2*16, 0);
	pixreverse(arrow.clr, 2*16, 0);
	h = defont0.height;
	w = defont0.info[' '].width;

	/*
	 *  swizzle the font longs.  we do both byte and bit swizzling
	 *  since the font is initialized with big endian longs.
	 */
	defont = &defont0;
	l = defont->bits->base;
	for(i = defont->bits->width*Dy(defont->bits->r); i > 0; i--, l++)
		*l = (*l<<24) | ((*l>>8)&0x0000ff00) | ((*l<<8)&0x00ff0000) | (*l>>24);
	pixreverse((uchar*)defont->bits->base,
		defont->bits->width*BY2WD*Dy(defont->bits->r), 0);
	window.min = Pt(50, 50);
	window.max = add(window.min, Pt(10+w*64, 10+h*24));

	cga = 1;
	crout(0x0a, 0xff);		/* turn off cursor */
	memset(CGASCREEN, 0, CGAWIDTH*CGAHEIGHT);
	gbitblt(&gscreen, window.min, &gscreen, window, Zero);
	window = inset(window, 5);
	cursor = window.min;
	window.max.y = window.min.y+((window.max.y-window.min.y)/h)*h;
	hwcurs = 0;

	mbb = gscreen.r;
	screenupdate();
}

/*
 *  collect changes to the 'soft' screen
 * paste tile into soft screen.
 * tile is at location r, first pixel in *data.  tl is length of scan line to insert,
 * l is amount to advance data after each scan line.
 */
void
mbbrect(Rectangle r)
screenload(Rectangle r, uchar *data, int tl, int l)
{
	if (r.min.x < mbb.min.x)
		mbb.min.x = r.min.x;
	if (r.min.y < mbb.min.y)
		mbb.min.y = r.min.y;
	if (r.max.x > mbb.max.x)
		mbb.max.x = r.max.x;
	if (r.max.y > mbb.max.y)
		mbb.max.y = r.max.y;
	mousescreenupdate();
}
	int y, lpart, rpart, mx, m, mr;
	uchar *q;
	extern void cursorlock(Rectangle);
	extern void cursorunlock(void);

void
mbbpt(Point p)
{
	if (p.x < mbb.min.x)
		mbb.min.x = p.x;
	if (p.y < mbb.min.y)
		mbb.min.y = p.y;
	if (p.x >= mbb.max.x)
		mbb.max.x = p.x+1;
	if (p.y >= mbb.max.y)
		mbb.max.y = p.y+1;
	if(!rectclip(&r, gscreen.r) || tl<=0)
		return;
	lock(&screenlock);
	cursorlock(r);
	screenupdate();
	q = gbaddr(&gscreen, r.min);
	mx = 7>>gscreen.ldepth;
	lpart = (r.min.x & mx) << gscreen.ldepth;
	rpart = (r.max.x & mx) << gscreen.ldepth;
	m = 0xFF >> lpart;
	mr = 0xFF ^ (0xFF >> rpart);
	/* may need to do bit insertion on edges */
	if(l == 1){	/* all in one byte */
		if(rpart)
			m ^= 0xFF >> rpart;
		for(y=r.min.y; y<r.max.y; y++){
			*q ^= (*data^*q) & m;
			q += gscreen.width*sizeof(ulong);
			data += l;
		}
	}else if(lpart==0 && rpart==0){	/* easy case */
		for(y=r.min.y; y<r.max.y; y++){
			memmove(q, data, tl);
			q += gscreen.width*sizeof(ulong);
			data += l;
		}
	}else if(rpart==0){
		for(y=r.min.y; y<r.max.y; y++){
			*q ^= (*data^*q) & m;
			if(tl > 1)
				memmove(q+1, data+1, tl-1);
			q += gscreen.width*sizeof(ulong);
			data += l;
		}
	}else if(lpart == 0){
		for(y=r.min.y; y<r.max.y; y++){
			if(tl > 1)
				memmove(q, data, tl-1);
			q[tl-1] ^= (data[tl-1]^q[tl-1]) & mr;
			q += gscreen.width*sizeof(ulong);
			data += l;
		}
	}else for(y=r.min.y; y<r.max.y; y++){
			*q ^= (*data^*q) & m;
			if(l > 2)
				memmove(q+1, data+1, tl-2);
			q[tl-1] ^= (data[tl-1]^q[l-1]) & mr;
			q += gscreen.width*sizeof(ulong);
			data += l;
		}
	mbbrect(r);
	screenupdate();
	cursorunlock();
	screenupdate();
	unlock(&screenlock);
}

/*
 *  paging routines for different cards
 */
static void
nopage(int page)
{
	USED(page);
}
/*
 * The following code is unproven: we haven't got the
 * ATI stuff to work yet.
 *  copy litte endian soft screen to big endian hard screen
 */
static void
atipage(int page)
{
	/* the ext register is in the ATI ROM at a fixed address */
	ushort extreg = *((ushort *)0x800C0010);
	uchar v;

	outb(extreg, 0xb2);
	v = (inb(extreg+1) & 0xe1) | (page<<1);
	outb(extreg, 0xb2);
	outb(extreg+1, v);
}
/*
 * The following assumes that the new mode registers have been selected.
 */
static void
tridentpage(int page)
{
	srout(0xe, (srin(0xe)&0xf0) | page^0x2);
}
static void
tsengpage(int page)
{
	outb(0x3cd, (page<<4)|page);
}
static void
cirruspage(int page)
{
	grout(0x9, page<<4);
}
static void
parapage(int page)
{
	grout(0x9, page<<4);
}

/*
 *  copy litte endian soft screen to big endian hard screen
 */
static void
vgaupdate(void)
void
screenupdate(void)
{
	uchar *sp, *hp, *edisp;
	int y, len, incs, inch, off, page;


@@ 772,20 671,311 @@ vgaupdate(void)
}

void
screenupdate(void)
screenputs(char *s, int n)
{
	lock(&vgalock);
	vgaupdate();
	unlock(&vgalock);
	int i;
	Rune r;
	char buf[4];

	if(cga) {
		cgascreenputs(s, n);
		return;
	}

	if((getstatus() & IFLAG) == 0) {
		/* don't deadlock trying to print in interrupt */
		if(!canlock(&screenlock))
			return;	
	} else
		lock(&screenlock);

	while(n > 0) {
		i = chartorune(&r, s);
		if(i == 0){
			s++;
			--n;
			continue;
		}
		memmove(buf, s, i);
		buf[i] = 0;
		n -= i;
		s += i;
		screenputc(buf);
	}
	if(isscroll) {
		mbb = window;
		isscroll = 0;
	}

	screenupdate();
	unlock(&screenlock);
}

/*
 *  accessing registers
 */
static uchar
srin(int i) {
	outb(SRX, i);
	return inb(SR);
}
static void
genout(int reg, int val)
{
	if(reg == 0)
		outb(EMISCW, val);
	else if (reg == 1)
		outb(EFCW, val);
}
static void
srout(int reg, int val)
{
	outb(SRX, reg);
	outb(SR, val);
}
static void
grout(int reg, int val)
{
	outb(GRX, reg);
	outb(GR, val);
}
static void
arout(int reg, int val)
{
	inb(0x3DA);
	if (reg <= 0xf) {
		outb(ARW, reg | 0x0);
		outb(ARW, val);
		inb(0x3DA);
		outb(ARW, reg | 0x20);
	} else {
		outb(ARW, reg | 0x20);
		outb(ARW, val);
	}
}
static void
crout(int reg, int val)
{
	outb(CRX, reg);
	outb(CR, val);
}

static void
setmode(VGAmode *v)
{
	int i;

	/* turn screen off (to avoid damage) */
	srout(1, 0x21);

	for(i = 0; i < sizeof(v->general); i++)
		genout(i, v->general[i]);

	for(i = 0; i < sizeof(v->sequencer); i++)
		if(i == 1)
			srout(i, v->sequencer[i]|0x20);		/* avoid enabling screen */
		else
			srout(i, v->sequencer[i]);

	crout(Cvre, 0);	/* allow writes to CRT registers 0-7 */
	for(i = 0; i < sizeof(v->crt); i++)
		crout(i, v->crt[i]);

	for(i = 0; i < sizeof(v->graphics); i++)
		grout(i, v->graphics[i]);

	for(i = 0; i < sizeof(v->attribute); i++)
		arout(i, v->attribute[i]);

	/* turn screen on */
	srout(1, v->sequencer[1]);
}

static void
getmode(VGAmode *v)
{
	int i;
	v->general[0] = inb(0x3cc);
	v->general[1] = inb(0x3ca);
	for(i = 0; i < sizeof(v->sequencer); i++) {
		outb(SRX, i);
		v->sequencer[i] = inb(SR);
	}
	for(i = 0; i < sizeof(v->crt); i++) {
		outb(CRX, i);
		v->crt[i] = inb(CR);
	}
	for(i = 0; i < sizeof(v->graphics); i++) {
		outb(GRX, i);
		v->graphics[i] = inb(GR);
	}
	for(i = 0; i < sizeof(v->attribute); i++) {
		inb(0x3DA);
		outb(ARW, i | 0x20);
		v->attribute[i] = inb(ARR);
	}
}

static void
printmode(VGAmode *v)
{
	int i;
	print("g %2.2x %2x\n",
		v->general[0], v->general[1]);

	print("s ");
	for(i = 0; i < sizeof(v->sequencer); i++) {
		print(" %2.2x", v->sequencer[i]);
	}

	print("\nc ");
	for(i = 0; i < sizeof(v->crt); i++) {
		print(" %2.2x", v->crt[i]);
	}

	print("\ng ");
	for(i = 0; i < sizeof(v->graphics); i++) {
		print(" %2.2x", v->graphics[i]);
	}

	print("\na ");
	for(i = 0; i < sizeof(v->attribute); i++) {
		print(" %2.2x", v->attribute[i]);
	}
	print("\n");
}

/*
 *  expand 3 and 6 bits of color to 32
 */
static ulong
x3to32(uchar x)
{
	ulong y;

	x = x&7;
	x= (x<<3)|x;
	y = (x<<(32-6))|(x<<(32-12))|(x<<(32-18))|(x<<(32-24))|(x<<(32-30));
	return y;
}
static ulong
x6to32(uchar x)
{
	ulong y;

	x = x&0x3f;
	y = (x<<(32-6))|(x<<(32-12))|(x<<(32-18))|(x<<(32-24))|(x<<(32-30));
	return y;
}

/*
 *  just in case we have one
 */
void
hwcursset(ulong *s, ulong *c, int ox, int oy)
{
	USED(s, c, ox, oy);
}

void
hwcursmove(int x, int y)
{
	USED(x, y);
}

/*
 *  collect changes to the 'soft' screen
 */
void
mbbrect(Rectangle r)
{
	if (r.min.x < mbb.min.x)
		mbb.min.x = r.min.x;
	if (r.min.y < mbb.min.y)
		mbb.min.y = r.min.y;
	if (r.max.x > mbb.max.x)
		mbb.max.x = r.max.x;
	if (r.max.y > mbb.max.y)
		mbb.max.y = r.max.y;
}

void
mbbpt(Point p)
{
	if (p.x < mbb.min.x)
		mbb.min.x = p.x;
	if (p.y < mbb.min.y)
		mbb.min.y = p.y;
	if (p.x >= mbb.max.x)
		mbb.max.x = p.x+1;
	if (p.y >= mbb.max.y)
		mbb.max.y = p.y+1;
}

/*
 *  paging routines for different cards
 */
static void
nopage(int page)
{
	USED(page);
}

/*
 * Extended registers can be read with inb(), but must be
 * written with outs(). The index must be written each time
 * before the register is accessed.
 * The page bits are spread across registers 0xAE and 0xB2.
 * This can go away when we use the memory aperture.
 */
static void
atipage(int page)
{
	/* the ext register is in the ATI ROM at a fixed address */
	ushort extreg = *((ushort *)0x800C0010);
	uchar v;

	outb(extreg, 0xAE);
	v = (inb(extreg+1) & 0xFC)|((page>>4) & 0x03);
	outs(extreg, (v<<8)|0xAE);

	outb(extreg, 0xB2);
	v = (inb(extreg+1) & 0xE1)|((page & 0x0F)<<1);
	outs(extreg, (v<<8)|0xB2);
}

/*
 * The following assumes that the new mode registers have been selected.
 */
static void
tridentpage(int page)
{
	srout(0xe, (srin(0xe)&0xf0) | page^0x2);
}
static void
tsengpage(int page)
{
	outb(0x3cd, (page<<4)|page);
}
static void
cirruspage(int page)
{
	grout(0x9, page<<4);
}
static void
parapage(int page)
{
	grout(0x9, page<<4);
}

void
mousescreenupdate(void)
{
	if(canlock(&vgalock)){
		vgaupdate();
		unlock(&vgalock);
	}
	if(canlock(&screenlock) == 0)
		return;

	screenupdate();
	unlock(&screenlock);
}

static void


@@ 818,78 1008,60 @@ cgascreenputc(int c)
	}
}

void
static void
cgascreenputs(char *s, int n)
{
	while(n-- > 0)
		cgascreenputc(*s++);
}

void
screenputnl(void)
static void
scroll(void)
{
	int o;
	Rectangle r;

	out.pos.x = MINX;
	out.pos.y += defont0.height;
	if(out.pos.y > gscreen.r.max.y-defont0.height){
		vgaupdate();
		out.pos.y = gscreen.r.min.y;
	}
	r = Rect(0, out.pos.y, gscreen.r.max.x, out.pos.y+2*defont0.height);
	gbitblt(&gscreen, r.min, &gscreen, r, flipD[0]);
	mbbrect(r);
	vgaupdate();
	o = 5*h;
	r = Rpt(Pt(window.min.x, window.min.y+o), window.max);
	gbitblt(&gscreen, window.min, &gscreen, r, S);
	r = Rpt(Pt(window.min.x, window.max.y-o), window.max);
	gbitblt(&gscreen, r.min, &gscreen, r, Zero);
	cursor.y -= o;
	isscroll = 1;
}

void
screenputs(char *s, int n)
static void
screenputc(char *buf)
{
	Rune r;
	int i;
	char buf[4];
	Rectangle rect;

	if(cga) {
		cgascreenputs(s, n);
		return;
	}
	int pos;

	mbbpt(cursor);
	switch(buf[0]) {
	case '\n':
		if(cursor.y+h >= window.max.y)
			scroll();
		cursor.y += h;
		screenputc("\r");
		break;
	case '\r':
		cursor.x = window.min.x;
		break;
	case '\t':
		pos = (cursor.x-window.min.x)/w;
		pos = 8-(pos%8);
		cursor.x += pos*w;
		break;
	case '\b':
		if(cursor.x-w >= window.min.x)
			cursor.x -= w;
		break;
	default:
		if(cursor.x >= window.max.x-w)
			screenputc("\n");

	while(n > 0){
		i = chartorune(&r, s);
		if(i == 0){
			s++;
			--n;
			continue;
		}
		memmove(buf, s, i);
		buf[i] = 0;
		n -= i;
		s += i;
		if(r == '\n')
			screenputnl();
		else if(r == '\t'){
			out.pos.x += (8-((out.pos.x-MINX)/out.bwid&7))*out.bwid;
			if(out.pos.x >= gscreen.r.max.x)
				screenputnl();
		}else if(r == '\b'){
			if(out.pos.x >= out.bwid+MINX){
				out.pos.x -= out.bwid;
				gsubfstring(&gscreen, out.pos, defont, " ", flipD[S]);
			}
			rect.min = Pt(out.pos.x, out.pos.y);
			rect.max = Pt(out.pos.x+out.bwid, out.pos.y+defont0.height);
			mbbrect(rect);
		}else{
			if(out.pos.x >= gscreen.r.max.x-out.bwid)
				screenputnl();
			rect.min = Pt(out.pos.x, out.pos.y);
			rect.max = Pt(out.pos.x+out.bwid, out.pos.y+defont0.height);
			out.pos = gsubfstring(&gscreen, out.pos, defont, buf, flipD[S]);
			mbbrect(rect);
		}
		cursor = gsubfstring(&gscreen, cursor, &defont0, buf, S);
	}
	vgaupdate();
	mbbpt(Pt(cursor.x, cursor.y+h));
}

int


@@ 902,18 1074,18 @@ void
getcolor(ulong p, ulong *pr, ulong *pg, ulong *pb)
{
	p &= (1<<(1<<gscreen.ldepth))-1;
	lock(&vgalock);
	lock(&screenlock);
	*pr = colormap[p][0];
	*pg = colormap[p][1];
	*pb = colormap[p][2];
	unlock(&vgalock);
	unlock(&screenlock);
}

int
setcolor(ulong p, ulong r, ulong g, ulong b)
{
	p &= (1<<(1<<gscreen.ldepth))-1;
	lock(&vgalock);
	lock(&screenlock);
	colormap[p][0] = r;
	colormap[p][1] = g;
	colormap[p][2] = b;


@@ 921,49 1093,10 @@ setcolor(ulong p, ulong r, ulong g, ulong b)
	outb(CM, r>>(32-6));
	outb(CM, g>>(32-6));
	outb(CM, b>>(32-6));
	unlock(&vgalock);
	unlock(&screenlock);
	return ~0;
}

void
hwcursset(ulong *s, ulong *c, int ox, int oy)
{
	USED(s, c, ox, oy);
}

void
hwcursmove(int x, int y)
{
	USED(x, y);
}

/*
 *  a fatter than usual cursor for the safari
 */
Cursor fatarrow = {
	{ -1, -1 },
	{
		0xff, 0xff, 0x80, 0x01, 0x80, 0x02, 0x80, 0x0c, 
		0x80, 0x10, 0x80, 0x10, 0x80, 0x08, 0x80, 0x04, 
		0x80, 0x02, 0x80, 0x01, 0x80, 0x02, 0x8c, 0x04, 
		0x92, 0x08, 0x91, 0x10, 0xa0, 0xa0, 0xc0, 0x40, 
	},
	{
		0x00, 0x00, 0x7f, 0xfe, 0x7f, 0xfc, 0x7f, 0xf0, 
		0x7f, 0xe0, 0x7f, 0xe0, 0x7f, 0xf0, 0x7f, 0xf8, 
		0x7f, 0xfc, 0x7f, 0xfe, 0x7f, 0xfc, 0x73, 0xf8, 
		0x61, 0xf0, 0x60, 0xe0, 0x40, 0x40, 0x00, 0x00, 
	},
};

void
bigcursor(void)
{
	memmove(&arrow, &fatarrow, sizeof(fatarrow));
	pixreverse(arrow.set, 2*16, 0);
	pixreverse(arrow.clr, 2*16, 0);
}

/*
 *  Table for separating and reversing bits in a ldepth 1 bitmap.
 *  This aids in coverting a little endian ldepth 1 bitmap into the


@@ 1063,3 1196,133 @@ ulong l2revsep[] = {
 0x1010101, 0x1010103, 0x1010301, 0x1010303, 0x1030101, 0x1030103, 0x1030301, 0x1030303,
 0x3010101, 0x3010103, 0x3010301, 0x3010303, 0x3030101, 0x3030103, 0x3030301, 0x3030303,
};

/*
 *  reverse pixels into little endian order
 */
uchar revtab0[] = {
 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
 0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff,
};
uchar revtab1[] = {
 0x00, 0x40, 0x80, 0xc0, 0x10, 0x50, 0x90, 0xd0,
 0x20, 0x60, 0xa0, 0xe0, 0x30, 0x70, 0xb0, 0xf0,
 0x04, 0x44, 0x84, 0xc4, 0x14, 0x54, 0x94, 0xd4,
 0x24, 0x64, 0xa4, 0xe4, 0x34, 0x74, 0xb4, 0xf4,
 0x08, 0x48, 0x88, 0xc8, 0x18, 0x58, 0x98, 0xd8,
 0x28, 0x68, 0xa8, 0xe8, 0x38, 0x78, 0xb8, 0xf8,
 0x0c, 0x4c, 0x8c, 0xcc, 0x1c, 0x5c, 0x9c, 0xdc,
 0x2c, 0x6c, 0xac, 0xec, 0x3c, 0x7c, 0xbc, 0xfc,
 0x01, 0x41, 0x81, 0xc1, 0x11, 0x51, 0x91, 0xd1,
 0x21, 0x61, 0xa1, 0xe1, 0x31, 0x71, 0xb1, 0xf1,
 0x05, 0x45, 0x85, 0xc5, 0x15, 0x55, 0x95, 0xd5,
 0x25, 0x65, 0xa5, 0xe5, 0x35, 0x75, 0xb5, 0xf5,
 0x09, 0x49, 0x89, 0xc9, 0x19, 0x59, 0x99, 0xd9,
 0x29, 0x69, 0xa9, 0xe9, 0x39, 0x79, 0xb9, 0xf9,
 0x0d, 0x4d, 0x8d, 0xcd, 0x1d, 0x5d, 0x9d, 0xdd,
 0x2d, 0x6d, 0xad, 0xed, 0x3d, 0x7d, 0xbd, 0xfd,
 0x02, 0x42, 0x82, 0xc2, 0x12, 0x52, 0x92, 0xd2,
 0x22, 0x62, 0xa2, 0xe2, 0x32, 0x72, 0xb2, 0xf2,
 0x06, 0x46, 0x86, 0xc6, 0x16, 0x56, 0x96, 0xd6,
 0x26, 0x66, 0xa6, 0xe6, 0x36, 0x76, 0xb6, 0xf6,
 0x0a, 0x4a, 0x8a, 0xca, 0x1a, 0x5a, 0x9a, 0xda,
 0x2a, 0x6a, 0xaa, 0xea, 0x3a, 0x7a, 0xba, 0xfa,
 0x0e, 0x4e, 0x8e, 0xce, 0x1e, 0x5e, 0x9e, 0xde,
 0x2e, 0x6e, 0xae, 0xee, 0x3e, 0x7e, 0xbe, 0xfe,
 0x03, 0x43, 0x83, 0xc3, 0x13, 0x53, 0x93, 0xd3,
 0x23, 0x63, 0xa3, 0xe3, 0x33, 0x73, 0xb3, 0xf3,
 0x07, 0x47, 0x87, 0xc7, 0x17, 0x57, 0x97, 0xd7,
 0x27, 0x67, 0xa7, 0xe7, 0x37, 0x77, 0xb7, 0xf7,
 0x0b, 0x4b, 0x8b, 0xcb, 0x1b, 0x5b, 0x9b, 0xdb,
 0x2b, 0x6b, 0xab, 0xeb, 0x3b, 0x7b, 0xbb, 0xfb,
 0x0f, 0x4f, 0x8f, 0xcf, 0x1f, 0x5f, 0x9f, 0xdf,
 0x2f, 0x6f, 0xaf, 0xef, 0x3f, 0x7f, 0xbf, 0xff,
};
uchar revtab2[] = {
 0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70,
 0x80, 0x90, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0,
 0x01, 0x11, 0x21, 0x31, 0x41, 0x51, 0x61, 0x71,
 0x81, 0x91, 0xa1, 0xb1, 0xc1, 0xd1, 0xe1, 0xf1,
 0x02, 0x12, 0x22, 0x32, 0x42, 0x52, 0x62, 0x72,
 0x82, 0x92, 0xa2, 0xb2, 0xc2, 0xd2, 0xe2, 0xf2,
 0x03, 0x13, 0x23, 0x33, 0x43, 0x53, 0x63, 0x73,
 0x83, 0x93, 0xa3, 0xb3, 0xc3, 0xd3, 0xe3, 0xf3,
 0x04, 0x14, 0x24, 0x34, 0x44, 0x54, 0x64, 0x74,
 0x84, 0x94, 0xa4, 0xb4, 0xc4, 0xd4, 0xe4, 0xf4,
 0x05, 0x15, 0x25, 0x35, 0x45, 0x55, 0x65, 0x75,
 0x85, 0x95, 0xa5, 0xb5, 0xc5, 0xd5, 0xe5, 0xf5,
 0x06, 0x16, 0x26, 0x36, 0x46, 0x56, 0x66, 0x76,
 0x86, 0x96, 0xa6, 0xb6, 0xc6, 0xd6, 0xe6, 0xf6,
 0x07, 0x17, 0x27, 0x37, 0x47, 0x57, 0x67, 0x77,
 0x87, 0x97, 0xa7, 0xb7, 0xc7, 0xd7, 0xe7, 0xf7,
 0x08, 0x18, 0x28, 0x38, 0x48, 0x58, 0x68, 0x78,
 0x88, 0x98, 0xa8, 0xb8, 0xc8, 0xd8, 0xe8, 0xf8,
 0x09, 0x19, 0x29, 0x39, 0x49, 0x59, 0x69, 0x79,
 0x89, 0x99, 0xa9, 0xb9, 0xc9, 0xd9, 0xe9, 0xf9,
 0x0a, 0x1a, 0x2a, 0x3a, 0x4a, 0x5a, 0x6a, 0x7a,
 0x8a, 0x9a, 0xaa, 0xba, 0xca, 0xda, 0xea, 0xfa,
 0x0b, 0x1b, 0x2b, 0x3b, 0x4b, 0x5b, 0x6b, 0x7b,
 0x8b, 0x9b, 0xab, 0xbb, 0xcb, 0xdb, 0xeb, 0xfb,
 0x0c, 0x1c, 0x2c, 0x3c, 0x4c, 0x5c, 0x6c, 0x7c,
 0x8c, 0x9c, 0xac, 0xbc, 0xcc, 0xdc, 0xec, 0xfc,
 0x0d, 0x1d, 0x2d, 0x3d, 0x4d, 0x5d, 0x6d, 0x7d,
 0x8d, 0x9d, 0xad, 0xbd, 0xcd, 0xdd, 0xed, 0xfd,
 0x0e, 0x1e, 0x2e, 0x3e, 0x4e, 0x5e, 0x6e, 0x7e,
 0x8e, 0x9e, 0xae, 0xbe, 0xce, 0xde, 0xee, 0xfe,
 0x0f, 0x1f, 0x2f, 0x3f, 0x4f, 0x5f, 0x6f, 0x7f,
 0x8f, 0x9f, 0xaf, 0xbf, 0xcf, 0xdf, 0xef, 0xff,
};

void
pixreverse(uchar *p, int len, int ldepth)
{
	uchar *e;
	uchar *tab;

	switch(ldepth){
	case 0:
		tab = revtab0;
		break;
	case 1:
		tab = revtab1;
		break;
	case 2:
		tab = revtab2;
		break;
	default:
		return;
	}

	for(e = p + len; p < e; p++)
		*p = tab[*p];
}

M pc/ether509.c => pc/ether509.c +0 -2
@@ 219,7 219,6 @@ write(Ether *ether, void *buf, long n)
	ushort len;
	ulong port;

print("W|");
	port = ether->port;
	ether->tlen = n;
	len = ROUNDUP(ether->tlen, 4);


@@ 267,7 266,6 @@ interrupt(Ether *ether)
	port = ether->port;
	status = ins(port+Status);

print("I%2.2ux|", status);
	if(status & Failure){
		/*
		 * Adapter failure, try to find out why.

M pc/ether8003.c => pc/ether8003.c +4 -4
@@ 3,11 3,11 @@
#include "mem.h"
#include "dat.h"
#include "fns.h"
#include "../port/error.h"
#include "io.h"
#include "devtab.h"
#include "../port/error.h"
#include "../port/netif.h"

#include "ether.h"
#include "etherif.h"

/*
 * Western Digital/Standard Microsystems Corporation cards (WD80[01]3).


@@ 244,5 244,5 @@ wd8003reset(Ctlr *ctlr)
void
ether8003link(void)
{
	addethercard("WD8003", wd8003reset);
	addethercard("WD8003", reset);
}

M pc/ether8390.c => pc/ether8390.c +176 -214
@@ 8,11 8,11 @@
#include "mem.h"
#include "dat.h"
#include "fns.h"
#include "../port/error.h"
#include "io.h"
#include "devtab.h"
#include "../port/error.h"
#include "../port/netif.h"

#include "ether.h"
#include "etherif.h"

enum {
	Cr		= 0x00,		/* command register, all pages */


@@ 147,12 147,12 @@ typedef struct {
} Hdr;

static void
dp8390disable(Ctlr *ctlr)
dp8390disable(Ether *ether)
{
	ulong dp8390;
	int timo;

	dp8390 = ctlr->card.dp8390;
	dp8390 = ether->dp8390;
	/*
	 * Stop the chip. Set the Stp bit and wait for the chip
	 * to finish whatever was on its tiny mind before it sets


@@ 169,96 169,30 @@ dp8390disable(Ctlr *ctlr)
}

static void
dp8390ring(Ctlr *ctlr)
dp8390ring(Ether *ether)
{
	ulong dp8390;

	dp8390 = ctlr->card.dp8390;
	dp8390outb(dp8390+Pstart, ctlr->card.pstart);
	dp8390outb(dp8390+Pstop, ctlr->card.pstop);
	dp8390outb(dp8390+Bnry, ctlr->card.pstop-1);
	dp8390 = ether->dp8390;
	dp8390outb(dp8390+Pstart, ether->pstart);
	dp8390outb(dp8390+Pstop, ether->pstop);
	dp8390outb(dp8390+Bnry, ether->pstop-1);

	dp8390outb(dp8390+Cr, Page1|RDMAabort|Stp);
	dp8390outb(dp8390+Curr, ctlr->card.pstart);
	dp8390outb(dp8390+Curr, ether->pstart);
	dp8390outb(dp8390+Cr, Page0|RDMAabort|Stp);

	ctlr->card.nxtpkt = ctlr->card.pstart;
	ether->nxtpkt = ether->pstart;
}

void
dp8390reset(Ctlr *ctlr)
{
	ulong dp8390;

	dp8390 = ctlr->card.dp8390;
	/*
	 * This is the initialisation procedure described
	 * as 'mandatory' in the datasheet, with references
	 * to the 3Com503 technical reference manual.
	 */ 
	dp8390disable(ctlr);
	if(ctlr->card.bit16)
		dp8390outb(dp8390+Dcr, Ft4|Ls|Wts);
	else
		dp8390outb(dp8390+Dcr, Ft4|Ls);

	dp8390outb(dp8390+Rbcr0, 0);
	dp8390outb(dp8390+Rbcr1, 0);

	dp8390outb(dp8390+Tcr, 0);
	dp8390outb(dp8390+Rcr, Mon);

	/*
	 * Init the ring hardware and software ring pointers.
	 * Can't initialise ethernet address as we may not know
	 * it yet.
	 */
	dp8390ring(ctlr);
	dp8390outb(dp8390+Tpsr, ctlr->card.tstart);

	dp8390outb(dp8390+Isr, 0xFF);
	dp8390outb(dp8390+Imr, Cnte|Ovwe|Txee|Rxee|Ptxe|Prxe);

	/*
	 * Leave the chip initialised,
	 * but in monitor mode.
	 */
	dp8390outb(dp8390+Cr, Page0|RDMAabort|Sta);
}

void
dp8390attach(Ctlr *ctlr)
{
	/*
	 * Enable the chip for transmit/receive.
	 * The init routine leaves the chip in monitor
	 * mode. Clear the missed-packet counter, it
	 * increments while in monitor mode.
	 */
	dp8390outb(ctlr->card.dp8390+Rcr, Ab);
	dp8390inb(ctlr->card.dp8390+Cntr2);
}

void
dp8390mode(Ctlr *ctlr, int on)
{
	/*
	 * Set/reset promiscuous mode.
	 */
	if(on)
		dp8390outb(ctlr->card.dp8390+Rcr, Pro|Ab);
	else
		dp8390outb(ctlr->card.dp8390+Rcr, Ab);
}

void
dp8390setea(Ctlr *ctlr)
dp8390setea(Ether *ether)
{
	ulong dp8390;
	uchar cr;
	int i;

	dp8390 = ctlr->card.dp8390;
	dp8390 = ether->dp8390;
	/*
	 * Set the ethernet address into the chip.
	 * Take care to restore the command register


@@ 268,21 202,21 @@ dp8390setea(Ctlr *ctlr)
	 */
	cr = dp8390inb(dp8390+Cr) & ~Txp;
	dp8390outb(dp8390+Cr, Page1|(~(Ps1|Ps0) & cr));
	for(i = 0; i < sizeof(ctlr->ea); i++)
		dp8390outb(dp8390+Par0+i, ctlr->ea[i]);
	for(i = 0; i < sizeof(ether->ea); i++)
		dp8390outb(dp8390+Par0+i, ether->ea[i]);
	dp8390outb(dp8390+Cr, cr);
}

void
dp8390getea(Ctlr *ctlr)
dp8390getea(Ether *ether)
{
	ulong dp8390;
	uchar cr;
	int i;

	dp8390 = ctlr->card.dp8390;
	dp8390 = ether->dp8390;
	/*
	 * Set the ethernet address into the chip.
	 * Get the ethernet address from the chip.
	 * Take care to restore the command register
	 * afterwards. We don't care about multicast
	 * addresses as we never set the multicast


@@ 290,19 224,19 @@ dp8390getea(Ctlr *ctlr)
	 */
	cr = dp8390inb(dp8390+Cr) & ~Txp;
	dp8390outb(dp8390+Cr, Page1|(~(Ps1|Ps0) & cr));
	for(i = 0; i < sizeof(ctlr->ea); i++)
		ctlr->ea[i] = dp8390inb(dp8390+Par0+i);
	for(i = 0; i < sizeof(ether->ea); i++)
		ether->ea[i] = dp8390inb(dp8390+Par0+i);
	dp8390outb(dp8390+Cr, cr);
}

void*
dp8390read(Ctlr *ctlr, void *to, ulong from, ulong len)
static void*
dp8390read(Ether *ether, void *to, ulong from, ulong len)
{
	ulong dp8390;
	uchar cr;
	int timo;

	dp8390 = ctlr->card.dp8390;
	dp8390 = ether->dp8390;
	/*
	 * Read some data at offset 'from' in the card's memory
	 * using the DP8390 remote DMA facility, and place it at


@@ 315,7 249,7 @@ dp8390read(Ctlr *ctlr, void *to, ulong from, ulong len)
	/*
	 * Set up the remote DMA address and count.
	 */
	if(ctlr->card.bit16)
	if(ether->bit16)
		len = ROUNDUP(len, 2);
	dp8390outb(dp8390+Rbcr0, len & 0xFF);
	dp8390outb(dp8390+Rbcr1, (len>>8) & 0xFF);


@@ 327,10 261,10 @@ dp8390read(Ctlr *ctlr, void *to, ulong from, ulong len)
	 * out of the I/O port.
	 */
	dp8390outb(dp8390+Cr, Page0|RDMAread|Sta);
	if(ctlr->card.bit16)
		inss(ctlr->card.data, to, len/2);
	if(ether->bit16)
		inss(ether->data, to, len/2);
	else
		insb(ctlr->card.data, to, len);
		insb(ether->data, to, len);

	/*
	 * Wait for the remote DMA to complete. The timeout


@@ 347,13 281,13 @@ dp8390read(Ctlr *ctlr, void *to, ulong from, ulong len)
	return to;
}

void*
dp8390write(Ctlr *ctlr, ulong to, void *from, ulong len)
static void*
dp8390write(Ether *ether, ulong to, void *from, ulong len)
{
	ulong dp8390, crda;
	uchar cr;

	dp8390 = ctlr->card.dp8390;
	dp8390 = ether->dp8390;
	/*
	 * Write some data to offset 'to' in the card's memory
	 * using the DP8390 remote DMA facility, reading it at


@@ 363,7 297,7 @@ dp8390write(Ctlr *ctlr, ulong to, void *from, ulong len)
	dp8390outb(dp8390+Cr, Page0|RDMAabort|Sta);
	dp8390outb(dp8390+Isr, Rdc);

	if(ctlr->card.bit16)
	if(ether->bit16)
		len = ROUNDUP(len, 2);

	/*


@@ 371,9 305,9 @@ dp8390write(Ctlr *ctlr, ulong to, void *from, ulong len)
	 * This is straight from the DP8390[12D] datasheet, hence
	 * the initial set up for read.
	 */
	crda = to-1-ctlr->card.bit16;
	dp8390outb(dp8390+Rbcr0, (len+1+ctlr->card.bit16) & 0xFF);
	dp8390outb(dp8390+Rbcr1, ((len+1+ctlr->card.bit16)>>8) & 0xFF);
	crda = to-1-ether->bit16;
	dp8390outb(dp8390+Rbcr0, (len+1+ether->bit16) & 0xFF);
	dp8390outb(dp8390+Rbcr1, ((len+1+ether->bit16)>>8) & 0xFF);
	dp8390outb(dp8390+Rsar0, crda & 0xFF);
	dp8390outb(dp8390+Rsar1, (crda>>8) & 0xFF);
	dp8390outb(dp8390+Cr, Page0|RDMAread|Sta);


@@ 400,10 334,10 @@ dp8390write(Ctlr *ctlr, ulong to, void *from, ulong len)
	/*
	 * Pump the data into the I/O port.
	 */
	if(ctlr->card.bit16)
		outss(ctlr->card.data, from, len/2);
	if(ether->bit16)
		outss(ether->data, from, len/2);
	else
		outsb(ctlr->card.data, from, len);
		outsb(ether->data, from, len);

	/*
	 * Wait for the remote DMA to finish. We'll need


@@ 431,57 365,30 @@ getcurr(ulong dp8390)
}

static void
cldaquiet(ulong dp8390)
receive(Ether *ether)
{
	uchar a, b, c;

	/*
	 * 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 current local DMA registers and, if they are
	 * changing, wait.
	 */
	
	for(;;delay(10)){
		a = dp8390inb(dp8390+Clda0);
		b = dp8390inb(dp8390+Clda0);
		if(a != b)
			continue;
		c = dp8390inb(dp8390+Clda0);
		if(c != b)
			continue;
		break;
	}
}

void
dp8390receive(Ctlr *ctlr)
{
	RingBuf *ring;
	uchar curr, len1, *pkt;
	Hdr hdr;
	ulong dp8390, data, len;
	ushort type;
	Netfile *f, **fp, **ep;

	dp8390 = ctlr->card.dp8390;
	for(curr = getcurr(dp8390); ctlr->card.nxtpkt != curr; curr = getcurr(dp8390)){
		if(strcmp(arch->id, "NCRD.0") == 0)
			cldaquiet(dp8390);

		ctlr->inpackets++;
	dp8390 = ether->dp8390;
	for(curr = getcurr(dp8390); ether->nxtpkt != curr; curr = getcurr(dp8390)){
		ether->inpackets++;

		data = ctlr->card.nxtpkt*Dp8390BufSz;
		(*ctlr->card.read)(ctlr, &hdr, data, sizeof(Hdr));
		data = ether->nxtpkt*Dp8390BufSz;
		(*ether->read)(ctlr, &hdr, data, sizeof(Hdr));

		/*
		 * Don't believe the upper byte count, work it
		 * out from the software next-page pointer and
		 * the current next-page pointer.
		 */
		if(hdr.next > ctlr->card.nxtpkt)
			len1 = hdr.next - ctlr->card.nxtpkt - 1;
		if(hdr.next > ether->nxtpkt)
			len1 = hdr.next - ether->nxtpkt - 1;
		else
			len1 = (ctlr->card.pstop-ctlr->card.nxtpkt) + (hdr.next-ctlr->card.pstart) - 1;
			len1 = (ether->pstop-ether->nxtpkt) + (hdr.next-ether->pstart) - 1;
		if(hdr.len0 > (Dp8390BufSz-sizeof(Hdr)))
			len1--;



@@ 490,52 397,57 @@ dp8390receive(Ctlr *ctlr)
		/*
		 * Chip is badly scrogged, reinitialise the ring.
		 */
		if(hdr.next < ctlr->card.pstart || hdr.next >= ctlr->card.pstop
		if(hdr.next < ether->pstart || hdr.next >= ether->pstop
		  || len < 60 || len > sizeof(Etherpkt)){
			print("H#%2.2ux#%2.2ux#%2.2ux#%2.2ux,%d|",
				hdr.status, hdr.next, hdr.len0, hdr.len1, len);
			dp8390outb(dp8390+Cr, Page0|RDMAabort|Stp);
			dp8390ring(ctlr);
			dp8390ring(ether);
			dp8390outb(dp8390+Cr, Page0|RDMAabort|Sta);
			return;
		}

		/*
		 * If it's a good packet and we have a place to put it,
		 * read it in to the software ring.
		 * If the packet wraps round the hardware ring, read it
		 * in two pieces.
		 * If it's a good packet read it in to the software buffer.
		 * If the packet wraps round the hardware ring, read it in two pieces.
		 */
		ring = &ctlr->rb[ctlr->ri];
		if((hdr.status & (Fo|Fae|Crce|Prxok)) == Prxok && ring->owner == Interface){
			pkt = ring->pkt;
		if((hdr.status & (Fo|Fae|Crce|Prxok)) == Prxok){
			pkt = ether->rpkt;
			data += sizeof(Hdr);
			ring->len = len;

			if((data+len) >= ctlr->card.pstop*Dp8390BufSz){
				ulong count = ctlr->card.pstop*Dp8390BufSz - data;
			if((data+len) >= ether->pstop*Dp8390BufSz){
				ulong count = ether->pstop*Dp8390BufSz - data;

				(*ctlr->card.read)(ctlr, pkt, data, count);
				(*ether->read)(ctlr, pkt, data, count);
				pkt += count;
				data = ctlr->card.pstart*Dp8390BufSz;
				data = ether->pstart*Dp8390BufSz;
				len -= count;
			}
			if(len)
				(*ctlr->card.read)(ctlr, pkt, data, len);
				(*ether->read)(ctlr, pkt, data, len);

			ring->owner = Host;
			ctlr->ri = NEXT(ctlr->ri, ctlr->nrb);
			/*
			 * Copy the packet to whoever wants it.
			 */
			type = (ether->rpkt.type[0]<<8)|ether->rpkt.type[1];
			ep = &ether->f[Ntypes];
			for(fp = ether->f; fp < ep; fp++) {
				f = *fp;
				if(f && (f->type == type || f->type < 0))
					qproduce(f->in, &ether->rpkt, len);
			}
		}

		/*
		 * Finished woth this packet, update the
		 * hardware and software ring pointers.
		 */
		ctlr->card.nxtpkt = hdr.next;
		ether->nxtpkt = hdr.next;

		hdr.next--;
		if(hdr.next < ctlr->card.pstart)
			hdr.next = ctlr->card.pstop-1;
		if(hdr.next < ether->pstart)
			hdr.next = ether->pstop-1;
		dp8390outb(dp8390+Bnry, hdr.next);
	}
}


@@ 544,18 456,18 @@ dp8390receive(Ctlr *ctlr)
 * Initiate a transmission. Must be called splhi().
 */
void
dp8390transmit(Ctlr *ctlr)
dp8390transmit(Ether *ether)
{
	ulong dp8390;
	RingBuf *ring;

	dp8390 = ctlr->card.dp8390;
	ring = &ctlr->tb[ctlr->ti];
	if(ctlr->tbusy == 0 && ring->owner == Interface){
	dp8390 = ether->dp8390;
	ring = &ether->tb[ether->ti];
	if(ether->tbusy == 0 && ring->owner == Interface){

		ctlr->tbusy = 1;
		ether->tbusy = 1;

		(*ctlr->card.write)(ctlr, ctlr->card.tstart*Dp8390BufSz, ring->pkt, ring->len);
		(*ether->write)(ctlr, ether->tstart*Dp8390BufSz, ring->pkt, ring->len);

		dp8390outb(dp8390+Tbcr0, ring->len & 0xFF);
		dp8390outb(dp8390+Tbcr1, (ring->len>>8) & 0xFF);


@@ 563,14 475,14 @@ dp8390transmit(Ctlr *ctlr)
	}
}

void
dp8390overflow(Ctlr *ctlr)
static void
overflow(Ether *ether)
{
	ulong dp8390;
	uchar txp;
	int resend;

	dp8390 = ctlr->card.dp8390;
	dp8390 = ether->dp8390;
	/*
	 * The following procedure is taken from the DP8390[12D] datasheet,
	 * it seems pretty adamant that this is what has to be done.


@@ 587,41 499,22 @@ dp8390overflow(Ctlr *ctlr)

	dp8390outb(dp8390+Tcr, Lb);
	dp8390outb(dp8390+Cr, Page0|RDMAabort|Sta);
	(*ctlr->card.receive)(ctlr);
	(*ether->receive)(ether);
	dp8390outb(dp8390+Isr, Ovw);
	wakeup(&ctlr->rr);
	wakeup(&ether->rr);
	dp8390outb(dp8390+Tcr, 0);

	if(resend)
		dp8390outb(dp8390+Cr, Page0|RDMAabort|Txp|Sta);
}

void
dp8390watch(Ctlr *ctlr)
{
	int s;

	/*
	 * Stub watchdog routine.
	 * Whine if a transmit takes too long.
	 */
	s = splhi();
	if(ctlr->tbusy){
		ctlr->tbusy++;
		if(ctlr->tbusy > 1 && ctlr->debug)
			print("TB%d|", ctlr->tbusy);
	}
	splx(s);
}

void
dp8390intr(Ctlr *ctlr)
static void
interrupt(Ether *ether)
{
	ulong dp8390;
	RingBuf *ring;
	uchar isr, r;

	dp8390 = ctlr->card.dp8390;
	dp8390 = ether->dp8390;
	/*
	 * While there is something of interest,
	 * clear all the interrupts and process.


@@ 630,21 523,18 @@ dp8390intr(Ctlr *ctlr)
	while(isr = dp8390inb(dp8390+Isr)){

		if(isr & Ovw){
			if(ctlr->card.overflow)
				(*ctlr->card.overflow)(ctlr);
			overflow(ether);
			dp8390outb(dp8390+Isr, Ovw);
			ctlr->overflows++;
			ether->overflows++;
		}

		/*
		 * We have received packets.
		 * Take a spin round the ring and
		 * wakeup the kproc.
		 * Take a spin round the ring. and
		 */
		if(isr & (Rxe|Prx)){
			(*ctlr->card.receive)(ctlr);
			receive(ether);
			dp8390outb(dp8390+Isr, Rxe|Prx);
			wakeup(&ctlr->rr);
		}

		/*


@@ 655,30 545,102 @@ dp8390intr(Ctlr *ctlr)
		if(isr & (Txe|Ptx)){
			r = dp8390inb(dp8390+Tsr);
			if(isr & Txe){
				if((r & (Cdh|Fu|Crs|Abt)) && ctlr->debug)
				if((r & (Cdh|Fu|Crs|Abt)) && ether->debug)
					print("Tsr#%2.2ux|", r);
				ctlr->oerrs++;
				ether->oerrs++;
			}

			dp8390outb(dp8390+Isr, Txe|Ptx);

			if(isr & Ptx)
				ctlr->outpackets++;

			ring = &ctlr->tb[ctlr->ti];
			ring->owner = Host;
			ctlr->tbusy = 0;
			ctlr->ti = NEXT(ctlr->ti, ctlr->ntb);
			(*ctlr->card.transmit)(ctlr);
			wakeup(&ctlr->tr);
				ether->outpackets++;
			wakeup(&ether->tr);
		}

		if(isr & Cnt){
			ctlr->frames += dp8390inb(dp8390+Cntr0);
			ctlr->crcs += dp8390inb(dp8390+Cntr1);
			ctlr->buffs += dp8390inb(dp8390+Cntr2);
			ether->frames += dp8390inb(dp8390+Cntr0);
			ether->crcs += dp8390inb(dp8390+Cntr1);
			ether->buffs += dp8390inb(dp8390+Cntr2);
			dp8390outb(dp8390+Isr, Cnt);
		}
	}
	dp8390outb(dp8390+Imr, Cnte|Ovwe|Txee|Rxee|Ptxe|Prxe);
}

static void
promiscuous(Ether *ether, int on)
{
	/*
	 * Set/reset promiscuous mode.
	 */
	if(on)
		dp8390outb(ether->dp8390+Rcr, Pro|Ab);
	else
		dp8390outb(ether->dp8390+Rcr, Ab);
}

void
dp8390attach(Ether *ether)
{
	/*
	 * Enable the chip for transmit/receive.
	 * The init routine leaves the chip in monitor
	 * mode. Clear the missed-packet counter, it
	 * increments while in monitor mode.
	 */
	dp8390outb(ether->dp8390+Rcr, Ab);
	dp8390inb(ether->dp8390+Cntr2);
}

static int
dp8390reset(Ether *ether)
{
	ulong dp8390;

	dp8390 = ether->dp8390;
	/*
	 * This is the initialisation procedure described
	 * as 'mandatory' in the datasheet, with references
	 * to the 3Com503 technical reference manual.
	 */ 
	dp8390disable(ether);
	if(ether->bit16)
		dp8390outb(dp8390+Dcr, Ft4|Ls|Wts);
	else
		dp8390outb(dp8390+Dcr, Ft4|Ls);

	dp8390outb(dp8390+Rbcr0, 0);
	dp8390outb(dp8390+Rbcr1, 0);

	dp8390outb(dp8390+Tcr, 0);
	dp8390outb(dp8390+Rcr, Mon);

	/*
	 * Init the ring hardware and software ring pointers.
	 * Can't initialise ethernet address as we may not know
	 * it yet.
	 */
	dp8390ring(ether);
	dp8390outb(dp8390+Tpsr, ether->tstart);

	dp8390outb(dp8390+Isr, 0xFF);
	dp8390outb(dp8390+Imr, Cnte|Ovwe|Txee|Rxee|Ptxe|Prxe);

	/*
	 * Leave the chip initialised,
	 * but in monitor mode.
	 */
	dp8390outb(dp8390+Cr, Page0|RDMAabort|Sta);

	/*
	 * Set up the software configuration.
	 */
	ether->attach = attach;
	ether->write = write;
	ether->interrupt = interrupt;

	ether->promiscuous = promiscuous;
	ether->arg = ether;

	return 0;
}

M pc/etherif.h => pc/etherif.h +12 -0
@@ 22,6 22,18 @@ struct Ether {
	Netif;
};

typedef struct {
	uchar	bit16;			/* true if a 16 bit interface */
	uchar	ram;			/* true if card has shared memory */

	ulong	dp8390;			/* I/O address of 8390 */
	ulong	data;			/* I/O data port if no shared memory */
	uchar	nxtpkt;			/* software bndry */
	uchar	tstart;			/* 8390 ring addresses */
	uchar	pstart;
	uchar	pstop;
} Dp8390;

#define NEXT(x, l)	(((x)+1)%(l))
#define	HOWMANY(x, y)	(((x)+((y)-1))/(y))
#define ROUNDUP(x, y)	(HOWMANY((x), (y))*(y))

M pc/fns.h => pc/fns.h +1 -1
@@ 27,6 27,7 @@ ulong	fpstatus(void);
ulong	getcr0(void);
ulong	getcr2(void);
char*	getconf(char*);
ulong	getstatus(void);
void	i8042a20(void);
void	i8042reset(void);
void	ident(void);


@@ 74,7 75,6 @@ void	putidt(Segdesc*, int);
void	putcr3(ulong);
void	puttr(ulong);
void	screeninit(void);
void	screenputc(int);
void	screenputs(char*, int);
int	serial(int);
void	setvec(int, void (*)(Ureg*));

M pc/kbd.c => pc/kbd.c +0 -2
@@ 8,7 8,6 @@

#include	<libg.h>
#include	<gnot.h>
#include	"screen.h"

enum {
	Data=		0x60,	/* data port */


@@ 245,7 244,6 @@ kbdinit(void)
	kbdq = qopen(4*1024, 0, 0, 0);

	setvec(Kbdvec, kbdintr);
	bigcursor();

	/* wait for a quiescent controller */
	while((c = inb(Status)) & (Outbusy | Inready))

M pc/l.s => pc/l.s +5 -2
@@ 554,6 554,11 @@ TEXT	splx(SB),$0
	POPFL
	RET

TEXT	getstatus(SB),$0
	PUSHFL
	POPL	AX
	RET

/*
 *  do nothing whatsoever till interrupt happens
 */


@@ 608,7 613,6 @@ TEXT	config(SB),$0
	OUTB
	RET

#ifdef notdef
/*
 *  copy bitmap changes to screen memory for ldepth 0 screen.
 *  reverse the bits since the screen is big-endian


@@ 719,7 723,6 @@ l20:
	MOVB	BX,-1(DI)(CX*1)
	LOOP	l20
	RET
#endif /* notdef */

/*
 * The DP8390 ethernet chip needs some time between

M pc/trap.c => pc/trap.c +7 -0
@@ 234,12 234,19 @@ trap(Ureg *ur)
	int c;
	char buf[ERRLEN];
	Handler *h;
	static int iret_traps;

	v = ur->trap;

	user = (ur->cs&0xffff) == UESEL;
	if(user)
		up->dbgreg = ur;
	else if(ur->pc <= (ulong)end && *(uchar*)ur->pc == 0xCF) {
		if(iret_traps++ > 10)
			panic("iret trap");
		return;
	}
	iret_traps = 0;

	/*
	 *  tell the 8259 that we're done with the

M port/error.h => port/error.h +1 -0
@@ 51,4 51,5 @@ extern char Esoverlap[];	/* segments overlap */
extern char Emouseset[];	/* mouse type already set */
extern char Erecover[];		/* failed to recover fd */
extern char Eshort[];		/* i/o count too small */
extern char Enobitstore[];	/* out of screen memory */
extern char Egreg[];		/* coherency problem */