#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 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 )
{
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;
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;
SavageClearVM86Regs( psav->pInt10 );
psav->pInt10->ax = 0x4f14;
psav->pInt10->bx = 0x0001;
psav->pInt10->cx = n & 0x3fff;
psav->pInt10->di = Refresh & 0xffff;
xf86ExecX86int10( psav->pInt10 );
if( psav->TvOn ) {
SavageClearVM86Regs( psav->pInt10 );
psav->pInt10->ax = 0x4f14;
psav->pInt10->bx = 0x0007;
psav->pInt10->cx = psav->PAL ? 0x08 : 0x04;
psav->pInt10->dx = 0x0c;
xf86ExecX86int10( psav->pInt10 );
}
if( psav->iDevInfo != iDevInfo ) {
SavageClearVM86Regs( psav->pInt10 );
psav->pInt10->ax = 0x4f14;
psav->pInt10->bx = 0x0003;
psav->pInt10->cx = psav->PAL ? 0x08 : 0x04;
xf86ExecX86int10( psav->pInt10 );
psav->iDevInfo = SavageGetDevice( psav );
iDevInfo = psav->iDevInfo;
psav->CrtOnly = (iDevInfo == 1);
psav->TvOn = !!(iDevInfo & 4);
}
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
}
static int SavageGetDevice( SavagePtr psav )
{
SavageClearVM86Regs( psav->pInt10 );
psav->pInt10->ax = 0x4f14;
psav->pInt10->bx = 0x0103;
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;
}
pMode++;
}
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++
)
{
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)
)
)
{
iModeCount++;
if( s3vModeTable )
{
int iRefresh = 0;
s3vModeTable->Width = vmib->x_resolution;
s3vModeTable->Height = vmib->y_resolution;
s3vModeTable->VesaMode = *mode_list;
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;
psav->pInt10->bx = 0x0201;
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;
}