1 /*
2  * This is the X11R5 x386 driver for ATI VGA WONDER video adapters.  At
3  * present, this drive works best with ATI VGA WONDER PLUS and ATI VGA
4  * WONDER XL cards with the ATI18810 dot clock and the ATI28800-5 chip.
5  * ATI VGA WONDER cards with other chips revisions may not function as
6  * desired.
7  *
8  * Revised: Sat Feb 13 13:23:18 1993 by root@winter
9  *
10  */
11 
12 /*
13  * Copyright 1990,91 by Thomas Roell, Dinkelscherben, Germany.
14  *
15  * Permission to use, copy, modify, distribute, and sell this software and its
16  * documentation for any purpose is hereby granted without fee, provided that
17  * the above copyright notice appear in all copies and that both that
18  * copyright notice and this permission notice appear in supporting
19  * documentation, and that the name of Thomas Roell not be used in
20  * advertising or publicity pertaining to distribution of the software without
21  * specific, written prior permission.  Thomas Roell makes no representations
22  * about the suitability of this software for any purpose.  It is provided
23  * "as is" without express or implied warranty.
24  *
25  * THOMAS ROELL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
26  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
27  * EVENT SHALL THOMAS ROELL BE LIABLE FOR ANY SPECIAL, INDIRECT OR
28  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
29  * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
30  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
31  * PERFORMANCE OF THIS SOFTWARE.
32  *
33  * Author:  Thomas Roell, roell@informatik.tu-muenchen.de
34  *
35  * $XFree86: mit/server/ddx/x386/vga256/drivers/ati/driver.c,v 2.12 1993/10/18 12:18:47 dawes Exp $
36  */
37 
38 /*
39  * Hacked, to get it working by:
40  *	Per Lindqvist, pgd@compuram.bbt.se
41  *
42  * Enhancements to support most VGA Wonder cards (including Plus and XL)
43  * by Doug Evans, dje@sspiff.UUCP.
44  * ALL DISCLAIMERS APPLY TO THESE ADDITIONS AS WELL.
45  *
46  *	I've come to believe the people who design these cards couldn't
47  *	allow for future enhancements if their life depended on it!
48  *	The register set architecture is a joke!
49  *
50  */
51 
52 /*
53  * Hacked for X11R5 by Rik Faith (faith@cs.unc.edu), Thu Aug  6 21:35:18 1992
54  * ALL DISCLAIMERS APPLY TO MY ADDITIONS AS WELL.
55  *
56  * I wrote the ATIProbe and ATIEnterLeave routines from scratch.  I also
57  * re-organized the ATISave and ATIRestore routines.  This was necessary,
58  * since the vgaHWSave routine did not save the DAC values.  There also
59  * appeared to be a timing problem associated with the 486-33, but this is
60  * not well understood at this time.
61  *
62  * Change log, faith@cs.unc.edu:
63  *  3Feb93: ER_B0 in extregPlusXLAndOrMasks changed from 0x28 to 0x31.
64  *  3Feb93: ER_BE in extregPlusXLAndOrMasks changed from 0x08 to 0x18,
65  *          but ONLY for chips BEFORE the 28800-5.  This required adding
66  *          the ATIChipVersion variable.
67  *  3Feb93: Added message stating correct clocks line.
68  * 13Feb93: Fixed warning message for unsupported boards.
69  * 13Feb93: Added comments and shortened lines over 80 characters long.
70  * 13Feb93: Added the Graphics Ultra Plus \'a\' chip version
71  */
72 
73 /*
74  * NOTES:
75  *
76  *   1) The ATI 18800/28800 use a special registers for their extended
77  *      features. There is one index and one data register. Under MS-DOS this
78  *      should be specified by reading C000:10. But since we cannot read this
79  *      now, let's use the same fixed address as our unix kernel does:
80  *      0x1CE/0x1CF. I also got these ports form a second source, thus it seems
81  *      to be safe to use them.
82  *
83  *	This comment is no longer valid. We read C000:10.
84  *
85  *   2) The ATI 18800/28800 extended registers differ in their i/o behaviour
86  *      from the normal ones:
87  *
88  *       write:   outw(0x1CE, (data << 8) | index);
89  *       read:    outb(0x1CE, index); data = inb(0x1CF);
90  *
91  *      Two consecutive byte-writes are NOT allowed. Furthermore is a index
92  *      written to 0x1CE only usable ONCE !!!
93  *
94  * More notes by dje ...
95  *
96  *   3) I've tried to allow for a future when this code drives all VGA Wonder
97  *	cards. To do this I had decide what to do with the clock values. Boards
98  *	prior to V5 use 4 crystals. Boards V5 and later use a clock generator
99  *	chip. Just to complicate things a bit, V3 and V4 boards aren't
100  *	compatible when it comes to choosing clock frequencies. :-(
101  *
102  *	V3/V4 Board Clock Frequencies
103  *	R E G I S T E R S
104  *	1CE(*)		3C2	3C2		Frequency
105  *	B2h/BEh
106  *	Bit 6/4		Bit 3	Bit 2
107  *	---------	-------	-------		---------
108  *	0		0	0		50.175
109  *	0		0	1		56.644
110  *	0		1	0		Spare 1
111  *	0		1	1		44.900
112  *	1		0	0		44.900
113  *	1		0	1		50.175
114  *	1		1	0		Spare 2
115  *	1		1	1		36.000
116  *
117  *	(*): V3 uses Index B2h, bit 6; V4 uses Index BEh, bit 4.
118  *
119  *	V5,Plus,XL Board Clock Frequencies
120  *	R E G I S T E R S
121  *	1CE	1CE	3C2	3C2		Frequency
122  *	BEh	B9h
123  *	Bit 4	Bit 1	Bit 3	Bit 2
124  *	-------	------- -------	-------		---------
125  *	1	0	0	0		42.954
126  *	1	0	0	1		48.771
127  *	1	0	1	0		External 0 (16.657)
128  *	1	0	1	1		36.000
129  *	1	1	0	0		50.350
130  *	1	1	0	1		56.640
131  *	1	1	1	0		External 1 (28.322)
132  *	1	1	1	1		44.900
133  *	0	0	0	0		30.240
134  *	0	0	0	1		32.000
135  *	0	0	1	0		37.500
136  *	0	0	1	1		39.000
137  *	0	1	0	0		40.000
138  *	0	1	0	1		56.644
139  *	0	1	1	0		75.000
140  *	0	1	1	1		65.000
141  *
142  *	For all of the above (V3,V4,V5,Plus,XL), these frequencies can be
143  *	divided by 1, 2, 3, or 4:
144  *
145  *	Reg 1CE, Index B8h
146  *	Bit 7	Bit 6
147  *	0	0		Divide by 1
148  *	0	1		Divide by 2
149  *	1	0		Divide by 3
150  *	1	1		Divide by 4
151  *
152  *	What I've done is the following. The clock values specified in Xconfig
153  *	shall be:
154  *
155  *			18 22 25 28 36 44 50 56
156  *			30 32 37 39 40 0  75 65		(duplicate 56: --> 0)
157  *
158  *	The first row is usable on all VGA Wonder cards. The second row is
159  *	only usable on V5,Plus,XL cards. The code in ATIInit() will map these
160  *	clock values into the appropriate bit settings for each of the cards.
161  *	Some of these clock choices aren't really usable, think of these as
162  *	place holders.
163  *
164  *   4) The ATI Programmer's Reference Manual lacked enough prose to explain
165  *	what the various bits of all of the various registers do. It is
166  *	entirely reasonable to believe some of the choices I've made are
167  *	imperfect because I didn't understand what I was doing.
168  *
169  *   5) V3 board support needs a lot of work. I suspect it isn't worth it.
170  */
171 
172 
173 #include "X.h"
174 #include "input.h"
175 #include "screenint.h"
176 
177 #include "compiler.h"
178 
179 #include "x386.h"
180 #include "x386Priv.h"
181 #include "xf86_OSlib.h"
182 #include "xf86_HWlib.h"
183 #include "vga.h"
184 #include <sys/types.h>
185 
186 #define DEBUG       0
187 
188 #if DEBUG
189 #define TRACE(a)    ErrorF a	/* Enable TRACE statements */
190 #define DEBUG_PROBE 0		/* Debug the ATIProbe() routine */
191 #else
192 #define TRACE(a)		/* Disable TRACE statements */
193 #endif
194 
195 typedef struct {
196 	vgaHWRec std;		/* good old IBM VGA */
197 	unsigned char ATIExtRegBank[11]; /* ATI Registers B0,B1,B2,B3,B5,B6,B8,B9,BE,A6,A7 */
198 } vgaATIRec, *vgaATIPtr;
199 
200 #define ATI_BOARD_V3	0	/* which ATI board does the user have? */
201 #define ATI_BOARD_V4	1	/* keep these chronologically increasing */
202 #define ATI_BOARD_V5	2
203 #define ATI_BOARD_PLUS	3
204 #define ATI_BOARD_XL	4
205 
206 #define ER_B0	0		/* Extended Register indices (ATIExtRegBank) */
207 #define ER_B1	1
208 #define ER_B2	2
209 #define ER_B3	3
210 #define ER_B5	4
211 #define ER_B6	5
212 #define ER_B8	6
213 #define ER_B9	7
214 #define ER_BE	8
215 #define ER_A6	9
216 #define ER_A7	10
217 
218 #define ATIReg0	ATIExtRegBank[ER_B0]	/* simplifies dje's additions */
219 #define ATIReg1	ATIExtRegBank[ER_B1]
220 #define ATIReg2	ATIExtRegBank[ER_B2]
221 #define ATIReg3	ATIExtRegBank[ER_B3]
222 #define ATIReg5	ATIExtRegBank[ER_B5]
223 #define ATIReg6	ATIExtRegBank[ER_B6]
224 #define ATIReg8	ATIExtRegBank[ER_B8]
225 #define ATIReg9	ATIExtRegBank[ER_B9]
226 #define ATIRegE	ATIExtRegBank[ER_BE]
227 #define ATIRegA6 ATIExtRegBank[ER_A6]
228 #define ATIRegA7 ATIExtRegBank[ER_A7]
229 
230 static Bool ATIProbe();
231 static char *ATIIdent();
232 static void ATIEnterLeave();
233 static Bool ATIInit();
234 static void *ATISave();
235 static void ATIRestore();
236 static void ATIAdjust();
237 extern void ATISetRead();
238 extern void ATISetWrite();
239 extern void ATISetReadWrite();
240 static int inATI();
241 
242 vgaVideoChipRec ATI = {
243 	ATIProbe,
244 	ATIIdent,
245 	ATIEnterLeave,
246 	ATIInit,
247 	ATISave,
248 	ATIRestore,
249 	ATIAdjust,
250 	NoopDDA,
251 	NoopDDA,
252 	NoopDDA,
253 	ATISetRead,
254 	ATISetWrite,
255 	ATISetReadWrite,
256 	0x10000,
257 	0x10000,
258 	16,
259 	0xFFFF,
260 	0x00000, 0x10000,
261 	0x00000, 0x10000,
262 	TRUE,                    /* uses 2 banks */
263 	VGA_DIVIDE_VERT,
264 	{0,},
265 	16,
266 };
267 
268 short ATIExtReg = 0x1ce;	/* used by bank.s (must be short!) */
269 
270 static int ATIBoard;		/* one of ATI_BOARD_XXX */
271 static int ATIChipVersion;	/* chip version number */
272 
273 /*
274  * ATIIdent --
275  */
276 static char *
ATIIdent(n)277 ATIIdent(n)
278 int n;
279 {
280 	static char *chipsets[] = {"ati"};
281 
282 	if (n + 1 > sizeof(chipsets) / sizeof(char *))
283 		return(NULL);
284 	else
285 		return(chipsets[n]);
286 }
287 
288 /*
289  * ATIRestore --
290  *      restore a video mode
291  *
292  * Results:
293  *      nope.
294  *
295  * Side Effects:
296  *      the display enters a new graphics mode.
297  */
298 
299 static void
ATIRestore(restore)300 ATIRestore(restore)
301 vgaATIPtr restore;
302 {
303         int i;
304 
305 	TRACE(("ATIRestore(restore=0x%x)\n", restore));
306 
307 	if (vgaIOBase == 0x3B0)
308 		restore->std.MiscOutReg &= 0xFE;
309 	else
310 		restore->std.MiscOutReg |= 0x01;
311 
312 	/* Disable video */
313 	(void) inb(vgaIOBase + 0x0A);	/* reset flip-flop */
314 	outb(0x3C0, 0x00);
315 
316 	/* Unlock ATI specials */
317 	outw(ATIExtReg, ((inATI(0xb8) & 0xC0) << 8) | 0xb8);
318 
319 	/* Load Miscellaneous Output External Register */
320 	outb(0x3C2, restore->std.MiscOutReg);
321 
322 	outw(ATIExtReg, 0x00b2);	/* segment select 0 */
323 
324 	/* For text modes, download Character Generator into Plane 2 */
325 	if (restore->std.FontInfo1 || restore->std.FontInfo2 ||
326             restore->std.TextInfo) {
327 		/*
328 		 * here we switch temporary to 16 color-plane-mode, to simply
329 		 * copy the font-info and saved text
330 		 *
331 		 * BUGALLERT:
332 		 * The vga's segment-select register MUST be set appropriate !
333 		 */
334 
335 		inb(vgaIOBase + 0x0A); /* reset flip-flop */
336 		outb(0x3C0,0x10); outb(0x3C0, 0x01); /* graphics mode */
337 
338 #if 0
339 		outw(0x3c3, 0x0001);
340 #endif
341 
342 		if (restore->std.FontInfo1) {
343 			outw(0x3C4, 0x0402);    /* write to plane 2 */
344 			outw(0x3C4, 0x0604);    /* enable plane graphics */
345 			outw(0x3CE, 0x0204);    /* read plane 2 */
346 			outw(0x3CE, 0x0005);    /* write mode 0, read mode 0 */
347 			outw(0x3CE, 0x0506);    /* set graphics */
348 
349 			bcopy(restore->std.FontInfo1, vgaBase, 8192);
350 		}
351 
352 		if (restore->std.FontInfo2) {
353 			outw(0x3C4, 0x0802);	/* write to plane 3 */
354 			outw(0x3C4, 0x0604);	/* enable plane grp */
355 			outw(0x3CE, 0x0304);	/* read plane 3 */
356 			outw(0x3CE, 0x0005);	/* read/write mode 0 */
357 			outw(0x3CE, 0x0506);	/* set graphics */
358 			bcopy(restore->std.FontInfo2, vgaBase, 8192);
359 		}
360 
361 		if (restore->std.TextInfo) {
362 			outw(0x3C4, 0x0202);	/* write to plane 1 */
363 			outw(0x3C4, 0x0604);	/* enable plane grp */
364 			outw(0x3CE, 0x0104);	/* read plane 1 */
365 			outw(0x3CE, 0x0005);	/* read/write mode 0 */
366 			outw(0x3CE, 0x0506);	/* set graphics */
367 			bcopy(restore->std.TextInfo, vgaBase, 4096);
368 
369 			outw(0x3C4, 0x0102);	/* write to plane 0 */
370 			outw(0x3C4, 0x0604);	/* enable plane grp */
371 			outw(0x3CE, 0x0004);	/* read plane 0 */
372 			outw(0x3CE, 0x0005);	/* read/write mode 0 */
373 			outw(0x3CE, 0x0506);	/* set graphics */
374 			bcopy(restore->std.TextInfo + 4096, vgaBase, 4096);
375 		}
376 	}
377 
378 	/* This sequence is from the "VGA Wonder Programmer's
379 	   Reference Manual."  I assume it is correct :-)
380 	   faith@cs.unc.edu (7Aug92) */
381 
382 	/* Place Sequencer into Reset condition using its Reset Register */
383 	outw(0x3C4, 0x0100);
384 
385 	/* Load ATI Extended Registers */
386 	outw(ATIExtReg, (restore->ATIReg0 << 8) | 0xb0);
387 	outw(ATIExtReg, (restore->ATIReg1 << 8) | 0xb1);
388 	outw(ATIExtReg, (restore->ATIReg2 << 8) | 0xb2);
389 	outw(ATIExtReg, (restore->ATIReg5 << 8) | 0xb5);
390 	outw(ATIExtReg, (restore->ATIReg6 << 8) | 0xb6);
391 	outw(ATIExtReg, (restore->ATIRegE << 8) | 0xbe);
392 	outw(ATIExtReg, (restore->ATIReg3 << 8) | 0xb3);
393 	outw(ATIExtReg, (restore->ATIReg8 << 8) | 0xb8);
394 	if (ATIBoard >= ATI_BOARD_PLUS) {
395 		outw(ATIExtReg, (restore->ATIReg9 << 8) | 0xb9);
396 		outw(ATIExtReg, (restore->ATIRegA6 << 8) | 0xa6);
397 		outw(ATIExtReg, (restore->ATIRegA7 << 8) | 0xa7);
398 	}
399 
400 	/* Load Miscellaneous Output External Register */
401 	outb(0x3C2, restore->std.MiscOutReg);
402 
403 	/* Load Sequence Registers 1 through 4 */
404   	for (i=1; i<5;  i++) outw(0x3C4, (restore->std.Sequencer[i] << 8) | i);
405 
406 	/* Restart Sequencer using Reset Register */
407 	outw(0x3C4, 0x0300);
408 
409 	/* Load all 25 CRT Control Registers */
410 	/* But first, unlock CRTC registers 0 to 7 */
411 	outw(vgaIOBase + 4, ((restore->std.CRTC[0x11] & 0x7F) << 8) | 0x11);
412 	for (i=0; i<25; i++)
413 	      outw(vgaIOBase + 4,(restore->std.CRTC[i] << 8) | i);
414 
415 	/* Reset Attribute Controller address/data flip-flop */
416 	(void) inb(vgaIOBase + 0x0A);
417 
418 	/* Load all 20 Attribute Controller Registers */
419 	for (i=0; i<21; i++) {
420 	   (void) inb(vgaIOBase + 0x0A);
421 	   outb(0x3C0,i);
422 	   outb(0x3C0, restore->std.Attribute[i]);
423 	}
424 
425 	/* Load all 9 Graphics Controller Registers */
426 	for (i=0; i<9; i++) outw(0x3CE, (restore->std.Graphics[i] << 8) | i);
427 
428 	/* Load all 768 DAC Registers */
429 	outb(0x3C8,0x00);
430 	for (i=0; i<768; i++) outb(0x3C9, restore->std.DAC[i]);
431 
432 	/* Reset Attribute Controller address/data flip-flop */
433 	(void) inb(vgaIOBase + 0x0A);
434 
435 	/* Turn Attribute Controller on */
436 	outb(0x3C0, 0x20);
437 }
438 
439 /*
440  * ATISave --
441  *      save the current video mode
442  *
443  * Results:
444  *      pointer to the current mode record.
445  *
446  * Side Effects:
447  *      None.
448  */
449 
450 static void *
ATISave(save)451 ATISave(save)
452 vgaATIPtr save;
453 {
454 	unsigned char b2_save,b8_save;
455 	int i;
456 
457 	TRACE(("ATISave(save=0x%x)\n", save));
458 
459 	vgaIOBase = (inb(0x3cc) & 0x01) ? 0x3D0 : 0x3B0;
460 
461 	/* Disable video */
462 	inb(vgaIOBase + 0x0A); /* reset flip-flop */
463 	outb( 0x3c0, 0x00 );
464 
465 	/* Unlock ATI specials */
466 	outw(ATIExtReg, (((b8_save = inATI(0xb8)) & 0xC0) << 8) | 0xb8);
467 
468 	if (save == NULL) {
469 	   save = (vgaATIPtr)Xcalloc(sizeof(vgaATIRec));
470 	   TRACE(("ATISave: save = 0x%x\n",save));
471 	}
472 
473 	/*
474 	 * now get the fuck'in register
475 	 */
476 	save->std.MiscOutReg = inb(0x3CC);
477 
478 
479 	b2_save = inATI(0xb2);
480 	outw(ATIExtReg, 0x00b2);	/* segment select 0 */
481 
482 	save->ATIReg0 = inATI(0xb0);
483 	save->ATIReg1 = inATI(0xb1);
484 	save->ATIReg2 = b2_save;
485 	save->ATIReg3 = inATI(0xb3);
486 	save->ATIReg5 = inATI(0xb5);
487 	save->ATIReg6 = inATI(0xb6);
488 	save->ATIReg8 = b8_save;
489 	save->ATIRegE = inATI(0xbe);
490 	if (ATIBoard >= ATI_BOARD_PLUS) {
491 		save->ATIReg9 = inATI(0xb9);
492 		save->ATIRegA6 = inATI(0xa6);
493 		save->ATIRegA7 = inATI(0xa7);
494 	}
495 
496 	for (i=0; i<25; i++) {
497 	   outb(vgaIOBase + 4,i);
498 	   save->std.CRTC[i] = inb(vgaIOBase + 5);
499 	}
500 
501 	for (i=0; i<21; i++) {
502 	   inb(vgaIOBase + 0x0A); /* reset flip-flop */
503 	   outb(0x3C0,i);
504 	   save->std.Attribute[i] = inb(0x3C1);
505 	}
506 
507 	for (i=0; i<9;  i++) {
508 	   outb(0x3CE,i); save->std.Graphics[i]  = inb(0x3CF);
509 	}
510 
511 	for (i=0; i<5;  i++) {
512 	   outb(0x3C4,i); save->std.Sequencer[i] = inb(0x3C5);
513 	}
514 
515 	/*
516 	 * save the colorlookuptable
517 	 */
518 	outb(0x3C6,0xFF);
519 	outb(0x3C7,0x00);
520 	for (i=0; i<768; i++) save->std.DAC[i] = inb(0x3C9);
521 
522 	/*
523 	 * get the character set of the first non-graphics application
524 	 */
525 	if (((save->std.Attribute[0x10] & 0x01) == 0) &&
526 	    (save->std.FontInfo1 == NULL)) {
527 	   /*
528 	    * Here we switch temporary to 16 color-plane-mode, to simply
529 	    * copy the font-info
530 	    *
531 	    * BUGALLERT: The vga's segment-select register
532 	    *            MUST be set appropriate !
533 	    */
534 	   save->std.FontInfo1 = (pointer)xalloc(8192);
535 	   inb(vgaIOBase + 0x0A); /* reset flip-flop */
536 	   outb(0x3C0,0x10); outb(0x3C0, 0x01); /* graphics mode */
537 	   outw(0x3C4, 0x0402);    /* write to plane 2 */
538 	   outw(0x3C4, 0x0604);    /* enable plane graphics */
539 	   outw(0x3CE, 0x0204);    /* read plane 2 */
540 	   outw(0x3CE, 0x0005);    /* write mode 0, read mode 0 */
541 	   outw(0x3CE, 0x0506);    /* set graphics */
542 
543 	   bcopy(vgaBase, save->std.FontInfo1, 8192);
544 
545 #ifndef HAS_USL_VTS
546 	   if (save->std.FontInfo2 == NULL) {
547 		save->std.FontInfo2 = (pointer)xalloc(8192);
548 		/* plane 3 */
549 		outw(0x3C4, 0x0802);
550 		outw(0x3C4, 0x0604);
551 		outw(0x3CE, 0x0304);
552 		outw(0x3CE, 0x0005);
553 		outw(0x3CE, 0x0506);
554 		bcopy(vgaBase, save->std.FontInfo2, 8192);
555 	   }
556 
557 	   if (save->std.TextInfo == NULL) {
558 		save->std.TextInfo = (pointer)xalloc(8192);
559 		/* plane 1 */
560 		outw(0x3C4, 0x0202);
561 		outw(0x3C4, 0x0604);
562 		outw(0x3CE, 0x0104);
563 		outw(0x3CE, 0x0005);
564 		outw(0x3CE, 0x0506);
565 		bcopy(vgaBase, save->std.TextInfo, 4096);
566 
567 		/* plane 0 */
568 		outw(0x3C4, 0x0102);
569 		outw(0x3C4, 0x0604);
570 		outw(0x3CE, 0x0004);
571 		outw(0x3CE, 0x0005);
572 		outw(0x3CE, 0x0506);
573 		bcopy(vgaBase, save->std.TextInfo + 4096, 4096);
574 	   }
575 #endif /* HAS_USL_VTS */
576 	}
577 
578 	/* Enable video */
579 	inb(vgaIOBase + 0x0A); /* reset flip-flop */
580 	outb( 0x3c0, 0x20 );
581 
582 	return ((void *) save);
583 }
584 
585 /*
586  * ATIInit --
587  *      Handle the initialization, etc. of a screen.
588  *
589  * Results:
590  *      None.
591  *
592  * Side Effects:
593  *
594  */
595 
596 #define TABLE_END	255	/* denotes end of extended register table */
597 
598 /*
599  * Various bit values for mapping the clock values in Xconfig to bit masks for
600  * the various registers.
601  * WARNING: The bits are carefully chosen. They must not collide.
602  *
603  * See the discussion at the beginning of this file.
604  */
605 
606 #define CLOCK_0		(0 << 2)	/* values for Reg 3C2, bits 2,3 */
607 #define CLOCK_1		(1 << 2)
608 #define CLOCK_2		(2 << 2)
609 #define CLOCK_3		(3 << 2)
610 #define CLOCK_MASK	0x0c
611 
612 #define DIVIDE_BY_2	0x40	/* divide freq. by 2 */
613 #define DIVIDE_MASK	0xc0	/* for all of Reg 1CE, Index B8h, bits 6,7 */
614 
615 #define V3V4_BIT64	0x10	/* V3 Reg 1CE, Index B2h, Bit 6; and
616 				   V4 Reg 1CE, Index BEh, Bit 4 */
617 
618 #define V5_BE_BIT4	0x10	/* V5,Plus,XL Reg 1CE, Index BEh, bit 4 */
619 #define V5_B9_BIT1	0x02	/* V5,Plus,XL Reg 1CE, Index B9h, bit 1 */
620 
621 static Bool
ATIInit(mode)622 ATIInit(mode)
623 DisplayModePtr mode;
624 {
625 	/*
626 	 * We use a table lookup method for setting the extended registers.
627 	 * These values are taken from the Programmer's Ref. Manual and are
628 	 * based on Mode 62h. Support for higher resolutions on earlier boards
629 	 * is not complete (but I have documented what's missing).
630 	 */
631 	static unsigned char extregV3AndOrMasks[][3] = {
632 		{ ER_B0, 0xc1, 0x30 },	/* 30 is 38 for mode 63h */
633 		{ ER_B1, 0x87, 0x00 },
634 		{ ER_B2, 0xbe, 0x00 },	/* 00 is 40 for mode 63h */
635 		{ ER_B5, 0x7f, 0x00 },
636 		{ ER_B6, 0xe7, 0x00 },
637 		{ ER_B8, 0x3f, 0x00 },
638 		{ TABLE_END }
639 	};
640 	static unsigned char extregV4AndOrMasks[][3] = {
641 		{ ER_B0, 0xc1, 0x30 },	/* FIXME: 30 is 38 for mode 63h */
642 		{ ER_B1, 0x87, 0x00 },
643 		{ ER_B3, 0xaf, 0x00 },
644 		{ ER_B5, 0x7f, 0x00 },
645 		{ ER_B6, 0xe7, 0x00 },
646 		{ ER_B8, 0x3f, 0x00 },
647 		{ ER_BE, 0xe5, 0x08 },
648 		{ TABLE_END }
649 	};
650 	static unsigned char extregV5AndOrMasks[][3] = {
651 		{ ER_B0, 0xc1, 0x30 },	/* FIXME: 30 is 38 for mode 63h */
652 		{ ER_B1, 0x87, 0x00 },
653 		{ ER_B3, 0xaf, 0x00 },
654 		{ ER_B5, 0x7f, 0x00 },
655 		{ ER_B6, 0xe7, 0x00 },
656 		{ ER_B8, 0x3f, 0x00 },
657 		{ ER_B9, 0xfd, 0x00 },
658 		{ ER_BE, 0xe5, 0x08 },
659 		{ TABLE_END }
660 	};
661 	/*
662 	 * Plus and XL Extended Registers ...
663 	 *
664 	 * The Programmer's Reference Manual has lots of contradictions. Sigh.
665 	 * ER_B0: Page 16-5 says AND mask is 0xd8. Page 16-33 has 0xd1.
666 	 * ER_B8: Page 16-5 has an AND mask of 0x7f which is wrong.
667 	 * ER_B9: Page 16-5 has an AND mask of 0xff which is wrong.
668 	 * ER_BE: Page 16-5 has an AND mask of 0xf5 which is wrong.
669 	 */
670 	static unsigned char extregPlusXLAndOrMasks[][3] = {
671 	   /* Changed ER_B0 entry from 0x28 to 0x31, Wed Feb  3 09:22:13 1993,
672 	      based on patch by ruhtra@turing.toronto.edu (Arthur Tateishi). */
673 		{ ER_B0, 0xd9, 0x31 },	/* Experiment: 28 was 20 */
674 		{ ER_B1, 0x87, 0x00 },
675 		{ ER_B3, 0xaf, 0x00 },
676 		{ ER_B5, 0x7f, 0x00 },
677 		{ ER_B6, 0xe2, 0x04 },
678 		{ ER_B8, 0x3f, 0x00 },
679 		{ ER_B9, 0xfd, 0x00 },
680 		{ ER_BE, 0xe5, 0x08 },
681 		{ ER_A6, 0xfe, 0x01 },	/* Experiment */
682 		{ ER_A7, 0xf4, 0x08 },
683 		{ TABLE_END }
684 	};
685 	static unsigned char extregIndices[11] = {
686 		/* These values must coincide with the ER_x values. */
687 		0xb0, 0xb1, 0xb2, 0xb3, 0xb5, 0xb6, 0xb8, 0xb9, 0xbe,
688 		0xa6, 0xa7
689 	};
690 	static unsigned char clockV3V4Table[] = {
691 		/* clock values: 18 22 25 28 36 44 50 56 */
692 		V3V4_BIT64 | CLOCK_3 | DIVIDE_BY_2, /*18*/
693 		0          | CLOCK_3 | DIVIDE_BY_2, /*22*/
694 		0          | CLOCK_0 | DIVIDE_BY_2, /*25*/
695 		0          | CLOCK_1 | DIVIDE_BY_2, /*28*/
696 		V3V4_BIT64 | CLOCK_3,               /*36*/
697 		0          | CLOCK_3,               /*44*/
698 		0          | CLOCK_0,               /*50*/
699 		0          | CLOCK_1                /*56*/
700 	};
701 	static unsigned char clockV5PlusXLTable[] = {
702 		/* clock values: 18 22 25 28 36 44 50 56
703 		                 30 32 37 39 40 56 75 65 */
704 		V5_BE_BIT4 | 0          | CLOCK_3 | DIVIDE_BY_2, /*18*/
705 		V5_BE_BIT4 | V5_B9_BIT1 | CLOCK_3 | DIVIDE_BY_2, /*22*/
706 		V5_BE_BIT4 | V5_B9_BIT1 | CLOCK_0 | DIVIDE_BY_2, /*25*/
707 		V5_BE_BIT4 | V5_B9_BIT1 | CLOCK_1 | DIVIDE_BY_2, /*28*/
708 		V5_BE_BIT4 | 0          | CLOCK_3,               /*36*/
709 		V5_BE_BIT4 | V5_B9_BIT1 | CLOCK_3,               /*44*/
710 		V5_BE_BIT4 | V5_B9_BIT1 | CLOCK_0,               /*50*/
711 		V5_BE_BIT4 | V5_B9_BIT1 | CLOCK_1,               /*56*/
712 		0          | 0          | CLOCK_0,               /*30*/
713 		0          | 0          | CLOCK_1,               /*32*/
714 		0          | 0          | CLOCK_2,               /*37*/
715 		0          | 0          | CLOCK_3,               /*39*/
716 		0          | V5_B9_BIT1 | CLOCK_0,               /*40*/
717 		0          | V5_B9_BIT1 | CLOCK_1,               /*56*/
718 		0          | V5_B9_BIT1 | CLOCK_2,               /*75*/
719 		0          | V5_B9_BIT1 | CLOCK_3                /*65*/
720 	};
721 	int i,fd;
722 	unsigned char byte_42,byte_43,byte_44;
723 	unsigned char (*extregTabPtr)[3];
724 	unsigned char *clockTabPtr;
725 	vgaATIPtr new;	/* was: #define new ((vgaATIPtr)vgaNewVideoState)
726 				- made a variable to ease debugging */
727 
728 	TRACE(("ATIInit(mode=0x%x)\n", mode));
729 
730 	/*
731 	 * Set the default values ...
732 	 */
733 
734 	if (!vgaHWInit(mode, sizeof(vgaATIRec)))
735 	  return(FALSE);
736 
737 	new = (vgaATIPtr) vgaNewVideoState;	/* must do after vgaHWInit() */
738 
739 	/*
740 	 * On with ATI specific stuff ...
741 	 */
742 
743 	switch (ATIBoard) {
744 	case ATI_BOARD_V3 :
745 		extregTabPtr = extregV3AndOrMasks;
746 		clockTabPtr = clockV3V4Table;
747 		break;
748 	case ATI_BOARD_V4 :
749 		extregTabPtr = extregV4AndOrMasks;
750 		clockTabPtr = clockV3V4Table;
751 		break;
752 	case ATI_BOARD_V5 :
753 		extregTabPtr = extregV5AndOrMasks;
754 		clockTabPtr = clockV5PlusXLTable;
755 		break;
756 	case ATI_BOARD_PLUS :
757 	case ATI_BOARD_XL :
758 	default :
759 		extregTabPtr = extregPlusXLAndOrMasks;
760 		clockTabPtr = clockV5PlusXLTable;
761 		break;
762 	}
763 
764 	/*
765 	 * The VGA Wonder/XL has a bit that says "multiply vertical values by
766 	 * 2". This applies to CRTC[8,10h,12h,15h,18h]. At least that's what
767 	 * the manual says. I suspect it applies elsewhere, and that even a few
768 	 * of these values may be wrong. Unfortunately, their 1024x768 examples
769 	 * don't set this bit, so what is going on?
770 	 *
771 	 * We use this feature when the vertical display size is > 480. This
772 	 * means that odd values in the vertical timing field in Xconfig are
773 	 * truncated (modulo 2).
774 	 *
775 	 * I've duplicated all of vgaHWInit()'s setting of CRTC for
776 	 * completeness. Down the road we may have to add more stuff, so I've
777 	 * brought it all in here just in case.
778 	 */
779 
780 	if (mode->VDisplay > 480) {
781 		int shift = 1 + ((ATIBoard > ATI_BOARD_V3) &&
782 				 (mode->Flags & V_INTERLACE));
783 
784 		mode->VDisplay >>= shift;
785 		mode->VSyncStart >>= shift;
786 		mode->VSyncEnd >>= shift;
787 		mode->VTotal >>= shift;
788 
789 		new->std.CRTC[0]  = (mode->HTotal >> 3) - 5;
790 		new->std.CRTC[1]  = (mode->HDisplay >> 3) - 1;
791 		new->std.CRTC[2]  = (mode->HSyncStart >> 3) - 1;
792 		new->std.CRTC[3]  = ((mode->HSyncEnd >> 3) & 0x1f) | 0x80;
793 		new->std.CRTC[4]  = (mode->HSyncStart >> 3);
794 		new->std.CRTC[5]  = (((mode->HSyncEnd >> 3) & 0x20) << 2)
795 			| (((mode->HSyncEnd >> 3)) & 0x1f);
796 		new->std.CRTC[6]  = (mode->VTotal - 2) & 0xff;
797 		new->std.CRTC[7]  = (((mode->VTotal - 2) & 0x100) >> 8)
798 			| (((mode->VDisplay - 1) & 0x100) >> 7)
799 			| ((mode->VSyncStart & 0x100) >> 6)
800 			| (((mode->VSyncStart) & 0x100) >> 5)
801 			| 0x10
802 			| (((mode->VTotal - 2) & 0x200) >> 4)
803 			| (((mode->VDisplay - 1) & 0x200) >> 3)
804 			| ((mode->VSyncStart & 0x200) >> 2);
805 		new->std.CRTC[8]  = 0x00;
806 		new->std.CRTC[9]  = ((mode->VSyncStart & 0x200) >> 4 ) | 0x40;
807 		new->std.CRTC[10] = 0x00;
808 		new->std.CRTC[11] = 0x00;
809 		new->std.CRTC[12] = 0x00;
810 		new->std.CRTC[13] = 0x00;
811 		new->std.CRTC[14] = 0x00;
812 		new->std.CRTC[15] = 0x00;
813 		new->std.CRTC[16] = mode->VSyncStart & 0xff;
814 		new->std.CRTC[17] = (mode->VSyncEnd & 0x0f) | 0x20;
815 		new->std.CRTC[18] = (mode->VDisplay -1) & 0xff;
816 		new->std.CRTC[19] = vga256InfoRec.virtualX >> 4;
817 		new->std.CRTC[20] = 0x00;
818 		new->std.CRTC[21] = mode->VSyncStart & 0xff;
819 		new->std.CRTC[22] = (mode->VSyncStart + 1) & 0xff;
820 		new->std.CRTC[23] = 0xe7; /* bit 0x04 sets "*2 vert. values" */
821 		new->std.CRTC[24] = 0xff;
822 
823 		mode->VDisplay <<= shift;
824 		mode->VSyncStart <<= shift;
825 		mode->VSyncEnd <<= shift;
826 		mode->VTotal <<= shift;
827 	} else {
828 		new->std.CRTC[23] = 0xe3;	/* ATI uses an even/odd bank
829 							256 color mode */
830 	}
831 
832 	new->std.Sequencer[4] = 0x0a;
833 	new->std.Graphics[5] = 0x00;
834 	new->std.Attribute[16] = 0x01;
835 
836 	/*
837 	 * Experiment. It looks like MiscOutReg is a little different for
838 	 * the high resolution modes. I've duplicated the code from
839 	 * vgaHWInit() because it looks like they have different handling
840 	 * if the syncs are explicitly mentioned, and I want to preserve
841 	 * this.
842 
843 	if ((mode->Flags & (V_PHSYNC | V_NHSYNC))
844 		&& (mode->Flags & (V_PVSYNC | V_NVSYNC)))
845 	{
846 		new->MiscOutReg = 0x23;
847 		if (mode->Flags & V_NHSYNC) new->MiscOutReg |= 0x40;
848 		if (mode->Flags & V_NVSYNC) new->MiscOutReg |= 0x80;
849 	} else {
850 		if      (mode->VDisplay < 400) new->MiscOutReg = 0xA3;
851 		else if (mode->VDisplay < 480) new->MiscOutReg = 0x63;
852 		else if (mode->VDisplay < 768) new->MiscOutReg = 0xE3;
853 		else                           new->MiscOutReg = 0xE3;
854 	}
855 
856 	/*
857 	 * Get the extended register values ...
858 	 */
859 
860 	bzero(new->ATIExtRegBank, sizeof(new->ATIExtRegBank));
861 	for (i = 0; extregTabPtr[i][0] != TABLE_END; i++) {
862 		new->ATIExtRegBank[extregTabPtr[i][0]] =
863 			(inATI(extregIndices[extregTabPtr[i][0]]) &
864 				extregTabPtr[i][1]) |
865 					extregTabPtr[i][2];
866 	}
867 
868 	if ((ATIBoard > ATI_BOARD_V3) && (mode->Flags & V_INTERLACE))
869 		new->ATIRegE |= 0x02;	/* FIXME: doesn't work */
870 
871 	/*
872 	 * Handle the oddballs ...
873 	 *
874 	 * It appears that bit 0 of extended register 0xb6 enables the upper
875 	 * 512KB. ATI's MSWindows driver sets this bit to 1, and it appears
876 	 * to work here as well (previously I was getting duplicate images:
877 	 * the lower 512KB being used twice).
878 	 */
879 
880 	switch (ATIBoard) {
881 	case ATI_BOARD_V3 :
882 	case ATI_BOARD_V4 :
883 	case ATI_BOARD_V5 :
884 		break;
885 	case ATI_BOARD_PLUS :
886 	case ATI_BOARD_XL :
887 	default :
888 		if (ATIChipVersion < '5' || ATIChipVersion >= 'a') {
889 		   /* Changed ER_BE entry from 0x08 to 0x18,
890 		      Wed Feb  3 12:11:27 1993, based on patch by
891 		      aal@broue.rot.qc.ca (Alain Hebert). */
892 		   new->ATIExtRegBank[ER_BE] |= 0x10;
893 		}
894 
895 		if (vga256InfoRec.videoRam == 1024)
896 			new->ATIReg6 |= 0x01;
897 		break;
898 	}
899 
900 	/*
901 	 * Get the clock value ...
902 	 * See the discussion at the beginning of this file.
903 	 */
904 
905 	new->std.MiscOutReg &= ~CLOCK_MASK;
906 	new->std.MiscOutReg |= clockTabPtr[mode->Clock] & CLOCK_MASK;
907 
908 	if (ATIBoard == ATI_BOARD_V3) {
909 		if (clockTabPtr[mode->Clock] & V3V4_BIT64)
910 			new->ATIReg2 |= 0x40;
911 	} else if (ATIBoard == ATI_BOARD_V4) {
912 		if (clockTabPtr[mode->Clock] & V3V4_BIT64)
913 			new->ATIRegE |= 0x10;
914 	} else {
915 		if (clockTabPtr[mode->Clock] & V5_BE_BIT4)
916 			new->ATIRegE |= 0x10;
917 		if (clockTabPtr[mode->Clock] & V5_B9_BIT1)
918 			new->ATIReg9 |= 0x02;
919 	}
920 
921 	new->ATIReg8 |= clockTabPtr[mode->Clock] & DIVIDE_MASK;
922 	return(TRUE);
923 }
924 
925 /*
926  * ATIAdjust --
927  *      adjust the current video frame to display the mousecursor
928  *
929  * Results:
930  *      nope.
931  *
932  * Side Effects:
933  *      the display scrolls
934  */
935 
936 static void
ATIAdjust(x,y)937 ATIAdjust(x, y)
938      int x, y;
939 {
940 	int Base;
941 
942 	/**
943 	 ** TODO: Adjust the shift-count here !!!
944 	 **	Ferraro writes, that there may be no shift at all. But this
945 	 **	would kill our panning feature.
946 	 **/
947 
948 	Base = (y * vga256InfoRec.virtualX + x + 3) >> 3;
949 
950 	outw(vgaIOBase + 4, (Base & 0x00FF00) | 0x0C);
951 	outw(vgaIOBase + 4, ((Base & 0x00FF) << 8) | 0x0D);
952 }
953 
954 static int
inATI(index)955 inATI(index)
956 {
957 	outb(ATIExtReg, index);
958 	return inb(ATIExtReg + 1);
959 }
960 
961 /*
962  * ATIProbe() checks for an ATI card.
963  *
964  * Returns TRUE or FALSE on exit.
965  *
966  * Makes sure the following are set in vga256InofRec:
967  *    chipset
968  *    videoRam
969  *    clocks
970  *
971  * Also sets:
972  *    ATIBoard
973  *    ATIExtREG
974  *
975  * References:
976  *   "VGA WONDER Programmer's Reference,"
977  *      ATI Technologies, 1991.
978  *      Release 1.2 -- Reference #PRG28800
979  *      (Part No. 10709B0412)
980  *      Chapter 7: Identification and Configuration
981  *
982  *   George Sutty and Steve Blair's "Advanced Programmer's
983  *      Guide to SuperVGAs," Brady/Simon & Schuster, 1990.
984  *      Chapter 11: ATI 18800 ATI VGAWONDER
985  *
986  *   Some random document from the ATI BBS dated 3Jun91,
987  *      which may have been called PROGINGO.DOC.
988  *
989  * Written by:
990  * Rik Faith (faith@cs.unc.edu), Sun Aug  9 09:27:40 1992
991  *
992  */
993 
994 #define SIGNATURE_LENGTH	9
995 #define BIOS_DATA_SIZE		0x50
996 static Bool
ATIProbe()997 ATIProbe()
998 {
999    char *signature = "761295520";
1000 /*   const char signature[] = "761295520"; */
1001    const char signature_length = SIGNATURE_LENGTH;
1002    const int  bios_data_size = BIOS_DATA_SIZE;
1003    char bios_signature[SIGNATURE_LENGTH];
1004    char bios_data[BIOS_DATA_SIZE];
1005    unsigned ports[2];
1006    int  fd;
1007 
1008    TRACE(("ATIProbe()\n"));
1009 
1010    /*
1011     * Set up I/O ports to be used by this card
1012     */
1013    xf86ClearIOPortList(vga256InfoRec.scrnIndex);
1014    xf86AddIOPorts(vga256InfoRec.scrnIndex, Num_VGA_IOPorts, VGA_IOPorts);
1015 
1016    if (vga256InfoRec.chipset) {
1017       if (StrCaseCmp(vga256InfoRec.chipset, ATIIdent(0)))
1018          return FALSE;
1019    } else {
1020       if (xf86ReadBIOS(vga256InfoRec.BIOSbase, 0x31,
1021 			(unsigned char *)bios_signature,
1022 			signature_length) != signature_length)
1023 	 return FALSE;
1024       if (strncmp( signature, bios_signature, signature_length )) {
1025 	 TRACE(("ATIProbe: Incorrect Signature\n"));
1026 	 return FALSE;
1027       }
1028    }
1029 
1030    /* Assume an ATI card. */
1031    vga256InfoRec.chipset = ATIIdent(0);
1032 
1033    /* Now look in the BIOS for magic numbers. */
1034    if (xf86ReadBIOS(vga256InfoRec.BIOSbase, 0x00, (unsigned char *)bios_data,
1035 		     bios_data_size) != bios_data_size)
1036       return FALSE;
1037 
1038    ErrorF( "ATI BIOS Information Block:\n" );
1039    ErrorF( "   Signature code:                %c%c = ",
1040 	   bios_data[ 0x40 ], bios_data[ 0x41 ] );
1041    if (bios_data[ 0x40 ] != '3') ErrorF( "Unknown\n" );
1042    else switch( bios_data[ 0x41 ] ) {
1043    case '1':
1044       ErrorF( "VGA WONDER\n" );
1045       break;
1046    case '2':
1047       ErrorF( "EGA WONDER800+\n" );
1048       break;
1049    case '3':
1050       ErrorF( "VGA BASIC-16\n" );
1051       break;
1052    default:
1053       ErrorF( "Unknown\n" );
1054       break;
1055    }
1056    ErrorF( "   Chip version:                  %c =  ",
1057 	   bios_data[ 0x43 ] );
1058    switch (bios_data[ 0x43 ] ) {
1059    case '1':
1060       ErrorF( "ATI 18800\n" );
1061       break;
1062    case '2':
1063       ErrorF( "ATI 18800-1\n" );
1064       break;
1065    case '3':
1066       ErrorF( "ATI 28800-2\n" );
1067       break;
1068    case '4': case '5':
1069       ErrorF( "ATI 28800-%c\n", bios_data[ 0x43 ] );
1070       break;
1071    case 'a':
1072       ErrorF( "Mach-32\n" );
1073       break;
1074    default:
1075       ErrorF( "Unknown\n" );
1076       break;
1077    }
1078    ErrorF( "   BIOS version:                  %d.%d\n",
1079 	   bios_data[ 0x4c ], bios_data[ 0x4d ] );
1080 
1081 
1082 #if DEBUG_PROBE
1083    ErrorF( "\n" );
1084 #endif
1085 
1086    ErrorF( "   Byte at offset 0x42 =          0x%02x\n",
1087 	   bios_data[ 0x42 ] );
1088 
1089 #if DEBUG_PROBE
1090    ErrorF( "   8 and 16 bit ROM supported:    %s\n",
1091 	   bios_data[ 0x42 ] & 0x01 ? "Yes" : "No" );
1092    ErrorF( "   Mouse chip present:            %s\n",
1093 	   bios_data[ 0x42 ] & 0x02 ? "Yes" : "No" );
1094    ErrorF( "   Inport compatible mouse port : %s\n",
1095 	   bios_data[ 0x42 ] & 0x04 ? "Yes" : "No" );
1096    ErrorF( "   Micro Channel supported:       %s\n",
1097 	   bios_data[ 0x42 ] & 0x08 ? "Yes" : "No" );
1098    ErrorF( "   Clock chip present:            %s\n",
1099 	   bios_data[ 0x42 ] & 0x10 ? "Yes" : "No" );
1100    ErrorF( "   Uses c000:0 to d000:ffff:      %s\n",
1101 	   bios_data[ 0x42 ] & 0x80 ? "Yes" : "No" );
1102    ErrorF( "\n" );
1103 #endif
1104 
1105    ErrorF( "   Byte at offset 0x44 =          0x%02x\n",
1106 	  bios_data[ 0x44 ] );
1107 
1108 #if DEBUG_PROBE
1109    ErrorF( "   Supports 70Hz non-interlaced:  %s\n",
1110 	   bios_data[ 0x44 ] & 0x01 ? "No" : "Yes" );
1111    ErrorF( "   Supports Korean characters:    %s\n",
1112 	   bios_data[ 0x44 ] & 0x02 ? "Yes" : "No" );
1113    ErrorF( "   Uses 45Mhz memory clock:       %s\n",
1114 	   bios_data[ 0x44 ] & 0x04 ? "Yes" : "No" );
1115    ErrorF( "   Supports zero wait states:     %s\n",
1116 	   bios_data[ 0x44 ] & 0x08 ? "Yes" : "No" );
1117    ErrorF( "   Uses paged ROMS:               %s\n",
1118 	   bios_data[ 0x44 ] & 0x10 ? "Yes" : "No" );
1119    ErrorF( "   8514/A hardware on board:      %s\n",
1120 	   bios_data[ 0x44 ] & 0x40 ? "No" : "Yes" );
1121    ErrorF( "   32K color DAC on board:        %s\n",
1122 	   bios_data[ 0x44 ] & 0x80 ? "Yes" : "No" );
1123 #endif
1124 
1125    ATIExtReg = *((short int *)bios_data + 0x08);
1126    ports[0] = ATIExtReg;
1127    ports[1] = ATIExtReg+1;
1128    xf86AddIOPorts(vga256InfoRec.scrnIndex, 2, ports);
1129 
1130    ATIChipVersion = bios_data[ 0x43 ];
1131 
1132    switch( bios_data[ 0x43 ] ) {
1133    case '1':
1134       ATIBoard = ATI_BOARD_V3;
1135       break;
1136    case '2':
1137       if (bios_data[ 0x42 ] & 0x10) ATIBoard = ATI_BOARD_V5;
1138       else ATIBoard = ATI_BOARD_V4;
1139       break;
1140    case '3':
1141    case '4':
1142       ATIBoard = ATI_BOARD_PLUS;
1143       break;
1144    case '5':
1145    case 'a':			/* Graphics Ultra Plus */
1146    default:
1147       if (bios_data[ 0x44 ] & 0x80) ATIBoard = ATI_BOARD_XL;
1148       else ATIBoard = ATI_BOARD_PLUS;
1149    }
1150 
1151    ErrorF( "\n  This video adapter is a:        " );
1152    switch (ATIBoard) {
1153    case ATI_BOARD_V3:   ErrorF( "VGA WONDER V3\n" ); break;
1154    case ATI_BOARD_V4:   ErrorF( "VGA WONDER V4\n" ); break;
1155    case ATI_BOARD_V5:   ErrorF( "VGA WONDER V5\n" ); break;
1156    case ATI_BOARD_PLUS: ErrorF( "VGA WONDER PLUS (V6)\n" ); break;
1157    case ATI_BOARD_XL:   ErrorF( "VGA WONDER XL (V7)\n" ); break;
1158    default:             ErrorF( "Unknown\n" ); break;
1159    }
1160 
1161    ATIEnterLeave( ENTER );
1162 
1163    if (!vga256InfoRec.videoRam) {
1164       if (bios_data[ 0x43 ] <= '2') {
1165 	 outb( ATIExtReg, 0xbb );
1166 	 vga256InfoRec.videoRam = (inb( ATIExtReg + 1 ) & 0x20) ? 512 : 256;
1167       } else {
1168 	 outb( ATIExtReg, 0xb0 );
1169 	 switch (inb( ATIExtReg + 1 ) & 0x18) {
1170 	 case 0x00:
1171 	    vga256InfoRec.videoRam = 256;
1172 	    break;
1173 	 case 0x10:
1174 	    vga256InfoRec.videoRam = 512;
1175 	    break;
1176 	 case 0x08:
1177 	    vga256InfoRec.videoRam = 1024;
1178 	    break;
1179 	 }
1180       }
1181    }
1182 
1183    ErrorF( "  Amount of RAM on video adapter: %dk\n",
1184 	   vga256InfoRec.videoRam );
1185    if (bios_data[ 0x43 ] < '4') {
1186       ErrorF( "  WARNING: Driver may not work correctly with your board!\n" );
1187    }
1188    ErrorF( "\n" );
1189 
1190 #if DEBUG_PROBE
1191    ErrorF( "\nThe extended registers (ATIExtREG) are at 0x%x\n", ATIExtReg );
1192    ErrorF( "The x386 ATI driver will set ATIBoard =   %d\n", ATIBoard );
1193 #endif
1194 
1195    if (vga256InfoRec.videoRam < 512) {
1196       ErrorF( "ATI driver requires at least 512k video RAM!\n" );
1197       ATIEnterLeave( LEAVE );
1198       return FALSE;
1199    }
1200 
1201    if (!vga256InfoRec.clocks) {
1202       ErrorF( "ATI driver requires \"clocks\" to be set in Xconfig!\n" );
1203       ErrorF( "Clocks 18 22 25 28 36 44 50 56\n" );
1204       ErrorF( "       30 32 37 39 40  0 75 65\n" );
1205       ATIEnterLeave( LEAVE );
1206       return FALSE;
1207    }
1208 
1209    vga256InfoRec.bankedMono = FALSE;
1210    return TRUE;
1211 }
1212 
1213 /*
1214  * ATIEnterLeave()
1215  *
1216  * This routine is used when entering or leaving X (i.e., when starting or
1217  * exiting an X session, or when switching to or from a vt which does not
1218  * have an X session running.
1219  *
1220  * Assumptions:
1221  *   ATIProbe() has been called first, so that ATIExtReg is valid.
1222  *
1223  * Written by:
1224  * Rik Faith (faith@cs.unc.edu), Sun Aug  9 13:50:33 1992
1225  *
1226  */
1227 
1228 static void
ATIEnterLeave(enter)1229 ATIEnterLeave( enter )
1230    Bool enter;
1231 {
1232   unsigned char temp;
1233 
1234   TRACE(("ATIEnterLeave(%d)\n",enter));
1235 
1236   if (enter)
1237     {
1238       xf86EnableIOPorts(vga256InfoRec.scrnIndex);
1239       vgaIOBase = (inb(0x3CC) & 0x01) ? 0x3D0 : 0x3B0;
1240     }
1241   else
1242     {
1243       xf86DisableIOPorts(vga256InfoRec.scrnIndex);
1244     }
1245 }
1246 
1247