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

1995/0508/pc/devvga.c (diff list | history)

pc/devvga.c on 1992/0527
1992/0527    
#include	"u.h" 
#include	"../port/lib.h" 
#include	"mem.h" 
#include	"dat.h" 
#include	"fns.h" 
#include	"io.h" 
#include	"../port/error.h" 
 
1992/0603    
#include	<libg.h> 
1994/0414    
#include	"screen.h" 
1994/0624    
#include	"vga.h" 
1992/0527    
 
1993/1116    
enum 
{ 
1995/0406    
	/* default footprint is 64k */ 
1994/0412    
	Footshift=	16, 
	Footprint=	1<<Footshift, 
 
1995/0406    
	/*  CGA screen dimensions */ 
	CGAWIDTH=	160, 
	CGAHEIGHT=	24, 
};  
/* 
 *  screen memory addresses 
 */ 
#define SCREENMEM	(0xA0000 | KZERO) 
#define CGASCREEN	((uchar*)(0xB8000 | KZERO)) 
 
static	ulong	screenmem = SCREENMEM; 
static	int	footprint = Footprint; 
static	int	footshift = Footshift; 
static	int	screendisabled; 
 
1992/1119    
/* imported */ 
1994/0413    
extern	Subfont defont0; 
1995/0126    
extern Cursor curs;			/* barf */ 
1992/1119    
 
/* exported */ 
1994/0413    
Bitmap	gscreen; 
1994/0810    
Lock palettelock;			/* access to DAC registers */ 
Cursor curcursor;			/* current cursor */ 
1992/1119    
 
1993/1116    
/* vga screen */ 
static	Lock	screenlock; 
1995/0126    
static	ulong	colormap[Pcolours][3]; 
1992/1119    
 
1993/1116    
/* cga screen */ 
static	int	cga = 1;		/* true if in cga mode */ 
 
/* system window */ 
static	Rectangle window; 
static	int	h, w; 
1994/0413    
static	Point	curpos; 
1993/1116    
 
1995/0126    
static void nopage(int); 
1992/1119    
 
1995/0126    
static Vgac vga = { 
	"vga", 
	nopage, 
1993/1116    
 
1994/0624    
	0, 
}; 
 
1995/0126    
static Vgac *vgactlr = &vga;			/* available VGA ctlrs */ 
1995/0204    
static Vgac *vgac = &vga;			/* current VGA ctlr */ 
1995/0126    
static Hwgc *hwgctlr;				/* available HWGC's */ 
Hwgc *hwgc;					/* current HWGC */ 
 
1994/0930    
static char interlaced[2]; 
1994/0624    
 
1994/0415    
/* 
 *  work areas for bitblting screen characters, scrolling, and cursor redraw 
 */ 
Bitmap chwork; 
Bitmap scrollwork; 
Bitmap cursorwork; 
 
1993/1116    
/* predefined for the stupid compiler */ 
static void	setscreen(int, int, int); 
static void	cgascreenputc(int); 
static void	cgascreenputs(char*, int); 
static void	screenputc(char*); 
static void	scroll(void); 
1994/0415    
static void	workinit(Bitmap*, int, int); 
1994/0416    
extern void	screenload(Rectangle, uchar*, int, int, int); 
extern void	screenunload(Rectangle, uchar*, int, int, int); 
static void	cursorlock(Rectangle); 
static void	cursorunlock(void); 
1993/1116    
 
1994/0416    
extern int	graphicssubtile(uchar*, int, int, Rectangle, Rectangle, uchar**); 
1994/0413    
 
1992/1119    
/* 
1993/1116    
 *  vga device 
1992/1119    
 */ 
enum 
{ 
1994/0624    
	Qdir		= 0, 
	Qvgaiob		= 1, 
	Qvgaiow		= 2, 
	Qvgaiol		= 3, 
	Qvgactl		= 4, 
1995/0508    
	Qvgaiosl	= 5, 
	Nvga		= Qvgaiosl, 
1992/1119    
}; 
1992/0527    
Dirtab vgadir[]={ 
1994/0624    
	"vgaiob",	{ Qvgaiob },	0,	0666, 
	"vgaiow",	{ Qvgaiow },	0,	0666, 
	"vgaiol",	{ Qvgaiol },	0,	0666, 
1995/0508    
	"vgaiosl",	{ Qvgaiosl },	0,	0666,	/* Debugging: philw */ 
1994/0624    
	"vgactl",	{ Qvgactl },	0,	0666, 
1992/0527    
}; 
 
void 
1992/1119    
vgareset(void) 
{ 
1994/0414    
	cursor.disable++; 
1992/0527    
} 
 
void 
vgainit(void) 
{ 
} 
 
Chan* 
vgaattach(char *upec) 
{ 
	return devattach('v', upec); 
} 
 
Chan* 
vgaclone(Chan *c, Chan *nc) 
{ 
	return devclone(c, nc); 
} 
 
int 
vgawalk(Chan *c, char *name) 
{ 
	return devwalk(c, name, vgadir, Nvga, devgen); 
} 
 
void 
vgastat(Chan *c, char *dp) 
{ 
1992/1119    
	devstat(c, dp, vgadir, Nvga, devgen); 
1992/0527    
} 
 
Chan* 
vgaopen(Chan *c, int omode) 
{ 
	return devopen(c, omode, vgadir, Nvga, devgen); 
} 
 
void 
vgacreate(Chan *c, char *name, int omode, ulong perm) 
{ 
1992/0711    
	USED(c, name, omode, perm); 
1992/0527    
	error(Eperm); 
} 
 
void 
vgaclose(Chan *c) 
{ 
1992/0711    
	USED(c); 
1992/0527    
} 
 
1994/0624    
static int 
checkvgaport(int port, int len) 
{ 
	if((port == 0x102 || port == 0x46E8) && len == 1) 
		return 0; 
	if(port >= 0x3B0 && port+len < 0x3E0) 
		return 0; 
	return -1; 
} 
 
1992/0527    
long 
vgaread(Chan *c, void *buf, long n, ulong offset) 
{ 
1992/0711    
	int port; 
1993/1116    
	uchar *cp; 
1995/0406    
	char cbuf[128]; 
1993/1116    
	ushort *sp; 
1994/0603    
	ulong *lp; 
1995/0126    
	Vgac *vgacp; 
1992/0528    
 
1992/0527    
	switch(c->qid.path&~CHDIR){ 
	case Qdir: 
		return devdirread(c, buf, n, vgadir, Nvga, devgen); 
1994/0624    
	case Qvgactl: 
1995/0204    
		if(cga) 
			return readstr(offset, buf, n, "type: cga\n"); 
		vgacp = vgac; 
1995/0126    
		port = sprint(cbuf, "type: %s\n", vgacp->name); 
1994/0930    
		port += sprint(cbuf+port, "size: %dx%dx%d%s\n", 
			gscreen.r.max.x, gscreen.r.max.y, 
			1<<gscreen.ldepth, interlaced); 
1994/0624    
		port += sprint(cbuf+port, "hwgc: "); 
		if(hwgc) 
1995/0406    
			port += sprint(cbuf+port, "%s\n", hwgc->name); 
1994/0624    
		else 
1995/0406    
			port += sprint(cbuf+port, "off\n"); 
		sprint(cbuf+port, "addr: 0x%lux\n", screenmem&~KZERO); 
1992/1119    
		return readstr(offset, buf, n, cbuf); 
1994/0624    
	case Qvgaiob: 
		port = offset; 
1994/0702    
		/*if(checkvgaport(port, n)) 
			error(Eperm);*/ 
1994/0624    
		for(cp = buf; port < offset+n; port++) 
			*cp++ = vgai(port); 
1992/0528    
		return n; 
1994/0624    
	case Qvgaiow: 
1993/1116    
		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; 
1994/0624    
	case Qvgaiol: 
1994/0603    
		if((n & 03) || (offset & 03)) 
			error(Ebadarg); 
		n /= 4; 
		for (lp = buf, port=offset; port<offset+n; port+=4) 
			*lp++ = inl(port); 
		return n*4; 
1992/0527    
	} 
1992/1119    
	error(Eperm); 
	return 0; 
1992/0527    
} 
 
1995/0108    
Block* 
vgabread(Chan *c, long n, ulong offset) 
{ 
	return devbread(c, n, offset); 
} 
 
1994/0624    
static void 
vgactl(char *arg) 
{ 
1995/0406    
	int n; 
	ulong x, y, z; 
	char *cp, *field[4]; 
1995/0126    
	Hwgc *hwgcp; 
	Vgac *vgacp; 
1994/0624    
 
1995/0406    
	n = getfields(arg, field, 4, " "); 
	if(n < 2) 
1994/0624    
		error(Ebadarg); 
 
1995/0406    
	if(strcmp(field[0], "disable") == 0){ 
		screendisabled = 1; 
	} 
	else if(strcmp(field[0], "enable") == 0){ 
		screendisabled = 0; 
	} 
	else if(strcmp(field[0], "hwgc") == 0){ 
		if(n < 2) 
			error(Ebadarg); 
1994/0624    
		if(strcmp(field[1], "off") == 0){ 
			if(hwgc){ 
				(*hwgc->disable)(); 
				hwgc = 0; 
				cursoron(1); 
			} 
			return; 
		} 
 
1995/0126    
		for(hwgcp = hwgctlr; hwgcp; hwgcp = hwgcp->link){ 
			if(strcmp(field[1], hwgcp->name) == 0){ 
1994/0624    
				if(hwgc) 
					(*hwgc->disable)(); 
				else 
					cursoroff(1); 
1995/0126    
				hwgc = hwgcp; 
1994/0624    
				(*hwgc->enable)(); 
				setcursor(&curs); 
				cursoron(1); 
				return; 
			} 
		} 
	} 
	else if(strcmp(field[0], "type") == 0){ 
1995/0406    
		if(n < 2) 
			error(Ebadarg); 
1995/0126    
		for(vgacp = vgactlr; vgacp; vgacp = vgacp->link){ 
			if(strcmp(field[1], vgacp->name) == 0){ 
				vgac = vgacp; 
1994/0624    
				return; 
			} 
		} 
	} 
	else if(strcmp(field[0], "size") == 0){ 
1995/0406    
		if(n < 2) 
			error(Ebadarg); 
1995/0206    
		x = strtoul(field[1], &cp, 0); 
		if(x == 0 || x > 2048) 
1994/0624    
			error(Ebadarg); 
 
		if(*cp) 
			cp++; 
1995/0206    
		y = strtoul(cp, &cp, 0); 
		if(y == 0 || y > 1280) 
1994/0624    
			error(Ebadarg); 
 
		if(*cp) 
			cp++; 
1995/0206    
		switch(strtoul(cp, &cp, 0)){ 
		case 8: 
			z = 3; break; 
		case 1: 
			z = 0; break; 
		default: 
1995/0207    
			z = 0; 
1994/0624    
			error(Ebadarg); 
1995/0206    
		} 
1994/0930    
		interlaced[0] = *cp; 
1994/0624    
 
1995/0206    
		cursoroff(1); 
1994/0624    
		setscreen(x, y, z); 
		cursoron(1); 
		return; 
	} 
1995/0406    
	else if(strcmp(field[0], "linear") == 0){ 
		if(n < 2) 
			error(Ebadarg); 
		x = strtoul(field[1], 0, 0); 
		if(n < 3) 
			y = 0; 
		else 
			y = strtoul(field[2], 0, 0); 
1994/0624    
 
1995/0406    
		/* see if it fits in the usual place */ 
1995/0407    
		if(x <= Footprint){ 
1995/0406    
			screenmem = SCREENMEM; 
1995/0407    
			if(x == 0){ 
1995/0406    
				footprint = Footprint; 
1995/0407    
				footshift = Footshift; 
			} else { 
1995/0406    
				footprint = x; 
1995/0407    
				for(n = 0; n < 31; n++) 
					if((1<<n) >= footprint) 
						break; 
				footshift = n; 
			} 
1995/0406    
			gscreen.base = (void*)screenmem; 
			return; 
		} 
 
		/* grab new space */ 
		if(y == 0){ 
			if(footprint >= x) 
				return; 
		} else { 
			int s, e; 
 
			s = screenmem & ~KZERO; 
			e = s + footprint; 
			s = ROUND(s, y); 
			if(e > s + x) 
				return; 
		} 
		y = getspace(x, y); 
		if(y == 0) 
			error("not enough free address space"); 
		screenmem = y; 
		gscreen.base = (void*)y; 
		footprint = x; 
1995/0407    
		for(n = 0; n < 31; n++) 
			if((1<<n) >= footprint) 
				break; 
		footshift = n; 
1995/0406    
		return; 
	} 
 
1994/0624    
	error(Ebadarg); 
} 
 
1992/0527    
long 
1992/0528    
vgawrite(Chan *c, void *buf, long n, ulong offset) 
1992/0527    
{ 
1994/0624    
	int port; 
	uchar *cp; 
	char cbuf[64]; 
1993/1116    
	ushort *sp; 
1994/0603    
	ulong *lp; 
1992/0528    
 
1992/0527    
	switch(c->qid.path&~CHDIR){ 
	case Qdir: 
		error(Eperm); 
1994/0503    
	case Qvgactl: 
		if(offset != 0 || n >= sizeof(cbuf)) 
			error(Ebadarg); 
		memmove(cbuf, buf, n); 
		cbuf[n] = 0; 
1994/0624    
		vgactl(cbuf); 
1992/0603    
		return n; 
1994/0624    
	case Qvgaiob: 
		port = offset; 
1994/0702    
		/*if(checkvgaport(port, n)) 
			error(Eperm);*/ 
1994/0624    
		for(cp = buf; port < offset+n; port++) 
			vgao(port, *cp++); 
1992/0604    
		return n; 
1994/0624    
	case Qvgaiow: 
1993/1116    
		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; 
1994/0624    
	case Qvgaiol: 
1994/0603    
		if((n & 03) || (offset & 03)) 
			error(Ebadarg); 
		n /= 4; 
		for (lp = buf, port=offset; port<offset+n; port+=4) 
			outl(port, *lp++); 
		return n*4; 
1995/0508    
	case Qvgaiosl: 
		if((n & 03) || (offset & 03)) 
			error(Ebadarg); 
		outsl(offset, buf, n/4); 
		return n; 
1992/0527    
	} 
1992/1119    
	error(Eperm); 
	return 0; 
1995/0108    
} 
 
long 
vgabwrite(Chan *c, Block *bp, ulong offset) 
{ 
	return devbwrite(c, bp, offset); 
1992/0527    
} 
 
void 
vgaremove(Chan *c) 
{ 
1992/0711    
	USED(c); 
1992/0527    
	error(Eperm); 
} 
 
void 
vgawstat(Chan *c, char *dp) 
{ 
1992/0711    
	USED(c, dp); 
1992/0527    
	error(Eperm); 
} 
1992/1119    
 
1994/0624    
int 
vgaxi(long port, uchar index) 
1993/1116    
{ 
1994/0624    
	uchar data; 
 
	switch(port){ 
 
	case Seqx: 
	case Crtx: 
	case Grx: 
		outb(port, index); 
		data = inb(port+1); 
		break; 
 
	case Attrx: 
		/* 
		 * Allow processor access to the colour 
		 * palette registers. Writes to Attrx must 
		 * be preceded by a read from Status1 to 
		 * initialise the register to point to the 
		 * index register and not the data register. 
		 * Processor access is allowed by turning 
		 * off bit 0x20. 
		 */ 
		inb(Status1); 
		if(index < 0x10){ 
			outb(Attrx, index); 
			data = inb(Attrx+1); 
			inb(Status1); 
			outb(Attrx, 0x20|index); 
		} 
		else{ 
			outb(Attrx, 0x20|index); 
			data = inb(Attrx+1); 
		} 
		break; 
 
	default: 
		return -1; 
	} 
 
	return data & 0xFF; 
1994/0416    
} 
1994/0624    
 
int 
vgaxo(long port, uchar index, uchar data) 
1994/0416    
{ 
1994/0624    
	switch(port){ 
 
	case Seqx: 
	case Crtx: 
	case Grx: 
		/* 
		 * We could use an outport here, but some chips 
		 * (e.g. 86C928) have trouble with that for some 
		 * registers. 
		 */ 
		outb(port, index); 
		outb(port+1, data); 
		break; 
 
	case Attrx: 
		inb(Status1); 
		if(index < 0x10){ 
			outb(Attrx, index); 
			outb(Attrx, data); 
			inb(Status1); 
			outb(Attrx, 0x20|index); 
		} 
		else{ 
			outb(Attrx, 0x20|index); 
			outb(Attrx, data); 
		} 
		break; 
 
	default: 
		return -1; 
1994/0416    
	} 
1994/0624    
 
	return 0; 
1994/0416    
} 
1994/0624    
 
/* 
 *  start the screen in CGA mode.  Create the fonts for VGA.  Called by 
 *  main(). 
 */ 
void 
screeninit(void) 
1994/0416    
{ 
1994/0624    
	int i; 
	ulong *l; 
 
	/* 
	 *  swizzle the font longs. 
	 */ 
	l = defont0.bits->base; 
	for(i = defont0.bits->width*Dy(defont0.bits->r); i > 0; i--, l++) 
		*l = (*l<<24) | ((*l>>8)&0x0000ff00) | ((*l<<8)&0x00ff0000) | (*l>>24); 
 
	/* 
	 *  start in CGA mode 
	 */ 
	cga = 1; 
	vgaxo(Crtx, 0x0A, 0xFF);		/* turn off cursor */ 
	memset(CGASCREEN, 0, CGAWIDTH*CGAHEIGHT); 
1994/0416    
} 
1993/1116    
 
1994/1029    
static ulong 
xnto32(uchar x, int n) 
{ 
	int s; 
	ulong y; 
 
	x &= (1<<n)-1; 
	y = 0; 
	for(s = 32 - n; s > 0; s -= n) 
		y |= x<<s; 
	if(s < 0) 
		y |= x>>(-s); 
	return y; 
} 
 
1993/1116    
/* 
 *  reconfigure screen shape 
 */ 
static void 
setscreen(int maxx, int maxy, int ldepth) 
{ 
1994/0416    
	int i, x, l, tl; 
	uchar *a; 
	Rectangle r; 
1993/1116    
 
1994/0415    
	if(waserror()){ 
		unlock(&screenlock); 
		nexterror(); 
	} 
	lock(&screenlock); 
 
1994/0416    
	/* setup a bitmap for the new size */ 
1993/1116    
	gscreen.ldepth = ldepth; 
1994/0415    
	gscreen.width = (maxx*(1<<gscreen.ldepth)+31)/32; 
1995/0406    
	gscreen.base = (void*)screenmem; 
1993/1116    
	gscreen.r.min = Pt(0, 0); 
	gscreen.r.max = Pt(maxx, maxy); 
	gscreen.clipr = gscreen.r; 
1995/0406    
	for(i = 0; i < gscreen.width*BY2WD*maxy; i += footprint){ 
		vgac->page(i>>footshift); 
		memset(gscreen.base, 0xff, footprint); 
1994/0412    
	} 
1993/1116    
 
1994/0416    
	/* get size for a system window */ 
1994/0415    
	h = defont0.height; 
	w = defont0.info[' '].width; 
	window.min = Pt(48, 48); 
1994/0812    
	window.max = add(window.min, Pt(10+w*80, 50*h)); 
1994/0415    
	if(window.max.y >= gscreen.r.max.y) 
		window.max.y = gscreen.r.max.y-1; 
	if(window.max.x >= gscreen.r.max.x) 
		window.max.x = gscreen.r.max.x-1; 
	window.max.y = window.min.y+((window.max.y-window.min.y)/h)*h; 
	curpos = window.min; 
 
1994/0416    
	/* work areas change when dimensions change */ 
1994/0415    
	workinit(&chwork, w, h); 
1994/0812    
	workinit(&scrollwork, 80*w, 1); 
1994/0416    
	workinit(&scrollwork, Dx(window), 1); 
1994/0415    
	cursorinit(); 
 
1994/0416    
	/* clear the system window */ 
	l = scrollwork.width * BY2WD; 
	memset(scrollwork.base, 0, l); 
	tl = graphicssubtile(0, l, gscreen.ldepth, gscreen.r, window, &a); 
	for(i = window.min.y; i < window.max.y; i++){ 
		r = Rect(window.min.x, i, window.max.x, i + 1); 
		screenload(r, (uchar*)scrollwork.base, tl, l, 1); 
	} 
 
1994/0415    
	unlock(&screenlock); 
	poperror(); 
 
1994/0416    
	/* default color map (has to be outside the lock) */ 
1993/1116    
	switch(ldepth){ 
	case 3: 
1995/0126    
		for(i = 0; i < Pcolours; i++) 
1994/0528    
			setcolor(i, xnto32(i>>5, 3), xnto32(i>>2, 3), xnto32(i, 2)); 
1994/0507    
		setcolor(0x55, xnto32(0x15, 6), xnto32(0x15, 6), xnto32(0x15, 6)); 
		setcolor(0xaa, xnto32(0x2a, 6), xnto32(0x2a, 6), xnto32(0x2a, 6)); 
		setcolor(0xff, xnto32(0x3f, 6), xnto32(0x3f, 6), xnto32(0x3f, 6)); 
1993/1116    
		break; 
	case 2: 
	case 1: 
	case 0: 
		for(i = 0; i < 16; i++){ 
1994/0507    
			x = xnto32((i*63)/15, 6); 
1993/1116    
			setcolor(i, x, x, x); 
		} 
		break; 
	} 
1994/0415    
 
1994/0416    
	/* switch software to graphics mode */ 
1993/1116    
	cga = 0; 
1994/0415    
} 
1993/1116    
 
1994/0415    
/* 
 *  init a bitblt work area 
 */ 
static void 
workinit(Bitmap *bm, int maxx, int maxy) 
{ 
	bm->ldepth = gscreen.ldepth; 
	bm->r = Rect(0, 0, maxx, maxy); 
	if(gscreen.ldepth != 3) 
		bm->r.max.x += 1<<(3-gscreen.ldepth); 
	bm->clipr = bm->r; 
	bm->width = ((bm->r.max.x << gscreen.ldepth) + 31) >> 5; 
	if(bm->base == 0) 
		bm->base = xalloc(maxx*maxy); 
1994/0412    
} 
1993/1116    
 
1994/0412    
/* 
 *  Load a byte into screen memory.  Assume that if the page 
 *  is wrong we just need to increment it. 
 */ 
static int 
byteload(uchar *q, uchar *data, int m, int *page, uchar *e) 
{ 
	int pg; 
	int diff; 
 
	diff = 0; 
	if(q >= e){ 
		pg = ++*page; 
1995/0126    
		vgac->page(pg); 
1995/0406    
		q -= footprint; 
		diff -= footprint; 
1994/0412    
	} 
	*q ^= (*data^*q) & m; 
	return diff; 
1993/1116    
} 
 
/* 
1994/0412    
 *  Load adjacent bytes into a screen memory.  Assume that if the page 
 *  is wrong we just need to increment it. 
 */ 
static int 
lineload(uchar *q, uchar *data, int len, int *page, uchar *e) 
{ 
	int rem, pg; 
	int diff; 
 
	diff = 0; 
	if(q >= e){ 
		pg = ++*page; 
1995/0126    
		vgac->page(pg); 
1995/0406    
		q -= footprint; 
		diff -= footprint; 
1994/0412    
	} 
 
	rem = e - q; 
 
	if(rem < len){ 
		memmove(q, data, rem); 
		pg = ++*page; 
1995/0126    
		vgac->page(pg); 
1995/0406    
		q -= footprint; 
		diff -= footprint; 
1994/0412    
		memmove(q+rem, data+rem, len-rem); 
	} else 
		memmove(q, data, len); 
 
	return diff; 
} 
 
/* 
 *   paste tile into hard screen. 
1993/1217    
 *   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. 
1993/1116    
 */ 
void 
1994/0412    
screenload(Rectangle r, uchar *data, int tl, int l, int dolock) 
1993/1116    
{ 
1994/0412    
	int y, lpart, rpart, mx, m, mr, page, sw; 
	ulong off; 
	uchar *q, *e; 
1993/1116    
 
1995/0406    
	if(screendisabled || cga || !rectclip(&r, gscreen.r) || tl<=0) 
1993/1116    
		return; 
1994/0412    
 
1994/0624    
	if(dolock && hwgc == 0) 
1994/0412    
		cursorlock(r); 
1994/0729    
	lock(&palettelock); 
1994/0412    
 
1994/0413    
	q = byteaddr(&gscreen, r.min); 
1993/1116    
	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); 
1994/0412    
 
	off = q - (uchar*)gscreen.base; 
1995/0406    
	page = off>>footshift; 
1995/0126    
	vgac->page(page); 
1995/0406    
	q = ((uchar*)gscreen.base) + (off&(footprint-1)); 
1994/0412    
 
	sw = gscreen.width*sizeof(ulong); 
1995/0406    
	e = ((uchar*)gscreen.base) + footprint; 
1994/0412    
 
1993/1116    
	/* may need to do bit insertion on edges */ 
1994/0407    
	if(tl <= 0){ 
		; 
	}else if(tl == 1){	/* all in one byte */ 
1993/1116    
		if(rpart) 
1993/1221    
			m &= mr; 
1993/1116    
		for(y=r.min.y; y<r.max.y; y++){ 
1994/0412    
			if(q < e) 
				*q ^= (*data^*q) & m; 
			else 
				q += byteload(q, data, m, &page, e); 
			q += sw; 
1993/1116    
			data += l; 
		} 
	}else if(lpart==0 && rpart==0){	/* easy case */ 
		for(y=r.min.y; y<r.max.y; y++){ 
1994/0412    
			if(q + tl <= e) 
				memmove(q, data, tl); 
			else 
				q += lineload(q, data, tl, &page, e); 
			q += sw; 
1993/1116    
			data += l; 
		} 
	}else if(rpart==0){ 
		for(y=r.min.y; y<r.max.y; y++){ 
1994/0412    
			if(q + tl <= e){ 
				*q ^= (*data^*q) & m; 
				memmove(q+1, data+1, tl-1); 
			} else { 
				q += byteload(q, data, m, &page, e); 
				q += lineload(q+1, data+1, tl-1, &page, e); 
			} 
			q += sw; 
1993/1116    
			data += l; 
		} 
	}else if(lpart == 0){ 
		for(y=r.min.y; y<r.max.y; y++){ 
1994/0412    
			if(q + tl <= e){ 
				memmove(q, data, tl-1); 
				q[tl-1] ^= (data[tl-1]^q[tl-1]) & mr; 
			} else {	/* new page */ 
				q += lineload(q, data, tl-1, &page, e); 
				q += byteload(q+tl-1, data+tl-1, mr, &page, e); 
			} 
			q += sw; 
1993/1116    
			data += l; 
		} 
	}else for(y=r.min.y; y<r.max.y; y++){ 
1994/0809    
		if(q + tl <= e){ 
			*q ^= (*data^*q) & m; 
			if(tl > 2) 
				memmove(q+1, data+1, tl-2); 
			q[tl-1] ^= (data[tl-1]^q[tl-1]) & mr; 
		} else {	/* new page */ 
			q += byteload(q, data, m, &page, e); 
			if(tl > 2) 
				q += lineload(q+1, data+1, tl-2, &page, e); 
			q += byteload(q+tl-1, data+tl-1, mr, &page, e); 
1993/1116    
		} 
1994/0809    
		q += sw; 
		data += l; 
	} 
1994/0412    
 
1994/0729    
	unlock(&palettelock); 
1994/0624    
	if(dolock && hwgc == 0) 
1994/0412    
		cursorunlock(); 
1993/1116    
} 
 
/* 
1994/0412    
 *  Get a byte from screen memory.  Assume that if the page 
 *  is wrong we just need to increment it. 
1993/1116    
 */ 
1994/0412    
static int 
byteunload(uchar *q, uchar *data, int m, int *page, uchar *e) 
1993/1116    
{ 
1994/0412    
	int pg; 
	int diff; 
1993/1116    
 
1994/0412    
	diff = 0; 
	if(q >= e){ 
		pg = ++*page; 
1995/0126    
		vgac->page(pg); 
1995/0406    
		q -= footprint; 
		diff -= footprint; 
1994/0412    
	} 
	*data ^= (*q^*data) & m; 
	return diff; 
} 
1993/1116    
 
1994/0412    
/* 
 *  Get a vector of bytes from screen memory.  Assume that if the page 
 *  is wrong we just need to increment it. 
 */ 
static int 
lineunload(uchar *q, uchar *data, int len, int *page, uchar *e) 
{ 
	int rem, pg; 
	int diff; 
1993/1116    
 
1994/0412    
	diff = 0; 
	if(q >= e){ 
		pg = ++*page; 
1995/0126    
		vgac->page(pg); 
1995/0406    
		q -= footprint; 
		diff -= footprint; 
1994/0412    
	} 
1993/1116    
 
1994/0412    
	rem = e - q; 
1993/1116    
 
1994/0412    
	if(rem < len){ 
		memmove(data, q, rem); 
		pg = ++*page; 
1995/0126    
		vgac->page(pg); 
1995/0406    
		q -= footprint; 
		diff -= footprint; 
1994/0412    
		memmove(data+rem, q+rem, len-rem); 
	} else 
		memmove(data, q, len); 
 
	return diff; 
} 
 
/* 
1994/0809    
 * get a tile from screen memory. 
 * 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. 
1994/0412    
 */ 
void 
screenunload(Rectangle r, uchar *data, int tl, int l, int dolock) 
{ 
	int y, lpart, rpart, mx, m, mr, page, sw; 
	ulong off; 
	uchar *q, *e; 
 
1995/0406    
	if(screendisabled || cga || !rectclip(&r, gscreen.r) || tl<=0) 
1993/1116    
		return; 
 
1994/0624    
	if(dolock && hwgc == 0) 
1994/0412    
		cursorlock(r); 
1994/0729    
	lock(&palettelock); 
1993/1116    
 
1994/0413    
	q = byteaddr(&gscreen, r.min); 
1994/0412    
	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); 
 
	off = q - (uchar*)gscreen.base; 
1995/0406    
	page = off>>footshift; 
1995/0126    
	vgac->page(page); 
1995/0406    
	q = ((uchar*)gscreen.base) + (off&(footprint-1)); 
1994/0412    
 
	sw = gscreen.width*sizeof(ulong); 
1995/0406    
	e = ((uchar*)gscreen.base) + footprint; 
1994/0412    
 
	/* may need to do bit insertion on edges */ 
	if(tl <= 0){ 
		; 
	}else if(tl == 1){	/* all in one byte */ 
		if(rpart) 
			m &= mr; 
		for(y=r.min.y; y<r.max.y; y++){ 
			if(q < e) 
				*data ^= (*q^*data) & m; 
			else 
				q += byteunload(q, data, m, &page, e); 
			q += sw; 
			data += l; 
		} 
	}else if(lpart==0 && rpart==0){	/* easy case */ 
		for(y=r.min.y; y<r.max.y; y++){ 
			if(q + tl <= e) 
				memmove(data, q, tl); 
			else 
				q += lineunload(q, data, tl, &page, e); 
			q += sw; 
			data += l; 
		} 
	}else if(rpart==0){ 
		for(y=r.min.y; y<r.max.y; y++){ 
			if(q + tl <= e){ 
				*data ^= (*q^*data) & m; 
				memmove(data+1, q+1, tl-1); 
1993/1116    
			} else { 
1994/0412    
				q += byteunload(q, data, m, &page, e); 
				q += lineunload(q+1, data+1, tl-1, &page, e); 
1993/1116    
			} 
1994/0412    
			q += sw; 
			data += l; 
1993/1116    
		} 
1994/0412    
	}else if(lpart == 0){ 
		for(y=r.min.y; y<r.max.y; y++){ 
			if(q + tl <= e){ 
				memmove(data, q, tl-1); 
				data[tl-1] ^= (q[tl-1]^data[tl-1]) & mr; 
			} else {	/* new page */ 
				q += lineunload(q, data, tl-1, &page, e); 
				q += byteunload(q+tl-1, data+tl-1, mr, &page, e); 
			} 
			q += sw; 
			data += l; 
		} 
	}else for(y=r.min.y; y<r.max.y; y++){ 
1994/0809    
		if(q + tl <= e){ 
			*data ^= (*q^*data) & m; 
			if(tl > 2) 
				memmove(data+1, q+1, tl-2); 
			data[tl-1] ^= (q[tl-1]^data[tl-1]) & mr; 
		} else {	/* new page */ 
			q += byteunload(q, data, m, &page, e); 
			if(tl > 2) 
				q += lineunload(q+1, data+1, tl-2, &page, e); 
			q += byteunload(q+tl-1, data+tl-1, mr, &page, e); 
1994/0412    
		} 
1994/0809    
		q += sw; 
		data += l; 
	} 
1994/0412    
 
1994/0729    
	unlock(&palettelock); 
1994/0624    
	if(dolock && hwgc == 0) 
1994/0412    
		cursorunlock(); 
1993/1116    
} 
 
1994/0412    
/* 
 *  write a string to the screen 
 */ 
1993/1116    
void 
screenputs(char *s, int n) 
{ 
	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); 
	} 
 
	unlock(&screenlock); 
} 
 
1992/1119    
static void 
nopage(int page) 
{ 
	USED(page); 
} 
 
1994/0415    
/* 
 *  character mode console 
 */ 
1992/1119    
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); 
	} 
} 
 
1993/1116    
static void 
1992/1119    
cgascreenputs(char *s, int n) 
{ 
	while(n-- > 0) 
		cgascreenputc(*s++); 
} 
 
1994/0415    
/* 
 *  graphics mode console 
 */ 
#define LINE2SCROLL 4 
1993/1116    
static void 
scroll(void) 
1992/1119    
{ 
1994/0416    
	int from, tl, l, diff; 
1994/0415    
	uchar *a; 
1992/1119    
	Rectangle r; 
 
1994/0416    
	diff = h*LINE2SCROLL; 
	l = scrollwork.width * BY2WD; 
1994/0415    
	tl = graphicssubtile(0, l, gscreen.ldepth, gscreen.r, window, &a); 
 
1994/0416    
	/* move lines up */ 
	for(from = window.min.y + diff; from < window.max.y; from++){ 
		r = Rect(window.min.x, from, window.max.x, from + 1); 
1994/0415    
		screenunload(r, (uchar*)scrollwork.base, tl, l, 1); 
1994/0416    
		r = Rect(window.min.x, from - diff, window.max.x, from - diff + 1); 
1994/0415    
		screenload(r, (uchar*)scrollwork.base, tl, l, 1); 
	} 
1994/0416    
 
	/* clear bottom */ 
	memset(scrollwork.base, 0, l); 
	for(from = window.max.y - diff; from < window.max.y; from++){ 
		r = Rect(window.min.x, from, window.max.x, from + 1); 
		screenload(r, (uchar*)scrollwork.base, tl, l, 1); 
	} 
	 
	curpos.y -= diff; 
1992/1119    
} 
 
1993/1116    
static void 
screenputc(char *buf) 
1992/1119    
{ 
1994/0415    
	int pos, l, tl, off; 
	uchar *a; 
	Rectangle r; 
1992/1119    
 
1993/1116    
	switch(buf[0]) { 
	case '\n': 
1994/0413    
		if(curpos.y+h >= window.max.y) 
1993/1116    
			scroll(); 
1994/0413    
		curpos.y += h; 
1993/1116    
		screenputc("\r"); 
		break; 
	case '\r': 
1994/0413    
		curpos.x = window.min.x; 
1993/1116    
		break; 
	case '\t': 
1994/0413    
		pos = (curpos.x-window.min.x)/w; 
1993/1116    
		pos = 8-(pos%8); 
1994/0413    
		curpos.x += pos*w; 
1993/1116    
		break; 
	case '\b': 
1994/0415    
		if(curpos.x-w >= window.min.x){ 
1994/0413    
			curpos.x -= w; 
1994/0415    
			screenputc(" "); 
			curpos.x -= w; 
		} 
1993/1116    
		break; 
	default: 
1994/0413    
		if(curpos.x >= window.max.x-w) 
1993/1116    
			screenputc("\n"); 
1992/1119    
 
1994/0415    
		/* tile width */ 
		r.min = curpos; 
		r.max = add(r.min, Pt(w, h)); 
		off = ((1<<gscreen.ldepth)*r.min.x) & 7; 
		l = chwork.width*BY2WD; 
		tl = graphicssubtile(0, l, gscreen.ldepth, gscreen.r, r, &a); 
 
		/* add char into work area */ 
		subfstring(&chwork, Pt(off, 0), &defont0, buf, S); 
 
		/* move work area to screen */ 
		screenload(r, (uchar*)chwork.base, tl, l, 0); 
 
		curpos.x += w; 
1992/1119    
	} 
} 
 
int 
screenbits(void) 
{ 
	return 1<<gscreen.ldepth;	/* bits per pixel */ 
} 
 
void 
getcolor(ulong p, ulong *pr, ulong *pg, ulong *pb) 
{ 
1993/1230    
	ulong x; 
 
	switch(gscreen.ldepth){ 
	default: 
1995/0126    
		x = 0xF; 
1993/1230    
		break; 
	case 3: 
1995/0126    
		x = 0xFF; 
1993/1230    
		break; 
	} 
	p &= x; 
	p ^= x; 
1994/0729    
	lock(&palettelock); 
1995/0126    
	*pr = colormap[p][Pred]; 
	*pg = colormap[p][Pgreen]; 
	*pb = colormap[p][Pblue]; 
1994/0729    
	unlock(&palettelock); 
1992/1119    
} 
 
int 
setcolor(ulong p, ulong r, ulong g, ulong b) 
{ 
1993/1230    
	ulong x; 
 
	switch(gscreen.ldepth){ 
	default: 
1995/0126    
		x = 0xF; 
1993/1230    
		break; 
	case 3: 
1995/0126    
		x = 0xFF; 
1993/1230    
		break; 
	} 
	p &= x; 
	p ^= x; 
1994/0729    
	lock(&palettelock); 
1995/0126    
	colormap[p][Pred] = r; 
	colormap[p][Pgreen] = g; 
	colormap[p][Pblue] = b; 
	vgao(PaddrW, p); 
	vgao(Pdata, r>>(32-6)); 
	vgao(Pdata, g>>(32-6)); 
	vgao(Pdata, b>>(32-6)); 
1994/0729    
	unlock(&palettelock); 
1992/1119    
	return ~0; 
1994/0414    
} 
 
/* 
 *  software cursor 
1994/0624    
 *  and hacks for hardware cursor 
1994/0414    
 */ 
 
1994/0415    
/* 
 *  area to store the bits that are behind the cursor 
 */ 
1994/0521    
static ulong backbits[16*4]; 
static ulong clrbits[16]; 
static ulong setbits[16]; 
1994/0414    
 
1994/0415    
/* 
 *  the white border around the cursor 
 */ 
1994/0414    
Bitmap	clr = 
{ 
	{0, 0, 16, 16}, 
	{0, 0, 16, 16}, 
	0, 
1994/0521    
	clrbits, 
1994/0414    
	0, 
	1, 
}; 
 
1994/0415    
/* 
 *  the black center of the cursor 
 */ 
1994/0414    
Bitmap	set = 
{ 
	{0, 0, 16, 16}, 
	{0, 0, 16, 16}, 
	0, 
1994/0521    
	setbits, 
1994/0414    
	0, 
	1, 
}; 
 
void 
cursorinit(void) 
{ 
	static int already; 
 
	lock(&cursor); 
 
1994/0415    
	workinit(&cursorwork, 16, 16); 
1994/0414    
	cursor.l = cursorwork.width*BY2WD; 
 
	if(!already){ 
		cursor.disable--; 
		already = 1; 
	} 
 
	unlock(&cursor); 
} 
 
void 
1994/0520    
setcursor(Cursor *curs) 
1994/0414    
{ 
1994/0520    
	uchar *p; 
	int i; 
 
1994/0624    
	if(hwgc) 
		(*hwgc->load)(curs); 
	else for(i=0; i<16; i++){ 
1994/0520    
		p = (uchar*)&set.base[i]; 
		*p = curs->set[2*i]; 
		*(p+1) = curs->set[2*i+1]; 
		p = (uchar*)&clr.base[i]; 
		*p = curs->clr[2*i]; 
		*(p+1) = curs->clr[2*i+1]; 
	} 
1994/0414    
} 
 
1994/0624    
int 
1994/0414    
cursoron(int dolock) 
{ 
1994/0624    
	int xoff, yoff, s, ret; 
1994/0414    
	Rectangle r; 
	uchar *a; 
	struct { 
		Bitmap *dm; 
		Point p; 
		Bitmap *sm; 
		Rectangle r; 
		Fcode f; 
	} xx; 
 
	if(cursor.disable) 
1994/0624    
		return 0; 
	if(dolock){ 
		s = 0;		/* to avoid compiler warning */ 
1994/0414    
		lock(&cursor); 
1994/0624    
	} else 
		s = spllo();	/* to avoid freezing out the eia ports */ 
1994/0414    
 
1994/0624    
	ret = 0; 
	if(hwgc) 
		ret = (*hwgc->move)(mousexy()); 
1994/0503    
	else if(cursor.visible++ == 0){ 
1994/0414    
		cursor.r.min = mousexy(); 
		cursor.r.max = add(cursor.r.min, Pt(16, 16)); 
		cursor.r = raddp(cursor.r, cursor.offset); 
	 
1994/0416    
		/* offsets into backup area and clr/set bitmaps */ 
		r.min = Pt(0, 0); 
		if(cursor.r.min.x < 0){ 
			xoff = cursor.r.min.x; 
			r.min.x = -xoff; 
		} else 
			xoff = ((1<<gscreen.ldepth)*cursor.r.min.x) & 7; 
		if(cursor.r.min.y < 0){ 
			yoff = cursor.r.min.y; 
			r.min.y = -yoff; 
		} else 
			yoff = 0; 
		r.max = add(r.min, Pt(16, 16)); 
1994/0414    
	 
		/* clip the cursor rectangle */ 
		xx.dm = &cursorwork; 
1994/0416    
		xx.p = Pt(xoff, yoff); 
1994/0414    
		xx.sm = &gscreen; 
		xx.r = cursor.r; 
		bitbltclip(&xx); 
	 
		/* tile width */ 
		cursor.tl = graphicssubtile(0, cursor.l, gscreen.ldepth, 
				gscreen.r, xx.r, &a); 
		if(cursor.tl > 0){ 
			/* get tile */ 
1994/0415    
			screenunload(xx.r, (uchar*)cursorwork.base, cursor.tl, cursor.l, 0); 
1994/0414    
	 
			/* save for cursoroff */ 
1994/0415    
			memmove(backbits, cursorwork.base, cursor.l*16); 
1994/0414    
	 
			/* add mouse into work area */ 
1994/0415    
			bitblt(&cursorwork, xx.p, &clr, r, D&~S); 
			bitblt(&cursorwork, xx.p, &set, r, S|D); 
1994/0414    
	 
			/* put back tile */ 
			cursor.clipr = xx.r; 
1994/0415    
			screenload(xx.r, (uchar*)cursorwork.base, cursor.tl, cursor.l, 0); 
1994/0414    
		} 
	} 
 
	if(dolock) 
		unlock(&cursor); 
1994/0624    
	else 
		splx(s); 
 
	return ret; 
1994/0414    
} 
 
void 
cursoroff(int dolock) 
{ 
1994/0624    
	if(hwgc) 
1994/0503    
		return; 
1994/0414    
	if(cursor.disable) 
		return; 
1994/0510    
	if(dolock) 
1994/0414    
		lock(&cursor); 
1994/0510    
 
1994/0414    
	if(--cursor.visible == 0 && cursor.tl > 0) 
		screenload(cursor.clipr, (uchar*)backbits, cursor.tl, cursor.l, 0); 
1994/0510    
 
1994/0414    
	if(dolock) 
		unlock(&cursor); 
} 
 
1994/0415    
static void 
1994/0414    
cursorlock(Rectangle r) 
{ 
	lock(&cursor); 
	if(rectXrect(cursor.r, r)){ 
		cursoroff(0); 
		cursor.frozen = 1; 
	} 
	cursor.disable++; 
	unlock(&cursor); 
} 
 
1994/0415    
static void 
1994/0414    
cursorunlock(void) 
{ 
	lock(&cursor); 
	cursor.disable--; 
	if(cursor.frozen) 
		cursoron(0); 
	cursor.frozen = 0; 
	unlock(&cursor); 
1995/0126    
} 
 
void 
addhwgclink(Hwgc *hwgcp) 
{ 
	hwgcp->link = hwgctlr; 
	hwgctlr = hwgcp; 
} 
 
void 
addvgaclink(Vgac *vgacp) 
{ 
	vgacp->link = vgactlr; 
	vgactlr = vgacp; 
1992/1119    
} 


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