Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

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