Subversion Repositories planix.SVN

Rev

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

Rev Author Line No. Line
2 - 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
};
50
 
51
static Cmdtab vgactlmsg[] = {
52
	CMactualsize,	"actualsize",	2,
53
	CMblank,	"blank",	1,
54
	CMblanktime,	"blanktime",	2,
55
	CMdrawinit,	"drawinit",	1,
56
	CMhwaccel,	"hwaccel",	2,
57
	CMhwblank,	"hwblank",	2,
58
	CMhwgc,		"hwgc",		2,
59
	CMlinear,	"linear",	0,
60
	CMpalettedepth,	"palettedepth",	2,
61
	CMpanning,	"panning",	2,
62
	CMsize,		"size",		3,
63
	CMtextmode,	"textmode",	1,
64
	CMtype,		"type",		2,
65
	CMunblank,	"unblank",	1,
66
};
67
 
68
static void
69
vgareset(void)
70
{
71
	/* reserve the 'standard' vga registers */
72
	if(ioalloc(0x2b0, 0x2df-0x2b0+1, 0, "vga") < 0)
73
		panic("vga ports already allocated"); 
74
	if(ioalloc(0x3c0, 0x3da-0x3c0+1, 0, "vga") < 0)
75
		panic("vga ports already allocated"); 
76
	conf.monitor = 1;
77
}
78
 
79
static Chan*
80
vgaattach(char* spec)
81
{
82
	if(*spec && strcmp(spec, "0"))
83
		error(Eio);
84
	return devattach('v', spec);
85
}
86
 
87
Walkqid*
88
vgawalk(Chan* c, Chan *nc, char** name, int nname)
89
{
90
	return devwalk(c, nc, name, nname, vgadir, nelem(vgadir), devgen);
91
}
92
 
93
static int
94
vgastat(Chan* c, uchar* dp, int n)
95
{
96
	return devstat(c, dp, n, vgadir, nelem(vgadir), devgen);
97
}
98
 
99
static Chan*
100
vgaopen(Chan* c, int omode)
101
{
102
	VGAscr *scr;
103
	static char *openctl = "openctl\n";
104
 
105
	scr = &vgascreen[0];
106
	if ((ulong)c->qid.path == Qvgaovlctl) {
107
		if (scr->dev && scr->dev->ovlctl)
108
			scr->dev->ovlctl(scr, c, openctl, strlen(openctl));
109
		else 
110
			error(Enonexist);
111
	}
112
	return devopen(c, omode, vgadir, nelem(vgadir), devgen);
113
}
114
 
115
static void
116
vgaclose(Chan* c)
117
{
118
	VGAscr *scr;
119
	static char *closectl = "closectl\n";
120
 
121
	scr = &vgascreen[0];
122
	if((ulong)c->qid.path == Qvgaovlctl)
123
		if(scr->dev && scr->dev->ovlctl){
124
			if(waserror()){
125
				print("ovlctl error: %s\n", up->errstr);
126
				return;
127
			}
128
			scr->dev->ovlctl(scr, c, closectl, strlen(closectl));
129
			poperror();
130
		}
131
}
132
 
133
static void
134
checkport(int start, int end)
135
{
136
	/* standard vga regs are OK */
137
	if(start >= 0x2b0 && end <= 0x2df+1)
138
		return;
139
	if(start >= 0x3c0 && end <= 0x3da+1)
140
		return;
141
 
142
	if(iounused(start, end))
143
		return;
144
	error(Eperm);
145
}
146
 
147
static long
148
vgaread(Chan* c, void* a, long n, vlong off)
149
{
150
	int len;
151
	char *p, *s;
152
	VGAscr *scr;
153
	ulong offset = off;
154
	char chbuf[30];
155
 
156
	switch((ulong)c->qid.path){
157
 
158
	case Qdir:
159
		return devdirread(c, a, n, vgadir, nelem(vgadir), devgen);
160
 
161
	case Qvgabios:
162
		if(offset >= 0x100000)
163
			return 0;
164
		if(offset+n >= 0x100000)
165
			n = 0x100000 - offset;
166
		memmove(a, (uchar*)kaddr(0)+offset, n);
167
		return n;
168
 
169
	case Qvgactl:
170
		scr = &vgascreen[0];
171
 
172
		p = malloc(READSTR);
173
		if(p == nil)
174
			error(Enomem);
175
		if(waserror()){
176
			free(p);
177
			nexterror();
178
		}
179
 
180
		len = 0;
181
 
182
		if(scr->dev)
183
			s = scr->dev->name;
184
		else
185
			s = "cga";
186
		len += snprint(p+len, READSTR-len, "type %s\n", s);
187
 
188
		if(scr->gscreen) {
189
			len += snprint(p+len, READSTR-len, "size %dx%dx%d %s\n",
190
				scr->gscreen->r.max.x, scr->gscreen->r.max.y,
191
				scr->gscreen->depth, chantostr(chbuf, scr->gscreen->chan));
192
 
193
			if(Dx(scr->gscreen->r) != Dx(physgscreenr) 
194
			|| Dy(scr->gscreen->r) != Dy(physgscreenr))
195
				len += snprint(p+len, READSTR-len, "actualsize %dx%d\n",
196
					physgscreenr.max.x, physgscreenr.max.y);
197
		}
198
 
199
		len += snprint(p+len, READSTR-len, "blank time %lud idle %d state %s\n",
200
			blanktime, drawidletime(), scr->isblank ? "off" : "on");
201
		len += snprint(p+len, READSTR-len, "hwaccel %s\n", hwaccel ? "on" : "off");
202
		len += snprint(p+len, READSTR-len, "hwblank %s\n", hwblank ? "on" : "off");
203
		len += snprint(p+len, READSTR-len, "panning %s\n", panning ? "on" : "off");
204
		len += snprint(p+len, READSTR-len, "addr p 0x%lux v 0x%p size 0x%ux\n", scr->paddr, scr->vaddr, scr->apsize);
205
		USED(len);
206
 
207
		n = readstr(offset, a, n, p);
208
		poperror();
209
		free(p);
210
 
211
		return n;
212
 
213
	case Qvgaovl:
214
	case Qvgaovlctl:
215
		error(Ebadusefd);
216
		break;
217
 
218
	default:
219
		error(Egreg);
220
		break;
221
	}
222
 
223
	return 0;
224
}
225
 
226
static char Ebusy[] = "vga already configured";
227
 
228
static void
229
vgactl(Cmdbuf *cb)
230
{
231
	int align, i, size, x, y, z;
232
	char *chanstr, *p;
233
	ulong chan;
234
	Cmdtab *ct;
235
	VGAscr *scr;
236
	extern VGAdev *vgadev[];
237
	extern VGAcur *vgacur[];
238
 
239
	scr = &vgascreen[0];
240
	ct = lookupcmd(cb, vgactlmsg, nelem(vgactlmsg));
241
	switch(ct->index){
242
	case CMhwgc:
243
		if(strcmp(cb->f[1], "off") == 0){
244
			lock(&cursor);
245
			if(scr->cur){
246
				if(scr->cur->disable)
247
					scr->cur->disable(scr);
248
				scr->cur = nil;
249
			}
250
			unlock(&cursor);
251
			return;
252
		}
253
		if(strcmp(cb->f[1], "soft") == 0){
254
			lock(&cursor);
255
			swcursorinit();
256
			if(scr->cur && scr->cur->disable)
257
				scr->cur->disable(scr);
258
			scr->cur = &swcursor;
259
			if(scr->cur->enable)
260
				scr->cur->enable(scr);
261
			unlock(&cursor);
262
			return;
263
		}
264
		for(i = 0; vgacur[i]; i++){
265
			if(strcmp(cb->f[1], vgacur[i]->name))
266
				continue;
267
			lock(&cursor);
268
			if(scr->cur && scr->cur->disable)
269
				scr->cur->disable(scr);
270
			scr->cur = vgacur[i];
271
			if(scr->cur->enable)
272
				scr->cur->enable(scr);
273
			unlock(&cursor);
274
			return;
275
		}
276
		break;
277
 
278
	case CMtype:
279
		for(i = 0; vgadev[i]; i++){
280
			if(strcmp(cb->f[1], vgadev[i]->name))
281
				continue;
282
			if(scr->dev && scr->dev->disable)
283
				scr->dev->disable(scr);
284
			scr->dev = vgadev[i];
285
			if(scr->dev->enable)
286
				scr->dev->enable(scr);
287
			return;
288
		}
289
		break;
290
 
291
	case CMtextmode:
292
		screeninit();
293
		return;
294
 
295
	case CMsize:
296
		x = strtoul(cb->f[1], &p, 0);
297
		if(x == 0 || x > 10240)
298
			error(Ebadarg);
299
		if(*p)
300
			p++;
301
 
302
		y = strtoul(p, &p, 0);
303
		if(y == 0 || y > 10240)
304
			error(Ebadarg);
305
		if(*p)
306
			p++;
307
 
308
		z = strtoul(p, &p, 0);
309
 
310
		chanstr = cb->f[2];
311
		if((chan = strtochan(chanstr)) == 0)
312
			error("bad channel");
313
 
314
		if(chantodepth(chan) != z)
315
			error("depth, channel do not match");
316
 
317
		cursoroff(1);
318
		deletescreenimage();
319
		if(screensize(x, y, z, chan))
320
			error(Egreg);
321
		vgascreenwin(scr);
322
		resetscreenimage();
323
		cursoron(1);
324
		return;
325
 
326
	case CMactualsize:
327
		if(scr->gscreen == nil)
328
			error("set the screen size first");
329
 
330
		x = strtoul(cb->f[1], &p, 0);
331
		if(x == 0 || x > 2048)
332
			error(Ebadarg);
333
		if(*p)
334
			p++;
335
 
336
		y = strtoul(p, nil, 0);
337
		if(y == 0 || y > 2048)
338
			error(Ebadarg);
339
 
340
		if(x > scr->gscreen->r.max.x || y > scr->gscreen->r.max.y)
341
			error("physical screen bigger than virtual");
342
 
343
		physgscreenr = Rect(0,0,x,y);
344
		scr->gscreen->clipr = physgscreenr;
345
		return;
346
 
347
	case CMpalettedepth:
348
		x = strtoul(cb->f[1], &p, 0);
349
		if(x != 8 && x != 6)
350
			error(Ebadarg);
351
 
352
		scr->palettedepth = x;
353
		return;
354
 
355
	case CMdrawinit:
356
		if(scr->gscreen == nil)
357
			error("drawinit: no gscreen");
358
		if(scr->dev && scr->dev->drawinit)
359
			scr->dev->drawinit(scr);
360
		return;
361
 
362
	case CMlinear:
363
		if(cb->nf!=2 && cb->nf!=3)
364
			error(Ebadarg);
365
		size = strtoul(cb->f[1], 0, 0);
366
		if(cb->nf == 2)
367
			align = 0;
368
		else
369
			align = strtoul(cb->f[2], 0, 0);
370
		if(screenaperture(size, align) < 0)
371
			error("not enough free address space");
372
		return;
373
/*	
374
	case CMmemset:
375
		memset((void*)strtoul(cb->f[1], 0, 0), atoi(cb->f[2]), atoi(cb->f[3]));
376
		return;
377
*/
378
 
379
	case CMblank:
380
		drawblankscreen(1);
381
		return;
382
 
383
	case CMunblank:
384
		drawblankscreen(0);
385
		return;
386
 
387
	case CMblanktime:
388
		blanktime = strtoul(cb->f[1], 0, 0);
389
		return;
390
 
391
	case CMpanning:
392
		if(strcmp(cb->f[1], "on") == 0){
393
			if(scr == nil || scr->cur == nil)
394
				error("set screen first");
395
			if(!scr->cur->doespanning)
396
				error("panning not supported");
397
			scr->gscreen->clipr = scr->gscreen->r;
398
			panning = 1;
399
		}
400
		else if(strcmp(cb->f[1], "off") == 0){
401
			scr->gscreen->clipr = physgscreenr;
402
			panning = 0;
403
		}else
404
			break;
405
		return;
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
};