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 char *p; 102 103 /* 104 * Set up for linear addressing: try to allocate the 105 * kernel memory map then read the base-address back. 106 * vga->linear is a compatibility hack. 107 */ 108 if(vga->linear == 0){ 109 vga->ctlr->flag &= ~Ulinear; 110 return; 111 } 112 if(vga->ctlr->flag & Ulinear){ 113 /* 114 * If there's already an aperture don't bother trying 115 * to set up a new one. 116 */ 117 vgactlr("addr", buf); 118 if(atoi(buf)==0 && (buf[0]!='p' || buf[1]!=' ' || atoi(buf+2)==0)){ 119 sprint(buf, "0x%lux 0x%lux", vga->apz ? vga->apz : vga->vmz, vga->vma); 120 vgactlw("linear", buf); 121 vgactlr("addr", buf); 122 } 123 trace("linear->addr %s\n", buf); 124 /* 125 * old: addr 0x12345678 126 * new: addr p 0x12345678 v 0x82345678 size 0x123 127 */ 128 if(buf[0]=='p' && buf[1]==' '){ 129 vga->vmb = strtoul(buf+2, 0, 0); 130 p = strstr(buf, "size"); 131 if(p) 132 vga->apz = strtoul(p+4, 0, 0); 133 }else 134 vga->vmb = strtoul(buf, 0, 0); 135 } 136 else 137 vgactlw("linear", "0"); 138 } 139 140 char* 141 chanstr[32+1] = { 142 [1] "k1", 143 [2] "k2", 144 [4] "k4", 145 [8] "m8", 146 [16] "r5g6b5", 147 [24] "r8g8b8", 148 [32] "x8r8g8b8", 149 }; 150 151 void 152 main(int argc, char** argv) 153 { 154 char *bios, buf[256], sizeb[256], *p, *vsize, *psize; 155 char *type, *vtype; 156 int fd, virtual, len; 157 Ctlr *ctlr; 158 Vga *vga; 159 160 fmtinstall('H', encodefmt); 161 Binit(&stdout, 1, OWRITE); 162 163 bios = getenv("vgactlr"); 164 if((type = getenv("monitor")) == 0) 165 type = "vga"; 166 psize = vsize = "640x480x8"; 167 168 ARGBEGIN{ 169 170 case 'b': 171 bios = ARGF(); 172 break; 173 174 case 'B': 175 dumpbios(0x10000); 176 exits(0); 177 178 case 'c': 179 cflag = 1; 180 break; 181 182 case 'd': 183 dflag = 1; 184 break; 185 186 case 'i': 187 iflag = 1; 188 break; 189 190 case 'l': 191 lflag = 1; 192 break; 193 194 case 'm': 195 type = ARGF(); 196 break; 197 198 case 'p': 199 pflag = 1; 200 break; 201 202 case 'r': 203 /* 204 * rflag > 1 means "leave me alone, I know what I'm doing." 205 */ 206 rflag++; 207 break; 208 209 case 'v': 210 vflag = 1; 211 break; 212 213 case 'V': 214 vflag = 1; 215 Vflag = 1; 216 break; 217 218 case 'x': 219 dbname = ARGF(); 220 break; 221 222 default: 223 error(usage, argv0); 224 225 }ARGEND 226 227 virtual = 0; 228 switch(argc){ 229 case 1: 230 vsize = psize = argv[0]; 231 break; 232 case 2: 233 psize = argv[0]; 234 vsize = argv[1]; 235 virtual = 1; 236 break; 237 case 0: 238 break; 239 default: 240 error(usage, argv0); 241 } 242 243 if(lflag && strcmp(vsize, "text") == 0){ 244 vesatextmode(); 245 vgactlw("textmode", ""); 246 exits(0); 247 } 248 249 vga = alloc(sizeof(Vga)); 250 if(bios){ 251 if((vga->offset = strtol(bios, &p, 0)) == 0 || *p++ != '=') 252 error("main: bad BIOS string format - %s\n", bios); 253 len = strlen(p); 254 vga->bios = alloc(len+1); 255 strncpy(vga->bios, p, len); 256 trace("main->BIOS %s\n", bios); 257 } 258 259 /* 260 * Try to identify the VGA card and grab 261 * registers. Print them out if requested. 262 */ 263 if(strcmp(type, "vesa") == 0 264 || dbctlr(dbname, vga) == 0 || vga->ctlr == 0) 265 if(dbvesa(vga) == 0 || vga->ctlr == 0){ 266 Bprint(&stdout, "%s: controller not in %s, not vesa\n", argv0, dbname); 267 dumpbios(256); 268 type = "vga"; 269 vsize = psize = "640x480x1"; 270 virtual = 0; 271 vga->ctlr = &generic; 272 vga->link = &generic; 273 } 274 275 trace("main->snarf\n"); 276 for(ctlr = vga->link; ctlr; ctlr = ctlr->link){ 277 if(ctlr->snarf == 0) 278 continue; 279 trace("%s->snarf\n", ctlr->name); 280 (*ctlr->snarf)(vga, ctlr); 281 } 282 283 if(pflag) 284 dump(vga); 285 286 for(ctlr = vga->link; ctlr; ctlr = ctlr->link) 287 if(ctlr->flag & Ferror) 288 error("%r"); 289 290 if(iflag || lflag){ 291 if(getenv(type)) 292 snprint(monitordb, sizeof monitordb, "/env/%s", type); 293 else 294 strecpy(monitordb, monitordb+sizeof monitordb, dbname); 295 296 if(vga->vesa){ 297 strcpy(monitordb, "vesa bios"); 298 vga->mode = dbvesamode(psize); 299 }else 300 vga->mode = dbmode(monitordb, type, psize); 301 if(vga->mode == 0) 302 error("main: %s@%s not in %s\n", type, psize, monitordb); 303 304 if(virtual){ 305 if((p = strchr(vsize, 'x')) == nil) 306 error("bad virtual size %s\n", vsize); 307 vga->virtx = atoi(vsize); 308 vga->virty = atoi(p+1); 309 if(vga->virtx < vga->mode->x || vga->virty < vga->mode->y) 310 error("virtual size smaller than physical size\n"); 311 vga->panning = 1; 312 } 313 else{ 314 vga->virtx = vga->mode->x; 315 vga->virty = vga->mode->y; 316 vga->panning = 0; 317 } 318 319 trace("vmf %d vmdf %d vf1 %lud vbw %lud\n", 320 vga->mode->frequency, vga->mode->deffrequency, 321 vga->f[1], vga->mode->videobw); 322 if(vga->mode->frequency == 0 && vga->mode->videobw != 0 && vga->f[1] != 0){ 323 /* 324 * boost clock as much as possible subject 325 * to video and memory bandwidth constraints 326 */ 327 ulong bytes, freq, membw; 328 double rr; 329 330 freq = vga->mode->videobw; 331 if(freq > vga->f[1]) 332 freq = vga->f[1]; 333 334 rr = (double)freq/(vga->mode->ht*vga->mode->vt); 335 if(rr > 85.0) /* >85Hz is ridiculous */ 336 rr = 85.0; 337 338 bytes = (vga->mode->x*vga->mode->y*vga->mode->z)/8; 339 membw = rr*bytes; 340 if(vga->membw != 0 && membw > vga->membw){ 341 membw = vga->membw; 342 rr = (double)membw/bytes; 343 } 344 345 freq = rr*(vga->mode->ht*vga->mode->vt); 346 vga->mode->frequency = freq; 347 348 trace("using frequency %lud rr %.2f membw %lud\n", 349 freq, rr, membw); 350 } 351 else if(vga->mode->frequency == 0) 352 vga->mode->frequency = vga->mode->deffrequency; 353 354 for(ctlr = vga->link; ctlr; ctlr = ctlr->link){ 355 if(ctlr->options == 0) 356 continue; 357 trace("%s->options\n", ctlr->name); 358 (*ctlr->options)(vga, ctlr); 359 } 360 361 /* 362 * skip init for vesa - vesa will do the registers for us 363 */ 364 if(!vga->vesa) 365 for(ctlr = vga->link; ctlr; ctlr = ctlr->link){ 366 if(ctlr->init == 0) 367 continue; 368 trace("%s->init\n", ctlr->name); 369 (*ctlr->init)(vga, ctlr); 370 } 371 372 if(strcmp(vga->mode->chan, "") == 0){ 373 if(vga->mode->z < nelem(chanstr) && chanstr[vga->mode->z]) 374 strcpy(vga->mode->chan, chanstr[vga->mode->z]); 375 else 376 error("%s: unknown channel type to use for depth %d", vga->ctlr->name, vga->mode->z); 377 } 378 379 if(iflag || pflag) 380 dump(vga); 381 382 if(lflag){ 383 trace("main->load\n"); 384 if(vga->vmz && (vga->virtx*vga->virty*vga->mode->z)/8 > vga->vmz) 385 error("%s: not enough video memory - %lud\n", 386 vga->ctlr->name, vga->vmz); 387 388 if(vga->ctlr->type) 389 vtype = vga->ctlr->type; 390 else if(p = strchr(vga->ctlr->name, '-')){ 391 strncpy(buf, vga->ctlr->name, p - vga->ctlr->name); 392 buf[p - vga->ctlr->name] = 0; 393 vtype = buf; 394 } 395 else 396 vtype = vga->ctlr->name; 397 vgactlw("type", vtype); 398 399 /* 400 * VESA must be set up before linear. 401 * Set type to vesa for linear. 402 */ 403 if(vga->vesa){ 404 vesa.load(vga, vga->vesa); 405 if(vga->vesa->flag&Ferror) 406 error("vesa load error\n"); 407 vgactlw("type", vesa.name); 408 } 409 410 /* 411 * The new draw device needs linear mode set 412 * before size. 413 */ 414 linear(vga); 415 416 /* 417 * Linear is over so switch to other driver for 418 * acceleration. 419 */ 420 if(vga->vesa) 421 vgactlw("type", vtype); 422 423 sprint(buf, "%ludx%ludx%d %s", 424 vga->virtx, vga->virty, 425 vga->mode->z, vga->mode->chan); 426 if(rflag){ 427 vgactlr("size", sizeb); 428 if(rflag < 2 && strcmp(buf, sizeb) != 0) 429 error("bad refresh: %s != %s\n", 430 buf, sizeb); 431 } 432 else 433 vgactlw("size", buf); 434 435 /* 436 * No fiddling with registers if VESA set 437 * things up already. Sorry. 438 */ 439 if(!vga->vesa){ 440 /* 441 * Turn off the display during the load. 442 */ 443 sequencer(vga, 0); 444 445 for(ctlr = vga->link; ctlr; ctlr = ctlr->link){ 446 if(ctlr->load == 0 || ctlr == &vesa) 447 continue; 448 trace("%s->load\n", ctlr->name); 449 (*ctlr->load)(vga, ctlr); 450 } 451 452 sequencer(vga, 1); 453 } 454 455 vgactlw("drawinit", ""); 456 457 if(vga->hwgc == 0 || cflag) 458 vgactlw("hwgc", "soft"); 459 else 460 vgactlw("hwgc", vga->hwgc->name); 461 462 /* might as well initialize the cursor */ 463 if((fd = open("/dev/cursor", OWRITE)) >= 0){ 464 write(fd, buf, 0); 465 close(fd); 466 } 467 468 if(vga->virtx != vga->mode->x || vga->virty != vga->mode->y){ 469 sprint(buf, "%dx%d", vga->mode->x, vga->mode->y); 470 vgactlw("actualsize", buf); 471 if(vga->panning) 472 vgactlw("panning", "on"); 473 } 474 475 if(pflag) 476 dump(vga); 477 } 478 } 479 480 trace("main->exits\n"); 481 exits(0); 482 } 483