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 driver using just vesa bios to set up.
3
 *
4
 * note that setting hwaccel to zero will cause cursor ghosts to be
5
 * left behind.  hwaccel set non-zero repairs this.
6
 */
7
#include "u.h"
8
#include "../port/lib.h"
9
#include "mem.h"
10
#include "dat.h"
11
#include "fns.h"
12
#include "io.h"
13
#include "../port/error.h"
14
#include "ureg.h"
15
 
16
#define	Image	IMAGE
17
#include <draw.h>
18
#include <memdraw.h>
19
#include <cursor.h>
20
#include "screen.h"
21
 
22
enum {
23
	Usesoftscreen = 1,
24
};
25
 
26
static void *hardscreen;
27
static uchar modebuf[0x1000];
28
 
29
#define WORD(p) ((p)[0] | ((p)[1]<<8))
30
#define LONG(p) ((p)[0] | ((p)[1]<<8) | ((p)[2]<<16) | ((p)[3]<<24))
31
#define PWORD(p, v) (p)[0] = (v); (p)[1] = (v)>>8
32
#define PLONG(p, v) (p)[0] = (v); (p)[1] = (v)>>8; (p)[2] = (v)>>16; (p)[3] = (v)>>24
33
 
34
static uchar*
35
vbesetup(Ureg *u, int ax)
36
{
37
	ulong pa;
38
 
39
	pa = PADDR(RMBUF);
40
	memset(modebuf, 0, sizeof modebuf);
41
	memset(u, 0, sizeof *u);
42
	u->ax = ax;
43
	u->es = (pa>>4)&0xF000;
44
	u->di = pa&0xFFFF;
45
	return modebuf;
46
}
47
 
48
static void
49
vbecall(Ureg *u)
50
{
51
	Chan *creg, *cmem;
52
	ulong pa;
53
 
54
	cmem = namec("/dev/realmodemem", Aopen, ORDWR, 0);
55
	if(waserror()){
56
		cclose(cmem);
57
		nexterror();
58
	}
59
	creg = namec("/dev/realmode", Aopen, ORDWR, 0);
60
	if(waserror()){
61
		cclose(creg);
62
		nexterror();
63
	}
64
	pa = PADDR(RMBUF);
65
	devtab[cmem->type]->write(cmem, modebuf, sizeof modebuf, pa);
66
	u->trap = 0x10;
67
	devtab[creg->type]->write(creg, u, sizeof *u, 0);
68
 
69
	devtab[creg->type]->read(creg, u, sizeof *u, 0);
70
	if((u->ax&0xFFFF) != 0x004F)
71
		error("vesa bios error");
72
	devtab[cmem->type]->read(cmem, modebuf, sizeof modebuf, pa);
73
 
74
	poperror();
75
	cclose(creg);
76
	poperror();
77
	cclose(cmem);
78
}
79
 
80
static void
81
vbecheck(void)
82
{
83
	Ureg u;
84
	uchar *p;
85
 
86
	p = vbesetup(&u, 0x4F00);
87
	strcpy((char*)p, "VBE2");
88
	vbecall(&u);
89
	if(memcmp((char*)p, "VESA", 4) != 0)
90
		error("bad vesa signature");
91
	if(p[5] < 2)
92
		error("bad vesa version");
93
}
94
 
95
static int
96
vbegetmode(void)
97
{
98
	Ureg u;
99
 
100
	vbesetup(&u, 0x4F03);
101
	vbecall(&u);
102
	return u.bx;
103
}
104
 
105
static uchar*
106
vbemodeinfo(int mode)
107
{
108
	uchar *p;
109
	Ureg u;
110
 
111
	p = vbesetup(&u, 0x4F01);
112
	u.cx = mode;
113
	vbecall(&u);
114
	return p;
115
}
116
 
117
static void
118
vesalinear(VGAscr *scr, int, int)
119
{
120
	int i, mode, size, havesize;
121
	uchar *p;
122
	ulong paddr;
123
	Pcidev *pci;
124
 
125
	if(hardscreen) {
126
		scr->vaddr = 0;
127
		scr->paddr = scr->apsize = 0;
128
		return;
129
	}
130
 
131
	vbecheck();
132
	mode = vbegetmode();
133
	/*
134
	 * bochs loses the top bits - cannot use this
135
	if((mode&(1<<14)) == 0)
136
		error("not in linear graphics mode");
137
	 */
138
	mode &= 0x3FFF;
139
	p = vbemodeinfo(mode);
140
	if(!(WORD(p+0) & (1<<4)))
141
		error("not in VESA graphics mode");
142
	if(!(WORD(p+0) & (1<<7)))
143
		error("not in linear graphics mode");
144
 
145
	paddr = LONG(p+40);
146
	size = WORD(p+20)*WORD(p+16);
147
	size = PGROUND(size);
148
 
149
	/*
150
	 * figure out max size of memory so that we have
151
	 * enough if the screen is resized.
152
	 */
153
	pci = nil;
154
	havesize = 0;
155
	while(!havesize && (pci = pcimatch(pci, 0, 0)) != nil){
156
		if(pci->ccrb != Pcibcdisp)
157
			continue;
158
		for(i=0; i<nelem(pci->mem); i++)
159
			if(paddr == (pci->mem[i].bar&~0x0F)){
160
				if(pci->mem[i].size > size)
161
					size = pci->mem[i].size;
162
				havesize = 1;
163
				break;
164
			}
165
	}
166
 
167
	/* no pci - heuristic guess */
168
	if (!havesize)
169
		if(size < 4*1024*1024)
170
			size = 4*1024*1024;
171
		else
172
			size = ROUND(size, 1024*1024);
173
	if(size > 16*1024*1024)		/* arbitrary */
174
		size = 16*1024*1024;
175
 
176
	vgalinearaddr(scr, paddr, size);
177
	if(scr->apsize)
178
		addvgaseg("vesascreen", scr->paddr, scr->apsize);
179
 
180
	if(Usesoftscreen){
181
		hardscreen = scr->vaddr;
182
		scr->vaddr = 0;
183
		scr->paddr = scr->apsize = 0;
184
	}
185
}
186
 
187
static void
188
vesaflush(VGAscr *scr, Rectangle r)
189
{
190
	int t, w, wid, off;
191
	ulong *hp, *sp, *esp;
192
 
193
	if(hardscreen == nil)
194
		return;
195
	if(rectclip(&r, scr->gscreen->r) == 0)
196
		return;
197
	sp = (ulong*)(scr->gscreendata->bdata + scr->gscreen->zero);
198
	t = (r.max.x * scr->gscreen->depth + 2*BI2WD-1) / BI2WD;
199
	w = (r.min.x * scr->gscreen->depth) / BI2WD;
200
	w = (t - w) * BY2WD;
201
	wid = scr->gscreen->width;
202
	off = r.min.y * wid + (r.min.x * scr->gscreen->depth) / BI2WD;
203
 
204
	hp = hardscreen;
205
	hp += off;
206
	sp += off;
207
	esp = sp + Dy(r) * wid;
208
	while(sp < esp){
209
		memmove(hp, sp, w);
210
		hp += wid;
211
		sp += wid;
212
	}
213
}
214
 
215
VGAdev vgavesadev = {
216
	"vesa",
217
	0,
218
	0,
219
	0,
220
	vesalinear,
221
	0,
222
	0,
223
	0,
224
	0,
225
	vesaflush,
226
};