1 /*
2 * $XFree86: mit/server/ddx/x386/vga256/drivers/et3000/driver.c,v 2.10 1993/09/22 15:47:12 dawes Exp $
3 *
4 * Copyright 1990,91 by Thomas Roell, Dinkelscherben, Germany.
5 *
6 * Permission to use, copy, modify, distribute, and sell this software and its
7 * documentation for any purpose is hereby granted without fee, provided that
8 * the above copyright notice appear in all copies and that both that
9 * copyright notice and this permission notice appear in supporting
10 * documentation, and that the name of Thomas Roell not be used in
11 * advertising or publicity pertaining to distribution of the software without
12 * specific, written prior permission. Thomas Roell makes no representations
13 * about the suitability of this software for any purpose. It is provided
14 * "as is" without express or implied warranty.
15 *
16 * THOMAS ROELL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
17 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
18 * EVENT SHALL THOMAS ROELL BE LIABLE FOR ANY SPECIAL, INDIRECT OR
19 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
20 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
21 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
22 * PERFORMANCE OF THIS SOFTWARE.
23 *
24 * Author: Thomas Roell, roell@informatik.tu-muenchen.de
25 *
26 * $Header: /proj/X11/mit/server/ddx/x386/drivers/et3000/RCS/driver.c,v 1.2 1991/06/27 00:03:27 root Exp $
27 */
28
29
30 #include "X.h"
31 #include "input.h"
32 #include "screenint.h"
33
34 #include "compiler.h"
35
36 #include "x386.h"
37 #include "x386Priv.h"
38 #include "xf86_OSlib.h"
39 #include "xf86_HWlib.h"
40 #include "vga.h"
41
42 typedef struct {
43 vgaHWRec std; /* good old IBM VGA */
44 unsigned char ExtStart; /* Tseng ET3000 specials CRTC 0x23/0x24/0x25 */
45 unsigned char CRTCControl;
46 unsigned char Overflow;
47 unsigned char ZoomControl; /* TS 6 & 7 */
48 unsigned char AuxillaryMode;
49 unsigned char Misc; /* ATC 0x16 */
50 unsigned char SegSel;
51 } vgaET3000Rec, *vgaET3000Ptr;
52
53
54 static Bool ET3000Probe();
55 static char * ET3000Ident();
56 static Bool ET3000ClockSelect();
57 static void ET3000EnterLeave();
58 static Bool ET3000Init();
59 static void * ET3000Save();
60 static void ET3000Restore();
61 static void ET3000Adjust();
62 extern void ET3000SetRead();
63 extern void ET3000SetWrite();
64 extern void ET3000SetReadWrite();
65
66 vgaVideoChipRec ET3000 = {
67 ET3000Probe,
68 ET3000Ident,
69 ET3000EnterLeave,
70 ET3000Init,
71 ET3000Save,
72 ET3000Restore,
73 ET3000Adjust,
74 NoopDDA,
75 NoopDDA,
76 NoopDDA,
77 ET3000SetRead,
78 ET3000SetWrite,
79 ET3000SetReadWrite,
80 0x10000,
81 0x10000,
82 16,
83 0xFFFF,
84 0x00000, 0x10000,
85 0x00000, 0x10000,
86 TRUE, /* Uses 2 banks */
87 VGA_DIVIDE_VERT,
88 {0,},
89 16,
90 };
91
92 #define new ((vgaET3000Ptr)vgaNewVideoState)
93
94 static unsigned ET3000_ExtPorts[] = {0x3B8, 0x3BF, 0x3CD, 0x3D8};
95 static int Num_ET3000_ExtPorts =
96 (sizeof(ET3000_ExtPorts)/sizeof(ET3000_ExtPorts[0]));
97
98 /*
99 * ET3000ClockSelect --
100 * select one of the possible clocks ...
101 */
102
103 static Bool
ET3000ClockSelect(no)104 ET3000ClockSelect(no)
105 int no;
106 {
107 static unsigned char save1, save2;
108 unsigned char temp;
109
110 switch(no)
111 {
112 case CLK_REG_SAVE:
113 save1 = inb(0x3CC);
114 outb(vgaIOBase + 4, 0x24); save2 = inb(vgaIOBase + 5);
115 break;
116 case CLK_REG_RESTORE:
117 outb(0x3C2, save1);
118 outw(vgaIOBase + 4, 0x24 | (save2 << 8));
119 break;
120 default:
121 temp = inb(0x3CC);
122 outb(0x3C2, ( temp & 0xf3) | ((no << 2) & 0x0C));
123 outw(vgaIOBase+0x04, 0x24 | ((no & 0x04) << 7));
124 }
125 return(TRUE);
126 }
127
128
129 /*
130 * ET3000Ident --
131 */
132
133 static char *
ET3000Ident(n)134 ET3000Ident(n)
135 int n;
136 {
137 static char *chipsets[] = {"et3000"};
138
139 if (n + 1 > sizeof(chipsets) / sizeof(char *))
140 return(NULL);
141 else
142 return(chipsets[n]);
143 }
144
145
146 /*
147 * ET3000Probe --
148 * check up whether a Et3000 based board is installed
149 */
150
151 static Bool
ET3000Probe()152 ET3000Probe()
153 {
154 /*
155 * Set up I/O ports to be used by this card
156 */
157 xf86ClearIOPortList(vga256InfoRec.scrnIndex);
158 xf86AddIOPorts(vga256InfoRec.scrnIndex, Num_VGA_IOPorts, VGA_IOPorts);
159 xf86AddIOPorts(vga256InfoRec.scrnIndex, Num_ET3000_ExtPorts, ET3000_ExtPorts);
160
161 if (vga256InfoRec.chipset)
162 {
163 if (StrCaseCmp(vga256InfoRec.chipset, ET3000Ident(0)))
164 return (FALSE);
165 else
166 ET3000EnterLeave(ENTER);
167 }
168 else
169 {
170 unsigned char temp, origVal, newVal;
171
172 ET3000EnterLeave(ENTER);
173 origVal = inb(0x3CD);
174 outb(0x3CD, origVal ^ 0x3F);
175 newVal = inb(0x3CD);
176 outb(0x3CD, origVal);
177 if (newVal != (origVal ^ 0x3F))
178 {
179 ET3000EnterLeave(LEAVE);
180 return(FALSE);
181 }
182 /*
183 * At this stage, we think it's a Tseng, now make sure it's
184 * an ET3000.
185 */
186 temp = inb(vgaIOBase+0x0A);
187 outb(vgaIOBase+0x04, 0x1B);
188 origVal = inb(vgaIOBase+0x05);
189 outb(vgaIOBase+0x05, origVal ^ 0xFF);
190 newVal = inb(vgaIOBase+0x05);
191 outb(vgaIOBase+0x05, origVal);
192 if (newVal != (origVal ^ 0xFF))
193 {
194 ET3000EnterLeave(LEAVE);
195 return(FALSE);
196 }
197 }
198
199 if (!vga256InfoRec.videoRam) vga256InfoRec.videoRam = 512;
200 if (!vga256InfoRec.clocks) vgaGetClocks(8 , ET3000ClockSelect);
201
202 vga256InfoRec.chipset = ET3000Ident(0);
203 vga256InfoRec.bankedMono = TRUE;
204 return(TRUE);
205 }
206
207
208
209 /*
210 * ET3000EnterLeave --
211 * enable/disable io-mapping
212 */
213
214 static void
ET3000EnterLeave(enter)215 ET3000EnterLeave(enter)
216 Bool enter;
217 {
218 unsigned char temp;
219
220 if (enter)
221 {
222 xf86EnableIOPorts(vga256InfoRec.scrnIndex);
223
224 vgaIOBase = (inb(0x3CC) & 0x01) ? 0x3D0 : 0x3B0;
225 outb(0x3BF, 0x03); /* unlock ET3000 special */
226 outb(vgaIOBase + 8, 0xA0);
227 outb(vgaIOBase + 4, 0x11); temp = inb(vgaIOBase + 5);
228 outb(vgaIOBase + 5, temp & 0x7F);
229 }
230 else
231 {
232 outb(0x3BF, 0x01); /* relock ET3000 special */
233 outb(vgaIOBase + 8, 0xA0);
234
235 xf86DisableIOPorts(vga256InfoRec.scrnIndex);
236 }
237 }
238
239
240
241 /*
242 * ET3000Restore --
243 * restore a video mode
244 */
245
246 static void
ET3000Restore(restore)247 ET3000Restore(restore)
248 vgaET3000Ptr restore;
249 {
250 unsigned char i;
251
252 outb(0x3CD, restore->SegSel);
253
254 outw(0x3C4, (restore->ZoomControl << 8) | 0x06);
255 outw(0x3C4, (restore->AuxillaryMode << 8) | 0x07);
256 i = inb(vgaIOBase + 0x0A); /* reset flip-flop */
257 outb(0x3C0, 0x36); outb(0x3C0, restore->Misc);
258 outw(vgaIOBase + 4, (restore->ExtStart << 8) | 0x23);
259 if (restore->std.NoClock >= 0)
260 outw(vgaIOBase + 4, (restore->CRTCControl << 8) | 0x24);
261 outw(vgaIOBase + 4, (restore->Overflow << 8) | 0x25);
262
263 vgaHWRestore(restore);
264 }
265
266
267
268 /*
269 * ET3000Save --
270 * save the current video mode
271 */
272
273 static void *
ET3000Save(save)274 ET3000Save(save)
275 vgaET3000Ptr save;
276 {
277 unsigned char i;
278 unsigned char temp1, temp2;
279
280 /*
281 * we need this here , cause we MUST disable the ROM SYNC feature
282 */
283 vgaIOBase = (inb(0x3CC) & 0x01) ? 0x3D0 : 0x3B0;
284 outb(vgaIOBase + 4, 0x24); temp1 = inb(vgaIOBase + 5);
285 outb(vgaIOBase + 5, temp1 & 0x0f);
286 temp2 = inb(0x3CD);
287
288 outb(0x3CD,0x40); /* segment select */
289
290 save = (vgaET3000Ptr)vgaHWSave(save, sizeof(vgaET3000Rec));
291 save->CRTCControl = temp1;
292 save->SegSel = temp2;
293
294 outb(vgaIOBase + 4, 0x23); save->ExtStart = inb(vgaIOBase + 5);
295 outb(vgaIOBase + 4, 0x25); save->Overflow = inb(vgaIOBase + 5);
296 outb(0x3C4, 6); save->ZoomControl = inb(0x3C5);
297 outb(0x3C4, 7); save->AuxillaryMode = inb(0x3C5);
298 i = inb(vgaIOBase + 0x0A); /* reset flip-flop */
299 outb(0x3C0, 0x36); save->Misc = inb(0x3C1); outb(0x3C0, save->Misc);
300
301 return ((void *) save);
302 }
303
304
305
306 /*
307 * ET3000Init --
308 * Handle the initialization, etc. of a screen.
309 */
310
311 static Bool
ET3000Init(mode)312 ET3000Init(mode)
313 DisplayModePtr mode;
314 {
315 #ifdef MONOVGA
316 Bool first_time = (!new);
317 int i;
318 #endif
319
320 #ifdef MONOVGA
321 /* weird mode, halve the horizontal timings */
322 mode->HTotal /= 2;
323 mode->HDisplay /= 2;
324 mode->HSyncStart /= 2;
325 mode->HSyncEnd /= 2;
326 #endif
327 if (!vgaHWInit(mode,sizeof(vgaET3000Rec)))
328 return(FALSE);
329 #ifdef MONOVGA
330 /* restore... */
331 mode->HTotal *= 2;
332 mode->HDisplay *= 2;
333 mode->HSyncStart *= 2;
334 mode->HSyncEnd *= 2;
335 #endif
336
337 #ifndef MONOVGA
338 new->std.Sequencer[4] = 0x06; /* use the FAST 256 Color Mode */
339 #endif
340 new->ZoomControl = 0x00;
341 new->Misc = 0x10;
342 new->ExtStart = 0x00;
343 if (new->std.NoClock >= 0)
344 new->CRTCControl = (int)(new->std.NoClock & 0x04) >> 1 ;
345 new->Overflow = 0x10
346 | ((mode->VSyncStart & 0x400) >> 7 )
347 | (((mode->VDisplay -1) & 0x400) >> 8 )
348 | (((mode->VTotal -2) & 0x400) >> 9 )
349 | ((mode->VSyncStart & 0x400) >> 10 )
350 | (mode->Flags & V_INTERLACE ? 0x80 : 0);
351
352 #ifdef MONOVGA
353 new->AuxillaryMode = 0xc8; /* MCLK / 2, devil knows what's that */
354 new->std.CRTC[5] |= 0x60; /* Hsync skew */
355 new->std.CRTC[19] = vga256InfoRec.virtualX >> 5;
356 /* This weird mode uses the DAC in an unusual way */
357 if (first_time)
358 {
359 for (i = 0; i < 768; i+=3)
360 if ((i/3) & (1 << BIT_PLANE))
361 {
362 new->std.DAC[i] = vga256InfoRec.whiteColour.red;
363 new->std.DAC[i + 1] = vga256InfoRec.whiteColour.green;
364 new->std.DAC[i + 2] = vga256InfoRec.whiteColour.blue;
365 }
366 else
367 {
368 new->std.DAC[i] = vga256InfoRec.blackColour.red;
369 new->std.DAC[i + 1] = vga256InfoRec.blackColour.green;
370 new->std.DAC[i + 2] = vga256InfoRec.blackColour.blue;
371 }
372 }
373 new->std.Attribute[17] = 0x00;
374
375 #else /* !MONOVGA */
376 new->AuxillaryMode = 0x88;
377 #endif
378 return(TRUE);
379 }
380
381
382 /*
383 * ET3000Adjust --
384 * adjust the current video frame to display the mousecursor
385 */
386
387 static void
ET3000Adjust(x,y)388 ET3000Adjust(x, y)
389 int x, y;
390 {
391 #ifdef USE_PAN
392 #ifdef MONOVGA
393 int Base = (y * vga256InfoRec.virtualX + x + 3) >> 4;
394 int wants_pan = (y * vga256InfoRec.virtualX + x + 3) & 8;
395 #else
396 int Base = (y * vga256InfoRec.virtualX + x + 1) >> 3;
397 int wants_pan = (y * vga256InfoRec.virtualX + x + 1) & 4;
398 #endif
399 #else
400 #ifdef MONOVGA
401 int Base = (y * vga256InfoRec.virtualX + x + 7) >> 4;
402 #else
403 int Base = (y * vga256InfoRec.virtualX + x + 3) >> 3;
404 #endif
405 #endif
406
407 #ifdef USE_PAN
408 /* Wait for vertical retrace */
409 {
410 unsigned char tmp;
411
412 while (tmp = inb(vgaIOBase + 0x0A) & 0x80)
413 ;
414 }
415 #endif
416
417 outw(vgaIOBase + 4, (Base & 0x00FF00) | 0x0C);
418 outw(vgaIOBase + 4, ((Base & 0x00FF) << 8) | 0x0D);
419 outw(vgaIOBase + 4, ((Base & 0x010000) >> 7) | 0x23);
420
421 #ifdef USE_PAN
422 /* set horizontal panning register */
423 (void)inb(vgaIOBase + 0x0A);
424 outb(0x3C0, 0x33);
425 outb(0x3C0, wants_pan ? 3 : 0);
426 #endif
427 }
428
429
430
431