1 #include <u.h> 2 #include <libc.h> 3 #include <bio.h> 4 5 #include "pci.h" 6 #include "vga.h" 7 8 Biobuf stdout; 9 10 static int iflag, lflag, pflag, rflag; 11 static char *usage = 12 "usage: aux/vga [ -BcdilpvV ] [ -b bios-id ] [ -m monitor ] [ -x db ] [ mode [ virtualsize ] ]\n"; 13 14 static char *dbname = "/lib/vgadb"; 15 static char monitordb[128]; 16 17 static void 18 dump(Vga* vga) 19 { 20 Ctlr *ctlr; 21 Attr *attr; 22 23 if(vga->mode) 24 dbdumpmode(vga->mode); 25 26 for(attr = vga->attr; attr; attr = attr->next) 27 Bprint(&stdout, "vga->attr: %s=%s\n", attr->attr, attr->val); 28 29 for(ctlr = vga->link; ctlr; ctlr = ctlr->link){ 30 if(ctlr->dump == 0) 31 continue; 32 33 trace("%s->dump\n", ctlr->name); 34 if(ctlr->flag && ctlr->flag != Fsnarf){ 35 printitem(ctlr->name, "flag"); 36 printflag(ctlr->flag); 37 Bprint(&stdout, "\n"); 38 } 39 (*ctlr->dump)(vga, ctlr); 40 ctlr->flag |= Fdump; 41 } 42 Bprint(&stdout, "\n"); 43 } 44 45 void 46 resyncinit(Vga* vga, Ctlr* ctlr, ulong on, ulong off) 47 { 48 Ctlr *link; 49 50 trace("%s->resyncinit on 0x%8.8luX off 0x%8.8luX\n", 51 ctlr->name, on, off); 52 53 for(link = vga->link; link; link = link->link){ 54 link->flag |= on; 55 link->flag &= ~off; 56 if(link == ctlr) 57 continue; 58 59 if(link->init == 0 || (link->flag & Finit) == 0) 60 continue; 61 link->flag &= ~Finit; 62 trace("%s->init 0x%8.8luX\n", link->name, link->flag); 63 (*link->init)(vga, link); 64 } 65 } 66 67 void 68 sequencer(Vga* vga, int on) 69 { 70 static uchar seq01; 71 static int state = 1; 72 char *s; 73 74 if(on) 75 s = "on"; 76 else 77 s = "off"; 78 trace("sequencer->enter %s\n", s); 79 if(on){ 80 if(vga) 81 seq01 = vga->sequencer[0x01]; 82 if(state == 0){ 83 seq01 |= 0x01; 84 vgaxo(Seqx, 0x01, seq01); 85 vgaxo(Seqx, 0x00, 0x03); 86 } 87 } 88 else{ 89 vgaxo(Seqx, 0x00, 0x01); 90 seq01 = vgaxi(Seqx, 0x01); 91 vgaxo(Seqx, 0x01, seq01|0x20); 92 } 93 state = on; 94 trace("sequencer->leave %s\n", s); 95 } 96 97 static void 98 linear(Vga* vga) 99 { 100 char buf[256]; 101 102 /* 103 * Set up for linear addressing: try to allocate the 104 * kernel memory map then read the base-address back. 105 * vga->linear is a compatibility hack. 106 */ 107 if(vga->linear == 0){ 108 vga->ctlr->flag &= ~Ulinear; 109 return; 110 } 111 if(vga->ctlr->flag & Ulinear){ 112 sprint(buf, "0x%lux 0x%lux", vga->apz ? vga->apz : vga->vmz, vga->vma); 113 vgactlw("linear", buf); 114 vgactlr("addr", buf); 115 trace("linear->addr %s\n", buf); 116 vga->vmb = strtoul(buf, 0, 0); 117 } 118 else 119 vgactlw("linear", "0"); 120 } 121 122 char* 123 chanstr[32+1] = { 124 [1] "k1", 125 [2] "k2", 126 [4] "k4", 127 [8] "m8", 128 [16] "r5g6b5", 129 [24] "r8g8b8", 130 [32] "x8r8g8b8", 131 }; 132 133 void 134 main(int argc, char** argv) 135 { 136 char *bios, buf[256], sizeb[256], *p, *vsize, *psize, *type; 137 int virtual, len; 138 Ctlr *ctlr; 139 Vga *vga; 140 141 Binit(&stdout, 1, OWRITE); 142 143 bios = getenv("vgactlr"); 144 if((type = getenv("monitor")) == 0) 145 type = "vga"; 146 psize = vsize = "640x480x8"; 147 148 ARGBEGIN{ 149 150 case 'b': 151 bios = ARGF(); 152 break; 153 154 case 'B': 155 dumpbios(0x10000); 156 exits(0); 157 158 case 'c': 159 cflag = 1; 160 break; 161 162 case 'd': 163 dflag = 1; 164 break; 165 166 case 'i': 167 iflag = 1; 168 break; 169 170 case 'l': 171 lflag = 1; 172 break; 173 174 case 'm': 175 type = ARGF(); 176 break; 177 178 case 'p': 179 pflag = 1; 180 break; 181 182 case 'r': 183 /* 184 * rflag > 1 means "leave me alone, I know what I'm doing." 185 */ 186 rflag++; 187 break; 188 189 case 'v': 190 vflag = 1; 191 break; 192 193 case 'V': 194 vflag = 1; 195 Vflag = 1; 196 break; 197 198 case 'x': 199 dbname = ARGF(); 200 break; 201 202 default: 203 error(usage, argv0); 204 205 }ARGEND 206 207 virtual = 0; 208 switch(argc){ 209 case 1: 210 vsize = psize = argv[0]; 211 break; 212 case 2: 213 psize = argv[0]; 214 vsize = argv[1]; 215 virtual = 1; 216 break; 217 case 0: 218 break; 219 default: 220 error(usage, argv0); 221 } 222 223 vga = alloc(sizeof(Vga)); 224 if(bios){ 225 if((vga->offset = strtol(bios, &p, 0)) == 0 || *p++ != '=') 226 error("main: bad BIOS string format - %s\n", bios); 227 len = strlen(p); 228 vga->bios = alloc(len+1); 229 strncpy(vga->bios, p, len); 230 trace("main->BIOS %s\n", bios); 231 } 232 233 /* 234 * Try to identify the VGA card and grab 235 * registers. Print them out if requested. 236 */ 237 if(dbctlr(dbname, vga) == 0 || vga->ctlr == 0){ 238 Bprint(&stdout, "%s: controller not in %s\n", argv0, dbname); 239 dumpbios(256); 240 type = "vga"; 241 vsize = psize = "640x480x1"; 242 virtual = 0; 243 vga->ctlr = &generic; 244 vga->link = &generic; 245 } 246 247 trace("main->snarf\n"); 248 for(ctlr = vga->link; ctlr; ctlr = ctlr->link){ 249 if(ctlr->snarf == 0) 250 continue; 251 trace("%s->snarf\n", ctlr->name); 252 (*ctlr->snarf)(vga, ctlr); 253 } 254 255 if(pflag) 256 dump(vga); 257 258 for(ctlr = vga->link; ctlr; ctlr = ctlr->link) 259 if(ctlr->flag & Ferror) 260 error("%r"); 261 262 if(iflag || lflag){ 263 if(getenv(type)) 264 sprint(monitordb, "/env/%s", type); 265 else 266 strcpy(monitordb, dbname); 267 268 if((vga->mode = dbmode(monitordb, type, psize)) == 0) 269 error("main: %s@%s not in %s\n", type, psize, monitordb); 270 if(virtual){ 271 if((p = strchr(vsize, 'x')) == nil) 272 error("bad virtual size %s\n", vsize); 273 vga->virtx = atoi(vsize); 274 vga->virty = atoi(p+1); 275 if(vga->virtx < vga->mode->x || vga->virty < vga->mode->y) 276 error("virtual size smaller than physical size\n"); 277 vga->panning = 1; 278 } 279 else{ 280 vga->virtx = vga->mode->x; 281 vga->virty = vga->mode->y; 282 vga->panning = 0; 283 } 284 285 trace("vmf %d vmdf %d vf1 %lud vbw %lud\n", 286 vga->mode->frequency, vga->mode->deffrequency, 287 vga->f[1], vga->mode->videobw); 288 if(vga->mode->frequency == 0 && vga->mode->videobw != 0 && vga->f[1] != 0){ 289 /* 290 * boost clock as much as possible subject 291 * to video and memory bandwidth constraints 292 */ 293 ulong bytes, freq, membw; 294 double rr; 295 296 freq = vga->mode->videobw; 297 if(freq > vga->f[1]) 298 freq = vga->f[1]; 299 300 rr = (double)freq/(vga->mode->ht*vga->mode->vt); 301 if(rr > 85.0) /* >85Hz is ridiculous */ 302 rr = 85.0; 303 304 bytes = (vga->mode->x*vga->mode->y*vga->mode->z)/8; 305 membw = rr*bytes; 306 if(vga->membw != 0 && membw > vga->membw){ 307 membw = vga->membw; 308 rr = (double)membw/bytes; 309 } 310 311 freq = rr*(vga->mode->ht*vga->mode->vt); 312 vga->mode->frequency = freq; 313 314 trace("using frequency %lud rr %.2f membw %lud\n", 315 freq, rr, membw); 316 } 317 else if(vga->mode->frequency == 0) 318 vga->mode->frequency = vga->mode->deffrequency; 319 320 for(ctlr = vga->link; ctlr; ctlr = ctlr->link){ 321 if(ctlr->options == 0) 322 continue; 323 trace("%s->options\n", ctlr->name); 324 (*ctlr->options)(vga, ctlr); 325 } 326 327 for(ctlr = vga->link; ctlr; ctlr = ctlr->link){ 328 if(ctlr->init == 0) 329 continue; 330 trace("%s->init\n", ctlr->name); 331 (*ctlr->init)(vga, ctlr); 332 } 333 334 if(strcmp(vga->mode->chan, "") == 0){ 335 if(vga->mode->z < nelem(chanstr) && chanstr[vga->mode->z]) 336 strcpy(vga->mode->chan, chanstr[vga->mode->z]); 337 else 338 error("%s: unknown channel type to use for depth %d", vga->ctlr->name, vga->mode->z); 339 } 340 341 if(iflag || pflag) 342 dump(vga); 343 344 if(lflag){ 345 trace("main->load\n"); 346 if(vga->vmz && (vga->virtx*vga->virty*vga->mode->z)/8 > vga->vmz) 347 error("%s: not enough video memory - %lud\n", 348 vga->ctlr->name, vga->vmz); 349 350 if(vga->ctlr->type) 351 vgactlw("type", vga->ctlr->type); 352 else if(p = strchr(vga->ctlr->name, '-')){ 353 strncpy(buf, vga->ctlr->name, p - vga->ctlr->name); 354 buf[p - vga->ctlr->name] = 0; 355 vgactlw("type", buf); 356 } 357 else 358 vgactlw("type", vga->ctlr->name); 359 360 /* 361 * The new draw device needs linear mode set 362 * before size. 363 */ 364 linear(vga); 365 366 sprint(buf, "%ludx%ludx%d %s", 367 vga->virtx, vga->virty, 368 vga->mode->z, vga->mode->chan); 369 if(rflag){ 370 vgactlr("size", sizeb); 371 if(rflag < 2 && strcmp(buf, sizeb) != 0) 372 error("bad refresh: %s != %s\n", 373 buf, sizeb); 374 } 375 else 376 vgactlw("size", buf); 377 378 /* 379 * Turn off the display during the load. 380 */ 381 sequencer(vga, 0); 382 383 for(ctlr = vga->link; ctlr; ctlr = ctlr->link){ 384 if(ctlr->load == 0) 385 continue; 386 trace("%s->load\n", ctlr->name); 387 (*ctlr->load)(vga, ctlr); 388 } 389 390 sequencer(vga, 1); 391 392 vgactlw("drawinit", ""); 393 394 if(vga->hwgc == 0 || cflag) 395 vgactlw("hwgc", "off"); 396 else 397 vgactlw("hwgc", vga->hwgc->name); 398 399 if(vga->virtx != vga->mode->x || vga->virty != vga->mode->y){ 400 sprint(buf, "%dx%d", vga->mode->x, vga->mode->y); 401 vgactlw("actualsize", buf); 402 if(vga->panning) 403 vgactlw("panning", "on"); 404 } 405 406 if(pflag) 407 dump(vga); 408 } 409 } 410 411 trace("main->exits\n"); 412 exits(0); 413 } 414