diff options
Diffstat (limited to 'src/savage_vbe.c')
-rw-r--r-- | src/savage_vbe.c | 302 |
1 files changed, 302 insertions, 0 deletions
diff --git a/src/savage_vbe.c b/src/savage_vbe.c new file mode 100644 index 0000000..f0a0edc --- /dev/null +++ b/src/savage_vbe.c @@ -0,0 +1,302 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/savage/savage_vbe.c,v 1.12 2002/10/02 20:39:55 alanh Exp $ */ + +#include "savage_driver.h" +#include "savage_vbe.h" + +#if X_BYTE_ORDER == X_LITTLE_ENDIAN +#define B_O16(x) (x) +#define B_O32(x) (x) +#else +#define B_O16(x) ((((x) & 0xff) << 8) | (((x) & 0xff) >> 8)) +#define B_O32(x) ((((x) & 0xff) << 24) | (((x) & 0xff00) << 8) \ + | (((x) & 0xff0000) >> 8) | (((x) & 0xff000000) >> 24)) +#endif +#define L_ADD(x) (B_O32(x) & 0xffff) + ((B_O32(x) >> 12) & 0xffff00) + +Bool vbeModeInit( vbeInfoPtr, int ); +static int SavageGetDevice( SavagePtr psav ); +/*static int SavageGetTVType( SavagePtr psav );*/ + +static void +SavageClearVM86Regs( xf86Int10InfoPtr pInt ) +{ + pInt->ax = 0; + pInt->bx = 0; + pInt->cx = 0; + pInt->dx = 0; + pInt->si = 0; + pInt->di = 0; + pInt->es = 0xc000; + pInt->num = 0x10; +} + +void +SavageSetTextMode( SavagePtr psav ) +{ + /* Restore display device if changed. */ + if( psav->iDevInfo != psav->iDevInfoPrim ) { + SavageClearVM86Regs( psav->pInt10 ); + psav->pInt10->ax = 0x4f14; + psav->pInt10->bx = 0x0003; + psav->pInt10->cx = psav->iDevInfoPrim; + xf86ExecX86int10( psav->pInt10 ); + } + + SavageClearVM86Regs( psav->pInt10 ); + + psav->pInt10->ax = 0x83; + + xf86ExecX86int10( psav->pInt10 ); +} + + +void +SavageSetVESAMode( SavagePtr psav, int n, int Refresh ) +{ + int iDevInfo; + static int iCount = 0; + + /* Get current display device status. */ + + iDevInfo = SavageGetDevice(psav); + psav->iDevInfo = iDevInfo; + if( !iCount++ ) + psav->iDevInfoPrim = psav->iDevInfo; + if( psav->CrtOnly ) + psav->iDevInfo = CRT_ACTIVE; + if( psav->TvOn ) + psav->iDevInfo = TV_ACTIVE; + + /* Establish the refresh rate for this mode. */ + + SavageClearVM86Regs( psav->pInt10 ); + psav->pInt10->ax = 0x4f14; /* S3 extensions */ + psav->pInt10->bx = 0x0001; /* Set default refresh rate */ + psav->pInt10->cx = n; + psav->pInt10->di = Refresh & 0xffff; + + xf86ExecX86int10( psav->pInt10 ); + + /* Set TV type if TV is on. */ + if( psav->TvOn ) { + SavageClearVM86Regs( psav->pInt10 ); + psav->pInt10->ax = 0x4f14; /* S3 extensions */ + psav->pInt10->bx = 0x0007; /* TV extensions */ + psav->pInt10->cx = psav->PAL ? 0x08 : 0x04; + psav->pInt10->dx = 0x0c; + xf86ExecX86int10( psav->pInt10 ); + } + + /* Manipulate output device set. */ + if( psav->iDevInfo != iDevInfo ) { + SavageClearVM86Regs( psav->pInt10 ); + psav->pInt10->ax = 0x4f14; /* S3 extensions */ + psav->pInt10->bx = 0x0003; /* set active devices */ + psav->pInt10->cx = psav->PAL ? 0x08 : 0x04; + xf86ExecX86int10( psav->pInt10 ); + + /* Re-fetch actual device set. */ + psav->iDevInfo = SavageGetDevice( psav ); + iDevInfo = psav->iDevInfo; + psav->CrtOnly = (iDevInfo == 1); + psav->TvOn = !!(iDevInfo & 4); + } + + /* Now, make this mode current. */ + + if( xf86LoaderCheckSymbol( "VBESetVBEMode" ) ) + { + if( !VBESetVBEMode( psav->pVbe, n, NULL ) ) + { + ErrorF("Set video mode failed\n"); + } + } +#ifdef XFree86LOADER + else + { + if( !vbeModeInit( psav->pVbe, n ) ) + { + ErrorF("Set video mode failed\n"); + } + } +#endif +} + + +/* Function to get supported device list. */ + +static int SavageGetDevice( SavagePtr psav ) +{ + SavageClearVM86Regs( psav->pInt10 ); + psav->pInt10->ax = 0x4f14; /* S3 extensions */ + psav->pInt10->bx = 0x0103; /* get active devices */ + + xf86ExecX86int10( psav->pInt10 ); + + return ((psav->pInt10->cx) & 0xf); +} + + +void +SavageFreeBIOSModeTable( SavagePtr psav, SavageModeTablePtr* ppTable ) +{ + int i; + SavageModeEntryPtr pMode = (*ppTable)->Modes; + + for( i = (*ppTable)->NumModes; i--; ) + { + if( pMode->RefreshRate ) + { + xfree( pMode->RefreshRate ); + pMode->RefreshRate = NULL; + } + } + + xfree( *ppTable ); +} + + +SavageModeTablePtr +SavageGetBIOSModeTable( SavagePtr psav, int iDepth ) +{ + int nModes = SavageGetBIOSModes( psav, iDepth, NULL ); + SavageModeTablePtr pTable; + + pTable = (SavageModeTablePtr) + xcalloc( 1, sizeof(SavageModeTableRec) + + (nModes-1) * sizeof(SavageModeEntry) ); + if( pTable ) { + pTable->NumModes = nModes; + SavageGetBIOSModes( psav, iDepth, pTable->Modes ); + } + + return pTable; +} + + +unsigned short +SavageGetBIOSModes( + SavagePtr psav, + int iDepth, + SavageModeEntryPtr s3vModeTable ) +{ + unsigned short iModeCount = 0; + unsigned short int *mode_list; + pointer vbeLinear = NULL; + vbeControllerInfoPtr vbe = NULL; + int vbeReal; + struct vbe_mode_info_block * vmib; + + if( !psav->pVbe ) + return 0; + + vbe = (vbeControllerInfoPtr) psav->pVbe->memory; + vbeLinear = xf86Int10AllocPages( psav->pInt10, 1, &vbeReal ); + if( !vbeLinear ) + { + ErrorF( "Cannot allocate scratch page in real mode memory." ); + return 0; + } + vmib = (struct vbe_mode_info_block *) vbeLinear; + + for ( + mode_list = xf86int10Addr( psav->pInt10, L_ADD(vbe->VideoModePtr) ); + *mode_list != 0xffff; + mode_list++ + ) + { + /* + * This is a HACK to work around what I believe is a BUG in the + * Toshiba Satellite BIOSes in 08/2000 and 09/2000. The BIOS + * table for 1024x600 says it has six refresh rates, when in fact + * it only has 3. When I ask for rate #4, the BIOS goes into an + * infinite loop until the user interrupts it, usually by pressing + * Ctrl-Alt-F1. For now, we'll just punt everything with a VESA + * number greater than or equal to 0200. + * + * This also prevents some strange and unusual results seen with + * the later ProSavage/PM133 BIOSes directly from S3/VIA. + */ + if( *mode_list >= 0x0200 ) + continue; + + SavageClearVM86Regs( psav->pInt10 ); + + psav->pInt10->ax = 0x4f01; + psav->pInt10->cx = *mode_list; + psav->pInt10->es = SEG_ADDR(vbeReal); + psav->pInt10->di = SEG_OFF(vbeReal); + psav->pInt10->num = 0x10; + + xf86ExecX86int10( psav->pInt10 ); + + if( + (vmib->bits_per_pixel == iDepth) && + ( + (vmib->memory_model == VBE_MODEL_256) || + (vmib->memory_model == VBE_MODEL_PACKED) || + (vmib->memory_model == VBE_MODEL_RGB) + ) + ) + { + /* This mode is a match. */ + + iModeCount++; + + /* If we're supposed to fetch information, do it now. */ + + if( s3vModeTable ) + { + int iRefresh = 0; + + s3vModeTable->Width = vmib->x_resolution; + s3vModeTable->Height = vmib->y_resolution; + s3vModeTable->VesaMode = *mode_list; + + /* Query the refresh rates at this mode. */ + + psav->pInt10->cx = *mode_list; + psav->pInt10->dx = 0; + + do + { + if( (iRefresh % 8) == 0 ) + { + if( s3vModeTable->RefreshRate ) + { + s3vModeTable->RefreshRate = (unsigned char *) + xrealloc( + s3vModeTable->RefreshRate, + (iRefresh+8) * sizeof(unsigned char) + ); + } + else + { + s3vModeTable->RefreshRate = (unsigned char *) + xcalloc( + sizeof(unsigned char), + (iRefresh+8) + ); + } + } + + psav->pInt10->ax = 0x4f14; /* S3 extended functions */ + psav->pInt10->bx = 0x0201; /* query refresh rates */ + psav->pInt10->num = 0x10; + xf86ExecX86int10( psav->pInt10 ); + + s3vModeTable->RefreshRate[iRefresh++] = psav->pInt10->di; + } + while( psav->pInt10->dx ); + + s3vModeTable->RefreshCount = iRefresh; + + s3vModeTable++; + } + } + } + + xf86Int10FreePages( psav->pInt10, vbeLinear, 1 ); + + return iModeCount; +} |