devvga.c 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498
  1. /*
  2. * VGA controller
  3. */
  4. #include "u.h"
  5. #include "../port/lib.h"
  6. #include "mem.h"
  7. #include "dat.h"
  8. #include "fns.h"
  9. #include "io.h"
  10. #include "../port/error.h"
  11. #define Image IMAGE
  12. #include <draw.h>
  13. #include <memdraw.h>
  14. #include <cursor.h>
  15. #include "screen.h"
  16. enum {
  17. Qdir,
  18. Qvgabios,
  19. Qvgactl,
  20. Qvgaovl,
  21. Qvgaovlctl,
  22. };
  23. static Dirtab vgadir[] = {
  24. ".", { Qdir, 0, QTDIR }, 0, 0550,
  25. "vgabios", { Qvgabios, 0 }, 0x100000, 0440,
  26. "vgactl", { Qvgactl, 0 }, 0, 0660,
  27. "vgaovl", { Qvgaovl, 0 }, 0, 0660,
  28. "vgaovlctl", { Qvgaovlctl, 0 }, 0, 0660,
  29. };
  30. enum {
  31. CMactualsize,
  32. CMblank,
  33. CMblanktime,
  34. CMdrawinit,
  35. CMhwaccel,
  36. CMhwblank,
  37. CMhwgc,
  38. CMlinear,
  39. CMpalettedepth,
  40. CMpanning,
  41. CMsize,
  42. CMtextmode,
  43. CMtype,
  44. CMunblank,
  45. };
  46. static Cmdtab vgactlmsg[] = {
  47. CMactualsize, "actualsize", 2,
  48. CMblank, "blank", 1,
  49. CMblanktime, "blanktime", 2,
  50. CMdrawinit, "drawinit", 1,
  51. CMhwaccel, "hwaccel", 2,
  52. CMhwblank, "hwblank", 2,
  53. CMhwgc, "hwgc", 2,
  54. CMlinear, "linear", 0,
  55. CMpalettedepth, "palettedepth", 2,
  56. CMpanning, "panning", 2,
  57. CMsize, "size", 3,
  58. CMtextmode, "textmode", 1,
  59. CMtype, "type", 2,
  60. CMunblank, "unblank", 1,
  61. };
  62. static void
  63. vgareset(void)
  64. {
  65. /* reserve the 'standard' vga registers */
  66. if(ioalloc(0x2b0, 0x2df-0x2b0+1, 0, "vga") < 0)
  67. panic("vga ports already allocated");
  68. if(ioalloc(0x3c0, 0x3da-0x3c0+1, 0, "vga") < 0)
  69. panic("vga ports already allocated");
  70. conf.monitor = 1;
  71. }
  72. static Chan*
  73. vgaattach(char* spec)
  74. {
  75. if(*spec && strcmp(spec, "0"))
  76. error(Eio);
  77. return devattach('v', spec);
  78. }
  79. Walkqid*
  80. vgawalk(Chan* c, Chan *nc, char** name, int nname)
  81. {
  82. return devwalk(c, nc, name, nname, vgadir, nelem(vgadir), devgen);
  83. }
  84. static int
  85. vgastat(Chan* c, uchar* dp, int n)
  86. {
  87. return devstat(c, dp, n, vgadir, nelem(vgadir), devgen);
  88. }
  89. static Chan*
  90. vgaopen(Chan* c, int omode)
  91. {
  92. VGAscr *scr;
  93. static char *openctl = "openctl\n";
  94. scr = &vgascreen[0];
  95. if ((ulong)c->qid.path == Qvgaovlctl) {
  96. if (scr->dev && scr->dev->ovlctl)
  97. scr->dev->ovlctl(scr, c, openctl, strlen(openctl));
  98. else
  99. error(Enonexist);
  100. }
  101. return devopen(c, omode, vgadir, nelem(vgadir), devgen);
  102. }
  103. static void
  104. vgaclose(Chan* c)
  105. {
  106. VGAscr *scr;
  107. static char *closectl = "closectl\n";
  108. scr = &vgascreen[0];
  109. if((ulong)c->qid.path == Qvgaovlctl)
  110. if(scr->dev && scr->dev->ovlctl){
  111. if(waserror()){
  112. print("ovlctl error: %s\n", up->errstr);
  113. return;
  114. }
  115. scr->dev->ovlctl(scr, c, closectl, strlen(closectl));
  116. poperror();
  117. }
  118. }
  119. static void
  120. checkport(int start, int end)
  121. {
  122. /* standard vga regs are OK */
  123. if(start >= 0x2b0 && end <= 0x2df+1)
  124. return;
  125. if(start >= 0x3c0 && end <= 0x3da+1)
  126. return;
  127. if(iounused(start, end))
  128. return;
  129. error(Eperm);
  130. }
  131. static long
  132. vgaread(Chan* c, void* a, long n, vlong off)
  133. {
  134. int len;
  135. char *p, *s;
  136. VGAscr *scr;
  137. ulong offset = off;
  138. char chbuf[30];
  139. switch((ulong)c->qid.path){
  140. case Qdir:
  141. return devdirread(c, a, n, vgadir, nelem(vgadir), devgen);
  142. case Qvgabios:
  143. if(offset >= 0x100000)
  144. return 0;
  145. if(offset+n >= 0x100000)
  146. n = 0x100000 - offset;
  147. memmove(a, (uchar*)kaddr(0)+offset, n);
  148. return n;
  149. case Qvgactl:
  150. scr = &vgascreen[0];
  151. p = malloc(READSTR);
  152. if(waserror()){
  153. free(p);
  154. nexterror();
  155. }
  156. len = 0;
  157. if(scr->dev)
  158. s = scr->dev->name;
  159. else
  160. s = "cga";
  161. len += snprint(p+len, READSTR-len, "type %s\n", s);
  162. if(scr->gscreen) {
  163. len += snprint(p+len, READSTR-len, "size %dx%dx%d %s\n",
  164. scr->gscreen->r.max.x, scr->gscreen->r.max.y,
  165. scr->gscreen->depth, chantostr(chbuf, scr->gscreen->chan));
  166. if(Dx(scr->gscreen->r) != Dx(physgscreenr)
  167. || Dy(scr->gscreen->r) != Dy(physgscreenr))
  168. len += snprint(p+len, READSTR-len, "actualsize %dx%d\n",
  169. physgscreenr.max.x, physgscreenr.max.y);
  170. }
  171. len += snprint(p+len, READSTR-len, "blank time %lud idle %d state %s\n",
  172. blanktime, drawidletime(), scr->isblank ? "off" : "on");
  173. len += snprint(p+len, READSTR-len, "hwaccel %s\n", hwaccel ? "on" : "off");
  174. len += snprint(p+len, READSTR-len, "hwblank %s\n", hwblank ? "on" : "off");
  175. len += snprint(p+len, READSTR-len, "panning %s\n", panning ? "on" : "off");
  176. len += snprint(p+len, READSTR-len, "addr p 0x%lux v 0x%p size 0x%ux\n", scr->paddr, scr->vaddr, scr->apsize);
  177. USED(len);
  178. n = readstr(offset, a, n, p);
  179. poperror();
  180. free(p);
  181. return n;
  182. case Qvgaovl:
  183. case Qvgaovlctl:
  184. error(Ebadusefd);
  185. break;
  186. default:
  187. error(Egreg);
  188. break;
  189. }
  190. return 0;
  191. }
  192. static char Ebusy[] = "vga already configured";
  193. static void
  194. vgactl(Cmdbuf *cb)
  195. {
  196. int align, i, size, x, y, z;
  197. char *chanstr, *p;
  198. ulong chan;
  199. Cmdtab *ct;
  200. VGAscr *scr;
  201. extern VGAdev *vgadev[];
  202. extern VGAcur *vgacur[];
  203. scr = &vgascreen[0];
  204. ct = lookupcmd(cb, vgactlmsg, nelem(vgactlmsg));
  205. switch(ct->index){
  206. case CMhwgc:
  207. if(strcmp(cb->f[1], "off") == 0){
  208. lock(&cursor);
  209. if(scr->cur){
  210. if(scr->cur->disable)
  211. scr->cur->disable(scr);
  212. scr->cur = nil;
  213. }
  214. unlock(&cursor);
  215. return;
  216. }
  217. if(strcmp(cb->f[1], "soft") == 0){
  218. lock(&cursor);
  219. swcursorinit();
  220. if(scr->cur && scr->cur->disable)
  221. scr->cur->disable(scr);
  222. scr->cur = &swcursor;
  223. if(scr->cur->enable)
  224. scr->cur->enable(scr);
  225. unlock(&cursor);
  226. return;
  227. }
  228. for(i = 0; vgacur[i]; i++){
  229. if(strcmp(cb->f[1], vgacur[i]->name))
  230. continue;
  231. lock(&cursor);
  232. if(scr->cur && scr->cur->disable)
  233. scr->cur->disable(scr);
  234. scr->cur = vgacur[i];
  235. if(scr->cur->enable)
  236. scr->cur->enable(scr);
  237. unlock(&cursor);
  238. return;
  239. }
  240. break;
  241. case CMtype:
  242. for(i = 0; vgadev[i]; i++){
  243. if(strcmp(cb->f[1], vgadev[i]->name))
  244. continue;
  245. if(scr->dev && scr->dev->disable)
  246. scr->dev->disable(scr);
  247. scr->dev = vgadev[i];
  248. if(scr->dev->enable)
  249. scr->dev->enable(scr);
  250. return;
  251. }
  252. break;
  253. case CMtextmode:
  254. screeninit();
  255. return;
  256. case CMsize:
  257. x = strtoul(cb->f[1], &p, 0);
  258. if(x == 0 || x > 10240)
  259. error(Ebadarg);
  260. if(*p)
  261. p++;
  262. y = strtoul(p, &p, 0);
  263. if(y == 0 || y > 10240)
  264. error(Ebadarg);
  265. if(*p)
  266. p++;
  267. z = strtoul(p, &p, 0);
  268. chanstr = cb->f[2];
  269. if((chan = strtochan(chanstr)) == 0)
  270. error("bad channel");
  271. if(chantodepth(chan) != z)
  272. error("depth, channel do not match");
  273. cursoroff(1);
  274. deletescreenimage();
  275. if(screensize(x, y, z, chan))
  276. error(Egreg);
  277. vgascreenwin(scr);
  278. resetscreenimage();
  279. cursoron(1);
  280. return;
  281. case CMactualsize:
  282. if(scr->gscreen == nil)
  283. error("set the screen size first");
  284. x = strtoul(cb->f[1], &p, 0);
  285. if(x == 0 || x > 2048)
  286. error(Ebadarg);
  287. if(*p)
  288. p++;
  289. y = strtoul(p, nil, 0);
  290. if(y == 0 || y > 2048)
  291. error(Ebadarg);
  292. if(x > scr->gscreen->r.max.x || y > scr->gscreen->r.max.y)
  293. error("physical screen bigger than virtual");
  294. physgscreenr = Rect(0,0,x,y);
  295. scr->gscreen->clipr = physgscreenr;
  296. return;
  297. case CMpalettedepth:
  298. x = strtoul(cb->f[1], &p, 0);
  299. if(x != 8 && x != 6)
  300. error(Ebadarg);
  301. scr->palettedepth = x;
  302. return;
  303. case CMdrawinit:
  304. memimagedraw(scr->gscreen, scr->gscreen->r, memblack, ZP, nil, ZP, S);
  305. if(scr && scr->dev && scr->dev->drawinit)
  306. scr->dev->drawinit(scr);
  307. return;
  308. case CMlinear:
  309. if(cb->nf!=2 && cb->nf!=3)
  310. error(Ebadarg);
  311. size = strtoul(cb->f[1], 0, 0);
  312. if(cb->nf == 2)
  313. align = 0;
  314. else
  315. align = strtoul(cb->f[2], 0, 0);
  316. if(screenaperture(size, align) < 0)
  317. error("not enough free address space");
  318. return;
  319. /*
  320. case CMmemset:
  321. memset((void*)strtoul(cb->f[1], 0, 0), atoi(cb->f[2]), atoi(cb->f[3]));
  322. return;
  323. */
  324. case CMblank:
  325. drawblankscreen(1);
  326. return;
  327. case CMunblank:
  328. drawblankscreen(0);
  329. return;
  330. case CMblanktime:
  331. blanktime = strtoul(cb->f[1], 0, 0);
  332. return;
  333. case CMpanning:
  334. if(strcmp(cb->f[1], "on") == 0){
  335. if(scr == nil || scr->cur == nil)
  336. error("set screen first");
  337. if(!scr->cur->doespanning)
  338. error("panning not supported");
  339. scr->gscreen->clipr = scr->gscreen->r;
  340. panning = 1;
  341. }
  342. else if(strcmp(cb->f[1], "off") == 0){
  343. scr->gscreen->clipr = physgscreenr;
  344. panning = 0;
  345. }else
  346. break;
  347. return;
  348. case CMhwaccel:
  349. if(strcmp(cb->f[1], "on") == 0)
  350. hwaccel = 1;
  351. else if(strcmp(cb->f[1], "off") == 0)
  352. hwaccel = 0;
  353. else
  354. break;
  355. return;
  356. case CMhwblank:
  357. if(strcmp(cb->f[1], "on") == 0)
  358. hwblank = 1;
  359. else if(strcmp(cb->f[1], "off") == 0)
  360. hwblank = 0;
  361. else
  362. break;
  363. return;
  364. }
  365. cmderror(cb, "bad VGA control message");
  366. }
  367. char Enooverlay[] = "No overlay support";
  368. static long
  369. vgawrite(Chan* c, void* a, long n, vlong off)
  370. {
  371. ulong offset = off;
  372. Cmdbuf *cb;
  373. VGAscr *scr;
  374. switch((ulong)c->qid.path){
  375. case Qdir:
  376. error(Eperm);
  377. case Qvgactl:
  378. if(offset || n >= READSTR)
  379. error(Ebadarg);
  380. cb = parsecmd(a, n);
  381. if(waserror()){
  382. free(cb);
  383. nexterror();
  384. }
  385. vgactl(cb);
  386. poperror();
  387. free(cb);
  388. return n;
  389. case Qvgaovl:
  390. scr = &vgascreen[0];
  391. if (scr->dev == nil || scr->dev->ovlwrite == nil) {
  392. error(Enooverlay);
  393. break;
  394. }
  395. return scr->dev->ovlwrite(scr, a, n, off);
  396. case Qvgaovlctl:
  397. scr = &vgascreen[0];
  398. if (scr->dev == nil || scr->dev->ovlctl == nil) {
  399. error(Enooverlay);
  400. break;
  401. }
  402. scr->dev->ovlctl(scr, c, a, n);
  403. return n;
  404. default:
  405. error(Egreg);
  406. break;
  407. }
  408. return 0;
  409. }
  410. Dev vgadevtab = {
  411. 'v',
  412. "vga",
  413. vgareset,
  414. devinit,
  415. devshutdown,
  416. vgaattach,
  417. vgawalk,
  418. vgastat,
  419. vgaopen,
  420. devcreate,
  421. vgaclose,
  422. vgaread,
  423. devbread,
  424. vgawrite,
  425. devbwrite,
  426. devremove,
  427. devwstat,
  428. };