]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/aux/vga/main.c
exec(2): fix prototypes
[plan9front.git] / sys / src / cmd / aux / vga / main.c
1 #include <u.h>
2 #include <libc.h>
3 #include <bio.h>
4
5 #include "pci.h"
6 #include "vga.h"
7
8 Biobuf stdout;
9
10 static int iflag, lflag, pflag, rflag;
11
12 static char *dbname = "/lib/vgadb";
13 static char monitordb[128];
14
15 static void
16 dump(Vga* vga)
17 {
18         Ctlr *ctlr;
19         Attr *attr;
20         int i;
21         
22         if(vga->mode)
23                 dbdumpmode(vga->mode);
24
25         for(attr = vga->attr; attr; attr = attr->next)
26                 Bprint(&stdout, "vga->attr: %s=%s\n", attr->attr, attr->val);
27
28         for(ctlr = vga->link; ctlr; ctlr = ctlr->link){
29                 if(ctlr->dump == 0)
30                         continue;
31
32                 trace("%s->dump\n", ctlr->name);
33                 if(ctlr->flag && ctlr->flag != Fsnarf){
34                         printitem(ctlr->name, "flag");
35                         printflag(ctlr->flag);
36                         Bprint(&stdout, "\n");
37                 }
38                 (*ctlr->dump)(vga, ctlr);
39                 ctlr->flag |= Fdump;
40         }
41
42         for(i=0; i < nelem(vga->edid); i++){
43                 if(vga->edid[i])
44                         printedid(vga->edid[i]);
45         }
46
47         Bprint(&stdout, "\n");
48 }
49
50 void
51 resyncinit(Vga* vga, Ctlr* ctlr, ulong on, ulong off)
52 {
53         Ctlr *link;
54
55         trace("%s->resyncinit on 0x%8.8luX off 0x%8.8luX\n",
56                 ctlr->name, on, off);
57
58         for(link = vga->link; link; link = link->link){
59                 link->flag |= on;
60                 link->flag &= ~off;
61                 if(link == ctlr)
62                         continue;
63
64                 if(link->init == 0 || (link->flag & Finit) == 0)
65                         continue;
66                 link->flag &= ~Finit;
67                 trace("%s->init 0x%8.8luX\n", link->name, link->flag);
68                 (*link->init)(vga, link);
69         }
70 }
71
72 void
73 sequencer(Vga* vga, int on)
74 {
75         static uchar seq01;
76         static int state = 1;
77         char *s;
78
79         if(on)
80                 s = "on";
81         else
82                 s = "off";
83         trace("sequencer->enter %s\n", s);
84         if(on){
85                 if(vga)
86                         seq01 = vga->sequencer[0x01];
87                 if(state == 0){
88                         seq01 |= 0x01;
89                         vgaxo(Seqx, 0x01, seq01);
90                         vgaxo(Seqx, 0x00, 0x03);
91                 }
92         }
93         else{
94                 vgaxo(Seqx, 0x00, 0x01);
95                 seq01 = vgaxi(Seqx, 0x01);
96                 vgaxo(Seqx, 0x01, seq01|0x20);
97         }
98         state = on;
99         trace("sequencer->leave %s\n", s);
100 }
101
102 static void
103 linear(Vga* vga)
104 {
105         char buf[256];
106         char *p;
107
108         /*
109          * Set up for linear addressing: try to allocate the
110          * kernel memory map then read the base-address back.
111          * vga->linear is a compatibility hack.
112          */
113         if(vga->linear == 0){
114                 vga->ctlr->flag &= ~Ulinear;
115                 return;
116         }
117         if(vga->ctlr->flag & Ulinear){
118                 /*
119                  * If there's already an aperture don't bother trying
120                  * to set up a new one.
121                  */
122                 vgactlr("addr", buf);
123                 if(atoi(buf)==0 && (buf[0]!='p' || buf[1]!=' ' || atoi(buf+2)==0)){
124                         sprint(buf, "0x%lux 0x%lux", vga->apz ? vga->apz : vga->vmz, vga->vma);
125                         vgactlw("linear", buf);
126                         vgactlr("addr", buf);
127                 }
128                 trace("linear->addr %s\n", buf);
129                 /*
130                  * old: addr 0x12345678
131                  * new: addr p 0x12345678 v 0x82345678 size 0x123
132                  */
133                 if(buf[0]=='p' && buf[1]==' '){
134                         vga->vmb = strtoul(buf+2, 0, 0);
135                         p = strstr(buf, "size");
136                         if(p)
137                                 vga->apz = strtoul(p+4, 0, 0);
138                 }else
139                         vga->vmb = strtoul(buf, 0, 0);
140         }
141         else
142                 vgactlw("linear", "0");
143 }
144
145 static Mode*
146 dbedidmode(Vga *vga, char *type, char *size)
147 {
148         char buf[32], *p;
149         int i, x, y, z;
150         Modelist *l;
151         Mode *m;
152
153         z = 32;
154         x = y = 0;
155         snprint(buf, sizeof(buf), "%s", size);
156         if((p = strchr(buf, 'x')) != nil){
157                 *p++ = 0;
158                 x = atoi(buf);
159                 y = atoi(p);
160                 if((p = strchr(p, 'x')) != nil){
161                         *p++ = 0;
162                         z = atoi(p);
163                 }
164         }
165
166         for(i=0; i<nelem(vga->edid); i++){
167                 if(vga->edid[i] == nil)
168                         continue;
169                 for(l = vga->edid[i]->modelist; l != nil; l = l->next)
170                         if(strcmp(l->name, type) == 0)
171                                 goto found;
172         }
173         for(i=0; i<nelem(vga->edid); i++){
174                 if(vga->edid[i] == nil)
175                         continue;
176                 for(l = vga->edid[i]->modelist; l != nil; l = l->next)
177                         if((x == 0 || l->x == x) && (y == 0 || l->y == y))
178                                 goto found;
179         }
180         return nil;
181
182 found:
183         m = alloc(sizeof(Mode));
184         *m = *((Mode*)l);
185         m->z = z;
186         x = m->x;
187         y = m->y;
188         snprint(m->type, sizeof(m->type), "%s", type);
189         snprint(m->size, sizeof(m->size), "%dx%dx%d", x, y, z);
190         return m;
191 }
192
193 char*
194 chanstr[32+1] = {
195 [1]     "k1",
196 [2]     "k2",
197 [4]     "k4",
198 [8]     "m8",
199 [16]    "r5g6b5",
200 [24]    "r8g8b8",
201 [32]    "x8r8g8b8",
202 };
203
204 static void
205 usage(void)
206 {
207         fprint(2, "usage: aux/vga [ -BcdilpvV ] [ -b bios-id ] [ -m monitor ] [ -x db ] [ mode [ virtualsize ] ]\n");
208         exits("usage");
209 }
210
211 void
212 main(int argc, char** argv)
213 {
214         char *bios, buf[256], sizeb[256], *p, *vsize, *psize;
215         char *type, *vtype;
216         int virtual, len;
217         Ctlr *ctlr;
218         Vga *vga;
219
220         fmtinstall('H', encodefmt);
221         Binit(&stdout, 1, OWRITE);
222
223         bios = getenv("vgactlr");
224         if((type = getenv("monitor")) == 0)
225                 type = "vga";
226         psize = vsize = "640x480x8";
227
228         ARGBEGIN{
229         default:
230                 usage();
231                 break;
232         case 'b':
233                 bios = EARGF(usage());
234                 break;
235         case 'B':
236                 dumpbios(0x10000);
237                 exits(0);
238         case 'c':
239                 cflag = 1;
240                 break;
241         case 'd':
242                 dflag = 1;
243                 break;
244         case 'i':
245                 iflag = 1;
246                 break;
247         case 'l':
248                 lflag = 1;
249                 break;
250         case 'm':
251                 type = EARGF(usage());
252                 break;
253         case 'p':
254                 pflag = 1;
255                 break;
256         case 'r':
257                 /*
258                  * rflag > 1 means "leave me alone, I know what I'm doing."
259                  */
260                 rflag++;
261                 break;
262         case 'v':
263                 vflag = 1;
264                 break;
265         case 'V':
266                 vflag = 1;
267                 Vflag = 1;
268                 break;
269         case 'x':
270                 dbname = EARGF(usage());
271                 break;
272         }ARGEND
273
274         virtual = 0;
275         switch(argc){
276         default:
277                 usage();
278                 break;
279         case 1:
280                 vsize = psize = argv[0];
281                 break;
282         case 2:
283                 psize = argv[0];
284                 vsize = argv[1];
285                 virtual = 1;
286                 break;
287         case 0:
288                 break;
289         }
290
291         if(lflag && strcmp(vsize, "text") == 0){
292                 vesatextmode();
293                 vgactlw("textmode", "");
294                 exits(0);
295         }
296
297         vga = alloc(sizeof(Vga));
298         if(bios){
299                 if((vga->offset = strtol(bios, &p, 0)) == 0 || *p++ != '=')
300                         error("main: bad BIOS string format - %s\n", bios);
301                 len = strlen(p);
302                 vga->bios = alloc(len+1);
303                 strncpy(vga->bios, p, len);
304                 trace("main->BIOS %s\n", bios);
305         }
306
307         /*
308          * Try to identify the VGA card and grab
309          * registers.  Print them out if requested.
310          * If monitor=vesa or our vga controller can't be found
311          * in vgadb, try vesa modes; failing that, try vga.
312          */
313         if(strcmp(type, "vesa") == 0 || dbctlr(dbname, vga) == 0 ||
314             vga->ctlr == 0)
315                 if(dbvesa(vga) == 0 || vga->ctlr == 0){
316                         Bprint(&stdout, "%s: controller not in %s, not vesa\n",
317                                 argv0, dbname);
318                         dumpbios(256);
319                         type = "vga";
320                         vsize = psize = "640x480x1";
321                         virtual = 0;
322                         vga->ctlr = &generic;
323                         vga->link = &generic;
324                 }
325
326         trace("main->snarf\n");
327         for(ctlr = vga->link; ctlr; ctlr = ctlr->link){
328                 if(ctlr->snarf == 0)
329                         continue;
330                 trace("%s->snarf\n", ctlr->name);
331                 (*ctlr->snarf)(vga, ctlr);
332         }
333
334         if(pflag)
335                 dump(vga);
336
337         for(ctlr = vga->link; ctlr; ctlr = ctlr->link)
338                 if(ctlr->flag & Ferror)
339                         error("%r\n");
340
341         if(iflag || lflag){
342                 if(getenv(type))
343                         snprint(monitordb, sizeof monitordb, "/env/%s", type);
344                 else
345                         strecpy(monitordb, monitordb+sizeof monitordb, dbname);
346
347                 if(vga->vesa){
348                         strcpy(monitordb, "vesa bios");
349                         vga->mode = dbvesamode(vga, psize);
350                 }else {
351                         vga->mode = dbmode(monitordb, type, psize);
352                         if(vga->mode == nil)
353                                 vga->mode = dbedidmode(vga, type, psize);
354                 }
355                 if(vga->mode == nil)
356                         error("main: %s@%s not in %s\n", type, psize, monitordb);
357
358                 /*
359                  * because vga programs shb/ehb (Crt02, Crt03) the same as
360                  * shs/ehs (Crt04, Crt05), only shb/ehb is specified in vgadb
361                  * meaning the horizontal sync pulse start and end position.
362                  */
363                 if(vga->mode->shs == 0)
364                         vga->mode->shs = vga->mode->shb;
365                 if(vga->mode->ehs == 0)
366                         vga->mode->ehs = vga->mode->ehb;
367
368                 if(virtual){
369                         if((p = strchr(vsize, 'x')) == nil)
370                                 error("bad virtual size %s\n", vsize);
371                         vga->virtx = atoi(vsize);
372                         vga->virty = atoi(p+1);
373                         if(vga->virtx < vga->mode->x || vga->virty < vga->mode->y)
374                                 error("virtual size smaller than physical size\n");
375                         vga->panning = 1;
376                 }
377                 else{
378                         vga->virtx = vga->mode->x;
379                         vga->virty = vga->mode->y;
380                         vga->panning = 0;
381                 }
382
383                 trace("vmf %d vmdf %d vf1 %lud vbw %lud\n",
384                         vga->mode->frequency, vga->mode->deffrequency,
385                         vga->f[1], vga->mode->videobw);
386                 if(vga->mode->frequency == 0 && vga->mode->videobw != 0 && vga->f[1] != 0){
387                         /*
388                          * boost clock as much as possible subject
389                          * to video and memory bandwidth constraints
390                          */
391                         ulong bytes, freq, membw;
392                         double rr;
393
394                         freq = vga->mode->videobw;
395                         if(freq > vga->f[1])
396                                 freq = vga->f[1];
397
398                         rr = (double)freq/(vga->mode->ht*vga->mode->vt);
399                         if(rr > 85.0)           /* >85Hz is ridiculous */
400                                 rr = 85.0;
401
402                         bytes = (vga->mode->x*vga->mode->y*vga->mode->z)/8;
403                         membw = rr*bytes;
404                         if(vga->membw != 0 && membw > vga->membw){
405                                 membw = vga->membw;
406                                 rr = (double)membw/bytes;
407                         }
408
409                         freq = rr*(vga->mode->ht*vga->mode->vt);
410                         vga->mode->frequency = freq;
411
412                         trace("using frequency %lud rr %.2f membw %lud\n",
413                                 freq, rr, membw);
414                 }
415                 else if(vga->mode->frequency == 0)
416                         vga->mode->frequency = vga->mode->deffrequency;
417
418                 for(ctlr = vga->link; ctlr; ctlr = ctlr->link){
419                         if(ctlr->options == 0)
420                                 continue;
421                         trace("%s->options\n", ctlr->name);
422                         (*ctlr->options)(vga, ctlr);
423                 }
424
425                 /*
426                  * skip init for vesa - vesa will do the registers for us
427                  */
428                 if(!vga->vesa)
429                 for(ctlr = vga->link; ctlr; ctlr = ctlr->link){
430                         if(ctlr->init == 0)
431                                 continue;
432                         trace("%s->init\n", ctlr->name);
433                         (*ctlr->init)(vga, ctlr);
434                 }
435
436                 if(strcmp(vga->mode->chan, "") == 0){
437                         if(vga->mode->z < nelem(chanstr) && chanstr[vga->mode->z])
438                                 strcpy(vga->mode->chan, chanstr[vga->mode->z]);
439                         else
440                                 error("%s: unknown channel type to use for depth %d\n", vga->ctlr->name, vga->mode->z);
441                 }
442
443                 if(iflag || pflag)
444                         dump(vga);
445
446                 if(lflag){
447                         trace("main->load\n");
448                         if(vga->vmz && (vga->virtx*vga->virty*vga->mode->z)/8 > vga->vmz)
449                                 error("%s: not enough video memory - %lud\n",
450                                         vga->ctlr->name, vga->vmz);
451
452                         if(vga->ctlr->type)
453                                 vtype = vga->ctlr->type;
454                         else if(p = strchr(vga->ctlr->name, '-')){
455                                 strncpy(buf, vga->ctlr->name, p - vga->ctlr->name);
456                                 buf[p - vga->ctlr->name] = 0;
457                                 vtype = buf;
458                         }
459                         else
460                                 vtype = vga->ctlr->name;
461
462                         /*
463                          * VESA must be set up before linear.
464                          * Set type to vesa for linear.
465                          */
466                         if(vga->vesa){
467                                 vesa.load(vga, vga->vesa);
468                                 if(vga->vesa->flag&Ferror)
469                                         error("vesa load error\n");
470                                 vgactlw("type", vesa.name);
471                         } else
472                                 vgactlw("type", vtype);
473
474                         /*
475                          * The new draw device needs linear mode set
476                          * before size.
477                          */
478                         linear(vga);
479
480                         /*
481                          * Linear is over so switch to other driver for
482                          * acceleration.
483                          */
484                         if(vga->vesa && strcmp(vesa.name, vtype))
485                                 vgactlw("type", vtype);
486
487                         sprint(buf, "%ludx%ludx%d %s",
488                                 vga->virtx, vga->virty,
489                                 vga->mode->z, vga->mode->chan);
490                         if(rflag){
491                                 vgactlr("size", sizeb);
492                                 if(rflag < 2 && strcmp(buf, sizeb) != 0)
493                                         error("bad refresh: %s != %s\n",
494                                                 buf, sizeb);
495                         }
496                         else
497                                 vgactlw("size", buf);
498
499                         /*
500                          * No fiddling with registers if VESA set 
501                          * things up already.  Sorry.
502                          */
503                         if(!vga->vesa){
504                                 /*
505                                  * Turn off the display during the load.
506                                  */
507                                 sequencer(vga, 0);
508         
509                                 for(ctlr = vga->link; ctlr; ctlr = ctlr->link){
510                                         if(ctlr->load == 0 || ctlr == &vesa)
511                                                 continue;
512                                         trace("%s->load\n", ctlr->name);
513                                         (*ctlr->load)(vga, ctlr);
514                                 }
515         
516                                 sequencer(vga, 1);
517                         }
518
519                         vgactlw("drawinit", "");
520
521                         if(vga->hwgc == 0 || cflag)
522                                 vgactlw("hwgc", "soft");
523                         else
524                                 vgactlw("hwgc", vga->hwgc->name);
525
526                         if(vga->virtx != vga->mode->x || vga->virty != vga->mode->y){
527                                 sprint(buf, "%dx%d", vga->mode->x, vga->mode->y);
528                                 vgactlw("actualsize", buf);
529                                 if(vga->panning)
530                                         vgactlw("panning", "on");
531                         }
532
533                         if(pflag)
534                                 dump(vga);
535                 }
536         }
537
538         trace("main->exits\n");
539         exits(0);
540 }