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