1 /*
2  * Copyright 1993 Hans Oey <hans@mo.hobby.nl>
3  *
4  * Permission to use, copy, modify, distribute, and sell this software and its
5  * documentation for any purpose is hereby granted without fee, provided that
6  * the above copyright notice appear in all copies and that both that
7  * copyright notice and this permission notice appear in supporting
8  * documentation, and that the name of Hans Oey not be used in
9  * advertising or publicity pertaining to distribution of the software without
10  * specific, written prior permission.  Hans Oey makes no representations
11  * about the suitability of this software for any purpose.  It is provided
12  * "as is" without express or implied warranty.
13  *
14  * HANS OEY DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
15  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
16  * EVENT SHALL HANS OEY BE LIABLE FOR ANY SPECIAL, INDIRECT OR
17  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
18  * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
19  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
20  * PERFORMANCE OF THIS SOFTWARE.
21  *
22  */
23 
24 /* $XFree86: mit/server/ddx/x386/vga256/drivers/compaq/cpq_driver.c,v 2.10 1993/10/06 14:56:03 dawes Exp $ */
25 
26 /*
27   This XFree86 driver is intended to blow up your screen
28   and crash your disks. Other damage to your system
29   may occur. If the software fails this purpose it will
30   try to make random changes to program and data files.
31   It is provided "as is" without express or implied warranty
32   by Hans Oey. On my Compaq LTE Lite/25c it failed completely
33   and only gave me a boring X screen.
34 
35   The software was based on the other XFree86 drivers. I am
36   very gratefull to Thomas Roell and the XFree86 team, but
37   stacking up all copyright notices for the next twenty
38   years seems a waste of disk space.
39 */
40 
41 #include "X.h"
42 #include "input.h"
43 #include "screenint.h"
44 
45 #include "compiler.h"
46 
47 #include "x386.h"
48 #include "x386Priv.h"
49 #include "xf86_OSlib.h"
50 #include "xf86_HWlib.h"
51 #include "vga.h"
52 
53 typedef struct {
54 	vgaHWRec std;               /* good old IBM VGA */
55 	unsigned char PageRegister0;
56 	unsigned char PageRegister1;
57 	unsigned char ControlRegister0;
58 	unsigned char EnvironmentReg;
59 } vgaCOMPAQRec, *vgaCOMPAQPtr;
60 
61 
62 static Bool     COMPAQProbe();
63 static char *   COMPAQIdent();
64 static Bool     COMPAQClockSelect();
65 static void     COMPAQEnterLeave();
66 static Bool     COMPAQInit();
67 static void *   COMPAQSave();
68 static void     COMPAQRestore();
69 static void     COMPAQAdjust();
70 static void     COMPAQSaveScreen();
71 extern void     COMPAQSetRead();
72 extern void     COMPAQSetWrite();
73 extern void     COMPAQSetReadWrite();
74 
75 vgaVideoChipRec COMPAQ = {
76 	COMPAQProbe,
77 	COMPAQIdent,
78 	COMPAQEnterLeave,
79 	COMPAQInit,
80 	COMPAQSave,
81 	COMPAQRestore,
82 	COMPAQAdjust,
83 	COMPAQSaveScreen,
84 	NoopDDA,
85 	NoopDDA,
86 	COMPAQSetRead,
87 	COMPAQSetWrite,
88 	COMPAQSetReadWrite,
89 	0x10000,
90 	0x08000,
91 	15,
92 	0x7FFF,
93 	0x00000, 0x08000,
94 	0x08000, 0x10000,
95 	TRUE,                                 /* Uses 2 banks */
96 	VGA_NO_DIVIDE_VERT,
97 	{0,},
98 	8,
99 };
100 
101 #define new ((vgaCOMPAQPtr)vgaNewVideoState)
102 
COMPAQIdent(n)103 char *COMPAQIdent(n)
104 int n;
105 {
106 	static char *chipsets[] = {"cpq_avga"};
107 
108 	if (n + 1 > sizeof(chipsets) / sizeof(char *))
109 		return NULL;
110 	else
111 		return chipsets[n];
112 }
113 
114 
115 /*
116    COMPAQClockSelect --  select one of the possible clocks ...
117 */
118 static Bool
COMPAQClockSelect(no)119 COMPAQClockSelect(no)
120 int no;
121 {
122 	static unsigned char save1;
123 	unsigned char temp;
124 
125 	switch(no) {
126 	case CLK_REG_SAVE:
127 		save1 = inb(0x3CC);
128 		break;
129 	case CLK_REG_RESTORE:
130 		outb(0x3C2, save1);
131 		break;
132 	default:
133 		temp = inb(0x3CC);
134 		outb(0x3C2, (temp & 0xf3) | ((no << 2) & 0x0C));
135 		break;
136 	}
137 	return(TRUE);
138 }
139 
140 
141 /*
142    COMPAQProbe() checks for a Compaq VGC
143    Returns TRUE or FALSE on exit.
144 
145    Makes sure the following are set in vga256InfoRec:
146      chipset
147      videoRam
148      clocks
149 */
150 #define VGABIOS_START vga256InfoRec.BIOSbase
151 #define SIGNATURE_LENGTH 6
152 #define ATI_SIGNATURE_LENGTH 9
153 #define BUFSIZE ATI_SIGNATURE_LENGTH	/* but at least 3 bytes */
154 
155 static Bool
COMPAQProbe()156 COMPAQProbe()
157 {
158 	unsigned char SetReset;        /* Set/Reset Data */
159         unsigned char Rotate;
160         unsigned char EnvironmentReg;
161         unsigned char BLTConf;
162         unsigned char temp;
163 
164 	/*
165 	 * Set up I/O ports to be used by this card
166 	 */
167 	xf86ClearIOPortList(vga256InfoRec.scrnIndex);
168 	xf86AddIOPorts(vga256InfoRec.scrnIndex, Num_VGA_IOPorts, VGA_IOPorts);
169 
170 	if (vga256InfoRec.chipset) {
171 		if (StrCaseCmp(vga256InfoRec.chipset, COMPAQIdent(0)))
172 			return(FALSE);
173 		COMPAQEnterLeave(ENTER);
174 	}
175 	else {
176 		char buf[BUFSIZE];
177 		char *signature = "COMPAQ";
178 		char *ati_signature = "761295520";
179 
180     		/* check for COMPAQ VGC */
181 		if (xf86ReadBIOS(VGABIOS_START, 0, (unsigned char *)buf,
182 				 BUFSIZE) != BUFSIZE)
183 			return(FALSE);
184 		if ((buf[0] != (char)0x55) || (buf[1] != (char)0xAA))
185 			return(FALSE);
186 		if (xf86ReadBIOS(VGABIOS_START, (buf[2] * 512) - 0x16,
187 				 (unsigned char *)buf,
188 				 SIGNATURE_LENGTH) != SIGNATURE_LENGTH)
189 			return(FALSE);
190 		if (strncmp(signature, buf, SIGNATURE_LENGTH))
191 			return FALSE;
192 
193 		/*
194 		 * Now make sure it isn't an ATI card with a COMPAQ signature
195 		 * in the BIOS
196 		 */
197 
198 		if (xf86ReadBIOS(VGABIOS_START, 0x31, (unsigned char *)buf,
199 				 ATI_SIGNATURE_LENGTH) != ATI_SIGNATURE_LENGTH)
200 			return(FALSE);
201 		if (!strncmp(ati_signature, buf, ATI_SIGNATURE_LENGTH))
202 			return(FALSE);
203 
204     		COMPAQEnterLeave(ENTER);
205 
206 		/* at least it is some COMPAQ :-) */
207 		/* check for seperate SR and BLTConf registers. */
208 		outb(0x3ce, 0x00); SetReset = inb(0x3cf);
209 		outb(0x3ce, 0x03); Rotate = inb(0x3cf);
210 		outb(0x3ce, 0x0f); EnvironmentReg = inb(0x3cf);
211 		outb(0x3cf, 0x05); /* unlock */
212 		outb(0x3ce, 0x10); BLTConf = inb(0x3cf);
213 
214 		if ((BLTConf & 0x0f) == SetReset) {
215 			/* try another pattern */
216 			temp = ~SetReset & 0xff;
217 			outw(0x3ce, temp << 8 | 0x00);	/*change Set/Rst Data*/
218 			outb(0x3ce, 0x10);		/*read BLTConf reg   */
219 			if ((inb(0x3cf) & 0x0f) == temp) {
220 				/* restore changed registers */
221 				outw(0x3ce, SetReset << 8 | 0x00);
222 				outw(0x3ce, EnvironmentReg << 8 | 0x0f);
223 				COMPAQEnterLeave(LEAVE);
224 				return FALSE;
225 			}
226 			/* restore */
227 			outw(0x3ce, SetReset << 8 | 0x00);
228 		}
229 		outw(0x3ce, EnvironmentReg << 8 | 0x0f);
230 	}
231 
232 	/* Detect how much memory is installed, that's easy :-) */
233 	if (!vga256InfoRec.videoRam)
234 		vga256InfoRec.videoRam = 512;
235 
236 	if (!vga256InfoRec.clocks)
237 		vgaGetClocks(4, COMPAQClockSelect);  /* 4? clocks available */
238 
239 	vga256InfoRec.chipset = COMPAQIdent(0);
240 	vga256InfoRec.bankedMono = FALSE;     /* who cares ;-) */
241 
242 	return TRUE;
243 }
244 
245 /*
246    COMPAQEnterLeave() -- enable/disable io-mapping
247 
248    This routine is used when entering or leaving X (i.e., when starting or
249    exiting an X session, or when switching to or from a vt which does not
250    have an X session running.
251 */
COMPAQEnterLeave(enter)252 static void COMPAQEnterLeave(enter)
253 Bool enter;
254 {
255 	if (enter) {
256 		xf86EnableIOPorts(vga256InfoRec.scrnIndex);
257 		vgaIOBase = (inb(0x3CC) & 0x01) ? 0x3D0 : 0x3B0;
258 	}
259 	else {
260 		xf86DisableIOPorts(vga256InfoRec.scrnIndex);
261 	}
262 }
263 
264 /*
265    COMPAQRestore -- restore a video mode
266 */
267 
COMPAQRestore(restore)268 static void COMPAQRestore(restore)
269 vgaCOMPAQPtr restore;
270 {
271 	if (restore->EnvironmentReg == 0x0f)
272 		outw(0x3ce, 0 << 8 | 0x0f);		/* lock */
273 	else
274 		outw(0x3ce, 0x05 << 8 | 0x0f);		/* unlock */
275 
276 	vgaHWRestore(restore);
277 
278 	/* Compaq doesn't like the sequencer reset in vgaHWRestore */
279 	outw(0x3ce, restore->ControlRegister0 << 8 | 0x40);
280 	outw(0x3ce, restore->PageRegister0 << 8 | 0x45);
281 	outw(0x3ce, restore->PageRegister1 << 8 | 0x46);
282 
283 	/*
284 	 * Don't need to do any clock stuff - the bits are in MiscOutReg,
285 	 * which is handled by vgaHWRestore.
286 	 */
287 }
288 
289 /*
290   COMPAQSave -- save the current video mode
291 */
COMPAQSave(save)292 static void *COMPAQSave(save)
293 vgaCOMPAQPtr save;
294 {
295 	unsigned char temp0, temp1, temp2, temp3;
296 
297 	outb(0x3ce, 0x0f); temp0 = inb(0x3cf);       /* Environment Register */
298 	outb(0x3ce, 0x40); temp1 = inb(0x3cf);       /* Control Register 0 */
299 	outb(0x3ce, 0x45); temp2 = inb(0x3cf);       /* Page Register 0 */
300 	outb(0x3ce, 0x46); temp3 = inb(0x3cf);       /* Page Register 1 */
301 
302 	save = (vgaCOMPAQPtr)vgaHWSave(save, sizeof(vgaCOMPAQRec));
303 
304 	save->EnvironmentReg = temp0;
305 	save->ControlRegister0 = temp1;
306 	save->PageRegister0 = temp2;
307 	save->PageRegister1 = temp3;
308 
309 	return ((void *) save);
310 }
311 
312 /*
313   COMPAQInit -- Handle the initialization of the VGAs registers
314 */
COMPAQInit(mode)315 static Bool COMPAQInit(mode)
316 DisplayModePtr mode;
317 {
318 #ifndef MONOVGA
319 	/* Double horizontal timings. */
320 	mode->HTotal <<= 1;
321 	mode->HDisplay <<= 1;
322 	mode->HSyncStart <<= 1;
323 	mode->HSyncEnd <<= 1;
324 #endif
325 
326 	if (!vgaHWInit(mode,sizeof(vgaCOMPAQRec)))
327 		return(FALSE);
328 #ifndef MONOVGA
329 	/* Restore them, they are used elsewhere */
330 	mode->HTotal >>= 1;
331 	mode->HDisplay >>= 1;
332 	mode->HSyncStart >>= 1;
333 	mode->HSyncEnd >>= 1;
334 #endif
335 
336 #ifndef MONOVGA
337 	new->std.Sequencer[0x02] = 0xff; /* write plane mask for 256 colors */
338 	new->std.CRTC[0x13] = vga256InfoRec.virtualX >> 3;
339 	new->std.CRTC[0x14] = 0x40;
340 #endif
341 
342 #ifdef MONOVGA
343 	new->ControlRegister0 = 0x00;
344 #else
345 	new->ControlRegister0 = 0x01;
346 #endif
347 
348 	new->EnvironmentReg = 0x05;
349 	new->PageRegister0 = 0x0;
350 	new->PageRegister1 = 0x0;
351 
352 	return(TRUE);
353 }
354 
355 /*
356  * COMPAQAdjust --
357  *      adjust the current video frame to display the mousecursor
358  */
359 
360 static void
COMPAQAdjust(x,y)361 COMPAQAdjust(x, y)
362      int x, y;
363 {
364 #ifdef MONOVGA
365 	int Base = (y * vga256InfoRec.virtualX + x + 3) >> 3;
366 #else
367 	int Base = (y * vga256InfoRec.virtualX + x + 1) >> 2;
368 #endif
369 
370 	outw(vgaIOBase + 4, (Base & 0x00FF00) | 0x0C);
371 	outw(vgaIOBase + 4, ((Base & 0x00FF) << 8) | 0x0D);
372 }
373 
374 /*
375  * COMPAQSaveScreen --
376  *	Save registers that can be disrupted by a synchronous reset
377  */
378 static void
COMPAQSaveScreen(mode)379 COMPAQSaveScreen(mode)
380 int mode;
381 {
382 	static unsigned char save1, save2, save3;
383 
384 	if (mode == SS_START)
385 	{
386 		outb(0x3ce, 0x45); save1 = inb(0x3cf);  /* Page Register 0 */
387 		outb(0x3ce, 0x46); save2 = inb(0x3cf);  /* Page Register 1 */
388 		outb(0x3ce, 0x40); save3 = inb(0x3cf);  /* Control Register 0 */
389 	}
390 	else
391 	{
392 		outw(0x3ce, save3 << 8 | 0x40);
393 		outw(0x3ce, save2 << 8 | 0x46);
394 		outw(0x3ce, save1 << 8 | 0x45);
395 	}
396 }
397