1 #include <u.h>
2 #include <libc.h>
3 #include <bio.h>
4
5 #include "pci.h"
6 #include "vga.h"
7
8 enum {
9 Rid = 0,
10 Renable,
11 Rwidth,
12 Rheight,
13 Rmaxwidth,
14 Rmaxheight,
15 Rdepth,
16 Rbpp,
17 Rpseudocolor,
18 Rrmask,
19 Rgmask,
20 Rbmask,
21 Rbpl,
22 Rfbstart,
23 Rfboffset,
24 Rfbmaxsize,
25 Rfbsize,
26 Rcap,
27 Rmemstart,
28 Rmemsize,
29 Rconfigdone,
30 Rsync,
31 Rbusy,
32 Rguestid,
33 Rcursorid,
34 Rcursorx,
35 Rcursory,
36 Rcursoron,
37 Rhostbpp,
38 Nreg,
39
40 Crectfill = 1<<0,
41 Crectcopy = 1<<1,
42 Crectpatfill = 1<<2,
43 Coffscreen = 1<<3,
44 Crasterop = 1<<4,
45 Ccursor = 1<<5,
46 Ccursorbypass = 1<<6,
47 Ccursorbypass2 = 1<<7,
48 C8bitemulation = 1<<8,
49 Calphacursor = 1<<9,
50
51 Rpalette = 1024,
52 };
53
54 typedef struct Vmware Vmware;
55 struct Vmware {
56 ulong mmio;
57 ulong fb;
58
59 ulong ra;
60 ulong rd;
61
62 ulong r[Nreg];
63
64 char chan[32];
65 int depth;
66 };
67
68 static char*
69 rname[Nreg] = {
70 "ID",
71 "Enable",
72 "Width",
73 "Height",
74 "MaxWidth",
75 "MaxHeight",
76 "Depth",
77 "Bpp",
78 "PseudoColor",
79 "RedMask",
80 "GreenMask",
81 "BlueMask",
82 "Bpl",
83 "FbStart",
84 "FbOffset",
85 "FbMaxSize",
86 "FbSize",
87 "Cap",
88 "MemStart",
89 "MemSize",
90 "ConfigDone",
91 "Sync",
92 "Busy",
93 "GuestID",
94 "CursorID",
95 "CursorX",
96 "CursorY",
97 "CursorOn",
98 "HostBpp",
99 };
100
101 static ulong
vmrd(Vmware * vm,int i)102 vmrd(Vmware *vm, int i)
103 {
104 outportl(vm->ra, i);
105 return inportl(vm->rd);
106 }
107
108 static void
vmwr(Vmware * vm,int i,ulong v)109 vmwr(Vmware *vm, int i, ulong v)
110 {
111 outportl(vm->ra, i);
112 outportl(vm->rd, v);
113 }
114
115 static uint
bits(ulong a)116 bits(ulong a)
117 {
118 int b;
119
120 for(b=0; a; a>>=1)
121 if(a&1)
122 b++;
123 return b;
124 }
125
126 static void
snarf(Vga * vga,Ctlr * ctlr)127 snarf(Vga* vga, Ctlr* ctlr)
128 {
129 int extra, i;
130 Pcidev *p;
131 Vmware *vm;
132
133 p = vga->pci;
134 if(p == nil)
135 error("%s: vga->pci not set\n", ctlr->name);
136
137 vm = alloc(sizeof(Vmware));
138
139 switch(p->did){
140 case 0x710: /* VMware video chipset #1 */
141 vm->ra = 0x4560;
142 vm->rd = 0x4560+4;
143 break;
144
145 case 0x405: /* VMware video chipset #2, untested */
146 vm->ra = p->mem[0].bar&~3;
147 vm->rd = vm->ra+1;
148 break;
149
150 default:
151 error("%s: unrecognized chipset %.4ux\n", ctlr->name, p->did);
152 }
153
154 for(i=0; i<Nreg; i++)
155 vm->r[i] = vmrd(vm, i);
156
157 //vmwr(vm, Renable, 0);
158 /*
159 * Figure out color channel. Delay errors until init,
160 * which is after the register dump.
161 */
162 vm->depth = vm->r[Rbpp];
163 extra = vm->r[Rbpp] - vm->r[Rdepth];
164 if(vm->r[Rrmask] > vm->r[Rgmask] && vm->r[Rgmask] > vm->r[Rbmask]){
165 if(extra)
166 sprint(vm->chan, "x%d", extra);
167 else
168 vm->chan[0] = '\0';
169 sprint(vm->chan+strlen(vm->chan), "r%dg%db%d", bits(vm->r[Rrmask]),
170 bits(vm->r[Rgmask]), bits(vm->r[Rbmask]));
171 }else if(vm->r[Rbmask] > vm->r[Rgmask] && vm->r[Rgmask] > vm->r[Rrmask]){
172 sprint(vm->chan, "b%dg%dr%d", bits(vm->r[Rbmask]),
173 bits(vm->r[Rgmask]), bits(vm->r[Rrmask]));
174 if(extra)
175 sprint(vm->chan+strlen(vm->chan), "x%d", extra);
176 }else
177 sprint(vm->chan, "unknown");
178
179 /* Record the frame buffer start, size */
180 vga->vmb = vm->r[Rfbstart];
181 vga->apz = vm->r[Rfbmaxsize];
182
183 vga->private = vm;
184 ctlr->flag |= Fsnarf;
185 }
186
187
188 static void
options(Vga *,Ctlr * ctlr)189 options(Vga*, Ctlr* ctlr)
190 {
191 ctlr->flag |= Hlinear|Henhanced|Foptions;
192 }
193
194
195 static void
clock(Vga *,Ctlr *)196 clock(Vga*, Ctlr*)
197 {
198 /* BEST CLOCK ROUTINE EVER! */
199 }
200
201 static void
init(Vga * vga,Ctlr * ctlr)202 init(Vga* vga, Ctlr* ctlr)
203 {
204 Vmware *vm;
205
206 vm = vga->private;
207
208 vmwr(vm, Rid, (0x900000<<8)|2);
209 if(vmrd(vm, Rid)&0xFF != 2)
210 error("old vmware svga version %lud; need version 2\n",
211 vmrd(vm,Rid)&0xFF);
212
213 ctlr->flag |= Ulinear;
214 if(strcmp(vm->chan, "unknown") == 0)
215 error("couldn't translate color masks into channel\n");
216
217 /* Always use the screen depth, and clip the screen size */
218 vga->mode->z = vm->r[Rbpp];
219 if(vga->mode->x > vm->r[Rmaxwidth])
220 vga->mode->x = vm->r[Rmaxwidth];
221 if(vga->mode->y > vm->r[Rmaxheight])
222 vga->mode->y = vm->r[Rmaxheight];
223
224 vm->r[Rwidth] = vga->mode->x;
225 vm->r[Rheight] = vga->mode->y;
226
227 /* Figure out the channel string */
228 strcpy(vga->mode->chan, vm->chan);
229
230 /* Record the bytes per line */
231 ctlr->flag |= Finit;
232 }
233
234 static void
load(Vga * vga,Ctlr * ctlr)235 load(Vga* vga, Ctlr *ctlr)
236 {
237 char buf[64];
238 int x;
239 Vmware *vm;
240
241 vm = vga->private;
242 vmwr(vm, Rwidth, vm->r[Rwidth]);
243 vmwr(vm, Rheight, vm->r[Rheight]);
244 vmwr(vm, Renable, 1);
245 vmwr(vm, Rguestid, 0x5010); /* OS type is "Other" */
246
247 x = vmrd(vm, Rbpl)/(vm->depth/8);
248 if(x != vga->mode->x){
249 vga->virtx = x;
250 sprint(buf, "%ludx%ludx%d %s", vga->virtx, vga->virty,
251 vga->mode->z, vga->mode->chan);
252 vgactlw("size", buf);
253 }
254 ctlr->flag |= Fload;
255 }
256
257 static void
dump(Vga * vga,Ctlr * ctlr)258 dump(Vga* vga, Ctlr* ctlr)
259 {
260 int i;
261 Vmware *vm;
262
263 vm = vga->private;
264
265 for(i=0; i<Nreg; i++){
266 printitem(ctlr->name, rname[i]);
267 Bprint(&stdout, " %.8lux\n", vm->r[i]);
268 }
269
270 printitem(ctlr->name, "chan");
271 Bprint(&stdout, " %s\n", vm->chan);
272 printitem(ctlr->name, "depth");
273 Bprint(&stdout, " %d\n", vm->depth);
274 printitem(ctlr->name, "linear");
275
276 }
277
278 Ctlr vmware = {
279 "vmware", /* name */
280 snarf, /* snarf */
281 options, /* options */
282 init, /* init */
283 load, /* load */
284 dump, /* dump */
285 };
286
287 Ctlr vmwarehwgc = {
288 "vmwarehwgc", /* name */
289 0, /* snarf */
290 0, /* options */
291 0, /* init */
292 0, /* load */
293 0, /* dump */
294 };
295
296