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

1994/0415/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" 
1992/0527    
 
1993/1116    
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 */ 
}; 
1992/1119    
 
1994/0412    
enum 
{ 
	Footshift=	16, 
	Footprint=	1<<Footshift, 
}; 
 
1992/1119    
/* imported */ 
1994/0413    
extern	Subfont defont0; 
1993/1117    
extern Cursor arrow; 
1992/1119    
 
/* exported */ 
1994/0413    
Subfont *defont; 
Bitmap	gscreen; 
1992/1119    
 
1993/1116    
/* vga screen */ 
static	Lock	screenlock; 
1994/0415    
static	Lock	loadlock; 
1993/1116    
static	ulong	colormap[256][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    
 
1992/0527    
/* 
1992/1119    
 *  screen dimensions 
1992/0527    
 */ 
1993/1116    
#define	MINX	8 
1992/1119    
#define MAXX	640 
#define MAXY	480 
1993/1116    
#define	CGAWIDTH	160 
#define	CGAHEIGHT	24 
1992/0527    
 
1992/1119    
/* 
1993/1116    
 *  screen memory addresses 
1992/1119    
 */ 
1993/1116    
#define SCREENMEM	(0xA0000 | KZERO) 
#define CGASCREEN	((uchar*)(0xB8000 | KZERO)) 
1992/0527    
 
1993/1116    
/* 
 *  VGA modes 
 */ 
1992/1119    
typedef struct VGAmode	VGAmode; 
struct VGAmode 
{ 
	uchar	general[2]; 
	uchar	sequencer[5]; 
	uchar	crt[0x19]; 
	uchar	graphics[9]; 
	uchar	attribute[0x15]; 
1992/0527    
}; 
 
1992/1119    
/* 
 *  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, 
}; 
 
/* 
 *  definitions of known cards 
 */ 
typedef struct Vgacard	Vgacard; 
struct Vgacard 
{ 
	char	*name; 
1993/1116    
	void	(*setpage)(int);	/* routine to page though display memory */ 
1992/1119    
}; 
 
enum 
{ 
1992/1216    
	Ati,		/* ATI */ 
1992/1124    
	Pvga1a,		/* paradise */ 
1992/1216    
	Trident,	/* Trident 8900 */ 
	Tseng,		/* tseng labs te4000 */ 
1993/0915    
	Cirrus,		/* Cirrus CLGD542X */ 
1994/0311    
	S3, 
1992/1119    
	Generic, 
}; 
 
1993/1116    
static void	nopage(int), tsengpage(int), tridentpage(int), parapage(int); 
1994/0311    
static void	atipage(int), cirruspage(int), s3page(int); 
1993/1116    
 
1993/0106    
Vgacard vgachips[] = 
1992/1119    
{ 
1993/0106    
[Ati]		{ "ati", atipage, }, 
1992/1124    
[Pvga1a]	{ "pvga1a", parapage, }, 
1992/1216    
[Trident]	{ "trident", tridentpage, }, 
1992/1119    
[Tseng]		{ "tseng", tsengpage, }, 
1993/0915    
[Cirrus]	{ "cirrus", cirruspage, }, 
1994/0311    
[S3]		{ "s3", s3page, }, 
1992/1119    
[Generic]	{ "generic", nopage, }, 
		{ 0, 0, }, 
}; 
 
Vgacard	*vgacard;	/* current vga card */ 
 
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 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	cgascreenputc(int); 
static void	cgascreenputs(char*, int); 
static void	screenputc(char*); 
static void	scroll(void); 
static ulong	x3to32(uchar); 
static ulong	x6to32(uchar); 
1994/0415    
static void	workinit(Bitmap*, int, int); 
1993/1116    
 
1994/0415    
static void cursorlock(Rectangle); 
static void cursorunlock(void); 
extern int graphicssubtile(uchar*, int, int, Rectangle, Rectangle, uchar**); 
1994/0413    
 
1992/1119    
/* 
1993/1116    
 *  vga device 
1992/1119    
 */ 
enum 
{ 
	Qdir=		0, 
	Qvgasize=	1, 
	Qvgatype=	2, 
	Qvgaport=	3, 
1993/1116    
	Qvgaportw=	4, 
	Nvga=		4, 
1992/1119    
}; 
1992/0527    
Dirtab vgadir[]={ 
	"vgasize",	{Qvgasize},	0,		0666, 
1992/1119    
	"vgatype",	{Qvgatype},	0,		0666, 
1992/0528    
	"vgaport",	{Qvgaport},	0,		0666, 
1993/1116    
	"vgaportw",	{Qvgaportw},	0,		0666, 
1992/0527    
}; 
 
void 
1992/1119    
vgareset(void) 
{ 
1993/0106    
	vgacard = &vgachips[Generic]; 
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    
} 
 
long 
vgaread(Chan *c, void *buf, long n, ulong offset) 
{ 
1992/0711    
	int port; 
1993/1116    
	uchar *cp; 
1992/1119    
	char cbuf[64]; 
1993/1116    
	ushort *sp; 
1992/0528    
 
1992/0527    
	switch(c->qid.path&~CHDIR){ 
	case Qdir: 
		return devdirread(c, buf, n, vgadir, Nvga, devgen); 
	case Qvgasize: 
1992/1119    
		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); 
1992/0528    
	case Qvgaport: 
1993/1116    
		for (cp = buf, port=offset; port<offset+n; port++) 
1992/0528    
			*cp++ = inb(port); 
		return n; 
1993/1116    
	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; 
1992/0527    
	} 
1992/1119    
	error(Eperm); 
	return 0; 
1992/0527    
} 
 
long 
1992/0528    
vgawrite(Chan *c, void *buf, long n, ulong offset) 
1992/0527    
{ 
1992/1119    
	char cbuf[64], *cp; 
	Vgacard *vp; 
	int port, maxx, maxy, ldepth; 
1993/1116    
	ushort *sp; 
1992/0528    
 
1992/0527    
	switch(c->qid.path&~CHDIR){ 
	case Qdir: 
		error(Eperm); 
	case Qvgatype: 
1992/1119    
		if(offset != 0 || n >= sizeof(cbuf) || n < 1) 
1992/0528    
			error(Ebadarg); 
1992/1119    
		memmove(cbuf, buf, n); 
		cbuf[n] = 0; 
		if(cp = strchr(cbuf, '\n')) 
			*cp = 0; 
1993/0106    
		for(vp = vgachips; vp->name; vp++) 
1992/1119    
			if(strcmp(cbuf, vp->name) == 0){ 
				vgacard = vp; 
				return n; 
			} 
		error(Ebadarg); 
1992/0527    
	case Qvgasize: 
1992/1119    
		if(offset != 0 || n >= sizeof(cbuf)) 
1992/0528    
			error(Ebadarg); 
1992/0603    
		memmove(cbuf, buf, n); 
1992/0604    
		cbuf[n] = 0; 
1992/0603    
		cp = cbuf; 
		maxx = strtoul(cp, &cp, 0); 
1992/1119    
		if(*cp!=0) 
			cp++; 
1992/0603    
		maxy = strtoul(cp, &cp, 0); 
1992/1119    
		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) 
1992/0603    
			error(Ebadarg); 
1993/1117    
		cursoroff(1); 
1992/1119    
		setscreen(maxx, maxy, ldepth); 
1993/1117    
		cursoron(1); 
1992/0603    
		return n; 
1992/0528    
	case Qvgaport: 
1993/1116    
		for (cp = buf, port=offset; port<offset+n; port++) 
1992/0528    
			outb(port, *cp++); 
1992/0604    
		return n; 
1993/1116    
	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; 
1992/0527    
	} 
1992/1119    
	error(Eperm); 
	return 0; 
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    
 
1993/1116    
/* 
 *  start the screen in CGA mode.  Create the fonts for VGA. 
 */ 
void 
screeninit(void) 
{ 
	int i; 
	ulong *l; 
 
	/* 
1993/1221    
	 *  swizzle the font longs. 
1993/1117    
	 */ 
1994/0413    
	l = defont0.bits->base; 
	for(i = defont0.bits->width*Dy(defont0.bits->r); i > 0; i--, l++) 
1993/1116    
		*l = (*l<<24) | ((*l>>8)&0x0000ff00) | ((*l<<8)&0x00ff0000) | (*l>>24); 
1994/0412    
 
1993/1116    
	/* 
	 *  start in CGA mode 
	 */ 
	cga = 1; 
	crout(0x0a, 0xff);		/* turn off cursor */ 
	memset(CGASCREEN, 0, CGAWIDTH*CGAHEIGHT); 
} 
 
1994/0412    
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]); 
} 
 
1993/1116    
/* 
 *  reconfigure screen shape 
 */ 
static void 
setscreen(int maxx, int maxy, int ldepth) 
{ 
1994/0412    
	int i, x; 
1993/1116    
 
1994/0415    
	if(waserror()){ 
		unlock(&screenlock); 
		nexterror(); 
	} 
	lock(&screenlock); 
 
1994/0412    
	switch(ldepth){ 
	case 0: 
1993/1116    
		setmode(&mode12); 
1994/0412    
		break; 
	case 3: 
		setmode(&mode13); 
		break; 
	default: 
		error(Ebadarg); 
	} 
1993/1116    
 
	/* 
1994/0412    
	 *  setup a bitmap for the new size 
1993/1116    
	 */ 
	gscreen.ldepth = ldepth; 
1994/0415    
	gscreen.width = (maxx*(1<<gscreen.ldepth)+31)/32; 
1994/0412    
	gscreen.base = (void*)SCREENMEM; 
1993/1116    
	gscreen.r.min = Pt(0, 0); 
	gscreen.r.max = Pt(maxx, maxy); 
	gscreen.clipr = gscreen.r; 
1994/0412    
	for(i = 0; i < gscreen.width*BY2WD*maxy; i += Footprint){ 
		vgacard->setpage(i>>Footshift); 
1994/0415    
		memset(gscreen.base, 0xff, Footprint); 
1994/0412    
	} 
1993/1116    
 
	/* 
1994/0415    
	 *  set up inset system window 
1993/1116    
	 */ 
1994/0415    
	h = defont0.height; 
	w = defont0.info[' '].width; 
 
	window.min = Pt(48, 48); 
	window.max = add(window.min, Pt(10+w*64, 36*h)); 
	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; 
 
	vgacard->setpage(0); 
	window.max.y = window.min.y+((window.max.y-window.min.y)/h)*h; 
	bitblt(&gscreen, window.min, &gscreen, window, Zero); 
	curpos = window.min; 
 
	/* work areas */ 
	workinit(&chwork, w, h); 
	workinit(&scrollwork, 64*w, 1); 
	cursorinit(); 
 
	unlock(&screenlock); 
	poperror(); 
 
	/* 
	 *  default color map (has to be outside the lock) 
	 */ 
1993/1116    
	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: 
		for(i = 0; i < 16; i++){ 
			x = x6to32((i*63)/15); 
			setcolor(i, x, x, x); 
		} 
		break; 
	} 
1994/0415    
 
	/* stop character mode changes */ 
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; 
		vgacard->setpage(pg); 
		q -= Footprint; 
		diff -= Footprint; 
	} 
	*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; 
		vgacard->setpage(pg); 
		q -= Footprint; 
		diff -= Footprint; 
	} 
 
	rem = e - q; 
 
	if(rem < len){ 
		memmove(q, data, rem); 
		pg = ++*page; 
		vgacard->setpage(pg); 
		q -= Footprint; 
		diff -= Footprint; 
		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    
 
	if(!rectclip(&r, gscreen.r) || tl<=0) 
		return; 
1994/0412    
 
	if(dolock) 
		cursorlock(r); 
1994/0415    
	lock(&loadlock); 
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; 
	page = off>>Footshift; 
	vgacard->setpage(page); 
	q = ((uchar*)gscreen.base) + (off&(Footprint-1)); 
 
	sw = gscreen.width*sizeof(ulong); 
	e = ((uchar*)gscreen.base) + Footprint; 
 
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/0412    
			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); 
			} 
			q += sw; 
1993/1116    
			data += l; 
		} 
1994/0412    
 
1994/0415    
	unlock(&loadlock); 
1994/0412    
	if(dolock) 
		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; 
		vgacard->setpage(pg); 
		q -= Footprint; 
		diff -= Footprint; 
	} 
	*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; 
		vgacard->setpage(pg); 
		q -= Footprint; 
		diff -= Footprint; 
	} 
1993/1116    
 
1994/0412    
	rem = e - q; 
1993/1116    
 
1994/0412    
	if(rem < len){ 
		memmove(data, q, rem); 
		pg = ++*page; 
		vgacard->setpage(pg); 
		q -= Footprint; 
		diff -= Footprint; 
		memmove(data+rem, q+rem, len-rem); 
	} else 
		memmove(data, q, len); 
 
	return diff; 
} 
 
/* 
 *   paste tile into hard 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 
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; 
 
	if(!rectclip(&r, gscreen.r) || tl<=0) 
1993/1116    
		return; 
 
1994/0412    
	if(dolock) 
		cursorlock(r); 
1994/0415    
	lock(&loadlock); 
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; 
	page = off>>Footshift; 
1993/1116    
	vgacard->setpage(page); 
1994/0412    
	q = ((uchar*)gscreen.base) + (off&(Footprint-1)); 
 
	sw = gscreen.width*sizeof(ulong); 
	e = ((uchar*)gscreen.base) + Footprint; 
 
	/* 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++){ 
			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); 
			} 
			q += sw; 
			data += l; 
		} 
 
1994/0415    
	unlock(&loadlock); 
1994/0412    
	if(dolock) 
		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); 
} 
 
/* 
 *  accessing registers 
 */ 
static uchar 
1993/0108    
srin(int i) { 
	outb(SRX, i); 
	return inb(SR); 
} 
1993/1116    
static void 
1992/1119    
genout(int reg, int val) 
{ 
	if(reg == 0) 
		outb(EMISCW, val); 
	else if (reg == 1) 
		outb(EFCW, val); 
} 
1993/1116    
static void 
1992/1119    
srout(int reg, int val) 
{ 
	outb(SRX, reg); 
	outb(SR, val); 
} 
1993/1116    
static void 
1992/1119    
grout(int reg, int val) 
{ 
	outb(GRX, reg); 
	outb(GR, val); 
} 
1993/1116    
static void 
1992/1119    
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); 
	} 
} 
1993/1116    
static void 
1992/1119    
crout(int reg, int val) 
{ 
	outb(CRX, reg); 
	outb(CR, val); 
} 
 
/* 
 *  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; 
} 
 
1993/1116    
/* 
1992/1119    
 *  paging routines for different cards 
 */ 
static void 
nopage(int page) 
{ 
	USED(page); 
1992/1216    
} 
1993/1116    
 
1993/0106    
/* 
1993/1116    
 * 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. 
1993/0106    
 */ 
1992/1216    
static void 
1993/0106    
atipage(int page) 
{ 
	/* the ext register is in the ATI ROM at a fixed address */ 
	ushort extreg = *((ushort *)0x800C0010); 
	uchar v; 
 
1993/1116    
	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); 
1993/0106    
} 
1993/1116    
 
1993/0206    
/* 
 * The following assumes that the new mode registers have been selected. 
 */ 
1993/0106    
static void 
1992/1216    
tridentpage(int page) 
{ 
1993/0915    
	srout(0xe, (srin(0xe)&0xf0) | page^0x2); 
1992/1119    
} 
static void 
tsengpage(int page) 
{ 
	outb(0x3cd, (page<<4)|page); 
1992/1124    
} 
static void 
1993/0915    
cirruspage(int page) 
{ 
	grout(0x9, page<<4); 
} 
static void 
1992/1124    
parapage(int page) 
{ 
1993/0915    
	grout(0x9, page<<4); 
1994/0311    
} 
static void 
s3page(int page) 
{ 
	uchar crt51; 
 
	/* 
1994/0323    
	 * I don't understand why these are different. 
1994/0311    
	 */ 
1994/0412    
	if(gscreen.ldepth == 3){ 
1994/0323    
		/* 
		 * The S3 registers need to be unlocked for this. 
		 * Let's hope they are already: 
		 *	crout(0x38, 0x48); 
		 *	crout(0x39, 0xA0); 
		 * 
		 * The page is 6 bits, the lower 4 bits in Crt35<3:0>, 
		 * the upper 2 in Crt51<3:2>. 
		 */ 
		crout(0x35, page & 0x0F); 
		outb(CRX, 0x51); 
		crt51 = (0xF3 & inb(CR))|((page & 0x30)>>2); 
		outb(CR, crt51); 
	} 
	else 
		crout(0x35, (page<<2) & 0x0C); 
1992/1119    
} 
 
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/0415    
	int from, to, tl, l; 
	uchar *a; 
1992/1119    
	Rectangle r; 
 
1994/0415    
	l = gscreen.width * BY2WD; 
	tl = graphicssubtile(0, l, gscreen.ldepth, gscreen.r, window, &a); 
 
	from = window.min.y + LINE2SCROLL*h; 
	to = window.min.y; 
	for(; from < window.max.y; from++){ 
		r = Rpt(Pt(window.min.x, from), Pt(window.max.x, from + 1)); 
		screenunload(r, (uchar*)scrollwork.base, tl, l, 1); 
		r = Rpt(Pt(window.min.x, to), Pt(window.max.x, to+1)); 
		screenload(r, (uchar*)scrollwork.base, tl, l, 1); 
	} 
		 
	curpos.y -= LINE2SCROLL*h; 
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: 
		x = 0xf; 
		break; 
	case 3: 
		x = 0xff; 
		break; 
	} 
	p &= x; 
	p ^= x; 
1993/1116    
	lock(&screenlock); 
1992/1119    
	*pr = colormap[p][0]; 
	*pg = colormap[p][1]; 
	*pb = colormap[p][2]; 
1993/1116    
	unlock(&screenlock); 
1992/1119    
} 
 
int 
setcolor(ulong p, ulong r, ulong g, ulong b) 
{ 
1993/1230    
	ulong x; 
 
	switch(gscreen.ldepth){ 
	default: 
		x = 0xf; 
		break; 
	case 3: 
		x = 0xff; 
		break; 
	} 
	p &= x; 
	p ^= x; 
1993/1116    
	lock(&screenlock); 
1992/1119    
	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)); 
1993/1116    
	unlock(&screenlock); 
1992/1119    
	return ~0; 
1994/0414    
} 
 
/* 
 *  software cursor 
 */ 
 
1994/0415    
/* 
 *  area to store the bits that are behind the cursor 
 */ 
ulong backbits[16*4]; 
1994/0414    
 
1994/0415    
/* 
 *  the white border around the cursor 
 */ 
1994/0414    
Bitmap	clr = 
{ 
	{0, 0, 16, 16}, 
	{0, 0, 16, 16}, 
	0, 
	0, 
	0, 
	1, 
}; 
 
1994/0415    
/* 
 *  the black center of the cursor 
 */ 
1994/0414    
Bitmap	set = 
{ 
	{0, 0, 16, 16}, 
	{0, 0, 16, 16}, 
	0, 
	0, 
	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 
setcursor(ulong *setbits, ulong *clrbits, int offx, int offy) 
{ 
	USED(offx, offy); 
	set.base = setbits; 
	clr.base = clrbits; 
} 
 
void 
cursoron(int dolock) 
{ 
	int off; 
	Rectangle r; 
	uchar *a; 
	struct { 
		Bitmap *dm; 
		Point p; 
		Bitmap *sm; 
		Rectangle r; 
		Fcode f; 
	} xx; 
 
	if(cursor.disable) 
		return; 
	if(dolock) 
		lock(&cursor); 
 
	if(cursor.visible++ == 0){ 
		cursor.r.min = mousexy(); 
		cursor.r.max = add(cursor.r.min, Pt(16, 16)); 
		cursor.r = raddp(cursor.r, cursor.offset); 
	 
		/* bit offset into backup area */ 
		if(cursor.r.min.x < 0) 
			off = cursor.r.min.x; 
		else 
			off = ((1<<gscreen.ldepth)*cursor.r.min.x) & 7; 
	 
		/* clip the cursor rectangle */ 
		xx.dm = &cursorwork; 
		xx.p = Pt(off, 0); 
		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 */ 
			r = Rect(0, 0, Dx(xx.r), Dy(xx.r)); 
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); 
} 
 
void 
cursoroff(int dolock) 
{ 
	if(cursor.disable) 
		return; 
	if(dolock) 
		lock(&cursor); 
	if(--cursor.visible == 0 && cursor.tl > 0) 
		screenload(cursor.clipr, (uchar*)backbits, cursor.tl, cursor.l, 0); 
	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); 
1992/1119    
} 


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