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