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 */ 256 if(strcmp(type, "vesa") == 0 257 || dbctlr(dbname, vga) == 0 || vga->ctlr == 0) 258 if(dbvesa(vga) == 0 || vga->ctlr == 0){ 259 Bprint(&stdout, "%s: controller not in %s, not vesa\n", argv0, dbname); 260 dumpbios(256); 261 type = "vga"; 262 vsize = psize = "640x480x1"; 263 virtual = 0; 264 vga->ctlr = &generic; 265 vga->link = &generic; 266 } 267 268 trace("main->snarf\n"); 269 for(ctlr = vga->link; ctlr; ctlr = ctlr->link){ 270 if(ctlr->snarf == 0) 271 continue; 272 trace("%s->snarf\n", ctlr->name); 273 (*ctlr->snarf)(vga, ctlr); 274 } 275 276 if(pflag) 277 dump(vga); 278 279 for(ctlr = vga->link; ctlr; ctlr = ctlr->link) 280 if(ctlr->flag & Ferror) 281 error("%r"); 282 283 if(iflag || lflag){ 284 if(getenv(type)) 285 snprint(monitordb, sizeof monitordb, "/env/%s", type); 286 else 287 strecpy(monitordb, monitordb+sizeof monitordb, dbname); 288 289 if(vga->vesa){ 290 strcpy(monitordb, "vesa bios"); 291 vga->mode = dbvesamode(psize); 292 }else 293 vga->mode = dbmode(monitordb, type, psize); 294 if(vga->mode == 0) 295 error("main: %s@%s not in %s\n", type, psize, monitordb); 296 297 if(virtual){ 298 if((p = strchr(vsize, 'x')) == nil) 299 error("bad virtual size %s\n", vsize); 300 vga->virtx = atoi(vsize); 301 vga->virty = atoi(p+1); 302 if(vga->virtx < vga->mode->x || vga->virty < vga->mode->y) 303 error("virtual size smaller than physical size\n"); 304 vga->panning = 1; 305 } 306 else{ 307 vga->virtx = vga->mode->x; 308 vga->virty = vga->mode->y; 309 vga->panning = 0; 310 } 311 312 trace("vmf %d vmdf %d vf1 %lud vbw %lud\n", 313 vga->mode->frequency, vga->mode->deffrequency, 314 vga->f[1], vga->mode->videobw); 315 if(vga->mode->frequency == 0 && vga->mode->videobw != 0 && vga->f[1] != 0){ 316 /* 317 * boost clock as much as possible subject 318 * to video and memory bandwidth constraints 319 */ 320 ulong bytes, freq, membw; 321 double rr; 322 323 freq = vga->mode->videobw; 324 if(freq > vga->f[1]) 325 freq = vga->f[1]; 326 327 rr = (double)freq/(vga->mode->ht*vga->mode->vt); 328 if(rr > 85.0) /* >85Hz is ridiculous */ 329 rr = 85.0; 330 331 bytes = (vga->mode->x*vga->mode->y*vga->mode->z)/8; 332 membw = rr*bytes; 333 if(vga->membw != 0 && membw > vga->membw){ 334 membw = vga->membw; 335 rr = (double)membw/bytes; 336 } 337 338 freq = rr*(vga->mode->ht*vga->mode->vt); 339 vga->mode->frequency = freq; 340 341 trace("using frequency %lud rr %.2f membw %lud\n", 342 freq, rr, membw); 343 } 344 else if(vga->mode->frequency == 0) 345 vga->mode->frequency = vga->mode->deffrequency; 346 347 for(ctlr = vga->link; ctlr; ctlr = ctlr->link){ 348 if(ctlr->options == 0) 349 continue; 350 trace("%s->options\n", ctlr->name); 351 (*ctlr->options)(vga, ctlr); 352 } 353 354 /* 355 * skip init for vesa - vesa will do the registers for us 356 */ 357 if(!vga->vesa) 358 for(ctlr = vga->link; ctlr; ctlr = ctlr->link){ 359 if(ctlr->init == 0) 360 continue; 361 trace("%s->init\n", ctlr->name); 362 (*ctlr->init)(vga, ctlr); 363 } 364 365 if(strcmp(vga->mode->chan, "") == 0){ 366 if(vga->mode->z < nelem(chanstr) && chanstr[vga->mode->z]) 367 strcpy(vga->mode->chan, chanstr[vga->mode->z]); 368 else 369 error("%s: unknown channel type to use for depth %d", vga->ctlr->name, vga->mode->z); 370 } 371 372 if(iflag || pflag) 373 dump(vga); 374 375 if(lflag){ 376 trace("main->load\n"); 377 if(vga->vmz && (vga->virtx*vga->virty*vga->mode->z)/8 > vga->vmz) 378 error("%s: not enough video memory - %lud\n", 379 vga->ctlr->name, vga->vmz); 380 381 if(vga->ctlr->type) 382 vtype = vga->ctlr->type; 383 else if(p = strchr(vga->ctlr->name, '-')){ 384 strncpy(buf, vga->ctlr->name, p - vga->ctlr->name); 385 buf[p - vga->ctlr->name] = 0; 386 vtype = buf; 387 } 388 else 389 vtype = vga->ctlr->name; 390 vgactlw("type", vtype); 391 392 /* 393 * VESA must be set up before linear. 394 * Set type to vesa for linear. 395 */ 396 if(vga->vesa){ 397 vesa.load(vga, vga->vesa); 398 if(vga->vesa->flag&Ferror) 399 error("vesa load error\n"); 400 vgactlw("type", vesa.name); 401 } 402 403 /* 404 * The new draw device needs linear mode set 405 * before size. 406 */ 407 linear(vga); 408 409 /* 410 * Linear is over so switch to other driver for 411 * acceleration. 412 */ 413 if(vga->vesa) 414 vgactlw("type", vtype); 415 416 sprint(buf, "%ludx%ludx%d %s", 417 vga->virtx, vga->virty, 418 vga->mode->z, vga->mode->chan); 419 if(rflag){ 420 vgactlr("size", sizeb); 421 if(rflag < 2 && strcmp(buf, sizeb) != 0) 422 error("bad refresh: %s != %s\n", 423 buf, sizeb); 424 } 425 else 426 vgactlw("size", buf); 427 428 /* 429 * No fiddling with registers if VESA set 430 * things up already. Sorry. 431 */ 432 if(!vga->vesa){ 433 /* 434 * Turn off the display during the load. 435 */ 436 sequencer(vga, 0); 437 438 for(ctlr = vga->link; ctlr; ctlr = ctlr->link){ 439 if(ctlr->load == 0 || ctlr == &vesa) 440 continue; 441 trace("%s->load\n", ctlr->name); 442 (*ctlr->load)(vga, ctlr); 443 } 444 445 sequencer(vga, 1); 446 } 447 448 vgactlw("drawinit", ""); 449 450 if(vga->hwgc == 0 || cflag) 451 vgactlw("hwgc", "soft"); 452 else 453 vgactlw("hwgc", vga->hwgc->name); 454 455 /* might as well initialize the cursor */ 456 if((fd = open("/dev/cursor", OWRITE)) >= 0){ 457 write(fd, buf, 0); 458 close(fd); 459 } 460 461 if(vga->virtx != vga->mode->x || vga->virty != vga->mode->y){ 462 sprint(buf, "%dx%d", vga->mode->x, vga->mode->y); 463 vgactlw("actualsize", buf); 464 if(vga->panning) 465 vgactlw("panning", "on"); 466 } 467 468 if(pflag) 469 dump(vga); 470 } 471 } 472 473 trace("main->exits\n"); 474 exits(0); 475 } 476