19a747e4fSDavid du Colombier #include <u.h>
29a747e4fSDavid du Colombier #include <libc.h>
39a747e4fSDavid du Colombier #include <bio.h>
49a747e4fSDavid du Colombier
59a747e4fSDavid du Colombier #include "pci.h"
69a747e4fSDavid du Colombier #include "vga.h"
79a747e4fSDavid du Colombier
89a747e4fSDavid du Colombier enum {
99a747e4fSDavid du Colombier Rid = 0,
109a747e4fSDavid du Colombier Renable,
119a747e4fSDavid du Colombier Rwidth,
129a747e4fSDavid du Colombier Rheight,
139a747e4fSDavid du Colombier Rmaxwidth,
149a747e4fSDavid du Colombier Rmaxheight,
159a747e4fSDavid du Colombier Rdepth,
169a747e4fSDavid du Colombier Rbpp,
179a747e4fSDavid du Colombier Rpseudocolor,
189a747e4fSDavid du Colombier Rrmask,
199a747e4fSDavid du Colombier Rgmask,
209a747e4fSDavid du Colombier Rbmask,
219a747e4fSDavid du Colombier Rbpl,
229a747e4fSDavid du Colombier Rfbstart,
239a747e4fSDavid du Colombier Rfboffset,
249a747e4fSDavid du Colombier Rfbmaxsize,
259a747e4fSDavid du Colombier Rfbsize,
269a747e4fSDavid du Colombier Rcap,
279a747e4fSDavid du Colombier Rmemstart,
289a747e4fSDavid du Colombier Rmemsize,
299a747e4fSDavid du Colombier Rconfigdone,
309a747e4fSDavid du Colombier Rsync,
319a747e4fSDavid du Colombier Rbusy,
329a747e4fSDavid du Colombier Rguestid,
339a747e4fSDavid du Colombier Rcursorid,
349a747e4fSDavid du Colombier Rcursorx,
359a747e4fSDavid du Colombier Rcursory,
369a747e4fSDavid du Colombier Rcursoron,
37b7b24591SDavid du Colombier Rhostbpp,
389a747e4fSDavid du Colombier Nreg,
399a747e4fSDavid du Colombier
409a747e4fSDavid du Colombier Crectfill = 1<<0,
419a747e4fSDavid du Colombier Crectcopy = 1<<1,
429a747e4fSDavid du Colombier Crectpatfill = 1<<2,
439a747e4fSDavid du Colombier Coffscreen = 1<<3,
449a747e4fSDavid du Colombier Crasterop = 1<<4,
459a747e4fSDavid du Colombier Ccursor = 1<<5,
469a747e4fSDavid du Colombier Ccursorbypass = 1<<6,
479a747e4fSDavid du Colombier Ccursorbypass2 = 1<<7,
489a747e4fSDavid du Colombier C8bitemulation = 1<<8,
499a747e4fSDavid du Colombier Calphacursor = 1<<9,
509a747e4fSDavid du Colombier
519a747e4fSDavid du Colombier Rpalette = 1024,
529a747e4fSDavid du Colombier };
539a747e4fSDavid du Colombier
549a747e4fSDavid du Colombier typedef struct Vmware Vmware;
559a747e4fSDavid du Colombier struct Vmware {
569a747e4fSDavid du Colombier ulong mmio;
579a747e4fSDavid du Colombier ulong fb;
589a747e4fSDavid du Colombier
599a747e4fSDavid du Colombier ulong ra;
609a747e4fSDavid du Colombier ulong rd;
619a747e4fSDavid du Colombier
629a747e4fSDavid du Colombier ulong r[Nreg];
639a747e4fSDavid du Colombier
649a747e4fSDavid du Colombier char chan[32];
659a747e4fSDavid du Colombier int depth;
669a747e4fSDavid du Colombier };
679a747e4fSDavid du Colombier
689a747e4fSDavid du Colombier static char*
699a747e4fSDavid du Colombier rname[Nreg] = {
709a747e4fSDavid du Colombier "ID",
719a747e4fSDavid du Colombier "Enable",
729a747e4fSDavid du Colombier "Width",
739a747e4fSDavid du Colombier "Height",
749a747e4fSDavid du Colombier "MaxWidth",
759a747e4fSDavid du Colombier "MaxHeight",
769a747e4fSDavid du Colombier "Depth",
779a747e4fSDavid du Colombier "Bpp",
789a747e4fSDavid du Colombier "PseudoColor",
799a747e4fSDavid du Colombier "RedMask",
809a747e4fSDavid du Colombier "GreenMask",
819a747e4fSDavid du Colombier "BlueMask",
829a747e4fSDavid du Colombier "Bpl",
839a747e4fSDavid du Colombier "FbStart",
849a747e4fSDavid du Colombier "FbOffset",
859a747e4fSDavid du Colombier "FbMaxSize",
869a747e4fSDavid du Colombier "FbSize",
879a747e4fSDavid du Colombier "Cap",
889a747e4fSDavid du Colombier "MemStart",
899a747e4fSDavid du Colombier "MemSize",
909a747e4fSDavid du Colombier "ConfigDone",
919a747e4fSDavid du Colombier "Sync",
929a747e4fSDavid du Colombier "Busy",
939a747e4fSDavid du Colombier "GuestID",
949a747e4fSDavid du Colombier "CursorID",
959a747e4fSDavid du Colombier "CursorX",
969a747e4fSDavid du Colombier "CursorY",
979a747e4fSDavid du Colombier "CursorOn",
98b7b24591SDavid du Colombier "HostBpp",
999a747e4fSDavid du Colombier };
1009a747e4fSDavid du Colombier
1019a747e4fSDavid du Colombier static ulong
vmrd(Vmware * vm,int i)1029a747e4fSDavid du Colombier vmrd(Vmware *vm, int i)
1039a747e4fSDavid du Colombier {
1049a747e4fSDavid du Colombier outportl(vm->ra, i);
1059a747e4fSDavid du Colombier return inportl(vm->rd);
1069a747e4fSDavid du Colombier }
1079a747e4fSDavid du Colombier
1089a747e4fSDavid du Colombier static void
vmwr(Vmware * vm,int i,ulong v)1099a747e4fSDavid du Colombier vmwr(Vmware *vm, int i, ulong v)
1109a747e4fSDavid du Colombier {
1119a747e4fSDavid du Colombier outportl(vm->ra, i);
1129a747e4fSDavid du Colombier outportl(vm->rd, v);
1139a747e4fSDavid du Colombier }
1149a747e4fSDavid du Colombier
1159a747e4fSDavid du Colombier static uint
bits(ulong a)1169a747e4fSDavid du Colombier bits(ulong a)
1179a747e4fSDavid du Colombier {
1189a747e4fSDavid du Colombier int b;
1199a747e4fSDavid du Colombier
1209a747e4fSDavid du Colombier for(b=0; a; a>>=1)
1219a747e4fSDavid du Colombier if(a&1)
1229a747e4fSDavid du Colombier b++;
1239a747e4fSDavid du Colombier return b;
1249a747e4fSDavid du Colombier }
1259a747e4fSDavid du Colombier
1269a747e4fSDavid du Colombier static void
snarf(Vga * vga,Ctlr * ctlr)1279a747e4fSDavid du Colombier snarf(Vga* vga, Ctlr* ctlr)
1289a747e4fSDavid du Colombier {
129b7b24591SDavid du Colombier int extra, i;
1309a747e4fSDavid du Colombier Pcidev *p;
1319a747e4fSDavid du Colombier Vmware *vm;
1329a747e4fSDavid du Colombier
1339a747e4fSDavid du Colombier p = vga->pci;
1349a747e4fSDavid du Colombier if(p == nil)
1359a747e4fSDavid du Colombier error("%s: vga->pci not set\n", ctlr->name);
1369a747e4fSDavid du Colombier
1379a747e4fSDavid du Colombier vm = alloc(sizeof(Vmware));
1389a747e4fSDavid du Colombier
1399a747e4fSDavid du Colombier switch(p->did){
1409a747e4fSDavid du Colombier case 0x710: /* VMware video chipset #1 */
1419a747e4fSDavid du Colombier vm->ra = 0x4560;
1429a747e4fSDavid du Colombier vm->rd = 0x4560+4;
1439a747e4fSDavid du Colombier break;
1449a747e4fSDavid du Colombier
1459a747e4fSDavid du Colombier case 0x405: /* VMware video chipset #2, untested */
1469a747e4fSDavid du Colombier vm->ra = p->mem[0].bar&~3;
1479a747e4fSDavid du Colombier vm->rd = vm->ra+1;
1489a747e4fSDavid du Colombier break;
1499a747e4fSDavid du Colombier
1509a747e4fSDavid du Colombier default:
1519a747e4fSDavid du Colombier error("%s: unrecognized chipset %.4ux\n", ctlr->name, p->did);
1529a747e4fSDavid du Colombier }
1539a747e4fSDavid du Colombier
1549a747e4fSDavid du Colombier for(i=0; i<Nreg; i++)
1559a747e4fSDavid du Colombier vm->r[i] = vmrd(vm, i);
1569a747e4fSDavid du Colombier
1579a747e4fSDavid du Colombier //vmwr(vm, Renable, 0);
1589a747e4fSDavid du Colombier /*
1599a747e4fSDavid du Colombier * Figure out color channel. Delay errors until init,
1609a747e4fSDavid du Colombier * which is after the register dump.
1619a747e4fSDavid du Colombier */
162b7b24591SDavid du Colombier vm->depth = vm->r[Rbpp];
163b7b24591SDavid du Colombier extra = vm->r[Rbpp] - vm->r[Rdepth];
1649a747e4fSDavid du Colombier if(vm->r[Rrmask] > vm->r[Rgmask] && vm->r[Rgmask] > vm->r[Rbmask]){
165b7b24591SDavid du Colombier if(extra)
166b7b24591SDavid du Colombier sprint(vm->chan, "x%d", extra);
167b7b24591SDavid du Colombier else
168b7b24591SDavid du Colombier vm->chan[0] = '\0';
169b7b24591SDavid du Colombier sprint(vm->chan+strlen(vm->chan), "r%dg%db%d", bits(vm->r[Rrmask]),
1709a747e4fSDavid du Colombier bits(vm->r[Rgmask]), bits(vm->r[Rbmask]));
171b7b24591SDavid du Colombier }else if(vm->r[Rbmask] > vm->r[Rgmask] && vm->r[Rgmask] > vm->r[Rrmask]){
1729a747e4fSDavid du Colombier sprint(vm->chan, "b%dg%dr%d", bits(vm->r[Rbmask]),
1739a747e4fSDavid du Colombier bits(vm->r[Rgmask]), bits(vm->r[Rrmask]));
174b7b24591SDavid du Colombier if(extra)
175b7b24591SDavid du Colombier sprint(vm->chan+strlen(vm->chan), "x%d", extra);
176b7b24591SDavid du Colombier }else
1779a747e4fSDavid du Colombier sprint(vm->chan, "unknown");
1789a747e4fSDavid du Colombier
1799a747e4fSDavid du Colombier /* Record the frame buffer start, size */
1809a747e4fSDavid du Colombier vga->vmb = vm->r[Rfbstart];
1819a747e4fSDavid du Colombier vga->apz = vm->r[Rfbmaxsize];
1829a747e4fSDavid du Colombier
1839a747e4fSDavid du Colombier vga->private = vm;
1849a747e4fSDavid du Colombier ctlr->flag |= Fsnarf;
1859a747e4fSDavid du Colombier }
1869a747e4fSDavid du Colombier
1879a747e4fSDavid du Colombier
1889a747e4fSDavid du Colombier static void
options(Vga *,Ctlr * ctlr)1899a747e4fSDavid du Colombier options(Vga*, Ctlr* ctlr)
1909a747e4fSDavid du Colombier {
1919a747e4fSDavid du Colombier ctlr->flag |= Hlinear|Henhanced|Foptions;
1929a747e4fSDavid du Colombier }
1939a747e4fSDavid du Colombier
1949a747e4fSDavid du Colombier
1959a747e4fSDavid du Colombier static void
clock(Vga *,Ctlr *)1969a747e4fSDavid du Colombier clock(Vga*, Ctlr*)
1979a747e4fSDavid du Colombier {
1989a747e4fSDavid du Colombier /* BEST CLOCK ROUTINE EVER! */
1999a747e4fSDavid du Colombier }
2009a747e4fSDavid du Colombier
2019a747e4fSDavid du Colombier static void
init(Vga * vga,Ctlr * ctlr)2029a747e4fSDavid du Colombier init(Vga* vga, Ctlr* ctlr)
2039a747e4fSDavid du Colombier {
2049a747e4fSDavid du Colombier Vmware *vm;
2059a747e4fSDavid du Colombier
2069a747e4fSDavid du Colombier vm = vga->private;
2079a747e4fSDavid du Colombier
2089a747e4fSDavid du Colombier vmwr(vm, Rid, (0x900000<<8)|2);
2099a747e4fSDavid du Colombier if(vmrd(vm, Rid)&0xFF != 2)
210*8cf6001eSDavid du Colombier error("old vmware svga version %lud; need version 2\n",
2119a747e4fSDavid du Colombier vmrd(vm,Rid)&0xFF);
2129a747e4fSDavid du Colombier
2139a747e4fSDavid du Colombier ctlr->flag |= Ulinear;
2149a747e4fSDavid du Colombier if(strcmp(vm->chan, "unknown") == 0)
215*8cf6001eSDavid du Colombier error("couldn't translate color masks into channel\n");
2169a747e4fSDavid du Colombier
2179a747e4fSDavid du Colombier /* Always use the screen depth, and clip the screen size */
218b7b24591SDavid du Colombier vga->mode->z = vm->r[Rbpp];
2199a747e4fSDavid du Colombier if(vga->mode->x > vm->r[Rmaxwidth])
2209a747e4fSDavid du Colombier vga->mode->x = vm->r[Rmaxwidth];
2219a747e4fSDavid du Colombier if(vga->mode->y > vm->r[Rmaxheight])
2229a747e4fSDavid du Colombier vga->mode->y = vm->r[Rmaxheight];
2239a747e4fSDavid du Colombier
2249a747e4fSDavid du Colombier vm->r[Rwidth] = vga->mode->x;
2259a747e4fSDavid du Colombier vm->r[Rheight] = vga->mode->y;
2269a747e4fSDavid du Colombier
2279a747e4fSDavid du Colombier /* Figure out the channel string */
2289a747e4fSDavid du Colombier strcpy(vga->mode->chan, vm->chan);
2299a747e4fSDavid du Colombier
2309a747e4fSDavid du Colombier /* Record the bytes per line */
2319a747e4fSDavid du Colombier ctlr->flag |= Finit;
2329a747e4fSDavid du Colombier }
2339a747e4fSDavid du Colombier
2349a747e4fSDavid du Colombier static void
load(Vga * vga,Ctlr * ctlr)2359a747e4fSDavid du Colombier load(Vga* vga, Ctlr *ctlr)
2369a747e4fSDavid du Colombier {
237b7b24591SDavid du Colombier char buf[64];
238b7b24591SDavid du Colombier int x;
2399a747e4fSDavid du Colombier Vmware *vm;
2409a747e4fSDavid du Colombier
2419a747e4fSDavid du Colombier vm = vga->private;
2429a747e4fSDavid du Colombier vmwr(vm, Rwidth, vm->r[Rwidth]);
2439a747e4fSDavid du Colombier vmwr(vm, Rheight, vm->r[Rheight]);
2449a747e4fSDavid du Colombier vmwr(vm, Renable, 1);
2459a747e4fSDavid du Colombier vmwr(vm, Rguestid, 0x5010); /* OS type is "Other" */
2469a747e4fSDavid du Colombier
247b7b24591SDavid du Colombier x = vmrd(vm, Rbpl)/(vm->depth/8);
248b7b24591SDavid du Colombier if(x != vga->mode->x){
249b7b24591SDavid du Colombier vga->virtx = x;
250b7b24591SDavid du Colombier sprint(buf, "%ludx%ludx%d %s", vga->virtx, vga->virty,
251b7b24591SDavid du Colombier vga->mode->z, vga->mode->chan);
252b7b24591SDavid du Colombier vgactlw("size", buf);
253b7b24591SDavid du Colombier }
2549a747e4fSDavid du Colombier ctlr->flag |= Fload;
2559a747e4fSDavid du Colombier }
2569a747e4fSDavid du Colombier
2579a747e4fSDavid du Colombier static void
dump(Vga * vga,Ctlr * ctlr)2589a747e4fSDavid du Colombier dump(Vga* vga, Ctlr* ctlr)
2599a747e4fSDavid du Colombier {
2609a747e4fSDavid du Colombier int i;
2619a747e4fSDavid du Colombier Vmware *vm;
2629a747e4fSDavid du Colombier
2639a747e4fSDavid du Colombier vm = vga->private;
2649a747e4fSDavid du Colombier
2659a747e4fSDavid du Colombier for(i=0; i<Nreg; i++){
2669a747e4fSDavid du Colombier printitem(ctlr->name, rname[i]);
2679a747e4fSDavid du Colombier Bprint(&stdout, " %.8lux\n", vm->r[i]);
2689a747e4fSDavid du Colombier }
2699a747e4fSDavid du Colombier
2709a747e4fSDavid du Colombier printitem(ctlr->name, "chan");
2719a747e4fSDavid du Colombier Bprint(&stdout, " %s\n", vm->chan);
2729a747e4fSDavid du Colombier printitem(ctlr->name, "depth");
2739a747e4fSDavid du Colombier Bprint(&stdout, " %d\n", vm->depth);
2749a747e4fSDavid du Colombier printitem(ctlr->name, "linear");
2759a747e4fSDavid du Colombier
2769a747e4fSDavid du Colombier }
2779a747e4fSDavid du Colombier
2789a747e4fSDavid du Colombier Ctlr vmware = {
2799a747e4fSDavid du Colombier "vmware", /* name */
2809a747e4fSDavid du Colombier snarf, /* snarf */
2819a747e4fSDavid du Colombier options, /* options */
2829a747e4fSDavid du Colombier init, /* init */
2839a747e4fSDavid du Colombier load, /* load */
2849a747e4fSDavid du Colombier dump, /* dump */
2859a747e4fSDavid du Colombier };
2869a747e4fSDavid du Colombier
2879a747e4fSDavid du Colombier Ctlr vmwarehwgc = {
2889a747e4fSDavid du Colombier "vmwarehwgc", /* name */
2899a747e4fSDavid du Colombier 0, /* snarf */
2909a747e4fSDavid du Colombier 0, /* options */
2919a747e4fSDavid du Colombier 0, /* init */
2929a747e4fSDavid du Colombier 0, /* load */
2939a747e4fSDavid du Colombier 0, /* dump */
2949a747e4fSDavid du Colombier };
2959a747e4fSDavid du Colombier
296