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.
3004 lines
92 KiB
3004 lines
92 KiB
//***************************************************************************
|
|
//
|
|
// Module Name:
|
|
//
|
|
// permedia.c
|
|
//
|
|
// Abstract:
|
|
//
|
|
// This module contains the code that implements the Permedia2 miniport driver
|
|
//
|
|
// 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"
|
|
|
|
#include "string.h"
|
|
|
|
#define USE_SINGLE_CYCLE_BLOCK_WRITES 0
|
|
|
|
#if defined(ALLOC_PRAGMA)
|
|
#pragma alloc_text(PAGE,DriverEntry)
|
|
#pragma alloc_text(PAGE,Permedia2FindAdapter)
|
|
#pragma alloc_text(PAGE,Permedia2RegistryCallback)
|
|
#pragma alloc_text(PAGE,Permedia2RetrieveGammaCallback)
|
|
#pragma alloc_text(PAGE,InitializeAndSizeRAM)
|
|
#pragma alloc_text(PAGE,ConstructValidModesList)
|
|
#pragma alloc_text(PAGE,Permedia2Initialize)
|
|
#pragma alloc_text(PAGE,Permedia2StartIO)
|
|
#pragma alloc_text(PAGE,Permedia2SetColorLookup)
|
|
#pragma alloc_text(PAGE,Permedia2GetClockSpeeds)
|
|
#pragma alloc_text(PAGE,ZeroMemAndDac)
|
|
#endif
|
|
|
|
//
|
|
// NtVersion: NT4 - This driver is working on NT4
|
|
// WIN2K - This driver is working on Windows 2000
|
|
//
|
|
|
|
short NtVersion;
|
|
|
|
ULONG
|
|
DriverEntry (
|
|
PVOID Context1,
|
|
PVOID Context2
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is the initial entry point to the video miniport driver.
|
|
|
|
This routine is called by the I/O subsystem when the video miniport
|
|
is loaded. The miniport is responsible for initializing a
|
|
VIDEO_HW_INITIALIZATION_DATA structure to register the driver functions
|
|
called by the video port driver in response to requests from the display
|
|
driver, plug and play manager, power management, or other driver
|
|
components.
|
|
|
|
The following tasks MUST be completed by the video miniport in the
|
|
context of DriverEntry. Driver writers should consult the documentation
|
|
for full details on the exact initialization process.
|
|
|
|
1. Initialize VIDEO_HW_INITIALIZATION_DATA structure with all relevant
|
|
data structures.
|
|
|
|
2. Call VideoPortInitialize.
|
|
|
|
3. Return appropriate status value to the caller of DriverEntry.
|
|
|
|
Drivers can undertake other tasks as required and under the restrictions
|
|
outlined in the documentation.
|
|
|
|
Arguments:
|
|
|
|
Context1 - First context value passed by the operating system. This is
|
|
the value with which the miniport driver calls VideoPortInitialize().
|
|
|
|
Context2 - Second context value passed by the operating system. This is
|
|
the value with which the miniport driver calls VideoPortInitialize().
|
|
|
|
Return Value:
|
|
|
|
Status from VideoPortInitialize()
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
VIDEO_HW_INITIALIZATION_DATA hwInitData;
|
|
VP_STATUS initializationStatus;
|
|
|
|
//
|
|
// Zero out structure.
|
|
//
|
|
|
|
VideoPortZeroMemory(&hwInitData, sizeof(VIDEO_HW_INITIALIZATION_DATA));
|
|
|
|
//
|
|
// Specify sizes of structure and extension.
|
|
//
|
|
|
|
hwInitData.HwInitDataSize = sizeof(VIDEO_HW_INITIALIZATION_DATA);
|
|
|
|
//
|
|
// Set entry points.
|
|
//
|
|
|
|
hwInitData.HwFindAdapter = Permedia2FindAdapter;
|
|
hwInitData.HwInitialize = Permedia2Initialize;
|
|
hwInitData.HwStartIO = Permedia2StartIO;
|
|
hwInitData.HwResetHw = Permedia2ResetHW;
|
|
hwInitData.HwInterrupt = Permedia2VidInterrupt;
|
|
hwInitData.HwGetPowerState = Permedia2GetPowerState;
|
|
hwInitData.HwSetPowerState = Permedia2SetPowerState;
|
|
hwInitData.HwGetVideoChildDescriptor = Permedia2GetChildDescriptor;
|
|
|
|
//
|
|
// Declare the legacy resources
|
|
//
|
|
|
|
hwInitData.HwLegacyResourceList = P2LegacyResourceList;
|
|
hwInitData.HwLegacyResourceCount = P2LegacyResourceEntries;
|
|
|
|
//
|
|
// Determine the size we require for the device extension.
|
|
//
|
|
|
|
hwInitData.HwDeviceExtensionSize = sizeof(HW_DEVICE_EXTENSION);
|
|
|
|
//
|
|
// This device only supports the PCI bus.
|
|
//
|
|
|
|
hwInitData.AdapterInterfaceType = PCIBus;
|
|
|
|
NtVersion = WIN2K;
|
|
|
|
initializationStatus = VideoPortInitialize(Context1,
|
|
Context2,
|
|
&hwInitData,
|
|
NULL);
|
|
|
|
if( initializationStatus != NO_ERROR)
|
|
{
|
|
hwInitData.HwInitDataSize = SIZE_OF_W2K_VIDEO_HW_INITIALIZATION_DATA;
|
|
initializationStatus = VideoPortInitialize(Context1,
|
|
Context2,
|
|
&hwInitData,
|
|
NULL);
|
|
}
|
|
|
|
if( initializationStatus != NO_ERROR)
|
|
{
|
|
NtVersion = NT4;
|
|
hwInitData.HwInterrupt = NULL;
|
|
|
|
hwInitData.HwInitDataSize = SIZE_OF_NT4_VIDEO_HW_INITIALIZATION_DATA;
|
|
initializationStatus = VideoPortInitialize(Context1,
|
|
Context2,
|
|
&hwInitData,
|
|
NULL);
|
|
}
|
|
|
|
DEBUG_PRINT((2, "PERM2: VideoPortInitialize returned status 0x%x\n", initializationStatus));
|
|
|
|
return initializationStatus;
|
|
|
|
} // end DriverEntry()
|
|
|
|
|
|
VP_STATUS
|
|
Permedia2FindAdapter(
|
|
PVOID HwDeviceExtension,
|
|
PVOID pReserved,
|
|
PWSTR ArgumentString,
|
|
PVIDEO_PORT_CONFIG_INFO ConfigInfo,
|
|
PUCHAR Again
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
This routine gets the access ranges for a device on an enumerable
|
|
bus and, if necessary, determines the device type
|
|
|
|
Arguments:
|
|
|
|
HwDeviceExtension -
|
|
System supplied device extension supplied to the miniport for
|
|
a per-device storage area.
|
|
|
|
pReserved -
|
|
NULL on Windows 2000 and should be ignored by the miniport.
|
|
|
|
ArgumentString -
|
|
Suuplies a NULL terminated ASCII string. This string originates
|
|
from the user. This pointer can be NULL.
|
|
|
|
ConfigInfo -
|
|
Points to a VIDEO_PORT_CONFIG_INFO structure allocated and initialized
|
|
by the port driver. This structure will contain as much information
|
|
as could be obtained by the port driver. This routine is responsible
|
|
for filling in any relevant missing information.
|
|
|
|
Again - Is not used on Windows 2000.
|
|
We set this to FALSE on NT 4, since we only support one adapter on NT4.
|
|
|
|
Return Value:
|
|
|
|
This routine must return:
|
|
|
|
NO_ERROR -
|
|
Indicates that the routine completed without error.
|
|
|
|
ERROR_INVALID_PARAMETER -
|
|
Indicates that the adapter could not be properly configured or
|
|
information was inconsistent. (NOTE: This does not mean that the
|
|
adapter could not be initialized. Miniports must not attempt to
|
|
initialize the adapter until HwVidInitialize.)
|
|
|
|
ERROR_DEV_NOT_EXIST - Indicates no host adapter was found for the
|
|
supplied configuration information.
|
|
|
|
--*/
|
|
|
|
{
|
|
PHW_DEVICE_EXTENSION hwDeviceExtension = HwDeviceExtension;
|
|
P2_DECL_VARS;
|
|
WCHAR StringBuffer[60];
|
|
ULONG StringLength;
|
|
VP_STATUS vpStatus;
|
|
ULONG UseSoftwareCursor;
|
|
ULONG ulValue;
|
|
ULONG i;
|
|
VIDEO_ACCESS_RANGE *pciAccessRange = hwDeviceExtension->PciAccessRange;
|
|
PWSTR pwszChip, pwszDAC, pwszAdapterString;
|
|
ULONG cbChip, cbDAC, cbAdapterString, cbBiosString;
|
|
ULONG pointerCaps;
|
|
USHORT usData;
|
|
|
|
//
|
|
// 3 (major number) + 1 (dot) + 3 (minor number) + 1 (L'\0') = 8 digtis
|
|
// is enough for bios verions string
|
|
//
|
|
|
|
WCHAR pwszBiosString[8];
|
|
|
|
//
|
|
// save current NT version obtained at DriverEntry
|
|
//
|
|
|
|
hwDeviceExtension->NtVersion = NtVersion;
|
|
|
|
//
|
|
// Make sure the size of the structure is at least as large as what we
|
|
// are expecting (check version of the config info structure).
|
|
//
|
|
|
|
if ( (NtVersion == WIN2K) &&
|
|
(ConfigInfo->Length < sizeof(VIDEO_PORT_CONFIG_INFO)) )
|
|
{
|
|
|
|
DEBUG_PRINT((1, "bad size for VIDEO_PORT_CONFIG_INFO\n"));
|
|
|
|
return (ERROR_INVALID_PARAMETER);
|
|
|
|
}
|
|
else if ( (NtVersion == NT4) &&
|
|
(ConfigInfo->Length < SIZE_OF_NT4_VIDEO_PORT_CONFIG_INFO) )
|
|
{
|
|
|
|
DEBUG_PRINT((1, "bad size for VIDEO_PORT_CONFIG_INFO\n"));
|
|
|
|
return (ERROR_INVALID_PARAMETER);
|
|
|
|
}
|
|
|
|
//
|
|
// we must be a PCI device
|
|
//
|
|
|
|
if (ConfigInfo->AdapterInterfaceType != PCIBus)
|
|
{
|
|
DEBUG_PRINT((1, "not a PCI device\n"));
|
|
return (ERROR_DEV_NOT_EXIST);
|
|
}
|
|
|
|
//
|
|
// Retrieve pointers of those new video port functions in Win2k.
|
|
// If you don't want to support NT4, you don't need to do this. You
|
|
// can just call these functions by their name.
|
|
//
|
|
|
|
if ( NtVersion == WIN2K )
|
|
{
|
|
|
|
if(!(hwDeviceExtension->Win2kVideoPortGetRomImage =
|
|
ConfigInfo->VideoPortGetProcAddress( hwDeviceExtension,
|
|
"VideoPortGetRomImage")))
|
|
{
|
|
return (ERROR_DEV_NOT_EXIST);
|
|
}
|
|
|
|
if(!(hwDeviceExtension->Win2kVideoPortGetCommonBuffer =
|
|
ConfigInfo->VideoPortGetProcAddress( hwDeviceExtension,
|
|
"VideoPortGetCommonBuffer")))
|
|
{
|
|
return (ERROR_DEV_NOT_EXIST);
|
|
}
|
|
|
|
if(!(hwDeviceExtension->Win2kVideoPortFreeCommonBuffer =
|
|
ConfigInfo->VideoPortGetProcAddress( hwDeviceExtension,
|
|
"VideoPortFreeCommonBuffer")))
|
|
{
|
|
return (ERROR_DEV_NOT_EXIST);
|
|
}
|
|
|
|
if(!(hwDeviceExtension->Win2kVideoPortDDCMonitorHelper =
|
|
ConfigInfo->VideoPortGetProcAddress( hwDeviceExtension,
|
|
"VideoPortDDCMonitorHelper")))
|
|
{
|
|
return (ERROR_DEV_NOT_EXIST);
|
|
}
|
|
|
|
if(!(hwDeviceExtension->Win2kVideoPortInterlockedExchange =
|
|
ConfigInfo->VideoPortGetProcAddress( hwDeviceExtension,
|
|
"VideoPortInterlockedExchange")))
|
|
{
|
|
return (ERROR_DEV_NOT_EXIST);
|
|
}
|
|
|
|
if(!(hwDeviceExtension->Win2kVideoPortGetVgaStatus =
|
|
ConfigInfo->VideoPortGetProcAddress( hwDeviceExtension,
|
|
"VideoPortGetVgaStatus")))
|
|
{
|
|
return (ERROR_DEV_NOT_EXIST);
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
|
|
//
|
|
// We only support one adapter on NT 4
|
|
//
|
|
|
|
Again = FALSE;
|
|
}
|
|
|
|
//
|
|
// will be initialized in CopyROMInitializationTable
|
|
//
|
|
|
|
hwDeviceExtension->culTableEntries = 0;
|
|
|
|
//
|
|
// will be initialized in ConstructValidModesList
|
|
//
|
|
|
|
hwDeviceExtension->pFrequencyDefault = NULL;
|
|
|
|
//
|
|
// We'll set this TRUE when in InitializeVideo after programming the VTG
|
|
//
|
|
|
|
hwDeviceExtension->bVTGRunning = FALSE;
|
|
hwDeviceExtension->bMonitorPoweredOn = TRUE;
|
|
hwDeviceExtension->ChipClockSpeed = 0;
|
|
hwDeviceExtension->RefClockSpeed = 0;
|
|
hwDeviceExtension->P28bppRGB = 0;
|
|
hwDeviceExtension->ExportNon3DModes = 0;
|
|
hwDeviceExtension->PreviousPowerState = VideoPowerOn;
|
|
|
|
//
|
|
// pick up capabilities on the way.
|
|
//
|
|
|
|
hwDeviceExtension->Capabilities = CAPS_GLYPH_EXPAND;
|
|
|
|
//
|
|
// We'll use a software pointer in all modes if the user sets
|
|
// the correct entry in the registry.
|
|
//
|
|
|
|
UseSoftwareCursor = 0;
|
|
|
|
vpStatus = VideoPortGetRegistryParameters( HwDeviceExtension,
|
|
L"UseSoftwareCursor",
|
|
FALSE,
|
|
Permedia2RegistryCallback,
|
|
&UseSoftwareCursor);
|
|
|
|
if ( ( vpStatus == NO_ERROR ) && UseSoftwareCursor)
|
|
{
|
|
hwDeviceExtension->Capabilities |= CAPS_SW_POINTER;
|
|
}
|
|
|
|
//
|
|
// Query the PCI to see if any of our supported chip devices exist.
|
|
//
|
|
|
|
if ( NtVersion == WIN2K )
|
|
{
|
|
if (!Permedia2AssignResources( HwDeviceExtension,
|
|
ConfigInfo,
|
|
PCI_TYPE0_ADDRESSES + 1,
|
|
pciAccessRange ))
|
|
{
|
|
DEBUG_PRINT((1, "Permedia2AssignResources failed\n"));
|
|
return (ERROR_DEV_NOT_EXIST);
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
if (!Permedia2AssignResourcesNT4( HwDeviceExtension,
|
|
ConfigInfo,
|
|
PCI_TYPE0_ADDRESSES + 1,
|
|
pciAccessRange ))
|
|
{
|
|
DEBUG_PRINT((1, "Permedia2AssignResources failed\n"));
|
|
return (ERROR_DEV_NOT_EXIST);
|
|
}
|
|
|
|
}
|
|
|
|
//
|
|
// construct the identifier string including the revision id
|
|
//
|
|
|
|
StringLength = sizeof(L"3Dlabs PERMEDIA2");
|
|
|
|
VideoPortMoveMemory((PVOID)StringBuffer,
|
|
(PVOID)(L"3Dlabs PERMEDIA2"),
|
|
StringLength);
|
|
|
|
pwszChip = (PWSTR)StringBuffer;
|
|
cbChip = StringLength;
|
|
|
|
//
|
|
// Set the defaults for the board type.
|
|
//
|
|
|
|
hwDeviceExtension->deviceInfo.BoardId = PERMEDIA2_BOARD;
|
|
|
|
pwszAdapterString = L"Permedia 2";
|
|
cbAdapterString = sizeof(L"Permedia 2");
|
|
|
|
//
|
|
// Get the mapped addresses for the control registers and the
|
|
// framebuffer. Must use local variable pCtrlRegs so macro
|
|
// declarations further down will work.
|
|
//
|
|
|
|
pCtrlRegs = VideoPortGetDeviceBase(
|
|
HwDeviceExtension,
|
|
pciAccessRange[PCI_CTRL_BASE_INDEX].RangeStart,
|
|
pciAccessRange[PCI_CTRL_BASE_INDEX].RangeLength,
|
|
pciAccessRange[PCI_CTRL_BASE_INDEX].RangeInIoSpace
|
|
);
|
|
|
|
if (pCtrlRegs == NULL)
|
|
{
|
|
DEBUG_PRINT((1, "CTRL DeviceBase mapping failed\n"));
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
hwDeviceExtension->ctrlRegBase = pCtrlRegs;
|
|
|
|
//
|
|
// Some boards have a ROM which we can use to identify them.
|
|
//
|
|
|
|
CopyROMInitializationTable(hwDeviceExtension);
|
|
|
|
|
|
if(hwDeviceExtension->culTableEntries == 0)
|
|
{
|
|
//
|
|
// No initialization table, but P2 really needs one in order to come
|
|
// out of sleep mode correctly. Generate initialization table by
|
|
// default values
|
|
//
|
|
|
|
GenerateInitializationTable(hwDeviceExtension);
|
|
}
|
|
|
|
|
|
//
|
|
// Find out what type of RAMDAC we have.
|
|
//
|
|
|
|
vpStatus = NO_ERROR;
|
|
|
|
hwDeviceExtension->pRamdac = &(pCtrlRegs->ExternalVideo);
|
|
|
|
//
|
|
// some RAMDACs may not support a cursor so a software cursor is the default
|
|
//
|
|
|
|
pointerCaps = CAPS_SW_POINTER;
|
|
|
|
//
|
|
// Check for a TI TVP4020
|
|
//
|
|
|
|
if(DEVICE_FAMILY_ID(hwDeviceExtension->deviceInfo.DeviceId) == PERMEDIA_P2S_ID)
|
|
{
|
|
//
|
|
// P2 with 3Dlabs RAMDAC, check for a rev 2 chip
|
|
//
|
|
|
|
i = VideoPortReadRegisterUlong(CHIP_CONFIG);
|
|
|
|
if(i & 0x40000000)
|
|
{
|
|
DEBUG_PRINT((2, "PERM2: Permedia2 is rev 2\n"));
|
|
hwDeviceExtension->deviceInfo.RevisionId = 2;
|
|
}
|
|
else
|
|
{
|
|
DEBUG_PRINT((2, "PERM2: Permedia2 is rev 1\n"));
|
|
}
|
|
|
|
hwDeviceExtension->DacId = P2RD_RAMDAC;
|
|
pointerCaps = (ULONG)CAPS_P2RD_POINTER;
|
|
|
|
hwDeviceExtension->deviceInfo.ActualDacId = P2RD_RAMDAC;
|
|
|
|
pwszDAC = L"3Dlabs P2RD";
|
|
cbDAC = sizeof(L"3Dlabs P2RD");
|
|
|
|
DEBUG_PRINT((1, "PERM2: using P2RD RAMDAC\n"));
|
|
}
|
|
else
|
|
{
|
|
hwDeviceExtension->DacId = TVP4020_RAMDAC;
|
|
pointerCaps = CAPS_TVP4020_POINTER;
|
|
|
|
hwDeviceExtension->deviceInfo.ActualDacId = TVP4020_RAMDAC;
|
|
|
|
if(hwDeviceExtension->deviceInfo.RevisionId == PERMEDIA2A_REV_ID)
|
|
{
|
|
pwszDAC = L"TI TVP4020A";
|
|
cbDAC = sizeof(L"TI TVP4020A");
|
|
DEBUG_PRINT((1, "PERM2: using TVP4020A RAMDAC\n"));
|
|
}
|
|
else
|
|
{
|
|
pwszDAC = L"TI TVP4020C";
|
|
cbDAC = sizeof(L"TI TVP4020C");
|
|
DEBUG_PRINT((1, "PERM2: using TVP4020C RAMDAC\n"));
|
|
}
|
|
}
|
|
|
|
//
|
|
// use the RAMDAC cursor capability only if the user didn't specify
|
|
// a software cursor
|
|
//
|
|
|
|
if (!(hwDeviceExtension->Capabilities & CAPS_SW_POINTER))
|
|
{
|
|
hwDeviceExtension->Capabilities |= pointerCaps;
|
|
}
|
|
|
|
hwDeviceExtension->PhysicalFrameIoSpace =
|
|
pciAccessRange[PCI_FB_BASE_INDEX].RangeInIoSpace |
|
|
VIDEO_MEMORY_SPACE_P6CACHE;
|
|
|
|
if ( (hwDeviceExtension->pFramebuffer =
|
|
VideoPortGetDeviceBase(
|
|
HwDeviceExtension,
|
|
pciAccessRange[PCI_FB_BASE_INDEX].RangeStart,
|
|
pciAccessRange[PCI_FB_BASE_INDEX].RangeLength,
|
|
(UCHAR) hwDeviceExtension->PhysicalFrameIoSpace
|
|
) ) == NULL)
|
|
{
|
|
|
|
//
|
|
// Some machines have limitations on how much PCI address space they
|
|
// can map in so try again, reducing the amount we map till we succeed
|
|
// or the size gets to zero in which case we really have failed.
|
|
//
|
|
|
|
ULONG sz;
|
|
|
|
DEBUG_PRINT((1, "PERM2: FB DeviceBase mapping failed\n"));
|
|
|
|
for ( sz = pciAccessRange[PCI_FB_BASE_INDEX].RangeLength;
|
|
sz > 0;
|
|
sz -= 1024*1024 )
|
|
{
|
|
|
|
if ( (hwDeviceExtension->pFramebuffer =
|
|
VideoPortGetDeviceBase(
|
|
HwDeviceExtension,
|
|
pciAccessRange[PCI_FB_BASE_INDEX].RangeStart,
|
|
sz,
|
|
(UCHAR) hwDeviceExtension->PhysicalFrameIoSpace
|
|
) ) != NULL)
|
|
{
|
|
|
|
//
|
|
// store the modified size
|
|
//
|
|
|
|
pciAccessRange[PCI_FB_BASE_INDEX].RangeLength = sz;
|
|
|
|
break;
|
|
|
|
}
|
|
}
|
|
|
|
//
|
|
// if sz is zero, well we tried ...
|
|
//
|
|
|
|
if (sz == 0)
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
DEBUG_PRINT((1, "PERM2: FB mapped at 0x%x for length 0x%x (%s)\n",
|
|
hwDeviceExtension->pFramebuffer,
|
|
pciAccessRange[PCI_FB_BASE_INDEX].RangeLength,
|
|
pciAccessRange[PCI_FB_BASE_INDEX].RangeInIoSpace ?
|
|
"I/O Ports" : "MemMapped"));
|
|
|
|
|
|
//
|
|
// Initialize the RAM registers and dynamically size the framebuffer
|
|
//
|
|
|
|
if (!InitializeAndSizeRAM(hwDeviceExtension, pciAccessRange))
|
|
{
|
|
DEBUG_PRINT((0, "InitializeAndSizeRAM failed\n"));
|
|
return ERROR_DEV_NOT_EXIST;
|
|
}
|
|
|
|
//
|
|
// Record the size of the video memory.
|
|
//
|
|
|
|
hwDeviceExtension->AdapterMemorySize =
|
|
pciAccessRange[PCI_FB_BASE_INDEX].RangeLength;
|
|
|
|
|
|
#if defined(_ALPHA_)
|
|
|
|
//
|
|
// We want to use a dense space mapping of the frame buffer
|
|
// whenever we can on the Alpha.
|
|
//
|
|
|
|
hwDeviceExtension->PhysicalFrameIoSpace = 4;
|
|
|
|
//
|
|
// The new DeskStation Alpha machines don't always support
|
|
// dense space. Therefore, we should try to map the memory
|
|
// at this point as a test. If the mapping succeeds then
|
|
// we can use dense space, otherwise we'll use sparse space.
|
|
//
|
|
|
|
{
|
|
PULONG MappedSpace=0;
|
|
VP_STATUS status;
|
|
|
|
DEBUG_PRINT((1, "PERM2: Checking to see if we can use dense space...\n"));
|
|
|
|
//
|
|
// We want to try to map the dense memory where it will ultimately
|
|
// be mapped anyway.
|
|
//
|
|
|
|
MappedSpace = (PULONG)VideoPortGetDeviceBase (
|
|
hwDeviceExtension,
|
|
pciAccessRange[PCI_FB_BASE_INDEX].RangeStart,
|
|
pciAccessRange[PCI_FB_BASE_INDEX].RangeLength,
|
|
(UCHAR) hwDeviceExtension->PhysicalFrameIoSpace
|
|
);
|
|
|
|
if (MappedSpace == NULL)
|
|
{
|
|
//
|
|
// Well, looks like we can't use dense space to map the
|
|
// range. Lets use sparse space, and let the display
|
|
// driver know.
|
|
//
|
|
|
|
DEBUG_PRINT((1, "PERM2: Can't use dense space!\n"));
|
|
|
|
hwDeviceExtension->PhysicalFrameIoSpace = 0;
|
|
|
|
hwDeviceExtension->Capabilities |= CAPS_SPARSE_SPACE;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// The mapping worked. However, we were only mapping to
|
|
// see if dense space was supported. Free the memory.
|
|
//
|
|
|
|
DEBUG_PRINT((1, "PERM2: We can use dense space.\n"));
|
|
|
|
VideoPortFreeDeviceBase(hwDeviceExtension,
|
|
MappedSpace);
|
|
}
|
|
}
|
|
|
|
#endif // defined(_ALPHA_)
|
|
|
|
//
|
|
// We now have a complete hardware description of the hardware.
|
|
// Save the information to the registry so it can be used by
|
|
// configuration programs - such as the display applet.
|
|
//
|
|
|
|
VideoPortSetRegistryParameters(HwDeviceExtension,
|
|
L"HardwareInformation.ChipType",
|
|
pwszChip,
|
|
cbChip);
|
|
|
|
VideoPortSetRegistryParameters(HwDeviceExtension,
|
|
L"HardwareInformation.DacType",
|
|
pwszDAC,
|
|
cbDAC);
|
|
|
|
VideoPortSetRegistryParameters(HwDeviceExtension,
|
|
L"HardwareInformation.MemorySize",
|
|
&hwDeviceExtension->AdapterMemorySize,
|
|
sizeof(ULONG));
|
|
|
|
VideoPortSetRegistryParameters(HwDeviceExtension,
|
|
L"HardwareInformation.AdapterString",
|
|
pwszAdapterString,
|
|
cbAdapterString);
|
|
|
|
cbBiosString = GetBiosVersion(HwDeviceExtension, (PWSTR) pwszBiosString);
|
|
|
|
VideoPortSetRegistryParameters(HwDeviceExtension,
|
|
L"HardwareInformation.BiosString",
|
|
pwszBiosString,
|
|
cbBiosString);
|
|
|
|
ConstructValidModesList(HwDeviceExtension, hwDeviceExtension);
|
|
|
|
if (hwDeviceExtension->NumAvailableModes == 0)
|
|
{
|
|
DEBUG_PRINT((1, "No video modes available\n"));
|
|
|
|
return(ERROR_DEV_NOT_EXIST);
|
|
}
|
|
|
|
//
|
|
// Frame buffer information
|
|
//
|
|
|
|
hwDeviceExtension->PhysicalFrameAddress =
|
|
pciAccessRange[PCI_FB_BASE_INDEX].RangeStart;
|
|
|
|
hwDeviceExtension->FrameLength =
|
|
pciAccessRange[PCI_FB_BASE_INDEX].RangeLength;
|
|
|
|
//
|
|
// Control Register information
|
|
// Get the base address, starting at zero and map all registers
|
|
//
|
|
|
|
hwDeviceExtension->PhysicalRegisterAddress =
|
|
pciAccessRange[PCI_CTRL_BASE_INDEX].RangeStart;
|
|
|
|
hwDeviceExtension->RegisterLength =
|
|
pciAccessRange[PCI_CTRL_BASE_INDEX].RangeLength;
|
|
|
|
hwDeviceExtension->RegisterSpace =
|
|
pciAccessRange[PCI_CTRL_BASE_INDEX].RangeInIoSpace;
|
|
|
|
ConfigInfo->VdmPhysicalVideoMemoryAddress.LowPart = 0x000A0000;
|
|
ConfigInfo->VdmPhysicalVideoMemoryAddress.HighPart = 0x00000000;
|
|
ConfigInfo->VdmPhysicalVideoMemoryLength = 0x00020000;
|
|
|
|
|
|
//
|
|
// Clear out the Emulator entries and the state size since this driver
|
|
// does not support them.
|
|
//
|
|
|
|
ConfigInfo->NumEmulatorAccessEntries = 0;
|
|
ConfigInfo->EmulatorAccessEntries = NULL;
|
|
ConfigInfo->EmulatorAccessEntriesContext = 0;
|
|
|
|
//
|
|
// This driver does not do SAVE/RESTORE of hardware state.
|
|
//
|
|
|
|
ConfigInfo->HardwareStateSize = 0;
|
|
|
|
//
|
|
// in a multi-adapter system we'll need to disable VGA for the
|
|
// secondary adapters
|
|
//
|
|
|
|
if(!hwDeviceExtension->bVGAEnabled)
|
|
{
|
|
DEBUG_PRINT((1, "PERM2: disabling VGA for the secondary card\n"));
|
|
|
|
//
|
|
// Enable graphics mode, disable VGA
|
|
//
|
|
|
|
VideoPortWriteRegisterUchar(PERMEDIA_MMVGA_INDEX_REG,
|
|
PERMEDIA_VGA_CTRL_INDEX);
|
|
|
|
usData = (USHORT)VideoPortReadRegisterUchar(PERMEDIA_MMVGA_DATA_REG);
|
|
usData &= ~PERMEDIA_VGA_ENABLE;
|
|
|
|
usData = (usData << 8) | PERMEDIA_VGA_CTRL_INDEX;
|
|
VideoPortWriteRegisterUshort(PERMEDIA_MMVGA_INDEX_REG, usData);
|
|
|
|
#define INTERNAL_VGA_ENABLE (1 << 1)
|
|
#define VGA_FIXED_ADD_DECODE (1 << 2)
|
|
|
|
ulValue = VideoPortReadRegisterUlong(CHIP_CONFIG);
|
|
ulValue &= ~INTERNAL_VGA_ENABLE;
|
|
ulValue &= ~VGA_FIXED_ADD_DECODE;
|
|
VideoPortWriteRegisterUlong(CHIP_CONFIG, ulValue);
|
|
|
|
}
|
|
|
|
//
|
|
// Indicate a successful completion status.
|
|
//
|
|
|
|
return NO_ERROR;
|
|
|
|
} // end Permedia2FindAdapter()
|
|
|
|
VOID
|
|
ConstructValidModesList(
|
|
PVOID HwDeviceExtension,
|
|
PHW_DEVICE_EXTENSION hwDeviceExtension
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Here we prune valid modes, based on rules according to the chip
|
|
capabilities and memory requirements.
|
|
|
|
We prune modes so that we will not annoy the user by presenting
|
|
modes in the 'Video Applet' which we know the user can't use.
|
|
|
|
Look up the registry to see if we want to export modes which can only
|
|
be used as single buffered by 3D applications. If we only want double
|
|
buffered modes then, effectively, we have only half the memory in
|
|
which to display the standard 2D resolution. This is only not true at 12bpp
|
|
where we can double buffer at any resolution.
|
|
|
|
--*/
|
|
{
|
|
PP2_VIDEO_FREQUENCIES FrequencyEntry;
|
|
PP2_VIDEO_MODES ModeEntry;
|
|
LONG AdapterMemorySize;
|
|
ULONG ModeIndex;
|
|
ULONG i;
|
|
|
|
hwDeviceExtension->NumAvailableModes = 0;
|
|
|
|
//
|
|
// Since there are a number of frequencies possible for each
|
|
// distinct resolution/colour depth, we cycle through the
|
|
// frequency table and find the appropriate mode entry for that
|
|
// frequency entry.
|
|
//
|
|
|
|
if (!BuildFrequencyList(hwDeviceExtension))
|
|
return;
|
|
|
|
for (FrequencyEntry = hwDeviceExtension->FrequencyTable, ModeIndex = 0;
|
|
FrequencyEntry->BitsPerPel != 0;
|
|
FrequencyEntry++, ModeIndex++)
|
|
{
|
|
|
|
//
|
|
// Find the mode for this entry. First, assume we won't find one.
|
|
//
|
|
|
|
FrequencyEntry->ModeValid = FALSE;
|
|
FrequencyEntry->ModeIndex = ModeIndex;
|
|
|
|
for (ModeEntry = P2Modes, i = 0; i < NumP2VideoModes; ModeEntry++, i++)
|
|
{
|
|
|
|
if ((FrequencyEntry->BitsPerPel ==
|
|
ModeEntry->ModeInformation.BitsPerPlane) &&
|
|
(FrequencyEntry->ScreenWidth ==
|
|
ModeEntry->ModeInformation.VisScreenWidth) &&
|
|
(FrequencyEntry->ScreenHeight ==
|
|
ModeEntry->ModeInformation.VisScreenHeight))
|
|
{
|
|
AdapterMemorySize = (LONG)hwDeviceExtension->AdapterMemorySize;
|
|
|
|
//
|
|
// We've found a mode table entry that matches this frequency
|
|
// table entry. Now we'll figure out if we can actually do
|
|
// this mode/frequency combination. For now, assume we'll
|
|
// succeed.
|
|
//
|
|
|
|
FrequencyEntry->ModeEntry = ModeEntry;
|
|
FrequencyEntry->ModeValid = TRUE;
|
|
|
|
ModeEntry->ModeInformation.ScreenStride =
|
|
ModeEntry->ScreenStrideContiguous;
|
|
|
|
//
|
|
// Rule: use true color at 8bpp if we've enabled that
|
|
// capability above.
|
|
//
|
|
|
|
if ((FrequencyEntry->BitsPerPel == 8) &&
|
|
(hwDeviceExtension->Capabilities & CAPS_8BPP_RGB))
|
|
{
|
|
ModeEntry->ModeInformation.AttributeFlags &=
|
|
~(VIDEO_MODE_PALETTE_DRIVEN | VIDEO_MODE_MANAGED_PALETTE);
|
|
|
|
//
|
|
// NB. These must match the way the palette is loaded in
|
|
// InitializeVideo.
|
|
//
|
|
|
|
ModeEntry->ModeInformation.RedMask = 0x07;
|
|
ModeEntry->ModeInformation.GreenMask = 0x38;
|
|
ModeEntry->ModeInformation.BlueMask = 0xc0;
|
|
}
|
|
|
|
//
|
|
// Rule: We have to have enough memory to handle the mode.
|
|
//
|
|
|
|
if ((LONG)(ModeEntry->ModeInformation.VisScreenHeight *
|
|
ModeEntry->ModeInformation.ScreenStride) >
|
|
AdapterMemorySize)
|
|
{
|
|
FrequencyEntry->ModeValid = FALSE;
|
|
}
|
|
|
|
{
|
|
ULONG pixelData;
|
|
ULONG DacDepth = FrequencyEntry->BitsPerPel;
|
|
|
|
//
|
|
// We need the proper pixel size to calculate timing values
|
|
//
|
|
|
|
if (DacDepth == 15)
|
|
{
|
|
DacDepth = 16;
|
|
}
|
|
else if (DacDepth == 12)
|
|
{
|
|
DacDepth = 32;
|
|
}
|
|
|
|
pixelData = FrequencyEntry->PixelClock * (DacDepth / 8);
|
|
|
|
if (((FrequencyEntry->PixelClock > P2_MAX_PIXELCLOCK ||
|
|
pixelData > P2_MAX_PIXELDATA)))
|
|
{
|
|
FrequencyEntry->ModeValid = FALSE;
|
|
}
|
|
|
|
//
|
|
// Don't supports 24bpp
|
|
//
|
|
|
|
if(FrequencyEntry->BitsPerPel == 24)
|
|
{
|
|
FrequencyEntry->ModeValid = FALSE;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Don't forget to count it if it's still a valid mode after
|
|
// applying all those rules.
|
|
//
|
|
|
|
if (FrequencyEntry->ModeValid)
|
|
{
|
|
if(hwDeviceExtension->pFrequencyDefault == NULL &&
|
|
ModeEntry->ModeInformation.BitsPerPlane == 8 &&
|
|
ModeEntry->ModeInformation.VisScreenWidth == 640 &&
|
|
ModeEntry->ModeInformation.VisScreenHeight == 480)
|
|
{
|
|
hwDeviceExtension->pFrequencyDefault = FrequencyEntry;
|
|
}
|
|
|
|
hwDeviceExtension->NumAvailableModes++;
|
|
}
|
|
|
|
//
|
|
// We've found a mode for this frequency entry, so we
|
|
// can break out of the mode loop:
|
|
//
|
|
|
|
break;
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
hwDeviceExtension->NumTotalModes = ModeIndex;
|
|
|
|
DEBUG_PRINT((2, "PERM2: %d total modes\n", ModeIndex));
|
|
DEBUG_PRINT((2, "PERM2: %d total valid modes\n", hwDeviceExtension->NumAvailableModes));
|
|
}
|
|
|
|
|
|
VP_STATUS
|
|
Permedia2RegistryCallback(
|
|
PVOID HwDeviceExtension,
|
|
PVOID Context,
|
|
PWSTR ValueName,
|
|
PVOID ValueData,
|
|
ULONG ValueLength
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is used to read back various registry values.
|
|
|
|
Arguments:
|
|
|
|
HwDeviceExtension - Supplies a pointer to the miniport's device extension.
|
|
|
|
Context - Context value passed to the get registry paramters routine. If
|
|
this is not null assume it's a ULONG* and save the data value in it.
|
|
|
|
ValueName - Name of the value requested.
|
|
|
|
ValueData - Pointer to the requested data.
|
|
|
|
ValueLength - Length of the requested data.
|
|
|
|
Return Value:
|
|
|
|
if the variable doesn't exist return an error,
|
|
else if a context is supplied assume it's a PULONG and fill in the value
|
|
and return no error, else if the value is non-zero return an error.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
if (ValueLength)
|
|
{
|
|
if (Context)
|
|
{
|
|
*(ULONG *)Context = *(PULONG)ValueData;
|
|
}
|
|
else if (*((PULONG)ValueData) != 0)
|
|
{
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
return NO_ERROR;
|
|
|
|
} else
|
|
{
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
} // end Permedia2RegistryCallback()
|
|
|
|
|
|
VP_STATUS
|
|
Permedia2RetrieveGammaCallback(
|
|
PVOID HwDeviceExtension,
|
|
PVOID Context,
|
|
PWSTR ValueName,
|
|
PVOID ValueData,
|
|
ULONG ValueLength
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is used to read back the gamma LUT from the registry.
|
|
|
|
Arguments:
|
|
|
|
HwDeviceExtension - Supplies a pointer to the miniport's device extension.
|
|
|
|
Context - Context value passed to the get registry paramters routine
|
|
|
|
ValueName - Name of the value requested.
|
|
|
|
ValueData - Pointer to the requested data.
|
|
|
|
ValueLength - Length of the requested data.
|
|
|
|
Return Value:
|
|
|
|
if the variable doesn't exist return an error, else copy the gamma lut
|
|
into the supplied pointer
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
if (ValueLength != MAX_CLUT_SIZE)
|
|
{
|
|
|
|
DEBUG_PRINT((1, "Permedia2RetrieveGammaCallback got ValueLength of %d\n", ValueLength));
|
|
|
|
return ERROR_INVALID_PARAMETER;
|
|
|
|
}
|
|
|
|
VideoPortMoveMemory(Context, ValueData, MAX_CLUT_SIZE);
|
|
|
|
return NO_ERROR;
|
|
|
|
} // end Permedia2RetrieveGammaCallback()
|
|
|
|
|
|
BOOLEAN
|
|
InitializeAndSizeRAM(
|
|
PHW_DEVICE_EXTENSION hwDeviceExtension,
|
|
PVIDEO_ACCESS_RANGE pciAccessRange
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Initialize extra control registers and dynamically size the
|
|
video RAM for the Permedia.
|
|
|
|
Arguments:
|
|
|
|
hwDeviceExtension - Supplies a pointer to the miniport's device extension.
|
|
pciAccessRange - access range of mapped resources
|
|
|
|
Return Value:
|
|
|
|
FALSE if we find no RAM, TRUE otherwise
|
|
|
|
--*/
|
|
|
|
{
|
|
PVOID HwDeviceExtension = (PVOID)hwDeviceExtension;
|
|
ULONG fbMappedSize;
|
|
ULONG i, j;
|
|
P2_DECL;
|
|
|
|
PULONG pV, pVStart, pVEnd;
|
|
ULONG testPattern;
|
|
ULONG probeSize;
|
|
ULONG save0, save1;
|
|
ULONG temp;
|
|
ULONG saveVidCtl;
|
|
USHORT saveVGA, usData;
|
|
|
|
|
|
if(hwDeviceExtension->culTableEntries)
|
|
{
|
|
//
|
|
// When vga is enabled, these registers should be set by bios at
|
|
// boot time. But we saw cases when bios failed to do this. We'll
|
|
// set these register when vga is off or when we see values are
|
|
// wrong
|
|
//
|
|
|
|
if(!hwDeviceExtension->bVGAEnabled ||
|
|
!VerifyBiosSettings(hwDeviceExtension))
|
|
{
|
|
//
|
|
// save video control and vga register
|
|
//
|
|
|
|
saveVidCtl = VideoPortReadRegisterUlong(VIDEO_CONTROL);
|
|
|
|
VideoPortWriteRegisterUchar( PERMEDIA_MMVGA_INDEX_REG,
|
|
PERMEDIA_VGA_CTRL_INDEX );
|
|
|
|
saveVGA = (USHORT)VideoPortReadRegisterUchar(
|
|
PERMEDIA_MMVGA_DATA_REG );
|
|
|
|
//
|
|
// Disable Video and VGA
|
|
//
|
|
|
|
VideoPortWriteRegisterUlong(VIDEO_CONTROL, 0);
|
|
|
|
usData = saveVGA & (USHORT)(~PERMEDIA_VGA_ENABLE);
|
|
usData = (usData << 8) | PERMEDIA_VGA_CTRL_INDEX;
|
|
VideoPortWriteRegisterUshort(PERMEDIA_MMVGA_INDEX_REG, usData);
|
|
|
|
ProcessInitializationTable(hwDeviceExtension);
|
|
|
|
#if USE_SINGLE_CYCLE_BLOCK_WRITES
|
|
{
|
|
|
|
i = VideoPortReadRegisterUlong(MEM_CONFIG);
|
|
|
|
VideoPortWriteRegisterUlong(MEM_CONFIG, i | (1 << 21)); // single cycle block writes
|
|
|
|
}
|
|
#endif //USE_SINGLE_CYCLE_BLOCK_WRITES
|
|
|
|
//
|
|
// Restore VGA and video control
|
|
//
|
|
|
|
saveVGA = (saveVGA << 8) | PERMEDIA_VGA_CTRL_INDEX;
|
|
VideoPortWriteRegisterUshort(PERMEDIA_MMVGA_INDEX_REG, saveVGA);
|
|
|
|
VideoPortWriteRegisterUlong(VIDEO_CONTROL, saveVidCtl);
|
|
|
|
}
|
|
}
|
|
|
|
|
|
VideoPortWriteRegisterUlong(APERTURE_ONE, 0x0);
|
|
VideoPortWriteRegisterUlong(APERTURE_TWO, 0x0);
|
|
|
|
VideoPortWriteRegisterUlong(BYPASS_WRITE_MASK, 0xFFFFFFFF);
|
|
|
|
if (pciAccessRange == NULL)
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
fbMappedSize = pciAccessRange[PCI_FB_BASE_INDEX].RangeLength;
|
|
|
|
i = VideoPortReadRegisterUlong(MEM_CONFIG);
|
|
|
|
//
|
|
// MEM_CONFIG doesn't have the number of memory banks defined
|
|
// at boot-time for P2: set up the board for 8MB. Can't do this
|
|
// if the VGA is running, but that's OK. The VGA has set this
|
|
// register to what we want.
|
|
//
|
|
|
|
if (!hwDeviceExtension->bVGAEnabled)
|
|
{
|
|
i |= (3 << 29);
|
|
|
|
pciAccessRange[PCI_FB_BASE_INDEX].RangeLength =
|
|
(((i >> 29) & 0x3) + 1) * (2*1024*1024);
|
|
|
|
VideoPortWriteRegisterUlong(MEM_CONFIG, i);
|
|
VideoPortStallExecution(10);
|
|
}
|
|
|
|
testPattern = 0x55aa33cc;
|
|
probeSize = (128 * 1024 / sizeof(ULONG)); // In DWords
|
|
|
|
//
|
|
// Dynamically size the SGRAM. Sample every 128K. If you happen to
|
|
// have some VERY odd SGRAM size you may need cut this down. After
|
|
// each write to the probe address, write to SGRAM address zero to
|
|
// clear the PCI data bus. Otherwise, if we read from fresh air the
|
|
// written value may be floating on the bus and the read give it back
|
|
// to us.
|
|
//
|
|
// Note, if the memory wraps around at the end, then a different
|
|
// algorithm must be used (which waits for address zero to become
|
|
// equal to the address being written).
|
|
//
|
|
// Any valid pixel that we probe, we save and restore. This is to
|
|
// avoid dots on the screen if we have booted onto the Permedia2 board.
|
|
//
|
|
|
|
pVStart = (PULONG)hwDeviceExtension->pFramebuffer;
|
|
pVEnd = (PULONG)((ULONG_PTR)pVStart + fbMappedSize);
|
|
|
|
//
|
|
// check out address zero
|
|
//
|
|
|
|
save0 = VideoPortReadRegisterUlong(pVStart);
|
|
save1 = VideoPortReadRegisterUlong(pVStart+1);
|
|
|
|
VideoPortWriteRegisterUlong(pVStart, testPattern);
|
|
VideoPortWriteRegisterUlong(pVStart+1, 0);
|
|
|
|
if ((temp = VideoPortReadRegisterUlong(pVStart)) != testPattern)
|
|
{
|
|
DEBUG_PRINT((1, "cannot access SGRAM. Expected 0x%x, got 0x%x\n",
|
|
testPattern, temp));
|
|
return FALSE;
|
|
}
|
|
|
|
VideoPortWriteRegisterUlong(pVStart+1, save1);
|
|
|
|
for (pV = pVStart + probeSize; pV < pVEnd; pV += probeSize)
|
|
{
|
|
save1 = VideoPortReadRegisterUlong(pV);
|
|
VideoPortWriteRegisterUlong(pV, testPattern);
|
|
VideoPortWriteRegisterUlong(pVStart, 0);
|
|
|
|
if ((temp = VideoPortReadRegisterUlong(pV)) != testPattern)
|
|
{
|
|
|
|
DEBUG_PRINT((1, "PERM2: FB probe failed at offset 0x%x\n",
|
|
(LONG)((LONG_PTR)pV - (LONG_PTR)pVStart)));
|
|
|
|
DEBUG_PRINT((1, "PERM2: \tread back 0x%x, wanted 0x%x\n",
|
|
temp, testPattern));
|
|
break;
|
|
}
|
|
|
|
VideoPortWriteRegisterUlong(pV, save1);
|
|
|
|
}
|
|
|
|
VideoPortWriteRegisterUlong(pVStart, save0);
|
|
|
|
if (pV < pVEnd)
|
|
{
|
|
//
|
|
// I could also set MEM_CONFIG to the correct value here as we
|
|
// now know the size of SGRAM, but as it's never used again
|
|
// I won't bother
|
|
//
|
|
|
|
pciAccessRange[PCI_FB_BASE_INDEX].RangeLength =
|
|
(ULONG)((ULONG_PTR)pV - (ULONG_PTR)pVStart);
|
|
|
|
DEBUG_PRINT((1, "PERM2: SGRAM dynamically resized to length 0x%x\n",
|
|
pciAccessRange[PCI_FB_BASE_INDEX].RangeLength));
|
|
|
|
}
|
|
|
|
if (pciAccessRange[PCI_FB_BASE_INDEX].RangeLength > fbMappedSize)
|
|
{
|
|
pciAccessRange[PCI_FB_BASE_INDEX].RangeLength = fbMappedSize;
|
|
}
|
|
|
|
DEBUG_PRINT((2, "PERM2: got a size of 0x%x bytes\n",
|
|
pciAccessRange[PCI_FB_BASE_INDEX].RangeLength));
|
|
|
|
//
|
|
// finally, if the SGRAM size is actually smaller than the region that
|
|
// we probed, remap to the smaller size to save on page table entries.
|
|
// Not doing this causes some systems to run out of PTEs.
|
|
//
|
|
|
|
if (fbMappedSize > pciAccessRange[PCI_FB_BASE_INDEX].RangeLength)
|
|
{
|
|
VideoPortFreeDeviceBase(HwDeviceExtension,
|
|
hwDeviceExtension->pFramebuffer);
|
|
|
|
if ( (hwDeviceExtension->pFramebuffer =
|
|
VideoPortGetDeviceBase(HwDeviceExtension,
|
|
pciAccessRange[PCI_FB_BASE_INDEX].RangeStart,
|
|
pciAccessRange[PCI_FB_BASE_INDEX].RangeLength,
|
|
(UCHAR) hwDeviceExtension->PhysicalFrameIoSpace)) == NULL)
|
|
{
|
|
|
|
//
|
|
// this shouldn't happen but we'd better check
|
|
//
|
|
|
|
DEBUG_PRINT((0, "Remap of framebuffer to smaller size failed!!!\n"));
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
DEBUG_PRINT((1, "PERM2: Remapped framebuffer memory to 0x%x, size 0x%x\n",
|
|
hwDeviceExtension->pFramebuffer,
|
|
pciAccessRange[PCI_FB_BASE_INDEX].RangeLength));
|
|
}
|
|
|
|
//
|
|
// PERMEDIA2 has no localbuffer
|
|
//
|
|
|
|
hwDeviceExtension->deviceInfo.LocalbufferWidth = 0;
|
|
hwDeviceExtension->deviceInfo.LocalbufferLength = 0;
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
BOOLEAN
|
|
Permedia2Initialize(
|
|
PVOID HwDeviceExtension
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine does one time initialization of the device.
|
|
|
|
Arguments:
|
|
|
|
HwDeviceExtension - Supplies a pointer to the miniport's device extension.
|
|
|
|
Return Value:
|
|
|
|
Returns TRUE when success.
|
|
|
|
--*/
|
|
|
|
{
|
|
PHW_DEVICE_EXTENSION hwDeviceExtension = HwDeviceExtension;
|
|
ULONG ulValue;
|
|
P2_DECL;
|
|
|
|
//
|
|
// always initialize the IRQ control block...
|
|
// the memory is used to store information which is global to all
|
|
// driver instances of a display card by the display driver
|
|
//
|
|
|
|
if ( hwDeviceExtension->NtVersion == WIN2K)
|
|
{
|
|
if (!Permedia2InitializeInterruptBlock(hwDeviceExtension))
|
|
{
|
|
|
|
DEBUG_PRINT((0, "PERM2: failed to initialize the IRQ control block\n"));
|
|
return FALSE;
|
|
|
|
}
|
|
}
|
|
|
|
//
|
|
// Clear the framebuffer.
|
|
//
|
|
|
|
VideoPortZeroDeviceMemory(hwDeviceExtension->pFramebuffer,
|
|
hwDeviceExtension->AdapterMemorySize);
|
|
|
|
return TRUE;
|
|
|
|
} // end Permedia2Initialize()
|
|
|
|
|
|
BOOLEAN
|
|
Permedia2StartIO(
|
|
PVOID HwDeviceExtension,
|
|
PVIDEO_REQUEST_PACKET RequestPacket
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is the main execution routine for the miniport driver. It
|
|
accepts a Video Request Packet, performs the request, and then returns
|
|
with the appropriate status.
|
|
|
|
Arguments:
|
|
|
|
HwDeviceExtension - Supplies a pointer to the miniport's device extension.
|
|
|
|
RequestPacket - Pointer to the video request packet. This structure
|
|
contains all the parameters passed to the VideoIoControl function.
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
|
|
{
|
|
PHW_DEVICE_EXTENSION hwDeviceExtension = HwDeviceExtension;
|
|
P2_DECL;
|
|
VP_STATUS status;
|
|
PVIDEO_MODE_INFORMATION modeInformation;
|
|
PVIDEO_MEMORY_INFORMATION memoryInformation;
|
|
PVIDEOPARAMETERS pVideoParams;
|
|
PVIDEO_CLUT clutBuffer;
|
|
ULONG inIoSpace;
|
|
ULONG RequestedMode;
|
|
ULONG modeNumber;
|
|
ULONG ulValue;
|
|
HANDLE ProcessHandle;
|
|
PP2_VIDEO_MODES ModeEntry;
|
|
P2_VIDEO_FREQUENCIES FrequencyEntry, *pFrequencyEntry;
|
|
VIDEO_X86_BIOS_ARGUMENTS biosArguments;
|
|
|
|
//
|
|
// Switch on the IoContolCode in the RequestPacket. It indicates which
|
|
// function must be performed by the driver.
|
|
//
|
|
|
|
switch (RequestPacket->IoControlCode)
|
|
{
|
|
|
|
case IOCTL_VIDEO_QUERY_REGISTRY_DWORD:
|
|
{
|
|
DEBUG_PRINT((2, "PERM2: got IOCTL_VIDEO_QUERY_REGISTRY_DWORD\n"));
|
|
|
|
if (RequestPacket->OutputBufferLength <
|
|
(RequestPacket->StatusBlock->Information = sizeof(ULONG)))
|
|
{
|
|
status = ERROR_INSUFFICIENT_BUFFER;
|
|
break;
|
|
}
|
|
|
|
if (VideoPortGetRegistryParameters( HwDeviceExtension,
|
|
RequestPacket->InputBuffer,
|
|
FALSE,
|
|
Permedia2RegistryCallback,
|
|
&ulValue) != NO_ERROR )
|
|
{
|
|
DEBUG_PRINT((1, "PERM2: IOCTL_VIDEO_QUERY_REGISTRY_DWORD failed\n"));
|
|
|
|
status = ERROR_INVALID_PARAMETER;
|
|
break;
|
|
}
|
|
|
|
*(PULONG)(RequestPacket->OutputBuffer) = ulValue;
|
|
|
|
status = NO_ERROR;
|
|
break;
|
|
}
|
|
|
|
case IOCTL_VIDEO_REG_SAVE_GAMMA_LUT:
|
|
{
|
|
DEBUG_PRINT((2, "PERM2: got IOCTL_VIDEO_REG_SAVE_GAMMA_LUT\n"));
|
|
|
|
if (RequestPacket->InputBufferLength <
|
|
(RequestPacket->StatusBlock->Information = MAX_CLUT_SIZE))
|
|
{
|
|
|
|
status = ERROR_INSUFFICIENT_BUFFER;
|
|
break;
|
|
|
|
}
|
|
|
|
status = VideoPortSetRegistryParameters( HwDeviceExtension,
|
|
L"DisplayGammaLUT",
|
|
RequestPacket->InputBuffer,
|
|
MAX_CLUT_SIZE);
|
|
break;
|
|
}
|
|
|
|
case IOCTL_VIDEO_REG_RETRIEVE_GAMMA_LUT:
|
|
{
|
|
DEBUG_PRINT((2, "PERM2: got IOCTL_VIDEO_REG_RETRIEVE_GAMMA_LUT\n"));
|
|
|
|
if (RequestPacket->OutputBufferLength <
|
|
(RequestPacket->StatusBlock->Information = MAX_CLUT_SIZE))
|
|
{
|
|
status = ERROR_INSUFFICIENT_BUFFER;
|
|
break;
|
|
}
|
|
|
|
status = VideoPortGetRegistryParameters( HwDeviceExtension,
|
|
L"DisplayGammaLUT",
|
|
FALSE,
|
|
Permedia2RetrieveGammaCallback,
|
|
RequestPacket->InputBuffer);
|
|
break;
|
|
}
|
|
|
|
case IOCTL_VIDEO_QUERY_DEVICE_INFO:
|
|
|
|
DEBUG_PRINT((1, "PERM2: Permedia2StartIO - QUERY_deviceInfo\n"));
|
|
|
|
if ( RequestPacket->OutputBufferLength <
|
|
(RequestPacket->StatusBlock->Information = sizeof(P2_Device_Info)))
|
|
|
|
{
|
|
status = ERROR_INSUFFICIENT_BUFFER;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Copy our local PCI info to the output buffer
|
|
//
|
|
|
|
*(P2_Device_Info *)(RequestPacket->OutputBuffer) =
|
|
hwDeviceExtension->deviceInfo;
|
|
|
|
status = NO_ERROR;
|
|
break;
|
|
|
|
case IOCTL_VIDEO_MAP_VIDEO_MEMORY:
|
|
|
|
DEBUG_PRINT((1, "PERM2: Permedia2StartIO - MapVideoMemory\n"));
|
|
|
|
if ( ( RequestPacket->OutputBufferLength <
|
|
( RequestPacket->StatusBlock->Information =
|
|
sizeof(VIDEO_MEMORY_INFORMATION) ) ) ||
|
|
( RequestPacket->InputBufferLength < sizeof(VIDEO_MEMORY) ) )
|
|
{
|
|
status = ERROR_INSUFFICIENT_BUFFER;
|
|
break;
|
|
}
|
|
|
|
memoryInformation = RequestPacket->OutputBuffer;
|
|
|
|
memoryInformation->VideoRamBase = ((PVIDEO_MEMORY)
|
|
(RequestPacket->InputBuffer))->RequestedVirtualAddress;
|
|
|
|
memoryInformation->VideoRamLength =
|
|
hwDeviceExtension->FrameLength;
|
|
|
|
inIoSpace = hwDeviceExtension->PhysicalFrameIoSpace;
|
|
|
|
//
|
|
// Performance:
|
|
//
|
|
// Enable USWC
|
|
// We only do it for the frame buffer - memory mapped registers can
|
|
// not be mapped USWC because write combining the registers would
|
|
// cause very bad things to happen !
|
|
//
|
|
|
|
status = VideoPortMapMemory( HwDeviceExtension,
|
|
hwDeviceExtension->PhysicalFrameAddress,
|
|
&(memoryInformation->VideoRamLength),
|
|
&inIoSpace,
|
|
&(memoryInformation->VideoRamBase));
|
|
|
|
if (status != NO_ERROR)
|
|
{
|
|
DEBUG_PRINT((1, "PERM2: VideoPortMapMemory failed with error %d\n", status));
|
|
break;
|
|
}
|
|
|
|
//
|
|
// The frame buffer and virtual memory and equivalent in this
|
|
// case.
|
|
//
|
|
|
|
memoryInformation->FrameBufferBase =
|
|
memoryInformation->VideoRamBase;
|
|
|
|
memoryInformation->FrameBufferLength =
|
|
memoryInformation->VideoRamLength;
|
|
|
|
break;
|
|
|
|
|
|
case IOCTL_VIDEO_UNMAP_VIDEO_MEMORY:
|
|
|
|
DEBUG_PRINT((1, "PERM2: Permedia2StartIO - UnMapVideoMemory\n"));
|
|
|
|
if (RequestPacket->InputBufferLength < sizeof(VIDEO_MEMORY))
|
|
{
|
|
status = ERROR_INSUFFICIENT_BUFFER;
|
|
break;
|
|
}
|
|
|
|
status = VideoPortUnmapMemory(
|
|
HwDeviceExtension,
|
|
((PVIDEO_MEMORY)(RequestPacket->InputBuffer))->
|
|
RequestedVirtualAddress,
|
|
0 );
|
|
|
|
break;
|
|
|
|
|
|
case IOCTL_VIDEO_QUERY_PUBLIC_ACCESS_RANGES:
|
|
|
|
DEBUG_PRINT((1, "PERM2: Permedia2StartIO - QueryPublicAccessRanges\n"));
|
|
|
|
{
|
|
|
|
PVIDEO_PUBLIC_ACCESS_RANGES portAccess;
|
|
ULONG physicalPortLength;
|
|
PVOID VirtualAddress;
|
|
PHYSICAL_ADDRESS PhysicalAddress;
|
|
|
|
if ( ( RequestPacket->OutputBufferLength <
|
|
( RequestPacket->StatusBlock->Information =
|
|
sizeof(VIDEO_PUBLIC_ACCESS_RANGES))) ||
|
|
( RequestPacket->InputBufferLength < sizeof(VIDEO_MEMORY) ) )
|
|
{
|
|
|
|
status = ERROR_INSUFFICIENT_BUFFER;
|
|
break;
|
|
}
|
|
|
|
ProcessHandle = (HANDLE)(((PVIDEO_MEMORY)
|
|
(RequestPacket->InputBuffer))->RequestedVirtualAddress);
|
|
|
|
if (ProcessHandle != (HANDLE)0)
|
|
{
|
|
//
|
|
// map 4K area for a process
|
|
//
|
|
|
|
DEBUG_PRINT((2, "PERM2: Mapping in 4K area from Control registers\n"));
|
|
|
|
VirtualAddress = (PVOID)ProcessHandle;
|
|
PhysicalAddress = hwDeviceExtension->PhysicalRegisterAddress;
|
|
PhysicalAddress.LowPart += 0x2000;
|
|
physicalPortLength = 0x1000;
|
|
|
|
}
|
|
else
|
|
{
|
|
DEBUG_PRINT((2, "PERM2: Mapping in all Control registers\n"));
|
|
VirtualAddress = NULL;
|
|
PhysicalAddress = hwDeviceExtension->PhysicalRegisterAddress;
|
|
physicalPortLength = hwDeviceExtension->RegisterLength;
|
|
}
|
|
|
|
portAccess = RequestPacket->OutputBuffer;
|
|
|
|
portAccess->VirtualAddress = VirtualAddress;
|
|
portAccess->InIoSpace = hwDeviceExtension->RegisterSpace;
|
|
portAccess->MappedInIoSpace = portAccess->InIoSpace;
|
|
|
|
status = VideoPortMapMemory( HwDeviceExtension,
|
|
PhysicalAddress,
|
|
&physicalPortLength,
|
|
&(portAccess->MappedInIoSpace),
|
|
&(portAccess->VirtualAddress));
|
|
|
|
if (status == NO_ERROR)
|
|
{
|
|
DEBUG_PRINT((1, "PERM2: mapped PAR[0] at vaddr 0x%x for length 0x%x\n",
|
|
portAccess->VirtualAddress,
|
|
physicalPortLength));
|
|
}
|
|
else
|
|
{
|
|
DEBUG_PRINT((1, "PERM2: VideoPortMapMemory failed with status 0x%x\n", status));
|
|
}
|
|
|
|
if ( (RequestPacket->OutputBufferLength >=
|
|
3 * sizeof(VIDEO_PUBLIC_ACCESS_RANGES) ) &&
|
|
(ProcessHandle == (HANDLE)0) )
|
|
{
|
|
|
|
RequestPacket->StatusBlock->Information =
|
|
3 * sizeof(VIDEO_PUBLIC_ACCESS_RANGES);
|
|
|
|
portAccess = RequestPacket->OutputBuffer;
|
|
PhysicalAddress = hwDeviceExtension->PhysicalRegisterAddress;
|
|
physicalPortLength = hwDeviceExtension->RegisterLength;
|
|
|
|
#if defined(_ALPHA_)
|
|
|
|
//
|
|
// for alpha, we want to map in a dense version of the
|
|
// control registers if we can. If this fails, we null
|
|
// the virtual address
|
|
//
|
|
|
|
portAccess += 2;
|
|
portAccess->VirtualAddress = NULL;
|
|
portAccess->InIoSpace = hwDeviceExtension->RegisterSpace;
|
|
portAccess->MappedInIoSpace = 4;
|
|
|
|
status = VideoPortMapMemory( HwDeviceExtension,
|
|
PhysicalAddress,
|
|
&physicalPortLength,
|
|
&(portAccess->MappedInIoSpace),
|
|
&(portAccess->VirtualAddress));
|
|
|
|
if (status == NO_ERROR)
|
|
{
|
|
DEBUG_PRINT((1, "PERM2: mapped dense PAR[0] at vaddr 0x%x for length 0x%x\n",
|
|
portAccess->VirtualAddress,
|
|
physicalPortLength));
|
|
}
|
|
else
|
|
{
|
|
DEBUG_PRINT((1, "PERM2: dense VideoPortMapMemory failed with status 0x%x\n", status));
|
|
}
|
|
#else
|
|
//
|
|
// all others, we just copy range[0]
|
|
//
|
|
|
|
portAccess[2] = portAccess[0];
|
|
#endif
|
|
}
|
|
}
|
|
|
|
break;
|
|
|
|
case IOCTL_VIDEO_FREE_PUBLIC_ACCESS_RANGES:
|
|
|
|
DEBUG_PRINT((1, "PERM2: Permedia2StartIO - FreePublicAccessRanges\n"));
|
|
|
|
if (RequestPacket->InputBufferLength < sizeof(VIDEO_MEMORY))
|
|
{
|
|
|
|
status = ERROR_INSUFFICIENT_BUFFER;
|
|
break;
|
|
}
|
|
|
|
status = VideoPortUnmapMemory(
|
|
HwDeviceExtension,
|
|
((PVIDEO_MEMORY)(RequestPacket->InputBuffer))->
|
|
RequestedVirtualAddress,
|
|
0);
|
|
|
|
if (status != NO_ERROR)
|
|
{
|
|
DEBUG_PRINT((1, "PERM2: VideoPortUnmapMemory failed with status 0x%x\n", status));
|
|
}
|
|
|
|
#if defined(_ALPHA_)
|
|
|
|
{
|
|
PVIDEO_MEMORY pVideoMemory;
|
|
PVOID pVirtualAddress;
|
|
|
|
if (RequestPacket->InputBufferLength >= 3 * sizeof(VIDEO_MEMORY))
|
|
{
|
|
pVideoMemory = (PVIDEO_MEMORY)(RequestPacket->InputBuffer);
|
|
|
|
pVirtualAddress = pVideoMemory->RequestedVirtualAddress;
|
|
|
|
pVideoMemory += 2;
|
|
|
|
if((pVideoMemory->RequestedVirtualAddress) &&
|
|
(pVideoMemory->RequestedVirtualAddress != pVirtualAddress))
|
|
{
|
|
status = VideoPortUnmapMemory(
|
|
HwDeviceExtension,
|
|
pVideoMemory->RequestedVirtualAddress,
|
|
0 );
|
|
}
|
|
|
|
if (status != NO_ERROR)
|
|
DEBUG_PRINT((1, "PERM2: VideoPortUnmapMemory failed on Alpha with status 0x%x\n", status));
|
|
|
|
}
|
|
}
|
|
|
|
#endif
|
|
break;
|
|
|
|
case IOCTL_VIDEO_HANDLE_VIDEOPARAMETERS:
|
|
|
|
DEBUG_PRINT((1, "PERM2: Permedia2StartIO - HandleVideoParameters\n"));
|
|
|
|
//
|
|
// We don't support a tv connector so just return NO_ERROR here
|
|
//
|
|
|
|
pVideoParams = (PVIDEOPARAMETERS) (RequestPacket->InputBuffer);
|
|
|
|
if (pVideoParams->dwCommand == VP_COMMAND_GET)
|
|
{
|
|
pVideoParams = (PVIDEOPARAMETERS) (RequestPacket->OutputBuffer);
|
|
pVideoParams->dwFlags = 0;
|
|
}
|
|
|
|
RequestPacket->StatusBlock->Information = sizeof(VIDEOPARAMETERS);
|
|
status = NO_ERROR;
|
|
break;
|
|
|
|
case IOCTL_VIDEO_QUERY_AVAIL_MODES:
|
|
|
|
DEBUG_PRINT((1, "PERM2: Permedia2StartIO - QueryAvailableModes\n"));
|
|
|
|
if (RequestPacket->OutputBufferLength <
|
|
( RequestPacket->StatusBlock->Information =
|
|
hwDeviceExtension->NumAvailableModes *
|
|
sizeof(VIDEO_MODE_INFORMATION)) )
|
|
|
|
{
|
|
|
|
status = ERROR_INSUFFICIENT_BUFFER;
|
|
|
|
} else
|
|
{
|
|
|
|
modeInformation = RequestPacket->OutputBuffer;
|
|
|
|
for (pFrequencyEntry = hwDeviceExtension->FrequencyTable;
|
|
pFrequencyEntry->BitsPerPel != 0;
|
|
pFrequencyEntry++)
|
|
{
|
|
|
|
if (pFrequencyEntry->ModeValid)
|
|
{
|
|
*modeInformation =
|
|
pFrequencyEntry->ModeEntry->ModeInformation;
|
|
|
|
modeInformation->Frequency =
|
|
pFrequencyEntry->ScreenFrequency;
|
|
|
|
modeInformation->ModeIndex =
|
|
pFrequencyEntry->ModeIndex;
|
|
|
|
modeInformation++;
|
|
}
|
|
}
|
|
|
|
status = NO_ERROR;
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
case IOCTL_VIDEO_QUERY_CURRENT_MODE:
|
|
|
|
DEBUG_PRINT((1, "PERM2: Permedia2StartIO - QueryCurrentModes. current mode is %d\n",
|
|
hwDeviceExtension->ActiveModeEntry->ModeInformation.ModeIndex));
|
|
|
|
if (RequestPacket->OutputBufferLength <
|
|
(RequestPacket->StatusBlock->Information =
|
|
sizeof(VIDEO_MODE_INFORMATION)) )
|
|
{
|
|
|
|
status = ERROR_INSUFFICIENT_BUFFER;
|
|
|
|
} else
|
|
{
|
|
|
|
*((PVIDEO_MODE_INFORMATION)RequestPacket->OutputBuffer) =
|
|
hwDeviceExtension->ActiveModeEntry->ModeInformation;
|
|
|
|
((PVIDEO_MODE_INFORMATION)RequestPacket->OutputBuffer)->Frequency =
|
|
hwDeviceExtension->ActiveFrequencyEntry.ScreenFrequency;
|
|
|
|
status = NO_ERROR;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
case IOCTL_VIDEO_QUERY_NUM_AVAIL_MODES:
|
|
|
|
DEBUG_PRINT((1, "PERM2: Permedia2StartIO - QueryNumAvailableModes (= %d)\n",
|
|
hwDeviceExtension->NumAvailableModes));
|
|
|
|
//
|
|
// Find out the size of the data to be put in the the buffer and
|
|
// return that in the status information (whether or not the
|
|
// information is there). If the buffer passed in is not large
|
|
// enough return an appropriate error code.
|
|
//
|
|
|
|
if (RequestPacket->OutputBufferLength <
|
|
(RequestPacket->StatusBlock->Information = sizeof(VIDEO_NUM_MODES)))
|
|
{
|
|
|
|
status = ERROR_INSUFFICIENT_BUFFER;
|
|
|
|
} else
|
|
{
|
|
//
|
|
// Configure the valid modes again. This allows non 3D accelerated
|
|
// modes to be added dynamically. BUT, we cannot allow modes to be
|
|
// dynamically removed. If we do we may have nowhere to go after
|
|
// the Test screen (or if we logout). So only reconfigure these
|
|
// modes if the ExportNon3D flag is turned on and it used to be
|
|
// off. If it was already on then there's no need to reconfigure.
|
|
//
|
|
|
|
if (!hwDeviceExtension->ExportNon3DModes)
|
|
{
|
|
ULONG ExportNon3DModes = 0;
|
|
|
|
status = VideoPortGetRegistryParameters(HwDeviceExtension,
|
|
PERM2_EXPORT_HIRES_REG_STRING,
|
|
FALSE,
|
|
Permedia2RegistryCallback,
|
|
&ExportNon3DModes);
|
|
|
|
if (( status == NO_ERROR) && ExportNon3DModes)
|
|
{
|
|
ConstructValidModesList( HwDeviceExtension,
|
|
hwDeviceExtension );
|
|
}
|
|
|
|
}
|
|
|
|
((PVIDEO_NUM_MODES)RequestPacket->OutputBuffer)->NumModes =
|
|
hwDeviceExtension->NumAvailableModes;
|
|
|
|
((PVIDEO_NUM_MODES)RequestPacket->OutputBuffer)->ModeInformationLength =
|
|
sizeof(VIDEO_MODE_INFORMATION);
|
|
|
|
status = NO_ERROR;
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
case IOCTL_VIDEO_SET_CURRENT_MODE:
|
|
|
|
DEBUG_PRINT((1, "PERM2: Permedia2StartIO - SetCurrentMode\n"));
|
|
|
|
if(!hwDeviceExtension->bVGAEnabled)
|
|
{
|
|
//
|
|
// secondary card: if it's just returned from hibernation
|
|
// it won't be set-up yet
|
|
// NB. primary is OK, its BIOS has run
|
|
//
|
|
|
|
PCI_COMMON_CONFIG PciData;
|
|
|
|
VideoPortGetBusData(hwDeviceExtension,
|
|
PCIConfiguration,
|
|
0,
|
|
&PciData,
|
|
0,
|
|
PCI_COMMON_HDR_LENGTH);
|
|
|
|
if((PciData.Command & PCI_ENABLE_MEMORY_SPACE) == 0)
|
|
{
|
|
//
|
|
// memory accesses not turned on - this card has just returned
|
|
// from hibernation and is back in its default state: set it
|
|
// up once more
|
|
//
|
|
|
|
PowerOnReset(hwDeviceExtension);
|
|
|
|
}
|
|
}
|
|
|
|
//
|
|
// Check if the size of the data in the input buffer is large enough.
|
|
//
|
|
|
|
if (RequestPacket->InputBufferLength < sizeof(VIDEO_MODE))
|
|
{
|
|
RequestPacket->StatusBlock->Information = sizeof(VIDEO_MODE);
|
|
status = ERROR_INSUFFICIENT_BUFFER;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Find the correct entries in the P2_VIDEO_MODES and
|
|
// P2_VIDEO_FREQUENCIES tables that correspond to this
|
|
// mode number.
|
|
//
|
|
// ( Remember that each mode in the P2_VIDEO_MODES table
|
|
// can have a number of possible frequencies associated with it.)
|
|
//
|
|
|
|
RequestedMode = ((PVIDEO_MODE) RequestPacket->InputBuffer)->RequestedMode;
|
|
|
|
modeNumber = RequestedMode & ~VIDEO_MODE_NO_ZERO_MEMORY;
|
|
|
|
if ((modeNumber >= hwDeviceExtension->NumTotalModes) ||
|
|
!(hwDeviceExtension->FrequencyTable[modeNumber].ModeValid))
|
|
{
|
|
RequestPacket->StatusBlock->Information =
|
|
hwDeviceExtension->NumTotalModes;
|
|
|
|
status = ERROR_INVALID_PARAMETER;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Re-sample the clock speed. This allows us to change the clock speed
|
|
// on the fly using the display applet Test button.
|
|
//
|
|
|
|
Permedia2GetClockSpeeds(HwDeviceExtension);
|
|
|
|
FrequencyEntry = hwDeviceExtension->FrequencyTable[modeNumber];
|
|
ModeEntry = FrequencyEntry.ModeEntry;
|
|
|
|
//
|
|
// At this point, 'ModeEntry' and 'FrequencyEntry' point to the
|
|
// necessary table entries required for setting the requested mode.
|
|
//
|
|
// Zero the DAC and the Screen buffer memory.
|
|
//
|
|
|
|
ZeroMemAndDac(hwDeviceExtension, RequestedMode);
|
|
|
|
ModeEntry->ModeInformation.DriverSpecificAttributeFlags =
|
|
hwDeviceExtension->Capabilities;
|
|
|
|
//
|
|
// For low resolution modes we may have to do various tricks
|
|
// such as line doubling and getting the RAMDAC to zoom.
|
|
// Record any such zoom in the Mode DeviceAttributes field.
|
|
// Primarily this is to allow the display driver to
|
|
// compensate when asked to move the cursor or change its
|
|
// shape.
|
|
//
|
|
// Currently, low res means lower than 512 pixels width.
|
|
//
|
|
|
|
if (FrequencyEntry.ScreenWidth < 512)
|
|
{
|
|
// Permedia does line doubling. If using a TVP we must
|
|
// get it to zoom by 2 in X to get the pixel rate up.
|
|
//
|
|
ModeEntry->ModeInformation.DriverSpecificAttributeFlags |= CAPS_ZOOM_Y_BY2;
|
|
|
|
}
|
|
|
|
if (!InitializeVideo(HwDeviceExtension, &FrequencyEntry))
|
|
{
|
|
DEBUG_PRINT((1, "PERM2: InitializeVideo failed\n"));
|
|
RequestPacket->StatusBlock->Information = modeNumber;
|
|
status = ERROR_INVALID_PARAMETER;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Save the mode since we know the rest will work.
|
|
//
|
|
|
|
hwDeviceExtension->ActiveModeEntry = ModeEntry;
|
|
hwDeviceExtension->ActiveFrequencyEntry = FrequencyEntry;
|
|
|
|
//
|
|
// Update VIDEO_MODE_INFORMATION fields
|
|
//
|
|
// Now that we've set the mode, we now know the screen stride, and
|
|
// so can update some fields in the VIDEO_MODE_INFORMATION
|
|
// structure for this mode. The Permedia 2 display driver is expected
|
|
// to call IOCTL_VIDEO_QUERY_CURRENT_MODE to query these corrected
|
|
// values.
|
|
//
|
|
//
|
|
// Calculate the bitmap width (note the '+ 1' on BitsPerPlane is
|
|
// so that '15bpp' works out right). 12bpp is special in that we
|
|
// support it as sparse nibbles within a 32-bit pixel. ScreenStride
|
|
// is in bytes; VideoMemoryBitmapWidth is measured in pixels;
|
|
//
|
|
|
|
if (ModeEntry->ModeInformation.BitsPerPlane != 12)
|
|
{
|
|
ModeEntry->ModeInformation.VideoMemoryBitmapWidth =
|
|
ModeEntry->ModeInformation.ScreenStride
|
|
/ ((ModeEntry->ModeInformation.BitsPerPlane + 1) >> 3);
|
|
}
|
|
else
|
|
{
|
|
ModeEntry->ModeInformation.VideoMemoryBitmapWidth =
|
|
ModeEntry->ModeInformation.ScreenStride >> 2;
|
|
}
|
|
|
|
//
|
|
// Calculate the bitmap height.
|
|
//
|
|
|
|
ulValue = hwDeviceExtension->AdapterMemorySize;
|
|
ModeEntry->ModeInformation.VideoMemoryBitmapHeight =
|
|
ulValue / ModeEntry->ModeInformation.ScreenStride;
|
|
|
|
status = NO_ERROR;
|
|
|
|
break;
|
|
|
|
case IOCTL_VIDEO_SET_COLOR_REGISTERS:
|
|
|
|
DEBUG_PRINT((1, "PERM2: Permedia2StartIO - SetColorRegs\n"));
|
|
|
|
clutBuffer = (PVIDEO_CLUT) RequestPacket->InputBuffer;
|
|
|
|
status = Permedia2SetColorLookup(hwDeviceExtension,
|
|
clutBuffer,
|
|
RequestPacket->InputBufferLength,
|
|
FALSE, // update when we need to
|
|
TRUE); // Update cache entries as
|
|
// well as RAMDAC
|
|
break;
|
|
|
|
case IOCTL_VIDEO_RESET_DEVICE:
|
|
|
|
DEBUG_PRINT((1, "PERM2: Permedia2StartIO - RESET_DEVICE\n"));
|
|
|
|
if(hwDeviceExtension->bVGAEnabled)
|
|
{
|
|
//
|
|
// Do any resets required before getting the BIOS to
|
|
// do an INT 10
|
|
//
|
|
//
|
|
// reset the VGA before rerouting the bypass to display VGA
|
|
//
|
|
// Only reset the device if the monitor is on. If it is off,
|
|
// then executing the int10 will turn it back on.
|
|
//
|
|
|
|
if (hwDeviceExtension->bMonitorPoweredOn)
|
|
{
|
|
//
|
|
// Do an Int10 to mode 3 will put the VGA to a known state.
|
|
//
|
|
|
|
VideoPortZeroMemory(&biosArguments,
|
|
sizeof(VIDEO_X86_BIOS_ARGUMENTS));
|
|
|
|
biosArguments.Eax = 0x0003;
|
|
|
|
VideoPortInt10(HwDeviceExtension, &biosArguments);
|
|
}
|
|
}
|
|
|
|
status = NO_ERROR;
|
|
break;
|
|
|
|
case IOCTL_VIDEO_SHARE_VIDEO_MEMORY:
|
|
{
|
|
|
|
PVIDEO_SHARE_MEMORY pShareMemory;
|
|
PVIDEO_SHARE_MEMORY_INFORMATION pShareMemoryInformation;
|
|
PHYSICAL_ADDRESS shareAddress;
|
|
PVOID virtualAddress;
|
|
ULONG sharedViewSize;
|
|
|
|
DEBUG_PRINT((1, "PERM2: Permedia2StartIO - ShareVideoMemory\n"));
|
|
|
|
if( (RequestPacket->OutputBufferLength < sizeof(VIDEO_SHARE_MEMORY_INFORMATION)) ||
|
|
(RequestPacket->InputBufferLength < sizeof(VIDEO_MEMORY)) )
|
|
{
|
|
DEBUG_PRINT((1, "PERM2: IOCTL_VIDEO_SHARE_VIDEO_MEMORY - ERROR_INSUFFICIENT_BUFFER\n"));
|
|
status = ERROR_INSUFFICIENT_BUFFER;
|
|
break;
|
|
}
|
|
|
|
pShareMemory = RequestPacket->InputBuffer;
|
|
|
|
if( (pShareMemory->ViewOffset > hwDeviceExtension->AdapterMemorySize) ||
|
|
((pShareMemory->ViewOffset + pShareMemory->ViewSize) >
|
|
hwDeviceExtension->AdapterMemorySize) )
|
|
{
|
|
DEBUG_PRINT((1, "PERM2: IOCTL_VIDEO_SHARE_VIDEO_MEMORY - ERROR_INVALID_PARAMETER\n"));
|
|
status = ERROR_INVALID_PARAMETER;
|
|
break;
|
|
}
|
|
|
|
RequestPacket->StatusBlock->Information =
|
|
sizeof(VIDEO_SHARE_MEMORY_INFORMATION);
|
|
|
|
//
|
|
// Beware: the input buffer and the output buffer are the same
|
|
// buffer, and therefore data should not be copied from one to the
|
|
// other
|
|
//
|
|
|
|
virtualAddress = pShareMemory->ProcessHandle;
|
|
sharedViewSize = pShareMemory->ViewSize;
|
|
|
|
inIoSpace = hwDeviceExtension->PhysicalFrameIoSpace;
|
|
|
|
//
|
|
// NOTE: we are ignoring ViewOffset
|
|
//
|
|
|
|
shareAddress.QuadPart =
|
|
hwDeviceExtension->PhysicalFrameAddress.QuadPart;
|
|
|
|
//
|
|
// Unlike the MAP_MEMORY IOCTL, in this case we can not map extra
|
|
// address space since the application could actually use the
|
|
// pointer we return to it to touch locations in the address space
|
|
// that do not have actual video memory in them.
|
|
//
|
|
// An app doing this would cause the machine to crash.
|
|
//
|
|
|
|
status = VideoPortMapMemory( hwDeviceExtension,
|
|
shareAddress,
|
|
&sharedViewSize,
|
|
&inIoSpace,
|
|
&virtualAddress );
|
|
|
|
pShareMemoryInformation = RequestPacket->OutputBuffer;
|
|
|
|
pShareMemoryInformation->SharedViewOffset = pShareMemory->ViewOffset;
|
|
pShareMemoryInformation->VirtualAddress = virtualAddress;
|
|
pShareMemoryInformation->SharedViewSize = sharedViewSize;
|
|
|
|
}
|
|
break;
|
|
|
|
|
|
case IOCTL_VIDEO_UNSHARE_VIDEO_MEMORY:
|
|
{
|
|
PVIDEO_SHARE_MEMORY pShareMemory;
|
|
|
|
DEBUG_PRINT((1, "PERM2: Permedia2StartIO - UnshareVideoMemory\n"));
|
|
|
|
if (RequestPacket->InputBufferLength < sizeof(VIDEO_SHARE_MEMORY))
|
|
{
|
|
status = ERROR_INSUFFICIENT_BUFFER;
|
|
break;
|
|
|
|
}
|
|
|
|
pShareMemory = RequestPacket->InputBuffer;
|
|
|
|
status = VideoPortUnmapMemory(hwDeviceExtension,
|
|
pShareMemory->RequestedVirtualAddress,
|
|
pShareMemory->ProcessHandle);
|
|
}
|
|
break;
|
|
|
|
|
|
case IOCTL_VIDEO_QUERY_LINE_DMA_BUFFER:
|
|
|
|
//
|
|
// Return the line DMA buffer information. The buffer size and
|
|
// virtual address will be zero if the buffer couldn't be allocated.
|
|
//
|
|
// output buffer has zero length, so free buffer....
|
|
//
|
|
|
|
status = ERROR_INSUFFICIENT_BUFFER;
|
|
|
|
if (RequestPacket->OutputBufferLength <
|
|
(RequestPacket->StatusBlock->Information = sizeof(LINE_DMA_BUFFER)))
|
|
{
|
|
|
|
//
|
|
// Maybe we should free something
|
|
//
|
|
|
|
if ( RequestPacket->InputBufferLength >= sizeof(LINE_DMA_BUFFER))
|
|
{
|
|
if (hwDeviceExtension->ulLineDMABufferUsage > 0)
|
|
{
|
|
hwDeviceExtension->ulLineDMABufferUsage--;
|
|
if (hwDeviceExtension->ulLineDMABufferUsage == 0)
|
|
{
|
|
VideoPortFreeCommonBuffer(
|
|
hwDeviceExtension,
|
|
hwDeviceExtension->LineDMABuffer.size,
|
|
hwDeviceExtension->LineDMABuffer.virtAddr,
|
|
hwDeviceExtension->LineDMABuffer.physAddr,
|
|
hwDeviceExtension->LineDMABuffer.cacheEnabled);
|
|
|
|
memset(&hwDeviceExtension->LineDMABuffer,
|
|
0,
|
|
sizeof(LINE_DMA_BUFFER));
|
|
}
|
|
}
|
|
status = NO_ERROR;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
PLINE_DMA_BUFFER pDMAIn, pDMAOut;
|
|
|
|
pDMAIn = (PLINE_DMA_BUFFER)RequestPacket->InputBuffer;
|
|
pDMAOut = (PLINE_DMA_BUFFER)RequestPacket->OutputBuffer;
|
|
|
|
if (RequestPacket->InputBufferLength >= sizeof(LINE_DMA_BUFFER))
|
|
{
|
|
if (hwDeviceExtension->ulLineDMABufferUsage == 0)
|
|
{
|
|
*pDMAOut = *pDMAIn;
|
|
|
|
if( ( pDMAOut->virtAddr =
|
|
VideoPortGetCommonBuffer( hwDeviceExtension,
|
|
pDMAIn->size,
|
|
PAGE_SIZE,
|
|
&pDMAOut->physAddr,
|
|
&pDMAOut->size,
|
|
pDMAIn->cacheEnabled ) )
|
|
!= NULL )
|
|
{
|
|
hwDeviceExtension->LineDMABuffer=*pDMAOut;
|
|
hwDeviceExtension->ulLineDMABufferUsage++;
|
|
}
|
|
|
|
} else
|
|
{
|
|
*pDMAOut = hwDeviceExtension->LineDMABuffer;
|
|
hwDeviceExtension->ulLineDMABufferUsage++;
|
|
}
|
|
|
|
status = NO_ERROR;
|
|
}
|
|
}
|
|
|
|
DEBUG_PRINT((1, "PERM2: QUERY LINE DMA BUFFER status %d\n", status));
|
|
break;
|
|
|
|
case IOCTL_VIDEO_QUERY_EMULATED_DMA_BUFFER:
|
|
|
|
DEBUG_PRINT((1, "PERM2: Permedia2StartIO - QUERY EMULATED DMA BUFFER\n"));
|
|
|
|
//
|
|
// Allocate/free the emulated DMA buffer. The buffer size and
|
|
// virtual address will be zero if the buffer couldn't be allocated.
|
|
//
|
|
// output buffer has zero length, so free buffer....
|
|
//
|
|
|
|
status = ERROR_INSUFFICIENT_BUFFER;
|
|
|
|
if (RequestPacket->InputBufferLength >= sizeof(EMULATED_DMA_BUFFER))
|
|
{
|
|
PEMULATED_DMA_BUFFER pDMAIn, pDMAOut;
|
|
|
|
pDMAIn = (PEMULATED_DMA_BUFFER)RequestPacket->InputBuffer;
|
|
|
|
if (RequestPacket->OutputBufferLength <
|
|
(RequestPacket->StatusBlock->Information = sizeof(EMULATED_DMA_BUFFER)))
|
|
{
|
|
VideoPortFreePool(hwDeviceExtension, pDMAIn->virtAddr);
|
|
status = NO_ERROR;
|
|
}
|
|
else
|
|
{
|
|
pDMAOut = (PEMULATED_DMA_BUFFER)RequestPacket->OutputBuffer;
|
|
|
|
if ( ( pDMAOut->virtAddr =
|
|
VideoPortAllocatePool( hwDeviceExtension,
|
|
VpPagedPool,
|
|
pDMAIn->size,
|
|
pDMAIn->tag ) )
|
|
!= NULL )
|
|
{
|
|
pDMAOut->size = pDMAIn->size;
|
|
pDMAOut->tag = pDMAIn->tag;
|
|
}
|
|
|
|
status = NO_ERROR;
|
|
}
|
|
}
|
|
|
|
DEBUG_PRINT((1, "PERM2: QUERY EMULATED DMA BUFFER status %d\n", status));
|
|
break;
|
|
|
|
case IOCTL_VIDEO_MAP_INTERRUPT_CMD_BUF:
|
|
|
|
DEBUG_PRINT((1, "PERM2: Permedia2StartIO - MapInterruptCmdBuf\n"));
|
|
|
|
if (RequestPacket->OutputBufferLength <
|
|
(RequestPacket->StatusBlock->Information =
|
|
sizeof(PVOID)) )
|
|
{
|
|
//
|
|
// They've give us a duff buffer.
|
|
//
|
|
|
|
status = ERROR_INSUFFICIENT_BUFFER;
|
|
}
|
|
else
|
|
{
|
|
*((PVOID*)(RequestPacket->OutputBuffer)) =
|
|
hwDeviceExtension->InterruptControl.ControlBlock;
|
|
status = NO_ERROR;
|
|
}
|
|
|
|
DEBUG_PRINT((1, "PERM2: MapInterruptCmdBuf returns va %x\n",
|
|
*(PULONG)(RequestPacket->OutputBuffer)));
|
|
break;
|
|
|
|
|
|
#if defined(_X86_)
|
|
|
|
case IOCTL_VIDEO_QUERY_INTERLOCKEDEXCHANGE:
|
|
|
|
status = ERROR_INSUFFICIENT_BUFFER;
|
|
|
|
if ( RequestPacket->OutputBufferLength >=
|
|
(RequestPacket->StatusBlock->Information = sizeof(PVOID)) )
|
|
{
|
|
PVOID *pIE = (PVOID)RequestPacket->OutputBuffer;
|
|
*pIE = (PVOID) VideoPortInterlockedExchange;
|
|
status = NO_ERROR;
|
|
}
|
|
|
|
break;
|
|
#endif
|
|
|
|
|
|
case IOCTL_VIDEO_STALL_EXECUTION:
|
|
if (RequestPacket->InputBufferLength >= sizeof(ULONG))
|
|
{
|
|
ULONG *pMicroseconds = (ULONG *)RequestPacket->InputBuffer;
|
|
VideoPortStallExecution(*pMicroseconds);
|
|
status = NO_ERROR;
|
|
} else
|
|
{
|
|
status = ERROR_INSUFFICIENT_BUFFER;
|
|
}
|
|
|
|
break;
|
|
|
|
//
|
|
// if we get here, an invalid IoControlCode was specified.
|
|
//
|
|
|
|
default:
|
|
|
|
DEBUG_PRINT((1, "Fell through Permedia2 startIO routine - invalid command\n"));
|
|
|
|
status = ERROR_INVALID_FUNCTION;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
RequestPacket->StatusBlock->Status = status;
|
|
|
|
if( status != NO_ERROR )
|
|
RequestPacket->StatusBlock->Information = 0;
|
|
|
|
return TRUE;
|
|
|
|
} // end Permedia2StartIO()
|
|
|
|
|
|
BOOLEAN
|
|
Permedia2ResetHW(
|
|
PVOID HwDeviceExtension,
|
|
ULONG Columns,
|
|
ULONG Rows
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine resets the hardware when a soft reboot is performed. We
|
|
need this to reset the VGA pass through.
|
|
|
|
THIS FUNCTION CANNOT BE PAGED.
|
|
|
|
Arguments:
|
|
|
|
hwDeviceExtension - Pointer to the miniport driver's device extension.
|
|
|
|
Columns - Specifies the number of columns of the mode to be set up.
|
|
|
|
Rows - Specifies the number of rows of the mode to be set up.
|
|
|
|
Return Value:
|
|
|
|
We always return FALSE to force the HAL to do an INT10 reset.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
//
|
|
// return false so the HAL does an INT10 mode 3
|
|
//
|
|
|
|
return(FALSE);
|
|
}
|
|
|
|
|
|
VP_STATUS
|
|
Permedia2SetColorLookup(
|
|
PHW_DEVICE_EXTENSION hwDeviceExtension,
|
|
PVIDEO_CLUT ClutBuffer,
|
|
ULONG ClutBufferSize,
|
|
BOOLEAN ForceRAMDACWrite,
|
|
BOOLEAN UpdateCache
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine sets a specified portion of the color lookup table settings.
|
|
|
|
Arguments:
|
|
|
|
hwDeviceExtension - Pointer to the miniport driver's device extension.
|
|
|
|
ClutBufferSize - Length of the input buffer supplied by the user.
|
|
|
|
ClutBuffer - Pointer to the structure containing the color lookup table.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
USHORT i, j;
|
|
TVP4020_DECL;
|
|
P2RD_DECL;
|
|
PVIDEO_CLUT LUTCachePtr = &(hwDeviceExtension->LUTCache.LUTCache);
|
|
P2_DECL;
|
|
ULONG VsEnd;
|
|
|
|
//
|
|
// Check if the size of the data in the input buffer is large enough.
|
|
//
|
|
|
|
if ( (ClutBufferSize < (sizeof(VIDEO_CLUT) - sizeof(ULONG))) ||
|
|
(ClutBufferSize < (sizeof(VIDEO_CLUT) +
|
|
(sizeof(ULONG) * (ClutBuffer->NumEntries - 1))) ) )
|
|
{
|
|
|
|
DEBUG_PRINT((1, "PERM2: Permedia2SetColorLookup: insufficient buffer (was %d, min %d)\n",
|
|
ClutBufferSize,
|
|
(sizeof(VIDEO_CLUT) + (sizeof(ULONG) * (ClutBuffer->NumEntries - 1)))));
|
|
|
|
return ERROR_INSUFFICIENT_BUFFER;
|
|
}
|
|
|
|
//
|
|
// Check to see if the parameters are valid.
|
|
//
|
|
|
|
if ( (ClutBuffer->NumEntries == 0) ||
|
|
(ClutBuffer->FirstEntry > VIDEO_MAX_COLOR_REGISTER) ||
|
|
(ClutBuffer->FirstEntry + ClutBuffer->NumEntries >
|
|
VIDEO_MAX_COLOR_REGISTER + 1) )
|
|
{
|
|
DEBUG_PRINT((1, "Permedia2SetColorLookup: invalid parameter\n"));
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
//
|
|
// Set CLUT registers directly on the hardware.
|
|
//
|
|
|
|
switch (hwDeviceExtension->DacId)
|
|
{
|
|
case TVP4020_RAMDAC:
|
|
case P2RD_RAMDAC:
|
|
break;
|
|
|
|
default:
|
|
return (ERROR_DEV_NOT_EXIST);
|
|
}
|
|
|
|
if (hwDeviceExtension->bVTGRunning &&
|
|
hwDeviceExtension->bMonitorPoweredOn)
|
|
{
|
|
//
|
|
// if VTG has been set-up, we wait for VSync before updating
|
|
// the palette entries (just to avoid possible flickers)
|
|
//
|
|
|
|
VsEnd = VideoPortReadRegisterUlong(VS_END);
|
|
while ( VideoPortReadRegisterUlong(LINE_COUNT) > VsEnd );
|
|
}
|
|
|
|
//
|
|
// RAMDAC Programming phase
|
|
//
|
|
|
|
for ( i = 0, j = ClutBuffer->FirstEntry;
|
|
i < ClutBuffer->NumEntries;
|
|
i++, j++ )
|
|
{
|
|
|
|
//
|
|
// Update the RAMDAC entry if it has changed or if we have
|
|
// been told to overwrite it.
|
|
//
|
|
|
|
if ( ForceRAMDACWrite ||
|
|
( LUTCachePtr->LookupTable[j].RgbLong !=
|
|
ClutBuffer->LookupTable[i].RgbLong ) )
|
|
{
|
|
switch (hwDeviceExtension->DacId)
|
|
{
|
|
case TVP4020_RAMDAC:
|
|
TVP4020_LOAD_PALETTE_INDEX (
|
|
j,
|
|
ClutBuffer->LookupTable[i].RgbArray.Red,
|
|
ClutBuffer->LookupTable[i].RgbArray.Green,
|
|
ClutBuffer->LookupTable[i].RgbArray.Blue);
|
|
break;
|
|
|
|
case P2RD_RAMDAC:
|
|
P2RD_LOAD_PALETTE_INDEX (
|
|
j,
|
|
ClutBuffer->LookupTable[i].RgbArray.Red,
|
|
ClutBuffer->LookupTable[i].RgbArray.Green,
|
|
ClutBuffer->LookupTable[i].RgbArray.Blue);
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
|
|
//
|
|
// Update the cache, if instructed to do so
|
|
//
|
|
|
|
if (UpdateCache)
|
|
{
|
|
LUTCachePtr->LookupTable[j].RgbLong = ClutBuffer->LookupTable[i].RgbLong;
|
|
}
|
|
}
|
|
|
|
return NO_ERROR;
|
|
|
|
} // end Permedia2SetColorLookup()
|
|
|
|
|
|
|
|
VOID
|
|
Permedia2GetClockSpeeds(
|
|
PVOID HwDeviceExtension
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Work out the chip clock speed and save in hwDeviceExtension.
|
|
|
|
Arguments:
|
|
|
|
hwDeviceExtension - Supplies a pointer to the miniport's device extension.
|
|
|
|
Return Value:
|
|
|
|
On return the following values will be in hwDeviceExtension:
|
|
|
|
- ChipClockSpeed: this is the desired speed for the chip
|
|
- RefClockSpeed: this is the speed of the oscillator input on the board
|
|
|
|
Note:
|
|
|
|
We use ChipClockSpeed to refer to the speed of the chip. RefClockSpeed
|
|
is the reference clock speed.
|
|
|
|
--*/
|
|
|
|
{
|
|
PHW_DEVICE_EXTENSION hwDeviceExtension = HwDeviceExtension;
|
|
ULONG ulValue, ulChipClk, ulRefClk;
|
|
VP_STATUS status;
|
|
P2_DECL;
|
|
|
|
//
|
|
// inherit the values from board zero or default
|
|
//
|
|
|
|
ulChipClk = hwDeviceExtension->ChipClockSpeed;
|
|
ulRefClk = REF_CLOCK_SPEED;
|
|
|
|
//
|
|
// Use the Registry specified clock-speed if supplied
|
|
//
|
|
|
|
status = VideoPortGetRegistryParameters( HwDeviceExtension,
|
|
L"PermediaClockSpeed",
|
|
FALSE,
|
|
Permedia2RegistryCallback,
|
|
&ulChipClk);
|
|
|
|
if ( (status != NO_ERROR) || ulChipClk == 0)
|
|
{
|
|
|
|
//
|
|
// The Registry does not specify an override so read the chip clock
|
|
// speed (in MHz) from the Video ROM BIOS (offset 0xA in the BIOS)
|
|
// NB. this involves changing the aperture 2 register so aperture
|
|
// better be completely idle or we could be in trouble; fortunately
|
|
// we only call this function during a mode change and expect
|
|
// aperture 2 (the FrameBuffer) to be idle
|
|
//
|
|
|
|
ULONG Default = VideoPortReadRegisterUlong(APERTURE_TWO);
|
|
UCHAR *p = (UCHAR *)hwDeviceExtension->pFramebuffer;
|
|
|
|
//
|
|
// r/w via aperture 2 actually go to ROM
|
|
//
|
|
|
|
VideoPortWriteRegisterUlong(APERTURE_TWO, Default | 0x200);
|
|
|
|
//
|
|
// If we have a valid ROM then read the clock speed
|
|
//
|
|
|
|
if (VideoPortReadRegisterUshort ((USHORT *) p) == 0xAA55)
|
|
{
|
|
//
|
|
// Get the clock speed, on some boards (eg Creative), the clock
|
|
// value at 0x0A is sometimes remains undefined leading to
|
|
// unpredictable results. The values are validated before this
|
|
// function returns
|
|
//
|
|
|
|
ulChipClk = VideoPortReadRegisterUchar(&(p[0xA]));
|
|
|
|
DEBUG_PRINT((1, "ROM clk speed value 0x%x\n Mhz", ulChipClk));
|
|
|
|
}
|
|
else
|
|
{
|
|
DEBUG_PRINT((1, "Bad BIOS ROM header 0x%x\n",
|
|
(ULONG) VideoPortReadRegisterUshort ((USHORT *) p)));
|
|
|
|
}
|
|
|
|
VideoPortWriteRegisterUlong(APERTURE_TWO, Default);
|
|
}
|
|
|
|
//
|
|
// Convert to Hz
|
|
//
|
|
|
|
ulChipClk *= 1000000;
|
|
|
|
//
|
|
// Validate the selected clock speed, adjust if it is either too
|
|
// high or too low.
|
|
//
|
|
|
|
if (ulChipClk < MIN_PERMEDIA_CLOCK_SPEED)
|
|
{
|
|
if(ulChipClk == 0x00)
|
|
{
|
|
ulChipClk = PERMEDIA2_DEFAULT_CLOCK_SPEED;
|
|
}
|
|
else
|
|
{
|
|
ulChipClk = MIN_PERMEDIA_CLOCK_SPEED;
|
|
}
|
|
}
|
|
|
|
if (ulChipClk > MAX_PERMEDIA_CLOCK_SPEED)
|
|
{
|
|
DEBUG_PRINT((1, "PERM2: Permedia clock speed %d too fast. Limiting to %d\n" ,
|
|
ulChipClk, MAX_PERMEDIA_CLOCK_SPEED));
|
|
|
|
ulChipClk= PERMEDIA2_DEFAULT_CLOCK_SPEED;
|
|
|
|
}
|
|
|
|
DEBUG_PRINT((3, "PERM2: Permedia Clock Speed set to %dHz\n", ulChipClk));
|
|
|
|
hwDeviceExtension->ChipClockSpeed = ulChipClk;
|
|
hwDeviceExtension->RefClockSpeed = ulRefClk;
|
|
}
|
|
|
|
|
|
VOID
|
|
ZeroMemAndDac(
|
|
PHW_DEVICE_EXTENSION hwDeviceExtension,
|
|
ULONG RequestedMode
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Initialize the DAC to 0 (black).
|
|
|
|
Arguments:
|
|
|
|
hwDeviceExtension - Supplies a pointer to the miniport's device extension.
|
|
|
|
RequestedMode - use the VIDEO_MODE_NO_ZERO_MEMORY bit to determine if the
|
|
framebuffer should be cleared
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
|
|
{
|
|
ULONG i;
|
|
P2_DECL;
|
|
TVP4020_DECL;
|
|
P2RD_DECL;
|
|
|
|
//
|
|
// Turn off the screen at the DAC.
|
|
//
|
|
|
|
if (hwDeviceExtension->DacId == TVP4020_RAMDAC)
|
|
{
|
|
TVP4020_SET_PIXEL_READMASK (0x0);
|
|
TVP4020_PALETTE_START_WR (0);
|
|
|
|
for (i = 0; i <= VIDEO_MAX_COLOR_REGISTER; i++)
|
|
{
|
|
TVP4020_LOAD_PALETTE (0, 0, 0);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
P2RD_SET_PIXEL_READMASK (0x0);
|
|
P2RD_PALETTE_START_WR(0);
|
|
|
|
for (i = 0; i <= VIDEO_MAX_COLOR_REGISTER; i++)
|
|
{
|
|
P2RD_LOAD_PALETTE (0, 0, 0);
|
|
}
|
|
}
|
|
|
|
if (!(RequestedMode & VIDEO_MODE_NO_ZERO_MEMORY))
|
|
{
|
|
//
|
|
// Zero the memory. Don't use Permedia 2 as we would have to save and
|
|
// restore state and that's a pain. This is not time critical.
|
|
//
|
|
|
|
VideoPortZeroDeviceMemory(hwDeviceExtension->pFramebuffer,
|
|
hwDeviceExtension->FrameLength);
|
|
|
|
DEBUG_PRINT((1, "PERM2: framebuffer cleared\n"));
|
|
}
|
|
|
|
//
|
|
// Turn on the screen at the DAC
|
|
//
|
|
|
|
if (hwDeviceExtension->DacId == TVP4020_RAMDAC)
|
|
{
|
|
TVP4020_SET_PIXEL_READMASK (0xff);
|
|
}
|
|
else
|
|
{
|
|
P2RD_SET_PIXEL_READMASK (0xff);
|
|
}
|
|
|
|
LUT_CACHE_INIT();
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
#if DBG
|
|
|
|
VOID
|
|
DumpPCIConfigSpace(
|
|
PVOID HwDeviceExtension,
|
|
ULONG bus,
|
|
ULONG slot)
|
|
{
|
|
|
|
PPCI_COMMON_CONFIG PciData;
|
|
UCHAR buffer[sizeof(PCI_COMMON_CONFIG)];
|
|
ULONG j;
|
|
|
|
PciData = (PPCI_COMMON_CONFIG)buffer;
|
|
|
|
j = VideoPortGetBusData( HwDeviceExtension,
|
|
PCIConfiguration,
|
|
slot,
|
|
PciData,
|
|
0,
|
|
PCI_COMMON_HDR_LENGTH + 4 );
|
|
|
|
//
|
|
// don't report junk slots
|
|
//
|
|
|
|
if (PciData->VendorID == 0xffff)
|
|
return;
|
|
|
|
DEBUG_PRINT((2, "PERM2: DumpPCIConfigSpace: VideoPortGetBusData returned %d PCI_COMMON_HDR_LENGTH = %d\n",
|
|
j, PCI_COMMON_HDR_LENGTH+4));
|
|
|
|
DEBUG_PRINT((2, "DumpPCIConfigSpace: ------------------------\n"));
|
|
DEBUG_PRINT((2, " Bus: %d\n", bus ));
|
|
DEBUG_PRINT((2, " Slot: %d\n", slot ));
|
|
DEBUG_PRINT((2, " Vendor Id: 0x%x\n", PciData->VendorID ));
|
|
DEBUG_PRINT((2, " Device Id: 0x%x\n", PciData->DeviceID ));
|
|
DEBUG_PRINT((2, " Command: 0x%x\n", PciData->Command ));
|
|
DEBUG_PRINT((2, " Status: 0x%x\n", PciData->Status ));
|
|
DEBUG_PRINT((2, " Rev Id: 0x%x\n", PciData->RevisionID ));
|
|
DEBUG_PRINT((2, " ProgIf: 0x%x\n", PciData->ProgIf ));
|
|
DEBUG_PRINT((2, " SubClass: 0x%x\n", PciData->SubClass ));
|
|
DEBUG_PRINT((2, " BaseClass: 0x%x\n", PciData->BaseClass ));
|
|
DEBUG_PRINT((2, " CacheLine: 0x%x\n", PciData->CacheLineSize ));
|
|
DEBUG_PRINT((2, " Latency: 0x%x\n", PciData->LatencyTimer ));
|
|
DEBUG_PRINT((2, " Header Type: 0x%x\n", PciData->HeaderType ));
|
|
DEBUG_PRINT((2, " BIST: 0x%x\n", PciData->BIST ));
|
|
DEBUG_PRINT((2, " Base Reg[0]: 0x%x\n", PciData->u.type0.BaseAddresses[0] ));
|
|
DEBUG_PRINT((2, " Base Reg[1]: 0x%x\n", PciData->u.type0.BaseAddresses[1] ));
|
|
DEBUG_PRINT((2, " Base Reg[2]: 0x%x\n", PciData->u.type0.BaseAddresses[2] ));
|
|
DEBUG_PRINT((2, " Base Reg[3]: 0x%x\n", PciData->u.type0.BaseAddresses[3] ));
|
|
DEBUG_PRINT((2, " Base Reg[4]: 0x%x\n", PciData->u.type0.BaseAddresses[4] ));
|
|
DEBUG_PRINT((2, " Base Reg[5]: 0x%x\n", PciData->u.type0.BaseAddresses[5] ));
|
|
DEBUG_PRINT((2, " Rom Base: 0x%x\n", PciData->u.type0.ROMBaseAddress ));
|
|
DEBUG_PRINT((2, " Interrupt Line: 0x%x\n", PciData->u.type0.InterruptLine ));
|
|
DEBUG_PRINT((2, " Interrupt Pin: 0x%x\n", PciData->u.type0.InterruptPin ));
|
|
DEBUG_PRINT((2, " Min Grant: 0x%x\n", PciData->u.type0.MinimumGrant ));
|
|
DEBUG_PRINT((2, " Max Latency: 0x%x\n", PciData->u.type0.MaximumLatency ));
|
|
|
|
DEBUG_PRINT((2, " AGP Capability: 0x%x\n", buffer[0x40]));
|
|
DEBUG_PRINT((2, " AGP Next Cap: 0x%x\n", buffer[0x41]));
|
|
DEBUG_PRINT((2, " AGP Revision: 0x%x\n", buffer[0x42]));
|
|
DEBUG_PRINT((2, " AGP Status: 0x%x\n", buffer[0x43]));
|
|
|
|
}
|
|
|
|
#endif //DBG
|