main.c 8.0 KB

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