reactos/win32ss/drivers/miniport/vga_new/modeset.c
2019-03-04 21:58:42 +01:00

899 lines
24 KiB
C

/*
* PROJECT: ReactOS VGA Miniport Driver
* LICENSE: Microsoft NT4 DDK Sample Code License
* FILE: win32ss/drivers/miniport/vga_new/modeset.c
* PURPOSE: Handles switching to Standard VGA Modes for compatible cards
* PROGRAMMERS: Copyright (c) 1992 Microsoft Corporation
* ReactOS Portable Systems Group
*/
#include "vga.h"
VP_STATUS
NTAPI
VgaInterpretCmdStream(
PHW_DEVICE_EXTENSION HwDeviceExtension,
PUSHORT pusCmdStream
);
VP_STATUS
NTAPI
VgaSetMode(
PHW_DEVICE_EXTENSION HwDeviceExtension,
PVIDEO_MODE Mode,
ULONG ModeSize,
// eVb: 2.1 [SET MODE] - Add new output parameter for framebuffer update functionality
PULONG PhysPtrChange
// eVb: 2.1 [END]
);
VP_STATUS
NTAPI
VgaQueryAvailableModes(
PHW_DEVICE_EXTENSION HwDeviceExtension,
PVIDEO_MODE_INFORMATION ModeInformation,
ULONG ModeInformationSize,
PULONG_PTR OutputSize
);
VP_STATUS
NTAPI
VgaQueryNumberOfAvailableModes(
PHW_DEVICE_EXTENSION HwDeviceExtension,
PVIDEO_NUM_MODES NumModes,
ULONG NumModesSize,
PULONG_PTR OutputSize
);
VP_STATUS
NTAPI
VgaQueryCurrentMode(
PHW_DEVICE_EXTENSION HwDeviceExtension,
PVIDEO_MODE_INFORMATION ModeInformation,
ULONG ModeInformationSize,
PULONG_PTR OutputSize
);
VOID
NTAPI
VgaZeroVideoMemory(
PHW_DEVICE_EXTENSION HwDeviceExtension
);
#if defined(ALLOC_PRAGMA)
#pragma alloc_text(PAGE,VgaInterpretCmdStream)
#pragma alloc_text(PAGE,VgaSetMode)
#pragma alloc_text(PAGE,VgaQueryAvailableModes)
#pragma alloc_text(PAGE,VgaQueryNumberOfAvailableModes)
#pragma alloc_text(PAGE,VgaZeroVideoMemory)
#endif
//---------------------------------------------------------------------------
VP_STATUS
NTAPI
VgaInterpretCmdStream(
PHW_DEVICE_EXTENSION HwDeviceExtension,
PUSHORT pusCmdStream
)
/*++
Routine Description:
Interprets the appropriate command array to set up VGA registers for the
requested mode. Typically used to set the VGA into a particular mode by
programming all of the registers
Arguments:
HwDeviceExtension - Pointer to the miniport driver's device extension.
pusCmdStream - array of commands to be interpreted.
Return Value:
The status of the operation (can only fail on a bad command); TRUE for
success, FALSE for failure.
--*/
{
ULONG ulCmd;
ULONG_PTR ulPort;
UCHAR jValue;
USHORT usValue;
ULONG culCount;
ULONG ulIndex;
ULONG_PTR ulBase;
if (pusCmdStream == NULL) {
VideoDebugPrint((1, "VgaInterpretCmdStream - Invalid pusCmdStream\n"));
return TRUE;
}
ulBase = (ULONG_PTR)HwDeviceExtension->IOAddress;
//
// Now set the adapter to the desired mode.
//
while ((ulCmd = *pusCmdStream++) != EOD) {
//
// Determine major command type
//
switch (ulCmd & 0xF0) {
//
// Basic input/output command
//
case INOUT:
//
// Determine type of inout instruction
//
if (!(ulCmd & IO)) {
//
// Out instruction. Single or multiple outs?
//
if (!(ulCmd & MULTI)) {
//
// Single out. Byte or word out?
//
if (!(ulCmd & BW)) {
//
// Single byte out
//
ulPort = *pusCmdStream++;
jValue = (UCHAR) *pusCmdStream++;
VideoPortWritePortUchar((PUCHAR)(ulBase+ulPort),
jValue);
} else {
//
// Single word out
//
ulPort = *pusCmdStream++;
usValue = *pusCmdStream++;
VideoPortWritePortUshort((PUSHORT)(ulBase+ulPort),
usValue);
}
} else {
//
// Output a string of values
// Byte or word outs?
//
if (!(ulCmd & BW)) {
//
// String byte outs. Do in a loop; can't use
// VideoPortWritePortBufferUchar because the data
// is in USHORT form
//
ulPort = ulBase + *pusCmdStream++;
culCount = *pusCmdStream++;
while (culCount--) {
jValue = (UCHAR) *pusCmdStream++;
VideoPortWritePortUchar((PUCHAR)ulPort,
jValue);
}
} else {
//
// String word outs
//
ulPort = *pusCmdStream++;
culCount = *pusCmdStream++;
VideoPortWritePortBufferUshort((PUSHORT)
(ulBase + ulPort), pusCmdStream, culCount);
pusCmdStream += culCount;
}
}
} else {
// In instruction
//
// Currently, string in instructions aren't supported; all
// in instructions are handled as single-byte ins
//
// Byte or word in?
//
if (!(ulCmd & BW)) {
//
// Single byte in
//
ulPort = *pusCmdStream++;
jValue = VideoPortReadPortUchar((PUCHAR)ulBase+ulPort);
} else {
//
// Single word in
//
ulPort = *pusCmdStream++;
usValue = VideoPortReadPortUshort((PUSHORT)
(ulBase+ulPort));
}
}
break;
//
// Higher-level input/output commands
//
case METAOUT:
//
// Determine type of metaout command, based on minor
// command field
//
switch (ulCmd & 0x0F) {
//
// Indexed outs
//
case INDXOUT:
ulPort = ulBase + *pusCmdStream++;
culCount = *pusCmdStream++;
ulIndex = *pusCmdStream++;
while (culCount--) {
usValue = (USHORT) (ulIndex +
(((ULONG)(*pusCmdStream++)) << 8));
VideoPortWritePortUshort((PUSHORT)ulPort, usValue);
ulIndex++;
}
break;
//
// Masked out (read, AND, XOR, write)
//
case MASKOUT:
ulPort = *pusCmdStream++;
jValue = VideoPortReadPortUchar((PUCHAR)ulBase+ulPort);
jValue &= *pusCmdStream++;
jValue ^= *pusCmdStream++;
VideoPortWritePortUchar((PUCHAR)ulBase + ulPort,
jValue);
break;
//
// Attribute Controller out
//
case ATCOUT:
ulPort = ulBase + *pusCmdStream++;
culCount = *pusCmdStream++;
ulIndex = *pusCmdStream++;
while (culCount--) {
// Write Attribute Controller index
VideoPortWritePortUchar((PUCHAR)ulPort,
(UCHAR)ulIndex);
// Write Attribute Controller data
jValue = (UCHAR) *pusCmdStream++;
VideoPortWritePortUchar((PUCHAR)ulPort, jValue);
ulIndex++;
}
break;
//
// None of the above; error
//
default:
return FALSE;
}
break;
//
// NOP
//
case NCMD:
break;
//
// Unknown command; error
//
default:
return FALSE;
}
}
return TRUE;
} // end VgaInterpretCmdStream()
VP_STATUS
NTAPI
VgaSetMode(
PHW_DEVICE_EXTENSION HwDeviceExtension,
PVIDEO_MODE Mode,
ULONG ModeSize,
// eVb: 2.2 [SET MODE] - Add new output parameter for framebuffer update functionality
PULONG PhysPtrChange
// eVb: 2.2 [END]
)
/*++
Routine Description:
This routine sets the vga into the requested mode.
Arguments:
HwDeviceExtension - Pointer to the miniport driver's device extension.
Mode - Pointer to the structure containing the information about the
font to be set.
ModeSize - Length of the input buffer supplied by the user.
Return Value:
ERROR_INSUFFICIENT_BUFFER if the input buffer was not large enough
for the input data.
ERROR_INVALID_PARAMETER if the mode number is invalid.
NO_ERROR if the operation completed successfully.
--*/
{
PVIDEOMODE pRequestedMode;
VP_STATUS status;
ULONG RequestedModeNum;
// eVb: 2.3 [SET MODE] - Add new output parameter for framebuffer update functionality
*PhysPtrChange = FALSE;
// eVb: 2.3 [END]
//
// Check if the size of the data in the input buffer is large enough.
//
if (ModeSize < sizeof(VIDEO_MODE))
{
return ERROR_INSUFFICIENT_BUFFER;
}
//
// Extract the clear memory, and map linear bits.
//
RequestedModeNum = Mode->RequestedMode &
~(VIDEO_MODE_NO_ZERO_MEMORY | VIDEO_MODE_MAP_MEM_LINEAR);
if (!(Mode->RequestedMode & VIDEO_MODE_NO_ZERO_MEMORY))
{
#if defined(_X86_)
VgaZeroVideoMemory(HwDeviceExtension);
#endif
}
//
// Check to see if we are requesting a valid mode
//
// eVb: 2.4 [CIRRUS] - Remove Cirrus-specific check for valid mode
if ( (RequestedModeNum >= NumVideoModes) )
// eVb: 2.4 [END]
{
VideoDebugPrint((0, "Invalide Mode Number = %d!\n", RequestedModeNum));
return ERROR_INVALID_PARAMETER;
}
VideoDebugPrint((2, "Attempting to set mode %d\n",
RequestedModeNum));
// eVb: 2.5 [VBE] - Use dynamic VBE mode list instead of hard-coded VGA list
pRequestedMode = &VgaModeList[RequestedModeNum];
// eVb: 2.5 [END]
VideoDebugPrint((2, "Info on Requested Mode:\n"
"\tResolution: %dx%d\n",
pRequestedMode->hres,
pRequestedMode->vres ));
//
// VESA BIOS mode switch
//
// eVb: 2.6 [VBE] - VBE Mode Switch Support
status = VbeSetMode(HwDeviceExtension, pRequestedMode, PhysPtrChange);
if (status == ERROR_INVALID_FUNCTION)
{
//
// VGA mode switch
//
if (!pRequestedMode->CmdStream) return ERROR_INVALID_FUNCTION;
if (!VgaInterpretCmdStream(HwDeviceExtension, pRequestedMode->CmdStream)) return ERROR_INVALID_FUNCTION;
goto Cleanup;
}
else if (status != NO_ERROR) return status;
// eVb: 2.6 [END]
// eVb: 2.7 [MODE-X] - Windows VGA Miniport Supports Mode-X, we should too
//
// ModeX check
//
if (pRequestedMode->hres == 320)
{
VideoDebugPrint((0, "ModeX not support!!!\n"));
return ERROR_INVALID_PARAMETER;
}
// eVb: 2.7 [END]
//
// Text mode check
//
if (!(pRequestedMode->fbType & VIDEO_MODE_GRAPHICS))
{
// eVb: 2.8 [TODO] - This code path is not implemented yet
VideoDebugPrint((0, "Text-mode not support!!!\n"));
return ERROR_INVALID_PARAMETER;
// eVb: 2.8 [END]
}
Cleanup:
//
// Update the location of the physical frame buffer within video memory.
//
// eVb: 2.9 [VBE] - Linear and banked support is unified in VGA, unlike Cirrus
HwDeviceExtension->PhysicalVideoMemoryBase.LowPart = pRequestedMode->PhysBase;
HwDeviceExtension->PhysicalVideoMemoryLength = pRequestedMode->PhysSize;
HwDeviceExtension->PhysicalFrameLength =
pRequestedMode->FrameBufferSize;
HwDeviceExtension->PhysicalFrameOffset.LowPart =
pRequestedMode->FrameBufferBase;
// eVb: 2.9 [END]
//
// Store the new mode value.
//
HwDeviceExtension->CurrentMode = pRequestedMode;
HwDeviceExtension->ModeIndex = Mode->RequestedMode;
return NO_ERROR;
} //end VgaSetMode()
VP_STATUS
NTAPI
VgaQueryAvailableModes(
PHW_DEVICE_EXTENSION HwDeviceExtension,
PVIDEO_MODE_INFORMATION ModeInformation,
ULONG ModeInformationSize,
PULONG_PTR OutputSize
)
/*++
Routine Description:
This routine returns the list of all available available modes on the
card.
Arguments:
HwDeviceExtension - Pointer to the miniport driver's device extension.
ModeInformation - Pointer to the output buffer supplied by the user.
This is where the list of all valid modes is stored.
ModeInformationSize - 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:
ERROR_INSUFFICIENT_BUFFER if the output buffer was not large enough
for the data being returned.
NO_ERROR if the operation completed successfully.
--*/
{
PVIDEO_MODE_INFORMATION videoModes = ModeInformation;
ULONG i;
//
// Find out the size of the data to be put in 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 (ModeInformationSize < (*OutputSize =
// eVb: 2.10 [VBE] - We store VBE/VGA mode count in this global, not in DevExt like Cirrus
NumVideoModes *
// eVb: 2.10 [END]
sizeof(VIDEO_MODE_INFORMATION)) ) {
return ERROR_INSUFFICIENT_BUFFER;
}
//
// For each mode supported by the card, store the mode characteristics
// in the output buffer.
//
for (i = 0; i < NumVideoModes; i++)
{
videoModes->Length = sizeof(VIDEO_MODE_INFORMATION);
videoModes->ModeIndex = i;
// eVb: 2.11 [VBE] - Use dynamic VBE mode list instead of hard-coded VGA list
videoModes->VisScreenWidth = VgaModeList[i].hres;
videoModes->ScreenStride = VgaModeList[i].wbytes;
videoModes->VisScreenHeight = VgaModeList[i].vres;
videoModes->NumberOfPlanes = VgaModeList[i].numPlanes;
videoModes->BitsPerPlane = VgaModeList[i].bitsPerPlane;
videoModes->Frequency = VgaModeList[i].Frequency;
videoModes->XMillimeter = 320; // temporary hardcoded constant
videoModes->YMillimeter = 240; // temporary hardcoded constant
videoModes->AttributeFlags = VgaModeList[i].fbType;
// eVb: 2.11 [END]
if ((VgaModeList[i].bitsPerPlane == 32) ||
(VgaModeList[i].bitsPerPlane == 24))
{
videoModes->NumberRedBits = 8;
videoModes->NumberGreenBits = 8;
videoModes->NumberBlueBits = 8;
videoModes->RedMask = 0xff0000;
videoModes->GreenMask = 0x00ff00;
videoModes->BlueMask = 0x0000ff;
}
else if (VgaModeList[i].bitsPerPlane == 16)
{
videoModes->NumberRedBits = 6;
videoModes->NumberGreenBits = 6;
videoModes->NumberBlueBits = 6;
videoModes->RedMask = 0x1F << 11;
videoModes->GreenMask = 0x3F << 5;
videoModes->BlueMask = 0x1F;
}
// eVb: 2.12 [VGA] - Add support for 15bpp modes, which Cirrus doesn't support
else if (VgaModeList[i].bitsPerPlane == 15)
{
videoModes->NumberRedBits = 6;
videoModes->NumberGreenBits = 6;
videoModes->NumberBlueBits = 6;
videoModes->RedMask = 0x3E << 9;
videoModes->GreenMask = 0x1F << 5;
videoModes->BlueMask = 0x1F;
}
// eVb: 2.12 [END]
else
{
videoModes->NumberRedBits = 6;
videoModes->NumberGreenBits = 6;
videoModes->NumberBlueBits = 6;
videoModes->RedMask = 0;
videoModes->GreenMask = 0;
videoModes->BlueMask = 0;
}
// eVb: 2.13 [VGA] - All modes are palette managed/driven, unlike Cirrus
videoModes->AttributeFlags |= VIDEO_MODE_PALETTE_DRIVEN |
VIDEO_MODE_MANAGED_PALETTE;
// eVb: 2.13 [END]
videoModes++;
}
return NO_ERROR;
} // end VgaGetAvailableModes()
VP_STATUS
NTAPI
VgaQueryNumberOfAvailableModes(
PHW_DEVICE_EXTENSION HwDeviceExtension,
PVIDEO_NUM_MODES NumModes,
ULONG NumModesSize,
PULONG_PTR OutputSize
)
/*++
Routine Description:
This routine returns the number of available modes for this particular
video card.
Arguments:
HwDeviceExtension - Pointer to the miniport driver's device extension.
NumModes - Pointer to the output buffer supplied by the user. This is
where the number of modes is stored.
NumModesSize - 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.
Return Value:
ERROR_INSUFFICIENT_BUFFER if the output buffer was not large enough
for the data being returned.
NO_ERROR if the operation completed successfully.
--*/
{
//
// 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 (NumModesSize < (*OutputSize = sizeof(VIDEO_NUM_MODES)) ) {
return ERROR_INSUFFICIENT_BUFFER;
}
//
// Store the number of modes into the buffer.
//
// eVb: 2.14 [VBE] - We store VBE/VGA mode count in this global, not in DevExt like Cirrus
NumModes->NumModes = NumVideoModes;
// eVb: 2.14 [END]
NumModes->ModeInformationLength = sizeof(VIDEO_MODE_INFORMATION);
return NO_ERROR;
} // end VgaGetNumberOfAvailableModes()
VP_STATUS
NTAPI
VgaQueryCurrentMode(
PHW_DEVICE_EXTENSION HwDeviceExtension,
PVIDEO_MODE_INFORMATION ModeInformation,
ULONG ModeInformationSize,
PULONG_PTR OutputSize
)
/*++
Routine Description:
This routine returns a description of the current video mode.
Arguments:
HwDeviceExtension - Pointer to the miniport driver's device extension.
ModeInformation - Pointer to the output buffer supplied by the user.
This is where the current mode information is stored.
ModeInformationSize - 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:
ERROR_INSUFFICIENT_BUFFER if the output buffer was not large enough
for the data being returned.
NO_ERROR if the operation completed successfully.
--*/
{
//
// check if a mode has been set
//
if (HwDeviceExtension->CurrentMode == NULL ) {
return ERROR_INVALID_FUNCTION;
}
//
// 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 (ModeInformationSize < (*OutputSize = sizeof(VIDEO_MODE_INFORMATION))) {
return ERROR_INSUFFICIENT_BUFFER;
}
//
// Store the characteristics of the current mode into the buffer.
//
ModeInformation->Length = sizeof(VIDEO_MODE_INFORMATION);
ModeInformation->ModeIndex = HwDeviceExtension->ModeIndex;
ModeInformation->VisScreenWidth = HwDeviceExtension->CurrentMode->hres;
ModeInformation->ScreenStride = HwDeviceExtension->CurrentMode->wbytes;
ModeInformation->VisScreenHeight = HwDeviceExtension->CurrentMode->vres;
ModeInformation->NumberOfPlanes = HwDeviceExtension->CurrentMode->numPlanes;
ModeInformation->BitsPerPlane = HwDeviceExtension->CurrentMode->bitsPerPlane;
ModeInformation->Frequency = HwDeviceExtension->CurrentMode->Frequency;
ModeInformation->XMillimeter = 320; // temporary hardcoded constant
ModeInformation->YMillimeter = 240; // temporary hardcoded constant
ModeInformation->AttributeFlags = HwDeviceExtension->CurrentMode->fbType;
if ((ModeInformation->BitsPerPlane == 32) ||
(ModeInformation->BitsPerPlane == 24))
{
ModeInformation->NumberRedBits = 8;
ModeInformation->NumberGreenBits = 8;
ModeInformation->NumberBlueBits = 8;
ModeInformation->RedMask = 0xff0000;
ModeInformation->GreenMask = 0x00ff00;
ModeInformation->BlueMask = 0x0000ff;
}
else if (ModeInformation->BitsPerPlane == 16)
{
ModeInformation->NumberRedBits = 6;
ModeInformation->NumberGreenBits = 6;
ModeInformation->NumberBlueBits = 6;
ModeInformation->RedMask = 0x1F << 11;
ModeInformation->GreenMask = 0x3F << 5;
ModeInformation->BlueMask = 0x1F;
}
// eVb: 2.12 [VGA] - Add support for 15bpp modes, which Cirrus doesn't support
else if (ModeInformation->BitsPerPlane == 15)
{
ModeInformation->NumberRedBits = 6;
ModeInformation->NumberGreenBits = 6;
ModeInformation->NumberBlueBits = 6;
ModeInformation->RedMask = 0x3E << 9;
ModeInformation->GreenMask = 0x1F << 5;
ModeInformation->BlueMask = 0x1F;
}
// eVb: 2.12 [END]
else
{
ModeInformation->NumberRedBits = 6;
ModeInformation->NumberGreenBits = 6;
ModeInformation->NumberBlueBits = 6;
ModeInformation->RedMask = 0;
ModeInformation->GreenMask = 0;
ModeInformation->BlueMask = 0;
}
// eVb: 2.13 [VGA] - All modes are palette managed/driven, unlike Cirrus
ModeInformation->AttributeFlags |= VIDEO_MODE_PALETTE_DRIVEN |
VIDEO_MODE_MANAGED_PALETTE;
// eVb: 2.13 [END]
return NO_ERROR;
} // end VgaQueryCurrentMode()
VOID
NTAPI
VgaZeroVideoMemory(
PHW_DEVICE_EXTENSION HwDeviceExtension
)
/*++
Routine Description:
This routine zeros the first 256K on the VGA.
Arguments:
HwDeviceExtension - Pointer to the miniport driver's device extension.
Return Value:
None.
--*/
{
UCHAR temp;
//
// Map font buffer at A0000
//
VgaInterpretCmdStream(HwDeviceExtension, EnableA000Data);
//
// Enable all planes.
//
VideoPortWritePortUchar(HwDeviceExtension->IOAddress + SEQ_ADDRESS_PORT,
IND_MAP_MASK);
temp = VideoPortReadPortUchar(HwDeviceExtension->IOAddress +
SEQ_DATA_PORT) | (UCHAR)0x0F;
VideoPortWritePortUchar(HwDeviceExtension->IOAddress + SEQ_DATA_PORT,
temp);
VideoPortZeroDeviceMemory(HwDeviceExtension->VideoMemoryAddress, 0xFFFF);
VgaInterpretCmdStream(HwDeviceExtension, DisableA000Color);
}