diff options
author | Taru Karttunen <taruti@taruti.net> | 2011-03-30 15:46:40 +0300 |
---|---|---|
committer | Taru Karttunen <taruti@taruti.net> | 2011-03-30 15:46:40 +0300 |
commit | e5888a1ffdae813d7575f5fb02275c6bb07e5199 (patch) | |
tree | d8d51eac403f07814b9e936eed0c9a79195e2450 /sys/src/cmd/aux/vga/main.c |
Import sources from 2011-03-30 iso image
Diffstat (limited to 'sys/src/cmd/aux/vga/main.c')
-rwxr-xr-x | sys/src/cmd/aux/vga/main.c | 478 |
1 files changed, 478 insertions, 0 deletions
diff --git a/sys/src/cmd/aux/vga/main.c b/sys/src/cmd/aux/vga/main.c new file mode 100755 index 000000000..77d6ba979 --- /dev/null +++ b/sys/src/cmd/aux/vga/main.c @@ -0,0 +1,478 @@ +#include <u.h> +#include <libc.h> +#include <bio.h> + +#include "pci.h" +#include "vga.h" + +Biobuf stdout; + +static int iflag, lflag, pflag, rflag; + +static char *dbname = "/lib/vgadb"; +static char monitordb[128]; + +static void +dump(Vga* vga) +{ + Ctlr *ctlr; + Attr *attr; + + if(vga->mode) + dbdumpmode(vga->mode); + + for(attr = vga->attr; attr; attr = attr->next) + Bprint(&stdout, "vga->attr: %s=%s\n", attr->attr, attr->val); + + for(ctlr = vga->link; ctlr; ctlr = ctlr->link){ + if(ctlr->dump == 0) + continue; + + trace("%s->dump\n", ctlr->name); + if(ctlr->flag && ctlr->flag != Fsnarf){ + printitem(ctlr->name, "flag"); + printflag(ctlr->flag); + Bprint(&stdout, "\n"); + } + (*ctlr->dump)(vga, ctlr); + ctlr->flag |= Fdump; + } + Bprint(&stdout, "\n"); +} + +void +resyncinit(Vga* vga, Ctlr* ctlr, ulong on, ulong off) +{ + Ctlr *link; + + trace("%s->resyncinit on 0x%8.8luX off 0x%8.8luX\n", + ctlr->name, on, off); + + for(link = vga->link; link; link = link->link){ + link->flag |= on; + link->flag &= ~off; + if(link == ctlr) + continue; + + if(link->init == 0 || (link->flag & Finit) == 0) + continue; + link->flag &= ~Finit; + trace("%s->init 0x%8.8luX\n", link->name, link->flag); + (*link->init)(vga, link); + } +} + +void +sequencer(Vga* vga, int on) +{ + static uchar seq01; + static int state = 1; + char *s; + + if(on) + s = "on"; + else + s = "off"; + trace("sequencer->enter %s\n", s); + if(on){ + if(vga) + seq01 = vga->sequencer[0x01]; + if(state == 0){ + seq01 |= 0x01; + vgaxo(Seqx, 0x01, seq01); + vgaxo(Seqx, 0x00, 0x03); + } + } + else{ + vgaxo(Seqx, 0x00, 0x01); + seq01 = vgaxi(Seqx, 0x01); + vgaxo(Seqx, 0x01, seq01|0x20); + } + state = on; + trace("sequencer->leave %s\n", s); +} + +static void +linear(Vga* vga) +{ + char buf[256]; + char *p; + + /* + * Set up for linear addressing: try to allocate the + * kernel memory map then read the base-address back. + * vga->linear is a compatibility hack. + */ + if(vga->linear == 0){ + vga->ctlr->flag &= ~Ulinear; + return; + } + if(vga->ctlr->flag & Ulinear){ + /* + * If there's already an aperture don't bother trying + * to set up a new one. + */ + vgactlr("addr", buf); + if(atoi(buf)==0 && (buf[0]!='p' || buf[1]!=' ' || atoi(buf+2)==0)){ + sprint(buf, "0x%lux 0x%lux", vga->apz ? vga->apz : vga->vmz, vga->vma); + vgactlw("linear", buf); + vgactlr("addr", buf); + } + trace("linear->addr %s\n", buf); + /* + * old: addr 0x12345678 + * new: addr p 0x12345678 v 0x82345678 size 0x123 + */ + if(buf[0]=='p' && buf[1]==' '){ + vga->vmb = strtoul(buf+2, 0, 0); + p = strstr(buf, "size"); + if(p) + vga->apz = strtoul(p+4, 0, 0); + }else + vga->vmb = strtoul(buf, 0, 0); + } + else + vgactlw("linear", "0"); +} + +char* +chanstr[32+1] = { +[1] "k1", +[2] "k2", +[4] "k4", +[8] "m8", +[16] "r5g6b5", +[24] "r8g8b8", +[32] "x8r8g8b8", +}; + +static void +usage(void) +{ + fprint(2, "usage: aux/vga [ -BcdilpvV ] [ -b bios-id ] [ -m monitor ] [ -x db ] [ mode [ virtualsize ] ]\n"); + exits("usage"); +} + +void +main(int argc, char** argv) +{ + char *bios, buf[256], sizeb[256], *p, *vsize, *psize; + char *type, *vtype; + int fd, virtual, len; + Ctlr *ctlr; + Vga *vga; + + fmtinstall('H', encodefmt); + Binit(&stdout, 1, OWRITE); + + bios = getenv("vgactlr"); + if((type = getenv("monitor")) == 0) + type = "vga"; + psize = vsize = "640x480x8"; + + ARGBEGIN{ + default: + usage(); + break; + case 'b': + bios = EARGF(usage()); + break; + case 'B': + dumpbios(0x10000); + exits(0); + case 'c': + cflag = 1; + break; + case 'd': + dflag = 1; + break; + case 'i': + iflag = 1; + break; + case 'l': + lflag = 1; + break; + case 'm': + type = EARGF(usage()); + break; + case 'p': + pflag = 1; + break; + case 'r': + /* + * rflag > 1 means "leave me alone, I know what I'm doing." + */ + rflag++; + break; + case 'v': + vflag = 1; + break; + case 'V': + vflag = 1; + Vflag = 1; + break; + case 'x': + dbname = EARGF(usage()); + break; + }ARGEND + + virtual = 0; + switch(argc){ + default: + usage(); + break; + case 1: + vsize = psize = argv[0]; + break; + case 2: + psize = argv[0]; + vsize = argv[1]; + virtual = 1; + break; + case 0: + break; + } + + if(lflag && strcmp(vsize, "text") == 0){ + vesatextmode(); + vgactlw("textmode", ""); + exits(0); + } + + vga = alloc(sizeof(Vga)); + if(bios){ + if((vga->offset = strtol(bios, &p, 0)) == 0 || *p++ != '=') + error("main: bad BIOS string format - %s\n", bios); + len = strlen(p); + vga->bios = alloc(len+1); + strncpy(vga->bios, p, len); + trace("main->BIOS %s\n", bios); + } + + /* + * Try to identify the VGA card and grab + * registers. Print them out if requested. + * If monitor=vesa or our vga controller can't be found + * in vgadb, try vesa modes; failing that, try vga. + */ + if(strcmp(type, "vesa") == 0 || dbctlr(dbname, vga) == 0 || + vga->ctlr == 0) + if(dbvesa(vga) == 0 || vga->ctlr == 0){ + Bprint(&stdout, "%s: controller not in %s, not vesa\n", + argv0, dbname); + dumpbios(256); + type = "vga"; + vsize = psize = "640x480x1"; + virtual = 0; + vga->ctlr = &generic; + vga->link = &generic; + } + + trace("main->snarf\n"); + for(ctlr = vga->link; ctlr; ctlr = ctlr->link){ + if(ctlr->snarf == 0) + continue; + trace("%s->snarf\n", ctlr->name); + (*ctlr->snarf)(vga, ctlr); + } + + if(pflag) + dump(vga); + + for(ctlr = vga->link; ctlr; ctlr = ctlr->link) + if(ctlr->flag & Ferror) + error("%r\n"); + + if(iflag || lflag){ + if(getenv(type)) + snprint(monitordb, sizeof monitordb, "/env/%s", type); + else + strecpy(monitordb, monitordb+sizeof monitordb, dbname); + + if(vga->vesa){ + strcpy(monitordb, "vesa bios"); + vga->mode = dbvesamode(psize); + }else + vga->mode = dbmode(monitordb, type, psize); + if(vga->mode == 0) + error("main: %s@%s not in %s\n", type, psize, monitordb); + + if(virtual){ + if((p = strchr(vsize, 'x')) == nil) + error("bad virtual size %s\n", vsize); + vga->virtx = atoi(vsize); + vga->virty = atoi(p+1); + if(vga->virtx < vga->mode->x || vga->virty < vga->mode->y) + error("virtual size smaller than physical size\n"); + vga->panning = 1; + } + else{ + vga->virtx = vga->mode->x; + vga->virty = vga->mode->y; + vga->panning = 0; + } + + trace("vmf %d vmdf %d vf1 %lud vbw %lud\n", + vga->mode->frequency, vga->mode->deffrequency, + vga->f[1], vga->mode->videobw); + if(vga->mode->frequency == 0 && vga->mode->videobw != 0 && vga->f[1] != 0){ + /* + * boost clock as much as possible subject + * to video and memory bandwidth constraints + */ + ulong bytes, freq, membw; + double rr; + + freq = vga->mode->videobw; + if(freq > vga->f[1]) + freq = vga->f[1]; + + rr = (double)freq/(vga->mode->ht*vga->mode->vt); + if(rr > 85.0) /* >85Hz is ridiculous */ + rr = 85.0; + + bytes = (vga->mode->x*vga->mode->y*vga->mode->z)/8; + membw = rr*bytes; + if(vga->membw != 0 && membw > vga->membw){ + membw = vga->membw; + rr = (double)membw/bytes; + } + + freq = rr*(vga->mode->ht*vga->mode->vt); + vga->mode->frequency = freq; + + trace("using frequency %lud rr %.2f membw %lud\n", + freq, rr, membw); + } + else if(vga->mode->frequency == 0) + vga->mode->frequency = vga->mode->deffrequency; + + for(ctlr = vga->link; ctlr; ctlr = ctlr->link){ + if(ctlr->options == 0) + continue; + trace("%s->options\n", ctlr->name); + (*ctlr->options)(vga, ctlr); + } + + /* + * skip init for vesa - vesa will do the registers for us + */ + if(!vga->vesa) + for(ctlr = vga->link; ctlr; ctlr = ctlr->link){ + if(ctlr->init == 0) + continue; + trace("%s->init\n", ctlr->name); + (*ctlr->init)(vga, ctlr); + } + + if(strcmp(vga->mode->chan, "") == 0){ + if(vga->mode->z < nelem(chanstr) && chanstr[vga->mode->z]) + strcpy(vga->mode->chan, chanstr[vga->mode->z]); + else + error("%s: unknown channel type to use for depth %d\n", vga->ctlr->name, vga->mode->z); + } + + if(iflag || pflag) + dump(vga); + + if(lflag){ + trace("main->load\n"); + if(vga->vmz && (vga->virtx*vga->virty*vga->mode->z)/8 > vga->vmz) + error("%s: not enough video memory - %lud\n", + vga->ctlr->name, vga->vmz); + + if(vga->ctlr->type) + vtype = vga->ctlr->type; + else if(p = strchr(vga->ctlr->name, '-')){ + strncpy(buf, vga->ctlr->name, p - vga->ctlr->name); + buf[p - vga->ctlr->name] = 0; + vtype = buf; + } + else + vtype = vga->ctlr->name; + vgactlw("type", vtype); + + /* + * VESA must be set up before linear. + * Set type to vesa for linear. + */ + if(vga->vesa){ + vesa.load(vga, vga->vesa); + if(vga->vesa->flag&Ferror) + error("vesa load error\n"); + vgactlw("type", vesa.name); + } + + /* + * The new draw device needs linear mode set + * before size. + */ + linear(vga); + + /* + * Linear is over so switch to other driver for + * acceleration. + */ + if(vga->vesa) + vgactlw("type", vtype); + + sprint(buf, "%ludx%ludx%d %s", + vga->virtx, vga->virty, + vga->mode->z, vga->mode->chan); + if(rflag){ + vgactlr("size", sizeb); + if(rflag < 2 && strcmp(buf, sizeb) != 0) + error("bad refresh: %s != %s\n", + buf, sizeb); + } + else + vgactlw("size", buf); + + /* + * No fiddling with registers if VESA set + * things up already. Sorry. + */ + if(!vga->vesa){ + /* + * Turn off the display during the load. + */ + sequencer(vga, 0); + + for(ctlr = vga->link; ctlr; ctlr = ctlr->link){ + if(ctlr->load == 0 || ctlr == &vesa) + continue; + trace("%s->load\n", ctlr->name); + (*ctlr->load)(vga, ctlr); + } + + sequencer(vga, 1); + } + + vgactlw("drawinit", ""); + + if(vga->hwgc == 0 || cflag) + vgactlw("hwgc", "soft"); + else + vgactlw("hwgc", vga->hwgc->name); + + /* might as well initialize the cursor */ + if((fd = open("/dev/cursor", OWRITE)) >= 0){ + write(fd, buf, 0); + close(fd); + } + + if(vga->virtx != vga->mode->x || vga->virty != vga->mode->y){ + sprint(buf, "%dx%d", vga->mode->x, vga->mode->y); + vgactlw("actualsize", buf); + if(vga->panning) + vgactlw("panning", "on"); + } + + if(pflag) + dump(vga); + } + } + + trace("main->exits\n"); + exits(0); +} |