summaryrefslogtreecommitdiff
path: root/sys/src/9/pc/devvga.c
diff options
context:
space:
mode:
authorTaru Karttunen <taruti@taruti.net>2011-03-30 15:46:40 +0300
committerTaru Karttunen <taruti@taruti.net>2011-03-30 15:46:40 +0300
commite5888a1ffdae813d7575f5fb02275c6bb07e5199 (patch)
treed8d51eac403f07814b9e936eed0c9a79195e2450 /sys/src/9/pc/devvga.c
Import sources from 2011-03-30 iso image
Diffstat (limited to 'sys/src/9/pc/devvga.c')
-rwxr-xr-xsys/src/9/pc/devvga.c498
1 files changed, 498 insertions, 0 deletions
diff --git a/sys/src/9/pc/devvga.c b/sys/src/9/pc/devvga.c
new file mode 100755
index 000000000..ae28fdd79
--- /dev/null
+++ b/sys/src/9/pc/devvga.c
@@ -0,0 +1,498 @@
+/*
+ * 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 void
+vgareset(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 int
+vgastat(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 void
+vgaclose(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 void
+checkport(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 long
+vgaread(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(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 0x%lux v 0x%p size 0x%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 void
+vgactl(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;
+ }
+ 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(1);
+ deletescreenimage();
+ if(screensize(x, y, z, chan))
+ error(Egreg);
+ vgascreenwin(scr);
+ resetscreenimage();
+ 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:
+ if(scr->gscreen == nil)
+ error("drawinit: no gscreen");
+ if(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 long
+vgawrite(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,
+ devremove,
+ devwstat,
+};