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