forsyth20121205-174063a80cc13 years agoHistory
620 lines · 10.8 KB · C
RawDownload
/* * VGA controller */#include "u.h"#include "../port/lib.h"#include "mem.h"#include "dat.h"#include "fns.h"#include "../port/error.h" #define	Image	IMAGE#include <draw.h>#include <memdraw.h>#include <cursor.h>#include "screen.h" typedef struct Vgaseg Vgaseg;struct Vgaseg {	QLock;	ulong	pa;	ulong	len;	void*	va;}; enum {	Nvgaseg = 4, 	Qdir = 0,	Qvgactl,	Qvgaovl,	Qvgaovlctl, 	Qsegs,	Qmax = Qsegs+Nvgaseg}; static Dirtab vgadir[Qmax] = {	".",	{ Qdir, 0, QTDIR },		0,	0550,	"vgactl",		{ Qvgactl, 0 },		0,	0660,	"vgaovl",		{ Qvgaovl, 0 },		0,	0660,	"vgaovlctl",	{ Qvgaovlctl, 0 },	0, 	0660,	/* dynamically-created memory segments are added here */}; static Vgaseg vgasegs[Nvgaseg];static Lock vgadirlock;static int nvgadir = Qsegs; enum {	CMactualsize,	CMblank,	CMblanktime,	CMdrawinit,	CMhwaccel,	CMhwblank,	CMhwgc,	CMlinear,	CMpalettedepth,	CMpanning,	CMsize,	CMtype,	CMunblank,}; static Cmdtab vgactlmsg[] = {	CMactualsize,	"actualsize",	2,	CMblank,	"blank",	1,	CMblanktime,	"blanktime",	2,	CMdrawinit,	"drawinit",	1,	CMhwaccel,	"hwaccel",	2,	CMhwblank,	"hwblank",	2,	CMhwgc,		"hwgc",		2,	CMlinear,	"linear",	0,	CMpalettedepth,	"palettedepth",	2,	CMpanning,	"panning",	2,	CMsize,		"size",		3,	CMtype,		"type",		2,	CMunblank,	"unblank",	1,}; static voidvgareset(void){	/* reserve the 'standard' vga registers */	if(ioalloc(0x2b0, 0x2df-0x2b0+1, 0, "vga") < 0)		panic("vga ports already allocated"); 	if(ioalloc(0x3c0, 0x3da-0x3c0+1, 0, "vga") < 0)		panic("vga ports already allocated"); 	conf.monitor = 1;} voidaddvgaseg(char *name, ulong pa, ulong size){	int i;	Dirtab d;	Vgaseg *s;	ulong va; 	va = mmukmap(pa, 0, size);	if(va == 0)		return;	memset(&d, 0, sizeof(d));	strecpy(d.name, d.name+sizeof(name), name);	lock(&vgadirlock);	for(i=0; i<nvgadir; i++)		if(strcmp(vgadir[i].name, name) == 0){			unlock(&vgadirlock);			print("devvga: duplicate segment %s\n", name);			return;		}	if(nvgadir >= nelem(vgadir)){		unlock(&vgadirlock);		print("devvga: segment %s: too many segments\n", name);		return;	}	d.qid.path = nvgadir;	d.perm = 0660;	d.length = size;	s = &vgasegs[nvgadir-Qsegs];	s->pa = pa;	s->len = size;	s->va = (void*)va;	vgadir[nvgadir] = d;	nvgadir++;	unlock(&vgadirlock);} static longvgasegrd(Vgaseg *s, uchar *buf, long n, ulong offset){	int i;	uchar *a, *d;	ulong v; 	if(offset >= s->len)		return 0;	if(offset+n > s->len)		n = s->len - offset;	d = (uchar*)s->va + offset;	qlock(s);	if(waserror()){		qunlock(s);		nexterror();	}	a = buf;	while(n > 0){		i = 4 - ((ulong)d & 3);		if(i > n)			i = n;		if(i == 3)			i = 2;		switch(i){		case 4:			v = (a[3]<<24) | (a[2]<<16) | (a[1]<<8) | a[0];			*(ulong*)d = v;			break;		case 2:			v = (a[1]<<8) | a[0];			*(ushort*)d = v;			break;		case 1:			*d = *a;			break;		}		d += i;		a += i;		n -= i;	}	poperror();	qunlock(s);	return a-buf;} static longvgasegwr(Vgaseg *s, uchar *buf, long n, ulong offset){	int i;	uchar *a, *r;	ulong v; 	if(offset >= s->len)		return 0;	if(offset+n > s->len)		n = s->len - offset;	r = (uchar*)s->va + offset;	qlock(s);	if(waserror()){		qunlock(s);		nexterror();	}	a = buf;	while(n > 0){		i = 4 - ((ulong)r & 3);		if(i > n)			i = n;		if(i == 3)			i = 2;		switch(i){		case 4:			v = *(ulong*)r;			a[0] = v;			a[1] = v>>8;			a[2] = v>>16;			a[3] = v>>24;			break;		case 2:			v = *(ushort*)r;			a[0] = v;			a[1] = v>>8;			break;		case 1:			*a = *r;			break;		}		r += i;		a += i;		n -= i;	}	poperror();	qunlock(s);	return a-buf;} static Chan*vgaattach(char* spec){	if(*spec && strcmp(spec, "0"))		error(Eio);	return devattach('v', spec);} Walkqid*vgawalk(Chan* c, Chan *nc, char** name, int nname){	return devwalk(c, nc, name, nname, vgadir, nvgadir, devgen);} static intvgastat(Chan* c, uchar* dp, int n){	return devstat(c, dp, n, vgadir, nvgadir, devgen);} static Chan*vgaopen(Chan* c, int omode){	VGAscr *scr;	static char *openctl = "openctl\n"; 	scr = &vgascreen[0];	if ((ulong)c->qid.path == Qvgaovlctl) {		if (scr->dev && scr->dev->ovlctl)			scr->dev->ovlctl(scr, c, openctl, strlen(openctl));		else 			error(Enonexist);	}	return devopen(c, omode, vgadir, nvgadir, devgen);} static voidvgaclose(Chan* c){	VGAscr *scr;	static char *closectl = "closectl\n"; 	scr = &vgascreen[0];	if((ulong)c->qid.path == Qvgaovlctl)		if(scr->dev && scr->dev->ovlctl){			if(waserror()){				print("ovlctl error: %s\n", up->env->errstr);				return;			}			scr->dev->ovlctl(scr, c, closectl, strlen(closectl));			poperror();		}} static voidcheckport(int start, int end){	/* standard vga regs are OK */	if(start >= 0x2b0 && end <= 0x2df+1)		return;	if(start >= 0x3c0 && end <= 0x3da+1)		return; 	if(iounused(start, end))		return;	error(Eperm);} static longvgaread(Chan* c, void* a, long n, vlong off){	int len;	char *p, *s;	VGAscr *scr;	ulong offset = off;	char chbuf[30]; 	switch((ulong)c->qid.path){ 	case Qdir:		return devdirread(c, a, n, vgadir, nvgadir, devgen); 	case Qvgactl:		scr = &vgascreen[0]; 		p = malloc(READSTR);		if(waserror()){			free(p);			nexterror();		} 		len = 0; 		if(scr->dev)			s = scr->dev->name;		else			s = "cga";		len += snprint(p+len, READSTR-len, "type %s\n", s); 		if(scr->gscreen) {			len += snprint(p+len, READSTR-len, "size %dx%dx%d %s\n",				scr->gscreen->r.max.x, scr->gscreen->r.max.y,				scr->gscreen->depth, chantostr(chbuf, scr->gscreen->chan)); 			if(Dx(scr->gscreen->r) != Dx(physgscreenr) 			|| Dy(scr->gscreen->r) != Dy(physgscreenr))				len += snprint(p+len, READSTR-len, "actualsize %dx%d\n",					physgscreenr.max.x, physgscreenr.max.y);		} 		len += snprint(p+len, READSTR-len, "blank time %lud idle %d state %s\n",			blanktime, drawidletime(), scr->isblank ? "off" : "on");		len += snprint(p+len, READSTR-len, "hwaccel %s\n", hwaccel ? "on" : "off");		len += snprint(p+len, READSTR-len, "hwblank %s\n", hwblank ? "on" : "off");		len += snprint(p+len, READSTR-len, "panning %s\n", panning ? "on" : "off");		snprint(p+len, READSTR-len, "addr 0x%lux\n", scr->aperture);		n = readstr(offset, a, n, p);		poperror();		free(p); 		return n; 	case Qvgaovl:	case Qvgaovlctl:		error(Ebadusefd);		break; 	default:		if(c->qid.path < nvgadir)			return vgasegrd(&vgasegs[c->qid.path], a, n, offset);		error(Egreg);		break;	} 	return 0;} static char Ebusy[] = "vga already configured"; static voidvgactl(Cmdbuf *cb){	int align, i, size, x, y, z;	char *chanstr, *p;	ulong chan;	Cmdtab *ct;	VGAscr *scr;	extern VGAdev *vgadev[];	extern VGAcur *vgacur[]; 	scr = &vgascreen[0];	ct = lookupcmd(cb, vgactlmsg, nelem(vgactlmsg));	switch(ct->index){	case CMhwgc:		if(strcmp(cb->f[1], "off") == 0){			lock(&cursor);			if(scr->cur){				if(scr->cur->disable)					scr->cur->disable(scr);				scr->cur = nil;			}			unlock(&cursor);			return;		} 		for(i = 0; vgacur[i]; i++){			if(strcmp(cb->f[1], vgacur[i]->name))				continue;			lock(&cursor);			if(scr->cur && scr->cur->disable)				scr->cur->disable(scr);			scr->cur = vgacur[i];			if(scr->cur->enable)				scr->cur->enable(scr);			unlock(&cursor);			return;		}		break; 	case CMtype:		for(i = 0; vgadev[i]; i++){			if(strcmp(cb->f[1], vgadev[i]->name))				continue;			if(scr->dev && scr->dev->disable)				scr->dev->disable(scr);			scr->dev = vgadev[i];			if(scr->dev->enable)				scr->dev->enable(scr);			return;		}		break; 	case CMsize:		if(drawhasclients())			error(Ebusy); 		x = strtoul(cb->f[1], &p, 0);		if(x == 0 || x > 2048)			error(Ebadarg);		if(*p)			p++; 		y = strtoul(p, &p, 0);		if(y == 0 || y > 2048)			error(Ebadarg);		if(*p)			p++; 		z = strtoul(p, &p, 0); 		chanstr = cb->f[2];		if((chan = strtochan(chanstr)) == 0)			error("bad channel"); 		if(chantodepth(chan) != z)			error("depth, channel do not match"); 		cursoroff(1);		deletescreenimage();		if(screensize(x, y, z, chan))			error(Egreg);		vgascreenwin(scr);		cursoron(1);		return; 	case CMactualsize:		if(scr->gscreen == nil)			error("set the screen size first"); 		x = strtoul(cb->f[1], &p, 0);		if(x == 0 || x > 2048)			error(Ebadarg);		if(*p)			p++; 		y = strtoul(p, nil, 0);		if(y == 0 || y > 2048)			error(Ebadarg); 		if(x > scr->gscreen->r.max.x || y > scr->gscreen->r.max.y)			error("physical screen bigger than virtual"); 		physgscreenr = Rect(0,0,x,y);		scr->gscreen->clipr = physgscreenr;		return;		case CMpalettedepth:		x = strtoul(cb->f[1], &p, 0);		if(x != 8 && x != 6)			error(Ebadarg); 		scr->palettedepth = x;		return; 	case CMdrawinit:		memimagedraw(scr->gscreen, scr->gscreen->r, memblack, ZP, nil, ZP, S);		if(scr && scr->dev && scr->dev->drawinit)			scr->dev->drawinit(scr);		return;		case CMlinear:		if(cb->nf!=2 && cb->nf!=3)			error(Ebadarg);		size = strtoul(cb->f[1], 0, 0);		if(cb->nf == 2)			align = 0;		else			align = strtoul(cb->f[2], 0, 0);		if(screenaperture(size, align))			error("not enough free address space");		return; 	case CMblank:		drawblankscreen(1);		return;	

Lines 1–500 of 620.