devvga.c 10 KB

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