Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

636 lines
15 KiB

//***************************************************************************
//
// Module Name:
//
// permmem.c
//
// Abstract:
//
// This module contains code to generate initialize table form ROM
//
// Environment:
//
// Kernel mode
//
//
// Copyright (c) 1994-1998 3Dlabs Inc. Ltd. All rights reserved.
// Copyright (c) 1995-1999 Microsoft Corporation. All Rights Reserved.
//
//***************************************************************************
#include "permedia.h"
#if defined(ALLOC_PRAGMA)
#pragma alloc_text(PAGE,CopyROMInitializationTable)
#pragma alloc_text(PAGE,GenerateInitializationTable)
#pragma alloc_text(PAGE,ProcessInitializationTable)
#pragma alloc_text(PAGE,IntergerToUnicode)
#pragma alloc_text(PAGE,GetBiosVersion)
#endif
VOID
CopyROMInitializationTable (
PHW_DEVICE_EXTENSION hwDeviceExtension
)
/*++
Routine Description:
this function should be called for devices that have an expansion ROM
which contains a register initialization table. The function assumes
the ROM is present and enabled.
Arguments:
hwDeviceExtension -
the device extension of the device whose ROM is to be read
pvROMAddress -
base address of the expansion ROM. This function assumes that
the offset to the initialization table is defined at 0x1c from
the beginning of ROM
Return:
void
--*/
{
PULONG pulROMTable;
PVOID pvROMAddress;
ULONG ulTableOffset;
ULONG cEntries;
PULONG pul;
ULONG ul;
hwDeviceExtension->culTableEntries = 0;
//
// just use default values on NT4
//
if(hwDeviceExtension->NtVersion == NT4)
return;
//
// the 2-byte offset to the initialization table is given at 0x1c
// from the start of ROM
//
pvROMAddress = VideoPortGetRomImage( hwDeviceExtension,
NULL,
0,
0x1c + 2 );
if(pvROMAddress == NULL)
{
DEBUG_PRINT((1, "CopyROMinitializationTable: Can not access ROM\n"));
return;
}
else if ( *(USHORT *)pvROMAddress != 0xAA55)
{
DEBUG_PRINT((1, "CopyROMinitializationTable: ROM Signature 0x%x is invalid\n",
*(USHORT *)pvROMAddress ));
return;
}
ulTableOffset = *((PUSHORT)(0x1c + (PCHAR)pvROMAddress));
//
// read the table header (32 bits)
//
pvROMAddress = VideoPortGetRomImage( hwDeviceExtension,
NULL,
0,
ulTableOffset + 4 );
if(pvROMAddress == NULL)
{
DEBUG_PRINT((1, "CopyROMinitializationTable: Can not access ROM\n"));
return;
}
pulROMTable = (PULONG)(ulTableOffset + (PCHAR)pvROMAddress);
//
// the table header (32 bits) has an identification code and a count
// of the number of entries in the table
//
if((*pulROMTable >> 16) != 0x3d3d)
{
DEBUG_PRINT((1, "CopyROMinitializationTable: invalid initialization table header\n"));
return;
}
//
// number of register address & data pairs
//
cEntries = *pulROMTable & 0xffff;
if(cEntries == 0)
{
DEBUG_PRINT((1, "CopyROMinitializationTable: empty initialization table\n"));
return;
}
//
// this assert, and the one after the copy should ensure we don't write
// past the end of the table
//
P2_ASSERT(cEntries * sizeof(ULONG) * 2 <= sizeof(hwDeviceExtension->aulInitializationTable),
"ERROR: too many initialization entries\n");
pvROMAddress = VideoPortGetRomImage( hwDeviceExtension,
NULL,
0,
ulTableOffset + 4 + cEntries * sizeof(ULONG) * 2 );
if(pvROMAddress == NULL)
{
DEBUG_PRINT((1, "CopyROMinitializationTable: Can not access ROM\n"));
return;
}
//
// each entry contains two 32-bit words
//
pul = hwDeviceExtension->aulInitializationTable;
//
// skip the 4 bype table header
//
pulROMTable = (PULONG)(ulTableOffset + 4 + (PCHAR)pvROMAddress);
ul = cEntries << 1;
while(ul--)
{
*pul++ = *pulROMTable;
++pulROMTable;
}
hwDeviceExtension->culTableEntries =
(ULONG)(pul - (ULONG *)hwDeviceExtension->aulInitializationTable) >> 1;
P2_ASSERT(cEntries == hwDeviceExtension->culTableEntries,
"ERROR: generated different size init table to that expected\n");
#if DBG
//
// output the initialization table
//
pul = hwDeviceExtension->aulInitializationTable;
ul = hwDeviceExtension->culTableEntries;
while(ul--)
{
ULONG ulReg;
ULONG ulRegData;
ulReg = *pul++;
ulRegData = *pul++;
DEBUG_PRINT((2, "CopyROMInitializationTable: initializing register %08.8Xh with %08.8Xh\n",
ulReg, ulRegData));
}
#endif //DBG
}
VOID
GenerateInitializationTable (
PHW_DEVICE_EXTENSION hwDeviceExtension
)
/*++
Routine Description:
creates a register initialization table (called if we can't read one
from ROM). If VGA is enabled the registers are already initialized so
we just read them back, otherwise we have to use default values
Arguments:
hwDeviceExtension - the device for which we are creating the table
Return:
void
--*/
{
ULONG cEntries;
PULONG pul;
ULONG ul;
int i, j;
P2_DECL;
hwDeviceExtension->culTableEntries = 0;
cEntries = 6;
//
// this assert, and the one after the copy should ensure we don't
// write past the end of the table
//
P2_ASSERT(cEntries * sizeof(ULONG) * 2 <= sizeof(hwDeviceExtension->aulInitializationTable),
"ERROR: to many initialization entries\n");
//
// each entry contains two 32-bit words
//
pul = hwDeviceExtension->aulInitializationTable;
if(hwDeviceExtension->bVGAEnabled)
{
//
// OK: no initialization table but VGA is running so our key
// registers have been initialized to sensible values
//
DEBUG_PRINT((1, "GenerateinitializationTable: VGA enabled: reading registers\n"));
//
// key entries are: ROM control, Boot Address, Memory Config and
// VStream Config
//
*pul++ = CTRL_REG_OFFSET(ROM_CONTROL);
*pul++ = VideoPortReadRegisterUlong(ROM_CONTROL);
*pul++ = CTRL_REG_OFFSET(BOOT_ADDRESS);
*pul++ = VideoPortReadRegisterUlong(BOOT_ADDRESS);
*pul++ = CTRL_REG_OFFSET(MEM_CONFIG);
*pul++ = VideoPortReadRegisterUlong(MEM_CONFIG);
*pul++ = CTRL_REG_OFFSET(VSTREAM_CONFIG);
*pul++ = VideoPortReadRegisterUlong(VSTREAM_CONFIG);
*pul++ = CTRL_REG_OFFSET(VIDEO_FIFO_CTL);
*pul++ = VideoPortReadRegisterUlong(VIDEO_FIFO_CTL);
*pul++ = CTRL_REG_OFFSET(V_CLK_CTL);
*pul++ = VideoPortReadRegisterUlong(V_CLK_CTL);
}
else
{
//
// no initialization table and no VGA. Use default values.
//
DEBUG_PRINT((2, "PERM2: GenerateInitializationTable() VGA disabled - using default values\n"));
*pul++ = CTRL_REG_OFFSET(ROM_CONTROL);
*pul++ = 0;
*pul++ = CTRL_REG_OFFSET(BOOT_ADDRESS);
*pul++ = 0x20;
*pul++ = CTRL_REG_OFFSET(MEM_CONFIG);
*pul++ = 0xe6002021;
*pul++ = CTRL_REG_OFFSET(VSTREAM_CONFIG);
*pul++ = 0x1f0;
*pul++ = CTRL_REG_OFFSET(VIDEO_FIFO_CTL);
*pul++ = 0x11008;
*pul++ = CTRL_REG_OFFSET(V_CLK_CTL);
if( DEVICE_FAMILY_ID(hwDeviceExtension->deviceInfo.DeviceId )
== PERMEDIA_P2S_ID )
{
*pul++ = 0x80;
}
else
{
*pul++ = 0x40;
}
}
hwDeviceExtension->culTableEntries =
(ULONG)(pul - (ULONG *)hwDeviceExtension->aulInitializationTable) >> 1;
P2_ASSERT(cEntries == hwDeviceExtension->culTableEntries,
"ERROR: generated different size init table to that expected\n");
#if DBG
//
// output the initialization table
//
pul = hwDeviceExtension->aulInitializationTable;
ul = hwDeviceExtension->culTableEntries;
while(ul--)
{
ULONG ulReg;
ULONG ulRegData;
ulReg = *pul++;
ulRegData = *pul++;
DEBUG_PRINT((2, "GenerateInitializationTable: initializing register %08.8Xh with %08.8Xh\n",
ulReg, ulRegData));
}
#endif //DBG
}
VOID
ProcessInitializationTable(
PHW_DEVICE_EXTENSION hwDeviceExtension
)
/*++
Routine Description:
this function processes the register initialization table
Arguments:
hwDeviceExtension - a pointer to the device extension.
Return:
void
--*/
{
PULONG pul;
ULONG cul;
ULONG ulRegAddr, ulRegData;
PULONG pulReg;
ULONG BaseAddrSelect;
P2_DECL;
pul = (PULONG)hwDeviceExtension->aulInitializationTable;
cul = hwDeviceExtension->culTableEntries;
while(cul--)
{
ulRegAddr = *pul++;
ulRegData = *pul++;
BaseAddrSelect = ulRegAddr >> 29;
if(BaseAddrSelect == 0)
{
//
// the offset is from the start of the control registers
//
pulReg = (PULONG)((ULONG_PTR)pCtrlRegs + (ulRegAddr & 0x3FFFFF));
}
else
{
DEBUG_PRINT((2, "ProcessInitializationTable: Invalid base address select %d regAddr = %d regData = %d\n",
BaseAddrSelect, ulRegAddr, ulRegData));
continue;
}
DEBUG_PRINT((2, "ProcessInitializationTable: initializing (region %d) register %08.8Xh with %08.8Xh\n",
BaseAddrSelect, pulReg, ulRegData));
VideoPortWriteRegisterUlong(pulReg, ulRegData);
}
//
// We need a small delay after initializing the above registers
//
VideoPortStallExecution(5);
}
BOOLEAN
VerifyBiosSettings(
PHW_DEVICE_EXTENSION hwDeviceExtension
)
/*++
Routine Description:
This function validate a few register values set by bios at boot time
Arguments:
hwDeviceExtension - a pointer to the device extension.
Return:
TRUE - if the everything is all right
FALSE - if some of the values don't match those in initialization table
--*/
{
PULONG pul;
ULONG cul;
ULONG ulRegAddr, ulRegData;
PULONG pulReg;
ULONG BaseAddrSelect;
P2_DECL;
pul = (PULONG)hwDeviceExtension->aulInitializationTable;
cul = hwDeviceExtension->culTableEntries;
while(cul--)
{
ulRegAddr = *pul++;
ulRegData = *pul++;
BaseAddrSelect = ulRegAddr >> 29;
if(BaseAddrSelect == 0)
{
//
// the offset is from the start of the control registers
//
pulReg = (PULONG)((ULONG_PTR)pCtrlRegs + (ulRegAddr & 0x3FFFFF));
//
// we only care above these registers
//
if ( ( pulReg != BOOT_ADDRESS ) && (pulReg != MEM_CONFIG) )
{
continue;
}
}
else
{
DEBUG_PRINT((2, "VerifyBiosSettings: Invalid base address select %d regAddr = %d regData = %d\n",
BaseAddrSelect, ulRegAddr, ulRegData));
continue;
}
if( ulRegData != VideoPortReadRegisterUlong(pulReg) )
{
DEBUG_PRINT((1, "VerifyBiosSettings: Bios failed to set some registers correctly. \n"));
return (FALSE);
}
}
return (TRUE);
}
LONG
GetBiosVersion (
PHW_DEVICE_EXTENSION hwDeviceExtension,
OUT PWSTR BiosVersionString
)
/*++
Routine Description:
this function get the bios version and convert it to a unicode string
Return:
lenth of bios version string in bytes
--*/
{
PVOID pvROMAddress;
ULONG len, ulVersion;
PCHAR pByte;
BiosVersionString[0] = L'\0' ;
//
// just return on NT4
//
if( hwDeviceExtension->NtVersion == NT4 )
{
return 0;
}
//
// bios version is stored at offset 7 and 8
//
pvROMAddress = VideoPortGetRomImage( hwDeviceExtension,
NULL,
0,
7 + 2 );
if( pvROMAddress == NULL )
{
DEBUG_PRINT((1, "GetBiosVersion: Can not access ROM\n"));
return 0;
}
else if ( *(USHORT *)pvROMAddress != 0xAA55)
{
DEBUG_PRINT(( 2, "GetBiosVersion: ROM Signature 0x%x is invalid\n",
*(USHORT *)pvROMAddress ));
return 0;
}
pByte = ( PCHAR ) pvROMAddress;
//
// get major version number at offset 7
//
ulVersion = (ULONG) pByte[7];
len = IntergerToUnicode( ulVersion, (PWSTR) (&BiosVersionString[0]));
//
// a dot between major and minor version number
//
BiosVersionString[len] = L'.' ;
len++;
//
// get minor version number at offset 8
//
ulVersion = (ULONG) pByte[8];
len = len + IntergerToUnicode( ulVersion, (PWSTR) (&BiosVersionString[len]) );
//
// len is the number of unicodes in string, we need to return
// the string size in bytes
//
return (len * sizeof(WCHAR) );
}
LONG
IntergerToUnicode(
IN ULONG Number,
OUT PWSTR UnicodeString
)
/*++
Routine Description:
this function convert an unsigned long to a unicode string
Return:
the number of the unicodes in UnicodeString
--*/
{
const WCHAR digits[] = L"0123456789";
LONG i, len;
//
// a ULONG decimal integer will not exceed 10 digits
//
WCHAR tmpString[10];
i = 10;
len = 0;
do
{
tmpString[--i] = digits[ Number % 10 ];
Number /= 10;
len++;
} while ( Number );
VideoPortMoveMemory(UnicodeString, &tmpString[i], sizeof(WCHAR) * len );
UnicodeString[len] = L'\0' ;
return( len );
}