mirror of
https://github.com/reactos/reactos.git
synced 2024-11-10 16:48:16 +00:00
c424146e2c
svn path=/branches/cmake-bringup/; revision=48236
449 lines
19 KiB
C
449 lines
19 KiB
C
/*
|
|
* PROJECT: ReactOS VGA Miniport Driver
|
|
* LICENSE: BSD - See COPYING.ARM in the top level directory
|
|
* FILE: boot/drivers/video/miniport/vga/vbemodes.c
|
|
* PURPOSE: Mode Initialization and Mode Set for VBE-compatible cards
|
|
* PROGRAMMERS: ReactOS Portable Systems Group
|
|
*/
|
|
|
|
/* INCLUDES *******************************************************************/
|
|
|
|
#include "vga.h"
|
|
|
|
/* FUNCTIONS ******************************************************************/
|
|
|
|
ULONG
|
|
NTAPI
|
|
RaiseToPower2Ulong(IN ULONG Value)
|
|
{
|
|
ULONG SquaredResult = Value;
|
|
if ((Value - 1) & Value) for (SquaredResult = 1; (SquaredResult < Value) && (SquaredResult); SquaredResult *= 2);
|
|
return SquaredResult;
|
|
}
|
|
|
|
ULONG
|
|
NTAPI
|
|
RaiseToPower2(IN USHORT Value)
|
|
{
|
|
ULONG SquaredResult = Value;
|
|
if ((Value - 1) & Value) for (SquaredResult = 1; (SquaredResult < Value) && (SquaredResult); SquaredResult *= 2);
|
|
return SquaredResult;
|
|
}
|
|
|
|
ULONG
|
|
NTAPI
|
|
VbeGetVideoMemoryBaseAddress(IN PHW_DEVICE_EXTENSION VgaExtension,
|
|
IN PVIDEOMODE VgaMode)
|
|
{
|
|
ULONG Length = 4 * 1024;
|
|
USHORT TrampolineMemorySegment, TrampolineMemoryOffset;
|
|
PVOID Context;
|
|
INT10_BIOS_ARGUMENTS BiosArguments;
|
|
PVBE_MODE_INFO VbeModeInfo;
|
|
ULONG BaseAddress;
|
|
VP_STATUS Status;
|
|
|
|
/* Need linear and INT10 interface */
|
|
if (!(VgaMode->fbType & VIDEO_MODE_BANKED)) return 0;
|
|
if (VgaExtension->Int10Interface.Size) return 0;
|
|
|
|
/* Allocate scratch area and context */
|
|
VbeModeInfo = VideoPortAllocatePool(VgaExtension, 1, sizeof(VBE_MODE_INFO), ' agV');
|
|
if (!VbeModeInfo) return 0;
|
|
Context = VgaExtension->Int10Interface.Context;
|
|
Status = VgaExtension->Int10Interface.Int10AllocateBuffer(Context,
|
|
&TrampolineMemorySegment,
|
|
&TrampolineMemoryOffset,
|
|
&Length);
|
|
if (Status != NO_ERROR) return 0;
|
|
|
|
/* Ask VBE BIOS for mode info */
|
|
BiosArguments.Ecx = HIWORD(VgaMode->Mode);
|
|
BiosArguments.Edi = TrampolineMemorySegment;
|
|
BiosArguments.SegEs = TrampolineMemoryOffset;
|
|
BiosArguments.Eax = VBE_GET_MODE_INFORMATION;
|
|
Status = VgaExtension->Int10Interface.Int10CallBios(Context, &BiosArguments);
|
|
if (Status != NO_ERROR) return 0;
|
|
if (BiosArguments.Eax != VBE_SUCCESS) return 0;
|
|
Status = VgaExtension->Int10Interface.Int10ReadMemory(Context,
|
|
TrampolineMemorySegment,
|
|
TrampolineMemoryOffset,
|
|
VbeModeInfo,
|
|
sizeof(VBE_MODE_INFO));
|
|
if (Status != NO_ERROR) return 0;
|
|
|
|
/* Return phys address and cleanup */
|
|
BaseAddress = VbeModeInfo->PhysBasePtr;
|
|
VgaExtension->Int10Interface.Int10FreeBuffer(Context,
|
|
TrampolineMemorySegment,
|
|
TrampolineMemoryOffset);
|
|
VideoPortFreePool(VgaExtension, VbeModeInfo);
|
|
return BaseAddress;
|
|
}
|
|
|
|
VP_STATUS
|
|
NTAPI
|
|
VbeSetMode(IN PHW_DEVICE_EXTENSION VgaDeviceExtension,
|
|
IN PVIDEOMODE VgaMode,
|
|
OUT PULONG PhysPtrChange)
|
|
{
|
|
VP_STATUS Status;
|
|
VIDEO_X86_BIOS_ARGUMENTS BiosArguments;
|
|
ULONG ModeIndex;
|
|
ULONG BaseAddress;
|
|
|
|
VideoPortZeroMemory(&BiosArguments, sizeof(BiosArguments));
|
|
ModeIndex = VgaMode->Mode;
|
|
BiosArguments.Eax = ModeIndex & 0x0000FFFF;
|
|
BiosArguments.Ebx = ModeIndex >> 16;
|
|
VideoPortDebugPrint(0, "Switching to %lx %lx\n", BiosArguments.Eax, BiosArguments.Ebx);
|
|
Status = VideoPortInt10(VgaDeviceExtension, &BiosArguments);
|
|
if (Status != NO_ERROR) return Status;
|
|
|
|
/* Check for VESA mode */
|
|
if (ModeIndex >> 16)
|
|
{
|
|
/* Mode set fail */
|
|
if (BiosArguments.Eax != VBE_SUCCESS) return ERROR_INVALID_PARAMETER;
|
|
|
|
/* Check current mode is desired mode */
|
|
BiosArguments.Eax = VBE_GET_CURRENT_VBE_MODE;
|
|
Status = VideoPortInt10(VgaDeviceExtension, &BiosArguments);
|
|
if ((Status == NO_ERROR) &&
|
|
(BiosArguments.Eax == VBE_SUCCESS) &&
|
|
((BiosArguments.Ebx ^ (ModeIndex >> 16)) & VBE_MODE_BITS))
|
|
{
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
/* Set logical scanline width if different from physical */
|
|
if (VgaMode->LogicalWidth != VgaMode->hres)
|
|
{
|
|
/* Check setting works after being set */
|
|
BiosArguments.Eax = VBE_SET_GET_LOGICAL_SCAN_LINE_LENGTH;
|
|
BiosArguments.Ecx = VgaMode->LogicalWidth;
|
|
BiosArguments.Ebx = 0;
|
|
Status = VideoPortInt10(VgaDeviceExtension, &BiosArguments);
|
|
if ((Status != NO_ERROR) ||
|
|
(BiosArguments.Eax != VBE_SUCCESS) ||
|
|
(BiosArguments.Ecx != VgaMode->LogicalWidth))
|
|
{
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Get VRAM address to update changes */
|
|
BaseAddress = VbeGetVideoMemoryBaseAddress(VgaDeviceExtension, VgaMode);
|
|
if ((BaseAddress) && (VgaMode->PhysBase != BaseAddress))
|
|
{
|
|
*PhysPtrChange = TRUE;
|
|
VgaMode->PhysBase = BaseAddress;
|
|
}
|
|
|
|
return NO_ERROR;
|
|
}
|
|
|
|
VOID
|
|
NTAPI
|
|
InitializeModeTable(IN PHW_DEVICE_EXTENSION VgaExtension)
|
|
{
|
|
ULONG ModeCount = 0;
|
|
ULONG Length = 4 * 1024;
|
|
ULONG TotalMemory;
|
|
VP_STATUS Status;
|
|
INT10_BIOS_ARGUMENTS BiosArguments;
|
|
PVBE_INFO VbeInfo;
|
|
PVBE_MODE_INFO VbeModeInfo;
|
|
PVOID Context;
|
|
USHORT TrampolineMemorySegment;
|
|
USHORT TrampolineMemoryOffset;
|
|
ULONG VbeVersion;
|
|
ULONG NewModes = 0;
|
|
BOOLEAN FourBppModeFound = FALSE;
|
|
USHORT ModeResult;
|
|
USHORT Mode;
|
|
PUSHORT ThisMode;
|
|
BOOLEAN LinearAddressing;
|
|
ULONG Size, ScreenSize;
|
|
PVIDEOMODE VgaMode;
|
|
PVOID BaseAddress;
|
|
ULONG ScreenStride = 0;
|
|
PHYSICAL_ADDRESS PhysicalAddress;
|
|
|
|
/* Enable only default vga modes if no vesa */
|
|
VgaModeList = ModesVGA;
|
|
if (VideoPortIsNoVesa())
|
|
{
|
|
VgaExtension->Int10Interface.Size = 0;
|
|
VgaExtension->Int10Interface.Version = 0;
|
|
return;
|
|
}
|
|
|
|
/* Query INT10 interface */
|
|
VgaExtension->Int10Interface.Version = VIDEO_PORT_INT10_INTERFACE_VERSION_1;
|
|
VgaExtension->Int10Interface.Size = sizeof(VIDEO_PORT_INT10_INTERFACE);
|
|
if (VideoPortQueryServices(VgaExtension,
|
|
VideoPortServicesInt10,
|
|
(PINTERFACE)&VgaExtension->Int10Interface))
|
|
{
|
|
VgaExtension->Int10Interface.Size = 0;
|
|
VgaExtension->Int10Interface.Version = 0;
|
|
}
|
|
|
|
/* Add ref */
|
|
//VideoPortDebugPrint(0, "have int10 iface\n");
|
|
VgaExtension->Int10Interface.InterfaceReference(VgaExtension->Int10Interface.Context);
|
|
Context = VgaExtension->Int10Interface.Context;
|
|
|
|
/* Allocate scratch area and context */
|
|
Status = VgaExtension->Int10Interface.Int10AllocateBuffer(Context,
|
|
&TrampolineMemorySegment,
|
|
&TrampolineMemoryOffset,
|
|
&Length);
|
|
if (Status != NO_ERROR) return;
|
|
VbeInfo = VideoPortAllocatePool(VgaExtension, 1, sizeof(VBE_INFO), ' agV');
|
|
VbeModeInfo = &VbeInfo->Modes;
|
|
if (!VbeInfo) return;
|
|
|
|
/* Init VBE data and write to card buffer */
|
|
//VideoPortDebugPrint(0, "have int10 data\n");
|
|
VbeInfo->ModeArray[128] = 0xFFFF;
|
|
strcpy(VbeInfo->Info.Signature, "VBE2");
|
|
Status = VgaExtension->Int10Interface.Int10WriteMemory(Context,
|
|
TrampolineMemorySegment,
|
|
TrampolineMemoryOffset,
|
|
VbeInfo,
|
|
512);
|
|
if (Status != NO_ERROR) return;
|
|
|
|
/* Get controller info */
|
|
BiosArguments.Edi = TrampolineMemoryOffset;
|
|
BiosArguments.SegEs = TrampolineMemorySegment;
|
|
BiosArguments.Eax = VBE_GET_CONTROLLER_INFORMATION;
|
|
Status = VgaExtension->Int10Interface.Int10CallBios(Context, &BiosArguments);
|
|
if (Status != NO_ERROR) return;
|
|
if (BiosArguments.Eax != VBE_SUCCESS) return;
|
|
Status = VgaExtension->Int10Interface.Int10ReadMemory(Context,
|
|
TrampolineMemorySegment,
|
|
TrampolineMemoryOffset,
|
|
VbeInfo,
|
|
512);
|
|
if (Status != NO_ERROR) return;
|
|
|
|
/* Check correct VBE BIOS */
|
|
//VideoPortDebugPrint(0, "have vbe data\n");
|
|
TotalMemory = VbeInfo->Info.TotalMemory << 16;
|
|
VbeVersion = VbeInfo->Info.Version;
|
|
VideoPortDebugPrint(0, "vbe version %lx memory %lx\n", VbeVersion, TotalMemory);
|
|
if (!ValidateVbeInfo(VgaExtension, VbeInfo)) return;
|
|
|
|
/* Read modes */
|
|
//VideoPortDebugPrint(0, "read modes from %p\n", VbeInfo->Info.VideoModePtr);
|
|
Status = VgaExtension->Int10Interface.Int10ReadMemory(Context,
|
|
HIWORD(VbeInfo->Info.VideoModePtr),
|
|
LOWORD(VbeInfo->Info.VideoModePtr),
|
|
VbeInfo->ModeArray,
|
|
128 * sizeof(USHORT));
|
|
if (Status != NO_ERROR) return;
|
|
//VideoPortDebugPrint(0, "Read modes at: %p\n", VbeInfo->ModeArray);
|
|
|
|
/* Count modes, check for new 4bpp SVGA modes */
|
|
ThisMode = VbeInfo->ModeArray;
|
|
ModeResult = VbeInfo->ModeArray[0];
|
|
while (ModeResult != 0xFFFF)
|
|
{
|
|
Mode = ModeResult & 0x1FF;
|
|
//VideoPortDebugPrint(0, "Mode found: %lx\n", Mode);
|
|
if ((Mode == 0x102) || (Mode == 0x6A)) FourBppModeFound = TRUE;
|
|
ModeResult = *++ThisMode;
|
|
NewModes++;
|
|
}
|
|
|
|
/* Remove the built-in mode if not supported by card and check max modes */
|
|
if (!FourBppModeFound) --NumVideoModes;
|
|
if ((NewModes >= 128) && (NumVideoModes > 8)) goto Cleanup;
|
|
|
|
/* Switch to new SVGA mode list, copy VGA modes */
|
|
VgaModeList = VideoPortAllocatePool(VgaExtension, 1, (NewModes + NumVideoModes) * sizeof(VIDEOMODE), ' agV');
|
|
if (!VgaModeList) goto Cleanup;
|
|
VideoPortMoveMemory(VgaModeList, ModesVGA, NumVideoModes * sizeof(VIDEOMODE));
|
|
|
|
/* Apply fixup for Intel Brookdale */
|
|
if (g_bIntelBrookdaleBIOS)
|
|
{
|
|
VideoPortDebugPrint(0, "Intel Brookdale-G Video BIOS Not Support!\n");
|
|
while (TRUE);
|
|
}
|
|
|
|
/* Scan SVGA modes */
|
|
// VideoPortDebugPrint(0, "Static modes: %d\n", NumVideoModes);
|
|
VgaMode = &VgaModeList[NumVideoModes];
|
|
ThisMode = VbeInfo->ModeArray;
|
|
//VideoPortDebugPrint(0, "new modes: %d\n", NewModes);
|
|
while (NewModes--)
|
|
{
|
|
/* Get info on mode */
|
|
BiosArguments.Eax = VBE_GET_MODE_INFORMATION;
|
|
BiosArguments.Ecx = *ThisMode;
|
|
BiosArguments.Edi = TrampolineMemoryOffset;
|
|
BiosArguments.SegEs = TrampolineMemorySegment;
|
|
Status = VgaExtension->Int10Interface.Int10CallBios(Context, &BiosArguments);
|
|
if (Status != NO_ERROR) goto Next;
|
|
if (BiosArguments.Eax != VBE_SUCCESS) goto Next;
|
|
Status = VgaExtension->Int10Interface.Int10ReadMemory(Context,
|
|
TrampolineMemorySegment,
|
|
TrampolineMemoryOffset,
|
|
VbeModeInfo,
|
|
256);
|
|
if (Status != NO_ERROR) goto Next;
|
|
|
|
/* Parse graphics modes only if linear framebuffer support */
|
|
//VideoPortDebugPrint(0, "attr: %lx\n", VbeModeInfo->ModeAttributes);
|
|
if (!(VbeModeInfo->ModeAttributes & (VBE_MODEATTR_VALID |
|
|
VBE_MODEATTR_GRAPHICS))) goto Next;
|
|
LinearAddressing = ((VbeVersion >= 0x200) &&
|
|
(VbeModeInfo->PhysBasePtr) &&
|
|
(VbeModeInfo->ModeAttributes & VBE_MODEATTR_LINEAR)) ?
|
|
TRUE : FALSE;
|
|
|
|
/* Check SVGA modes if 8bpp or higher */
|
|
//VideoPortDebugPrint(0, "PhysBase: %lx\n", VbeModeInfo->PhysBasePtr);
|
|
if ((VbeModeInfo->XResolution >= 640) &&
|
|
(VbeModeInfo->YResolution >= 480) &&
|
|
(VbeModeInfo->NumberOfPlanes >= 1) &&
|
|
(VbeModeInfo->BitsPerPixel >= 8))
|
|
{
|
|
/* Copy VGA mode info */
|
|
VideoPortZeroMemory(VgaMode, sizeof(VIDEOMODE));
|
|
VgaMode->numPlanes = VbeModeInfo->NumberOfPlanes;
|
|
VgaMode->hres = VbeModeInfo->XResolution;
|
|
VgaMode->vres = VbeModeInfo->YResolution;
|
|
VgaMode->Frequency = 1;
|
|
VgaMode->Mode = (*ThisMode << 16) | VBE_SET_VBE_MODE;
|
|
VgaMode->Granularity = VbeModeInfo->WinGranularity << 10;
|
|
//VideoPortDebugPrint(0, "Mode %lx (Granularity %d)\n", VgaMode->Mode, VgaMode->Granularity);
|
|
|
|
/* Set flags */
|
|
if (VbeModeInfo->ModeAttributes & VBE_MODEATTR_COLOR) VgaMode->fbType |= VIDEO_MODE_COLOR;
|
|
if (VbeModeInfo->ModeAttributes & VBE_MODEATTR_GRAPHICS) VgaMode->fbType |= VIDEO_MODE_GRAPHICS;
|
|
if (VbeModeInfo->ModeAttributes & VBE_MODEATTR_NON_VGA) VgaMode->NonVgaMode = TRUE;
|
|
|
|
/* If no char data, say 80x25 */
|
|
VgaMode->col = VbeModeInfo->XCharSize ? VbeModeInfo->XResolution / VbeModeInfo->XCharSize : 80;
|
|
VgaMode->row = VbeModeInfo->YCharSize ? VbeModeInfo->YResolution / VbeModeInfo->YCharSize : 25;
|
|
//VideoPortDebugPrint(0, "%d by %d rows\n", VgaMode->Columns, VgaMode->Rows);
|
|
|
|
/* Check RGB555 (15bpp only) */
|
|
VgaMode->bitsPerPlane = VbeModeInfo->BitsPerPixel / VbeModeInfo->NumberOfPlanes;
|
|
if ((VgaMode->bitsPerPlane == 16) && (VbeModeInfo->GreenMaskSize == 5)) VgaMode->bitsPerPlane = 15;
|
|
//VideoPortDebugPrint(0, "BPP: %d\n", VgaMode->BitsPerPlane);
|
|
|
|
/* Do linear or banked frame buffers */
|
|
VgaMode->FrameBufferBase = 0;
|
|
if (!LinearAddressing)
|
|
{
|
|
/* Read the screen stride (scanline size) */
|
|
ScreenStride = RaiseToPower2(VbeModeInfo->BytesPerScanLine);
|
|
VgaMode->wbytes = ScreenStride;
|
|
//VideoPortDebugPrint(0, "ScanLines: %lx Stride: %lx\n", VbeModeInfo->BytesPerScanLine, VgaMode->Stride);
|
|
|
|
/* Size of frame buffer is Height X ScanLine, align to bank/page size */
|
|
ScreenSize = VgaMode->hres * ScreenStride;
|
|
//VideoPortDebugPrint(0, "Size: %lx\n", ScreenSize);
|
|
Size = (ScreenSize + ((64 * 1024) - 1)) & ((64 * 1024) - 1);
|
|
//VideoPortDebugPrint(0, "Size: %lx\n", ScreenSize);
|
|
if (Size > TotalMemory) Size = (Size + ((4 * 1024) - 1)) & ((4 * 1024) - 1);
|
|
//VideoPortDebugPrint(0, "Size: %lx\n", ScreenSize);
|
|
|
|
/* Banked VGA at 0xA0000 (64K) */
|
|
//VideoPortDebugPrint(0, "Final size: %lx\n", Size);
|
|
VgaMode->fbType |= VIDEO_MODE_BANKED;
|
|
VgaMode->sbytes = Size;
|
|
VgaMode->PhysSize = 64 * 1024;
|
|
VgaMode->FrameBufferSize = 64 * 1024;
|
|
VgaMode->NoBankSwitch = TRUE;
|
|
VgaMode->PhysBase = 0xA0000;
|
|
VgaMode->LogicalWidth = RaiseToPower2(VgaMode->hres);
|
|
}
|
|
else
|
|
{
|
|
/* VBE 3.00+ has specific field, read legacy field if not */
|
|
//VideoPortDebugPrint(0, "LINEAR MODE!!!\n");
|
|
ScreenStride = (VbeVersion >= 0x300) ? VbeModeInfo->LinBytesPerScanLine : 0;
|
|
if (!ScreenStride) ScreenStride = VbeModeInfo->BytesPerScanLine;
|
|
VgaMode->wbytes = ScreenStride;
|
|
//VideoPortDebugPrint(0, "ScanLines: %lx Stride: %lx\n", VbeModeInfo->BytesPerScanLine, VgaMode->Stride);
|
|
|
|
/* Size of frame buffer is Height X ScanLine, align to page size */
|
|
ScreenSize = VgaMode->hres * LOWORD(VgaMode->wbytes);
|
|
//VideoPortDebugPrint(0, "Size: %lx\n", ScreenSize);
|
|
Size = RaiseToPower2Ulong(ScreenSize);
|
|
//VideoPortDebugPrint(0, "Size: %lx\n", ScreenSize);
|
|
if (Size > TotalMemory) Size = (Size + ((4 * 1024) - 1)) & ((4 * 1024) - 1);
|
|
//VideoPortDebugPrint(0, "Size: %lx\n", ScreenSize);
|
|
|
|
/* Linear VGA must read settings from VBE */
|
|
VgaMode->fbType |= VIDEO_MODE_LINEAR;
|
|
VgaMode->sbytes = Size;
|
|
VgaMode->PhysSize = Size;
|
|
VgaMode->FrameBufferSize = Size;
|
|
VgaMode->NoBankSwitch = FALSE;
|
|
VgaMode->PhysBase = VbeModeInfo->PhysBasePtr;
|
|
VgaMode->LogicalWidth = VgaMode->hres;
|
|
|
|
/* Make VBE_SET_VBE_MODE command use Linear Framebuffer Select */
|
|
VgaMode->Mode |= (VBE_MODE_LINEAR_FRAMEBUFFER << 16);
|
|
}
|
|
|
|
/* Override bank switch if not support by card */
|
|
if (VbeModeInfo->ModeAttributes & VBE_MODEATTR_NO_BANK_SWITCH) VgaMode->NoBankSwitch = TRUE;
|
|
|
|
/* Next */
|
|
if (ScreenSize <= TotalMemory)
|
|
{
|
|
VgaMode++;
|
|
ModeCount++;
|
|
}
|
|
}
|
|
Next:
|
|
/* Next */
|
|
ThisMode++;
|
|
}
|
|
|
|
/* Check if last mode was color to do test */
|
|
VideoPortDebugPrint(0, "mode scan complete. Total modes: %d\n", ModeCount);
|
|
if (--VgaMode->fbType & VIDEO_MODE_COLOR)
|
|
{
|
|
/* Try map physical buffer and free if worked */
|
|
PhysicalAddress.QuadPart = VgaMode->PhysBase;
|
|
BaseAddress = VideoPortGetDeviceBase(VgaExtension, PhysicalAddress, 4 * 1024, FALSE);
|
|
if (BaseAddress)
|
|
{
|
|
VideoPortFreeDeviceBase(VgaExtension, BaseAddress);
|
|
}
|
|
else
|
|
{
|
|
/* Not work, so throw out VBE data */
|
|
ModeCount = 0;
|
|
}
|
|
}
|
|
|
|
/* Cleanup sucess path */
|
|
VideoPortFreePool(VgaExtension, VbeInfo);
|
|
VgaExtension->Int10Interface.Int10FreeBuffer(Context,
|
|
TrampolineMemorySegment,
|
|
TrampolineMemoryOffset);
|
|
NumVideoModes += ModeCount;
|
|
return;
|
|
|
|
Cleanup:
|
|
/* Cleanup failure path, reset standard VGA and free memory */
|
|
VgaModeList = ModesVGA;
|
|
VideoPortFreePool(VgaExtension, VbeInfo);
|
|
VgaExtension->Int10Interface.Int10FreeBuffer(Context,
|
|
TrampolineMemorySegment,
|
|
TrampolineMemoryOffset);
|
|
}
|
|
|
|
/* EOF */
|