devvga.c 8.4 KB

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