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 102 vmrd(Vmware *vm, int i) 103 { 104 outportl(vm->ra, i); 105 return inportl(vm->rd); 106 } 107 108 static void 109 vmwr(Vmware *vm, int i, ulong v) 110 { 111 outportl(vm->ra, i); 112 outportl(vm->rd, v); 113 } 114 115 static uint 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 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 189 options(Vga*, Ctlr* ctlr) 190 { 191 ctlr->flag |= Hlinear|Henhanced|Foptions; 192 } 193 194 195 static void 196 clock(Vga*, Ctlr*) 197 { 198 /* BEST CLOCK ROUTINE EVER! */ 199 } 200 201 static void 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 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 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