xref: /plan9/sys/src/cmd/aux/vga/vga.c (revision 219b2ee8daee37f4aad58d63f21287faa8e4ffdc)
1 #include <u.h>
2 #include <libc.h>
3 
4 #include "vga.h"
5 
6 enum {
7 	NSeqx		= 0x05,
8 	NCrtx		= 0x19,
9 	NGrx		= 0x09,
10 	NAttrx		= 0x15,
11 };
12 
13 uchar
14 vgai(long port)
15 {
16 	uchar data;
17 
18 	switch(port){
19 
20 	case MiscR:
21 	case Status0:
22 	case Status1:
23 	case FeatureR:
24 	case PaddrW:
25 	case Pdata:
26 	case Pixmask:
27 	case Pstatus:
28 		data = inportb(port);
29 		break;
30 
31 	default:
32 		error("vgai(0x%4.4X): unknown port\n", port);
33 		/*NOTREACHED*/
34 		data = 0xFF;
35 		break;
36 	}
37 	return data;
38 }
39 
40 uchar
41 vgaxi(long port, uchar index)
42 {
43 	uchar data;
44 
45 	switch(port){
46 
47 	case Seqx:
48 	case Crtx:
49 	case Grx:
50 		outportb(port, index);
51 		data = inportb(port+1);
52 		break;
53 
54 	case Attrx:
55 		/*
56 		 * Allow processor access to the colour
57 		 * palette registers. Writes to Attrx must
58 		 * be preceded by a read from Status1 to
59 		 * initialise the register to point to the
60 		 * index register and not the data register.
61 		 * Processor access is allowed by turning
62 		 * off bit 0x20.
63 		 */
64 		inportb(Status1);
65 		if(index < 0x10){
66 			outportb(Attrx, index);
67 			data = inportb(Attrx+1);
68 			inportb(Status1);
69 			outportb(Attrx, 0x20|index);
70 		}
71 		else{
72 			outportb(Attrx, 0x20|index);
73 			data = inportb(Attrx+1);
74 		}
75 		break;
76 
77 	default:
78 		error("vgaxi(0x%4.4x, 0x%2.2X): unknown port\n", port, index);
79 		/*NOTREACHED*/
80 		data = 0xFF;
81 		break;
82 	}
83 	return data;
84 }
85 
86 void
87 vgao(long port, uchar data)
88 {
89 	switch(port){
90 
91 	case MiscW:
92 	case FeatureW:
93 	case PaddrW:
94 	case Pdata:
95 	case Pixmask:
96 	case PaddrR:
97 		outportb(port, data);
98 		break;
99 
100 	default:
101 		error("vgao(0x%4.4X, 0x%2.2X): unknown port\n", port, data);
102 		/*NOTREACHED*/
103 		break;
104 	}
105 }
106 
107 void
108 vgaxo(long port, uchar index, uchar data)
109 {
110 	switch(port){
111 
112 	case Seqx:
113 	case Crtx:
114 	case Grx:
115 		/*
116 		 * We could use an outport here, but some chips
117 		 * (e.g. 86C928) have trouble with that for some
118 		 * registers.
119 		 */
120 		outportb(port, index);
121 		outportb(port+1, data);
122 		break;
123 
124 	case Attrx:
125 		inportb(Status1);
126 		if(index < 0x10){
127 			outportb(Attrx, index);
128 			outportb(Attrx, data);
129 			inportb(Status1);
130 			outportb(Attrx, 0x20|index);
131 		}
132 		else{
133 			outportb(Attrx, 0x20|index);
134 			outportb(Attrx, data);
135 		}
136 		break;
137 
138 	default:
139 		error("vgaxo(0x%4.4X, 0x%2.2X, 0x%2.2X): unknown port\n", port, index, data);
140 		break;
141 	}
142 }
143 
144 static void
145 snarf(Vga *vga, Ctlr *ctlr)
146 {
147 	int i;
148 
149 	verbose("%s->snarf\n", ctlr->name);
150 	/*
151 	 * Generic VGA registers:
152 	 * 	misc, feature;
153 	 *	sequencer;
154 	 *	crt;
155 	 *	graphics;
156 	 *	attribute;
157 	 *	palette.
158 	 */
159 	vga->misc = vgai(MiscR);
160 	vga->feature = vgai(FeatureR);
161 
162 	for(i = 0; i < NSeqx; i++)
163 		vga->sequencer[i] = vgaxi(Seqx, i);
164 
165 	for(i = 0; i < NCrtx; i++)
166 		vga->crt[i] = vgaxi(Crtx, i);
167 
168 	for(i = 0; i < NGrx; i++)
169 		vga->graphics[i] = vgaxi(Grx, i);
170 
171 	for(i = 0; i < NAttrx; i++)
172 		vga->attribute[i] = vgaxi(Attrx, i);
173 
174 	if(dflag)
175 		(*palette.snarf)(vga, ctlr);
176 
177 	ctlr->flag |= Fsnarf;
178 }
179 
180 static void
181 init(Vga *vga, Ctlr *ctlr)
182 {
183 	Mode *mode;
184 	int vt, vde, vrs, vre;
185 	ulong x;
186 
187 	verbose("%s->init\n", ctlr->name);
188 	mode = vga->mode;
189 
190 	memset(vga->sequencer, 0, NSeqx*sizeof(vga->sequencer[0]));
191 	memset(vga->crt, 0, NCrtx*sizeof(vga->crt[0]));
192 	memset(vga->graphics, 0, NGrx*sizeof(vga->graphics[0]));
193 	memset(vga->attribute, 0, NAttrx*sizeof(vga->attribute[0]));
194 	if(dflag)
195 		memset(vga->palette, 0, sizeof(vga->palette));
196 
197 	/*
198 	 * Misc. If both the horizontal and vertical sync polarity
199 	 * options are set, use them. Otherwise use the defaults for
200 	 * the given vertical size.
201 	 */
202 	vga->misc = 0x23;
203 	if(mode->frequency == VgaFreq1)
204 		vga->misc |= 0x04;
205 	if(mode->hsync && mode->vsync){
206 		if(mode->hsync == '-')
207 			vga->misc |= 0x40;
208 		if(mode->vsync == '-')
209 			vga->misc |= 0x80;
210 	}
211 	else{
212 		if(mode->y < 480)
213 			vga->misc |= 0x40;
214 		else if(mode->y < 400)
215 			vga->misc |= 0x80;
216 		else if(mode->y < 768)
217 			vga->misc |= 0xC0;
218 	}
219 
220 	/*
221 	 * Sequencer
222 	 */
223 	vga->sequencer[0x00] = 0x03;
224 	vga->sequencer[0x01] = 0x01;
225 	vga->sequencer[0x02] = 0x0F;
226 	vga->sequencer[0x03] = 0x00;
227 	if(mode->z == 8)
228 		vga->sequencer[0x04] = 0x0A;
229 	else
230 		vga->sequencer[0x04] = 0x06;
231 
232 	/*
233 	 * Crt. Most of the work here is in dealing
234 	 * with field overflow.
235 	 */
236 	memset(vga->crt, 0, NCrtx);
237 
238 	vga->crt[0x00] = (mode->ht>>3)-5;
239 	vga->crt[0x01] = (mode->x>>3)-1;
240 	vga->crt[0x02] = (mode->shb>>3)-1;
241 
242 	/*
243 	 * End Horizontal Blank is a 6-bit field, 5-bits
244 	 * in Crt3, high bit in Crt5.
245 	 */
246 	x = mode->ehb>>3;
247 	vga->crt[0x03] = 0x80|(x & 0x1F);
248 	if(x & 0x20)
249 		vga->crt[0x05] |= 0x80;
250 	vga->crt[0x04] = mode->shb>>3;
251 	vga->crt[0x05] |= (x & 0x1F);
252 
253 	/*
254 	 * Vertical Total is 10-bits, 8 in Crt6, the high
255 	 * two bits in Crt7. What if vt is >= 1024? We hope
256 	 * the specific controller has some more overflow
257 	 * bits.
258 	 *
259 	 * Interlace: if 'v',  divide the vertical timing
260 	 * values by 2.
261 	 */
262 	vt = mode->vt;
263 	vde = mode->y;
264 	vrs = mode->vrs;
265 	vre = mode->vre;
266 
267 	if(mode->interlace == 'v'){
268 		vt /= 2;
269 		vde /= 2;
270 		vrs /= 2;
271 		vre /= 2;
272 	}
273 
274 	x = vt-2;
275 	vga->crt[0x06] = x;
276 	if(x & 0x100)
277 		vga->crt[0x07] |= 0x01;
278 	if(x & 0x200)
279 		vga->crt[0x07] |= 0x20;
280 
281 	x = vrs;
282 	vga->crt[0x10] = x;
283 	if(x & 0x100)
284 		vga->crt[0x07] |= 0x04;
285 	if(x & 0x200)
286 		vga->crt[0x07] |= 0x80;
287 
288 	vga->crt[0x11] = 0x20|(vre & 0x0F);
289 
290 	x = vde-1;
291 	vga->crt[0x12] = x;
292 	if(x & 0x100)
293 		vga->crt[0x07] |= 0x02;
294 	if(x & 0x200)
295 		vga->crt[0x07] |= 0x40;
296 
297 	vga->crt[0x15] = vrs;
298 	if(vrs & 0x100)
299 		vga->crt[0x07] |= 0x08;
300 	if(vrs & 0x200)
301 		vga->crt[0x09] |= 0x20;
302 
303 	vga->crt[0x16] = (vrs+1);
304 
305 	vga->crt[0x17] = 0x83;
306 	x = ((mode->x*mode->z)/8);
307 	if(x >= 512){
308 		vga->crt[0x14] |= 0x60;
309 		x /= 8;
310 	}
311 	else if(x >= 256){
312 		vga->crt[0x17] |= 0x08;
313 		x /= 4;
314 	}
315 	else{
316 		vga->crt[0x17] |= 0x40;
317 		x /= 2;
318 	}
319 	vga->crt[0x13] = x;
320 
321 	if(mode->x*mode->y*mode->z/8 > 64*1024)
322 		vga->crt[0x17] |= 0x20;
323 
324 	vga->crt[0x18] = 0x7FF;
325 	if(vga->crt[0x18] & 0x100)
326 		vga->crt[0x07] |= 0x10;
327 	if(vga->crt[0x18] & 0x200)
328 		vga->crt[0x09] |= 0x40;
329 
330 	/*
331 	 * Graphics
332 	 */
333 	memset(vga->graphics, 0, NGrx);
334 	if((vga->sequencer[0x04] & 0x04) == 0)
335 		vga->graphics[0x05] |= 0x10;
336 	if(mode->z == 8)
337 		vga->graphics[0x05] |= 0x40;
338 	vga->graphics[0x06] = 0x05;
339 	vga->graphics[0x07] = 0x0F;
340 	vga->graphics[0x08] = 0xFF;
341 
342 	/*
343 	 * Attribute
344 	 */
345 	memset(vga->attribute, 0, NAttrx);
346 	for(x = 0; x < 0x10; x++)
347 		vga->attribute[x] = x;
348 	vga->attribute[0x10] = 0x01;
349 	if(mode->z == 8)
350 		vga->attribute[0x10] |= 0x40;
351 	vga->attribute[0x11] = 0xFF;
352 	vga->attribute[0x12] = 0x0F;
353 
354 	/*
355 	 * Palette
356 	 */
357 	if(dflag)
358 		(*palette.init)(vga, ctlr);
359 
360 	ctlr->flag |= Finit;
361 }
362 
363 static void
364 load(Vga *vga, Ctlr *ctlr)
365 {
366 	int i;
367 
368 	verbose("%s->load\n", ctlr->name);
369 	/*
370 	 * Reset the sequencer and leave it off.
371 	 * Load the generic VGA registers:
372 	 *	misc;
373 	 *	sequencer (but not seq01, display enable);
374 	 *	take the sequencer out of reset;
375 	 *	take off write-protect on crt[0x00-0x07];
376 	 *	crt;
377 	 *	graphics;
378 	 *	attribute;
379 	 *	palette.
380 	vgaxo(Seqx, 0x00, 0x00);
381 	 */
382 
383 	vgao(MiscW, vga->misc);
384 
385 	for(i = 2; i < NSeqx; i++)
386 		vgaxo(Seqx, i, vga->sequencer[i]);
387 	/*vgaxo(Seqx, 0x00, 0x03);*/
388 
389 	vgaxo(Crtx, 0x11, vga->crt[0x11] & ~0x80);
390 	for(i = 0; i < NCrtx; i++)
391 		vgaxo(Crtx, i, vga->crt[i]);
392 
393 	for(i = 0; i < NGrx; i++)
394 		vgaxo(Grx, i, vga->graphics[i]);
395 
396 	for(i = 0; i < NAttrx; i++)
397 		vgaxo(Attrx, i, vga->attribute[i]);
398 
399 	if(dflag)
400 		(*palette.load)(vga, ctlr);
401 
402 	ctlr->flag |= Fload;
403 }
404 
405 static void
406 dump(Vga *vga, Ctlr *ctlr)
407 {
408 	int i;
409 
410 	printitem(ctlr->name, "misc");
411 	printreg(vga->misc);
412 	printitem(ctlr->name, "feature");
413 	printreg(vga->feature);
414 
415 	printitem(ctlr->name, "sequencer");
416 	for(i = 0; i < NSeqx; i++)
417 		printreg(vga->sequencer[i]);
418 
419 	printitem(ctlr->name, "crt");
420 	for(i = 0; i < NCrtx; i++)
421 		printreg(vga->crt[i]);
422 
423 	printitem(ctlr->name, "graphics");
424 	for(i = 0; i < NGrx; i++)
425 		printreg(vga->graphics[i]);
426 
427 	printitem(ctlr->name, "attribute");
428 	for(i = 0; i < NAttrx; i++)
429 		printreg(vga->attribute[i]);
430 
431 	if(dflag)
432 		(*palette.dump)(vga, ctlr);
433 
434 	if(vga->f){
435 		printitem(ctlr->name, "clock f");
436 		print("%9ld\n", vga->f);
437 		printitem(ctlr->name, "clock d i n p");
438 		print("%9ld %8ld       - %8ld %8ld\n", vga->d, vga->i, vga->n, vga->p);
439 	}
440 
441 	if(vga->vmb){
442 		printitem(ctlr->name, "vmb");
443 		print("%9ld\n", vga->vmb);
444 	}
445 }
446 
447 Ctlr generic = {
448 	"vga",				/* name */
449 	snarf,				/* snarf */
450 	0,				/* options */
451 	init,				/* init */
452 	load,				/* load */
453 	dump,				/* dump */
454 };
455