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