xref: /plan9/sys/src/cmd/aux/vga/vmware.c (revision 8cf6001e50e647a07ccf484b8e2f9940411befb9)
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