xref: /plan9/sys/src/9/pc/devvga.c (revision aa72973a2891ccbd3fb042462446761159389e19)
17dd7cddfSDavid du Colombier /*
27dd7cddfSDavid du Colombier  * VGA controller
37dd7cddfSDavid du Colombier  */
4bd389b36SDavid du Colombier #include "u.h"
5bd389b36SDavid du Colombier #include "../port/lib.h"
6bd389b36SDavid du Colombier #include "mem.h"
7bd389b36SDavid du Colombier #include "dat.h"
8bd389b36SDavid du Colombier #include "fns.h"
94de34a7eSDavid du Colombier #include "io.h"
10bd389b36SDavid du Colombier #include "../port/error.h"
11bd389b36SDavid du Colombier 
127dd7cddfSDavid du Colombier #define	Image	IMAGE
137dd7cddfSDavid du Colombier #include <draw.h>
147dd7cddfSDavid du Colombier #include <memdraw.h>
157dd7cddfSDavid du Colombier #include <cursor.h>
16bd389b36SDavid du Colombier #include "screen.h"
17bd389b36SDavid du Colombier 
18219b2ee8SDavid du Colombier enum {
197dd7cddfSDavid du Colombier 	Qdir,
204de34a7eSDavid du Colombier 	Qvgabios,
217dd7cddfSDavid du Colombier 	Qvgactl,
229a747e4fSDavid du Colombier 	Qvgaovl,
239a747e4fSDavid du Colombier 	Qvgaovlctl,
24bd389b36SDavid du Colombier };
25bd389b36SDavid du Colombier 
267dd7cddfSDavid du Colombier static Dirtab vgadir[] = {
279a747e4fSDavid du Colombier 	".",	{ Qdir, 0, QTDIR },		0,	0550,
284de34a7eSDavid du Colombier 	"vgabios",	{ Qvgabios, 0 },	0x100000, 0440,
297dd7cddfSDavid du Colombier 	"vgactl",		{ Qvgactl, 0 },		0,	0660,
309a747e4fSDavid du Colombier 	"vgaovl",		{ Qvgaovl, 0 },		0,	0660,
319a747e4fSDavid du Colombier 	"vgaovlctl",	{ Qvgaovlctl, 0 },	0, 	0660,
329a747e4fSDavid du Colombier };
339a747e4fSDavid du Colombier 
349a747e4fSDavid du Colombier enum {
359a747e4fSDavid du Colombier 	CMactualsize,
369a747e4fSDavid du Colombier 	CMblank,
379a747e4fSDavid du Colombier 	CMblanktime,
389a747e4fSDavid du Colombier 	CMdrawinit,
399a747e4fSDavid du Colombier 	CMhwaccel,
409a747e4fSDavid du Colombier 	CMhwblank,
419a747e4fSDavid du Colombier 	CMhwgc,
429a747e4fSDavid du Colombier 	CMlinear,
439a747e4fSDavid du Colombier 	CMpalettedepth,
449a747e4fSDavid du Colombier 	CMpanning,
459a747e4fSDavid du Colombier 	CMsize,
464de34a7eSDavid du Colombier 	CMtextmode,
479a747e4fSDavid du Colombier 	CMtype,
4839734e7eSDavid du Colombier 	CMunblank,
499a747e4fSDavid du Colombier };
509a747e4fSDavid du Colombier 
519a747e4fSDavid du Colombier static Cmdtab vgactlmsg[] = {
529a747e4fSDavid du Colombier 	CMactualsize,	"actualsize",	2,
539a747e4fSDavid du Colombier 	CMblank,	"blank",	1,
549a747e4fSDavid du Colombier 	CMblanktime,	"blanktime",	2,
559a747e4fSDavid du Colombier 	CMdrawinit,	"drawinit",	1,
569a747e4fSDavid du Colombier 	CMhwaccel,	"hwaccel",	2,
579a747e4fSDavid du Colombier 	CMhwblank,	"hwblank",	2,
589a747e4fSDavid du Colombier 	CMhwgc,		"hwgc",		2,
599a747e4fSDavid du Colombier 	CMlinear,	"linear",	0,
609a747e4fSDavid du Colombier 	CMpalettedepth,	"palettedepth",	2,
619a747e4fSDavid du Colombier 	CMpanning,	"panning",	2,
629a747e4fSDavid du Colombier 	CMsize,		"size",		3,
634de34a7eSDavid du Colombier 	CMtextmode,	"textmode",	1,
649a747e4fSDavid du Colombier 	CMtype,		"type",		2,
6539734e7eSDavid du Colombier 	CMunblank,	"unblank",	1,
667dd7cddfSDavid du Colombier };
677dd7cddfSDavid du Colombier 
687dd7cddfSDavid du Colombier static void
vgareset(void)69bd389b36SDavid du Colombier vgareset(void)
70bd389b36SDavid du Colombier {
717dd7cddfSDavid du Colombier 	/* reserve the 'standard' vga registers */
727dd7cddfSDavid du Colombier 	if(ioalloc(0x2b0, 0x2df-0x2b0+1, 0, "vga") < 0)
737dd7cddfSDavid du Colombier 		panic("vga ports already allocated");
747dd7cddfSDavid du Colombier 	if(ioalloc(0x3c0, 0x3da-0x3c0+1, 0, "vga") < 0)
757dd7cddfSDavid du Colombier 		panic("vga ports already allocated");
767dd7cddfSDavid du Colombier 	conf.monitor = 1;
77bd389b36SDavid du Colombier }
78bd389b36SDavid du Colombier 
797dd7cddfSDavid du Colombier static Chan*
vgaattach(char * spec)807dd7cddfSDavid du Colombier vgaattach(char* spec)
81bd389b36SDavid du Colombier {
827dd7cddfSDavid du Colombier 	if(*spec && strcmp(spec, "0"))
837dd7cddfSDavid du Colombier 		error(Eio);
847dd7cddfSDavid du Colombier 	return devattach('v', spec);
85bd389b36SDavid du Colombier }
86bd389b36SDavid du Colombier 
879a747e4fSDavid du Colombier Walkqid*
vgawalk(Chan * c,Chan * nc,char ** name,int nname)889a747e4fSDavid du Colombier vgawalk(Chan* c, Chan *nc, char** name, int nname)
89bd389b36SDavid du Colombier {
909a747e4fSDavid du Colombier 	return devwalk(c, nc, name, nname, vgadir, nelem(vgadir), devgen);
91bd389b36SDavid du Colombier }
92bd389b36SDavid du Colombier 
939a747e4fSDavid du Colombier static int
vgastat(Chan * c,uchar * dp,int n)949a747e4fSDavid du Colombier vgastat(Chan* c, uchar* dp, int n)
95219b2ee8SDavid du Colombier {
969a747e4fSDavid du Colombier 	return devstat(c, dp, n, vgadir, nelem(vgadir), devgen);
977dd7cddfSDavid du Colombier }
98219b2ee8SDavid du Colombier 
997dd7cddfSDavid du Colombier static Chan*
vgaopen(Chan * c,int omode)1007dd7cddfSDavid du Colombier vgaopen(Chan* c, int omode)
1017dd7cddfSDavid du Colombier {
1029a747e4fSDavid du Colombier 	VGAscr *scr;
1039a747e4fSDavid du Colombier 	static char *openctl = "openctl\n";
1049a747e4fSDavid du Colombier 
1059a747e4fSDavid du Colombier 	scr = &vgascreen[0];
1069a747e4fSDavid du Colombier 	if ((ulong)c->qid.path == Qvgaovlctl) {
107b7b24591SDavid du Colombier 		if (scr->dev && scr->dev->ovlctl)
1089a747e4fSDavid du Colombier 			scr->dev->ovlctl(scr, c, openctl, strlen(openctl));
1099a747e4fSDavid du Colombier 		else
1109a747e4fSDavid du Colombier 			error(Enonexist);
1119a747e4fSDavid du Colombier 	}
1127dd7cddfSDavid du Colombier 	return devopen(c, omode, vgadir, nelem(vgadir), devgen);
1137dd7cddfSDavid du Colombier }
1147dd7cddfSDavid du Colombier 
1157dd7cddfSDavid du Colombier static void
vgaclose(Chan * c)1169a747e4fSDavid du Colombier vgaclose(Chan* c)
1177dd7cddfSDavid du Colombier {
1189a747e4fSDavid du Colombier 	VGAscr *scr;
1199a747e4fSDavid du Colombier 	static char *closectl = "closectl\n";
1209a747e4fSDavid du Colombier 
1219a747e4fSDavid du Colombier 	scr = &vgascreen[0];
1229a747e4fSDavid du Colombier 	if((ulong)c->qid.path == Qvgaovlctl)
123b7b24591SDavid du Colombier 		if(scr->dev && scr->dev->ovlctl){
1249a747e4fSDavid du Colombier 			if(waserror()){
1259a747e4fSDavid du Colombier 				print("ovlctl error: %s\n", up->errstr);
1269a747e4fSDavid du Colombier 				return;
1279a747e4fSDavid du Colombier 			}
1289a747e4fSDavid du Colombier 			scr->dev->ovlctl(scr, c, closectl, strlen(closectl));
1299a747e4fSDavid du Colombier 			poperror();
1309a747e4fSDavid du Colombier 		}
1317dd7cddfSDavid du Colombier }
1327dd7cddfSDavid du Colombier 
1337dd7cddfSDavid du Colombier static void
checkport(int start,int end)1347dd7cddfSDavid du Colombier checkport(int start, int end)
1357dd7cddfSDavid du Colombier {
1367dd7cddfSDavid du Colombier 	/* standard vga regs are OK */
1377dd7cddfSDavid du Colombier 	if(start >= 0x2b0 && end <= 0x2df+1)
1387dd7cddfSDavid du Colombier 		return;
1397dd7cddfSDavid du Colombier 	if(start >= 0x3c0 && end <= 0x3da+1)
1407dd7cddfSDavid du Colombier 		return;
1417dd7cddfSDavid du Colombier 
1427dd7cddfSDavid du Colombier 	if(iounused(start, end))
1437dd7cddfSDavid du Colombier 		return;
1447dd7cddfSDavid du Colombier 	error(Eperm);
1457dd7cddfSDavid du Colombier }
1467dd7cddfSDavid du Colombier 
1477dd7cddfSDavid du Colombier static long
vgaread(Chan * c,void * a,long n,vlong off)1487dd7cddfSDavid du Colombier vgaread(Chan* c, void* a, long n, vlong off)
1497dd7cddfSDavid du Colombier {
1507dd7cddfSDavid du Colombier 	int len;
1517dd7cddfSDavid du Colombier 	char *p, *s;
1527dd7cddfSDavid du Colombier 	VGAscr *scr;
1537dd7cddfSDavid du Colombier 	ulong offset = off;
1547dd7cddfSDavid du Colombier 	char chbuf[30];
1557dd7cddfSDavid du Colombier 
1569a747e4fSDavid du Colombier 	switch((ulong)c->qid.path){
1577dd7cddfSDavid du Colombier 
1587dd7cddfSDavid du Colombier 	case Qdir:
1597dd7cddfSDavid du Colombier 		return devdirread(c, a, n, vgadir, nelem(vgadir), devgen);
1607dd7cddfSDavid du Colombier 
1614de34a7eSDavid du Colombier 	case Qvgabios:
1624de34a7eSDavid du Colombier 		if(offset >= 0x100000)
1634de34a7eSDavid du Colombier 			return 0;
1644de34a7eSDavid du Colombier 		if(offset+n >= 0x100000)
1654de34a7eSDavid du Colombier 			n = 0x100000 - offset;
1664de34a7eSDavid du Colombier 		memmove(a, (uchar*)kaddr(0)+offset, n);
1674de34a7eSDavid du Colombier 		return n;
1684de34a7eSDavid du Colombier 
1697dd7cddfSDavid du Colombier 	case Qvgactl:
1707dd7cddfSDavid du Colombier 		scr = &vgascreen[0];
1717dd7cddfSDavid du Colombier 
1727dd7cddfSDavid du Colombier 		p = malloc(READSTR);
173*aa72973aSDavid du Colombier 		if(p == nil)
174*aa72973aSDavid du Colombier 			error(Enomem);
1757dd7cddfSDavid du Colombier 		if(waserror()){
1767dd7cddfSDavid du Colombier 			free(p);
1777dd7cddfSDavid du Colombier 			nexterror();
1787dd7cddfSDavid du Colombier 		}
1797dd7cddfSDavid du Colombier 
1807dd7cddfSDavid du Colombier 		len = 0;
1817dd7cddfSDavid du Colombier 
1827dd7cddfSDavid du Colombier 		if(scr->dev)
1837dd7cddfSDavid du Colombier 			s = scr->dev->name;
1847dd7cddfSDavid du Colombier 		else
1857dd7cddfSDavid du Colombier 			s = "cga";
1867dd7cddfSDavid du Colombier 		len += snprint(p+len, READSTR-len, "type %s\n", s);
1877dd7cddfSDavid du Colombier 
1887dd7cddfSDavid du Colombier 		if(scr->gscreen) {
1897dd7cddfSDavid du Colombier 			len += snprint(p+len, READSTR-len, "size %dx%dx%d %s\n",
1907dd7cddfSDavid du Colombier 				scr->gscreen->r.max.x, scr->gscreen->r.max.y,
1917dd7cddfSDavid du Colombier 				scr->gscreen->depth, chantostr(chbuf, scr->gscreen->chan));
1927dd7cddfSDavid du Colombier 
1937dd7cddfSDavid du Colombier 			if(Dx(scr->gscreen->r) != Dx(physgscreenr)
1947dd7cddfSDavid du Colombier 			|| Dy(scr->gscreen->r) != Dy(physgscreenr))
1957dd7cddfSDavid du Colombier 				len += snprint(p+len, READSTR-len, "actualsize %dx%d\n",
1967dd7cddfSDavid du Colombier 					physgscreenr.max.x, physgscreenr.max.y);
1977dd7cddfSDavid du Colombier 		}
1987dd7cddfSDavid du Colombier 
1996a9fc400SDavid du Colombier 		len += snprint(p+len, READSTR-len, "blank time %lud idle %d state %s\n",
2006a9fc400SDavid du Colombier 			blanktime, drawidletime(), scr->isblank ? "off" : "on");
2017dd7cddfSDavid du Colombier 		len += snprint(p+len, READSTR-len, "hwaccel %s\n", hwaccel ? "on" : "off");
2027dd7cddfSDavid du Colombier 		len += snprint(p+len, READSTR-len, "hwblank %s\n", hwblank ? "on" : "off");
2039a747e4fSDavid du Colombier 		len += snprint(p+len, READSTR-len, "panning %s\n", panning ? "on" : "off");
2044de34a7eSDavid du Colombier 		len += snprint(p+len, READSTR-len, "addr p 0x%lux v 0x%p size 0x%ux\n", scr->paddr, scr->vaddr, scr->apsize);
2054de34a7eSDavid du Colombier 		USED(len);
2064de34a7eSDavid du Colombier 
2077dd7cddfSDavid du Colombier 		n = readstr(offset, a, n, p);
2087dd7cddfSDavid du Colombier 		poperror();
2097dd7cddfSDavid du Colombier 		free(p);
2107dd7cddfSDavid du Colombier 
2117dd7cddfSDavid du Colombier 		return n;
2127dd7cddfSDavid du Colombier 
2139a747e4fSDavid du Colombier 	case Qvgaovl:
2149a747e4fSDavid du Colombier 	case Qvgaovlctl:
2159a747e4fSDavid du Colombier 		error(Ebadusefd);
2169a747e4fSDavid du Colombier 		break;
2179a747e4fSDavid du Colombier 
2187dd7cddfSDavid du Colombier 	default:
2197dd7cddfSDavid du Colombier 		error(Egreg);
2207dd7cddfSDavid du Colombier 		break;
2217dd7cddfSDavid du Colombier 	}
2227dd7cddfSDavid du Colombier 
2237dd7cddfSDavid du Colombier 	return 0;
2247dd7cddfSDavid du Colombier }
2257dd7cddfSDavid du Colombier 
2267dd7cddfSDavid du Colombier static char Ebusy[] = "vga already configured";
2277dd7cddfSDavid du Colombier 
2287dd7cddfSDavid du Colombier static void
vgactl(Cmdbuf * cb)2299a747e4fSDavid du Colombier vgactl(Cmdbuf *cb)
2307dd7cddfSDavid du Colombier {
2319a747e4fSDavid du Colombier 	int align, i, size, x, y, z;
2329a747e4fSDavid du Colombier 	char *chanstr, *p;
2337dd7cddfSDavid du Colombier 	ulong chan;
2349a747e4fSDavid du Colombier 	Cmdtab *ct;
2357dd7cddfSDavid du Colombier 	VGAscr *scr;
2367dd7cddfSDavid du Colombier 	extern VGAdev *vgadev[];
2377dd7cddfSDavid du Colombier 	extern VGAcur *vgacur[];
238219b2ee8SDavid du Colombier 
2397dd7cddfSDavid du Colombier 	scr = &vgascreen[0];
2409a747e4fSDavid du Colombier 	ct = lookupcmd(cb, vgactlmsg, nelem(vgactlmsg));
2419a747e4fSDavid du Colombier 	switch(ct->index){
2429a747e4fSDavid du Colombier 	case CMhwgc:
2439a747e4fSDavid du Colombier 		if(strcmp(cb->f[1], "off") == 0){
2447dd7cddfSDavid du Colombier 			lock(&cursor);
2457dd7cddfSDavid du Colombier 			if(scr->cur){
2467dd7cddfSDavid du Colombier 				if(scr->cur->disable)
2477dd7cddfSDavid du Colombier 					scr->cur->disable(scr);
2487dd7cddfSDavid du Colombier 				scr->cur = nil;
249219b2ee8SDavid du Colombier 			}
2507dd7cddfSDavid du Colombier 			unlock(&cursor);
251219b2ee8SDavid du Colombier 			return;
252219b2ee8SDavid du Colombier 		}
2534de34a7eSDavid du Colombier 		if(strcmp(cb->f[1], "soft") == 0){
2544de34a7eSDavid du Colombier 			lock(&cursor);
2554de34a7eSDavid du Colombier 			swcursorinit();
2564de34a7eSDavid du Colombier 			if(scr->cur && scr->cur->disable)
2574de34a7eSDavid du Colombier 				scr->cur->disable(scr);
2584de34a7eSDavid du Colombier 			scr->cur = &swcursor;
2594de34a7eSDavid du Colombier 			if(scr->cur->enable)
2604de34a7eSDavid du Colombier 				scr->cur->enable(scr);
2614de34a7eSDavid du Colombier 			unlock(&cursor);
2624de34a7eSDavid du Colombier 			return;
2634de34a7eSDavid du Colombier 		}
2647dd7cddfSDavid du Colombier 		for(i = 0; vgacur[i]; i++){
2659a747e4fSDavid du Colombier 			if(strcmp(cb->f[1], vgacur[i]->name))
2667dd7cddfSDavid du Colombier 				continue;
2677dd7cddfSDavid du Colombier 			lock(&cursor);
2687dd7cddfSDavid du Colombier 			if(scr->cur && scr->cur->disable)
2697dd7cddfSDavid du Colombier 				scr->cur->disable(scr);
2707dd7cddfSDavid du Colombier 			scr->cur = vgacur[i];
2717dd7cddfSDavid du Colombier 			if(scr->cur->enable)
2727dd7cddfSDavid du Colombier 				scr->cur->enable(scr);
2737dd7cddfSDavid du Colombier 			unlock(&cursor);
274219b2ee8SDavid du Colombier 			return;
275219b2ee8SDavid du Colombier 		}
2769a747e4fSDavid du Colombier 		break;
2777dd7cddfSDavid du Colombier 
2789a747e4fSDavid du Colombier 	case CMtype:
2797dd7cddfSDavid du Colombier 		for(i = 0; vgadev[i]; i++){
2809a747e4fSDavid du Colombier 			if(strcmp(cb->f[1], vgadev[i]->name))
2817dd7cddfSDavid du Colombier 				continue;
2827dd7cddfSDavid du Colombier 			if(scr->dev && scr->dev->disable)
2837dd7cddfSDavid du Colombier 				scr->dev->disable(scr);
2847dd7cddfSDavid du Colombier 			scr->dev = vgadev[i];
2857dd7cddfSDavid du Colombier 			if(scr->dev->enable)
2867dd7cddfSDavid du Colombier 				scr->dev->enable(scr);
287219b2ee8SDavid du Colombier 			return;
288219b2ee8SDavid du Colombier 		}
2899a747e4fSDavid du Colombier 		break;
2909a747e4fSDavid du Colombier 
2914de34a7eSDavid du Colombier 	case CMtextmode:
2924de34a7eSDavid du Colombier 		screeninit();
2934de34a7eSDavid du Colombier 		return;
2944de34a7eSDavid du Colombier 
2959a747e4fSDavid du Colombier 	case CMsize:
2969a747e4fSDavid du Colombier 		x = strtoul(cb->f[1], &p, 0);
297868c5196SDavid du Colombier 		if(x == 0 || x > 10240)
298219b2ee8SDavid du Colombier 			error(Ebadarg);
2997dd7cddfSDavid du Colombier 		if(*p)
3007dd7cddfSDavid du Colombier 			p++;
301219b2ee8SDavid du Colombier 
3027dd7cddfSDavid du Colombier 		y = strtoul(p, &p, 0);
303868c5196SDavid du Colombier 		if(y == 0 || y > 10240)
304219b2ee8SDavid du Colombier 			error(Ebadarg);
3057dd7cddfSDavid du Colombier 		if(*p)
3067dd7cddfSDavid du Colombier 			p++;
307219b2ee8SDavid du Colombier 
3087dd7cddfSDavid du Colombier 		z = strtoul(p, &p, 0);
3097dd7cddfSDavid du Colombier 
3109a747e4fSDavid du Colombier 		chanstr = cb->f[2];
3117dd7cddfSDavid du Colombier 		if((chan = strtochan(chanstr)) == 0)
3127dd7cddfSDavid du Colombier 			error("bad channel");
3137dd7cddfSDavid du Colombier 
3147dd7cddfSDavid du Colombier 		if(chantodepth(chan) != z)
3157dd7cddfSDavid du Colombier 			error("depth, channel do not match");
316219b2ee8SDavid du Colombier 
317219b2ee8SDavid du Colombier 		cursoroff(1);
3187dd7cddfSDavid du Colombier 		deletescreenimage();
3197dd7cddfSDavid du Colombier 		if(screensize(x, y, z, chan))
3207dd7cddfSDavid du Colombier 			error(Egreg);
3217dd7cddfSDavid du Colombier 		vgascreenwin(scr);
3224de34a7eSDavid du Colombier 		resetscreenimage();
323219b2ee8SDavid du Colombier 		cursoron(1);
324219b2ee8SDavid du Colombier 		return;
3259a747e4fSDavid du Colombier 
3269a747e4fSDavid du Colombier 	case CMactualsize:
3277dd7cddfSDavid du Colombier 		if(scr->gscreen == nil)
3287dd7cddfSDavid du Colombier 			error("set the screen size first");
3297dd7cddfSDavid du Colombier 
3309a747e4fSDavid du Colombier 		x = strtoul(cb->f[1], &p, 0);
3317dd7cddfSDavid du Colombier 		if(x == 0 || x > 2048)
3327dd7cddfSDavid du Colombier 			error(Ebadarg);
3337dd7cddfSDavid du Colombier 		if(*p)
3347dd7cddfSDavid du Colombier 			p++;
3357dd7cddfSDavid du Colombier 
3367dd7cddfSDavid du Colombier 		y = strtoul(p, nil, 0);
3377dd7cddfSDavid du Colombier 		if(y == 0 || y > 2048)
3387dd7cddfSDavid du Colombier 			error(Ebadarg);
3397dd7cddfSDavid du Colombier 
3407dd7cddfSDavid du Colombier 		if(x > scr->gscreen->r.max.x || y > scr->gscreen->r.max.y)
3417dd7cddfSDavid du Colombier 			error("physical screen bigger than virtual");
3427dd7cddfSDavid du Colombier 
3439a747e4fSDavid du Colombier 		physgscreenr = Rect(0,0,x,y);
3449a747e4fSDavid du Colombier 		scr->gscreen->clipr = physgscreenr;
3457dd7cddfSDavid du Colombier 		return;
3467dd7cddfSDavid du Colombier 
3479a747e4fSDavid du Colombier 	case CMpalettedepth:
3489a747e4fSDavid du Colombier 		x = strtoul(cb->f[1], &p, 0);
3497dd7cddfSDavid du Colombier 		if(x != 8 && x != 6)
3507dd7cddfSDavid du Colombier 			error(Ebadarg);
3517dd7cddfSDavid du Colombier 
3527dd7cddfSDavid du Colombier 		scr->palettedepth = x;
3537dd7cddfSDavid du Colombier 		return;
3549a747e4fSDavid du Colombier 
3559a747e4fSDavid du Colombier 	case CMdrawinit:
356cb8c047aSDavid du Colombier 		if(scr->gscreen == nil)
357cb8c047aSDavid du Colombier 			error("drawinit: no gscreen");
358cb8c047aSDavid du Colombier 		if(scr->dev && scr->dev->drawinit)
3597dd7cddfSDavid du Colombier 			scr->dev->drawinit(scr);
3607dd7cddfSDavid du Colombier 		return;
3617dd7cddfSDavid du Colombier 
3629a747e4fSDavid du Colombier 	case CMlinear:
3639a747e4fSDavid du Colombier 		if(cb->nf!=2 && cb->nf!=3)
3649a747e4fSDavid du Colombier 			error(Ebadarg);
3659a747e4fSDavid du Colombier 		size = strtoul(cb->f[1], 0, 0);
3669a747e4fSDavid du Colombier 		if(cb->nf == 2)
3677dd7cddfSDavid du Colombier 			align = 0;
3687dd7cddfSDavid du Colombier 		else
3699a747e4fSDavid du Colombier 			align = strtoul(cb->f[2], 0, 0);
3704de34a7eSDavid du Colombier 		if(screenaperture(size, align) < 0)
3717dd7cddfSDavid du Colombier 			error("not enough free address space");
3727dd7cddfSDavid du Colombier 		return;
3739a747e4fSDavid du Colombier /*
3749a747e4fSDavid du Colombier 	case CMmemset:
3759a747e4fSDavid du Colombier 		memset((void*)strtoul(cb->f[1], 0, 0), atoi(cb->f[2]), atoi(cb->f[3]));
3767dd7cddfSDavid du Colombier 		return;
3777dd7cddfSDavid du Colombier */
3789a747e4fSDavid du Colombier 
3799a747e4fSDavid du Colombier 	case CMblank:
3807dd7cddfSDavid du Colombier 		drawblankscreen(1);
3817dd7cddfSDavid du Colombier 		return;
3829a747e4fSDavid du Colombier 
38339734e7eSDavid du Colombier 	case CMunblank:
38439734e7eSDavid du Colombier 		drawblankscreen(0);
38539734e7eSDavid du Colombier 		return;
38639734e7eSDavid du Colombier 
3879a747e4fSDavid du Colombier 	case CMblanktime:
3889a747e4fSDavid du Colombier 		blanktime = strtoul(cb->f[1], 0, 0);
3897dd7cddfSDavid du Colombier 		return;
3909a747e4fSDavid du Colombier 
3919a747e4fSDavid du Colombier 	case CMpanning:
3929a747e4fSDavid du Colombier 		if(strcmp(cb->f[1], "on") == 0){
3939a747e4fSDavid du Colombier 			if(scr == nil || scr->cur == nil)
3949a747e4fSDavid du Colombier 				error("set screen first");
3959a747e4fSDavid du Colombier 			if(!scr->cur->doespanning)
3969a747e4fSDavid du Colombier 				error("panning not supported");
3979a747e4fSDavid du Colombier 			scr->gscreen->clipr = scr->gscreen->r;
3989a747e4fSDavid du Colombier 			panning = 1;
3997dd7cddfSDavid du Colombier 		}
4009a747e4fSDavid du Colombier 		else if(strcmp(cb->f[1], "off") == 0){
4019a747e4fSDavid du Colombier 			scr->gscreen->clipr = physgscreenr;
4029a747e4fSDavid du Colombier 			panning = 0;
4039a747e4fSDavid du Colombier 		}else
4049a747e4fSDavid du Colombier 			break;
4059a747e4fSDavid du Colombier 		return;
4069a747e4fSDavid du Colombier 
4079a747e4fSDavid du Colombier 	case CMhwaccel:
4089a747e4fSDavid du Colombier 		if(strcmp(cb->f[1], "on") == 0)
4097dd7cddfSDavid du Colombier 			hwaccel = 1;
4109a747e4fSDavid du Colombier 		else if(strcmp(cb->f[1], "off") == 0)
4117dd7cddfSDavid du Colombier 			hwaccel = 0;
4127dd7cddfSDavid du Colombier 		else
4139a747e4fSDavid du Colombier 			break;
4147dd7cddfSDavid du Colombier 		return;
4159a747e4fSDavid du Colombier 
4169a747e4fSDavid du Colombier 	case CMhwblank:
4179a747e4fSDavid du Colombier 		if(strcmp(cb->f[1], "on") == 0)
4187dd7cddfSDavid du Colombier 			hwblank = 1;
4199a747e4fSDavid du Colombier 		else if(strcmp(cb->f[1], "off") == 0)
4207dd7cddfSDavid du Colombier 			hwblank = 0;
4217dd7cddfSDavid du Colombier 		else
4229a747e4fSDavid du Colombier 			break;
4237dd7cddfSDavid du Colombier 		return;
4247dd7cddfSDavid du Colombier 	}
425219b2ee8SDavid du Colombier 
4269a747e4fSDavid du Colombier 	cmderror(cb, "bad VGA control message");
427219b2ee8SDavid du Colombier }
428219b2ee8SDavid du Colombier 
4299a747e4fSDavid du Colombier char Enooverlay[] = "No overlay support";
4309a747e4fSDavid du Colombier 
4317dd7cddfSDavid du Colombier static long
vgawrite(Chan * c,void * a,long n,vlong off)4327dd7cddfSDavid du Colombier vgawrite(Chan* c, void* a, long n, vlong off)
433bd389b36SDavid du Colombier {
4347dd7cddfSDavid du Colombier 	ulong offset = off;
4359a747e4fSDavid du Colombier 	Cmdbuf *cb;
4369a747e4fSDavid du Colombier 	VGAscr *scr;
437bd389b36SDavid du Colombier 
4389a747e4fSDavid du Colombier 	switch((ulong)c->qid.path){
4397dd7cddfSDavid du Colombier 
440bd389b36SDavid du Colombier 	case Qdir:
441bd389b36SDavid du Colombier 		error(Eperm);
4427dd7cddfSDavid du Colombier 
443219b2ee8SDavid du Colombier 	case Qvgactl:
4447dd7cddfSDavid du Colombier 		if(offset || n >= READSTR)
445bd389b36SDavid du Colombier 			error(Ebadarg);
4469a747e4fSDavid du Colombier 		cb = parsecmd(a, n);
4477dd7cddfSDavid du Colombier 		if(waserror()){
4489a747e4fSDavid du Colombier 			free(cb);
4497dd7cddfSDavid du Colombier 			nexterror();
4507dd7cddfSDavid du Colombier 		}
4519a747e4fSDavid du Colombier 		vgactl(cb);
4527dd7cddfSDavid du Colombier 		poperror();
4539a747e4fSDavid du Colombier 		free(cb);
4549a747e4fSDavid du Colombier 		return n;
4559a747e4fSDavid du Colombier 
4569a747e4fSDavid du Colombier 	case Qvgaovl:
4579a747e4fSDavid du Colombier 		scr = &vgascreen[0];
458b7b24591SDavid du Colombier 		if (scr->dev == nil || scr->dev->ovlwrite == nil) {
4599a747e4fSDavid du Colombier 			error(Enooverlay);
4609a747e4fSDavid du Colombier 			break;
4619a747e4fSDavid du Colombier 		}
4629a747e4fSDavid du Colombier 		return scr->dev->ovlwrite(scr, a, n, off);
4639a747e4fSDavid du Colombier 
4649a747e4fSDavid du Colombier 	case Qvgaovlctl:
4659a747e4fSDavid du Colombier 		scr = &vgascreen[0];
466b7b24591SDavid du Colombier 		if (scr->dev == nil || scr->dev->ovlctl == nil) {
4679a747e4fSDavid du Colombier 			error(Enooverlay);
4689a747e4fSDavid du Colombier 			break;
4699a747e4fSDavid du Colombier 		}
4709a747e4fSDavid du Colombier 		scr->dev->ovlctl(scr, c, a, n);
471bd389b36SDavid du Colombier 		return n;
472219b2ee8SDavid du Colombier 
473219b2ee8SDavid du Colombier 	default:
4747dd7cddfSDavid du Colombier 		error(Egreg);
475219b2ee8SDavid du Colombier 		break;
476219b2ee8SDavid du Colombier 	}
477219b2ee8SDavid du Colombier 
478219b2ee8SDavid du Colombier 	return 0;
479219b2ee8SDavid du Colombier }
480219b2ee8SDavid du Colombier 
4817dd7cddfSDavid du Colombier Dev vgadevtab = {
4827dd7cddfSDavid du Colombier 	'v',
4837dd7cddfSDavid du Colombier 	"vga",
484bd389b36SDavid du Colombier 
4857dd7cddfSDavid du Colombier 	vgareset,
4867dd7cddfSDavid du Colombier 	devinit,
4879a747e4fSDavid du Colombier 	devshutdown,
4887dd7cddfSDavid du Colombier 	vgaattach,
4897dd7cddfSDavid du Colombier 	vgawalk,
4907dd7cddfSDavid du Colombier 	vgastat,
4917dd7cddfSDavid du Colombier 	vgaopen,
4927dd7cddfSDavid du Colombier 	devcreate,
4937dd7cddfSDavid du Colombier 	vgaclose,
4947dd7cddfSDavid du Colombier 	vgaread,
4957dd7cddfSDavid du Colombier 	devbread,
4967dd7cddfSDavid du Colombier 	vgawrite,
4977dd7cddfSDavid du Colombier 	devbwrite,
4987dd7cddfSDavid du Colombier 	devremove,
4997dd7cddfSDavid du Colombier 	devwstat,
500bd389b36SDavid du Colombier };
501