vesa.c 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512
  1. #include <u.h>
  2. #include <libc.h>
  3. #include <bio.h>
  4. #include </386/include/ureg.h>
  5. typedef struct Ureg Ureg;
  6. #include "pci.h"
  7. #include "vga.h"
  8. typedef struct Vbe Vbe;
  9. typedef struct Vmode Vmode;
  10. enum
  11. {
  12. MemSize = 1024*1024,
  13. PageSize = 4096,
  14. RealModeBuf = 0x9000,
  15. };
  16. struct Vbe
  17. {
  18. int rmfd; /* /dev/realmode */
  19. int memfd; /* /dev/realmem */
  20. uchar *mem; /* copy of memory; 1MB */
  21. uchar *isvalid; /* 1byte per 4kB in mem */
  22. uchar *buf;
  23. uchar *modebuf;
  24. };
  25. struct Vmode
  26. {
  27. char name[32];
  28. char chan[32];
  29. int id;
  30. int attr; /* flags */
  31. int bpl;
  32. int dx, dy;
  33. int depth;
  34. char *model;
  35. int r, g, b, x;
  36. int ro, go, bo, xo;
  37. int directcolor; /* flags */
  38. ulong paddr;
  39. };
  40. #define WORD(p) ((p)[0] | ((p)[1]<<8))
  41. #define LONG(p) ((p)[0] | ((p)[1]<<8) | ((p)[2]<<16) | ((p)[3]<<24))
  42. #define PWORD(p, v) (p)[0] = (v); (p)[1] = (v)>>8
  43. #define PLONG(p, v) (p)[0] = (v); (p)[1] = (v)>>8; (p)[2] = (v)>>16; (p)[3] = (v)>>24
  44. static Vbe *vbe;
  45. Vbe *mkvbe(void);
  46. int vbecheck(Vbe*);
  47. uchar *vbemodes(Vbe*);
  48. int vbemodeinfo(Vbe*, int, Vmode*);
  49. int vbegetmode(Vbe*);
  50. int vbesetmode(Vbe*, int);
  51. void vbeprintinfo(Vbe*);
  52. void vbeprintmodeinfo(Vbe*, int);
  53. int vbesnarf(Vbe*, Vga*);
  54. int
  55. dbvesa(Vga* vga)
  56. {
  57. vbe = mkvbe();
  58. if(vbe == nil){
  59. fprint(2, "mkvbe: %r\n");
  60. return 0;
  61. }
  62. if(vbecheck(vbe) < 0){
  63. fprint(2, "dbvesa: %r\n");
  64. return 0;
  65. }
  66. vga->link = alloc(sizeof(Ctlr));
  67. *vga->link = vesa;
  68. vga->vesa = vga->link;
  69. vga->ctlr = vga->link;
  70. vga->link->link = alloc(sizeof(Ctlr));
  71. *vga->link->link = softhwgc;
  72. vga->hwgc = vga->link->link;
  73. return 1;
  74. }
  75. Mode*
  76. dbvesamode(char *mode)
  77. {
  78. uchar *p, *ep;
  79. Vmode vm;
  80. Mode *m;
  81. if(vbe == nil)
  82. return nil;
  83. p = vbemodes(vbe);
  84. if(p == nil)
  85. return nil;
  86. for(ep=p+1024; (p[0]!=0xFF || p[1]!=0xFF) && p<ep; p+=2){
  87. if(vbemodeinfo(vbe, WORD(p), &vm) < 0)
  88. continue;
  89. if(strcmp(vm.name, mode) == 0)
  90. goto havemode;
  91. }
  92. werrstr("no such vesa mode");
  93. return nil;
  94. havemode:
  95. m = alloc(sizeof(Mode));
  96. strcpy(m->type, "vesa");
  97. strcpy(m->size, vm.name);
  98. strcpy(m->chan, vm.chan);
  99. m->frequency = 100;
  100. m->x = vm.dx;
  101. m->y = vm.dy;
  102. m->z = vm.depth;
  103. m->ht = m->x;
  104. m->shb = m->x;
  105. m->ehb = m->x;
  106. m->shs = m->x;
  107. m->ehs = m->x;
  108. m->vt = m->y;
  109. m->vrs = m->y;
  110. m->vre = m->y;
  111. m->attr = alloc(sizeof(Attr));
  112. m->attr->attr = "id";
  113. m->attr->val = alloc(32);
  114. sprint(m->attr->val, "0x%x", vm.id);
  115. return m;
  116. }
  117. static void
  118. snarf(Vga* vga, Ctlr* ctlr)
  119. {
  120. if(!vbe)
  121. vbe = mkvbe();
  122. if(vbe)
  123. vga->vesa = ctlr;
  124. vbesnarf(vbe, vga);
  125. vga->linear = 1;
  126. ctlr->flag |= Hlinear|Ulinear;
  127. }
  128. static void
  129. load(Vga* vga, Ctlr* ctlr)
  130. {
  131. if(vbe == nil)
  132. error("no vesa bios");
  133. if(vbesetmode(vbe, atoi(dbattr(vga->mode->attr, "id"))) < 0){
  134. ctlr->flag |= Ferror;
  135. fprint(2, "vbesetmode: %r\n");
  136. }
  137. }
  138. static void
  139. dump(Vga*, Ctlr*)
  140. {
  141. uchar *p, *ep;
  142. if(!vbe){
  143. Bprint(&stdout, "no vesa bios\n");
  144. return;
  145. }
  146. vbeprintinfo(vbe);
  147. p = vbemodes(vbe);
  148. if(p){
  149. for(ep=p+1024; (p[0]!=0xFF || p[1]!=0xFF) && p<ep; p+=2)
  150. vbeprintmodeinfo(vbe, WORD(p));
  151. }
  152. }
  153. Ctlr vesa = {
  154. "vesa", /* name */
  155. snarf, /* snarf */
  156. 0, /* options */
  157. 0, /* init */
  158. load, /* load */
  159. dump, /* dump */
  160. };
  161. Ctlr softhwgc = {
  162. "soft",
  163. };
  164. /*
  165. * VESA bios extension
  166. */
  167. typedef struct Flag Flag;
  168. struct Flag {
  169. int bit;
  170. char *desc;
  171. };
  172. static Flag capabilityflag[] = {
  173. 0x01, "8-bit-dac",
  174. 0x02, "not-vga",
  175. 0x04, "ramdac-needs-blank",
  176. 0x08, "stereoscopic",
  177. 0x10, "stereo-evc",
  178. 0
  179. };
  180. static Flag modeattributesflags[] = {
  181. 1<<0, "supported",
  182. 1<<2, "tty",
  183. 1<<3, "color",
  184. 1<<4, "graphics",
  185. 1<<5, "not-vga",
  186. 1<<6, "no-windowed-vga",
  187. 1<<7, "linear",
  188. 1<<8, "double-scan",
  189. 1<<9, "interlace",
  190. 1<<10, "triple-buffer",
  191. 1<<11, "stereoscopic",
  192. 1<<12, "dual-start-addr",
  193. 0
  194. };
  195. static Flag winattributesflags[] = {
  196. 1<<0, "relocatable",
  197. 1<<1, "readable",
  198. 1<<2, "writeable",
  199. 0
  200. };
  201. static Flag directcolorflags[] = {
  202. 1<<0, "programmable-color-ramp",
  203. 1<<1, "x-usable",
  204. 0
  205. };
  206. static char *modelstr[] = {
  207. "text", "cga", "hercules", "planar", "packed", "non-chain4", "direct", "YUV"
  208. };
  209. static void
  210. printflags(Flag *f, int b)
  211. {
  212. int i;
  213. for(i=0; f[i].bit; i++)
  214. if(f[i].bit & b)
  215. Bprint(&stdout, " %s", f[i].desc);
  216. Bprint(&stdout, "\n");
  217. }
  218. Vbe*
  219. mkvbe(void)
  220. {
  221. Vbe *vbe;
  222. vbe = alloc(sizeof(Vbe));
  223. if((vbe->rmfd = open("/dev/realmode", ORDWR)) < 0)
  224. return nil;
  225. if((vbe->memfd = open("/dev/realmodemem", ORDWR)) < 0)
  226. return nil;
  227. vbe->mem = alloc(MemSize);
  228. vbe->isvalid = alloc(MemSize/PageSize);
  229. vbe->buf = alloc(PageSize);
  230. vbe->modebuf = alloc(PageSize);
  231. return vbe;
  232. }
  233. static void
  234. loadpage(Vbe *vbe, int p)
  235. {
  236. if(p >= MemSize/PageSize || vbe->isvalid[p])
  237. return;
  238. if(pread(vbe->memfd, vbe->mem+p*PageSize, PageSize, p*PageSize) != PageSize)
  239. error("read /dev/realmodemem: %r\n");
  240. vbe->isvalid[p] = 1;
  241. }
  242. static void*
  243. unfarptr(Vbe *vbe, uchar *p)
  244. {
  245. int seg, off;
  246. seg = WORD(p+2);
  247. off = WORD(p);
  248. if(seg==0 && off==0)
  249. return nil;
  250. off += seg;
  251. if(off >= MemSize)
  252. return nil;
  253. loadpage(vbe, off/PageSize);
  254. loadpage(vbe, off/PageSize+1); /* just in case */
  255. return vbe->mem+off;
  256. }
  257. uchar*
  258. vbesetup(Vbe *vbe, Ureg *u, int ax)
  259. {
  260. memset(vbe->buf, 0, PageSize);
  261. memset(u, 0, sizeof *u);
  262. u->ax = ax;
  263. u->es = (RealModeBuf>>4)&0xF000;
  264. u->di = RealModeBuf&0xFFFF;
  265. return vbe->buf;
  266. }
  267. int
  268. vbecall(Vbe *vbe, Ureg *u)
  269. {
  270. u->trap = 0x10;
  271. if(pwrite(vbe->memfd, vbe->buf, PageSize, RealModeBuf) != PageSize)
  272. error("write /dev/realmodemem: %r\n");
  273. if(pwrite(vbe->rmfd, u, sizeof *u, 0) != sizeof *u)
  274. error("write /dev/realmode: %r\n");
  275. if(pread(vbe->rmfd, u, sizeof *u, 0) != sizeof *u)
  276. error("read /dev/realmode: %r\n");
  277. if(pread(vbe->memfd, vbe->buf, PageSize, RealModeBuf) != PageSize)
  278. error("read /dev/realmodemem: %r\n");
  279. if((u->ax&0xFFFF) != 0x004F){
  280. werrstr("VBE error %#.4lux", u->ax&0xFFFF);
  281. return -1;
  282. }
  283. memset(vbe->isvalid, 0, MemSize/PageSize);
  284. return 0;
  285. }
  286. int
  287. vbecheck(Vbe *vbe)
  288. {
  289. uchar *p;
  290. Ureg u;
  291. p = vbesetup(vbe, &u, 0x4F00);
  292. strcpy((char*)p, "VBE2");
  293. if(vbecall(vbe, &u) < 0)
  294. return -1;
  295. if(memcmp(p, "VESA", 4) != 0 || p[5] < 2)
  296. return -1;
  297. return 0;
  298. }
  299. int
  300. vbesnarf(Vbe *vbe, Vga *vga)
  301. {
  302. uchar *p;
  303. Ureg u;
  304. p = vbesetup(vbe, &u, 0x4F00);
  305. strcpy((char*)p, "VBE2");
  306. if(vbecall(vbe, &u) < 0)
  307. return -1;
  308. if(memcmp(p, "VESA", 4) != 0 || p[5] < 2)
  309. return -1;
  310. vga->apz = WORD(p+18)*0x10000UL;
  311. return 0;
  312. }
  313. void
  314. vbeprintinfo(Vbe *vbe)
  315. {
  316. uchar *p;
  317. Ureg u;
  318. p = vbesetup(vbe, &u, 0x4F00);
  319. strcpy((char*)p, "VBE2");
  320. if(vbecall(vbe, &u) < 0)
  321. return;
  322. printitem("vesa", "sig");
  323. Bprint(&stdout, "%.4s %d.%d\n", (char*)p, p[5], p[4]);
  324. if(p[5] < 2)
  325. return;
  326. printitem("vesa", "oem");
  327. Bprint(&stdout, "%s %d.%d\n", unfarptr(vbe, p+6), p[21], p[20]);
  328. printitem("vesa", "vendor");
  329. Bprint(&stdout, "%s\n", unfarptr(vbe, p+22));
  330. printitem("vesa", "product");
  331. Bprint(&stdout, "%s\n", unfarptr(vbe, p+26));
  332. printitem("vesa", "rev");
  333. Bprint(&stdout, "%s\n", unfarptr(vbe, p+30));
  334. printitem("vesa", "cap");
  335. printflags(capabilityflag, p[10]);
  336. printitem("vesa", "mem");
  337. Bprint(&stdout, "%lud\n", WORD(p+18)*0x10000UL);
  338. }
  339. uchar*
  340. vbemodes(Vbe *vbe)
  341. {
  342. uchar *p;
  343. Ureg u;
  344. p = vbesetup(vbe, &u, 0x4F00);
  345. strcpy((char*)p, "VBE2");
  346. if(vbecall(vbe, &u) < 0)
  347. return nil;
  348. memmove(vbe->modebuf, unfarptr(vbe, p+14), 1024);
  349. return vbe->modebuf;
  350. }
  351. int
  352. vbemodeinfo(Vbe *vbe, int id, Vmode *m)
  353. {
  354. uchar *p;
  355. Ureg u;
  356. p = vbesetup(vbe, &u, 0x4F01);
  357. u.cx = id;
  358. if(vbecall(vbe, &u) < 0)
  359. return -1;
  360. m->id = id;
  361. m->attr = WORD(p);
  362. m->bpl = WORD(p+16);
  363. m->dx = WORD(p+18);
  364. m->dy = WORD(p+20);
  365. m->depth = p[25];
  366. m->model = p[27] < nelem(modelstr) ? modelstr[p[27]] : "unknown";
  367. m->r = p[31];
  368. m->g = p[33];
  369. m->b = p[35];
  370. m->x = p[37];
  371. m->ro = p[32];
  372. m->go = p[34];
  373. m->bo = p[36];
  374. m->xo = p[38];
  375. m->directcolor = p[39];
  376. m->paddr = LONG(p+40);
  377. snprint(m->name, sizeof m->name, "%dx%dx%d",
  378. m->dx, m->dy, m->depth);
  379. if(m->depth <= 8)
  380. snprint(m->chan, sizeof m->chan, "m%d", m->depth);
  381. else if(m->xo)
  382. snprint(m->chan, sizeof m->chan, "x%dr%dg%db%d", m->x, m->r, m->g, m->b);
  383. else
  384. snprint(m->chan, sizeof m->chan, "r%dg%db%d", m->r, m->g, m->b);
  385. return 0;
  386. }
  387. void
  388. vbeprintmodeinfo(Vbe *vbe, int id)
  389. {
  390. Vmode m;
  391. if(vbemodeinfo(vbe, id, &m) < 0)
  392. return;
  393. printitem("vesa", "mode");
  394. Bprint(&stdout, "0x%ux %s %s %s\n",
  395. m.id, m.name, m.chan, m.model);
  396. }
  397. int
  398. vbegetmode(Vbe *vbe)
  399. {
  400. Ureg u;
  401. vbesetup(vbe, &u, 0x4F03);
  402. if(vbecall(vbe, &u) < 0)
  403. return 0;
  404. return u.bx;
  405. }
  406. int
  407. vbesetmode(Vbe *vbe, int id)
  408. {
  409. uchar *p;
  410. Ureg u;
  411. p = vbesetup(vbe, &u, 0x4F02);
  412. if(id != 3)
  413. id |= 3<<14; /* graphics: use linear, do not clear */
  414. u.bx = id;
  415. USED(p);
  416. /*
  417. * can set mode specifics (ht hss hse vt vss vse 0 clockhz refreshhz):
  418. *
  419. u.bx |= 1<<11;
  420. n = atoi(argv[2]); PWORD(p, n); p+=2;
  421. n = atoi(argv[3]); PWORD(p, n); p+=2;
  422. n = atoi(argv[4]); PWORD(p, n); p+=2;
  423. n = atoi(argv[5]); PWORD(p, n); p+=2;
  424. n = atoi(argv[6]); PWORD(p, n); p+=2;
  425. n = atoi(argv[7]); PWORD(p, n); p+=2;
  426. *p++ = atoi(argv[8]);
  427. n = atoi(argv[9]); PLONG(p, n); p += 4;
  428. n = atoi(argv[10]); PWORD(p, n); p += 2;
  429. if(p != vbe.buf+19){
  430. fprint(2, "prog error\n");
  431. return;
  432. }
  433. *
  434. */
  435. return vbecall(vbe, &u);
  436. }
  437. void
  438. vesatextmode(void)
  439. {
  440. if(vbe == nil){
  441. vbe = mkvbe();
  442. if(!vbe)
  443. error("mkvbe: %r\n");
  444. }
  445. if(vbecheck(vbe) < 0)
  446. error("vbecheck: %r\n");
  447. if(vbesetmode(vbe, 3) < 0)
  448. error("vbesetmode: %r\n");
  449. }