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