main.c 9.5 KB

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