~kris/9p

9hist

a5cb940b4a5ff0799479ce17613f6aab6b261f93 — David du Colombier 33 years ago e8340e6
Plan 9 from Bell Labs 1992-11-19
4 files changed, 917 insertions(+), 125 deletions(-)

M pc/devconfig.c
M pc/devhard.c
M pc/devvga.c
M pc/l.s
M pc/devconfig.c => pc/devconfig.c +20 -32
@@ 15,7 15,6 @@
 *  Driver for various VGA cards
 */

char	monitor[NAMELEN];	/* monitor name and type */
char	vgacard[NAMELEN];	/* vga card type */
struct screeninfo {
	int	maxx, maxy;	/* current bits per screen */


@@ 25,20 24,16 @@ struct screeninfo {

enum {
	Qdir=		0,
	Qvgamonitor=	1,
	Qvgasize=	2,
	Qvgatype=	3,
	Qvgaport=	4,
	Qvgamem=	5,
	Nvga=		6,
	Qvgasize=	1,
	Qvgatype=	2,
	Qvgaport=	3,
	Nvga=		4,
};

Dirtab vgadir[]={
	"vgamonitor",	{Qvgamonitor},	0,		0666,
	"vgatype",	{Qvgatype},	0,		0666,
	"vgasize",	{Qvgasize},	0,		0666,
	"vgaport",	{Qvgaport},	0,		0666,
	"vgamem",	{Qvgamem},	0,		0666,
};

/* a routine from ../port/devcons.c */


@@ 50,7 45,6 @@ configsetup(void) {

void
configreset(void) {
	strcpy(monitor, "generic");
	strcpy(vgacard, "generic");
	screeninfo.maxx = 640;
	screeninfo.maxy = 480;


@@ 109,34 103,20 @@ configclose(Chan *c)
long
configread(Chan *c, void *buf, long n, ulong offset)
{
	char obuf[60];
	int port;
	uchar *cp = buf;

	switch(c->qid.path&~CHDIR){
	case Qdir:
		return devdirread(c, buf, n, vgadir, Nvga, devgen);
	case Qvgamonitor:
		return readstr(offset, buf, n, monitor);
	case Qvgatype:
		return readstr(offset, buf, n, vgacard);
	case Qvgasize:
		sprint(obuf, "%d %d",
			gscreen.r.max.x, gscreen.r.max.y);
		return readstr(offset, buf, n, obuf);
	case Qvgaport:
		if (offset + n >= 0x8000)
			error(Ebadarg);
		for (port=offset; port<offset+n; port++)
			*cp++ = inb(port);
		return n;
	case Qvgamem:
		if (offset > 0x10000)
			return 0;
		if (offset + n > 0x10000)
			n = 0x10000 - offset;
		memmove(cp, (void *)(SCREENMEM+offset), n);
		return n;
	}
	error(Eperm);
	return 0;


@@ 151,8 131,6 @@ configwrite(Chan *c, void *buf, long n, ulong offset)
	switch(c->qid.path&~CHDIR){
	case Qdir:
		error(Eperm);
	case Qvgamonitor:
		error(Eperm);
	case Qvgatype:
		error(Eperm);
	case Qvgasize:


@@ 169,7 147,22 @@ configwrite(Chan *c, void *buf, long n, ulong offset)
		maxy = strtoul(cp, &cp, 0);
		if(*cp!=0)
			cp++;
		ldepth = strtoul(cp, &cp, 0);
		switch(strtoul(cp, &cp, 0)){
		case 1:
			ldepth = 0;
			break;
		case 2:
			ldepth = 1;
			break;
		case 4:
			ldepth = 2;
			break;
		case 8:
			ldepth = 3;
			break;
		default:
			ldepth = -1;
		}
		if(maxx == 0 || maxy == 0
		|| maxx > 1280 || maxy > 1024
		|| ldepth > 3 || ldepth < 0)


@@ 184,11 177,6 @@ configwrite(Chan *c, void *buf, long n, ulong offset)
			outb(port, *cp++);
		}
		return n;
	case Qvgamem:
		if (offset + n > 0x10000)
			error(Ebadarg);
		memmove((void *)(SCREENMEM+offset), buf, n);
		return n;
	}
	error(Eperm);
	return 0;

M pc/devhard.c => pc/devhard.c +10 -4
@@ 77,6 77,8 @@ struct Repl
 */
struct Drive
{
	QLock;

	Controller *cp;
	int	drive;
	int	confused;	/* needs to be recalibrated (or worse) */


@@ 214,8 216,10 @@ hardattach(char *spec)
	for(dp = hard; dp < &hard[conf.nhard]; dp++){
		if(waserror()){
			dp->online = 0;
			qunlock(dp);
			continue;
		}
		qlock(dp);
		if(!dp->online){
			hardparams(dp);
			dp->online = 1;


@@ 226,6 230,7 @@ hardattach(char *spec)
		 *  read Plan 9 partition table
		 */
		hardpart(dp);
		qunlock(dp);
		poperror();
	}
	return devattach('w', spec);


@@ 561,9 566,9 @@ hardsetbuf(Drive *dp, int on)

	sleep(&cp->r, cmddone, cp);

	if(cp->status & Serr)
/*	if(cp->status & Serr)
		DPRINT("hd%d setbuf err: status %lux, err %lux\n",
			dp-hard, cp->status, cp->error);
			dp-hard, cp->status, cp->error);/**/

	poperror();
	qunlock(cp);


@@ 659,6 664,7 @@ hardident(Drive *dp)
	dp->heads = ip->lheads;
	dp->sectors = ip->ls2t;
	dp->cap = dp->bytes * dp->cyl * dp->heads * dp->sectors;
	cp->lastcmd = cp->cmd;
	cp->cmd = 0;
	cp->buf = 0;
	free(buf);


@@ 982,8 988,8 @@ hardintr(Ureg *ur)
		cp->cmd = 0;
		break;
	default:
		print("weird disk interrupt, cmd=%.2ux, status=%.2ux\n",
			cp->cmd, cp->status);
		print("weird disk interrupt, cmd=%.2ux, lastcmd= %.2ux status=%.2ux\n",
			cp->cmd, cp->lastcmd, cp->status);
		break;
	}
}

M pc/devvga.c => pc/devvga.c +877 -84
@@ 8,54 8,148 @@

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

#define	MINX	8

struct{
	Point	pos;
	int	bwid;
}out;

/* 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;
static	GBitmap	vgascreen;
static	ulong colormap[256][3];
static	int cga = 1;		/* true if in cga mode */

/*
 *  Driver for various VGA cards
 *  screen dimensions
 */
#define MAXX	640
#define MAXY	480

char	monitor[NAMELEN];	/* monitor name and type */
char	vgacard[NAMELEN];	/* vga card type */
struct screeninfo {
	int	maxx, maxy;	/* current bits per screen */
	int	packed;		/* 0=planar, 1=packed */
	int	interlaced;	/* != 0 if interlaced */
} screeninfo;
/*
 *  'soft' screen bitmap
 */

enum {
	Qdir=		0,
	Qvgamonitor=	1,
	Qvgasize=	2,
	Qvgatype=	3,
	Qvgaport=	4,
	Qvgamem=	5,
	Nvga=		5,
typedef struct VGAmode	VGAmode;
struct VGAmode
{
	uchar	general[2];
	uchar	sequencer[5];
	uchar	crt[0x19];
	uchar	graphics[9];
	uchar	attribute[0x15];
};

/*
 *  640x480 display, 1, 2, or 4 bit color.
 */
VGAmode mode12 = 
{
	/* general */
	0xe7, 0x00,
	/* sequence */
	0x03, 0x01, 0x0f, 0x00, 0x06,
	/* crt */
	0x65, 0x4f, 0x50, 0x88, 0x55, 0x9a, 0x09, 0x3e,
	0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0xe8, 0x8b, 0xdf, 0x28, 0x00, 0xe7, 0x04, 0xe3,
	0xff,
	/* graphics */
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x0f,
	0xff,
	/* attribute */
	0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
	0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
	0x01, 0x10, 0x0f, 0x00, 0x00,
};

/*
 *  320x200 display, 8 bit color.
 */
VGAmode mode13 = 
{
	/* general */
	0x63, 0x00,
	/* sequence */
	0x03, 0x01, 0x0f, 0x00, 0x0e,
	/* crt */
	0x5f, 0x4f, 0x50, 0x82, 0x54, 0x80, 0xbf, 0x1f,
	0x00, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28,
	0x9c, 0x8e, 0x8f, 0x28, 0x40, 0x96, 0xb9, 0xa3,
	0xff,
	/* graphics */
	0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0f,
	0xff,
	/* attribute */
	0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
	0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
	0x41, 0x10, 0x0f, 0x00, 0x00,
};

static	Rectangle mbb;
static	Rectangle NULLMBB = {10000, 10000, -10000, -10000};
static	void nopage(int), tsengpage(int);;

/*
 *  definitions of known cards
 */
typedef struct Vgacard	Vgacard;
struct Vgacard
{
	char	*name;
	void	(*setpage)(int);
};

enum
{
	Tseng,		/* tseng labs te4000 */
	Generic,
};

Vgacard vgacards[] =
{
[Tseng]		{ "tseng", tsengpage, },
[Generic]	{ "generic", nopage, },
		{ 0, 0, },
};

Vgacard	*vgacard;	/* current vga card */

/*
 *  vga device directory
 */
enum
{
	Qdir=		0,
	Qvgasize=	1,
	Qvgatype=	2,
	Qvgaport=	3,
	Nvga=		4,
};
Dirtab vgadir[]={
	"vgamonitor",	{Qvgamonitor},	0,		0666,
	"vgatype",	{Qvgatype},	0,		0666,
	"vgasize",	{Qvgasize},	0,		0666,
	"vgatype",	{Qvgatype},	0,		0666,
	"vgaport",	{Qvgaport},	0,		0666,
	"vgamem",	{Qvgamem},	0,		0666,
};

/* a routine from ../port/devcons.c */
extern	int readstr(ulong, char *, ulong, char *);

void
vgasetup(void) {
}

void
vgareset(void) {
	strcpy(monitor, "generic");
	strcpy(vgacard, "generic");
	screeninfo.maxx = 640;
	screeninfo.maxy = 480;
	screeninfo.packed = 0;
	screeninfo.interlaced = 0;
vgareset(void)
{
	vgacard = &vgacards[Generic];
}

void


@@ 84,24 178,12 @@ vgawalk(Chan *c, char *name)
void
vgastat(Chan *c, char *dp)
{
	switch(c->qid.path){
	default:
		devstat(c, dp, vgadir, Nvga, devgen);
		break;
	}
	devstat(c, dp, vgadir, Nvga, devgen);
}

Chan*
vgaopen(Chan *c, int omode)
{
	switch(c->qid.path){
	case Qvgamonitor:
	case Qvgatype:
	case Qvgasize:
	case Qvgaport:
	case Qvgamem:
		break;
	}
	return devopen(c, omode, vgadir, Nvga, devgen);
}



@@ 121,84 203,98 @@ vgaclose(Chan *c)
long
vgaread(Chan *c, void *buf, long n, ulong offset)
{
	char obuf[60];
	int port;
	uchar *cp = buf;
	void *outfunc(int, int);
	char cbuf[64];

	switch(c->qid.path&~CHDIR){
	case Qdir:
		return devdirread(c, buf, n, vgadir, Nvga, devgen);
	case Qvgamonitor:
		return readstr(offset, buf, n, monitor);
	case Qvgatype:
		return readstr(offset, buf, n, vgacard);
	case Qvgasize:
		sprint(obuf, "%d %d",
			gscreen.r.max.x, gscreen.r.max.y);
		return readstr(offset, buf, n, obuf);
		sprint(cbuf, "%dx%dx%d", gscreen.r.max.x, gscreen.r.max.y,
			1<<gscreen.ldepth);
		return readstr(offset, buf, n, cbuf);
	case Qvgatype:
		return readstr(offset, buf, n, vgacard->name);
	case Qvgaport:
		if (offset + n >= 0x8000)
		if (offset + n >= 0x8000 || offset < 0x300)
			error(Ebadarg);
		for (port=offset; port<offset+n; port++)
			*cp++ = inb(port);
		return n;
	case Qvgamem:
		if (offset > 0x10000)
			return 0;
		if (offset + n > 0x10000)
			n = 0x10000 - offset;
		memmove(cp, (void *)(SCREENMEM+offset), n);
		return n;
	}
	error(Eperm);
	return 0;
}

long
vgawrite(Chan *c, void *buf, long n, ulong offset)
{
	char cbuf[20], *cp;
	int port, maxx, maxy;
	char cbuf[64], *cp;
	Vgacard *vp;
	int port, maxx, maxy, ldepth;

	switch(c->qid.path&~CHDIR){
	case Qdir:
		error(Eperm);
	case Qvgamonitor:
		if(offset != 0)
			error(Ebadarg);
		error(Eperm);
	case Qvgatype:
		if(offset != 0)
		if(offset != 0 || n >= sizeof(cbuf) || n < 1)
			error(Ebadarg);
		error(Eperm);
		memmove(cbuf, buf, n);
		cbuf[n] = 0;
		if(cp = strchr(cbuf, '\n'))
			*cp = 0;
		for(vp = vgacards; vp->name; vp++)
			if(strcmp(cbuf, vp->name) == 0){
				vgacard = vp;
				return n;
			}
		error(Ebadarg);
	case Qvgasize:
		if(offset != 0)
		if(offset != 0 || n >= sizeof(cbuf))
			error(Ebadarg);
		if(n >= sizeof(cbuf))
			n = sizeof(cbuf) - 1;
		memmove(cbuf, buf, n);
		cbuf[n] = 0;
		cp = cbuf;
		maxx = strtoul(cp, &cp, 0);
		if(*cp!=0)
			cp++;
		maxy = strtoul(cp, &cp, 0);
		if (maxx == 0 || maxy == 0 ||
		    maxx > 1280 || maxy > 1024)
		if(*cp!=0)
			cp++;
		switch(strtoul(cp, &cp, 0)){
		case 1:
			ldepth = 0;
			break;
		case 2:
			ldepth = 1;
			break;
		case 4:
			ldepth = 2;
			break;
		case 8:
			ldepth = 3;
			break;
		default:
			ldepth = -1;
		}
		if(maxx == 0 || maxy == 0
		|| maxx > 1280 || maxy > 1024
		|| ldepth > 3 || ldepth < 0)
			error(Ebadarg);
		setscreen(maxx, maxy, 1);
		setscreen(maxx, maxy, ldepth);
		return n;
	case Qvgaport:
		cp = buf;
		if (offset + n >= 0x8000)
		if (offset + n >= 0x8000 || offset < 0x300)
			error(Ebadarg);
		for (port=offset; port<offset+n; port++) {
			outb(port, *cp++);
		}
		return n;
	case Qvgamem:
		if (offset + n > 0x10000)
			error(Ebadarg);
		memmove((void *)(SCREENMEM+offset), buf, n);
		return n;
	}
	error(Eperm);
	return 0;
}

void


@@ 214,3 310,700 @@ vgawstat(Chan *c, char *dp)
	USED(c, dp);
	error(Eperm);
}

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

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

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

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

void
setscreen(int maxx, int maxy, int ldepth)
{
	int len, vgamaxy, width, i, x;
	uchar *p;

	if(ldepth == 3)
		setmode(&mode13);
	else
		setmode(&mode12);

	/* allocate a new soft bitmap area */
	width = (maxx*(1<<ldepth))/32;
	len = width * BY2WD * maxy;
	p = xalloc(len);
	if(p == 0)
		panic("can't alloc screen bitmap");
	mbb = NULLMBB;

	/*
	 *  zero hard screen and setup a bitmap for the new size
	 */
	if(ldepth == 3)
		vgascreen.ldepth = 3;
	else
		vgascreen.ldepth = 0;
	vgascreen.width = (maxx*(1<<vgascreen.ldepth))/32;
	if(maxy > (64*1024)/(vgascreen.width*BY2WD))
		vgamaxy = (64*1024)/(vgascreen.width*BY2WD);
	else
		vgamaxy = maxy;
	vgascreen.base = (void*)SCREENMEM;
	vgascreen.r.min = Pt(0, 0);
	vgascreen.r.max = Pt(maxx, vgamaxy);
	vgascreen.clipr = vgascreen.r;
	memset(vgascreen.base, 0xff, vgascreen.width * BY2WD * vgamaxy);

	/*
	 *  setup new soft screen, free memory for old screen
	 */
	if(gscreen.base)
		xfree(gscreen.base);
	gscreen.ldepth = ldepth;
	gscreen.width = width;
	gscreen.r.min = Pt(0, 0);
	gscreen.r.max = Pt(maxx, maxy);
	gscreen.clipr = gscreen.r;
	gscreen.base = (ulong*)p;
	memset(gscreen.base, 0xff, len);

	/*
	 *  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){
	case 3:
		for(i = 0; i < 256; i++)
			setcolor(i, x3to32(i>>5), x3to32(i>>2), x3to32(i<<1));
		break;
	case 2:
	case 1:
	case 0:
		gscreen.ldepth = 3;
		for(i = 0; i < 16; i++){
			x = x6to32((i*63)/15);
			setcolor(i, x, x, x);
		}
		gscreen.ldepth = ldepth;
		break;
	}
	cga = 0;
}

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

	/*
	 *  arrow is defined as a big endian
	 */
	pixreverse(arrow.set, 2*16, 0);
	pixreverse(arrow.clr, 2*16, 0);

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

	cga = 1;
	crout(0x0a, 0xff);		/* turn off cursor */
	memset(CGASCREEN, 0, CGAWIDTH*CGAHEIGHT);
}

/*
 *  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;
	if (Dy(mbb) > 32 || Dx(mbb) > 32)
		mousescreenupdate();
}

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);
}
static void
tsengpage(int page)
{
	outb(0x3cd, (page<<4)|page);
}

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

	r = mbb;
	mbb = NULLMBB;

	if(Dy(r) < 0)
		return;

	if(r.min.x < 0)
		r.min.x = 0;
	if(r.min.y < 0)
		r.min.y = 0;
	if(r.max.x > gscreen.r.max.x)
		r.max.x = gscreen.r.max.x;
	if(r.max.y > gscreen.r.max.y)
		r.max.y = gscreen.r.max.y;

	incs = gscreen.width * BY2WD;
	inch = vgascreen.width * BY2WD;

	switch(gscreen.ldepth){
	case 0:
		r.min.x &= ~15;		/* 16 bit allignment for l0update() */
		f = l0update;
		len = (r.max.x + 7)/8 - r.min.x/8;
		if(len & 1)
			len++;		/* 16 bit allignment for l0update() */
		break;
	case 1:
		r.min.x &= ~15;		/* 16 bit allignment for l1update() */
		f = l1update;
		len = (r.max.x + 7)/8 - r.min.x/8;
		if(len & 1)
			len++;		/* 16 bit allignment for l1update() */
		break;
	case 2:
		f = l2update;
		len = (r.max.x + 7)/8 - r.min.x/8;
		break;
	case 3:
		f = memmove;
		len = r.max.x - r.min.x;
		break;
	default:
		return;
	}
	if(len < 1)
		return;

	off = r.min.y * vgascreen.width * BY2WD + (r.min.x>>(3 - vgascreen.ldepth));
	page = off>>16;
	off &= (1<<16)-1;
	hp = ((uchar*)vgascreen.base) + off;
	off = r.min.y * gscreen.width * BY2WD + (r.min.x>>(3 - gscreen.ldepth));
	sp = ((uchar*)gscreen.base) + off;

	edisp = ((uchar*)vgascreen.base) + 64*1024;
	vgacard->setpage(page);
	for(y = r.min.y; y < r.max.y; y++){
		if(hp + inch < edisp){
			f(hp, sp, len);
			sp += incs;
			hp += inch;
		} else {
			off = edisp - hp;
			if(off <= len){
				if(off > 0)
					f(hp, sp, off);
				vgacard->setpage(++page);
				if(len - off > 0)
					f(vgascreen.base, sp+off, len - off);
			} else {
				f(hp, sp, len);
				vgacard->setpage(++page);
			}
			sp += incs;
			hp += inch - 64*1024;
		}
	}
}

void
screenupdate(void)
{
	lock(&vgalock);
	vgaupdate();
	unlock(&vgalock);
}

void
mousescreenupdate(void)
{
	if(canlock(&vgalock)){
		vgaupdate();
		unlock(&vgalock);
	}
}

static void
cgascreenputc(int c)
{
	int i;
	static int color;
	static int pos;

	if(c == '\n'){
		pos = pos/CGAWIDTH;
		pos = (pos+1)*CGAWIDTH;
	} else if(c == '\t'){
		i = 8 - ((pos/2)&7);
		while(i-->0)
			cgascreenputc(' ');
	} else if(c == '\b'){
		if(pos >= 2)
			pos -= 2;
		cgascreenputc(' ');
		pos -= 2;
	} else {
		CGASCREEN[pos++] = c;
		CGASCREEN[pos++] = 2;	/* green on black */
	}
	if(pos >= CGAWIDTH*CGAHEIGHT){
		memmove(CGASCREEN, &CGASCREEN[CGAWIDTH], CGAWIDTH*(CGAHEIGHT-1));
		memset(&CGASCREEN[CGAWIDTH*(CGAHEIGHT-1)], 0, CGAWIDTH);
		pos = CGAWIDTH*(CGAHEIGHT-1);
	}
}

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

void
screenputnl(void)
{
	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();
}

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

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

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

int
screenbits(void)
{
	return 1<<gscreen.ldepth;	/* bits per pixel */
}

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

int
setcolor(ulong p, ulong r, ulong g, ulong b)
{
	p &= (1<<(1<<gscreen.ldepth))-1;
	lock(&vgalock);
	colormap[p][0] = r;
	colormap[p][1] = g;
	colormap[p][2] = b;
	outb(CMWX, p);
	outb(CM, r>>(32-6));
	outb(CM, g>>(32-6));
	outb(CM, b>>(32-6));
	unlock(&vgalock);
	return ~0;
}

int
hwcursset(uchar *s, uchar *c, int ox, int oy)
{
	USED(s, c, ox, oy);
	return 0;
}

int
hwcursmove(int x, int y)
{
	USED(x, y);
	return 0;
}

void
mouseclock(void)
{
	spllo();	/* so we don't cause lost chars on the uart */
	mouseupdate(1);
}

/*
 *  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
 *  2 big-endian ldepth 0 bitmaps used for the VGA bit planes.
 *
 *	if the bits in uchar x are labeled
 *		76543210
 *	then l1revsep[x] yields a ushort with bits
 *		________1357________0246
 *	where _ represents a bit whose value is 0.
 *
 *  This table is used by l1update() in l.s.  l1update is implemented
 *  in assembler for speed.
 *
 */
ulong l1revsep[] = {
 0x00000, 0x00008, 0x80000, 0x80008, 0x00004, 0x0000c, 0x80004, 0x8000c,
 0x40000, 0x40008, 0xc0000, 0xc0008, 0x40004, 0x4000c, 0xc0004, 0xc000c,
 0x00002, 0x0000a, 0x80002, 0x8000a, 0x00006, 0x0000e, 0x80006, 0x8000e,
 0x40002, 0x4000a, 0xc0002, 0xc000a, 0x40006, 0x4000e, 0xc0006, 0xc000e,
 0x20000, 0x20008, 0xa0000, 0xa0008, 0x20004, 0x2000c, 0xa0004, 0xa000c,
 0x60000, 0x60008, 0xe0000, 0xe0008, 0x60004, 0x6000c, 0xe0004, 0xe000c,
 0x20002, 0x2000a, 0xa0002, 0xa000a, 0x20006, 0x2000e, 0xa0006, 0xa000e,
 0x60002, 0x6000a, 0xe0002, 0xe000a, 0x60006, 0x6000e, 0xe0006, 0xe000e,
 0x00001, 0x00009, 0x80001, 0x80009, 0x00005, 0x0000d, 0x80005, 0x8000d,
 0x40001, 0x40009, 0xc0001, 0xc0009, 0x40005, 0x4000d, 0xc0005, 0xc000d,
 0x00003, 0x0000b, 0x80003, 0x8000b, 0x00007, 0x0000f, 0x80007, 0x8000f,
 0x40003, 0x4000b, 0xc0003, 0xc000b, 0x40007, 0x4000f, 0xc0007, 0xc000f,
 0x20001, 0x20009, 0xa0001, 0xa0009, 0x20005, 0x2000d, 0xa0005, 0xa000d,
 0x60001, 0x60009, 0xe0001, 0xe0009, 0x60005, 0x6000d, 0xe0005, 0xe000d,
 0x20003, 0x2000b, 0xa0003, 0xa000b, 0x20007, 0x2000f, 0xa0007, 0xa000f,
 0x60003, 0x6000b, 0xe0003, 0xe000b, 0x60007, 0x6000f, 0xe0007, 0xe000f,
 0x10000, 0x10008, 0x90000, 0x90008, 0x10004, 0x1000c, 0x90004, 0x9000c,
 0x50000, 0x50008, 0xd0000, 0xd0008, 0x50004, 0x5000c, 0xd0004, 0xd000c,
 0x10002, 0x1000a, 0x90002, 0x9000a, 0x10006, 0x1000e, 0x90006, 0x9000e,
 0x50002, 0x5000a, 0xd0002, 0xd000a, 0x50006, 0x5000e, 0xd0006, 0xd000e,
 0x30000, 0x30008, 0xb0000, 0xb0008, 0x30004, 0x3000c, 0xb0004, 0xb000c,
 0x70000, 0x70008, 0xf0000, 0xf0008, 0x70004, 0x7000c, 0xf0004, 0xf000c,
 0x30002, 0x3000a, 0xb0002, 0xb000a, 0x30006, 0x3000e, 0xb0006, 0xb000e,
 0x70002, 0x7000a, 0xf0002, 0xf000a, 0x70006, 0x7000e, 0xf0006, 0xf000e,
 0x10001, 0x10009, 0x90001, 0x90009, 0x10005, 0x1000d, 0x90005, 0x9000d,
 0x50001, 0x50009, 0xd0001, 0xd0009, 0x50005, 0x5000d, 0xd0005, 0xd000d,
 0x10003, 0x1000b, 0x90003, 0x9000b, 0x10007, 0x1000f, 0x90007, 0x9000f,
 0x50003, 0x5000b, 0xd0003, 0xd000b, 0x50007, 0x5000f, 0xd0007, 0xd000f,
 0x30001, 0x30009, 0xb0001, 0xb0009, 0x30005, 0x3000d, 0xb0005, 0xb000d,
 0x70001, 0x70009, 0xf0001, 0xf0009, 0x70005, 0x7000d, 0xf0005, 0xf000d,
 0x30003, 0x3000b, 0xb0003, 0xb000b, 0x30007, 0x3000f, 0xb0007, 0xb000f,
 0x70003, 0x7000b, 0xf0003, 0xf000b, 0x70007, 0x7000f, 0xf0007, 0xf000f,
};

/*
 *  Table for separating and reversing bits in a ldepth 2 bitmap.
 *  This aids in coverting a little endian ldepth 1 bitmap into the
 *  4 big-endian ldepth 0 bitmaps used for the VGA bit planes.
 *
 *	if the bits in uchar x are labeled
 *		76543210
 *	then l1revsep[x] yields a ushort with bits
 *		______37______26______15______04
 *	where _ represents a bit whose value is 0.
 *
 *  This table is used by l2update() in l.s.  l2update is implemented
 *  in assembler for speed.
 *
 */
ulong l2revsep[] = {
 0x0000000, 0x0000002, 0x0000200, 0x0000202, 0x0020000, 0x0020002, 0x0020200, 0x0020202,
 0x2000000, 0x2000002, 0x2000200, 0x2000202, 0x2020000, 0x2020002, 0x2020200, 0x2020202,
 0x0000001, 0x0000003, 0x0000201, 0x0000203, 0x0020001, 0x0020003, 0x0020201, 0x0020203,
 0x2000001, 0x2000003, 0x2000201, 0x2000203, 0x2020001, 0x2020003, 0x2020201, 0x2020203,
 0x0000100, 0x0000102, 0x0000300, 0x0000302, 0x0020100, 0x0020102, 0x0020300, 0x0020302,
 0x2000100, 0x2000102, 0x2000300, 0x2000302, 0x2020100, 0x2020102, 0x2020300, 0x2020302,
 0x0000101, 0x0000103, 0x0000301, 0x0000303, 0x0020101, 0x0020103, 0x0020301, 0x0020303,
 0x2000101, 0x2000103, 0x2000301, 0x2000303, 0x2020101, 0x2020103, 0x2020301, 0x2020303,
 0x0010000, 0x0010002, 0x0010200, 0x0010202, 0x0030000, 0x0030002, 0x0030200, 0x0030202,
 0x2010000, 0x2010002, 0x2010200, 0x2010202, 0x2030000, 0x2030002, 0x2030200, 0x2030202,
 0x0010001, 0x0010003, 0x0010201, 0x0010203, 0x0030001, 0x0030003, 0x0030201, 0x0030203,
 0x2010001, 0x2010003, 0x2010201, 0x2010203, 0x2030001, 0x2030003, 0x2030201, 0x2030203,
 0x0010100, 0x0010102, 0x0010300, 0x0010302, 0x0030100, 0x0030102, 0x0030300, 0x0030302,
 0x2010100, 0x2010102, 0x2010300, 0x2010302, 0x2030100, 0x2030102, 0x2030300, 0x2030302,
 0x0010101, 0x0010103, 0x0010301, 0x0010303, 0x0030101, 0x0030103, 0x0030301, 0x0030303,
 0x2010101, 0x2010103, 0x2010301, 0x2010303, 0x2030101, 0x2030103, 0x2030301, 0x2030303,
 0x1000000, 0x1000002, 0x1000200, 0x1000202, 0x1020000, 0x1020002, 0x1020200, 0x1020202,
 0x3000000, 0x3000002, 0x3000200, 0x3000202, 0x3020000, 0x3020002, 0x3020200, 0x3020202,
 0x1000001, 0x1000003, 0x1000201, 0x1000203, 0x1020001, 0x1020003, 0x1020201, 0x1020203,
 0x3000001, 0x3000003, 0x3000201, 0x3000203, 0x3020001, 0x3020003, 0x3020201, 0x3020203,
 0x1000100, 0x1000102, 0x1000300, 0x1000302, 0x1020100, 0x1020102, 0x1020300, 0x1020302,
 0x3000100, 0x3000102, 0x3000300, 0x3000302, 0x3020100, 0x3020102, 0x3020300, 0x3020302,
 0x1000101, 0x1000103, 0x1000301, 0x1000303, 0x1020101, 0x1020103, 0x1020301, 0x1020303,
 0x3000101, 0x3000103, 0x3000301, 0x3000303, 0x3020101, 0x3020103, 0x3020301, 0x3020303,
 0x1010000, 0x1010002, 0x1010200, 0x1010202, 0x1030000, 0x1030002, 0x1030200, 0x1030202,
 0x3010000, 0x3010002, 0x3010200, 0x3010202, 0x3030000, 0x3030002, 0x3030200, 0x3030202,
 0x1010001, 0x1010003, 0x1010201, 0x1010203, 0x1030001, 0x1030003, 0x1030201, 0x1030203,
 0x3010001, 0x3010003, 0x3010201, 0x3010203, 0x3030001, 0x3030003, 0x3030201, 0x3030203,
 0x1010100, 0x1010102, 0x1010300, 0x1010302, 0x1030100, 0x1030102, 0x1030300, 0x1030302,
 0x3010100, 0x3010102, 0x3010300, 0x3010302, 0x3030100, 0x3030102, 0x3030300, 0x3030302,
 0x1010101, 0x1010103, 0x1010301, 0x1010303, 0x1030101, 0x1030103, 0x1030301, 0x1030303,
 0x3010101, 0x3010103, 0x3010301, 0x3010303, 0x3030101, 0x3030103, 0x3030301, 0x3030303,
};

M pc/l.s => pc/l.s +10 -5
@@ 635,19 635,24 @@ TEXT	config(SB),$0
	RET

/*
 *  copy bitmap changes to screen memory for ldepth 0 screen
 *  copy bitmap changes to screen memory for ldepth 0 screen.
 *  reverse the bits since the screen is big-endian
 *  and the bitmaps are little.
 */
TEXT	l0update(SB),$0
	XORL	AX,AX
	MOVL	len+8(FP),CX
	SHRL	$1,CX
	MOVL	from+4(FP),SI
	MOVL	to+0(FP),DI
	XORL	AX,AX
l00:
	MOVB	-1(SI)(CX*1),AL
	MOVB	revtab0(SB)(AX*1),AL
	MOVB	AL,-1(DI)(CX*1)
	MOVW	-2(SI)(CX*2),DX
	MOVB	DH,AL
	MOVB	revtab0(SB)(AX*1),BX
	SHLL	$8,BX
	MOVB	DL,AL
	ORB	revtab0(SB)(AX*1),BX
	MOVW	BX,-2(DI)(CX*2)
	LOOP	l00
	RET