Windows NT 4.0 source code leak
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.
 
 
 
 
 
 

5866 lines
169 KiB

/*++
Copyright (c) 1992 Microsoft Corporation
Copyright (c) 1994-1995 IBM Corporation
Module Name:
wd90c24a.c
Abstract:
This module contains the code that implements the WD90C24A/A2 miniport driver.
Environment:
kernel mode only
Notes:
Revision History:
--*/
#include "dderror.h"
#include "devioctl.h"
#include "miniport.h"
#include "ntddvdeo.h"
#include "video.h"
#include "wd90c24a.h"
#include "pvgaequ.h"
//
// Function declarations
//
// Functions that start with 'VGA' are entry points for the OS port driver.
//
VP_STATUS
VgaFindAdapter(
PVOID HwDeviceExtension,
PVOID HwContext,
PWSTR ArgumentString,
PVIDEO_PORT_CONFIG_INFO ConfigInfo,
PUCHAR Again
);
BOOLEAN
VgaInitialize(
PVOID HwDeviceExtension
);
BOOLEAN
VgaStartIO(
PVOID HwDeviceExtension,
PVIDEO_REQUEST_PACKET RequestPacket
);
VP_STATUS
WDRegistryCallback(
PVOID HwDeviceExtension,
PVOID Context,
PWSTR ValueName,
PVOID ValueData,
ULONG ValueLength
);
BOOLEAN
VgaResetHw(
IN PVOID HwDeviceExtension,
IN ULONG Columns,
IN ULONG Rows
);
//
// Private function prototypes.
//
VP_STATUS
VgaQueryAvailableModes(
PHW_DEVICE_EXTENSION HwDeviceExtension,
PVIDEO_MODE_INFORMATION ModeInformation,
ULONG ModeInformationSize,
PULONG OutputSize
);
VP_STATUS
VgaQueryNumberOfAvailableModes(
PHW_DEVICE_EXTENSION HwDeviceExtension,
PVIDEO_NUM_MODES NumModes,
ULONG NumModesSize,
PULONG OutputSize
);
VP_STATUS
VgaQueryCurrentMode(
PHW_DEVICE_EXTENSION HwDeviceExtension,
PVIDEO_MODE_INFORMATION ModeInformation,
ULONG ModeInformationSize,
PULONG OutputSize
);
VP_STATUS
VgaSetMode(
PHW_DEVICE_EXTENSION HwDeviceExtension,
PVIDEO_MODE Mode,
ULONG ModeSize
);
BOOLEAN
VgaIsPresent(
PHW_DEVICE_EXTENSION HwDeviceExtension
);
BOOLEAN
WdIsPresent(
PHW_DEVICE_EXTENSION HwDeviceExtension
);
VOID
VgaSizeMemory(
PHW_DEVICE_EXTENSION HwDeviceExtension
);
VOID
VgaInterpretCmdStream(
PVOID HwDeviceExtension,
PUSHORT pusCmdStream
);
VP_STATUS
VgaSetColorLookup(
PHW_DEVICE_EXTENSION HwDeviceExtension,
PVIDEO_CLUT ClutBuffer,
ULONG ClutBufferSize
);
#ifdef i386
VP_STATUS
VgaLoadAndSetFont(
PHW_DEVICE_EXTENSION HwDeviceExtension,
PVIDEO_LOAD_FONT_INFORMATION FontInformation,
ULONG FontInformationSize
);
VP_STATUS
VgaQueryCursorPosition(
PHW_DEVICE_EXTENSION HwDeviceExtension,
PVIDEO_CURSOR_POSITION CursorPosition,
ULONG CursorPositionSize,
PULONG OutputSize
);
VP_STATUS
VgaSetCursorPosition(
PHW_DEVICE_EXTENSION HwDeviceExtension,
PVIDEO_CURSOR_POSITION CursorPosition,
ULONG CursorPositionSize
);
VP_STATUS
VgaQueryCursorAttributes(
PHW_DEVICE_EXTENSION HwDeviceExtension,
PVIDEO_CURSOR_ATTRIBUTES CursorAttributes,
ULONG CursorAttributesSize,
PULONG OutputSize
);
VP_STATUS
VgaSetCursorAttributes(
PHW_DEVICE_EXTENSION HwDeviceExtension,
PVIDEO_CURSOR_ATTRIBUTES CursorAttributes,
ULONG CursorAttributesSize
);
VP_STATUS
VgaSetPaletteReg(
PHW_DEVICE_EXTENSION HwDeviceExtension,
PVIDEO_PALETTE_DATA PaletteBuffer,
ULONG PaletteBufferSize
);
VP_STATUS
VgaRestoreHardwareState(
PHW_DEVICE_EXTENSION HwDeviceExtension,
PVIDEO_HARDWARE_STATE HardwareState,
ULONG HardwareStateSize
);
VP_STATUS
VgaSaveHardwareState(
PHW_DEVICE_EXTENSION HwDeviceExtension,
PVIDEO_HARDWARE_STATE HardwareState,
ULONG HardwareStateSize,
PULONG OutputSize
);
#endif
BOOLEAN
TestPortUchar(
PUCHAR IoPort,
UCHAR Mask
);
VOID
GetPanelType(
PHW_DEVICE_EXTENSION HwDeviceExtension
);
VOID
VgaSetVirtualScreenPosition(
PHW_DEVICE_EXTENSION HwDeviceExtension
);
VOID
VgaValidateModes(
PHW_DEVICE_EXTENSION HwDeviceExtension
);
//
// External functions
//
VOID
UnlockAll(
PHW_DEVICE_EXTENSION HwDeviceExtension
);
#if defined(ALLOC_PRAGMA)
#pragma alloc_text(PAGE,DriverEntry)
#pragma alloc_text(PAGE,VgaFindAdapter)
#pragma alloc_text(PAGE,VgaInitialize)
#pragma alloc_text(PAGE,VgaStartIO)
#pragme alloc_text(PAGE,WDRegistryCallback)
#pragma alloc_text(PAGE,VgaResetHw)
#pragma alloc_text(PAGE,VgaIsPresent)
#pragma alloc_text(PAGE,WdIsPresent)
#pragma alloc_text(PAGE,VgaSizeMemory)
#pragma alloc_text(PAGE,VgaSetColorLookup)
#ifdef i386
#pragma alloc_text(PAGE,VgaLoadAndSetFont)
#pragma alloc_text(PAGE,VgaQueryCursorPosition)
#pragma alloc_text(PAGE,VgaSetCursorPosition)
#pragma alloc_text(PAGE,VgaQueryCursorAttributes)
#pragma alloc_text(PAGE,VgaSetCursorAttributes)
#pragma alloc_text(PAGE,VgaSetPaletteReg)
#pragma alloc_text(PAGE,VgaRestoreHardwareState)
#pragma alloc_text(PAGE,VgaSaveHardwareState)
#ifndef ENABLE_LINEAR_FRAME_BUFFER
#pragma alloc_text(PAGE,VgaGetBankSelectCode)
#endif
#pragma alloc_text(PAGE,VgaValidatorUcharEntry)
#pragma alloc_text(PAGE,VgaValidatorUshortEntry)
#pragma alloc_text(PAGE,VgaValidatorUlongEntry)
#endif
#pragma alloc_text(PAGE,TestPortUchar)
#pragma alloc_text(PAGE,GetPanelType)
#pragma alloc_text(PAGE,VgaSetVirtualScreenPosition)
#endif
ULONG
DriverEntry(
PVOID Context1,
PVOID Context2
)
/*++
Routine Description:
Installable driver initialization entry point.
This entry point is called directly by the I/O system.
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;
ULONG 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 = VgaFindAdapter;
hwInitData.HwInitialize = VgaInitialize;
hwInitData.HwInterrupt = NULL;
hwInitData.HwStartIO = VgaStartIO;
hwInitData.HwResetHw = VgaResetHw;
//
// Determine the size we require for the device extension.
//
hwInitData.HwDeviceExtensionSize = sizeof(HW_DEVICE_EXTENSION);
//
// Always start with parameters for device0 in this case.
// We can leave it like this since we know we will only ever find one
// VGA type adapter in a machine.
//
// hwInitData.StartingDeviceNumber = 0;
//
// Once all the relevant information has been stored, call the video
// port driver to do the initialization.
// For this device we will repeat this call four times, for ISA, EISA
// Internal and PCI.
// We will return the minimum of all return values.
//
//
// We will try the PCI bus first so that our ISA detection does'nt claim
// PCI cards.
//
//
// NOTE: since this driver only supports one adapter, we will return
// as soon as we find a device, without going on to the following buses.
// Normally one would call for each bus type and return the smallest
// value.
//
#ifdef PPC
hwInitData.AdapterInterfaceType = PCIBus;
initializationStatus = VideoPortInitialize(Context1,
Context2,
&hwInitData,
NULL);
if (initializationStatus == NO_ERROR)
{
return initializationStatus;
}
#endif
hwInitData.AdapterInterfaceType = MicroChannel;
initializationStatus = VideoPortInitialize(Context1,
Context2,
&hwInitData,
NULL);
//
// Return immediately instead of checkin for smallest return code.
//
if (initializationStatus == NO_ERROR)
{
return initializationStatus;
}
hwInitData.AdapterInterfaceType = Isa;
initializationStatus = VideoPortInitialize(Context1,
Context2,
&hwInitData,
NULL);
//
// Return immediately instead of checkin for smallest return code.
//
if (initializationStatus == NO_ERROR)
{
return initializationStatus;
}
hwInitData.AdapterInterfaceType = Eisa;
initializationStatus = VideoPortInitialize(Context1,
Context2,
&hwInitData,
NULL);
//
// Return immediately instead of checkin for smallest return code.
//
if (initializationStatus == NO_ERROR)
{
return initializationStatus;
}
hwInitData.AdapterInterfaceType = Internal;
initializationStatus = VideoPortInitialize(Context1,
Context2,
&hwInitData,
NULL);
return initializationStatus;
} // end DriverEntry()
VP_STATUS
WDRegistryCallback(
PVOID HwDeviceExtension,
PVOID Context,
PWSTR ValueName,
PVOID ValueData,
ULONG ValueLength
)
/*++
Routine Description:
This routine determines if the alternate register set was requested via
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:
returns NO_ERROR if the paramter was TRUE.
returns ERROR_INVALID_PARAMETER otherwise.
--*/
{
PHW_DEVICE_EXTENSION hwDeviceExtension = HwDeviceExtension;
if ((ValueData != NULL) && (ValueLength == sizeof(USHORT))) {
hwDeviceExtension->VirtualScreenOption = *((PUSHORT)ValueData);
return NO_ERROR;
} else {
return ERROR_INVALID_PARAMETER;
}
} // end WDRegistryCallback()
BOOLEAN
VgaResetHw(
IN PVOID HwDeviceExtension,
IN ULONG Columns,
IN ULONG Rows
)
/*++
routine description:
This routine resets the video adapter to the VGA standard text mode.
It is expected that HAL will call this function when;
1. The system is about to crash, and the debug information is required to be
displayed.
2. The system is about to restart.
arguments:
HwDeviceExtension - pointer to the miniport driver's device extension.
Columns - Number of columns for text mode (not used).
Rows - Number of rows for text mode (not used).
return value:
Always returns FALSE so that HAL is required to perform int10-type initialization
after the control is returned.
--*/
{
PHW_DEVICE_EXTENSION hwDeviceExtension = HwDeviceExtension;
//
// Reset to 8bpp mode
//
UnlockAll(hwDeviceExtension);
VideoPortWritePortUchar(hwDeviceExtension->IOAddress + SEQ_ADDRESS_PORT, pr58a);
VideoPortWritePortUchar(hwDeviceExtension->IOAddress + SEQ_DATA_PORT, 0);
//
// Indicates that HAL should reset the video adapter to the desired text mode
//
return FALSE;
}
VP_STATUS
VgaFindAdapter(
PVOID HwDeviceExtension,
PVOID HwContext,
PWSTR ArgumentString,
PVIDEO_PORT_CONFIG_INFO ConfigInfo,
PUCHAR Again
)
/*++
Routine Description:
This routine is called to determine if the adapter for this driver
is present in the system.
If it is present, the function fills out some information describing
the adapter.
Arguments:
HwDeviceExtension - Supplies the miniport driver's adapter storage. This
storage is initialized to zero before this call.
HwContext - Supplies the context value which was passed to
VideoPortInitialize().
ArgumentString - Supplies a NULL terminated ASCII string. This string
originates from the user.
ConfigInfo - Returns the configuration information structure which is
filled by the miniport driver. This structure is initialized with
any known configuration information (such as SystemIoBusNumber) by
the port driver. Where possible, drivers should have one set of
defaults which do not require any supplied configuration information.
Again - Indicates if the miniport driver wants the port driver to call
its VIDEO_HW_FIND_ADAPTER function again with a new device extension
and the same config info. This is used by the miniport drivers which
can search for several adapters on a bus.
Return Value:
This routine must return:
NO_ERROR - Indicates a host adapter was found and the
configuration information was successfully determined.
ERROR_INVALID_PARAMETER - Indicates an adapter was found but there was an
error obtaining the configuration information. If possible an error
should be logged.
ERROR_DEV_NOT_EXIST - Indicates no host adapter was found for the
supplied configuration information.
--*/
{
PHW_DEVICE_EXTENSION hwDeviceExtension = HwDeviceExtension;
VP_STATUS status;
//
// 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 (ConfigInfo->Length < sizeof(VIDEO_PORT_CONFIG_INFO)) {
return ERROR_INVALID_PARAMETER;
}
//
// No interrupt information is necessary.
//
//
// Check to see if there is a hardware resource conflict.
// Start by including the exted register. If that fails, then only use
// the normal registers.
//
hwDeviceExtension->ExtendedRegisters = TRUE;
status = VideoPortVerifyAccessRanges(hwDeviceExtension,
NUM_WD_ACCESS_RANGES,
VgaAccessRange);
if (status != NO_ERROR) {
hwDeviceExtension->ExtendedRegisters = FALSE;
status = VideoPortVerifyAccessRanges(hwDeviceExtension,
NUM_VGA_ACCESS_RANGES,
VgaAccessRange);
if (status != NO_ERROR) {
return status;
}
}
//
// Get logical IO port addresses.
//
if ( (hwDeviceExtension->IOAddress =
VideoPortGetDeviceBase(hwDeviceExtension,
VgaAccessRange->RangeStart,
VGA_MAX_IO_PORT - VGA_BASE_IO_PORT + 1,
TRUE)) == NULL) {
VideoDebugPrint((2, "VgaFindAdapter - Fail to get io address\n"));
return ERROR_INVALID_PARAMETER;
}
//
// Get logical Extended IO port addresses.
//
if ((hwDeviceExtension->ExtendedIOAddress =
VideoPortGetDeviceBase(HwDeviceExtension,
VgaAccessRange[3].RangeStart,
VgaAccessRange[3].RangeLength,
VgaAccessRange[3].RangeInIoSpace)) == NULL) {
VideoDebugPrint((2, "VgaFindAdapter - Fail to get extended io address\n"));
return ERROR_INVALID_PARAMETER;
}
//
// Determine whether a VGA is present.
//
if (!VgaIsPresent(hwDeviceExtension)) {
return ERROR_DEV_NOT_EXIST;
}
//
// Determine whether a WD chipset is present.
//
if (!WdIsPresent(hwDeviceExtension)) {
return ERROR_DEV_NOT_EXIST;
}
//
// Get Registry parameter.
// If that fails, then create Registry parameters.
//
if (NO_ERROR != VideoPortGetRegistryParameters(hwDeviceExtension,
L"VirtualScreen",
FALSE,
WDRegistryCallback,
NULL)) {
hwDeviceExtension->VirtualScreenOption = 2; // default is "AUTO"
VideoPortSetRegistryParameters(hwDeviceExtension,
L"VirtualScreen",
&hwDeviceExtension->VirtualScreenOption,
sizeof(USHORT));
}
#ifdef i386
//
// Pass a pointer to the emulator range we are using.
//
ConfigInfo->NumEmulatorAccessEntries = VGA_NUM_EMULATOR_ACCESS_ENTRIES;
ConfigInfo->EmulatorAccessEntries = VgaEmulatorAccessEntries;
ConfigInfo->EmulatorAccessEntriesContext = (ULONG) hwDeviceExtension;
ConfigInfo->VdmPhysicalVideoMemoryAddress.LowPart = MEM_VGA;
ConfigInfo->VdmPhysicalVideoMemoryAddress.HighPart = 0x00000000;
ConfigInfo->VdmPhysicalVideoMemoryLength = MEM_VGA_SIZE;
#else
//
// 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;
ConfigInfo->VdmPhysicalVideoMemoryAddress.LowPart = 0x00000000;
ConfigInfo->VdmPhysicalVideoMemoryAddress.HighPart = 0x00000000;
ConfigInfo->VdmPhysicalVideoMemoryLength = 0x00000000;
#endif
//
// Minimum size of the buffer required to store the hardware state
// information returned by IOCTL_VIDEO_SAVE_HARDWARE_STATE.
//
// This frame buffer driver does not require the hardware state
// save/restore because it is not VGA compatible.
ConfigInfo->HardwareStateSize = 0;
//
// Video memory information
//
hwDeviceExtension->PhysicalVideoMemoryBase.HighPart = 0x00000000;
#ifndef ENABLE_LINEAR_FRAME_BUFFER
hwDeviceExtension->PhysicalVideoMemoryBase.LowPart = MEM_VGA;
hwDeviceExtension->PhysicalVideoMemoryLength = MEM_VGA_SIZE;
#else
hwDeviceExtension->PhysicalVideoMemoryBase.LowPart = MEM_FRAME;
hwDeviceExtension->PhysicalVideoMemoryLength = MEM_FRAME_SIZE;
#endif
//
// Map the video memory into the system virtual address space so we can
// clear it out and use it for save and restore.
//
if ( (hwDeviceExtension->VideoMemoryAddress =
VideoPortGetDeviceBase(hwDeviceExtension,
hwDeviceExtension->PhysicalVideoMemoryBase,
hwDeviceExtension->PhysicalVideoMemoryLength, FALSE)) == NULL) {
VideoDebugPrint((1, "VgaFindAdapter - Fail to get memory address\n"));
return ERROR_INVALID_PARAMETER;
}
//
// Indicate we do not wish to be called again for another initialization.
//
*Again = 0;
//
// Indicate a successful completion status.
//
return NO_ERROR;
} // VgaFindAdapter()
BOOLEAN
VgaInitialize(
PVOID HwDeviceExtension
)
/*++
Routine Description:
This routine does one time initialization of the device.
Arguments:
HwDeviceExtension - Pointer to the miniport driver's adapter information.
Return Value:
None.
--*/
{
PHW_DEVICE_EXTENSION hwDeviceExtension = HwDeviceExtension;
#ifdef i386
//
// set up the default cursor position and type.
//
hwDeviceExtension->CursorPosition.Column = 0;
hwDeviceExtension->CursorPosition.Row = 0;
hwDeviceExtension->CursorTopScanLine = 0;
hwDeviceExtension->CursorBottomScanLine = 31;
hwDeviceExtension->CursorEnable = TRUE;
#endif
return TRUE;
} // VgaInitialize()
BOOLEAN
VgaStartIO(
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 - Pointer to the miniport driver's adapter information.
RequestPacket - Pointer to the video request packet. This structure
contains all the parameters passed to the VideoIoControl function.
Return Value:
This routine will return error codes from the various support routines
and will also return ERROR_INSUFFICIENT_BUFFER for incorrectly sized
buffers and ERROR_INVALID_FUNCTION for unsupported functions.
--*/
{
PHW_DEVICE_EXTENSION hwDeviceExtension = HwDeviceExtension;
VP_STATUS status;
VIDEO_MODE videoMode;
PVIDEO_MEMORY_INFORMATION memoryInformation;
PVIDEO_SHARE_MEMORY pShareMemory;
PVIDEO_SHARE_MEMORY_INFORMATION pShareMemoryInformation;
PHYSICAL_ADDRESS shareAddress;
PVOID virtualAddress;
ULONG sharedViewSize;
ULONG inIoSpace;
//
// Switch on the IoContolCode in the RequestPacket. It indicates which
// function must be performed by the driver.
//
switch (RequestPacket->IoControlCode) {
case IOCTL_VIDEO_MAP_VIDEO_MEMORY:
VideoDebugPrint((2, "VgaStartIO - MapVideoMemory\n"));
if ( (RequestPacket->OutputBufferLength <
(RequestPacket->StatusBlock->Information =
sizeof(VIDEO_MEMORY_INFORMATION))) ||
(RequestPacket->InputBufferLength < sizeof(VIDEO_MEMORY)) ) {
status = ERROR_INSUFFICIENT_BUFFER;
}
memoryInformation = RequestPacket->OutputBuffer;
memoryInformation->VideoRamBase = ((PVIDEO_MEMORY)
(RequestPacket->InputBuffer))->RequestedVirtualAddress;
memoryInformation->VideoRamLength =
hwDeviceExtension->PhysicalVideoMemoryLength;
inIoSpace = 0;
status = VideoPortMapMemory(hwDeviceExtension,
hwDeviceExtension->PhysicalVideoMemoryBase,
&(memoryInformation->VideoRamLength),
&inIoSpace,
&(memoryInformation->VideoRamBase));
//
// The frame buffer and virtual memory and equivalent in this
// case.
//
memoryInformation->FrameBufferBase =
memoryInformation->VideoRamBase;
memoryInformation->FrameBufferLength =
hwDeviceExtension->PhysicalFrameLength;
break;
case IOCTL_VIDEO_UNMAP_VIDEO_MEMORY:
VideoDebugPrint((2, "VgaStartIO - UnMapVideoMemory\n"));
if (RequestPacket->InputBufferLength < sizeof(VIDEO_MEMORY)) {
status = ERROR_INSUFFICIENT_BUFFER;
}
status = VideoPortUnmapMemory(hwDeviceExtension,
((PVIDEO_MEMORY)
(RequestPacket->InputBuffer))->
RequestedVirtualAddress,
0);
break;
case IOCTL_VIDEO_QUERY_AVAIL_MODES:
VideoDebugPrint((2, "VgaStartIO - QueryAvailableModes\n"));
status = VgaQueryAvailableModes(HwDeviceExtension,
(PVIDEO_MODE_INFORMATION)
RequestPacket->OutputBuffer,
RequestPacket->OutputBufferLength,
&RequestPacket->StatusBlock->Information);
break;
case IOCTL_VIDEO_QUERY_NUM_AVAIL_MODES:
VideoDebugPrint((2, "VgaStartIO - QueryNumAvailableModes\n"));
status = VgaQueryNumberOfAvailableModes(HwDeviceExtension,
(PVIDEO_NUM_MODES)
RequestPacket->OutputBuffer,
RequestPacket->OutputBufferLength,
&RequestPacket->StatusBlock->Information);
break;
case IOCTL_VIDEO_QUERY_CURRENT_MODE:
VideoDebugPrint((2, "VgaStartIO - QueryCurrentMode\n"));
status = VgaQueryCurrentMode(HwDeviceExtension,
(PVIDEO_MODE_INFORMATION) RequestPacket->OutputBuffer,
RequestPacket->OutputBufferLength,
&RequestPacket->StatusBlock->Information);
break;
case IOCTL_VIDEO_SET_CURRENT_MODE:
VideoDebugPrint((2, "VgaStartIO - SetCurrentModes\n"));
status = VgaSetMode(HwDeviceExtension,
(PVIDEO_MODE) RequestPacket->InputBuffer,
RequestPacket->InputBufferLength);
break;
case IOCTL_VIDEO_RESET_DEVICE:
VideoDebugPrint((2, "VgaStartIO - Reset Device\n"));
#ifdef i386
videoMode.RequestedMode = DEFAULT_MODE;
status = VgaSetMode(HwDeviceExtension,
(PVIDEO_MODE) &videoMode,
sizeof(videoMode));
#else
//
// Just make sure we return success for this IOCTL so we do not
// fail it, and display driver does no break on failiure.
//
// This IOCTL does not do anything on this machine because there
// is no basic mode to return to ...
//
status = NO_ERROR;
#endif
break;
#ifdef i386
case IOCTL_VIDEO_LOAD_AND_SET_FONT:
VideoDebugPrint((2, "VgaStartIO - LoadAndSetFont\n"));
status = VgaLoadAndSetFont(HwDeviceExtension,
(PVIDEO_LOAD_FONT_INFORMATION) RequestPacket->InputBuffer,
RequestPacket->InputBufferLength);
break;
case IOCTL_VIDEO_QUERY_CURSOR_POSITION:
VideoDebugPrint((2, "VgaStartIO - QueryCursorPosition\n"));
status = VgaQueryCursorPosition(HwDeviceExtension,
(PVIDEO_CURSOR_POSITION) RequestPacket->OutputBuffer,
RequestPacket->OutputBufferLength,
&RequestPacket->StatusBlock->Information);
break;
case IOCTL_VIDEO_SET_CURSOR_POSITION:
VideoDebugPrint((2, "VgaStartIO - SetCursorPosition\n"));
status = VgaSetCursorPosition(HwDeviceExtension,
(PVIDEO_CURSOR_POSITION)
RequestPacket->InputBuffer,
RequestPacket->InputBufferLength);
break;
case IOCTL_VIDEO_QUERY_CURSOR_ATTR:
VideoDebugPrint((2, "VgaStartIO - QueryCursorAttributes\n"));
status = VgaQueryCursorAttributes(HwDeviceExtension,
(PVIDEO_CURSOR_ATTRIBUTES) RequestPacket->OutputBuffer,
RequestPacket->OutputBufferLength,
&RequestPacket->StatusBlock->Information);
break;
case IOCTL_VIDEO_SET_CURSOR_ATTR:
VideoDebugPrint((2, "VgaStartIO - SetCursorAttributes\n"));
status = VgaSetCursorAttributes(HwDeviceExtension,
(PVIDEO_CURSOR_ATTRIBUTES) RequestPacket->InputBuffer,
RequestPacket->InputBufferLength);
break;
case IOCTL_VIDEO_SET_PALETTE_REGISTERS:
VideoDebugPrint((2, "VgaStartIO - SetPaletteRegs\n"));
status = VgaSetPaletteReg(HwDeviceExtension,
(PVIDEO_PALETTE_DATA) RequestPacket->InputBuffer,
RequestPacket->InputBufferLength);
break;
case IOCTL_VIDEO_ENABLE_VDM:
VideoDebugPrint((2, "VgaStartIO - EnableVDM\n"));
hwDeviceExtension->TrappedValidatorCount = 0;
hwDeviceExtension->SequencerAddressValue = 0;
hwDeviceExtension->CurrentNumVdmAccessRanges =
NUM_MINIMAL_VGA_VALIDATOR_ACCESS_RANGE;
hwDeviceExtension->CurrentVdmAccessRange =
MinimalVgaValidatorAccessRange;
VideoPortSetTrappedEmulatorPorts(hwDeviceExtension,
hwDeviceExtension->CurrentNumVdmAccessRanges,
hwDeviceExtension->CurrentVdmAccessRange);
status = NO_ERROR;
break;
case IOCTL_VIDEO_RESTORE_HARDWARE_STATE:
VideoDebugPrint((2, "VgaStartIO - RestoreHardwareState\n"));
status = VgaRestoreHardwareState(HwDeviceExtension,
(PVIDEO_HARDWARE_STATE) RequestPacket->InputBuffer,
RequestPacket->InputBufferLength);
break;
case IOCTL_VIDEO_SAVE_HARDWARE_STATE:
VideoDebugPrint((2, "VgaStartIO - SaveHardwareState\n"));
status = VgaSaveHardwareState(HwDeviceExtension,
(PVIDEO_HARDWARE_STATE) RequestPacket->OutputBuffer,
RequestPacket->OutputBufferLength,
&RequestPacket->StatusBlock->Information);
break;
#endif
case IOCTL_VIDEO_SET_COLOR_REGISTERS:
VideoDebugPrint((2, "VgaStartIO - SetColorRegs\n"));
status = VgaSetColorLookup(HwDeviceExtension,
(PVIDEO_CLUT) RequestPacket->InputBuffer,
RequestPacket->InputBufferLength);
break;
// The following code is added that the user-mode driver gets
// some virtual addresses of a hardware IO.
// The user-mode driver uses them for a hardware assist.
case IOCTL_VIDEO_QUERY_PUBLIC_ACCESS_RANGES:
VideoDebugPrint((2, "VgaStartIO - QueryPublicAccessRanges\n"));
{
PVIDEO_PUBLIC_ACCESS_RANGES portAccess;
ULONG physicalPortLength;
if ( RequestPacket->OutputBufferLength <
(RequestPacket->StatusBlock->Information =
sizeof(VIDEO_PUBLIC_ACCESS_RANGES)) ) {
status = ERROR_INSUFFICIENT_BUFFER;
break;
}
portAccess = RequestPacket->OutputBuffer;
portAccess->VirtualAddress = (PVOID) NULL; // Requested VA
portAccess->InIoSpace = VgaAccessRange[0].RangeInIoSpace;
portAccess->MappedInIoSpace = portAccess->InIoSpace;
physicalPortLength = 0x10000;
status = VideoPortMapMemory(hwDeviceExtension,
VgaAccessRange[0].RangeStart,
&physicalPortLength,
&(portAccess->MappedInIoSpace),
&(portAccess->VirtualAddress));
}
break;
case IOCTL_VIDEO_SET_POINTER_POSITION:
VideoDebugPrint((2, "VgaStartIO - SetPointerPosition\n"));
if (RequestPacket->InputBufferLength < sizeof(VIDEO_POINTER_POSITION)) {
status = ERROR_INSUFFICIENT_BUFFER;
} else {
VIDEO_POINTER_POSITION *pPointerPosition;
PUSHORT ExtIoBase;
ULONG x, y;
ExtIoBase = (PUSHORT) hwDeviceExtension->ExtendedIOAddress;
pPointerPosition = (VIDEO_POINTER_POSITION *) RequestPacket->InputBuffer;
// Retrieve the new position from the request packet
x = (ULONG)pPointerPosition->Column;
y = (ULONG)pPointerPosition->Row;
//
// Scroll the screen if virtual screen mode is active
//
if (hwDeviceExtension->VirtualScreenEnable) {
ULONG pSize_x, pSize_y;
ULONG vSize_x, vSize_y;
ULONG vPos_x, vPos_y;
vSize_x = hwDeviceExtension->CurrentMode->hres;
vSize_y = hwDeviceExtension->CurrentMode->vres;
vPos_x = hwDeviceExtension->VirtualScreenPosX;
vPos_y = hwDeviceExtension->VirtualScreenPosY;
pSize_x = hwDeviceExtension->PanelXResolution;
pSize_y = hwDeviceExtension->PanelYResolution;
//
// Adjust horizontal position
//
// Note: The new position must be aligned at 4-pixel boundary since
// horizontal pel panning register does not work in 8bpp/16bpp
// mode.
//
if (x < vPos_x) {
vPos_x = x & ~0x03;
} else if (x >= (vPos_x + pSize_x)) {
vPos_x = ((x - pSize_x + 1) + 3) & ~0x03;
} /* endif */
//
// Adjust vertical position
//
// Note: The vertical position is adjusted to prevent the LCD screen
// from flickering when desktop is not set to the solid color.
//
if (y < vPos_y) {
vPos_y = y & ~0x01;
} else if (y >= (vPos_y + pSize_y)) {
vPos_y = ((y - pSize_y + 1) + 1) & ~0x01;
} /* endif */
//
// Update the virtual screen position
//
hwDeviceExtension->VirtualScreenPosX = vPos_x;
hwDeviceExtension->VirtualScreenPosY = vPos_y;
VgaSetVirtualScreenPosition(hwDeviceExtension);
//
// Adjust the hardware cursor position since it should be set to the
// relative position of the upper left corner of visible portion.
//
x -= vPos_x;
y -= vPos_y;
} /* endif */
//
// move the hardware pointer to the new location
//
VideoPortWritePortUshort(ExtIoBase + 0, 0x1002);
VideoPortWritePortUshort(ExtIoBase + 1, (USHORT)(CUR_POS_X | x));
VideoPortWritePortUshort(ExtIoBase + 1, (USHORT)(CUR_POS_Y | y));
VideoPortWritePortUshort(ExtIoBase + 1, VideoPortReadPortUshort(ExtIoBase + 1));
status = NO_ERROR;
}
break;
case IOCTL_VIDEO_SHARE_VIDEO_MEMORY:
VideoDebugPrint((2, "VgaStartIO - ShareVideoMemory\n"));
if ( (RequestPacket->OutputBufferLength < sizeof(VIDEO_SHARE_MEMORY_INFORMATION)) ||
(RequestPacket->InputBufferLength < sizeof(VIDEO_MEMORY)) ) {
VideoDebugPrint((0, "IOCTL_VIDEO_SHARE_VIDEO_MEMORY - ERROR_INSUFFICIENT_BUFFER\n"));
status = ERROR_INSUFFICIENT_BUFFER;
break;
}
pShareMemory = RequestPacket->InputBuffer;
if ( (pShareMemory->ViewOffset > hwDeviceExtension->PhysicalFrameLength) ||
((pShareMemory->ViewOffset + pShareMemory->ViewSize) >
hwDeviceExtension->PhysicalFrameLength) ) {
VideoDebugPrint((0, "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 = 0;
//
// NOTE: we are ignoring ViewOffset
//
shareAddress.QuadPart =
hwDeviceExtension->PhysicalVideoMemoryBase.QuadPart;
//
// The frame buffer is always mapped linearly.
//
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:
VideoDebugPrint((2, "VgaStartIO - 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;
//
// if we get here, an invalid IoControlCode was specified.
//
default:
VideoDebugPrint((1, "Fell through vga startIO routine - invalid command\n"));
status = ERROR_INVALID_FUNCTION;
break;
}
RequestPacket->StatusBlock->Status = status;
return TRUE;
} // VgaStartIO()
//
// private routines
//
BOOLEAN
VgaIsPresent(
PHW_DEVICE_EXTENSION HwDeviceExtension
)
/*++
Routine Description:
This routine returns TRUE if a VGA is present. Determining whether a VGA
is present is a two-step process. First, this routine walks bits through
the Bit Mask register, to establish that there are readable indexed
registers (EGAs normally don't have readable registers, and other adapters
are unlikely to have indexed registers). This test is done first because
it's a non-destructive EGA rejection test (correctly rejects EGAs, but
doesn't potentially mess up the screen or the accessibility of display
memory). Normally, this would be an adequate test, but some EGAs have
readable registers, so next, we check for the existence of the Chain4 bit
in the Memory Mode register; this bit doesn't exist in EGAs. It's
conceivable that there are EGAs with readable registers and a register bit
where Chain4 is stored, although I don't know of any; if a better test yet
is needed, memory could be written to in Chain4 mode, and then examined
plane by plane in non-Chain4 mode to make sure the Chain4 bit did what it's
supposed to do. However, the current test should be adequate to eliminate
just about all EGAs, and 100% of everything else.
If this function fails to find a VGA, it attempts to undo any damage it
may have inadvertently done while testing. The underlying assumption for
the damage control is that if there's any non-VGA adapter at the tested
ports, it's an EGA or an enhanced EGA, because: a) I don't know of any
other adapters that use 3C4/5 or 3CE/F, and b), if there are other
adapters, I certainly don't know how to restore their original states. So
all error recovery is oriented toward putting an EGA back in a writable
state, so that error messages are visible. The EGA's state on entry is
assumed to be text mode, so the Memory Mode register is restored to the
default state for text mode.
If a VGA is found, the VGA is returned to its original state after
testing is finished.
Arguments:
None.
Return Value:
TRUE if a VGA is present, FALSE if not.
--*/
{
UCHAR originalGCAddr;
UCHAR originalSCAddr;
UCHAR originalBitMask;
UCHAR originalReadMap;
UCHAR originalMemoryMode;
UCHAR testMask;
BOOLEAN returnStatus;
//
// Remember the original state of the Graphics Controller Address register.
//
originalGCAddr = VideoPortReadPortUchar(HwDeviceExtension->IOAddress +
GRAPH_ADDRESS_PORT);
//
// Write the Read Map register with a known state so we can verify
// that it isn't changed after we fool with the Bit Mask. This ensures
// that we're dealing with indexed registers, since both the Read Map and
// the Bit Mask are addressed at GRAPH_DATA_PORT.
//
VideoPortWritePortUchar(HwDeviceExtension->IOAddress +
GRAPH_ADDRESS_PORT, IND_READ_MAP);
//
// If we can't read back the Graphics Address register setting we just
// performed, it's not readable and this isn't a VGA.
//
if ((VideoPortReadPortUchar(HwDeviceExtension->IOAddress +
GRAPH_ADDRESS_PORT) & GRAPH_ADDR_MASK) != IND_READ_MAP) {
return FALSE;
}
//
// Set the Read Map register to a known state.
//
originalReadMap = VideoPortReadPortUchar(HwDeviceExtension->IOAddress +
GRAPH_DATA_PORT);
VideoPortWritePortUchar(HwDeviceExtension->IOAddress +
GRAPH_DATA_PORT, READ_MAP_TEST_SETTING);
if (VideoPortReadPortUchar(HwDeviceExtension->IOAddress +
GRAPH_DATA_PORT) != READ_MAP_TEST_SETTING) {
//
// The Read Map setting we just performed can't be read back; not a
// VGA. Restore the default Read Map state.
//
VideoPortWritePortUchar(HwDeviceExtension->IOAddress +
GRAPH_DATA_PORT, READ_MAP_DEFAULT);
return FALSE;
}
//
// Remember the original setting of the Bit Mask register.
//
VideoPortWritePortUchar(HwDeviceExtension->IOAddress +
GRAPH_ADDRESS_PORT, IND_BIT_MASK);
if ((VideoPortReadPortUchar(HwDeviceExtension->IOAddress +
GRAPH_ADDRESS_PORT) & GRAPH_ADDR_MASK) != IND_BIT_MASK) {
//
// The Graphics Address register setting we just made can't be read
// back; not a VGA. Restore the default Read Map state.
//
VideoPortWritePortUchar(HwDeviceExtension->IOAddress +
GRAPH_ADDRESS_PORT, IND_READ_MAP);
VideoPortWritePortUchar(HwDeviceExtension->IOAddress +
GRAPH_DATA_PORT, READ_MAP_DEFAULT);
return FALSE;
}
originalBitMask = VideoPortReadPortUchar(HwDeviceExtension->IOAddress +
GRAPH_DATA_PORT);
//
// Set up the initial test mask we'll write to and read from the Bit Mask.
//
testMask = 0xBB;
do {
//
// Write the test mask to the Bit Mask.
//
VideoPortWritePortUchar(HwDeviceExtension->IOAddress +
GRAPH_DATA_PORT, testMask);
//
// Make sure the Bit Mask remembered the value.
//
if (VideoPortReadPortUchar(HwDeviceExtension->IOAddress +
GRAPH_DATA_PORT) != testMask) {
//
// The Bit Mask is not properly writable and readable; not a VGA.
// Restore the Bit Mask and Read Map to their default states.
//
VideoPortWritePortUchar(HwDeviceExtension->IOAddress +
GRAPH_DATA_PORT, BIT_MASK_DEFAULT);
VideoPortWritePortUchar(HwDeviceExtension->IOAddress +
GRAPH_ADDRESS_PORT, IND_READ_MAP);
VideoPortWritePortUchar(HwDeviceExtension->IOAddress +
GRAPH_DATA_PORT, READ_MAP_DEFAULT);
return FALSE;
}
//
// Cycle the mask for next time.
//
testMask >>= 1;
} while (testMask != 0);
//
// There's something readable at GRAPH_DATA_PORT; now switch back and
// make sure that the Read Map register hasn't changed, to verify that
// we're dealing with indexed registers.
//
VideoPortWritePortUchar(HwDeviceExtension->IOAddress +
GRAPH_ADDRESS_PORT, IND_READ_MAP);
if (VideoPortReadPortUchar(HwDeviceExtension->IOAddress +
GRAPH_DATA_PORT) != READ_MAP_TEST_SETTING) {
//
// The Read Map is not properly writable and readable; not a VGA.
// Restore the Bit Mask and Read Map to their default states, in case
// this is an EGA, so subsequent writes to the screen aren't garbled.
//
VideoPortWritePortUchar(HwDeviceExtension->IOAddress +
GRAPH_DATA_PORT, READ_MAP_DEFAULT);
VideoPortWritePortUchar(HwDeviceExtension->IOAddress +
GRAPH_ADDRESS_PORT, IND_BIT_MASK);
VideoPortWritePortUchar(HwDeviceExtension->IOAddress +
GRAPH_DATA_PORT, BIT_MASK_DEFAULT);
return FALSE;
}
//
// We've pretty surely verified the existence of the Bit Mask register.
// Put the Graphics Controller back to the original state.
//
VideoPortWritePortUchar(HwDeviceExtension->IOAddress +
GRAPH_DATA_PORT, originalReadMap);
VideoPortWritePortUchar(HwDeviceExtension->IOAddress +
GRAPH_ADDRESS_PORT, IND_BIT_MASK);
VideoPortWritePortUchar(HwDeviceExtension->IOAddress +
GRAPH_DATA_PORT, originalBitMask);
VideoPortWritePortUchar(HwDeviceExtension->IOAddress +
GRAPH_ADDRESS_PORT, originalGCAddr);
//
// Now, check for the existence of the Chain4 bit.
//
//
// Remember the original states of the Sequencer Address and Memory Mode
// registers.
//
originalSCAddr = VideoPortReadPortUchar(HwDeviceExtension->IOAddress +
SEQ_ADDRESS_PORT);
VideoPortWritePortUchar(HwDeviceExtension->IOAddress +
SEQ_ADDRESS_PORT, IND_MEMORY_MODE);
if ((VideoPortReadPortUchar(HwDeviceExtension->IOAddress +
SEQ_ADDRESS_PORT) & SEQ_ADDR_MASK) != IND_MEMORY_MODE) {
//
// Couldn't read back the Sequencer Address register setting we just
// performed.
//
return FALSE;
}
originalMemoryMode = VideoPortReadPortUchar(HwDeviceExtension->IOAddress +
SEQ_DATA_PORT);
//
// Toggle the Chain4 bit and read back the result. This must be done during
// sync reset, since we're changing the chaining state.
//
//
// Begin sync reset.
//
VideoPortWritePortUshort((PUSHORT)(HwDeviceExtension->IOAddress +
SEQ_ADDRESS_PORT),
(IND_SYNC_RESET + (START_SYNC_RESET_VALUE << 8)));
//
// Toggle the Chain4 bit.
//
VideoPortWritePortUchar(HwDeviceExtension->IOAddress +
SEQ_ADDRESS_PORT, IND_MEMORY_MODE);
VideoPortWritePortUchar(HwDeviceExtension->IOAddress +
SEQ_DATA_PORT, (UCHAR)(originalMemoryMode ^ CHAIN4_MASK));
if (VideoPortReadPortUchar(HwDeviceExtension->IOAddress +
SEQ_DATA_PORT) != (UCHAR) (originalMemoryMode ^ CHAIN4_MASK)) {
//
// Chain4 bit not there; not a VGA.
// Set text mode default for Memory Mode register.
//
VideoPortWritePortUchar(HwDeviceExtension->IOAddress +
SEQ_DATA_PORT, MEMORY_MODE_TEXT_DEFAULT);
//
// End sync reset.
//
VideoPortWritePortUshort((PUSHORT) (HwDeviceExtension->IOAddress +
SEQ_ADDRESS_PORT),
(IND_SYNC_RESET + (END_SYNC_RESET_VALUE << 8)));
returnStatus = FALSE;
} else {
//
// It's a VGA.
//
//
// Restore the original Memory Mode setting.
//
VideoPortWritePortUchar(HwDeviceExtension->IOAddress +
SEQ_DATA_PORT, originalMemoryMode);
//
// End sync reset.
//
VideoPortWritePortUshort((PUSHORT)(HwDeviceExtension->IOAddress +
SEQ_ADDRESS_PORT),
(USHORT)(IND_SYNC_RESET + (END_SYNC_RESET_VALUE << 8)));
//
// Restore the original Sequencer Address setting.
//
VideoPortWritePortUchar(HwDeviceExtension->IOAddress +
SEQ_ADDRESS_PORT, originalSCAddr);
returnStatus = TRUE;
}
return returnStatus;
} // VgaIsPresent()
BOOLEAN
WdIsPresent(
PHW_DEVICE_EXTENSION HwDeviceExtension
)
/*++
Routine Description:
This routine returns TRUE if an WD is present. It assumes that it's
already been established that a VGA is present. It performs the Western
Digital recommended ID test. If all this works, then this is indeed an
chip from Western Digital.
All the registers will be preserved either this function fails to find a
WD vga or a WD vga is found.
Arguments:
None.
Return Value:
TRUE if a WD is present, FALSE if not.
--*/
{
UCHAR GraphSave0c;
UCHAR GraphSave0f;
UCHAR temp1, temp2;
BOOLEAN status = TRUE;
PWSTR pszDeviceString;
ULONG cbString;
PUCHAR IoBase = HwDeviceExtension->IOAddress;
//
// write 3ce.0c
//
VideoPortWritePortUchar(HwDeviceExtension->IOAddress +
GRAPH_ADDRESS_PORT, 0x0c);
GraphSave0c = VideoPortReadPortUchar(HwDeviceExtension->IOAddress +
GRAPH_DATA_PORT);
temp1 = GraphSave0c & 0xbf;
VideoPortWritePortUchar(HwDeviceExtension->IOAddress +
GRAPH_DATA_PORT, temp1);
//
// write 3ce.0f
//
VideoPortWritePortUchar(HwDeviceExtension->IOAddress +
GRAPH_ADDRESS_PORT, 0x0f);
GraphSave0f = VideoPortReadPortUchar(HwDeviceExtension->IOAddress +
GRAPH_DATA_PORT);
VideoPortWritePortUchar(HwDeviceExtension->IOAddress +
GRAPH_DATA_PORT, 0x0);
//
// write 3ce.09
//
VideoPortWritePortUchar(HwDeviceExtension->IOAddress +
GRAPH_ADDRESS_PORT, 0x09);
temp1 = VideoPortReadPortUchar(HwDeviceExtension->IOAddress +
GRAPH_DATA_PORT);
VideoPortWritePortUchar(HwDeviceExtension->IOAddress +
GRAPH_DATA_PORT, (UCHAR)(temp1+1));
temp2 = VideoPortReadPortUchar(HwDeviceExtension->IOAddress +
GRAPH_DATA_PORT);
VideoPortWritePortUchar(HwDeviceExtension->IOAddress +
GRAPH_DATA_PORT, temp1);
if ((temp1+1) == temp2) {
status = FALSE;
goto NOT_WD;
}
VideoPortWritePortUshort((PUSHORT)(HwDeviceExtension->IOAddress +
GRAPH_ADDRESS_PORT), 0x050f);
VideoPortWritePortUchar(HwDeviceExtension->IOAddress +
GRAPH_ADDRESS_PORT, 0x09);
temp1 = VideoPortReadPortUchar(HwDeviceExtension->IOAddress +
GRAPH_DATA_PORT);
VideoPortWritePortUchar(HwDeviceExtension->IOAddress +
GRAPH_DATA_PORT, (UCHAR)(temp1+1));
temp2 = VideoPortReadPortUchar(HwDeviceExtension->IOAddress +
GRAPH_DATA_PORT);
VideoPortWritePortUchar(HwDeviceExtension->IOAddress +
GRAPH_DATA_PORT, temp1);
if ((temp1+1) != temp2) {
status = FALSE;
goto NOT_WD;
}
//
// it *is* a WD!
//
//
// Assume we have a WD90C24A/A2
//
HwDeviceExtension->BoardID = WD90C24A;
pszDeviceString = L"WD 90C24A/A2";
cbString = sizeof(L"WD 90C24A/A2");
//
// Identify the WD chip
//
VideoPortWritePortUshort(
(PUSHORT)(IoBase + GRAPH_ADDRESS_PORT),
(USHORT)pr5 | ((USHORT)pr5_unlock << 8));
VideoPortWritePortUshort(
(PUSHORT)(IoBase + CRTC_ADDRESS_PORT_COLOR),
(USHORT)pr10 | ((USHORT)pr10_unlock << 8));
VideoPortWritePortUshort(
(PUSHORT)(IoBase + SEQ_ADDRESS_PORT),
(USHORT)pr20 | ((USHORT)pr20_unlock << 8));
VideoPortWritePortUchar(IoBase + MISC_OUTPUT_REG_WRITE_PORT,
(UCHAR)(VideoPortReadPortUchar(IoBase + MISC_OUTPUT_REG_READ_PORT) | 0x01));
VideoPortWritePortUchar(IoBase + CRTC_ADDRESS_PORT_COLOR, (UCHAR)pr12);
if (!TestPortUchar(IoBase + CRTC_DATA_PORT_COLOR, 0xff)) {
HwDeviceExtension->BoardID = WDPVGA1A;
} else {
VideoPortWritePortUchar(IoBase + SEQ_ADDRESS_PORT, (UCHAR)pr21);
if (!TestPortUchar(IoBase + SEQ_DATA_PORT, 0xf0)) {
HwDeviceExtension->BoardID = WD90C00;
} else {
VideoPortWritePortUchar(IoBase + SEQ_ADDRESS_PORT, (UCHAR)pr30a);
if (!TestPortUchar(IoBase + SEQ_DATA_PORT, 0xff)) {
HwDeviceExtension->BoardID = WD90C20;
} else {
VideoPortWritePortUchar(IoBase + SEQ_ADDRESS_PORT, (UCHAR)pr34a);
if (!TestPortUchar(IoBase + SEQ_DATA_PORT, 0x0f)) {
HwDeviceExtension->BoardID = WD90C10;
} else {
UCHAR savePR1B;
UCHAR signature[3];
VideoPortWritePortUchar(IoBase + CRTC_ADDRESS_PORT_COLOR, (UCHAR)pr1b);
savePR1B = VideoPortReadPortUchar(IoBase + CRTC_DATA_PORT_COLOR);
VideoPortWritePortUchar(IoBase + CRTC_DATA_PORT_COLOR, (UCHAR)pr1b_lock);
VideoPortWritePortUshort(
(PUSHORT)(IoBase + CRTC_ADDRESS_PORT_COLOR),
(USHORT)pr30 | ((USHORT)pr30_lock << 8));
VideoPortWritePortUchar(IoBase + CRTC_ADDRESS_PORT_COLOR, (UCHAR)0x36);
signature[0] = VideoPortReadPortUchar(IoBase + CRTC_DATA_PORT_COLOR);
VideoPortWritePortUchar(IoBase + CRTC_ADDRESS_PORT_COLOR, (UCHAR)0x37);
signature[1] = VideoPortReadPortUchar(IoBase + CRTC_DATA_PORT_COLOR);
VideoPortWritePortUchar(IoBase + CRTC_ADDRESS_PORT_COLOR, (UCHAR)0x38);
signature[2] = VideoPortReadPortUchar(IoBase + CRTC_DATA_PORT_COLOR);
VideoPortWritePortUshort(
(PUSHORT)(IoBase + CRTC_ADDRESS_PORT_COLOR),
(USHORT)(pr1b | (savePR1B << 8)));
if ((signature[0] == '3') && (signature[1] == '0')) {
HwDeviceExtension->BoardID = WD90C30;
} else if ((signature[0] == '2') && (signature[1] == '4')) {
if (signature[2] == 'A')
HwDeviceExtension->BoardID = WD90C24A;
else
HwDeviceExtension->BoardID = WD90C24;
} else if ((signature[0] == '2') && (signature[1] == '6')) {
if (signature[2] == 'A')
HwDeviceExtension->BoardID = WD90C26A;
else
HwDeviceExtension->BoardID = WD90C26;
} else if ((signature[0] == '2') && (signature[1] == '7')) {
HwDeviceExtension->BoardID = WD90C26A;
} else if ((signature[0] == '3') && (signature[1] == '1')) {
HwDeviceExtension->BoardID = WD90C31;
} else if ((signature[0] == '3') && (signature[1] == '3')) {
HwDeviceExtension->BoardID = WD90C33;
} else {
HwDeviceExtension->BoardID = 0; // Unknown WD
} /* endif */
} /* endif */
} /* endif */
} /* endif */
} /* endif */
if ((HwDeviceExtension->BoardID != WD90C24A) ||
(!HwDeviceExtension->ExtendedRegisters)) {
status = FALSE;
goto NOT_WD;
} /* endif */
//
// Get the memory size.
//
VgaSizeMemory(HwDeviceExtension);
//
// Get the type of attached LCD display
//
GetPanelType(HwDeviceExtension);
//
// Finally, just validate the list of modes.
//
VgaValidateModes(HwDeviceExtension);
VideoPortSetRegistryParameters(HwDeviceExtension,
L"HardwareInformation.ChipType",
pszDeviceString,
cbString);
VideoPortSetRegistryParameters(HwDeviceExtension,
L"HardwareInformation.MemorySize",
&HwDeviceExtension->AdapterMemorySize,
sizeof(ULONG));
VideoPortSetRegistryParameters(HwDeviceExtension,
L"FlatPanel.Type",
&HwDeviceExtension->PanelType,
sizeof(UCHAR));
VideoPortSetRegistryParameters(HwDeviceExtension,
L"FlatPanel.XResolution",
&HwDeviceExtension->PanelXResolution,
sizeof(ULONG));
VideoPortSetRegistryParameters(HwDeviceExtension,
L"FlatPanel.YResolution",
&HwDeviceExtension->PanelYResolution,
sizeof(ULONG));
NOT_WD:
//
// Restore registers to what they were.
//
VideoPortWritePortUchar(HwDeviceExtension->IOAddress +
GRAPH_ADDRESS_PORT, 0x0c);
VideoPortWritePortUchar(HwDeviceExtension->IOAddress +
GRAPH_DATA_PORT, GraphSave0c);
VideoPortWritePortUchar(HwDeviceExtension->IOAddress +
GRAPH_ADDRESS_PORT, 0x0f);
VideoPortWritePortUchar(HwDeviceExtension->IOAddress +
GRAPH_DATA_PORT, GraphSave0f);
return status;
} // end WdIsPresent()
VOID
VgaSizeMemory(
PHW_DEVICE_EXTENSION HwDeviceExtension
)
/*++
Routine Description:
This routine determines the amount of VideoMemory on the adapter.
Arguments:
HwDeviceExtension - Pointer to the miniport driver's device extension.
Return Value:
None.
--*/
{
UCHAR data;
//
// 3CF.B Memory size
//
VideoPortWritePortUchar(HwDeviceExtension->IOAddress +
GRAPH_ADDRESS_PORT, 0x0B);
data = VideoPortReadPortUchar(HwDeviceExtension->IOAddress +
GRAPH_DATA_PORT);
switch ( data & 0xC0 ) {
case 0x00:
case 0x40:
HwDeviceExtension->AdapterMemorySize = 0x00040000;
break;
case 0x80:
HwDeviceExtension->AdapterMemorySize = 0x00080000;
break;
case 0xC0:
HwDeviceExtension->AdapterMemorySize = 0x00100000;
break;
default:
break;
}
} // end VgaSizeMemory();
#ifdef i386
VP_STATUS
VgaLoadAndSetFont(
PHW_DEVICE_EXTENSION HwDeviceExtension,
PVIDEO_LOAD_FONT_INFORMATION FontInformation,
ULONG FontInformationSize
)
/*++
Routine Description:
Takes a buffer containing a user-defined font and loads it into the
VGA soft font memory and programs the VGA to the appropriate character
cell size.
Arguments:
HwDeviceExtension - Pointer to the miniport driver's device extension.
FontInformation - Pointer to the structure containing the information
about the loadable ROM font to be set.
FontInformationSize - Length of the input buffer supplied by the user.
Return Value:
NO_ERROR - information returned successfully
ERROR_INSUFFICIENT_BUFFER - input buffer not large enough for input data.
ERROR_INVALID_PARAMETER - invalid video mode
--*/
{
PUCHAR destination;
PUCHAR source;
USHORT width;
ULONG i;
//
// check if a mode has been set
//
if (HwDeviceExtension->CurrentMode == NULL) {
return ERROR_INVALID_FUNCTION;
}
//
// Text mode only; If we are in a graphics mode, return an error
//
if (HwDeviceExtension->CurrentMode->fbType & VIDEO_MODE_GRAPHICS) {
return ERROR_INVALID_PARAMETER;
}
//
// Check if the size of the data in the input buffer is large enough
// and that it contains all the data.
//
if ( (FontInformationSize < sizeof(VIDEO_LOAD_FONT_INFORMATION)) ||
(FontInformationSize < sizeof(VIDEO_LOAD_FONT_INFORMATION) +
sizeof(UCHAR) * (FontInformation->FontSize - 1)) ) {
return ERROR_INSUFFICIENT_BUFFER;
}
//
// Check for the width and height of the font
//
if ( ((FontInformation->WidthInPixels != 8) &&
(FontInformation->WidthInPixels != 9)) ||
(FontInformation->HeightInPixels > 32) ) {
return ERROR_INVALID_PARAMETER;
}
//
// Check the size of the font buffer is the right size for the size
// font being passed down.
//
if (FontInformation->FontSize < FontInformation->HeightInPixels * 256 *
sizeof(UCHAR) ) {
return ERROR_INSUFFICIENT_BUFFER;
}
//
// Since the font parameters are valid, store the parameters in the
// device extension and load the font.
//
HwDeviceExtension->FontPelRows = FontInformation->HeightInPixels;
HwDeviceExtension->FontPelColumns = FontInformation->WidthInPixels;
HwDeviceExtension->CurrentMode->row =
HwDeviceExtension->CurrentMode->vres / HwDeviceExtension->FontPelRows;
width =
HwDeviceExtension->CurrentMode->hres / HwDeviceExtension->FontPelColumns;
if (width < (USHORT)HwDeviceExtension->CurrentMode->col) {
HwDeviceExtension->CurrentMode->col = width;
}
source = &(FontInformation->Font[0]);
//
// Set up the destination and source pointers for the font
//
destination = (PUCHAR)HwDeviceExtension->VideoMemoryAddress;
//
// Map font buffer at A0000
//
VgaInterpretCmdStream(HwDeviceExtension, EnableA000Data);
//
// Move the font to its destination
//
for (i = 1; i <= 256; i++) {
VideoPortWriteRegisterBufferUchar(destination,
source,
FontInformation->HeightInPixels);
destination += 32;
source += FontInformation->HeightInPixels;
}
VgaInterpretCmdStream(HwDeviceExtension, DisableA000Color);
//
// Restore to a text mode.
//
//
// Set Height of font.
//
VideoPortWritePortUchar(HwDeviceExtension->IOAddress +
CRTC_ADDRESS_PORT_COLOR, 0x9);
VideoPortWritePortUchar(HwDeviceExtension->IOAddress +
CRTC_DATA_PORT_COLOR,
(UCHAR)(FontInformation->HeightInPixels - 1));
//
// Set Width of font.
//
VideoPortWritePortUchar(HwDeviceExtension->IOAddress +
CRTC_ADDRESS_PORT_COLOR, 0x12);
VideoPortWritePortUchar(HwDeviceExtension->IOAddress +
CRTC_DATA_PORT_COLOR,
(UCHAR)(((USHORT)FontInformation->HeightInPixels *
(USHORT)HwDeviceExtension->CurrentMode->row) - 1));
i = HwDeviceExtension->CurrentMode->vres /
HwDeviceExtension->CurrentMode->row;
//
// Set Cursor End
//
VideoPortWritePortUchar(HwDeviceExtension->IOAddress +
CRTC_ADDRESS_PORT_COLOR, 0xb);
VideoPortWritePortUchar(HwDeviceExtension->IOAddress +
CRTC_DATA_PORT_COLOR, (UCHAR)--i);
//
// Set Cursor Start
//
VideoPortWritePortUchar(HwDeviceExtension->IOAddress +
CRTC_ADDRESS_PORT_COLOR, 0xa);
VideoPortWritePortUchar(HwDeviceExtension->IOAddress +
CRTC_DATA_PORT_COLOR, (UCHAR)--i);
return NO_ERROR;
} //end VgaLoadAndSetFont()
VP_STATUS
VgaQueryCursorPosition(
PHW_DEVICE_EXTENSION HwDeviceExtension,
PVIDEO_CURSOR_POSITION CursorPosition,
ULONG CursorPositionSize,
PULONG OutputSize
)
/*++
Routine Description:
This routine returns the row and column of the cursor.
Arguments:
HwDeviceExtension - Pointer to the miniport driver's device extension.
CursorPosition - Pointer to the output buffer supplied by the user. This
is where the cursor position is stored.
CursorPositionSize - Length of the output buffer supplied by the user.
OutputSize - Pointer to a buffer in which to return the actual size of
the data in the buffer. If the buffer was not large enough, this
contains the minimum required buffer size.
Return Value:
NO_ERROR - information returned successfully
ERROR_INSUFFICIENT_BUFFER - output buffer not large enough to return
any useful data
ERROR_INVALID_PARAMETER - invalid video mode
--*/
{
//
// check if a mode has been set
//
if (HwDeviceExtension->CurrentMode == NULL) {
return ERROR_INVALID_FUNCTION;
}
//
// Text mode only; If we are in a graphics mode, return an error
//
if (HwDeviceExtension->CurrentMode->fbType & VIDEO_MODE_GRAPHICS) {
*OutputSize = 0;
return ERROR_INVALID_PARAMETER;
}
//
// If the buffer passed in is not large enough return an
// appropriate error code.
//
if (CursorPositionSize < (*OutputSize = sizeof(VIDEO_CURSOR_POSITION)) ) {
*OutputSize = 0;
return ERROR_INSUFFICIENT_BUFFER;
}
//
// Store the position of the cursor into the buffer.
//
CursorPosition->Column = HwDeviceExtension->CursorPosition.Column;
CursorPosition->Row = HwDeviceExtension->CursorPosition.Row;
return NO_ERROR;
} // end VgaQueryCursorPosition()
VP_STATUS
VgaSetCursorPosition(
PHW_DEVICE_EXTENSION HwDeviceExtension,
PVIDEO_CURSOR_POSITION CursorPosition,
ULONG CursorPositionSize
)
/*++
Routine Description:
This routine verifies that the requested cursor position is within
the row and column bounds of the current mode and font. If valid, then
it sets the row and column of the cursor.
Arguments:
HwDeviceExtension - Pointer to the miniport driver's device extension.
CursorPosition - Pointer to the structure containing the cursor position.
CursorPositionSize - Length of the input buffer supplied by the user.
Return Value:
NO_ERROR - information returned successfully
ERROR_INSUFFICIENT_BUFFER - input buffer not large enough for input data
ERROR_INVALID_PARAMETER - invalid video mode
--*/
{
USHORT position;
//
// check if a mode has been set
//
if (HwDeviceExtension->CurrentMode == NULL) {
return ERROR_INVALID_FUNCTION;
}
//
// Text mode only; If we are in a graphics mode, return an error
//
if (HwDeviceExtension->CurrentMode->fbType & VIDEO_MODE_GRAPHICS) {
return ERROR_INVALID_PARAMETER;
}
//
// Check if the size of the data in the input buffer is large enough.
//
if (CursorPositionSize < sizeof(VIDEO_CURSOR_POSITION)) {
return ERROR_INSUFFICIENT_BUFFER;
}
//
// Check if the new values for the cursor positions are in the valid
// bounds for the screen.
//
if ((CursorPosition->Column >= HwDeviceExtension->CurrentMode->col) ||
(CursorPosition->Row >= HwDeviceExtension->CurrentMode->row)) {
return ERROR_INVALID_PARAMETER;
}
//
// Store these new values in the device extension so we can use them in
// a QUERY.
//
HwDeviceExtension->CursorPosition.Column = CursorPosition->Column;
HwDeviceExtension->CursorPosition.Row = CursorPosition->Row;
//
// Calculate the position on the screen at which the cursor must be
// be displayed
//
position = (USHORT) (HwDeviceExtension->CurrentMode->col *
CursorPosition->Row + CursorPosition->Column);
//
// Address Cursor Location Low Register in CRT Controller Registers
//
VideoPortWritePortUchar(HwDeviceExtension->IOAddress +
CRTC_ADDRESS_PORT_COLOR, IND_CURSOR_LOW_LOC);
//
// Set Cursor Location Low Register
//
VideoPortWritePortUchar(HwDeviceExtension->IOAddress +
CRTC_DATA_PORT_COLOR, (UCHAR) (position & 0x00FF));
//
// Address Cursor Location High Register in CRT Controller Registers
//
VideoPortWritePortUchar(HwDeviceExtension->IOAddress +
CRTC_ADDRESS_PORT_COLOR, IND_CURSOR_HIGH_LOC);
//
// Set Cursor Location High Register
//
VideoPortWritePortUchar(HwDeviceExtension->IOAddress +
CRTC_DATA_PORT_COLOR, (UCHAR) (position >> 8));
return NO_ERROR;
} // end VgaSetCursorPosition()
VP_STATUS
VgaQueryCursorAttributes(
PHW_DEVICE_EXTENSION HwDeviceExtension,
PVIDEO_CURSOR_ATTRIBUTES CursorAttributes,
ULONG CursorAttributesSize,
PULONG OutputSize
)
/*++
Routine Description:
This routine returns information about the height and visibility of the
cursor.
Arguments:
HwDeviceExtension - Pointer to the miniport driver's device extension.
CursorAttributes - Pointer to the output buffer supplied by the user.
This is where the cursor type is stored.
CursorAttributesSize - Length of the output buffer supplied by the user.
OutputSize - Pointer to a buffer in which to return the actual size of
the data in the buffer. If the buffer was not large enough, this
contains the minimum required buffer size.
Return Value:
NO_ERROR - information returned successfully
ERROR_INSUFFICIENT_BUFFER - output buffer not large enough to return
any useful data
ERROR_INVALID_PARAMETER - invalid video mode
--*/
{
//
// check if a mode has been set
//
if (HwDeviceExtension->CurrentMode == NULL) {
return ERROR_INVALID_FUNCTION;
}
//
// Text mode only; If we are in a graphics mode, return an error
//
if (HwDeviceExtension->CurrentMode->fbType & VIDEO_MODE_GRAPHICS) {
*OutputSize = 0;
return ERROR_INVALID_PARAMETER;
}
//
// 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 (CursorAttributesSize < (*OutputSize =
sizeof(VIDEO_CURSOR_ATTRIBUTES)) ) {
*OutputSize = 0;
return ERROR_INSUFFICIENT_BUFFER;
}
//
// Store the cursor information into the buffer.
//
CursorAttributes->Height = (USHORT) HwDeviceExtension->CursorTopScanLine;
CursorAttributes->Width = (USHORT) HwDeviceExtension->CursorBottomScanLine;
CursorAttributes->Enable = HwDeviceExtension->CursorEnable;
return NO_ERROR;
} // end VgaQueryCursorAttributes()
VP_STATUS
VgaSetCursorAttributes(
PHW_DEVICE_EXTENSION HwDeviceExtension,
PVIDEO_CURSOR_ATTRIBUTES CursorAttributes,
ULONG CursorAttributesSize
)
/*++
Routine Description:
This routine verifies that the requested cursor height is within the
bounds of the character cell. If valid, then it sets the new
visibility and height of the cursor.
Arguments:
HwDeviceExtension - Pointer to the miniport driver's device extension.
CursorType - Pointer to the structure containing the cursor information.
CursorTypeSize - Length of the input buffer supplied by the user.
Return Value:
NO_ERROR - information returned successfully
ERROR_INSUFFICIENT_BUFFER - input buffer not large enough for input data
ERROR_INVALID_PARAMETER - invalid video mode
--*/
{
UCHAR cursorLine;
//
// check if a mode has been set
//
if (HwDeviceExtension->CurrentMode == NULL) {
return ERROR_INVALID_FUNCTION;
}
//
// Text mode only; If we are in a graphics mode, return an error
//
if (HwDeviceExtension->CurrentMode->fbType & VIDEO_MODE_GRAPHICS) {
return ERROR_INVALID_PARAMETER;
}
//
// Check if the size of the data in the input buffer is large enough.
//
if (CursorAttributesSize < sizeof(VIDEO_CURSOR_ATTRIBUTES)) {
return ERROR_INSUFFICIENT_BUFFER;
}
//
// Check if the new values for the cursor type are in the valid range.
//
if ((CursorAttributes->Height >= HwDeviceExtension->FontPelRows) ||
(CursorAttributes->Width > 31)) {
return ERROR_INVALID_PARAMETER;
}
//
// Store the cursor information in the device extension so we can use
// them in a QUERY.
//
HwDeviceExtension->CursorTopScanLine = (UCHAR) CursorAttributes->Height;
HwDeviceExtension->CursorBottomScanLine = (UCHAR) CursorAttributes->Width;
HwDeviceExtension->CursorEnable = CursorAttributes->Enable;
//
// Address Cursor Start Register in CRT Controller Registers
//
VideoPortWritePortUchar(HwDeviceExtension->IOAddress +
CRTC_ADDRESS_PORT_COLOR,
IND_CURSOR_START);
//
// Set Cursor Start Register by writing to CRTCtl Data Register
// Preserve the high three bits of this register.
//
// Only the Five low bits are used for the cursor height.
// Bit 5 is cursor enable, bit 6 and 7 preserved.
//
cursorLine = (UCHAR) CursorAttributes->Height & 0x1F;
cursorLine |= VideoPortReadPortUchar(HwDeviceExtension->IOAddress +
CRTC_DATA_PORT_COLOR) & 0xC0;
if (!CursorAttributes->Enable) {
cursorLine |= 0x20; // Flip cursor off bit
}
VideoPortWritePortUchar(HwDeviceExtension->IOAddress + CRTC_DATA_PORT_COLOR,
cursorLine);
//
// Address Cursor End Register in CRT Controller Registers
//
VideoPortWritePortUchar(HwDeviceExtension->IOAddress +
CRTC_ADDRESS_PORT_COLOR,
IND_CURSOR_END);
//
// Set Cursor End Register. Preserve the high three bits of this
// register.
//
cursorLine =
(CursorAttributes->Width < (USHORT)(HwDeviceExtension->FontPelRows - 1)) ?
CursorAttributes->Width : (HwDeviceExtension->FontPelRows - 1);
cursorLine &= 0x1f;
cursorLine |= VideoPortReadPortUchar(HwDeviceExtension->IOAddress +
CRTC_DATA_PORT_COLOR) & 0xE0;
VideoPortWritePortUchar(HwDeviceExtension->IOAddress + CRTC_DATA_PORT_COLOR,
cursorLine);
return NO_ERROR;
} // end VgaSetCursorAttributes()
VP_STATUS
VgaSetPaletteReg(
PHW_DEVICE_EXTENSION HwDeviceExtension,
PVIDEO_PALETTE_DATA PaletteBuffer,
ULONG PaletteBufferSize
)
/*++
Routine Description:
This routine sets a specified portion of the EGA (not DAC) palette
registers.
Arguments:
HwDeviceExtension - Pointer to the miniport driver's device extension.
PaletteBuffer - Pointer to the structure containing the palette data.
PaletteBufferSize - Length of the input buffer supplied by the user.
Return Value:
NO_ERROR - information returned successfully
ERROR_INSUFFICIENT_BUFFER - input buffer not large enough for input data.
ERROR_INVALID_PARAMETER - invalid palette size.
--*/
{
USHORT i;
//
// Check if the size of the data in the input buffer is large enough.
//
if ((PaletteBufferSize) < (sizeof(VIDEO_PALETTE_DATA)) ||
(PaletteBufferSize < (sizeof(VIDEO_PALETTE_DATA) +
(sizeof(USHORT) * (PaletteBuffer->NumEntries -1)) ))) {
return ERROR_INSUFFICIENT_BUFFER;
}
//
// Check to see if the parameters are valid.
//
if ( (PaletteBuffer->FirstEntry > VIDEO_MAX_COLOR_REGISTER ) ||
(PaletteBuffer->NumEntries == 0) ||
(PaletteBuffer->FirstEntry + PaletteBuffer->NumEntries >
VIDEO_MAX_PALETTE_REGISTER + 1 ) ) {
return ERROR_INVALID_PARAMETER;
}
//
// Reset ATC to index mode
//
VideoPortReadPortUchar(HwDeviceExtension->IOAddress +
ATT_INITIALIZE_PORT_COLOR);
//
// Blast out our palette values.
//
for (i = 0; i < PaletteBuffer->NumEntries; i++) {
VideoPortWritePortUchar(HwDeviceExtension->IOAddress + ATT_ADDRESS_PORT,
(UCHAR)(i+PaletteBuffer->FirstEntry));
VideoPortWritePortUchar(HwDeviceExtension->IOAddress +
ATT_DATA_WRITE_PORT,
(UCHAR)PaletteBuffer->Colors[i]);
}
VideoPortWritePortUchar(HwDeviceExtension->IOAddress + ATT_ADDRESS_PORT,
VIDEO_ENABLE);
return NO_ERROR;
} // end VgaSetPaletteReg()
VP_STATUS
VgaRestoreHardwareState(
PHW_DEVICE_EXTENSION HwDeviceExtension,
PVIDEO_HARDWARE_STATE HardwareState,
ULONG HardwareStateSize
)
/*++
Routine Description:
Restores all registers and memory of the VGA.
Note: HardwareState points to the actual buffer from which the state
is to be restored. This buffer will always be big enough (we specified
the required size at DriverEntry).
Note: The offset in the hardware state header from which each general
register is restored is the offset of the write address of that register
from the base I/O address of the VGA.
!!! NOTE
We assume the miniport and the display driver have UNLOCKED the extended
registers so we can READ and WRITE them.
Arguments:
HwDeviceExtension - Pointer to the miniport driver's device extension.
HardwareState - Pointer to a structure from which the saved state is to be
restored (actually only info about and a pointer to the actual save
buffer).
HardwareStateSize - Length of the input buffer supplied by the user.
(Actually only the size of the HardwareState structure, not the
buffer it points to from which the state is actually restored. The
pointed-to buffer is assumed to be big enough.)
Return Value:
NO_ERROR - restore performed successfully
ERROR_INSUFFICIENT_BUFFER - input buffer not large enough to provide data
--*/
{
PVIDEO_HARDWARE_STATE_HEADER hardwareStateHeader;
ULONG i;
UCHAR dummy;
PUCHAR pScreen;
PUCHAR pucLatch;
PULONG pulBuffer;
PUCHAR port;
PUCHAR portValue;
PUCHAR portValueDAC;
ULONG bIsColor;
//
// Check if the size of the data in the input buffer is large enough.
//
if ((HardwareStateSize < sizeof(VIDEO_HARDWARE_STATE)) ||
(HardwareState->StateLength < VGA_TOTAL_STATE_SIZE)) {
return ERROR_INSUFFICIENT_BUFFER;
}
//
// Point to the buffer where the restore data is actually stored.
//
hardwareStateHeader = HardwareState->StateHeader;
//
// Make sure the offset are in the structure ...
//
if ((hardwareStateHeader->BasicSequencerOffset + VGA_NUM_SEQUENCER_PORTS >
HardwareState->StateLength) ||
(hardwareStateHeader->BasicCrtContOffset + VGA_NUM_CRTC_PORTS >
HardwareState->StateLength) ||
(hardwareStateHeader->BasicGraphContOffset + VGA_NUM_GRAPH_CONT_PORTS >
HardwareState->StateLength) ||
(hardwareStateHeader->BasicAttribContOffset + VGA_NUM_ATTRIB_CONT_PORTS >
HardwareState->StateLength) ||
(hardwareStateHeader->BasicDacOffset + (3 * VGA_NUM_DAC_ENTRIES) >
HardwareState->StateLength) ||
(hardwareStateHeader->BasicLatchesOffset + 4 >
HardwareState->StateLength) ||
(hardwareStateHeader->ExtendedSequencerOffset + EXT_NUM_SEQUENCER_PORTS >
HardwareState->StateLength) ||
(hardwareStateHeader->ExtendedCrtContOffset + EXT_NUM_CRTC_PORTS >
HardwareState->StateLength) ||
(hardwareStateHeader->ExtendedGraphContOffset + EXT_NUM_GRAPH_CONT_PORTS >
HardwareState->StateLength) ||
(hardwareStateHeader->ExtendedAttribContOffset + EXT_NUM_ATTRIB_CONT_PORTS >
HardwareState->StateLength) ||
(hardwareStateHeader->ExtendedDacOffset + (4 * EXT_NUM_DAC_ENTRIES) >
HardwareState->StateLength) ||
//
// Only check the validator state offset if there is unemulated data.
//
((hardwareStateHeader->VGAStateFlags & VIDEO_STATE_UNEMULATED_VGA_STATE) &&
(hardwareStateHeader->ExtendedValidatorStateOffset + VGA_VALIDATOR_AREA_SIZE >
HardwareState->StateLength)) ||
(hardwareStateHeader->ExtendedMiscDataOffset + VGA_MISC_DATA_AREA_OFFSET >
HardwareState->StateLength) ||
(hardwareStateHeader->Plane1Offset + hardwareStateHeader->PlaneLength >
HardwareState->StateLength) ||
(hardwareStateHeader->Plane2Offset + hardwareStateHeader->PlaneLength >
HardwareState->StateLength) ||
(hardwareStateHeader->Plane3Offset + hardwareStateHeader->PlaneLength >
HardwareState->StateLength) ||
(hardwareStateHeader->Plane4Offset + hardwareStateHeader->PlaneLength >
HardwareState->StateLength) ||
(hardwareStateHeader->DIBOffset +
hardwareStateHeader->DIBBitsPerPixel / 8 *
hardwareStateHeader->DIBXResolution *
hardwareStateHeader->DIBYResolution > HardwareState->StateLength) ||
(hardwareStateHeader->DIBXlatOffset + hardwareStateHeader->DIBXlatLength >
HardwareState->StateLength)) {
return ERROR_INVALID_PARAMETER;
}
//
// Set DAC register 0 to display black.
//
VideoPortWritePortUchar(HwDeviceExtension->IOAddress +
DAC_ADDRESS_WRITE_PORT, 0);
VideoPortWritePortUchar(HwDeviceExtension->IOAddress +
DAC_DATA_REG_PORT, 0);
VideoPortWritePortUchar(HwDeviceExtension->IOAddress +
DAC_DATA_REG_PORT, 0);
VideoPortWritePortUchar(HwDeviceExtension->IOAddress +
DAC_DATA_REG_PORT, 0);
//
// Set the DAC mask register to force DAC register 0 to display all the
// time (this is the register we just set to display black). From now on,
// nothing but black will show up on the screen.
//
VideoPortWritePortUchar(HwDeviceExtension->IOAddress +
DAC_PIXEL_MASK_PORT, 0);
//
// Restore the latches and the contents of display memory.
//
// Set up the VGA's hardware to allow us to copy to each plane in turn.
//
// Begin sync reset.
//
VideoPortWritePortUshort((PUSHORT) (HwDeviceExtension->IOAddress +
SEQ_ADDRESS_PORT),
(USHORT) (IND_SYNC_RESET + (START_SYNC_RESET_VALUE << 8)));
//
// Turn off Chain mode and map display memory at A0000 for 64K.
//
VideoPortWritePortUchar(HwDeviceExtension->IOAddress +
GRAPH_ADDRESS_PORT, IND_GRAPH_MISC);
VideoPortWritePortUchar(HwDeviceExtension->IOAddress +
GRAPH_DATA_PORT, (UCHAR) ((VideoPortReadPortUchar(
HwDeviceExtension->IOAddress + GRAPH_DATA_PORT) & 0xF1) | 0x04));
//
// Turn off Chain4 mode and odd/even.
//
VideoPortWritePortUchar(HwDeviceExtension->IOAddress +
SEQ_ADDRESS_PORT, IND_MEMORY_MODE);
VideoPortWritePortUchar(HwDeviceExtension->IOAddress +
SEQ_DATA_PORT,
(UCHAR) ((VideoPortReadPortUchar(HwDeviceExtension->IOAddress +
SEQ_DATA_PORT) & 0xF3) | 0x04));
//
// End sync reset.
//
VideoPortWritePortUshort((PUSHORT) (HwDeviceExtension->IOAddress +
SEQ_ADDRESS_PORT), (USHORT) (IND_SYNC_RESET +
(END_SYNC_RESET_VALUE << 8)));
//
// Set the write mode to 0, the read mode to 0, and turn off odd/even.
//
VideoPortWritePortUchar(HwDeviceExtension->IOAddress +
GRAPH_ADDRESS_PORT, IND_GRAPH_MODE);
VideoPortWritePortUchar(HwDeviceExtension->IOAddress +
GRAPH_DATA_PORT,
(UCHAR) ((VideoPortReadPortUchar(HwDeviceExtension->IOAddress +
GRAPH_DATA_PORT) & 0xE4) | 0x00));
//
// Set the Bit Mask to 0xFF to allow all CPU bits through.
//
VideoPortWritePortUshort((PUSHORT) (HwDeviceExtension->IOAddress +
GRAPH_ADDRESS_PORT), (USHORT) (IND_BIT_MASK + (0xFF << 8)));
//
// Set the Data Rotation and Logical Function fields to 0 to allow CPU
// data through unmodified.
//
VideoPortWritePortUshort((PUSHORT)(HwDeviceExtension->IOAddress +
GRAPH_ADDRESS_PORT), (USHORT) (IND_DATA_ROTATE + (0 << 8)));
//
// Set Set/Reset Enable to 0 to select CPU data for all planes.
//
VideoPortWritePortUshort((PUSHORT) (HwDeviceExtension->IOAddress +
GRAPH_ADDRESS_PORT), (USHORT) (IND_SET_RESET_ENABLE + (0 << 8)));
//
// Point the Sequencer Index to the Map Mask register.
//
VideoPortWritePortUchar(HwDeviceExtension->IOAddress +
SEQ_ADDRESS_PORT, IND_MAP_MASK);
//
// Restore the latches.
//
// Point to the saved data for the first latch.
//
pucLatch = ((PUCHAR) (hardwareStateHeader)) +
hardwareStateHeader->BasicLatchesOffset;
//
// Point to first byte of display memory.
//
pScreen = (PUCHAR) HwDeviceExtension->VideoMemoryAddress;
//
// Write the contents to be restored to each of the four latches in turn.
//
for (i = 0; i < 4; i++) {
//
// Set the Map Mask to select the plane we want to restore next.
//
VideoPortWritePortUchar(HwDeviceExtension->IOAddress +
SEQ_DATA_PORT, (UCHAR)(1<<i));
//
// Write this plane's latch.
//
VideoPortWriteRegisterUchar(pScreen, *pucLatch++);
}
//
// Read the latched data into the latches, and the latches are set.
//
dummy = VideoPortReadRegisterUchar(pScreen);
//
// Point to the offset of the saved data for the first plane.
//
pulBuffer = &(hardwareStateHeader->Plane1Offset);
//
// Restore each of the four planes in turn.
//
for (i = 0; i < 4; i++) {
//
// Set the Map Mask to select the plane we want to restore next.
//
VideoPortWritePortUchar(HwDeviceExtension->IOAddress +
SEQ_DATA_PORT, (UCHAR)(1<<i));
//
// Restore this plane from the buffer.
//
VideoPortMoveMemory((PUCHAR) HwDeviceExtension->VideoMemoryAddress,
((PUCHAR) (hardwareStateHeader)) + *pulBuffer,
hardwareStateHeader->PlaneLength);
pulBuffer++;
}
//
// If we have some unemulated data, put it back into the buffer
//
if (hardwareStateHeader->VGAStateFlags & VIDEO_STATE_UNEMULATED_VGA_STATE) {
if (!hardwareStateHeader->ExtendedValidatorStateOffset) {
return ERROR_INVALID_PARAMETER;
}
//
// Get the right offset in the struct and save all the data associated
// with the trapped validator data.
//
VideoPortMoveMemory(&(HwDeviceExtension->TrappedValidatorCount),
((PUCHAR) (hardwareStateHeader)) +
hardwareStateHeader->ExtendedValidatorStateOffset,
VGA_VALIDATOR_AREA_SIZE);
//
// Check to see if this is an appropriate access range.
// We are trapping - so we must have the trapping access range enabled.
//
if (((HwDeviceExtension->CurrentVdmAccessRange != FullVgaValidatorAccessRange) ||
(HwDeviceExtension->CurrentNumVdmAccessRanges != NUM_FULL_VGA_VALIDATOR_ACCESS_RANGE)) &&
((HwDeviceExtension->CurrentVdmAccessRange != MinimalVgaValidatorAccessRange) ||
(HwDeviceExtension->CurrentNumVdmAccessRanges != NUM_MINIMAL_VGA_VALIDATOR_ACCESS_RANGE))) {
return ERROR_INVALID_PARAMETER;
}
VideoPortSetTrappedEmulatorPorts(HwDeviceExtension,
HwDeviceExtension->CurrentNumVdmAccessRanges,
HwDeviceExtension->CurrentVdmAccessRange);
}
//
// Set the critical registers (clock and timing states) during sync reset.
//
// Begin sync reset.
//
VideoPortWritePortUshort((PUSHORT) (HwDeviceExtension->IOAddress +
SEQ_ADDRESS_PORT), (USHORT) (IND_SYNC_RESET +
(START_SYNC_RESET_VALUE << 8)));
//
// Restore the Miscellaneous Output register.
//
VideoPortWritePortUchar(HwDeviceExtension->IOAddress +
MISC_OUTPUT_REG_WRITE_PORT,
(UCHAR) (hardwareStateHeader->PortValue[MISC_OUTPUT_REG_WRITE_PORT] & 0xF7));
//
// Restore all Sequencer registers except the Sync Reset register, which
// is always not in reset (except when we send out a batched sync reset
// register set, but that can't be interrupted, so we know we're never in
// sync reset at save/restore time).
//
portValue = ((PUCHAR) hardwareStateHeader) +
hardwareStateHeader->BasicSequencerOffset + 1;
for (i = 1; i < VGA_NUM_SEQUENCER_PORTS; i++) {
VideoPortWritePortUshort((PUSHORT) (HwDeviceExtension->IOAddress +
SEQ_ADDRESS_PORT), (USHORT) (i + ((*portValue++) << 8)) );
}
//
// Restore extended sequencer registers
//
#ifdef EXTENDED_REGISTER_SAVE_RESTORE
if (hardwareStateHeader->ExtendedSequencerOffset) {
portValue = ((PUCHAR) hardwareStateHeader) +
hardwareStateHeader->ExtendedSequencerOffset;
for (i = WD_SEQUENCER_EXT_START; i <= WD_SEQUENCER_EXT_END; i++) {
VideoPortWritePortUshort((PUSHORT) (HwDeviceExtension->IOAddress +
SEQ_ADDRESS_PORT),
(USHORT) (i + ((*portValue++) << 8)) );
}
//
// Restore the second set of sequencer registers.
//
for (i = WD_SEQUENCER_1_EXT_START; i <= WD_SEQUENCER_1_EXT_END; i++) {
VideoPortWritePortUshort((PUSHORT) (HwDeviceExtension->IOAddress +
SEQ_ADDRESS_PORT),
(USHORT) (i + ((*portValue++) << 8)) );
}
}
#endif
//
// Restore the Graphics Controller Miscellaneous register, which contains
// the Chain bit.
//
portValue = ((PUCHAR) hardwareStateHeader) +
hardwareStateHeader->BasicGraphContOffset + IND_GRAPH_MISC;
VideoPortWritePortUshort((PUSHORT) (HwDeviceExtension->IOAddress +
GRAPH_ADDRESS_PORT), (USHORT)(IND_GRAPH_MISC + (*portValue << 8)));
//
// End sync reset.
//
VideoPortWritePortUshort((PUSHORT) (HwDeviceExtension->IOAddress +
SEQ_ADDRESS_PORT), (USHORT) (IND_SYNC_RESET +
(END_SYNC_RESET_VALUE << 8)));
//
// Figure out if color/mono switchable registers are at 3BX or 3DX.
// At the same time, save the state of the Miscellaneous Output register
// which is read from 3CC but written at 3C2.
//
if (hardwareStateHeader->PortValue[MISC_OUTPUT_REG_WRITE_PORT] & 0x01) {
bIsColor = TRUE;
} else {
bIsColor = FALSE;
}
//
// Restore the CRT Controller indexed registers.
//
// Unlock CRTC registers 0-7.
//
portValue = (PUCHAR) hardwareStateHeader +
hardwareStateHeader->BasicCrtContOffset;
if (bIsColor) {
VideoPortWritePortUshort((PUSHORT) (HwDeviceExtension->IOAddress +
CRTC_ADDRESS_PORT_COLOR), (USHORT) (IND_CRTC_PROTECT +
(((*(portValue + IND_CRTC_PROTECT)) & 0x7F) << 8)));
} else {
VideoPortWritePortUshort((PUSHORT) (HwDeviceExtension->IOAddress +
CRTC_ADDRESS_PORT_MONO), (USHORT) (IND_CRTC_PROTECT +
(((*(portValue + IND_CRTC_PROTECT)) & 0x7F) << 8)));
}
//
// Restore extended crtc registers.
//
#ifdef EXTENDED_REGISTER_SAVE_RESTORE
if (hardwareStateHeader->ExtendedCrtContOffset) {
portValue = (PUCHAR) hardwareStateHeader +
hardwareStateHeader->ExtendedCrtContOffset;
for (i = WD_CRTC_EXT_START; i <= WD_CRTC_EXT_END; i++) {
if (bIsColor) {
VideoPortWritePortUshort((PUSHORT) (HwDeviceExtension->IOAddress +
CRTC_ADDRESS_PORT_COLOR),
(USHORT) (i + ((*portValue++) << 8)));
} else {
VideoPortWritePortUshort((PUSHORT) (HwDeviceExtension->IOAddress +
CRTC_ADDRESS_PORT_MONO),
(USHORT) (i + ((*portValue++) << 8)));
}
}
//
// Second set of crtc registers
//
for (i = WD_CRTC_1_EXT_START; i <= WD_CRTC_1_EXT_END; i++) {
if (bIsColor) {
VideoPortWritePortUshort((PUSHORT) (HwDeviceExtension->IOAddress +
CRTC_ADDRESS_PORT_COLOR),
(USHORT) (i + ((*portValue++) << 8)));
} else {
VideoPortWritePortUshort((PUSHORT) (HwDeviceExtension->IOAddress +
CRTC_ADDRESS_PORT_MONO),
(USHORT) (i + ((*portValue++) << 8)));
}
}
}
#endif
//
// Now restore the CRTC registers.
//
portValue = (PUCHAR) hardwareStateHeader +
hardwareStateHeader->BasicCrtContOffset;
for (i = 0; i < VGA_NUM_CRTC_PORTS; i++) {
if (bIsColor) {
VideoPortWritePortUshort((PUSHORT) (HwDeviceExtension->IOAddress +
CRTC_ADDRESS_PORT_COLOR),
(USHORT) (i + ((*portValue++) << 8)));
} else {
VideoPortWritePortUshort((PUSHORT) (HwDeviceExtension->IOAddress +
CRTC_ADDRESS_PORT_MONO),
(USHORT) (i + ((*portValue++) << 8)));
}
}
//
// Restore the Graphics Controller indexed registers.
//
portValue = (PUCHAR) hardwareStateHeader +
hardwareStateHeader->BasicGraphContOffset;
for (i = 0; i < VGA_NUM_GRAPH_CONT_PORTS; i++) {
VideoPortWritePortUshort((PUSHORT) (HwDeviceExtension->IOAddress +
GRAPH_ADDRESS_PORT), (USHORT) (i + ((*portValue++) << 8)));
}
//
// Restore extended graphics controller registers.
//
#ifdef EXTENDED_REGISTER_SAVE_RESTORE
//
// The extended lock register (index 0x0F) will be restored last, so we do
// not need to do anything special with it.
//
if (hardwareStateHeader->ExtendedGraphContOffset) {
portValue = (PUCHAR) hardwareStateHeader +
hardwareStateHeader->ExtendedGraphContOffset;
for (i = WD_GRAPH_EXT_START; i <= WD_GRAPH_EXT_END; i++) {
VideoPortWritePortUshort((PUSHORT) (HwDeviceExtension->IOAddress +
GRAPH_ADDRESS_PORT),
(USHORT) (i + ((*portValue++) << 8)));
}
}
#endif
//
// Restore the Attribute Controller indexed registers.
//
portValue = (PUCHAR) hardwareStateHeader +
hardwareStateHeader->BasicAttribContOffset;
//
// Reset the AC index/data toggle, then blast out all the register
// settings.
//
if (bIsColor) {
dummy = VideoPortReadPortUchar(HwDeviceExtension->IOAddress +
INPUT_STATUS_1_COLOR);
} else {
dummy = VideoPortReadPortUchar(HwDeviceExtension->IOAddress +
INPUT_STATUS_1_MONO);
}
for (i = 0; i < VGA_NUM_ATTRIB_CONT_PORTS; i++) {
VideoPortWritePortUchar(HwDeviceExtension->IOAddress +
ATT_ADDRESS_PORT, (UCHAR)i);
VideoPortWritePortUchar(HwDeviceExtension->IOAddress +
ATT_DATA_WRITE_PORT, *portValue++);
}
//
// Restore DAC registers 1 through 255. We'll do register 0, the DAC Mask,
// and the index registers later.
// Set the DAC address port Index, then write out the DAC Data registers.
// Each three reads get Red, Green, and Blue components for that register.
//
// Write them one at a time due to problems on local bus machines.
//
portValueDAC = (PUCHAR) hardwareStateHeader +
hardwareStateHeader->BasicDacOffset + 3;
for (i = 1; i < VGA_NUM_DAC_ENTRIES; i++) {
VideoPortWritePortUchar(HwDeviceExtension->IOAddress +
DAC_ADDRESS_WRITE_PORT, (UCHAR)i);
VideoPortWritePortUchar(HwDeviceExtension->IOAddress +
DAC_DATA_REG_PORT, *portValueDAC++);
VideoPortWritePortUchar(HwDeviceExtension->IOAddress +
DAC_DATA_REG_PORT, *portValueDAC++);
VideoPortWritePortUchar(HwDeviceExtension->IOAddress +
DAC_DATA_REG_PORT, *portValueDAC++);
}
//
// Extended registers are not CURRENTLY supported in this driver.
//
//
// Restore the Feature Control register.
//
if (bIsColor) {
VideoPortWritePortUchar(HwDeviceExtension->IOAddress +
FEAT_CTRL_WRITE_PORT_COLOR,
hardwareStateHeader->PortValue[FEAT_CTRL_WRITE_PORT_COLOR]);
} else {
VideoPortWritePortUchar(HwDeviceExtension->IOAddress +
FEAT_CTRL_WRITE_PORT_MONO,
hardwareStateHeader->PortValue[FEAT_CTRL_WRITE_PORT_MONO]);
}
//
// Restore the Sequencer Index.
//
VideoPortWritePortUchar(HwDeviceExtension->IOAddress +
SEQ_ADDRESS_PORT,
hardwareStateHeader->PortValue[SEQ_ADDRESS_PORT]);
//
// Restore the CRT Controller Index.
//
if (bIsColor) {
VideoPortWritePortUchar(HwDeviceExtension->IOAddress +
CRTC_ADDRESS_PORT_COLOR,
hardwareStateHeader->PortValue[CRTC_ADDRESS_PORT_COLOR]);
} else {
VideoPortWritePortUchar(HwDeviceExtension->IOAddress +
CRTC_ADDRESS_PORT_MONO,
hardwareStateHeader->PortValue[CRTC_ADDRESS_PORT_MONO]);
}
//
// Restore the Graphics Controller Index.
//
VideoPortWritePortUchar(HwDeviceExtension->IOAddress +
GRAPH_ADDRESS_PORT,
hardwareStateHeader->PortValue[GRAPH_ADDRESS_PORT]);
//
// Restore the Attribute Controller Index and index/data toggle state.
//
if (bIsColor) {
port = HwDeviceExtension->IOAddress + INPUT_STATUS_1_COLOR;
} else {
port = HwDeviceExtension->IOAddress + INPUT_STATUS_1_MONO;
}
VideoPortReadPortUchar(port); // reset the toggle to Index state
VideoPortWritePortUchar(HwDeviceExtension->IOAddress +
ATT_ADDRESS_PORT, // restore the AC Index
hardwareStateHeader->PortValue[ATT_ADDRESS_PORT]);
//
// If the toggle should be in Data state, we're all set. If it should be in
// Index state, reset it to that condition.
//
if (hardwareStateHeader->AttribIndexDataState == 0) {
//
// Reset the toggle to Index state.
//
VideoPortReadPortUchar(port);
}
//
// Restore DAC register 0 and the DAC Mask, to unblank the screen.
//
portValueDAC = (PUCHAR) hardwareStateHeader +
hardwareStateHeader->BasicDacOffset;
//
// Restore the DAC Mask register.
//
VideoPortWritePortUchar(HwDeviceExtension->IOAddress +
DAC_PIXEL_MASK_PORT,
hardwareStateHeader->PortValue[DAC_PIXEL_MASK_PORT]);
//
// Restore DAC register 0.
//
VideoPortWritePortUchar(HwDeviceExtension->IOAddress +
DAC_ADDRESS_WRITE_PORT, 0);
VideoPortWritePortUchar(HwDeviceExtension->IOAddress +
DAC_DATA_REG_PORT, *portValueDAC++);
VideoPortWritePortUchar(HwDeviceExtension->IOAddress +
DAC_DATA_REG_PORT, *portValueDAC++);
VideoPortWritePortUchar(HwDeviceExtension->IOAddress +
DAC_DATA_REG_PORT, *portValueDAC++);
//
// Restore the read/write state and the current index of the DAC.
//
// See whether the Read or Write Index was written to most recently.
// (The upper nibble stored at DAC_STATE_PORT is the # of reads/writes
// for the current index.)
//
if ((hardwareStateHeader->PortValue[DAC_STATE_PORT] & 0x0F) == 3) {
//
// The DAC Read Index was written to last. Restore the DAC by setting
// up to read from the saved index - 1, because the way the Read
// Index works is that it autoincrements after reading, so you actually
// end up reading the data for the index you read at the DAC Write
// Mask register - 1.
//
// Set the Read Index to the index we read, minus 1, accounting for
// wrap from 255 back to 0. The DAC hardware immediately reads this
// register into a temporary buffer, then adds 1 to the index.
//
if (hardwareStateHeader->PortValue[DAC_ADDRESS_WRITE_PORT] == 0) {
VideoPortWritePortUchar(HwDeviceExtension->IOAddress +
DAC_ADDRESS_READ_PORT, 255);
} else {
VideoPortWritePortUchar(HwDeviceExtension->IOAddress +
DAC_ADDRESS_READ_PORT, (UCHAR)
(hardwareStateHeader->PortValue[DAC_ADDRESS_WRITE_PORT] -
1));
}
//
// Now read the hardware however many times are required to get to
// the partial read state we saved.
//
for (i = hardwareStateHeader->PortValue[DAC_STATE_PORT] >> 4;
i > 0; i--) {
dummy = VideoPortReadPortUchar(HwDeviceExtension->IOAddress +
DAC_DATA_REG_PORT);
}
} else {
//
// The DAC Write Index was written to last. Set the Write Index to the
// index value we read out of the DAC. Then, if a partial write
// (partway through an RGB triplet) was in place, write the partial
// values, which we obtained by writing them to the current DAC
// register. This DAC register will be wrong until the write is
// completed, but at least the values will be right once the write is
// finished, and most importantly we won't have messed up the sequence
// of RGB writes (which can be as long as 768 in a row).
//
VideoPortWritePortUchar(HwDeviceExtension->IOAddress +
DAC_ADDRESS_WRITE_PORT,
hardwareStateHeader->PortValue[DAC_ADDRESS_WRITE_PORT]);
//
// Now write to the hardware however many times are required to get to
// the partial write state we saved (if any).
//
// Point to the saved value for the DAC register that was in the
// process of being written to; we wrote the partial value out, so now
// we can restore it.
//
portValueDAC = (PUCHAR) hardwareStateHeader +
hardwareStateHeader->BasicDacOffset +
(hardwareStateHeader->PortValue[DAC_ADDRESS_WRITE_PORT] * 3);
for (i = hardwareStateHeader->PortValue[DAC_STATE_PORT] >> 4;
i > 0; i--) {
VideoPortWritePortUchar(HwDeviceExtension->IOAddress +
DAC_DATA_REG_PORT, *portValueDAC++);
}
}
return NO_ERROR;
} // end VgaRestoreHardwareState()
VP_STATUS
VgaSaveHardwareState(
PHW_DEVICE_EXTENSION HwDeviceExtension,
PVIDEO_HARDWARE_STATE HardwareState,
ULONG HardwareStateSize,
PULONG OutputSize
)
/*++
Routine Description:
Saves all registers and memory of the VGA.
Note: HardwareState points to the actual buffer in which the state
is saved. This buffer will always be big enough (we specified
the required size at DriverEntry).
Note: This routine leaves registers in any state it cares to, except
that it will not mess with any of the CRT or Sequencer parameters that
might make the monitor unhappy. It leaves the screen blanked by setting
the DAC Mask and DAC register 0 to all zero values. The next video
operation we expect after this is a mode set to take us back to Win32.
Note: The offset in the hardware state header in which each general
register is saved is the offset of the write address of that register from
the base I/O address of the VGA.
!!! NOTE
We must force the extended registers to be unlocked.
Arguments:
HwDeviceExtension - Pointer to the miniport driver's device extension.
HardwareState - Pointer to a structure in which the saved state will be
returned (actually only info about and a pointer to the actual save
buffer).
HardwareStateSize - Length of the output buffer supplied by the user.
(Actually only the size of the HardwareState structure, not the
buffer it points to where the state is actually saved. The pointed-
to buffer is assumed to be big enough.)
OutputSize - Pointer to a buffer in which to return the actual size of
the data returned in the buffer.
Return Value:
NO_ERROR - information returned successfully
ERROR_INSUFFICIENT_BUFFER - output buffer not large enough to return
any useful data
--*/
{
PVIDEO_HARDWARE_STATE_HEADER hardwareStateHeader;
PUCHAR pScreen;
PUCHAR portValue;
PUCHAR portValueDAC;
PUCHAR bufferPointer;
ULONG i;
UCHAR dummy, originalACIndex, originalACData;
UCHAR ucCRTC03;
ULONG bIsColor;
//
// See if the buffer is big enough to hold the hardware state structure.
// (This is only the HardwareState structure itself, not the buffer it
// points to.)
//
if (HardwareStateSize < sizeof(VIDEO_HARDWARE_STATE) ) {
*OutputSize = 0; // nothing returned
return ERROR_INSUFFICIENT_BUFFER;
}
//
// Amount of data we're going to return in the output buffer.
// (The VIDEO_HARDWARE_STATE in the output buffer points to the actual
// buffer in which the state is stored, which is assumed to be large
// enough.)
//
*OutputSize = sizeof(VIDEO_HARDWARE_STATE);
//
// Indicate the size of the full state save info.
//
HardwareState->StateLength = VGA_TOTAL_STATE_SIZE;
//
// hardwareStateHeader is a structure of offsets at the start of the
// actual save area that indicates the locations in which various VGA
// register and memory components are saved.
//
hardwareStateHeader = HardwareState->StateHeader;
//
// Zero out the structure.
//
VideoPortZeroMemory(hardwareStateHeader, sizeof(VIDEO_HARDWARE_STATE_HEADER));
//
// Set the Length field, which is basically a version ID.
//
hardwareStateHeader->Length = sizeof(VIDEO_HARDWARE_STATE_HEADER);
//
// Set the basic register offsets properly.
//
hardwareStateHeader->BasicSequencerOffset = VGA_BASIC_SEQUENCER_OFFSET;
hardwareStateHeader->BasicCrtContOffset = VGA_BASIC_CRTC_OFFSET;
hardwareStateHeader->BasicGraphContOffset = VGA_BASIC_GRAPH_CONT_OFFSET;
hardwareStateHeader->BasicAttribContOffset = VGA_BASIC_ATTRIB_CONT_OFFSET;
hardwareStateHeader->BasicDacOffset = VGA_BASIC_DAC_OFFSET;
hardwareStateHeader->BasicLatchesOffset = VGA_BASIC_LATCHES_OFFSET;
//
// Set the extended register offsets properly.
//
hardwareStateHeader->ExtendedSequencerOffset = VGA_EXT_SEQUENCER_OFFSET;
hardwareStateHeader->ExtendedCrtContOffset = VGA_EXT_CRTC_OFFSET;
hardwareStateHeader->ExtendedGraphContOffset = VGA_EXT_GRAPH_CONT_OFFSET;
hardwareStateHeader->ExtendedAttribContOffset = VGA_EXT_ATTRIB_CONT_OFFSET;
hardwareStateHeader->ExtendedDacOffset = VGA_EXT_DAC_OFFSET;
//
// Figure out if color/mono switchable registers are at 3BX or 3DX.
// At the same time, save the state of the Miscellaneous Output register
// which is read from 3CC but written at 3C2.
//
if ((hardwareStateHeader->PortValue[MISC_OUTPUT_REG_WRITE_PORT] =
VideoPortReadPortUchar(HwDeviceExtension->IOAddress +
MISC_OUTPUT_REG_READ_PORT))
& 0x01) {
bIsColor = TRUE;
} else {
bIsColor = FALSE;
}
//
// Force the video subsystem enable state to enabled.
//
VideoPortWritePortUchar(HwDeviceExtension->IOAddress +
VIDEO_SUBSYSTEM_ENABLE_PORT, 1);
//
// Save the DAC state first, so we can set the DAC to blank the screen
// so nothing after this shows up at all.
//
// Save the DAC Mask register.
//
hardwareStateHeader->PortValue[DAC_PIXEL_MASK_PORT] =
VideoPortReadPortUchar(HwDeviceExtension->IOAddress +
DAC_PIXEL_MASK_PORT);
//
// Save the DAC Index register. Note that there is actually only one DAC
// Index register, which functions as either the Read Index or the Write
// Index as needed.
//
hardwareStateHeader->PortValue[DAC_ADDRESS_WRITE_PORT] =
VideoPortReadPortUchar(HwDeviceExtension->IOAddress +
DAC_ADDRESS_WRITE_PORT);
//
// Save the DAC read/write state. We determine if the DAC has been written
// to or read from at the current index 0, 1, or 2 times (the application
// is in the middle of reading or writing a DAC register triplet if the
// count is 1 or 2), and save enough info so we can restore things
// properly. The only hole is if the application writes to the Write Index,
// then reads from instead of writes to the Data register, or vice-versa,
// or if they do a partial read write, then never finish it.
// This is fairly ridiculous behavior, however, and anyway there's nothing
// we can do about it.
//
hardwareStateHeader->PortValue[DAC_STATE_PORT] =
VideoPortReadPortUchar(HwDeviceExtension->IOAddress +
DAC_STATE_PORT);
if (hardwareStateHeader->PortValue[DAC_STATE_PORT] == 3) {
//
// The DAC Read Index was written to last. Figure out how many reads
// have been done from the current index. We'll restart this on restore
// by setting the Read Index to the current index - 1 (the read index
// is one greater than the index being read), then doing the proper
// number of reads.
//
// Read the Data register once, and see if the index changes.
//
dummy = VideoPortReadPortUchar(HwDeviceExtension->IOAddress +
DAC_DATA_REG_PORT);
if (VideoPortReadPortUchar(HwDeviceExtension->IOAddress +
DAC_ADDRESS_WRITE_PORT) !=
hardwareStateHeader->PortValue[DAC_ADDRESS_WRITE_PORT]) {
//
// The DAC Index changed, so two reads had already been done from
// the current index. Store the count "2" in the upper nibble of
// the read/write state field.
//
hardwareStateHeader->PortValue[DAC_STATE_PORT] |= 0x20;
} else {
//
// Read the Data register again, and see if the index changes.
//
dummy = VideoPortReadPortUchar(HwDeviceExtension->IOAddress +
DAC_DATA_REG_PORT);
if (VideoPortReadPortUchar(HwDeviceExtension->IOAddress +
DAC_ADDRESS_WRITE_PORT) !=
hardwareStateHeader->PortValue[DAC_ADDRESS_WRITE_PORT]) {
//
// The DAC Index changed, so one read had already been done
// from the current index. Store the count "1" in the upper
// nibble of the read/write state field.
//
hardwareStateHeader->PortValue[DAC_STATE_PORT] |= 0x10;
}
//
// If neither 2 nor 1 reads had been done from the current index,
// then 0 reads were done, and we're all set, since the upper
// nibble of the read/write state field is already 0.
//
}
} else {
//
// The DAC Write Index was written to last. Figure out how many writes
// have been done to the current index. We'll restart this on restore
// by setting the Write Index to the proper index, then doing the
// proper number of writes. When we do the DAC register save, we'll
// read out the value that gets written (if there was a partial write
// in progress), so we can restore the proper data later. This will
// cause this current DAC location to be briefly wrong in the 1- and
// 2-bytes-written case (until the app finishes the write), but that's
// better than having the wrong DAC values written for good.
//
// Write the Data register once, and see if the index changes.
//
VideoPortWritePortUchar(HwDeviceExtension->IOAddress +
DAC_DATA_REG_PORT, 0);
if (VideoPortReadPortUchar(HwDeviceExtension->IOAddress +
DAC_ADDRESS_WRITE_PORT) !=
hardwareStateHeader->PortValue[DAC_ADDRESS_WRITE_PORT]) {
//
// The DAC Index changed, so two writes had already been done to
// the current index. Store the count "2" in the upper nibble of
// the read/write state field.
//
hardwareStateHeader->PortValue[DAC_STATE_PORT] |= 0x20;
} else {
//
// Write the Data register again, and see if the index changes.
//
VideoPortWritePortUchar(HwDeviceExtension->IOAddress +
DAC_DATA_REG_PORT, 0);
if (VideoPortReadPortUchar(HwDeviceExtension->IOAddress +
DAC_ADDRESS_WRITE_PORT) !=
hardwareStateHeader->PortValue[DAC_ADDRESS_WRITE_PORT]) {
//
// The DAC Index changed, so one write had already been done
// to the current index. Store the count "1" in the upper
// nibble of the read/write state field.
//
hardwareStateHeader->PortValue[DAC_STATE_PORT] |= 0x10;
}
//
// If neither 2 nor 1 writes had been done to the current index,
// then 0 writes were done, and we're all set.
//
}
}
//
// Now, read out the 256 18-bit DAC palette registers (256 RGB triplets),
// and blank the screen.
//
portValueDAC = (PUCHAR) hardwareStateHeader + VGA_BASIC_DAC_OFFSET;
//
// Read out DAC register 0, so we can set it to black.
//
VideoPortWritePortUchar(HwDeviceExtension->IOAddress +
DAC_ADDRESS_READ_PORT, 0);
*portValueDAC++ = VideoPortReadPortUchar(HwDeviceExtension->IOAddress +
DAC_DATA_REG_PORT);
*portValueDAC++ = VideoPortReadPortUchar(HwDeviceExtension->IOAddress +
DAC_DATA_REG_PORT);
*portValueDAC++ = VideoPortReadPortUchar(HwDeviceExtension->IOAddress +
DAC_DATA_REG_PORT);
//
// Set DAC register 0 to display black.
//
VideoPortWritePortUchar(HwDeviceExtension->IOAddress +
DAC_ADDRESS_WRITE_PORT, 0);
VideoPortWritePortUchar(HwDeviceExtension->IOAddress +
DAC_DATA_REG_PORT, 0);
VideoPortWritePortUchar(HwDeviceExtension->IOAddress +
DAC_DATA_REG_PORT, 0);
VideoPortWritePortUchar(HwDeviceExtension->IOAddress +
DAC_DATA_REG_PORT, 0);
//
// Set the DAC mask register to force DAC register 0 to display all the
// time (this is the register we just set to display black). From now on,
// nothing but black will show up on the screen.
//
VideoPortWritePortUchar(HwDeviceExtension->IOAddress +
DAC_PIXEL_MASK_PORT, 0);
//
// Wait until we've gotten the Attribute Controller toggle state to save
// the rest of the DAC registers, so we can wait for vertical sync.
//
//
// Read out the Attribute Controller Index state, and deduce the Index/Data
// toggle state at the same time.
//
// Save the state of the Attribute Controller, both Index and Data,
// so we can test in which state the toggle currently is.
//
originalACIndex = hardwareStateHeader->PortValue[ATT_ADDRESS_PORT] =
VideoPortReadPortUchar(HwDeviceExtension->IOAddress +
ATT_ADDRESS_PORT);
originalACData = VideoPortReadPortUchar(HwDeviceExtension->IOAddress +
ATT_DATA_READ_PORT);
//
// Sequencer Index.
//
hardwareStateHeader->PortValue[SEQ_ADDRESS_PORT] =
VideoPortReadPortUchar(HwDeviceExtension->IOAddress +
SEQ_ADDRESS_PORT);
//
// Begin sync reset, just in case this is an SVGA and the currently
// indexed Attribute Controller register controls clocking stuff (a
// normal VGA won't require this).
//
VideoPortWritePortUshort((PUSHORT) (HwDeviceExtension->IOAddress +
SEQ_ADDRESS_PORT),
(USHORT) (IND_SYNC_RESET + (START_SYNC_RESET_VALUE << 8)));
//
// Now, write a different Index setting to the Attribute Controller, and
// see if the Index changes.
//
VideoPortWritePortUchar(HwDeviceExtension->IOAddress +
ATT_ADDRESS_PORT, (UCHAR) (originalACIndex ^ 0x10));
if (VideoPortReadPortUchar(HwDeviceExtension->IOAddress +
ATT_ADDRESS_PORT) == originalACIndex) {
//
// The Index didn't change, so the toggle was in the Data state.
//
hardwareStateHeader->AttribIndexDataState = 1;
//
// Restore the original Data state; we just corrupted it, and we need
// to read it out later; also, it may glitch the screen if not
// corrected. The toggle is already in the Index state.
//
VideoPortWritePortUchar(HwDeviceExtension->IOAddress +
ATT_ADDRESS_PORT, originalACIndex);
VideoPortWritePortUchar(HwDeviceExtension->IOAddress +
ATT_DATA_WRITE_PORT, originalACData);
} else {
//
// The Index did change, so the toggle was in the Index state.
// No need to restore anything, because the Data register didn't
// change, and we've already read out the Index register.
//
hardwareStateHeader->AttribIndexDataState = 0;
}
//
// End sync reset.
//
VideoPortWritePortUshort((PUSHORT) (HwDeviceExtension->IOAddress +
SEQ_ADDRESS_PORT),
(USHORT) (IND_SYNC_RESET + (END_SYNC_RESET_VALUE << 8)));
//
// Save the rest of the DAC registers.
// Set the DAC address port Index, then read out the DAC Data registers.
// Each three reads get Red, Green, and Blue components for that register.
//
// Read them one at a time due to problems on local bus machines.
//
for (i = 1; i < VGA_NUM_DAC_ENTRIES; i++) {
VideoPortWritePortUchar(HwDeviceExtension->IOAddress +
DAC_ADDRESS_READ_PORT, (UCHAR)i);
*portValueDAC++ = VideoPortReadPortUchar(HwDeviceExtension->IOAddress +
DAC_DATA_REG_PORT);
*portValueDAC++ = VideoPortReadPortUchar(HwDeviceExtension->IOAddress +
DAC_DATA_REG_PORT);
*portValueDAC++ = VideoPortReadPortUchar(HwDeviceExtension->IOAddress +
DAC_DATA_REG_PORT);
}
//
// The Feature Control register is read from 3CA but written at 3BA/3DA.
//
if (bIsColor) {
hardwareStateHeader->PortValue[FEAT_CTRL_WRITE_PORT_COLOR] =
VideoPortReadPortUchar(HwDeviceExtension->IOAddress +
FEAT_CTRL_READ_PORT);
} else {
hardwareStateHeader->PortValue[FEAT_CTRL_WRITE_PORT_MONO] =
VideoPortReadPortUchar(HwDeviceExtension->IOAddress +
FEAT_CTRL_READ_PORT);
}
//
// CRT Controller Index.
//
if (bIsColor) {
hardwareStateHeader->PortValue[CRTC_ADDRESS_PORT_COLOR] =
VideoPortReadPortUchar(HwDeviceExtension->IOAddress +
CRTC_ADDRESS_PORT_COLOR);
} else {
hardwareStateHeader->PortValue[CRTC_ADDRESS_PORT_MONO] =
VideoPortReadPortUchar(HwDeviceExtension->IOAddress +
CRTC_ADDRESS_PORT_MONO);
}
//
// Graphics Controller Index.
//
hardwareStateHeader->PortValue[GRAPH_ADDRESS_PORT] =
VideoPortReadPortUchar(HwDeviceExtension->IOAddress +
GRAPH_ADDRESS_PORT);
//
// Graphics Controller indexed registers.
//
portValue = (PUCHAR) hardwareStateHeader + VGA_BASIC_GRAPH_CONT_OFFSET;
for (i = 0; i < VGA_NUM_GRAPH_CONT_PORTS; i++) {
VideoPortWritePortUchar(HwDeviceExtension->IOAddress +
GRAPH_ADDRESS_PORT, (UCHAR)i);
*portValue++ = VideoPortReadPortUchar(HwDeviceExtension->IOAddress +
GRAPH_DATA_PORT);
}
//
// Save extended graphics controller registers.
//
#ifdef EXTENDED_REGISTER_SAVE_RESTORE
//
// Read the lock register (index 0x0F) value and save that.
//
*(((PUCHAR) hardwareStateHeader) + VGA_EXT_GRAPH_CONT_OFFSET +
(WD_GRAPH_EXT_END - WD_GRAPH_EXT_START)) =
VideoPortReadPortUchar(HwDeviceExtension->IOAddress + 0x0F);
//
// Unlock all extended registers so they can be read or written.
//
VideoPortWritePortUchar(HwDeviceExtension->IOAddress + 0x0F, 0x05);
portValue = (PUCHAR) hardwareStateHeader + VGA_EXT_GRAPH_CONT_OFFSET;
for (i = WD_GRAPH_EXT_START; i <= WD_GRAPH_EXT_END -1; i++) {
VideoPortWritePortUchar(HwDeviceExtension->IOAddress +
GRAPH_ADDRESS_PORT, (UCHAR)i);
*portValue++ = VideoPortReadPortUchar(HwDeviceExtension->IOAddress +
GRAPH_DATA_PORT);
}
#endif
//
// Sequencer indexed registers.
//
portValue = ((PUCHAR) hardwareStateHeader) + VGA_BASIC_SEQUENCER_OFFSET;
for (i = 0; i < VGA_NUM_SEQUENCER_PORTS; i++) {
VideoPortWritePortUchar(HwDeviceExtension->IOAddress +
SEQ_ADDRESS_PORT, (UCHAR)i);
*portValue++ = VideoPortReadPortUchar(HwDeviceExtension->IOAddress +
SEQ_DATA_PORT);
}
//
// Save extended sequencer registers.
//
#ifdef EXTENDED_REGISTER_SAVE_RESTORE
portValue = ((PUCHAR) hardwareStateHeader) + VGA_EXT_SEQUENCER_OFFSET;
for (i = WD_SEQUENCER_EXT_START; i <= WD_SEQUENCER_EXT_END; i++) {
VideoPortWritePortUchar(HwDeviceExtension->IOAddress +
SEQ_ADDRESS_PORT, (UCHAR)i);
*portValue++ = VideoPortReadPortUchar(HwDeviceExtension->IOAddress +
SEQ_DATA_PORT);
}
//
// Second set of sequencer registers
//
for (i = WD_SEQUENCER_1_EXT_START; i <= WD_SEQUENCER_1_EXT_END; i++) {
VideoPortWritePortUchar(HwDeviceExtension->IOAddress +
SEQ_ADDRESS_PORT, (UCHAR)i);
*portValue++ = VideoPortReadPortUchar(HwDeviceExtension->IOAddress +
SEQ_DATA_PORT);
}
#endif
//
// CRT Controller indexed registers.
//
//
// Remember the state of CRTC register 3, then force bit 7
// to 1 so we will read back the Vertical Retrace start and
// end registers rather than the light pen info.
//
if (bIsColor) {
VideoPortWritePortUchar(HwDeviceExtension->IOAddress +
CRTC_ADDRESS_PORT_COLOR, 3);
ucCRTC03 = VideoPortReadPortUchar(HwDeviceExtension->IOAddress +
CRTC_DATA_PORT_COLOR);
VideoPortWritePortUchar(HwDeviceExtension->IOAddress +
CRTC_DATA_PORT_COLOR, (UCHAR) (ucCRTC03 | 0x80));
} else {
VideoPortWritePortUchar(HwDeviceExtension->IOAddress +
CRTC_ADDRESS_PORT_MONO, 3);
ucCRTC03 = VideoPortReadPortUchar(HwDeviceExtension->IOAddress +
CRTC_DATA_PORT_MONO);
VideoPortWritePortUchar(HwDeviceExtension->IOAddress +
CRTC_DATA_PORT_MONO, (UCHAR) (ucCRTC03 | 0x80));
}
portValue = (PUCHAR) hardwareStateHeader + VGA_BASIC_CRTC_OFFSET;
for (i = 0; i < VGA_NUM_CRTC_PORTS; i++) {
if (bIsColor) {
VideoPortWritePortUchar(HwDeviceExtension->IOAddress +
CRTC_ADDRESS_PORT_COLOR, (UCHAR)i);
*portValue++ =
VideoPortReadPortUchar(HwDeviceExtension->IOAddress +
CRTC_DATA_PORT_COLOR);
} else {
VideoPortWritePortUchar(HwDeviceExtension->IOAddress +
CRTC_ADDRESS_PORT_MONO, (UCHAR)i);
*portValue++ =
VideoPortReadPortUchar(HwDeviceExtension->IOAddress +
CRTC_DATA_PORT_MONO);
}
}
portValue = (PUCHAR) hardwareStateHeader + VGA_BASIC_CRTC_OFFSET;
portValue[3] = ucCRTC03;
//
// Save extended crtc registers.
//
#ifdef EXTENDED_REGISTER_SAVE_RESTORE
portValue = (PUCHAR) hardwareStateHeader + VGA_EXT_CRTC_OFFSET;
for (i = WD_CRTC_EXT_START; i <= WD_CRTC_EXT_END; i++) {
if (bIsColor) {
VideoPortWritePortUchar(HwDeviceExtension->IOAddress +
CRTC_ADDRESS_PORT_COLOR, (UCHAR)i);
*portValue++ =
VideoPortReadPortUchar(HwDeviceExtension->IOAddress +
CRTC_DATA_PORT_COLOR);
} else {
VideoPortWritePortUchar(HwDeviceExtension->IOAddress +
CRTC_ADDRESS_PORT_MONO, (UCHAR)i);
*portValue++ =
VideoPortReadPortUchar(HwDeviceExtension->IOAddress +
CRTC_DATA_PORT_MONO);
}
}
//
// Save second set of crtc registers.
//
for (i = WD_CRTC_1_EXT_START; i <= WD_CRTC_1_EXT_END; i++) {
if (bIsColor) {
VideoPortWritePortUchar(HwDeviceExtension->IOAddress +
CRTC_ADDRESS_PORT_COLOR, (UCHAR)i);
*portValue++ =
VideoPortReadPortUchar(HwDeviceExtension->IOAddress +
CRTC_DATA_PORT_COLOR);
} else {
VideoPortWritePortUchar(HwDeviceExtension->IOAddress +
CRTC_ADDRESS_PORT_MONO, (UCHAR)i);
*portValue++ =
VideoPortReadPortUchar(HwDeviceExtension->IOAddress +
CRTC_DATA_PORT_MONO);
}
}
#endif
//
// Attribute Controller indexed registers.
//
portValue = (PUCHAR) hardwareStateHeader + VGA_BASIC_ATTRIB_CONT_OFFSET;
//
// For each indexed AC register, reset the flip-flop for reading the
// attribute register, then write the desired index to the AC Index,
// then read the value of the indexed register from the AC Data register.
//
for (i = 0; i < VGA_NUM_ATTRIB_CONT_PORTS; i++) {
if (bIsColor) {
dummy = VideoPortReadPortUchar(HwDeviceExtension->IOAddress +
INPUT_STATUS_1_COLOR);
} else {
dummy = VideoPortReadPortUchar(HwDeviceExtension->IOAddress +
INPUT_STATUS_1_MONO);
}
VideoPortWritePortUchar(HwDeviceExtension->IOAddress +
ATT_ADDRESS_PORT, (UCHAR)i);
*portValue++ = VideoPortReadPortUchar(HwDeviceExtension->IOAddress +
ATT_DATA_READ_PORT);
}
//
// Save the latches. This destroys one byte of display memory in each
// plane, which is unfortunate but unavoidable. Chips that provide
// a way to read back the latches can avoid this problem.
//
// Set up the VGA's hardware so we can write the latches, then read them
// back.
//
//
// Begin sync reset.
//
VideoPortWritePortUshort((PUSHORT) (HwDeviceExtension->IOAddress +
SEQ_ADDRESS_PORT),
(USHORT) (IND_SYNC_RESET + (START_SYNC_RESET_VALUE << 8)));
//
// Set the Miscellaneous register to make sure we can access video RAM.
//
VideoPortWritePortUchar(HwDeviceExtension->IOAddress +
MISC_OUTPUT_REG_WRITE_PORT, (UCHAR)(
hardwareStateHeader->PortValue[MISC_OUTPUT_REG_WRITE_PORT] |
0x02));
//
// Turn off Chain mode and map display memory at A0000 for 64K.
//
VideoPortWritePortUchar(HwDeviceExtension->IOAddress +
GRAPH_ADDRESS_PORT, IND_GRAPH_MISC);
VideoPortWritePortUchar(HwDeviceExtension->IOAddress +
GRAPH_DATA_PORT,
(UCHAR) ((VideoPortReadPortUchar(HwDeviceExtension->IOAddress +
GRAPH_DATA_PORT) & 0xF1) | 0x04));
//
// Turn off Chain4 mode and odd/even.
//
VideoPortWritePortUchar(HwDeviceExtension->IOAddress +
SEQ_ADDRESS_PORT, IND_MEMORY_MODE);
VideoPortWritePortUchar(HwDeviceExtension->IOAddress +
SEQ_DATA_PORT,
(UCHAR) ((VideoPortReadPortUchar(HwDeviceExtension->IOAddress +
SEQ_DATA_PORT) & 0xF3) | 0x04));
//
// End sync reset.
//
VideoPortWritePortUshort((PUSHORT) (HwDeviceExtension->IOAddress +
SEQ_ADDRESS_PORT),
(USHORT) (IND_SYNC_RESET + (END_SYNC_RESET_VALUE << 8)));
//
// Set the Map Mask to write to all planes.
//
VideoPortWritePortUshort((PUSHORT) (HwDeviceExtension->IOAddress +
SEQ_ADDRESS_PORT), (USHORT) (IND_MAP_MASK + (0x0F << 8)));
//
// Set the write mode to 0, the read mode to 0, and turn off odd/even.
//
VideoPortWritePortUchar(HwDeviceExtension->IOAddress +
GRAPH_ADDRESS_PORT, IND_GRAPH_MODE);
VideoPortWritePortUchar(HwDeviceExtension->IOAddress +
GRAPH_DATA_PORT,
(UCHAR) ((VideoPortReadPortUchar(HwDeviceExtension->IOAddress +
GRAPH_DATA_PORT) & 0xE4) | 0x01));
//
// Point to the last byte of display memory.
//
pScreen = (PUCHAR) HwDeviceExtension->VideoMemoryAddress +
VGA_PLANE_SIZE - 1;
//
// Write the latches to the last byte of display memory.
//
VideoPortWriteRegisterUchar(pScreen, 0);
//
// Cycle through the four planes, reading the latch data from each plane.
//
//
// Point the Graphics Controller Index to the Read Map register.
//
VideoPortWritePortUchar(HwDeviceExtension->IOAddress +
GRAPH_ADDRESS_PORT, IND_READ_MAP);
portValue = (PUCHAR) hardwareStateHeader + VGA_BASIC_LATCHES_OFFSET;
for (i=0; i<4; i++) {
//
// Set the Read Map for the current plane.
//
VideoPortWritePortUchar(HwDeviceExtension->IOAddress +
GRAPH_DATA_PORT, (UCHAR)i);
//
// Read the latched data we've written to memory.
//
*portValue++ = VideoPortReadRegisterUchar(pScreen);
}
//
// Set the VDM flags
// We are a standard VGA, and then check if we have unemulated state.
//
hardwareStateHeader->VGAStateFlags = 0;
#ifdef EXTENDED_REGISTER_SAVE_RESTORE
hardwareStateHeader->VGAStateFlags |= VIDEO_STATE_NON_STANDARD_VGA;
#endif
if (HwDeviceExtension->TrappedValidatorCount) {
hardwareStateHeader->VGAStateFlags |= VIDEO_STATE_UNEMULATED_VGA_STATE;
//
// Save the VDM Emulator data
// No need to save the state of the sequencer port register for our
// emulated data since it may change when we come back. It will be
// recomputed.
//
hardwareStateHeader->ExtendedValidatorStateOffset = VGA_VALIDATOR_OFFSET;
VideoPortMoveMemory(((PUCHAR) (hardwareStateHeader)) +
hardwareStateHeader->ExtendedValidatorStateOffset,
&(HwDeviceExtension->TrappedValidatorCount),
VGA_VALIDATOR_AREA_SIZE);
} else {
hardwareStateHeader->ExtendedValidatorStateOffset = 0;
}
//
// Set the size of each plane.
//
hardwareStateHeader->PlaneLength = VGA_PLANE_SIZE;
//
// Store all the offsets for the planes in the structure.
//
hardwareStateHeader->Plane1Offset = VGA_PLANE_0_OFFSET;
hardwareStateHeader->Plane2Offset = VGA_PLANE_1_OFFSET;
hardwareStateHeader->Plane3Offset = VGA_PLANE_2_OFFSET;
hardwareStateHeader->Plane4Offset = VGA_PLANE_3_OFFSET;
//
// Now copy the contents of video VRAM into the buffer.
//
// The VGA hardware is already set up so that video memory is readable;
// we already turned off Chain mode, mapped in at A0000, turned off Chain4,
// turned off odd/even, and set read mode 0 when we saved the latches.
//
// Point the Graphics Controller Index to the Read Map register.
//
VideoPortWritePortUchar(HwDeviceExtension->IOAddress +
GRAPH_ADDRESS_PORT, IND_READ_MAP);
//
// Point to the save area for the first plane.
//
bufferPointer = ((PUCHAR) (hardwareStateHeader)) +
hardwareStateHeader->Plane1Offset;
//
// Save the four planes consecutively.
//
for (i = 0; i < 4; i++) {
//
// Set the Read Map to select the plane we want to save next.
//
VideoPortWritePortUchar(HwDeviceExtension->IOAddress +
GRAPH_DATA_PORT, (UCHAR)i);
//
// Copy this plane into the buffer.
//
VideoPortMoveMemory(bufferPointer,
(PUCHAR) HwDeviceExtension->VideoMemoryAddress,
VGA_PLANE_SIZE);
//
// Point to the next plane's save area.
//
bufferPointer += VGA_PLANE_SIZE;
}
return NO_ERROR;
} // end VgaSaveHardwareState()
VP_STATUS
VgaValidatorUcharEntry(
ULONG Context,
ULONG Port,
UCHAR AccessMode,
PUCHAR Data
)
/*++
Routine Description:
Entry point into the validator for byte I/O operations.
The entry point will be called whenever a byte operation was performed
by a DOS application on one of the specified Video ports. The kernel
emulator will forward these requests.
Arguments:
Context - Context value that is passed to each call made to the validator
function. This is the value the miniport driver specified in the
MiniportConfigInfo->EmulatorAccessEntriesContext.
Port - Port on which the operation is to be performed.
AccessMode - Determines if it is a read or write operation.
Data - Pointer to a variable containing the data to be written or a
variable into which the read data should be stored.
Return Value:
NO_ERROR.
--*/
{
PHW_DEVICE_EXTENSION hwDeviceExtension = (PHW_DEVICE_EXTENSION) Context;
ULONG endEmulation;
UCHAR temp;
Port -= VGA_BASE_IO_PORT;
if (hwDeviceExtension->TrappedValidatorCount) {
endEmulation = 0;
//
// If we are processing a WRITE instruction, then store it in the
// playback buffer. If the buffer is full, then play it back right
// away, end sync reset and reinitialize the buffer with a sync
// reset instruction.
//
// If we have a READ, we must flush the buffer (which has the side
// effect of starting SyncReset), perform the read operation, stop
// sync reset, and put back a sync reset instruction in the buffer
// so we can go on appropriately
//
if (AccessMode & EMULATOR_WRITE_ACCESS) {
//
// Make sure Bit 3 of the Miscellaneous register is always 0.
// If it is 1 it could select a non-existent clock, and kill the
// system
//
if (Port == MISC_OUTPUT_REG_WRITE_PORT) {
*Data &= 0xF7;
}
hwDeviceExtension->TrappedValidatorData[hwDeviceExtension->
TrappedValidatorCount].Port = Port;
hwDeviceExtension->TrappedValidatorData[hwDeviceExtension->
TrappedValidatorCount].AccessType = VGA_VALIDATOR_UCHAR_ACCESS;
hwDeviceExtension->TrappedValidatorData[hwDeviceExtension->
TrappedValidatorCount].Data = *Data;
hwDeviceExtension->TrappedValidatorCount++;
//
// Check to see if this instruction was ending sync reset.
// If it did, we must flush the buffer and reset the trapped
// IO ports to the minimal set.
//
if ( (Port == SEQ_DATA_PORT) &&
((*Data & END_SYNC_RESET_VALUE) == END_SYNC_RESET_VALUE) &&
(hwDeviceExtension->SequencerAddressValue == IND_SYNC_RESET)) {
endEmulation = 1;
} else {
//
// If we are accessing the seq address port, keep track of the
// data value
//
if (Port == SEQ_ADDRESS_PORT) {
hwDeviceExtension->SequencerAddressValue = *Data;
}
//
// If the buffer is not full, then just return right away.
//
if (hwDeviceExtension->TrappedValidatorCount <
VGA_MAX_VALIDATOR_DATA - 1) {
return NO_ERROR;
}
}
}
//
// We are either in a READ path or a WRITE path that caused a
// a full buffer. So flush the buffer either way.
//
// To do this put an END_SYNC_RESET at the end since we want to make
// the buffer is ended sync reset ended.
//
hwDeviceExtension->TrappedValidatorData[hwDeviceExtension->
TrappedValidatorCount].Port = SEQ_ADDRESS_PORT;
hwDeviceExtension->TrappedValidatorData[hwDeviceExtension->
TrappedValidatorCount].AccessType = VGA_VALIDATOR_USHORT_ACCESS;
hwDeviceExtension->TrappedValidatorData[hwDeviceExtension->
TrappedValidatorCount].Data = (USHORT) (IND_SYNC_RESET +
(END_SYNC_RESET_VALUE << 8));
hwDeviceExtension->TrappedValidatorCount++;
VideoPortSynchronizeExecution(hwDeviceExtension,
VpHighPriority,
(PMINIPORT_SYNCHRONIZE_ROUTINE)
VgaPlaybackValidatorData,
hwDeviceExtension);
//
// Write back the real value of the sequencer address port.
//
VideoPortWritePortUchar(hwDeviceExtension->IOAddress +
SEQ_ADDRESS_PORT,
(UCHAR) hwDeviceExtension->SequencerAddressValue);
//
// If we are in a READ path, read the data
//
if (AccessMode & EMULATOR_READ_ACCESS) {
*Data = VideoPortReadPortUchar(hwDeviceExtension->IOAddress + Port);
endEmulation = 0;
}
//
// If we are ending emulation, reset trapping to the minimal amount
// and exit.
//
if (endEmulation) {
VideoPortSetTrappedEmulatorPorts(hwDeviceExtension,
NUM_MINIMAL_VGA_VALIDATOR_ACCESS_RANGE,
MinimalVgaValidatorAccessRange);
return NO_ERROR;
}
//
// For both cases, put back a START_SYNC_RESET in the buffer.
//
hwDeviceExtension->TrappedValidatorCount = 1;
hwDeviceExtension->TrappedValidatorData[0].Port = SEQ_ADDRESS_PORT;
hwDeviceExtension->TrappedValidatorData[0].AccessType =
VGA_VALIDATOR_USHORT_ACCESS;
hwDeviceExtension->TrappedValidatorData[0].Data =
(ULONG) (IND_SYNC_RESET + (START_SYNC_RESET_VALUE << 8));
} else {
//
// Nothing trapped.
// Lets check is the IO is trying to do something that would require
// us to stop trapping
//
if (AccessMode & EMULATOR_WRITE_ACCESS) {
//
// Make sure Bit 3 of the Miscellaneous register is always 0.
// If it is 1 it could select a non-existant clock, and kill the
// system
//
if (Port == MISC_OUTPUT_REG_WRITE_PORT) {
temp = VideoPortReadPortUchar(hwDeviceExtension->IOAddress +
SEQ_ADDRESS_PORT);
VideoPortWritePortUshort((PUSHORT) (hwDeviceExtension->IOAddress +
SEQ_ADDRESS_PORT),
(USHORT) (IND_SYNC_RESET +
(START_SYNC_RESET_VALUE << 8)));
VideoPortWritePortUchar(hwDeviceExtension->IOAddress + Port,
(UCHAR) (*Data & 0xF7) );
VideoPortWritePortUshort((PUSHORT) (hwDeviceExtension->IOAddress +
SEQ_ADDRESS_PORT),
(USHORT) (IND_SYNC_RESET +
(END_SYNC_RESET_VALUE << 8)));
VideoPortWritePortUchar(hwDeviceExtension->IOAddress +
SEQ_ADDRESS_PORT,
temp);
return NO_ERROR;
}
//
// If we get an access to the sequencer register, start trapping.
//
if ( (Port == SEQ_DATA_PORT) &&
((*Data & END_SYNC_RESET_VALUE) != END_SYNC_RESET_VALUE) &&
(VideoPortReadPortUchar(hwDeviceExtension->IOAddress +
SEQ_ADDRESS_PORT) == IND_SYNC_RESET)) {
VideoPortSetTrappedEmulatorPorts(hwDeviceExtension,
NUM_FULL_VGA_VALIDATOR_ACCESS_RANGE,
FullVgaValidatorAccessRange);
hwDeviceExtension->TrappedValidatorCount = 1;
hwDeviceExtension->TrappedValidatorData[0].Port = Port;
hwDeviceExtension->TrappedValidatorData[0].AccessType =
VGA_VALIDATOR_UCHAR_ACCESS;
hwDeviceExtension->TrappedValidatorData[0].Data = *Data;
//
// Start keeping track of the state of the sequencer port.
//
hwDeviceExtension->SequencerAddressValue = IND_SYNC_RESET;
} else {
VideoPortWritePortUchar(hwDeviceExtension->IOAddress + Port,
*Data);
}
} else {
*Data = VideoPortReadPortUchar(hwDeviceExtension->IOAddress + Port);
}
}
return NO_ERROR;
} // end VgaValidatorUcharEntry()
VP_STATUS
VgaValidatorUshortEntry(
ULONG Context,
ULONG Port,
UCHAR AccessMode,
PUSHORT Data
)
/*++
Routine Description:
Entry point into the validator for word I/O operations.
The entry point will be called whenever a byte operation was performed
by a DOS application on one of the specified Video ports. The kernel
emulator will forward these requests.
Arguments:
Context - Context value that is passed to each call made to the validator
function. This is the value the miniport driver specified in the
MiniportConfigInfo->EmulatorAccessEntriesContext.
Port - Port on which the operation is to be performed.
AccessMode - Determines if it is a read or write operation.
Data - Pointer to a variable containing the data to be written or a
variable into which the read data should be stored.
Return Value:
NO_ERROR.
--*/
{
PHW_DEVICE_EXTENSION hwDeviceExtension = (PHW_DEVICE_EXTENSION) Context;
ULONG endEmulation;
UCHAR temp;
Port -= VGA_BASE_IO_PORT;
if (hwDeviceExtension->TrappedValidatorCount) {
endEmulation = 0;
//
// If we are processing a WRITE instruction, then store it in the
// playback buffer. If the buffer is full, then play it back right
// away, end sync reset and reinitialize the buffer with a sync
// reset instruction.
//
// If we have a READ, we must flush the buffer (which has the side
// effect of starting SyncReset), perform the read operation, stop
// sync reset, and put back a sync reset instruction in the buffer
// so we can go on appropriately
//
if (AccessMode & EMULATOR_WRITE_ACCESS) {
//
// Make sure Bit 3 of the Miscellaneous register is always 0.
// If it is 1 it could select a non-existent clock, and kill the
// system
//
if (Port == MISC_OUTPUT_REG_WRITE_PORT) {
*Data &= 0xFFF7;
}
hwDeviceExtension->TrappedValidatorData[hwDeviceExtension->
TrappedValidatorCount].Port = Port;
hwDeviceExtension->TrappedValidatorData[hwDeviceExtension->
TrappedValidatorCount].AccessType = VGA_VALIDATOR_USHORT_ACCESS;
hwDeviceExtension->TrappedValidatorData[hwDeviceExtension->
TrappedValidatorCount].Data = *Data;
hwDeviceExtension->TrappedValidatorCount++;
//
// Check to see if this instruction was ending sync reset.
// If it did, we must flush the buffer and reset the trapped
// IO ports to the minimal set.
//
if (Port == SEQ_ADDRESS_PORT) {
//
// If we are accessing the seq address port, keep track of its
// value
//
hwDeviceExtension->SequencerAddressValue = (*Data & 0xFF);
}
if ((Port == SEQ_ADDRESS_PORT) &&
( ((*Data >> 8) & END_SYNC_RESET_VALUE) ==
END_SYNC_RESET_VALUE) &&
(hwDeviceExtension->SequencerAddressValue == IND_SYNC_RESET)) {
endEmulation = 1;
} else {
//
// If the buffer is not full, then just return right away.
//
if (hwDeviceExtension->TrappedValidatorCount <
VGA_MAX_VALIDATOR_DATA - 1) {
return NO_ERROR;
}
}
}
//
// We are either in a READ path or a WRITE path that caused a
// a full buffer. So flush the buffer either way.
//
// To do this put an END_SYNC_RESET at the end since we want to make
// the buffer is ended sync reset ended.
//
hwDeviceExtension->TrappedValidatorData[hwDeviceExtension->
TrappedValidatorCount].Port = SEQ_ADDRESS_PORT;
hwDeviceExtension->TrappedValidatorData[hwDeviceExtension->
TrappedValidatorCount].AccessType = VGA_VALIDATOR_USHORT_ACCESS;
hwDeviceExtension->TrappedValidatorData[hwDeviceExtension->
TrappedValidatorCount].Data = (USHORT) (IND_SYNC_RESET +
(END_SYNC_RESET_VALUE << 8));
hwDeviceExtension->TrappedValidatorCount++;
VideoPortSynchronizeExecution(hwDeviceExtension,
VpHighPriority,
(PMINIPORT_SYNCHRONIZE_ROUTINE)
VgaPlaybackValidatorData,
hwDeviceExtension);
//
// Write back the real value of the sequencer address port.
//
VideoPortWritePortUchar((PUCHAR) (hwDeviceExtension->IOAddress +
SEQ_ADDRESS_PORT),
(UCHAR) hwDeviceExtension->SequencerAddressValue);
//
// If we are in a READ path, read the data
//
if (AccessMode & EMULATOR_READ_ACCESS) {
*Data = VideoPortReadPortUshort((PUSHORT)(hwDeviceExtension->IOAddress
+ Port));
endEmulation = 0;
}
//
// If we are ending emulation, reset trapping to the minimal amount
// and exit.
//
if (endEmulation) {
VideoPortSetTrappedEmulatorPorts(hwDeviceExtension,
NUM_MINIMAL_VGA_VALIDATOR_ACCESS_RANGE,
MinimalVgaValidatorAccessRange);
return NO_ERROR;
}
//
// For both cases, put back a START_SYNC_RESET in the buffer.
//
hwDeviceExtension->TrappedValidatorCount = 1;
hwDeviceExtension->TrappedValidatorData[0].Port = SEQ_ADDRESS_PORT;
hwDeviceExtension->TrappedValidatorData[0].AccessType =
VGA_VALIDATOR_USHORT_ACCESS;
hwDeviceExtension->TrappedValidatorData[0].Data =
(ULONG) (IND_SYNC_RESET + (START_SYNC_RESET_VALUE << 8));
} else {
//
// Nothing trapped.
// Lets check is the IO is trying to do something that would require
// us to stop trapping
//
if (AccessMode & EMULATOR_WRITE_ACCESS) {
//
// Make sure Bit 3 of the Miscelaneous register is always 0.
// If it is 1 it could select a non-existent clock, and kill the
// system
//
if (Port == MISC_OUTPUT_REG_WRITE_PORT) {
temp = VideoPortReadPortUchar(hwDeviceExtension->IOAddress +
SEQ_ADDRESS_PORT);
VideoPortWritePortUshort((PUSHORT) (hwDeviceExtension->IOAddress +
SEQ_ADDRESS_PORT),
(USHORT) (IND_SYNC_RESET +
(START_SYNC_RESET_VALUE << 8)));
VideoPortWritePortUshort((PUSHORT) (hwDeviceExtension->IOAddress +
(ULONG)Port),
(USHORT) (*Data & 0xFFF7) );
VideoPortWritePortUshort((PUSHORT) (hwDeviceExtension->IOAddress +
SEQ_ADDRESS_PORT),
(USHORT) (IND_SYNC_RESET +
(END_SYNC_RESET_VALUE << 8)));
VideoPortWritePortUchar(hwDeviceExtension->IOAddress + SEQ_ADDRESS_PORT,
temp);
return NO_ERROR;
}
if ( (Port == SEQ_ADDRESS_PORT) &&
(((*Data>> 8) & END_SYNC_RESET_VALUE) != END_SYNC_RESET_VALUE) &&
((*Data & 0xFF) == IND_SYNC_RESET)) {
VideoPortSetTrappedEmulatorPorts(hwDeviceExtension,
NUM_FULL_VGA_VALIDATOR_ACCESS_RANGE,
FullVgaValidatorAccessRange);
hwDeviceExtension->TrappedValidatorCount = 1;
hwDeviceExtension->TrappedValidatorData[0].Port = Port;
hwDeviceExtension->TrappedValidatorData[0].AccessType =
VGA_VALIDATOR_USHORT_ACCESS;
hwDeviceExtension->TrappedValidatorData[0].Data = *Data;
//
// Start keeping track of the state of the sequencer port.
//
hwDeviceExtension->SequencerAddressValue = IND_SYNC_RESET;
} else {
VideoPortWritePortUshort((PUSHORT)(hwDeviceExtension->IOAddress +
Port),
*Data);
}
} else {
*Data = VideoPortReadPortUshort((PUSHORT)(hwDeviceExtension->IOAddress +
Port));
}
}
return NO_ERROR;
} // end VgaValidatorUshortEntry()
VP_STATUS
VgaValidatorUlongEntry(
ULONG Context,
ULONG Port,
UCHAR AccessMode,
PULONG Data
)
/*++
Routine Description:
Entry point into the validator for dword I/O operations.
The entry point will be called whenever a byte operation was performed
by a DOS application on one of the specified Video ports. The kernel
emulator will forward these requests.
Arguments:
Context - Context value that is passed to each call made to the validator
function. This is the value the miniport driver specified in the
MiniportConfigInfo->EmulatorAccessEntriesContext.
Port - Port on which the operation is to be performed.
AccessMode - Determines if it is a read or write operation.
Data - Pointer to a variable containing the data to be written or a
variable into which the read data should be stored.
Return Value:
NO_ERROR.
--*/
{
PHW_DEVICE_EXTENSION hwDeviceExtension = (PHW_DEVICE_EXTENSION) Context;
ULONG endEmulation;
UCHAR temp;
Port -= VGA_BASE_IO_PORT;
if (hwDeviceExtension->TrappedValidatorCount) {
endEmulation = 0;
//
// If we are processing a WRITE instruction, then store it in the
// playback buffer. If the buffer is full, then play it back right
// away, end sync reset and reinitialize the buffer with a sync
// reset instruction.
//
// If we have a READ, we must flush the buffer (which has the side
// effect of starting SyncReset), perform the read operation, stop
// sync reset, and put back a sync reset instruction in the buffer
// so we can go on appropriately
//
if (AccessMode & EMULATOR_WRITE_ACCESS) {
//
// Make sure Bit 3 of the Miscellaneous register is always 0.
// If it is 1 it could select a non-existent clock, and kill the
// system
//
if (Port == MISC_OUTPUT_REG_WRITE_PORT) {
*Data &= 0xFFFFFFF7;
}
hwDeviceExtension->TrappedValidatorData[hwDeviceExtension->
TrappedValidatorCount].Port = Port;
hwDeviceExtension->TrappedValidatorData[hwDeviceExtension->
TrappedValidatorCount].AccessType = VGA_VALIDATOR_ULONG_ACCESS;
hwDeviceExtension->TrappedValidatorData[hwDeviceExtension->
TrappedValidatorCount].Data = *Data;
hwDeviceExtension->TrappedValidatorCount++;
//
// Check to see if this instruction was ending sync reset.
// If it did, we must flush the buffer and reset the trapped
// IO ports to the minimal set.
//
if (Port == SEQ_ADDRESS_PORT) {
//
// If we are accessing the seq address port, keep track of its
// value
//
hwDeviceExtension->SequencerAddressValue = (*Data & 0xFF);
}
if ((Port == SEQ_ADDRESS_PORT) &&
( ((*Data >> 8) & END_SYNC_RESET_VALUE) ==
END_SYNC_RESET_VALUE) &&
(hwDeviceExtension->SequencerAddressValue == IND_SYNC_RESET)) {
endEmulation = 1;
} else {
//
// If the buffer is not full, then just return right away.
//
if (hwDeviceExtension->TrappedValidatorCount <
VGA_MAX_VALIDATOR_DATA - 1) {
return NO_ERROR;
}
}
}
//
// We are either in a READ path or a WRITE path that caused a
// a full buffer. So flush the buffer either way.
//
// To do this put an END_SYNC_RESET at the end since we want to make
// the buffer is ended sync reset ended.
//
hwDeviceExtension->TrappedValidatorData[hwDeviceExtension->
TrappedValidatorCount].Port = SEQ_ADDRESS_PORT;
hwDeviceExtension->TrappedValidatorData[hwDeviceExtension->
TrappedValidatorCount].AccessType = VGA_VALIDATOR_USHORT_ACCESS;
hwDeviceExtension->TrappedValidatorData[hwDeviceExtension->
TrappedValidatorCount].Data = (USHORT) (IND_SYNC_RESET +
(END_SYNC_RESET_VALUE << 8));
hwDeviceExtension->TrappedValidatorCount++;
VideoPortSynchronizeExecution(hwDeviceExtension,
VpHighPriority,
(PMINIPORT_SYNCHRONIZE_ROUTINE)
VgaPlaybackValidatorData,
hwDeviceExtension);
//
// Write back the real value of the sequencer address port.
//
VideoPortWritePortUchar(hwDeviceExtension->IOAddress +
SEQ_ADDRESS_PORT,
(UCHAR) hwDeviceExtension->SequencerAddressValue);
//
// If we are in a READ path, read the data
//
if (AccessMode & EMULATOR_READ_ACCESS) {
*Data = VideoPortReadPortUlong((PULONG) (hwDeviceExtension->IOAddress +
Port));
endEmulation = 0;
}
//
// If we are ending emulation, reset trapping to the minimal amount
// and exit.
//
if (endEmulation) {
VideoPortSetTrappedEmulatorPorts(hwDeviceExtension,
NUM_MINIMAL_VGA_VALIDATOR_ACCESS_RANGE,
MinimalVgaValidatorAccessRange);
return NO_ERROR;
}
//
// For both cases, put back a START_SYNC_RESET in the buffer.
//
hwDeviceExtension->TrappedValidatorCount = 1;
hwDeviceExtension->TrappedValidatorData[0].Port = SEQ_ADDRESS_PORT;
hwDeviceExtension->TrappedValidatorData[0].AccessType =
VGA_VALIDATOR_USHORT_ACCESS;
hwDeviceExtension->TrappedValidatorData[0].Data =
(ULONG) (IND_SYNC_RESET + (START_SYNC_RESET_VALUE << 8));
} else {
//
// Nothing trapped.
// Lets check is the IO is trying to do something that would require
// us to stop trapping
//
if (AccessMode & EMULATOR_WRITE_ACCESS) {
//
// Make sure Bit 3 of the Miscelaneous register is always 0.
// If it is 1 it could select a non-existant clock, and kill the
// system
//
if (Port == MISC_OUTPUT_REG_WRITE_PORT) {
temp = VideoPortReadPortUchar(hwDeviceExtension->IOAddress +
SEQ_ADDRESS_PORT);
VideoPortWritePortUshort((PUSHORT) (hwDeviceExtension->IOAddress +
SEQ_ADDRESS_PORT),
(USHORT) (IND_SYNC_RESET +
(START_SYNC_RESET_VALUE << 8)));
VideoPortWritePortUlong((PULONG) (hwDeviceExtension->IOAddress +
Port),
(ULONG) (*Data & 0xFFFFFFF7) );
VideoPortWritePortUshort((PUSHORT) (hwDeviceExtension->IOAddress +
SEQ_ADDRESS_PORT),
(USHORT) (IND_SYNC_RESET +
(END_SYNC_RESET_VALUE << 8)));
VideoPortWritePortUchar(hwDeviceExtension->IOAddress + SEQ_ADDRESS_PORT,
temp);
return NO_ERROR;
}
if ( (Port == SEQ_ADDRESS_PORT) &&
(((*Data>> 8) & END_SYNC_RESET_VALUE) != END_SYNC_RESET_VALUE) &&
((*Data & 0xFF) == IND_SYNC_RESET)) {
VideoPortSetTrappedEmulatorPorts(hwDeviceExtension,
NUM_FULL_VGA_VALIDATOR_ACCESS_RANGE,
FullVgaValidatorAccessRange);
hwDeviceExtension->TrappedValidatorCount = 1;
hwDeviceExtension->TrappedValidatorData[0].Port = Port;
hwDeviceExtension->TrappedValidatorData[0].AccessType =
VGA_VALIDATOR_ULONG_ACCESS;
hwDeviceExtension->TrappedValidatorData[0].Data = *Data;
//
// Start keeping track of the state of the sequencer port.
//
hwDeviceExtension->SequencerAddressValue = IND_SYNC_RESET;
} else {
VideoPortWritePortUlong((PULONG) (hwDeviceExtension->IOAddress +
Port),
*Data);
}
} else {
*Data = VideoPortReadPortUlong((PULONG) (hwDeviceExtension->IOAddress +
Port));
}
}
return NO_ERROR;
} // end VgaValidatorUlongEntry()
BOOLEAN
VgaPlaybackValidatorData(
PVOID Context
)
/*++
Routine Description:
Performs all the DOS apps IO port accesses that were trapped by the
validator. Only IO accesses that can be processed are WRITEs
The number of outstanding IO access in deviceExtension is set to
zero as a side effect.
This function must be called via a call to VideoPortSynchronizeRoutine.
Arguments:
Context - Context parameter passed to the synchronized routine.
Must be a pointer to the miniport driver's device extension.
Return Value:
TRUE.
--*/
{
PHW_DEVICE_EXTENSION hwDeviceExtension = Context;
ULONG ioBaseAddress = (ULONG) hwDeviceExtension->IOAddress;
UCHAR i;
PVGA_VALIDATOR_DATA validatorData = hwDeviceExtension->TrappedValidatorData;
//
// Loop through the array of data and do instructions one by one.
//
for (i = 0; i < hwDeviceExtension->TrappedValidatorCount;
i++, validatorData++) {
//
// Calculate base address first
//
ioBaseAddress = (ULONG)hwDeviceExtension->IOAddress +
validatorData->Port;
//
// This is a write operation. We will automatically stop when the
// buffer is empty.
//
switch (validatorData->AccessType) {
case VGA_VALIDATOR_UCHAR_ACCESS :
VideoPortWritePortUchar((PUCHAR)ioBaseAddress,
(UCHAR) validatorData->Data);
break;
case VGA_VALIDATOR_USHORT_ACCESS :
VideoPortWritePortUshort((PUSHORT)ioBaseAddress,
(USHORT) validatorData->Data);
break;
case VGA_VALIDATOR_ULONG_ACCESS :
VideoPortWritePortUlong((PULONG)ioBaseAddress,
(ULONG) validatorData->Data);
break;
default:
VideoDebugPrint((0, "InvalidValidatorAccessType\n" ));
}
}
hwDeviceExtension->TrappedValidatorCount = 0;
return TRUE;
} // end VgaPlaybackValidatorData()
#endif
//
// These are area to keep the color lookup table in suspend-resume.
// Because the color lookup table loses.
//
static UCHAR ClutBuf1[sizeof(VIDEO_CLUT) + sizeof(ULONG) * VIDEO_MAX_COLOR_REGISTER];
static UCHAR ClutBuf2[sizeof(VIDEO_CLUT) + sizeof(ULONG) * VIDEO_MAX_COLOR_REGISTER];
PVIDEO_CLUT CurrClutBuffer = (PVIDEO_CLUT)ClutBuf1;
PVIDEO_CLUT PrevClutBuffer = (PVIDEO_CLUT)ClutBuf2;
VP_STATUS
VgaSetColorLookup(
PHW_DEVICE_EXTENSION HwDeviceExtension,
PVIDEO_CLUT ClutBuffer,
ULONG ClutBufferSize
)
/*++
Routine Description:
This routine sets a specified portion of the DAC 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:
NO_ERROR - information returned successfully
ERROR_INSUFFICIENT_BUFFER - input buffer not large enough for input data.
ERROR_INVALID_PARAMETER - invalid clut size.
--*/
{
ULONG i;
ULONG DacIndex = VIDEO_MAX_COLOR_REGISTER + 1;
PUCHAR IoBase = HwDeviceExtension->IOAddress;
//
// 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)) ) ) {
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) ) {
return ERROR_INVALID_PARAMETER;
}
//
// Wait until next vertical retrace interval
//
while (0 != (VideoPortReadPortUchar(IoBase + INPUT_STATUS_1_COLOR) & 0x08));
while (0 == (VideoPortReadPortUchar(IoBase + INPUT_STATUS_1_COLOR) & 0x08));
//
// Set CLUT registers directly on the hardware
//
// Note: To prevent the "SNOW" noise on the screen, it is required to reduce the
// number of accesses to DAC registers. WD90C24A/A2 cannot be updated all
// DAC entries within a virtical retrace period.
//
for (i = 0; i < ClutBuffer->NumEntries; i++) {
if (ClutBuffer->LookupTable[i].RgbLong !=
CurrClutBuffer->LookupTable[(UCHAR)ClutBuffer->FirstEntry + (UCHAR)i].RgbLong) {
if (DacIndex != ((ULONG)ClutBuffer->FirstEntry + i)) {
DacIndex = (ULONG)ClutBuffer->FirstEntry + i;
VideoPortWritePortUchar(IoBase + DAC_ADDRESS_WRITE_PORT, (UCHAR)DacIndex);
} /* endif */
VideoPortWritePortBufferUchar(IoBase + DAC_DATA_REG_PORT,
&(ClutBuffer->LookupTable[i].RgbArray.Red),
0x03);
CurrClutBuffer->LookupTable[(UCHAR)DacIndex].RgbLong =
ClutBuffer->LookupTable[i].RgbLong;
DacIndex++;
} /* endif */
} /* endfor */
return NO_ERROR;
} // end VgaSetColorLookup()
BOOLEAN
TestPortUchar(
PUCHAR IoPort,
UCHAR Mask
)
/*++
Routine Description:
This routine checkes if the specified I/O port is writable or not
Arguments:
IoPort - Specifies the logical address of I/O port to be tested
Mask - Specifies the bits to be tested.
Return Value:
None.
--*/
{
UCHAR test_pattern, old_value, result = FALSE;
old_value = VideoPortReadPortUchar(IoPort);
test_pattern = 0x00;
VideoPortWritePortUchar(IoPort, (UCHAR)((old_value & ~Mask) | (test_pattern & Mask)));
if ((VideoPortReadPortUchar(IoPort) & Mask) == (test_pattern & Mask)) {
test_pattern = 0xff;
VideoPortWritePortUchar(IoPort, (UCHAR)((old_value & ~Mask) | (test_pattern & Mask)));
if ((VideoPortReadPortUchar(IoPort) & Mask) == (test_pattern & Mask))
result = TRUE;
} /* endif */
VideoPortWritePortUchar(IoPort, old_value);
return result;
}
VOID
GetPanelType(
PHW_DEVICE_EXTENSION HwDeviceExtension
)
/*++
Routine Description:
This routine get the type of attached LCD display.
Arguments:
HwDeviceExtension - Pointer to the miniport driver's device extension.
Return Value:
None.
--*/
{
#ifdef PPC
PUCHAR VAddress;
VIDEO_ACCESS_RANGE VAccessRange = {0x00000D00,0x00000000, 2, 1, 1, 0}; // Flat Panel Control Address/Data
#endif
//
// Assume CRT only mode
//
HwDeviceExtension->PanelType = NoLCD;
HwDeviceExtension->PanelXResolution = 0;
HwDeviceExtension->PanelYResolution = 0;
#ifdef PPC
if ((VAddress =
VideoPortGetDeviceBase(HwDeviceExtension,
VAccessRange.RangeStart,
VAccessRange.RangeLength,
VAccessRange.RangeInIoSpace)) == NULL) {
VideoDebugPrint((1, "GetPanelType - Fail to get address\n"));
return;
}
VideoPortWritePortUchar(VAddress, 0xff);
switch (VideoPortReadPortUchar(VAddress + 1) & 0x0f) {
case 0x0e : HwDeviceExtension->PanelType = IBM_F8515;
HwDeviceExtension->PanelXResolution = 640;
HwDeviceExtension->PanelYResolution = 480;
break;
case 0x0c : HwDeviceExtension->PanelType = IBM_F8532;
HwDeviceExtension->PanelXResolution = 800;
HwDeviceExtension->PanelYResolution = 600;
break;
case 0x0d : HwDeviceExtension->PanelType = TOSHIBA_DSTNC;
HwDeviceExtension->PanelXResolution = 640;
HwDeviceExtension->PanelYResolution = 480;
break;
default : break;
}
VideoDebugPrint((2, "GetPanelType - PanelType = %d\n",HwDeviceExtension->PanelType));
VideoPortFreeDeviceBase(HwDeviceExtension,VAddress);
#endif
} // end GetPanelType()
VOID
VgaSetVirtualScreenPosition (
PHW_DEVICE_EXTENSION HwDeviceExtension
)
/*++
Routine Description:
This routine set the position of virtual screen.
Arguments:
HwDeviceExtension - Pointer to the miniport driver's device extension.
Return Value:
None.
--*/
{
ULONG offset;
UCHAR pr3_val, pr5_val;
offset = HwDeviceExtension->VirtualScreenPosY * HwDeviceExtension->CurrentMode->wbytes
+ HwDeviceExtension->VirtualScreenPosX * (HwDeviceExtension->CurrentMode->bitsPerPlane/8);
/* */
/* Set starting address(20-bits) into the 4 registers as follows: */
/* */
/* 'aabbbbbbbbccccccccdd'b */
/* ÀÙÀÄÄÄÄÄÄÙÀÄÄÄÄÄÄÙÀÙ */
/* A A A A */
/* ³ ³ ³ ÀÄÄ ATTR 0x13 Horizontal Pel Panning Register */
/* ³ ³ ÀÄÄÄÄÄÄÄ CRTC 0x0D Start Address Low */
/* ³ ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ CRTC 0x0C Start Address High */
/* ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ PR3 Bit 4-3 Start Address Overflow */
/* */
// unlock PR0(A)-PR4
VideoPortWritePortUchar(HwDeviceExtension->IOAddress +
GRAPH_ADDRESS_PORT, pr5);
pr5_val = VideoPortReadPortUchar(HwDeviceExtension->IOAddress +
GRAPH_DATA_PORT);
VideoPortWritePortUchar(HwDeviceExtension->IOAddress +
GRAPH_DATA_PORT, pr5_unlock);
// set PR3
VideoPortWritePortUchar(HwDeviceExtension->IOAddress +
GRAPH_ADDRESS_PORT, pr3);
pr3_val = VideoPortReadPortUchar(HwDeviceExtension->IOAddress +
GRAPH_DATA_PORT);
VideoPortWritePortUchar(HwDeviceExtension->IOAddress +
GRAPH_DATA_PORT, (UCHAR)(pr3_val & ~0x18| ((offset >> 15) & 0x18)));
// lock PR0(A)-PR4
VideoPortWritePortUchar(HwDeviceExtension->IOAddress +
GRAPH_ADDRESS_PORT, pr5);
VideoPortWritePortUchar(HwDeviceExtension->IOAddress +
GRAPH_DATA_PORT, pr5_val);
VideoPortWritePortUchar(HwDeviceExtension->IOAddress +
CRTC_ADDRESS_PORT_COLOR, 0x0c);
VideoPortWritePortUchar(HwDeviceExtension->IOAddress +
CRTC_DATA_PORT_COLOR, (UCHAR)((offset >> 10) & 0x00ff));
VideoPortWritePortUchar(HwDeviceExtension->IOAddress +
CRTC_ADDRESS_PORT_COLOR, 0x0d);
VideoPortWritePortUchar(HwDeviceExtension->IOAddress +
CRTC_DATA_PORT_COLOR, (UCHAR)((offset >> 2) & 0x00ff));
} // end VgaSetVirtualScreenPosition()