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