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