503 lines · 9.2 KB · C
RawDownload
/* * VGA controller */#include "u.h"#include "../port/lib.h"#include "mem.h"#include "dat.h"#include "fns.h"#include "io.h"#include "../port/error.h" #define	Image	IMAGE#include <draw.h>#include <memdraw.h>#include <cursor.h>#include "screen.h" enum {	Qdir,	Qvgabios,	Qvgactl,	Qvgaovl,	Qvgaovlctl,}; static Dirtab vgadir[] = {	".",	{ Qdir, 0, QTDIR },		0,	0550,	"vgabios",	{ Qvgabios, 0 },	0x100000, 0440,	"vgactl",		{ Qvgactl, 0 },		0,	0660,	"vgaovl",		{ Qvgaovl, 0 },		0,	0660,	"vgaovlctl",	{ Qvgaovlctl, 0 },	0, 	0660,}; enum {	CMactualsize,	CMblank,	CMblanktime,	CMdrawinit,	CMhwaccel,	CMhwblank,	CMhwgc,	CMlinear,	CMpalettedepth,	CMpanning,	CMsize,	CMtextmode,	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,	CMtextmode,	"textmode",	1,	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;} 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, nelem(vgadir), devgen);} static intvgastat(Chan* c, uchar* dp, int n){	return devstat(c, dp, n, vgadir, nelem(vgadir), 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, nelem(vgadir), 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->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, nelem(vgadir), devgen); 	case Qvgabios:		if(offset >= 0x100000)			return 0;		if(offset+n >= 0x100000)			n = 0x100000 - offset;		memmove(a, (uchar*)kaddr(0)+offset, n);		return n; 	case Qvgactl:		scr = &vgascreen[0]; 		p = malloc(READSTR);		if(p == nil)			error(Enomem);		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");		len += snprint(p+len, READSTR-len, "addr p %#P v %#p size %#ux\n", scr->paddr, scr->vaddr, scr->apsize);		USED(len); 		n = readstr(offset, a, n, p);		poperror();		free(p); 		return n; 	case Qvgaovl:	case Qvgaovlctl:		error(Ebadusefd);		break; 	default:		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(scr->gscreen == nil)			error("hwgc: no gscreen"); 		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;		}		if(strcmp(cb->f[1], "soft") == 0){			lock(&cursor);			swcursorinit();			if(scr->cur && scr->cur->disable)				scr->cur->disable(scr);			scr->cur = &swcursor;			if(scr->cur->enable)				scr->cur->enable(scr);			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 CMtextmode:		screeninit();		return; 	case CMsize:		x = strtoul(cb->f[1], &p, 0);		if(x == 0 || x > 10240)			error(Ebadarg);		if(*p)			p++; 		y = strtoul(p, &p, 0);		if(y == 0 || y > 10240)			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();		deletescreenimage();		if(screensize(x, y, z, chan))			error(Egreg);		vgascreenwin(scr);		resetscreenimage();		cursoron();		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:		if(scr->gscreen == nil)			error("drawinit: no gscreen");		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) < 0)			error("not enough free address space");		return;/*		case CMmemset:		memset((void*)strtoul(cb->f[1], 0, 0), atoi(cb->f[2]), atoi(cb->f[3]));		return;*/ 	case CMblank:		drawblankscreen(1);		return;		case CMunblank:		drawblankscreen(0);		return;		case CMblanktime:		blanktime = strtoul(cb->f[1], 0, 0);		return; 	case CMpanning:		if(strcmp(cb->f[1], "on") == 0){			if(scr == nil || scr->cur == nil)				error("set screen first");			if(!scr->cur->doespanning)				error("panning not supported");			scr->gscreen->clipr = scr->gscreen->r;			panning = 1;		}		else if(strcmp(cb->f[1], "off") == 0){			scr->gscreen->clipr = physgscreenr;			panning = 0;		}else			break;		return; 	case CMhwaccel:		if(strcmp(cb->f[1], "on") == 0)			hwaccel = 1;		else if(strcmp(cb->f[1], "off") == 0)			hwaccel = 0;		else			break;		return;		case CMhwblank:		if(strcmp(cb->f[1], "on") == 0)			hwblank = 1;		else if(strcmp(cb->f[1], "off") == 0)			hwblank = 0;		else			break;		return;	} 	cmderror(cb, "bad VGA control message");} char Enooverlay[] = "No overlay support"; static longvgawrite(Chan* c, void* a, long n, vlong off){	ulong offset = off;	Cmdbuf *cb;	VGAscr *scr; 	switch((ulong)c->qid.path){ 	case Qdir:		error(Eperm); 	case Qvgactl:		if(offset || n >= READSTR)			error(Ebadarg);		cb = parsecmd(a, n);		if(waserror()){			free(cb);			nexterror();		}		vgactl(cb);		poperror();		free(cb);		return n; 	case Qvgaovl:		scr = &vgascreen[0];		if (scr->dev == nil || scr->dev->ovlwrite == nil) {			error(Enooverlay);			break;		}		return scr->dev->ovlwrite(scr, a, n, off); 	case Qvgaovlctl:		scr = &vgascreen[0];		if (scr->dev == nil || scr->dev->ovlctl == nil) {			error(Enooverlay);			break;		}		scr->dev->ovlctl(scr, c, a, n);		return n; 	default:		error(Egreg);		break;	} 	return 0;} Dev vgadevtab = {	'v',	"vga", 	vgareset,	devinit,	devshutdown,	vgaattach,	vgawalk,	vgastat,	vgaopen,	devcreate,	vgaclose,	vgaread,	devbread,	vgawrite,	devbwrite,

Lines 1–500 of 503.