1ab47cfaaSmrg
2ab47cfaaSmrg#ifdef HAVE_CONFIG_H
3ab47cfaaSmrg#include "config.h"
4ab47cfaaSmrg#endif
5ab47cfaaSmrg
6ab47cfaaSmrg#include "savage_driver.h"
7ab47cfaaSmrg#include "savage_vbe.h"
8ab47cfaaSmrg
9ab47cfaaSmrg#define iabs(a)	((int)(a)>0?(a):(-(a)))
10ab47cfaaSmrg
11ab47cfaaSmrg#if X_BYTE_ORDER == X_LITTLE_ENDIAN
12ab47cfaaSmrg#define B_O16(x)  (x)
13ab47cfaaSmrg#define B_O32(x)  (x)
14ab47cfaaSmrg#else
15ab47cfaaSmrg#define B_O16(x)  ((((x) & 0xff) << 8) | (((x) & 0xff) >> 8))
16ab47cfaaSmrg#define B_O32(x)  ((((x) & 0xff) << 24) | (((x) & 0xff00) << 8) \
17ab47cfaaSmrg                  | (((x) & 0xff0000) >> 8) | (((x) & 0xff000000) >> 24))
18ab47cfaaSmrg#endif
19ab47cfaaSmrg#define L_ADD(x)  (B_O32(x) & 0xffff) + ((B_O32(x) >> 12) & 0xffff00)
20ab47cfaaSmrg
21ab47cfaaSmrgstatic int SavageGetDevice( SavagePtr psav );
22ab47cfaaSmrg/*static int SavageGetTVType( SavagePtr psav );*/
23ab47cfaaSmrgvoid SavageSetVESAModeCrtc1( SavagePtr psav, int n, int Refresh );
24ab47cfaaSmrgvoid SavageSetVESAModeCrtc2( SavagePtr psav, int n, int Refresh );
25ab47cfaaSmrg
26ab47cfaaSmrgstatic void
27ab47cfaaSmrgSavageClearVM86Regs( xf86Int10InfoPtr pInt )
28ab47cfaaSmrg{
29ab47cfaaSmrg    pInt->ax = 0;
30ab47cfaaSmrg    pInt->bx = 0;
31ab47cfaaSmrg    pInt->cx = 0;
32ab47cfaaSmrg    pInt->dx = 0;
33ab47cfaaSmrg    pInt->si = 0;
34ab47cfaaSmrg    pInt->di = 0;
35ab47cfaaSmrg    pInt->es = 0xc000;
36ab47cfaaSmrg    pInt->num = 0x10;
37ab47cfaaSmrg}
38ab47cfaaSmrg
39ab47cfaaSmrgvoid
40ab47cfaaSmrgSavageSetTextMode( SavagePtr psav )
41ab47cfaaSmrg{
42ab47cfaaSmrg    /* Restore display device if changed. */
43ab47cfaaSmrg    if( psav->iDevInfo != psav->iDevInfoPrim ) {
44ab47cfaaSmrg	SavageClearVM86Regs( psav->pVbe->pInt10 );
45ab47cfaaSmrg	psav->pVbe->pInt10->ax = 0x4f14;
46ab47cfaaSmrg	psav->pVbe->pInt10->bx = 0x0003;
47ab47cfaaSmrg	psav->pVbe->pInt10->cx = psav->iDevInfoPrim;
48ab47cfaaSmrg	xf86ExecX86int10( psav->pVbe->pInt10 );
49ab47cfaaSmrg    }
50ab47cfaaSmrg
51ab47cfaaSmrg    SavageClearVM86Regs( psav->pVbe->pInt10 );
52ab47cfaaSmrg
53ab47cfaaSmrg    psav->pVbe->pInt10->ax = 0x83;
54ab47cfaaSmrg
55ab47cfaaSmrg    xf86ExecX86int10( psav->pVbe->pInt10 );
56ab47cfaaSmrg}
57ab47cfaaSmrg
58ab47cfaaSmrgvoid
59ab47cfaaSmrgSavageSetVESAModeCrtc1(SavagePtr psav, int n, int refresh)
60ab47cfaaSmrg{
61ab47cfaaSmrg    unsigned char byte;
62ab47cfaaSmrg
63ab47cfaaSmrg    xf86Msg(X_INFO,"SavageSetVESAModeCrtc1:mode=0x%x,refresh=%dHZ\n",n,refresh);
64ab47cfaaSmrg
65ab47cfaaSmrg    SavageClearVM86Regs(psav->pVbe->pInt10);
66ab47cfaaSmrg
67ab47cfaaSmrg    /* set active displays. */
68ab47cfaaSmrg    psav->pVbe->pInt10->ax = S3_EXTBIOS_INFO;
69ab47cfaaSmrg    psav->pVbe->pInt10->bx = S3_SET_ACTIVE_DISP;
70ab47cfaaSmrg    if (psav->TvOn)
71ab47cfaaSmrg    	psav->pVbe->pInt10->cx = 0x87; /* lcd, tv, crt, duoview */
72ab47cfaaSmrg    else
73ab47cfaaSmrg    	psav->pVbe->pInt10->cx = 0x83; /* lcd, crt, duoview */
74ab47cfaaSmrg    xf86ExecX86int10(psav->pVbe->pInt10);
75ab47cfaaSmrg
76ab47cfaaSmrg    SavageClearVM86Regs(psav->pVbe->pInt10);
77ab47cfaaSmrg
78ab47cfaaSmrg    /* Establish the refresh rate for this mode. */
79ab47cfaaSmrg    psav->pVbe->pInt10->ax = S3_EXTBIOS_INFO;
80ab47cfaaSmrg    psav->pVbe->pInt10->bx = S3_SET_REFRESH;
81ab47cfaaSmrg    psav->pVbe->pInt10->cx = n & 0x1ff;
82ab47cfaaSmrg    psav->pVbe->pInt10->di = refresh & 0xffff;
83ab47cfaaSmrg    xf86ExecX86int10(psav->pVbe->pInt10);
84ab47cfaaSmrg
85ab47cfaaSmrg    /* SR01:turn off screen */
86ab47cfaaSmrg    OUTREG8 (SEQ_ADDRESS_REG,0x01);
87ab47cfaaSmrg    byte = INREG8(SEQ_DATA_REG) | 0x20;
88ab47cfaaSmrg    OUTREG8(SEQ_DATA_REG,byte);
89ab47cfaaSmrg
90ab47cfaaSmrg    psav->pVbe->pInt10->ax = BIOS_SET_VBE_MODE;
91ab47cfaaSmrg    psav->pVbe->pInt10->bx = n;
92ab47cfaaSmrg    xf86ExecX86int10(psav->pVbe->pInt10);
93ab47cfaaSmrg
94ab47cfaaSmrg}
95ab47cfaaSmrg
96ab47cfaaSmrgvoid
97ab47cfaaSmrgSavageSetVESAModeCrtc2( SavagePtr psav, int n, int refresh )
98ab47cfaaSmrg{
99ab47cfaaSmrg
100ab47cfaaSmrg    xf86Msg(X_INFO,"SavageSetVESAModeCrtc2:mode=0x%x,refresh=%dHZ\n",n,refresh);
101ab47cfaaSmrg
102ab47cfaaSmrg    SavageClearVM86Regs(psav->pVbe->pInt10);
103ab47cfaaSmrg
104ab47cfaaSmrg    UnLockExtRegs();
105ab47cfaaSmrg
106ab47cfaaSmrg    psav->pVbe->pInt10->ax = S3_EXTBIOS_INFO;
107ab47cfaaSmrg    psav->pVbe->pInt10->bx = S3_ALT_SET_ACTIVE_DISP;
108ab47cfaaSmrg    if (psav->TvOn)
109ab47cfaaSmrg    	psav->pVbe->pInt10->cx = 0x87; /* lcd, tv, crt, duoview */
110ab47cfaaSmrg    else
111ab47cfaaSmrg    	psav->pVbe->pInt10->cx = 0x83; /* lcd, crt, duoview */
112ab47cfaaSmrg    psav->pVbe->pInt10->dx = n & 0x1ff;
113ab47cfaaSmrg    psav->pVbe->pInt10->di = refresh & 0xffff;
114ab47cfaaSmrg    xf86ExecX86int10(psav->pVbe->pInt10);
115ab47cfaaSmrg
116ab47cfaaSmrg}
117ab47cfaaSmrg
118ab47cfaaSmrgvoid
119ab47cfaaSmrgSavageSetVESAMode( SavagePtr psav, int n, int Refresh )
120ab47cfaaSmrg{
121ab47cfaaSmrg    int iDevInfo;
122ab47cfaaSmrg    static int iCount = 0;
123ab47cfaaSmrg
124ab47cfaaSmrg    if (psav->IsSecondary) {
125ab47cfaaSmrg        SavageSetVESAModeCrtc2(psav, n, Refresh);
126ab47cfaaSmrg	return;
127ab47cfaaSmrg    }
128ab47cfaaSmrg    if (psav->IsPrimary) {
129ab47cfaaSmrg        SavageSetVESAModeCrtc1(psav, n, Refresh);
130ab47cfaaSmrg	return;
131ab47cfaaSmrg    }
132ab47cfaaSmrg
133ab47cfaaSmrg    /* Get current display device status. */
134ab47cfaaSmrg
135ab47cfaaSmrg    iDevInfo = SavageGetDevice(psav);
136ab47cfaaSmrg    psav->iDevInfo = iDevInfo;
137ab47cfaaSmrg    if( !iCount++ )
138ab47cfaaSmrg	psav->iDevInfoPrim = psav->iDevInfo;
139ab47cfaaSmrg    if( psav->CrtOnly )
140ab47cfaaSmrg	psav->iDevInfo = CRT_ACTIVE;
141ab47cfaaSmrg    if( psav->TvOn )
142ab47cfaaSmrg	psav->iDevInfo = TV_ACTIVE;
143ab47cfaaSmrg
144ab47cfaaSmrg    /* Establish the refresh rate for this mode. */
145ab47cfaaSmrg
146ab47cfaaSmrg    SavageClearVM86Regs( psav->pVbe->pInt10 );
147ab47cfaaSmrg    psav->pVbe->pInt10->ax = 0x4f14;	/* S3 extensions */
148ab47cfaaSmrg    psav->pVbe->pInt10->bx = 0x0001;	/* Set default refresh rate */
149ab47cfaaSmrg    psav->pVbe->pInt10->cx = n & 0x3fff;
150ab47cfaaSmrg    psav->pVbe->pInt10->di = Refresh & 0xffff;
151ab47cfaaSmrg
152ab47cfaaSmrg    xf86ExecX86int10( psav->pVbe->pInt10 );
153ab47cfaaSmrg
154ab47cfaaSmrg    /* Set TV type if TV is on. */
155ab47cfaaSmrg    if( psav->TvOn ) {
156ab47cfaaSmrg	SavageClearVM86Regs( psav->pVbe->pInt10 );
157ab47cfaaSmrg	psav->pVbe->pInt10->ax = 0x4f14;	/* S3 extensions */
158ab47cfaaSmrg	psav->pVbe->pInt10->bx = 0x0007;	/* TV extensions */
159ab47cfaaSmrg	psav->pVbe->pInt10->cx = psav->PAL ? 0x08 : 0x04;
160ab47cfaaSmrg	psav->pVbe->pInt10->dx = 0x0c;
161ab47cfaaSmrg	xf86ExecX86int10( psav->pVbe->pInt10 );
162ab47cfaaSmrg    }
163ab47cfaaSmrg
164ab47cfaaSmrg    /* Manipulate output device set. */
165ab47cfaaSmrg    if( psav->iDevInfo != iDevInfo ) {
166ab47cfaaSmrg	SavageClearVM86Regs( psav->pVbe->pInt10 );
167ab47cfaaSmrg	psav->pVbe->pInt10->ax = 0x4f14;	/* S3 extensions */
168ab47cfaaSmrg	psav->pVbe->pInt10->bx = 0x0003;	/* set active devices */
169ab47cfaaSmrg	psav->pVbe->pInt10->cx = psav->iDevInfo;
170ab47cfaaSmrg	xf86ExecX86int10( psav->pVbe->pInt10 );
171ab47cfaaSmrg
172ab47cfaaSmrg	/* Re-fetch actual device set. */
173ab47cfaaSmrg	psav->iDevInfo = SavageGetDevice( psav );
174ab47cfaaSmrg	iDevInfo = psav->iDevInfo;
175ab47cfaaSmrg	psav->CrtOnly = (iDevInfo == 1);
176ab47cfaaSmrg	psav->TvOn = !!(iDevInfo & 4);
177ab47cfaaSmrg    }
178ab47cfaaSmrg
179ab47cfaaSmrg    /* Now, make this mode current. */
180ab47cfaaSmrg
181ab47cfaaSmrg    if( xf86LoaderCheckSymbol( "VBESetVBEMode" ) )
182ab47cfaaSmrg    {
183ab47cfaaSmrg	if( !VBESetVBEMode( psav->pVbe, n, NULL ) )
184ab47cfaaSmrg	{
185ab47cfaaSmrg	    ErrorF("Set video mode failed\n");
186ab47cfaaSmrg	}
187ab47cfaaSmrg    }
188ab47cfaaSmrg}
189ab47cfaaSmrg
190ab47cfaaSmrgvoid
191ab47cfaaSmrgSavageSetPanelEnabled( SavagePtr psav, Bool active )
192ab47cfaaSmrg{
193ab47cfaaSmrg    int iDevInfo;
194ab47cfaaSmrg    if( !psav->PanelX )
195ab47cfaaSmrg	return; /* no panel */
196ab47cfaaSmrg    iDevInfo = SavageGetDevice( psav );
197ab47cfaaSmrg    if( active )
198ab47cfaaSmrg	iDevInfo |= LCD_ACTIVE;
199ab47cfaaSmrg    else
200ab47cfaaSmrg	iDevInfo &= ~LCD_ACTIVE;
201ab47cfaaSmrg    SavageClearVM86Regs( psav->pVbe->pInt10 );
202ab47cfaaSmrg    psav->pVbe->pInt10->ax = 0x4f14;	/* S3 extensions */
203ab47cfaaSmrg    psav->pVbe->pInt10->bx = 0x0003;	/* set active devices */
204ab47cfaaSmrg    psav->pVbe->pInt10->cx = iDevInfo;
205ab47cfaaSmrg    xf86ExecX86int10( psav->pVbe->pInt10 );
206ab47cfaaSmrg}
207ab47cfaaSmrg
208ab47cfaaSmrg/* Function to get supported device list. */
209ab47cfaaSmrg
210ab47cfaaSmrgstatic int SavageGetDevice( SavagePtr psav )
211ab47cfaaSmrg{
212ab47cfaaSmrg    SavageClearVM86Regs( psav->pVbe->pInt10 );
213ab47cfaaSmrg    psav->pVbe->pInt10->ax = 0x4f14;	/* S3 extensions */
214ab47cfaaSmrg    psav->pVbe->pInt10->bx = 0x0103;	/* get active devices */
215ab47cfaaSmrg
216ab47cfaaSmrg    xf86ExecX86int10( psav->pVbe->pInt10 );
217ab47cfaaSmrg
218ab47cfaaSmrg    return ((psav->pVbe->pInt10->cx) & 0xf);
219ab47cfaaSmrg}
220ab47cfaaSmrg
221ab47cfaaSmrg
222ab47cfaaSmrgvoid
223ab47cfaaSmrgSavageFreeBIOSModeTable( SavagePtr psav, SavageModeTablePtr* ppTable )
224ab47cfaaSmrg{
225ab47cfaaSmrg    int i;
226ab47cfaaSmrg    SavageModeEntryPtr pMode = (*ppTable)->Modes;
227ab47cfaaSmrg
228ab47cfaaSmrg    for( i = (*ppTable)->NumModes; i--; )
229ab47cfaaSmrg    {
230ab47cfaaSmrg	if( pMode->RefreshRate )
231ab47cfaaSmrg	{
232aa9e3350Smrg	    free( pMode->RefreshRate );
233ab47cfaaSmrg	    pMode->RefreshRate = NULL;
234ab47cfaaSmrg	}
235ab47cfaaSmrg	pMode++;
236ab47cfaaSmrg    }
237ab47cfaaSmrg
238aa9e3350Smrg    free( *ppTable );
239ab47cfaaSmrg}
240ab47cfaaSmrg
241ab47cfaaSmrg
242ab47cfaaSmrgSavageModeTablePtr
243ab47cfaaSmrgSavageGetBIOSModeTable( SavagePtr psav, int iDepth )
244ab47cfaaSmrg{
245aa9e3350Smrg    VbeInfoBlock *vbe;
246aa9e3350Smrg    int nModes;
247ab47cfaaSmrg    SavageModeTablePtr pTable;
248ab47cfaaSmrg
249aa9e3350Smrg    if( !psav->pVbe )
250aa9e3350Smrg	return 0;
251aa9e3350Smrg
252aa9e3350Smrg    if (!(vbe = VBEGetVBEInfo(psav->pVbe)))
253aa9e3350Smrg	return 0;
254aa9e3350Smrg
255aa9e3350Smrg    nModes = SavageGetBIOSModes( psav, vbe, iDepth, NULL );
256aa9e3350Smrg
257ab47cfaaSmrg    pTable = (SavageModeTablePtr)
258aa9e3350Smrg	calloc( 1, sizeof(SavageModeTableRec) +
259ab47cfaaSmrg		    (nModes-1) * sizeof(SavageModeEntry) );
260ab47cfaaSmrg    if( pTable ) {
261ab47cfaaSmrg	pTable->NumModes = nModes;
262aa9e3350Smrg	SavageGetBIOSModes( psav, vbe, iDepth, pTable->Modes );
263ab47cfaaSmrg    }
264ab47cfaaSmrg
265aa9e3350Smrg    VBEFreeVBEInfo(vbe);
266aa9e3350Smrg
267ab47cfaaSmrg    return pTable;
268ab47cfaaSmrg}
269ab47cfaaSmrg
270ab47cfaaSmrg
271ab47cfaaSmrgunsigned short
272ab47cfaaSmrgSavageGetBIOSModes(
273ab47cfaaSmrg    SavagePtr psav,
274aa9e3350Smrg    VbeInfoBlock *vbe,
275ab47cfaaSmrg    int iDepth,
276ab47cfaaSmrg    SavageModeEntryPtr s3vModeTable )
277ab47cfaaSmrg{
278ab47cfaaSmrg    unsigned short iModeCount = 0;
279ab47cfaaSmrg    unsigned short int *mode_list;
280ab47cfaaSmrg    pointer vbeLinear = NULL;
281ab47cfaaSmrg    int vbeReal;
282ab47cfaaSmrg    struct vbe_mode_info_block * vmib;
283ab47cfaaSmrg
284ab47cfaaSmrg    vbeLinear = xf86Int10AllocPages( psav->pVbe->pInt10, 1, &vbeReal );
285ab47cfaaSmrg    if( !vbeLinear )
286ab47cfaaSmrg    {
287ab47cfaaSmrg	ErrorF( "Cannot allocate scratch page in real mode memory." );
288ab47cfaaSmrg	return 0;
289ab47cfaaSmrg    }
290ab47cfaaSmrg    vmib = (struct vbe_mode_info_block *) vbeLinear;
291ab47cfaaSmrg
292ab47cfaaSmrg    for (mode_list = vbe->VideoModePtr; *mode_list != 0xffff; mode_list++) {
293ab47cfaaSmrg
294ab47cfaaSmrg	/*
295ab47cfaaSmrg	 * This is a HACK to work around what I believe is a BUG in the
296ab47cfaaSmrg	 * Toshiba Satellite BIOSes in 08/2000 and 09/2000.  The BIOS
297ab47cfaaSmrg	 * table for 1024x600 says it has six refresh rates, when in fact
298ab47cfaaSmrg	 * it only has 3.  When I ask for rate #4, the BIOS goes into an
299ab47cfaaSmrg	 * infinite loop until the user interrupts it, usually by pressing
300ab47cfaaSmrg	 * Ctrl-Alt-F1.  For now, we'll just punt everything with a VESA
301ab47cfaaSmrg	 * number greater than or equal to 0200.
302ab47cfaaSmrg	 *
303ab47cfaaSmrg	 * This also prevents some strange and unusual results seen with
304ab47cfaaSmrg	 * the later ProSavage/PM133 BIOSes directly from S3/VIA.
305ab47cfaaSmrg	 */
306ab47cfaaSmrg	if( *mode_list >= 0x0200 )
307ab47cfaaSmrg	    continue;
308ab47cfaaSmrg
309ab47cfaaSmrg	SavageClearVM86Regs( psav->pVbe->pInt10 );
310ab47cfaaSmrg
311ab47cfaaSmrg	psav->pVbe->pInt10->ax = 0x4f01;
312ab47cfaaSmrg	psav->pVbe->pInt10->cx = *mode_list;
313ab47cfaaSmrg	psav->pVbe->pInt10->es = SEG_ADDR(vbeReal);
314ab47cfaaSmrg	psav->pVbe->pInt10->di = SEG_OFF(vbeReal);
315ab47cfaaSmrg	psav->pVbe->pInt10->num = 0x10;
316ab47cfaaSmrg
317ab47cfaaSmrg	xf86ExecX86int10( psav->pVbe->pInt10 );
318ab47cfaaSmrg
319ab47cfaaSmrg	if(
320ab47cfaaSmrg	   (vmib->bits_per_pixel == iDepth) &&
321ab47cfaaSmrg	   (
322ab47cfaaSmrg	      (vmib->memory_model == VBE_MODEL_256) ||
323ab47cfaaSmrg	      (vmib->memory_model == VBE_MODEL_PACKED) ||
324ab47cfaaSmrg	      (vmib->memory_model == VBE_MODEL_RGB)
325ab47cfaaSmrg	   )
326ab47cfaaSmrg	)
327ab47cfaaSmrg	{
328ab47cfaaSmrg	    /* This mode is a match. */
329ab47cfaaSmrg
330ab47cfaaSmrg	    iModeCount++;
331ab47cfaaSmrg
332ab47cfaaSmrg	    /* If we're supposed to fetch information, do it now. */
333ab47cfaaSmrg
334ab47cfaaSmrg	    if( s3vModeTable )
335ab47cfaaSmrg	    {
336ab47cfaaSmrg	        int iRefresh = 0;
337ab47cfaaSmrg
338ab47cfaaSmrg		s3vModeTable->Width = vmib->x_resolution;
339ab47cfaaSmrg		s3vModeTable->Height = vmib->y_resolution;
340ab47cfaaSmrg		s3vModeTable->VesaMode = *mode_list;
341ab47cfaaSmrg
342ab47cfaaSmrg		/* Query the refresh rates at this mode. */
343ab47cfaaSmrg
344ab47cfaaSmrg		psav->pVbe->pInt10->cx = *mode_list;
345ab47cfaaSmrg		psav->pVbe->pInt10->dx = 0;
346ab47cfaaSmrg
347ab47cfaaSmrg		do
348ab47cfaaSmrg		{
349ab47cfaaSmrg		    if( (iRefresh % 8) == 0 )
350ab47cfaaSmrg		    {
351ab47cfaaSmrg			if( s3vModeTable->RefreshRate )
352ab47cfaaSmrg			{
353ab47cfaaSmrg			    s3vModeTable->RefreshRate = (unsigned char *)
354aa9e3350Smrg				realloc(
355ab47cfaaSmrg				    s3vModeTable->RefreshRate,
356ab47cfaaSmrg				    (iRefresh+8) * sizeof(unsigned char)
357ab47cfaaSmrg				);
358ab47cfaaSmrg			}
359ab47cfaaSmrg			else
360ab47cfaaSmrg			{
361ab47cfaaSmrg			    s3vModeTable->RefreshRate = (unsigned char *)
362aa9e3350Smrg				calloc(
363ab47cfaaSmrg				    sizeof(unsigned char),
364ab47cfaaSmrg				    (iRefresh+8)
365ab47cfaaSmrg				);
366ab47cfaaSmrg			}
367ab47cfaaSmrg		    }
368ab47cfaaSmrg
369ab47cfaaSmrg		    psav->pVbe->pInt10->ax = 0x4f14;	/* S3 extended functions */
370ab47cfaaSmrg		    psav->pVbe->pInt10->bx = 0x0201;	/* query refresh rates */
371ab47cfaaSmrg		    psav->pVbe->pInt10->num = 0x10;
372ab47cfaaSmrg		    xf86ExecX86int10( psav->pVbe->pInt10 );
373ab47cfaaSmrg
374ab47cfaaSmrg		    s3vModeTable->RefreshRate[iRefresh++] = psav->pVbe->pInt10->di;
375ab47cfaaSmrg		}
376ab47cfaaSmrg		while( psav->pVbe->pInt10->dx );
377ab47cfaaSmrg
378ab47cfaaSmrg		s3vModeTable->RefreshCount = iRefresh;
379ab47cfaaSmrg
380ab47cfaaSmrg	    	s3vModeTable++;
381ab47cfaaSmrg	    }
382ab47cfaaSmrg	}
383ab47cfaaSmrg    }
384ab47cfaaSmrg
385ab47cfaaSmrg    xf86Int10FreePages( psav->pVbe->pInt10, vbeLinear, 1 );
386ab47cfaaSmrg
387ab47cfaaSmrg    return iModeCount;
388ab47cfaaSmrg}
389ab47cfaaSmrg
390ab47cfaaSmrgModeStatus SavageMatchBiosMode(ScrnInfoPtr pScrn,int width,int height,int refresh,
391ab47cfaaSmrg                              unsigned int *vesaMode,unsigned int *newRefresh)
392ab47cfaaSmrg{
393ab47cfaaSmrg    SavageModeEntryPtr pmt;
394ab47cfaaSmrg    Bool found = FALSE;
395ab47cfaaSmrg    SavagePtr psav = SAVPTR(pScrn);
396ab47cfaaSmrg    int i,j;
397ab47cfaaSmrg    unsigned int chosenVesaMode = 0;
398ab47cfaaSmrg    unsigned int chosenRefresh = 0;
399ab47cfaaSmrg
400ab47cfaaSmrg    /* Scan through our BIOS list to locate the closest valid mode. */
401ab47cfaaSmrg
402ab47cfaaSmrg    /*
403ab47cfaaSmrg     * If we ever break 4GHz clocks on video boards, we'll need to
404ab47cfaaSmrg     * change this.
405ab47cfaaSmrg     * refresh = (mode->Clock * 1000) / (mode->HTotal * mode->VTotal);
406ab47cfaaSmrg     * now we use VRefresh directly,instead of by calculating from dot clock
407ab47cfaaSmrg     */
408ab47cfaaSmrg
409ab47cfaaSmrg    for( i = 0, pmt = psav->ModeTable->Modes;
410ab47cfaaSmrg	i < psav->ModeTable->NumModes;
411ab47cfaaSmrg	i++, pmt++ )
412ab47cfaaSmrg    {
413ab47cfaaSmrg	if( (pmt->Width == width) &&
414ab47cfaaSmrg	    (pmt->Height == height) )
415ab47cfaaSmrg	{
416ab47cfaaSmrg	    int jDelta = 99;
417ab47cfaaSmrg	    int jBest = 0;
418ab47cfaaSmrg
419ab47cfaaSmrg	    /* We have an acceptable mode.  Find a refresh rate. */
420ab47cfaaSmrg	    chosenVesaMode = pmt->VesaMode;
421ab47cfaaSmrg            if (vesaMode)
422ab47cfaaSmrg                *vesaMode = chosenVesaMode;
423ab47cfaaSmrg	    for( j = 0; j < pmt->RefreshCount; j++ )
424ab47cfaaSmrg	    {
425ab47cfaaSmrg		if( pmt->RefreshRate[j] == refresh )
426ab47cfaaSmrg		{
427ab47cfaaSmrg		    /* Exact match. */
428ab47cfaaSmrg		    jBest = j;
429ab47cfaaSmrg		    break;
430ab47cfaaSmrg		}
431ab47cfaaSmrg		else if( iabs(pmt->RefreshRate[j] - refresh) < jDelta )
432ab47cfaaSmrg		{
433ab47cfaaSmrg		    jDelta = iabs(pmt->RefreshRate[j] - refresh);
434ab47cfaaSmrg		    jBest = j;
435ab47cfaaSmrg		}
436ab47cfaaSmrg	    }
437ab47cfaaSmrg	    chosenRefresh = pmt->RefreshRate[jBest];
438ab47cfaaSmrg            if (newRefresh)
439ab47cfaaSmrg                *newRefresh = chosenRefresh;
440ab47cfaaSmrg            found = TRUE;
441ab47cfaaSmrg	    break;
442ab47cfaaSmrg	}
443ab47cfaaSmrg    }
444ab47cfaaSmrg
445ab47cfaaSmrg    if( found ) {
446ab47cfaaSmrg	/* Success: we found a match in the BIOS. */
447ab47cfaaSmrg	xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
448ab47cfaaSmrg		  "Chose mode %x at %dHz.\n", chosenVesaMode, chosenRefresh );
449ab47cfaaSmrg        return MODE_OK;
450ab47cfaaSmrg    } else {
451ab47cfaaSmrg	xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
452ab47cfaaSmrg		  "No suitable BIOS mode found for %dx%d %dHz.\n",
453ab47cfaaSmrg		  width, height, refresh);
454ab47cfaaSmrg        return MODE_NOMODE;
455ab47cfaaSmrg    }
456ab47cfaaSmrg}
457