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