reactos/reactos/drivers/video/miniport/vbe/vbemp.c

996 lines
30 KiB
C
Raw Normal View History

/*
* ReactOS VBE miniport video driver
* Copyright (C) 2004 Filip Navara
*
* Power Management and VBE 1.2 support
* Copyright (C) 2004 Magnus Olsen
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* TODO:
* - Check input parameters everywhere.
* - Call VideoPortVerifyAccessRanges to reserve the memory we're about
* to map.
*/
/* INCLUDES *******************************************************************/
#include "vbemp.h"
/* PUBLIC AND PRIVATE FUNCTIONS ***********************************************/
VP_STATUS STDCALL
DriverEntry(IN PVOID Context1, IN PVOID Context2)
{
VIDEO_HW_INITIALIZATION_DATA InitData;
VideoPortZeroMemory(&InitData, sizeof(InitData));
InitData.HwInitDataSize = sizeof(VIDEO_HW_INITIALIZATION_DATA);
InitData.HwFindAdapter = VBEFindAdapter;
InitData.HwInitialize = VBEInitialize;
InitData.HwStartIO = VBEStartIO;
InitData.HwResetHw = VBEResetHw;
InitData.HwGetPowerState = VBEGetPowerState;
InitData.HwSetPowerState = VBESetPowerState;
InitData.HwDeviceExtensionSize = sizeof(VBE_DEVICE_EXTENSION);
return VideoPortInitialize(Context1, Context2, &InitData, NULL);
}
/*
* VBEFindAdapter
*
* Should detect a VBE compatible display adapter, but it's not possible
* to use video port Int 10 services at this time during initialization,
* so we always return NO_ERROR and do the real work in VBEInitialize.
*/
VP_STATUS STDCALL
VBEFindAdapter(
IN PVOID HwDeviceExtension,
IN PVOID HwContext,
IN PWSTR ArgumentString,
IN OUT PVIDEO_PORT_CONFIG_INFO ConfigInfo,
OUT PUCHAR Again)
{
return NO_ERROR;
}
/*
* VBESortModesCallback
*
* Helper function for sorting video mode list.
*/
static int
VBESortModesCallback(PVBE_MODEINFO VbeModeInfoA, PVBE_MODEINFO VbeModeInfoB)
{
DPRINT(("VBESortModesCallback: %dx%dx%d / %dx%dx%d\n",
VbeModeInfoA->XResolution, VbeModeInfoA->YResolution,
VbeModeInfoA->BitsPerPixel,
VbeModeInfoB->XResolution, VbeModeInfoB->YResolution,
VbeModeInfoB->BitsPerPixel));
/*
* FIXME: Until some reasonable method for changing video modes will
* be available we favor more bits per pixel. It should be changed
* later.
*/
if (VbeModeInfoA->BitsPerPixel < VbeModeInfoB->BitsPerPixel) return 1;
if (VbeModeInfoA->BitsPerPixel > VbeModeInfoB->BitsPerPixel) return -1;
if (VbeModeInfoA->XResolution < VbeModeInfoB->XResolution) return -1;
if (VbeModeInfoA->XResolution > VbeModeInfoB->XResolution) return 1;
if (VbeModeInfoA->YResolution < VbeModeInfoB->YResolution) return -1;
if (VbeModeInfoA->YResolution > VbeModeInfoB->YResolution) return 1;
return 0;
}
/*
* VBESortModes
*
* Simple function for sorting the video mode list. Uses bubble sort.
*/
VOID FASTCALL
VBESortModes(PVBE_DEVICE_EXTENSION DeviceExtension)
{
BOOLEAN Finished = FALSE;
ULONG Pos;
int Result;
VBE_MODEINFO TempModeInfo;
WORD TempModeNumber;
while (!Finished)
{
Finished = TRUE;
for (Pos = 0; Pos < DeviceExtension->ModeCount - 1; Pos++)
{
Result = VBESortModesCallback(
DeviceExtension->ModeInfo + Pos,
DeviceExtension->ModeInfo + Pos + 1);
if (Result > 0)
{
Finished = FALSE;
VideoPortMoveMemory(
&TempModeInfo,
DeviceExtension->ModeInfo + Pos,
sizeof(VBE_MODEINFO));
TempModeNumber = DeviceExtension->ModeNumbers[Pos];
VideoPortMoveMemory(
DeviceExtension->ModeInfo + Pos,
DeviceExtension->ModeInfo + Pos + 1,
sizeof(VBE_MODEINFO));
DeviceExtension->ModeNumbers[Pos] =
DeviceExtension->ModeNumbers[Pos + 1];
VideoPortMoveMemory(
DeviceExtension->ModeInfo + Pos + 1,
&TempModeInfo,
sizeof(VBE_MODEINFO));
DeviceExtension->ModeNumbers[Pos + 1] = TempModeNumber;
}
}
}
}
/*
* VBEInitialize
*
* Performs the first initialization of the adapter, after the HAL has given
* up control of the video hardware to the video port driver.
*
* This function performs these steps:
* - Gets global VBE information and finds if VBE BIOS is present.
* - Builds the internal mode list using the list of modes provided by
* the VBE.
*/
BOOLEAN STDCALL
VBEInitialize(PVOID HwDeviceExtension)
{
INT10_BIOS_ARGUMENTS BiosRegisters;
VP_STATUS Status;
PVBE_DEVICE_EXTENSION VBEDeviceExtension =
(PVBE_DEVICE_EXTENSION)HwDeviceExtension;
ULONG Length;
ULONG ModeCount;
ULONG SuitableModeCount;
USHORT ModeTemp;
ULONG CurrentMode;
PVBE_MODEINFO VbeModeInfo;
/*
* Get the Int 10 interface that we will use for allocating real
* mode memory and calling the video BIOS.
*/
VBEDeviceExtension->Int10Interface.Version = VIDEO_PORT_INT10_INTERFACE_VERSION_1;
VBEDeviceExtension->Int10Interface.Size = sizeof(VIDEO_PORT_INT10_INTERFACE);
Status = VideoPortQueryServices(
HwDeviceExtension,
VideoPortServicesInt10,
(PINTERFACE)&VBEDeviceExtension->Int10Interface);
if (Status != NO_ERROR)
{
DPRINT(("Failed to get Int 10 service functions (Status %x)\n", Status));
return FALSE;
}
/*
* Allocate a bit of memory that will be later used for VBE transport
* buffer. This memory must be accessible from V86 mode so it must fit
* in the first megabyte of physical memory.
*/
Length = 0x400;
Status = VBEDeviceExtension->Int10Interface.Int10AllocateBuffer(
VBEDeviceExtension->Int10Interface.Context,
&VBEDeviceExtension->TrampolineMemorySegment,
&VBEDeviceExtension->TrampolineMemoryOffset,
&Length);
if (Status != NO_ERROR)
{
DPRINT(("Failed to allocate virtual memory (Status %x)\n", Status));
return FALSE;
}
/*
* Get the VBE general information.
*/
VBEDeviceExtension->Int10Interface.Int10WriteMemory(
VBEDeviceExtension->Int10Interface.Context,
VBEDeviceExtension->TrampolineMemorySegment,
VBEDeviceExtension->TrampolineMemoryOffset,
"VBE2",
4);
VideoPortZeroMemory(&BiosRegisters, sizeof(BiosRegisters));
BiosRegisters.Eax = VBE_GET_CONTROLLER_INFORMATION;
BiosRegisters.Edi = VBEDeviceExtension->TrampolineMemoryOffset;
BiosRegisters.SegEs = VBEDeviceExtension->TrampolineMemorySegment;
VBEDeviceExtension->Int10Interface.Int10CallBios(
VBEDeviceExtension->Int10Interface.Context,
&BiosRegisters);
if (BiosRegisters.Eax == VBE_SUCCESS)
{
VBEDeviceExtension->Int10Interface.Int10ReadMemory(
VBEDeviceExtension->Int10Interface.Context,
VBEDeviceExtension->TrampolineMemorySegment,
VBEDeviceExtension->TrampolineMemoryOffset,
&VBEDeviceExtension->VbeInfo,
sizeof(VBEDeviceExtension->VbeInfo));
DPRINT(("VBE BIOS Present (%d.%d, %8ld Kb)\n",
VBEDeviceExtension->VbeInfo.Version / 0x100,
VBEDeviceExtension->VbeInfo.Version & 0xFF,
VBEDeviceExtension->VbeInfo.TotalMemory * 16));
#ifdef VBE12_SUPPORT
if (VBEDeviceExtension->VbeInfo.Version < 0x102)
#else
if (VBEDeviceExtension->VbeInfo.Version < 0x200)
#endif
{
DPRINT(("VBE BIOS present, but incompatible version.\n"));
return FALSE;
}
}
else
{
DPRINT(("No VBE BIOS found.\n"));
return FALSE;
}
/*
* Build a mode list here that can be later used by
* IOCTL_VIDEO_QUERY_NUM_AVAIL_MODES and IOCTL_VIDEO_QUERY_AVAIL_MODES
* calls.
*/
/*
* Get the number of supported video modes.
*
* No need to be map the memory. It's either in the video BIOS memory or
* in our trampoline memory. In either case the memory is already mapped.
*/
for (ModeCount = 0; ; ModeCount++)
{
/* Read the VBE mode number. */
VBEDeviceExtension->Int10Interface.Int10ReadMemory(
VBEDeviceExtension->Int10Interface.Context,
HIWORD(VBEDeviceExtension->VbeInfo.VideoModePtr),
LOWORD(VBEDeviceExtension->VbeInfo.VideoModePtr) + (ModeCount << 1),
&ModeTemp,
sizeof(ModeTemp));
/* End of list? */
if (ModeTemp == 0xFFFF || ModeTemp == 0)
break;
}
/*
* Allocate space for video modes information.
*/
VBEDeviceExtension->ModeInfo =
ExAllocatePool(PagedPool, ModeCount * sizeof(VBE_MODEINFO));
VBEDeviceExtension->ModeNumbers =
ExAllocatePool(PagedPool, ModeCount * sizeof(WORD));
/*
* Get the actual mode infos.
*/
for (CurrentMode = 0, SuitableModeCount = 0;
CurrentMode < ModeCount;
CurrentMode++)
{
/* Read the VBE mode number. */
VBEDeviceExtension->Int10Interface.Int10ReadMemory(
VBEDeviceExtension->Int10Interface.Context,
HIWORD(VBEDeviceExtension->VbeInfo.VideoModePtr),
LOWORD(VBEDeviceExtension->VbeInfo.VideoModePtr) + (CurrentMode << 1),
&ModeTemp,
sizeof(ModeTemp));
/* Call VBE BIOS to read the mode info. */
VideoPortZeroMemory(&BiosRegisters, sizeof(BiosRegisters));
BiosRegisters.Eax = VBE_GET_MODE_INFORMATION;
BiosRegisters.Ecx = ModeTemp;
BiosRegisters.Edi = VBEDeviceExtension->TrampolineMemoryOffset + 0x200;
BiosRegisters.SegEs = VBEDeviceExtension->TrampolineMemorySegment;
VBEDeviceExtension->Int10Interface.Int10CallBios(
VBEDeviceExtension->Int10Interface.Context,
&BiosRegisters);
/* Read the VBE mode info. */
VBEDeviceExtension->Int10Interface.Int10ReadMemory(
VBEDeviceExtension->Int10Interface.Context,
VBEDeviceExtension->TrampolineMemorySegment,
VBEDeviceExtension->TrampolineMemoryOffset + 0x200,
VBEDeviceExtension->ModeInfo + SuitableModeCount,
sizeof(VBE_MODEINFO));
VbeModeInfo = VBEDeviceExtension->ModeInfo + SuitableModeCount;
/* Is this mode acceptable? */
if (BiosRegisters.Eax == VBE_SUCCESS &&
VbeModeInfo->XResolution >= 640 &&
VbeModeInfo->YResolution >= 480 &&
(VbeModeInfo->MemoryModel == VBE_MEMORYMODEL_PACKEDPIXEL ||
VbeModeInfo->MemoryModel == VBE_MEMORYMODEL_DIRECTCOLOR))
{
if (VbeModeInfo->ModeAttributes & VBE_MODEATTR_LINEAR)
{
VBEDeviceExtension->ModeNumbers[SuitableModeCount] = ModeTemp | 0x4000;
SuitableModeCount++;
}
#ifdef VBE12_SUPPORT
else
{
VBEDeviceExtension->ModeNumbers[SuitableModeCount] = ModeTemp;
SuitableModeCount++;
}
#endif
}
}
if (SuitableModeCount == 0)
{
DPRINT(("VBEMP: No video modes supported\n"));
return FALSE;
}
VBEDeviceExtension->ModeCount = SuitableModeCount;
/*
* Sort the video mode list according to resolution and bits per pixel.
*/
VBESortModes(VBEDeviceExtension);
/*
* Print the supported video modes when DBG is set.
*/
#ifdef DBG
for (CurrentMode = 0;
CurrentMode < SuitableModeCount;
CurrentMode++)
{
DPRINT(("%dx%dx%d\n",
VBEDeviceExtension->ModeInfo[CurrentMode].XResolution,
VBEDeviceExtension->ModeInfo[CurrentMode].YResolution,
VBEDeviceExtension->ModeInfo[CurrentMode].BitsPerPixel));
}
#endif
return TRUE;
}
/*
* VBEStartIO
*
* Processes the specified Video Request Packet.
*/
BOOLEAN STDCALL
VBEStartIO(
PVOID HwDeviceExtension,
PVIDEO_REQUEST_PACKET RequestPacket)
{
BOOL Result;
RequestPacket->StatusBlock->Status = STATUS_UNSUCCESSFUL;
switch (RequestPacket->IoControlCode)
{
case IOCTL_VIDEO_SET_CURRENT_MODE:
if (RequestPacket->InputBufferLength < sizeof(VIDEO_MODE))
{
RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
return TRUE;
}
Result = VBESetCurrentMode(
(PVBE_DEVICE_EXTENSION)HwDeviceExtension,
(PVIDEO_MODE)RequestPacket->InputBuffer,
RequestPacket->StatusBlock);
break;
case IOCTL_VIDEO_RESET_DEVICE:
Result = VBEResetDevice(
(PVBE_DEVICE_EXTENSION)HwDeviceExtension,
RequestPacket->StatusBlock);
break;
case IOCTL_VIDEO_MAP_VIDEO_MEMORY:
if (RequestPacket->OutputBufferLength < sizeof(VIDEO_MEMORY_INFORMATION) ||
RequestPacket->InputBufferLength < sizeof(VIDEO_MEMORY))
{
RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
return TRUE;
}
Result = VBEMapVideoMemory(
(PVBE_DEVICE_EXTENSION)HwDeviceExtension,
(PVIDEO_MEMORY)RequestPacket->InputBuffer,
(PVIDEO_MEMORY_INFORMATION)RequestPacket->OutputBuffer,
RequestPacket->StatusBlock);
break;
case IOCTL_VIDEO_UNMAP_VIDEO_MEMORY:
if (RequestPacket->InputBufferLength < sizeof(VIDEO_MEMORY))
{
RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
return TRUE;
}
Result = VBEUnmapVideoMemory(
(PVBE_DEVICE_EXTENSION)HwDeviceExtension,
(PVIDEO_MEMORY)RequestPacket->InputBuffer,
RequestPacket->StatusBlock);
break;
case IOCTL_VIDEO_QUERY_NUM_AVAIL_MODES:
if (RequestPacket->OutputBufferLength < sizeof(VIDEO_NUM_MODES))
{
RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
return TRUE;
}
Result = VBEQueryNumAvailModes(
(PVBE_DEVICE_EXTENSION)HwDeviceExtension,
(PVIDEO_NUM_MODES)RequestPacket->OutputBuffer,
RequestPacket->StatusBlock);
break;
case IOCTL_VIDEO_QUERY_AVAIL_MODES:
if (RequestPacket->OutputBufferLength <
((PVBE_DEVICE_EXTENSION)HwDeviceExtension)->ModeCount * sizeof(VIDEO_MODE_INFORMATION))
{
RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
return TRUE;
}
Result = VBEQueryAvailModes(
(PVBE_DEVICE_EXTENSION)HwDeviceExtension,
(PVIDEO_MODE_INFORMATION)RequestPacket->OutputBuffer,
RequestPacket->StatusBlock);
break;
case IOCTL_VIDEO_SET_COLOR_REGISTERS:
if (RequestPacket->InputBufferLength < sizeof(VIDEO_CLUT) ||
RequestPacket->InputBufferLength <
(((PVIDEO_CLUT)RequestPacket->InputBuffer)->NumEntries * sizeof(ULONG)) +
sizeof(VIDEO_CLUT))
{
RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
return TRUE;
}
Result = VBESetColorRegisters(
(PVBE_DEVICE_EXTENSION)HwDeviceExtension,
(PVIDEO_CLUT)RequestPacket->InputBuffer,
RequestPacket->StatusBlock);
break;
case IOCTL_VIDEO_QUERY_CURRENT_MODE:
if (RequestPacket->OutputBufferLength < sizeof(VIDEO_MODE_INFORMATION))
{
RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
return TRUE;
}
Result = VBEQueryCurrentMode(
(PVBE_DEVICE_EXTENSION)HwDeviceExtension,
(PVIDEO_MODE_INFORMATION)RequestPacket->OutputBuffer,
RequestPacket->StatusBlock);
break;
default:
RequestPacket->StatusBlock->Status = STATUS_NOT_IMPLEMENTED;
return FALSE;
}
if (Result)
RequestPacket->StatusBlock->Status = STATUS_SUCCESS;
return TRUE;
}
/*
* VBEResetHw
*
* This function is called to reset the hardware to a known state.
*/
BOOLEAN STDCALL
VBEResetHw(
PVOID DeviceExtension,
ULONG Columns,
ULONG Rows)
{
return VBEResetDevice(DeviceExtension, NULL);
}
/*
* VBEGetPowerState
*
* Queries whether the device can support the requested power state.
*/
VP_STATUS STDCALL
VBEGetPowerState(
PVOID HwDeviceExtension,
ULONG HwId,
PVIDEO_POWER_MANAGEMENT VideoPowerControl)
{
INT10_BIOS_ARGUMENTS BiosRegisters;
PVBE_DEVICE_EXTENSION VBEDeviceExtension =
(PVBE_DEVICE_EXTENSION)HwDeviceExtension;
if (HwId != DISPLAY_ADAPTER_HW_ID ||
VideoPowerControl->Length < sizeof(VIDEO_POWER_MANAGEMENT))
return ERROR_INVALID_FUNCTION;
/*
* Get general power support information.
*/
VideoPortZeroMemory(&BiosRegisters, sizeof(BiosRegisters));
BiosRegisters.Eax = VBE_POWER_MANAGEMENT_EXTENSIONS;
BiosRegisters.Ebx = 0;
BiosRegisters.Edi = 0;
BiosRegisters.SegEs = 0;
VBEDeviceExtension->Int10Interface.Int10CallBios(
VBEDeviceExtension->Int10Interface.Context,
&BiosRegisters);
if (BiosRegisters.Eax == VBE_NOT_SUPPORTED)
return ERROR_NOT_SUPPORTED;
if (BiosRegisters.Eax != VBE_SUCCESS)
return ERROR_INVALID_FUNCTION;
/*
* Get current power state.
*/
VideoPortZeroMemory(&BiosRegisters, sizeof(BiosRegisters));
BiosRegisters.Eax = VBE_POWER_MANAGEMENT_EXTENSIONS;
BiosRegisters.Ebx = 0x2;
BiosRegisters.Edi = 0;
BiosRegisters.SegEs = 0;
VBEDeviceExtension->Int10Interface.Int10CallBios(
VBEDeviceExtension->Int10Interface.Context,
&BiosRegisters);
if (BiosRegisters.Eax == VBE_SUCCESS)
{
VideoPowerControl->DPMSVersion = BiosRegisters.Ebx & 0xFF;
switch (BiosRegisters.Ebx >> 8)
{
case 0: VideoPowerControl->PowerState = VideoPowerOn; break;
case 1: VideoPowerControl->PowerState = VideoPowerStandBy; break;
case 2: VideoPowerControl->PowerState = VideoPowerSuspend; break;
case 4: VideoPowerControl->PowerState = VideoPowerOff; break;
case 5: VideoPowerControl->PowerState = VideoPowerOn; break;
default: VideoPowerControl->PowerState = VideoPowerUnspecified;
}
return NO_ERROR;
}
return ERROR_NOT_SUPPORTED;
}
/*
* VBESetPowerState
*
* Sets the power state of the specified device
*/
VP_STATUS STDCALL
VBESetPowerState(
PVOID HwDeviceExtension,
ULONG HwId,
PVIDEO_POWER_MANAGEMENT VideoPowerControl)
{
INT10_BIOS_ARGUMENTS BiosRegisters;
PVBE_DEVICE_EXTENSION VBEDeviceExtension =
(PVBE_DEVICE_EXTENSION)HwDeviceExtension;
if (HwId != DISPLAY_ADAPTER_HW_ID ||
VideoPowerControl->Length < sizeof(VIDEO_POWER_MANAGEMENT) ||
VideoPowerControl->PowerState < VideoPowerOn ||
VideoPowerControl->PowerState > VideoPowerHibernate)
return ERROR_INVALID_FUNCTION;
if (VideoPowerControl->PowerState == VideoPowerHibernate)
return NO_ERROR;
/*
* Set current power state.
*/
VideoPortZeroMemory(&BiosRegisters, sizeof(BiosRegisters));
BiosRegisters.Eax = VBE_POWER_MANAGEMENT_EXTENSIONS;
BiosRegisters.Ebx = 1;
BiosRegisters.Edi = 0;
BiosRegisters.SegEs = 0;
switch (VideoPowerControl->PowerState)
{
case VideoPowerStandBy: BiosRegisters.Ebx |= 0x100; break;
case VideoPowerSuspend: BiosRegisters.Ebx |= 0x200; break;
case VideoPowerOff: BiosRegisters.Ebx |= 0x400; break;
}
VBEDeviceExtension->Int10Interface.Int10CallBios(
VBEDeviceExtension->Int10Interface.Context,
&BiosRegisters);
if (BiosRegisters.Eax == VBE_NOT_SUPPORTED)
return ERROR_NOT_SUPPORTED;
if (BiosRegisters.Eax != VBE_SUCCESS)
return ERROR_INVALID_FUNCTION;
return VBE_SUCCESS;
}
/*
* VBESetCurrentMode
*
* Sets the adapter to the specified operating mode.
*/
BOOL FASTCALL
VBESetCurrentMode(
PVBE_DEVICE_EXTENSION DeviceExtension,
PVIDEO_MODE RequestedMode,
PSTATUS_BLOCK StatusBlock)
{
INT10_BIOS_ARGUMENTS BiosRegisters;
if (RequestedMode->RequestedMode >= DeviceExtension->ModeCount)
{
return ERROR_INVALID_PARAMETER;
}
VideoPortZeroMemory(&BiosRegisters, sizeof(BiosRegisters));
BiosRegisters.Eax = VBE_SET_VBE_MODE;
BiosRegisters.Ebx = DeviceExtension->ModeNumbers[RequestedMode->RequestedMode];
DeviceExtension->Int10Interface.Int10CallBios(
DeviceExtension->Int10Interface.Context,
&BiosRegisters);
if (BiosRegisters.Eax == VBE_SUCCESS)
{
DeviceExtension->CurrentMode = RequestedMode->RequestedMode;
}
else
{
DPRINT(("VBEMP: VBESetCurrentMode failed (%x)\n", BiosRegisters.Eax));
DeviceExtension->CurrentMode = -1;
}
return BiosRegisters.Eax == VBE_SUCCESS;
}
/*
* VBEResetDevice
*
* Resets the video hardware to the default mode, to which it was initialized
* at system boot.
*/
BOOL FASTCALL
VBEResetDevice(
PVBE_DEVICE_EXTENSION DeviceExtension,
PSTATUS_BLOCK StatusBlock)
{
INT10_BIOS_ARGUMENTS BiosRegisters;
VideoPortZeroMemory(&BiosRegisters, sizeof(BiosRegisters));
BiosRegisters.Eax = VBE_SET_VBE_MODE;
BiosRegisters.Ebx = 0x3;
DeviceExtension->Int10Interface.Int10CallBios(
DeviceExtension->Int10Interface.Context,
&BiosRegisters);
return BiosRegisters.Eax == VBE_SUCCESS;
}
/*
* VBEMapVideoMemory
*
* Maps the video hardware frame buffer and video RAM into the virtual address
* space of the requestor.
*/
BOOL FASTCALL
VBEMapVideoMemory(
PVBE_DEVICE_EXTENSION DeviceExtension,
PVIDEO_MEMORY RequestedAddress,
PVIDEO_MEMORY_INFORMATION MapInformation,
PSTATUS_BLOCK StatusBlock)
{
PHYSICAL_ADDRESS FrameBuffer;
ULONG inIoSpace = VIDEO_MEMORY_SPACE_MEMORY;
StatusBlock->Information = sizeof(VIDEO_MEMORY_INFORMATION);
if (DeviceExtension->ModeInfo[DeviceExtension->CurrentMode].ModeAttributes &
VBE_MODEATTR_LINEAR)
{
FrameBuffer.QuadPart =
DeviceExtension->ModeInfo[DeviceExtension->CurrentMode].PhysBasePtr;
MapInformation->VideoRamBase = RequestedAddress->RequestedVirtualAddress;
MapInformation->VideoRamLength =
DeviceExtension->ModeInfo[DeviceExtension->CurrentMode].BytesPerScanLine *
DeviceExtension->ModeInfo[DeviceExtension->CurrentMode].YResolution;
}
#ifdef VBE12_SUPPORT
else
{
FrameBuffer.QuadPart = 0xA0000;
MapInformation->VideoRamBase = RequestedAddress->RequestedVirtualAddress;
MapInformation->VideoRamLength = 0x10000;
}
#endif
VideoPortMapMemory(DeviceExtension, FrameBuffer,
&MapInformation->VideoRamLength, &inIoSpace,
&MapInformation->VideoRamBase);
MapInformation->FrameBufferBase = MapInformation->VideoRamBase;
MapInformation->FrameBufferLength = MapInformation->VideoRamLength;
return TRUE;
}
/*
* VBEUnmapVideoMemory
*
* Releases a mapping between the virtual address space and the adapter's
* frame buffer and video RAM.
*/
BOOL FASTCALL
VBEUnmapVideoMemory(
PVBE_DEVICE_EXTENSION DeviceExtension,
PVIDEO_MEMORY VideoMemory,
PSTATUS_BLOCK StatusBlock)
{
VideoPortUnmapMemory(DeviceExtension, VideoMemory->RequestedVirtualAddress,
NULL);
return TRUE;
}
/*
* VBEQueryNumAvailModes
*
* Returns the number of video modes supported by the adapter and the size
* in bytes of the video mode information, which can be used to allocate a
* buffer for an IOCTL_VIDEO_QUERY_AVAIL_MODES request.
*/
BOOL FASTCALL
VBEQueryNumAvailModes(
PVBE_DEVICE_EXTENSION DeviceExtension,
PVIDEO_NUM_MODES Modes,
PSTATUS_BLOCK StatusBlock)
{
Modes->NumModes = DeviceExtension->ModeCount;
Modes->ModeInformationLength = sizeof(VIDEO_MODE_INFORMATION);
StatusBlock->Information = sizeof(VIDEO_NUM_MODES);
return TRUE;
}
/*
* VBEQueryMode
*
* Returns information about one particular video mode.
*/
VOID FASTCALL
VBEQueryMode(
PVBE_DEVICE_EXTENSION DeviceExtension,
PVIDEO_MODE_INFORMATION VideoMode,
ULONG VideoModeId)
{
PVBE_MODEINFO VBEMode = &DeviceExtension->ModeInfo[VideoModeId];
VideoMode->Length = sizeof(VIDEO_MODE_INFORMATION);
VideoMode->ModeIndex = VideoModeId;
VideoMode->VisScreenWidth = VBEMode->XResolution;
VideoMode->VisScreenHeight = VBEMode->YResolution;
VideoMode->ScreenStride = VBEMode->BytesPerScanLine;
VideoMode->NumberOfPlanes = VBEMode->NumberOfPlanes;
VideoMode->BitsPerPlane = VBEMode->BitsPerPixel / VBEMode->NumberOfPlanes;
VideoMode->Frequency = 0; /* FIXME */
VideoMode->XMillimeter = 0; /* FIXME */
VideoMode->YMillimeter = 0; /* FIXME */
if (VBEMode->BitsPerPixel > 8)
{
if (DeviceExtension->VbeInfo.Version < 0x300)
{
VideoMode->NumberRedBits = VBEMode->RedMaskSize;
VideoMode->NumberGreenBits = VBEMode->GreenMaskSize;
VideoMode->NumberBlueBits = VBEMode->BlueMaskSize;
VideoMode->RedMask = ((1 << VBEMode->RedMaskSize) - 1) << VBEMode->RedFieldPosition;
VideoMode->GreenMask = ((1 << VBEMode->GreenMaskSize) - 1) << VBEMode->GreenFieldPosition;
VideoMode->BlueMask = ((1 << VBEMode->BlueMaskSize) - 1) << VBEMode->BlueFieldPosition;
}
else
{
VideoMode->NumberRedBits = VBEMode->LinRedMaskSize;
VideoMode->NumberGreenBits = VBEMode->LinGreenMaskSize;
VideoMode->NumberBlueBits = VBEMode->LinBlueMaskSize;
VideoMode->RedMask = ((1 << VBEMode->LinRedMaskSize) - 1) << VBEMode->LinRedFieldPosition;
VideoMode->GreenMask = ((1 << VBEMode->LinGreenMaskSize) - 1) << VBEMode->LinGreenFieldPosition;
VideoMode->BlueMask = ((1 << VBEMode->LinBlueMaskSize) - 1) << VBEMode->LinBlueFieldPosition;
}
}
else
{
VideoMode->NumberRedBits =
VideoMode->NumberGreenBits =
VideoMode->NumberBlueBits = 6;
VideoMode->RedMask =
VideoMode->GreenMask =
VideoMode->BlueMask = 0;
}
VideoMode->VideoMemoryBitmapWidth = VBEMode->XResolution;
VideoMode->VideoMemoryBitmapHeight = VBEMode->YResolution;
VideoMode->AttributeFlags = VIDEO_MODE_GRAPHICS | VIDEO_MODE_COLOR |
VIDEO_MODE_NO_OFF_SCREEN;
if (VideoMode->BitsPerPlane <= 8)
VideoMode->AttributeFlags |= VIDEO_MODE_PALETTE_DRIVEN;
VideoMode->DriverSpecificAttributeFlags = 0;
}
/*
* VBEQueryAvailModes
*
* Returns information about each video mode supported by the adapter.
*/
BOOL FASTCALL
VBEQueryAvailModes(
PVBE_DEVICE_EXTENSION DeviceExtension,
PVIDEO_MODE_INFORMATION ReturnedModes,
PSTATUS_BLOCK StatusBlock)
{
ULONG CurrentModeId;
PVIDEO_MODE_INFORMATION CurrentMode;
PVBE_MODEINFO CurrentVBEMode;
for (CurrentModeId = 0, CurrentMode = ReturnedModes,
CurrentVBEMode = DeviceExtension->ModeInfo;
CurrentModeId < DeviceExtension->ModeCount;
CurrentModeId++, CurrentMode++, CurrentVBEMode++)
{
VBEQueryMode(DeviceExtension, CurrentMode, CurrentModeId);
}
StatusBlock->Information =
sizeof(VIDEO_MODE_INFORMATION) * DeviceExtension->ModeCount;
return TRUE;
}
/*
* VBEQueryCurrentMode
*
* Returns information about current video mode.
*/
BOOL FASTCALL
VBEQueryCurrentMode(
PVBE_DEVICE_EXTENSION DeviceExtension,
PVIDEO_MODE_INFORMATION VideoModeInfo,
PSTATUS_BLOCK StatusBlock)
{
StatusBlock->Information = sizeof(VIDEO_MODE_INFORMATION);
VBEQueryMode(
DeviceExtension,
VideoModeInfo,
DeviceExtension->CurrentMode);
return TRUE;
}
/*
* VBESetColorRegisters
*
* Sets the adapter's color registers to the specified RGB values. There
* are code paths in this function, one generic and one for VGA compatible
* controllers. The latter is needed for Bochs, where the generic one isn't
* yet implemented.
*/
BOOL FASTCALL
VBESetColorRegisters(
PVBE_DEVICE_EXTENSION DeviceExtension,
PVIDEO_CLUT ColorLookUpTable,
PSTATUS_BLOCK StatusBlock)
{
INT10_BIOS_ARGUMENTS BiosRegisters;
ULONG Entry;
PULONG OutputEntry;
ULONG OutputBuffer[256];
if (ColorLookUpTable->NumEntries + ColorLookUpTable->FirstEntry > 256)
return FALSE;
/*
* For VGA compatible adapters program the color registers directly.
*/
if (!(DeviceExtension->VbeInfo.Capabilities & 2))
{
for (Entry = ColorLookUpTable->FirstEntry;
Entry < ColorLookUpTable->NumEntries + ColorLookUpTable->FirstEntry;
Entry++)
{
VideoPortWritePortUchar((PUCHAR)0x03c8, Entry);
VideoPortWritePortUchar((PUCHAR)0x03c9, ColorLookUpTable->LookupTable[Entry].RgbArray.Red);
VideoPortWritePortUchar((PUCHAR)0x03c9, ColorLookUpTable->LookupTable[Entry].RgbArray.Green);
VideoPortWritePortUchar((PUCHAR)0x03c9, ColorLookUpTable->LookupTable[Entry].RgbArray.Blue);
}
return TRUE;
}
else
{
/*
* We can't just copy the values, because we need to swap the Red
* and Blue values.
*/
for (Entry = ColorLookUpTable->FirstEntry,
OutputEntry = OutputBuffer;
Entry < ColorLookUpTable->NumEntries + ColorLookUpTable->FirstEntry;
Entry++, OutputEntry++)
{
*OutputEntry =
(ColorLookUpTable->LookupTable[Entry].RgbArray.Red << 16) |
(ColorLookUpTable->LookupTable[Entry].RgbArray.Green << 8) |
(ColorLookUpTable->LookupTable[Entry].RgbArray.Blue);
}
DeviceExtension->Int10Interface.Int10WriteMemory(
DeviceExtension->Int10Interface.Context,
DeviceExtension->TrampolineMemorySegment,
DeviceExtension->TrampolineMemoryOffset,
OutputBuffer,
(OutputEntry - OutputBuffer) * sizeof(ULONG));
VideoPortZeroMemory(&BiosRegisters, sizeof(BiosRegisters));
BiosRegisters.Eax = VBE_SET_GET_PALETTE_DATA;
BiosRegisters.Ebx = 0;
BiosRegisters.Ecx = ColorLookUpTable->NumEntries;
BiosRegisters.Edx = ColorLookUpTable->FirstEntry;
BiosRegisters.Edi = DeviceExtension->TrampolineMemoryOffset;
BiosRegisters.SegEs = DeviceExtension->TrampolineMemorySegment;
DeviceExtension->Int10Interface.Int10CallBios(
DeviceExtension->Int10Interface.Context,
&BiosRegisters);
return BiosRegisters.Eax == VBE_SUCCESS;
}
}