devvga.c 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500
  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(p == nil)
  153. error(Enomem);
  154. if(waserror()){
  155. free(p);
  156. nexterror();
  157. }
  158. len = 0;
  159. if(scr->dev)
  160. s = scr->dev->name;
  161. else
  162. s = "cga";
  163. len += snprint(p+len, READSTR-len, "type %s\n", s);
  164. if(scr->gscreen) {
  165. len += snprint(p+len, READSTR-len, "size %dx%dx%d %s\n",
  166. scr->gscreen->r.max.x, scr->gscreen->r.max.y,
  167. scr->gscreen->depth, chantostr(chbuf, scr->gscreen->chan));
  168. if(Dx(scr->gscreen->r) != Dx(physgscreenr)
  169. || Dy(scr->gscreen->r) != Dy(physgscreenr))
  170. len += snprint(p+len, READSTR-len, "actualsize %dx%d\n",
  171. physgscreenr.max.x, physgscreenr.max.y);
  172. }
  173. len += snprint(p+len, READSTR-len, "blank time %lud idle %d state %s\n",
  174. blanktime, drawidletime(), scr->isblank ? "off" : "on");
  175. len += snprint(p+len, READSTR-len, "hwaccel %s\n", hwaccel ? "on" : "off");
  176. len += snprint(p+len, READSTR-len, "hwblank %s\n", hwblank ? "on" : "off");
  177. len += snprint(p+len, READSTR-len, "panning %s\n", panning ? "on" : "off");
  178. len += snprint(p+len, READSTR-len, "addr p 0x%lux v 0x%p size 0x%ux\n", scr->paddr, scr->vaddr, scr->apsize);
  179. USED(len);
  180. n = readstr(offset, a, n, p);
  181. poperror();
  182. free(p);
  183. return n;
  184. case Qvgaovl:
  185. case Qvgaovlctl:
  186. error(Ebadusefd);
  187. break;
  188. default:
  189. error(Egreg);
  190. break;
  191. }
  192. return 0;
  193. }
  194. static char Ebusy[] = "vga already configured";
  195. static void
  196. vgactl(Cmdbuf *cb)
  197. {
  198. int align, i, size, x, y, z;
  199. char *chanstr, *p;
  200. ulong chan;
  201. Cmdtab *ct;
  202. VGAscr *scr;
  203. extern VGAdev *vgadev[];
  204. extern VGAcur *vgacur[];
  205. scr = &vgascreen[0];
  206. ct = lookupcmd(cb, vgactlmsg, nelem(vgactlmsg));
  207. switch(ct->index){
  208. case CMhwgc:
  209. if(strcmp(cb->f[1], "off") == 0){
  210. lock(&cursor);
  211. if(scr->cur){
  212. if(scr->cur->disable)
  213. scr->cur->disable(scr);
  214. scr->cur = nil;
  215. }
  216. unlock(&cursor);
  217. return;
  218. }
  219. if(strcmp(cb->f[1], "soft") == 0){
  220. lock(&cursor);
  221. swcursorinit();
  222. if(scr->cur && scr->cur->disable)
  223. scr->cur->disable(scr);
  224. scr->cur = &swcursor;
  225. if(scr->cur->enable)
  226. scr->cur->enable(scr);
  227. unlock(&cursor);
  228. return;
  229. }
  230. for(i = 0; vgacur[i]; i++){
  231. if(strcmp(cb->f[1], vgacur[i]->name))
  232. continue;
  233. lock(&cursor);
  234. if(scr->cur && scr->cur->disable)
  235. scr->cur->disable(scr);
  236. scr->cur = vgacur[i];
  237. if(scr->cur->enable)
  238. scr->cur->enable(scr);
  239. unlock(&cursor);
  240. return;
  241. }
  242. break;
  243. case CMtype:
  244. for(i = 0; vgadev[i]; i++){
  245. if(strcmp(cb->f[1], vgadev[i]->name))
  246. continue;
  247. if(scr->dev && scr->dev->disable)
  248. scr->dev->disable(scr);
  249. scr->dev = vgadev[i];
  250. if(scr->dev->enable)
  251. scr->dev->enable(scr);
  252. return;
  253. }
  254. break;
  255. case CMtextmode:
  256. screeninit();
  257. return;
  258. case CMsize:
  259. x = strtoul(cb->f[1], &p, 0);
  260. if(x == 0 || x > 10240)
  261. error(Ebadarg);
  262. if(*p)
  263. p++;
  264. y = strtoul(p, &p, 0);
  265. if(y == 0 || y > 10240)
  266. error(Ebadarg);
  267. if(*p)
  268. p++;
  269. z = strtoul(p, &p, 0);
  270. chanstr = cb->f[2];
  271. if((chan = strtochan(chanstr)) == 0)
  272. error("bad channel");
  273. if(chantodepth(chan) != z)
  274. error("depth, channel do not match");
  275. cursoroff(1);
  276. deletescreenimage();
  277. if(screensize(x, y, z, chan))
  278. error(Egreg);
  279. vgascreenwin(scr);
  280. resetscreenimage();
  281. cursoron(1);
  282. return;
  283. case CMactualsize:
  284. if(scr->gscreen == nil)
  285. error("set the screen size first");
  286. x = strtoul(cb->f[1], &p, 0);
  287. if(x == 0 || x > 2048)
  288. error(Ebadarg);
  289. if(*p)
  290. p++;
  291. y = strtoul(p, nil, 0);
  292. if(y == 0 || y > 2048)
  293. error(Ebadarg);
  294. if(x > scr->gscreen->r.max.x || y > scr->gscreen->r.max.y)
  295. error("physical screen bigger than virtual");
  296. physgscreenr = Rect(0,0,x,y);
  297. scr->gscreen->clipr = physgscreenr;
  298. return;
  299. case CMpalettedepth:
  300. x = strtoul(cb->f[1], &p, 0);
  301. if(x != 8 && x != 6)
  302. error(Ebadarg);
  303. scr->palettedepth = x;
  304. return;
  305. case CMdrawinit:
  306. if(scr->gscreen == nil)
  307. error("drawinit: no gscreen");
  308. if(scr->dev && scr->dev->drawinit)
  309. scr->dev->drawinit(scr);
  310. return;
  311. case CMlinear:
  312. if(cb->nf!=2 && cb->nf!=3)
  313. error(Ebadarg);
  314. size = strtoul(cb->f[1], 0, 0);
  315. if(cb->nf == 2)
  316. align = 0;
  317. else
  318. align = strtoul(cb->f[2], 0, 0);
  319. if(screenaperture(size, align) < 0)
  320. error("not enough free address space");
  321. return;
  322. /*
  323. case CMmemset:
  324. memset((void*)strtoul(cb->f[1], 0, 0), atoi(cb->f[2]), atoi(cb->f[3]));
  325. return;
  326. */
  327. case CMblank:
  328. drawblankscreen(1);
  329. return;
  330. case CMunblank:
  331. drawblankscreen(0);
  332. return;
  333. case CMblanktime:
  334. blanktime = strtoul(cb->f[1], 0, 0);
  335. return;
  336. case CMpanning:
  337. if(strcmp(cb->f[1], "on") == 0){
  338. if(scr == nil || scr->cur == nil)
  339. error("set screen first");
  340. if(!scr->cur->doespanning)
  341. error("panning not supported");
  342. scr->gscreen->clipr = scr->gscreen->r;
  343. panning = 1;
  344. }
  345. else if(strcmp(cb->f[1], "off") == 0){
  346. scr->gscreen->clipr = physgscreenr;
  347. panning = 0;
  348. }else
  349. break;
  350. return;
  351. case CMhwaccel:
  352. if(strcmp(cb->f[1], "on") == 0)
  353. hwaccel = 1;
  354. else if(strcmp(cb->f[1], "off") == 0)
  355. hwaccel = 0;
  356. else
  357. break;
  358. return;
  359. case CMhwblank:
  360. if(strcmp(cb->f[1], "on") == 0)
  361. hwblank = 1;
  362. else if(strcmp(cb->f[1], "off") == 0)
  363. hwblank = 0;
  364. else
  365. break;
  366. return;
  367. }
  368. cmderror(cb, "bad VGA control message");
  369. }
  370. char Enooverlay[] = "No overlay support";
  371. static long
  372. vgawrite(Chan* c, void* a, long n, vlong off)
  373. {
  374. ulong offset = off;
  375. Cmdbuf *cb;
  376. VGAscr *scr;
  377. switch((ulong)c->qid.path){
  378. case Qdir:
  379. error(Eperm);
  380. case Qvgactl:
  381. if(offset || n >= READSTR)
  382. error(Ebadarg);
  383. cb = parsecmd(a, n);
  384. if(waserror()){
  385. free(cb);
  386. nexterror();
  387. }
  388. vgactl(cb);
  389. poperror();
  390. free(cb);
  391. return n;
  392. case Qvgaovl:
  393. scr = &vgascreen[0];
  394. if (scr->dev == nil || scr->dev->ovlwrite == nil) {
  395. error(Enooverlay);
  396. break;
  397. }
  398. return scr->dev->ovlwrite(scr, a, n, off);
  399. case Qvgaovlctl:
  400. scr = &vgascreen[0];
  401. if (scr->dev == nil || scr->dev->ovlctl == nil) {
  402. error(Enooverlay);
  403. break;
  404. }
  405. scr->dev->ovlctl(scr, c, a, n);
  406. return n;
  407. default:
  408. error(Egreg);
  409. break;
  410. }
  411. return 0;
  412. }
  413. Dev vgadevtab = {
  414. 'v',
  415. "vga",
  416. vgareset,
  417. devinit,
  418. devshutdown,
  419. vgaattach,
  420. vgawalk,
  421. vgastat,
  422. vgaopen,
  423. devcreate,
  424. vgaclose,
  425. vgaread,
  426. devbread,
  427. vgawrite,
  428. devbwrite,
  429. devremove,
  430. devwstat,
  431. };