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.
551 lines
18 KiB
551 lines
18 KiB
/******************************Module*Header*******************************\
|
|
* Module Name: screen.c
|
|
*
|
|
* Initializes the GDIINFO and DEVINFO structures for DrvEnablePDEV.
|
|
*
|
|
* Copyright (c) 1992 Microsoft Corporation
|
|
\**************************************************************************/
|
|
|
|
#include "driver.h"
|
|
|
|
#define SYSTM_LOGFONT {16,7,0,0,700,0,0,0,ANSI_CHARSET,OUT_DEFAULT_PRECIS, \
|
|
CLIP_DEFAULT_PRECIS,DEFAULT_QUALITY,VARIABLE_PITCH | \
|
|
FF_DONTCARE,L"System"}
|
|
#define HELVE_LOGFONT {12,9,0,0,400,0,0,0,ANSI_CHARSET,OUT_DEFAULT_PRECIS, \
|
|
CLIP_STROKE_PRECIS,PROOF_QUALITY,VARIABLE_PITCH | \
|
|
FF_DONTCARE,L"MS Sans Serif"}
|
|
#define COURI_LOGFONT {12,9,0,0,400,0,0,0,ANSI_CHARSET,OUT_DEFAULT_PRECIS, \
|
|
CLIP_STROKE_PRECIS,PROOF_QUALITY,FIXED_PITCH | \
|
|
FF_DONTCARE, L"Courier"}
|
|
|
|
// This is the basic devinfo for a default driver. This is used as a base and customized based
|
|
// on information passed back from the miniport driver.
|
|
|
|
const DEVINFO gDevInfoFrameBuffer = {
|
|
(GCAPS_OPAQUERECT | GCAPS_MONO_DITHER), /* Graphics capabilities */
|
|
|
|
// Should also implement GCAPS_HORIZSTRIKE so that the underlines
|
|
// aren't drawn using DrvBitBlt
|
|
|
|
SYSTM_LOGFONT, // Default font description
|
|
HELVE_LOGFONT, // ANSI variable font description
|
|
COURI_LOGFONT, // ANSI fixed font description
|
|
0, // Count of device fonts
|
|
BMF_16BPP, // Preferred DIB format
|
|
8, // Width of dither
|
|
8, // Height of dither
|
|
0 // Default palette to use for this device
|
|
};
|
|
|
|
/******************************Public*Routine******************************\
|
|
* bInitSURF
|
|
*
|
|
* Enables the surface. Maps the frame buffer into memory.
|
|
*
|
|
\**************************************************************************/
|
|
|
|
BOOL bInitSURF(PPDEV ppdev, BOOL bFirst)
|
|
{
|
|
VIDEO_MEMORY VideoMemory;
|
|
VIDEO_MEMORY_INFORMATION VideoMemoryInfo;
|
|
DWORD ReturnedDataLength;
|
|
|
|
// Set the mode.
|
|
|
|
if (EngDeviceIoControl(ppdev->hDriver,
|
|
IOCTL_VIDEO_SET_CURRENT_MODE,
|
|
(LPVOID) &ppdev->ulMode, // input buffer
|
|
sizeof(DWORD),
|
|
NULL,
|
|
0,
|
|
&ReturnedDataLength))
|
|
{
|
|
DISPDBG((0, "vga64k.dll: Failed SET_CURRENT_MODE\n"));
|
|
return(FALSE);
|
|
}
|
|
|
|
if (bFirst)
|
|
{
|
|
// Get the linear memory address range.
|
|
|
|
VideoMemory.RequestedVirtualAddress = NULL;
|
|
|
|
if (EngDeviceIoControl(ppdev->hDriver,
|
|
IOCTL_VIDEO_MAP_VIDEO_MEMORY,
|
|
(PVOID) &VideoMemory, // input buffer
|
|
sizeof (VIDEO_MEMORY),
|
|
(PVOID) &VideoMemoryInfo, // output buffer
|
|
sizeof (VideoMemoryInfo),
|
|
&ReturnedDataLength))
|
|
{
|
|
DISPDBG((0, "vga64k.dll: Failed MAP_VIDEO_MEMORY\n"));
|
|
return(FALSE);
|
|
}
|
|
}
|
|
|
|
// Record the Frame Buffer Linear Address.
|
|
|
|
if (bFirst)
|
|
{
|
|
ppdev->pjScreen = (PBYTE) VideoMemoryInfo.FrameBufferBase;
|
|
}
|
|
|
|
// Set the various write mode values, so we don't have to read before write
|
|
// later on
|
|
|
|
vSetWriteModes(&ppdev->ulrm0_wmX);
|
|
|
|
// Initialize the VGA registers to their default states, so that we
|
|
// can be sure of drawing properly even when the miniport didn't
|
|
// happen to set them the way we like them:
|
|
|
|
vInitRegs(ppdev);
|
|
|
|
// Since we just did a mode-set, we'll be in non-planar mode. And make
|
|
// sure we reset the bank manager (otherwise, after a switch from full-
|
|
// screen, we may think we've got one bank mapped in, when in fact there's
|
|
// a different one mapped in, and bad things would happen...).
|
|
|
|
ppdev->flBank &= ~BANK_PLANAR;
|
|
|
|
ppdev->rcl1WindowClip.bottom = -1;
|
|
ppdev->rcl2WindowClip[0].bottom = -1;
|
|
ppdev->rcl2WindowClip[1].bottom = -1;
|
|
|
|
ppdev->rcl1PlanarClip.bottom = -1;
|
|
ppdev->rcl2PlanarClip[0].bottom = -1;
|
|
ppdev->rcl2PlanarClip[1].bottom = -1;
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* vDisableSURF
|
|
*
|
|
* Disable the surface. Un-Maps the frame in memory.
|
|
*
|
|
\**************************************************************************/
|
|
|
|
VOID vDisableSURF(PPDEV ppdev)
|
|
{
|
|
DWORD returnedDataLength;
|
|
VIDEO_MEMORY videoMemory;
|
|
|
|
videoMemory.RequestedVirtualAddress = (PVOID) ppdev->pjScreen;
|
|
|
|
if (EngDeviceIoControl(ppdev->hDriver,
|
|
IOCTL_VIDEO_UNMAP_VIDEO_MEMORY,
|
|
(LPVOID) &videoMemory,
|
|
sizeof(VIDEO_MEMORY),
|
|
NULL,
|
|
0,
|
|
&returnedDataLength))
|
|
{
|
|
RIP("Failed UNMAP_VIDEO_MEMORY");
|
|
}
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* bInitPDEV
|
|
*
|
|
* Determine the mode we should be in based on the DEVMODE passed in.
|
|
* Query mini-port to get information needed to fill in the DevInfo and the
|
|
* GdiInfo .
|
|
*
|
|
\**************************************************************************/
|
|
|
|
BOOL bInitPDEV(
|
|
PPDEV ppdev,
|
|
DEVMODEW *pDevMode)
|
|
{
|
|
GDIINFO *pGdiInfo;
|
|
ULONG cModes;
|
|
PVIDEO_MODE_INFORMATION pVideoBuffer, pVideoModeSelected, pVideoTemp;
|
|
VIDEO_COLOR_CAPABILITIES colorCapabilities;
|
|
ULONG ulTemp;
|
|
BOOL bSelectDefault;
|
|
ULONG cbModeSize;
|
|
BANK_POSITION BankPosition;
|
|
ULONG ulReturn;
|
|
|
|
pGdiInfo = ppdev->pGdiInfo;
|
|
|
|
//
|
|
// calls the miniport to get mode information.
|
|
//
|
|
|
|
cModes = getAvailableModes(ppdev->hDriver, &pVideoBuffer, &cbModeSize);
|
|
|
|
if (cModes == 0)
|
|
{
|
|
DISPDBG((0, "vga64k.dll: no available modes\n"));
|
|
return(FALSE);
|
|
}
|
|
|
|
//
|
|
// Determine if we are looking for a default mode.
|
|
//
|
|
|
|
if ( ((pDevMode->dmPelsWidth) ||
|
|
(pDevMode->dmPelsHeight) ||
|
|
(pDevMode->dmBitsPerPel) ||
|
|
(pDevMode->dmDisplayFlags) ||
|
|
(pDevMode->dmDisplayFrequency)) == 0)
|
|
{
|
|
bSelectDefault = TRUE;
|
|
}
|
|
else
|
|
{
|
|
bSelectDefault = FALSE;
|
|
}
|
|
|
|
//
|
|
// Now see if the requested mode has a match in that table.
|
|
//
|
|
|
|
pVideoModeSelected = NULL;
|
|
pVideoTemp = pVideoBuffer;
|
|
|
|
while (cModes--)
|
|
{
|
|
if (pVideoTemp->Length != 0)
|
|
{
|
|
if (bSelectDefault ||
|
|
((pVideoTemp->VisScreenWidth == pDevMode->dmPelsWidth) &&
|
|
(pVideoTemp->VisScreenHeight == pDevMode->dmPelsHeight) &&
|
|
(pVideoTemp->BitsPerPlane *
|
|
pVideoTemp->NumberOfPlanes == pDevMode->dmBitsPerPel) &&
|
|
(pVideoTemp->Frequency == pDevMode->dmDisplayFrequency)))
|
|
{
|
|
pVideoModeSelected = pVideoTemp;
|
|
DISPDBG((2, "vga64k: Found a match\n")) ;
|
|
break;
|
|
}
|
|
}
|
|
|
|
pVideoTemp = (PVIDEO_MODE_INFORMATION)
|
|
(((PUCHAR)pVideoTemp) + cbModeSize);
|
|
}
|
|
|
|
//
|
|
// If no mode has been found, return an error
|
|
//
|
|
|
|
if (pVideoModeSelected == NULL)
|
|
{
|
|
DISPDBG((0, "vga64k.dll: no valid modes\n"));
|
|
EngFreeMem(pVideoBuffer);
|
|
return(FALSE);
|
|
}
|
|
|
|
//
|
|
// Fill in the GDIINFO data structure with the information returned from
|
|
// the kernel driver.
|
|
//
|
|
|
|
ppdev->ulMode = pVideoModeSelected->ModeIndex;
|
|
ppdev->cxScreen = pVideoModeSelected->VisScreenWidth;
|
|
ppdev->cyScreen = pVideoModeSelected->VisScreenHeight;
|
|
ppdev->ulBitCount = pVideoModeSelected->BitsPerPlane *
|
|
pVideoModeSelected->NumberOfPlanes;
|
|
ppdev->lDeltaScreen = pVideoModeSelected->ScreenStride;
|
|
|
|
ppdev->flRed = pVideoModeSelected->RedMask;
|
|
ppdev->flGreen = pVideoModeSelected->GreenMask;
|
|
ppdev->flBlue = pVideoModeSelected->BlueMask;
|
|
|
|
if (!(pVideoModeSelected->AttributeFlags & VIDEO_MODE_NO_OFF_SCREEN))
|
|
{
|
|
ppdev->fl |= DRIVER_USE_OFFSCREEN;
|
|
}
|
|
|
|
pGdiInfo->ulVersion = GDI_DRIVER_VERSION;
|
|
pGdiInfo->ulTechnology = DT_RASDISPLAY;
|
|
pGdiInfo->ulHorzSize = pVideoModeSelected->XMillimeter;
|
|
pGdiInfo->ulVertSize = pVideoModeSelected->YMillimeter;
|
|
|
|
pGdiInfo->ulHorzRes = ppdev->cxScreen;
|
|
pGdiInfo->ulVertRes = ppdev->cyScreen;
|
|
pGdiInfo->ulPanningHorzRes = ppdev->cxScreen;
|
|
pGdiInfo->ulPanningVertRes = ppdev->cyScreen;
|
|
pGdiInfo->cBitsPixel = pVideoModeSelected->BitsPerPlane;
|
|
pGdiInfo->cPlanes = pVideoModeSelected->NumberOfPlanes;
|
|
pGdiInfo->ulVRefresh = pVideoModeSelected->Frequency;
|
|
pGdiInfo->ulBltAlignment = 1; // We're not accelerated, and we don't
|
|
// care about window alignment
|
|
|
|
pGdiInfo->ulLogPixelsX = pDevMode->dmLogPixels;
|
|
pGdiInfo->ulLogPixelsY = pDevMode->dmLogPixels;
|
|
|
|
pGdiInfo->flTextCaps = TC_RA_ABLE | TC_SCROLLBLT;
|
|
pGdiInfo->flRaster = 0; // DDI reservers flRaster
|
|
|
|
pGdiInfo->ulDACRed = pVideoModeSelected->NumberRedBits;
|
|
pGdiInfo->ulDACGreen = pVideoModeSelected->NumberGreenBits;
|
|
pGdiInfo->ulDACBlue = pVideoModeSelected->NumberBlueBits;
|
|
|
|
pGdiInfo->ulAspectX = 0x24; // One-to-one aspect ratio
|
|
pGdiInfo->ulAspectY = 0x24;
|
|
pGdiInfo->ulAspectXY = 0x33;
|
|
|
|
pGdiInfo->xStyleStep = 1; // A style unit is 3 pels
|
|
pGdiInfo->yStyleStep = 1;
|
|
pGdiInfo->denStyleStep = 3;
|
|
|
|
pGdiInfo->ptlPhysOffset.x = 0;
|
|
pGdiInfo->ptlPhysOffset.y = 0;
|
|
pGdiInfo->szlPhysSize.cx = 0;
|
|
pGdiInfo->szlPhysSize.cy = 0;
|
|
|
|
// RGB and CMY color info.
|
|
|
|
// try to get it from the miniport.
|
|
// if the miniport doesn ot support this feature, use defaults.
|
|
|
|
if (EngDeviceIoControl(ppdev->hDriver,
|
|
IOCTL_VIDEO_QUERY_COLOR_CAPABILITIES,
|
|
NULL,
|
|
0,
|
|
&colorCapabilities,
|
|
sizeof(VIDEO_COLOR_CAPABILITIES),
|
|
&ulTemp))
|
|
{
|
|
DISPDBG((1, "vga64k DISP getcolorCapabilities failed \n"));
|
|
|
|
pGdiInfo->ciDevice.Red.x = 6700;
|
|
pGdiInfo->ciDevice.Red.y = 3300;
|
|
pGdiInfo->ciDevice.Red.Y = 0;
|
|
pGdiInfo->ciDevice.Green.x = 2100;
|
|
pGdiInfo->ciDevice.Green.y = 7100;
|
|
pGdiInfo->ciDevice.Green.Y = 0;
|
|
pGdiInfo->ciDevice.Blue.x = 1400;
|
|
pGdiInfo->ciDevice.Blue.y = 800;
|
|
pGdiInfo->ciDevice.Blue.Y = 0;
|
|
pGdiInfo->ciDevice.AlignmentWhite.x = 3127;
|
|
pGdiInfo->ciDevice.AlignmentWhite.y = 3290;
|
|
pGdiInfo->ciDevice.AlignmentWhite.Y = 0;
|
|
|
|
pGdiInfo->ciDevice.RedGamma = 20000;
|
|
pGdiInfo->ciDevice.GreenGamma = 20000;
|
|
pGdiInfo->ciDevice.BlueGamma = 20000;
|
|
|
|
}
|
|
else
|
|
{
|
|
|
|
pGdiInfo->ciDevice.Red.x = colorCapabilities.RedChromaticity_x;
|
|
pGdiInfo->ciDevice.Red.y = colorCapabilities.RedChromaticity_y;
|
|
pGdiInfo->ciDevice.Red.Y = 0;
|
|
pGdiInfo->ciDevice.Green.x = colorCapabilities.GreenChromaticity_x;
|
|
pGdiInfo->ciDevice.Green.y = colorCapabilities.GreenChromaticity_y;
|
|
pGdiInfo->ciDevice.Green.Y = 0;
|
|
pGdiInfo->ciDevice.Blue.x = colorCapabilities.BlueChromaticity_x;
|
|
pGdiInfo->ciDevice.Blue.y = colorCapabilities.BlueChromaticity_y;
|
|
pGdiInfo->ciDevice.Blue.Y = 0;
|
|
pGdiInfo->ciDevice.AlignmentWhite.x = colorCapabilities.WhiteChromaticity_x;
|
|
pGdiInfo->ciDevice.AlignmentWhite.y = colorCapabilities.WhiteChromaticity_y;
|
|
pGdiInfo->ciDevice.AlignmentWhite.Y = colorCapabilities.WhiteChromaticity_Y;
|
|
|
|
// if we have a color device store the three color gamma values,
|
|
// otherwise store the unique gamma value in all three.
|
|
|
|
if (colorCapabilities.AttributeFlags & VIDEO_DEVICE_COLOR)
|
|
{
|
|
pGdiInfo->ciDevice.RedGamma = colorCapabilities.RedGamma;
|
|
pGdiInfo->ciDevice.GreenGamma = colorCapabilities.GreenGamma;
|
|
pGdiInfo->ciDevice.BlueGamma = colorCapabilities.BlueGamma;
|
|
}
|
|
else
|
|
{
|
|
pGdiInfo->ciDevice.RedGamma = colorCapabilities.WhiteGamma;
|
|
pGdiInfo->ciDevice.GreenGamma = colorCapabilities.WhiteGamma;
|
|
pGdiInfo->ciDevice.BlueGamma = colorCapabilities.WhiteGamma;
|
|
}
|
|
|
|
};
|
|
|
|
pGdiInfo->ciDevice.Cyan.x = 0;
|
|
pGdiInfo->ciDevice.Cyan.y = 0;
|
|
pGdiInfo->ciDevice.Cyan.Y = 0;
|
|
pGdiInfo->ciDevice.Magenta.x = 0;
|
|
pGdiInfo->ciDevice.Magenta.y = 0;
|
|
pGdiInfo->ciDevice.Magenta.Y = 0;
|
|
pGdiInfo->ciDevice.Yellow.x = 0;
|
|
pGdiInfo->ciDevice.Yellow.y = 0;
|
|
pGdiInfo->ciDevice.Yellow.Y = 0;
|
|
|
|
// No dye correction for raster displays.
|
|
|
|
pGdiInfo->ciDevice.MagentaInCyanDye = 0;
|
|
pGdiInfo->ciDevice.YellowInCyanDye = 0;
|
|
pGdiInfo->ciDevice.CyanInMagentaDye = 0;
|
|
pGdiInfo->ciDevice.YellowInMagentaDye = 0;
|
|
pGdiInfo->ciDevice.CyanInYellowDye = 0;
|
|
pGdiInfo->ciDevice.MagentaInYellowDye = 0;
|
|
|
|
// Fill in the rest of the devinfo and GdiInfo structures.
|
|
|
|
pGdiInfo->ulNumColors = (ULONG)-1;
|
|
pGdiInfo->ulNumPalReg = 0;
|
|
|
|
pGdiInfo->ulDevicePelsDPI = 0; // For printers only
|
|
pGdiInfo->ulPrimaryOrder = PRIMARY_ORDER_CBA;
|
|
pGdiInfo->ulHTPatternSize = HT_PATSIZE_4x4_M;
|
|
pGdiInfo->ulHTOutputFormat = HT_FORMAT_16BPP;
|
|
pGdiInfo->flHTFlags = HT_FLAG_ADDITIVE_PRIMS;
|
|
|
|
// Fill in the basic devinfo structure
|
|
|
|
*(ppdev->pDevInfo) = gDevInfoFrameBuffer;
|
|
|
|
EngFreeMem(pVideoBuffer);
|
|
|
|
//
|
|
// Check to see if the miniport supports
|
|
// IOCTL_VIDEO_SET_BANK_POSITION.
|
|
//
|
|
|
|
BankPosition.ReadBankPosition = 0;
|
|
BankPosition.WriteBankPosition = 0;
|
|
|
|
if (EngDeviceIoControl(ppdev->hDriver,
|
|
IOCTL_VIDEO_SET_BANK_POSITION,
|
|
&BankPosition,
|
|
sizeof(BANK_POSITION),
|
|
NULL,
|
|
0,
|
|
&ulReturn) == NO_ERROR)
|
|
{
|
|
ppdev->BankIoctlSupported = TRUE;
|
|
|
|
} else {
|
|
|
|
ppdev->BankIoctlSupported = FALSE;
|
|
}
|
|
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* getAvailableModes
|
|
*
|
|
* Calls the miniport to get the list of modes supported by the kernel driver,
|
|
* and returns the list of modes supported by the diplay driver among those
|
|
*
|
|
* returns the number of entries in the videomode buffer.
|
|
* 0 means no modes are supported by the miniport or that an error occured.
|
|
*
|
|
* NOTE: the buffer must be freed up by the caller.
|
|
*
|
|
\**************************************************************************/
|
|
|
|
DWORD getAvailableModes(
|
|
HANDLE hDriver,
|
|
PVIDEO_MODE_INFORMATION *modeInformation,
|
|
DWORD *cbModeSize)
|
|
{
|
|
ULONG ulTemp;
|
|
VIDEO_NUM_MODES modes;
|
|
PVIDEO_MODE_INFORMATION pVideoTemp;
|
|
|
|
//
|
|
// Get the number of modes supported by the mini-port
|
|
//
|
|
|
|
if (EngDeviceIoControl(hDriver,
|
|
IOCTL_VIDEO_QUERY_NUM_AVAIL_MODES,
|
|
NULL,
|
|
0,
|
|
&modes,
|
|
sizeof(VIDEO_NUM_MODES),
|
|
&ulTemp))
|
|
{
|
|
DISPDBG((0, "vga64k getAvailableModes failed VIDEO_QUERY_NUM_AVAIL_MODES\n"));
|
|
return(0);
|
|
}
|
|
|
|
*cbModeSize = modes.ModeInformationLength;
|
|
|
|
//
|
|
// Allocate the buffer for the mini-port to write the modes in.
|
|
//
|
|
|
|
*modeInformation = (PVIDEO_MODE_INFORMATION)
|
|
EngAllocMem(FL_ZERO_MEMORY,
|
|
modes.NumModes *
|
|
modes.ModeInformationLength, ALLOC_TAG);
|
|
|
|
if (*modeInformation == (PVIDEO_MODE_INFORMATION) NULL)
|
|
{
|
|
DISPDBG((0, "vga64k getAvailableModes failed EngAllocMem\n"));
|
|
|
|
return 0;
|
|
}
|
|
|
|
//
|
|
// Ask the mini-port to fill in the available modes.
|
|
//
|
|
|
|
if (EngDeviceIoControl(hDriver,
|
|
IOCTL_VIDEO_QUERY_AVAIL_MODES,
|
|
NULL,
|
|
0,
|
|
*modeInformation,
|
|
modes.NumModes * modes.ModeInformationLength,
|
|
&ulTemp))
|
|
{
|
|
|
|
DISPDBG((0, "vga64k getAvailableModes failed VIDEO_QUERY_AVAIL_MODES\n"));
|
|
|
|
EngFreeMem(*modeInformation);
|
|
*modeInformation = (PVIDEO_MODE_INFORMATION) NULL;
|
|
|
|
return(0);
|
|
}
|
|
|
|
//
|
|
// Now see which of these modes are supported by the display driver.
|
|
// As an internal mechanism, set the length to 0 for the modes we
|
|
// DO NOT support.
|
|
//
|
|
|
|
ulTemp = modes.NumModes;
|
|
pVideoTemp = *modeInformation;
|
|
|
|
//
|
|
// Mode is rejected if it is not one plane, or not graphics, or is not
|
|
// one of 16 bits per pel (that is all the vga64k currently supports)
|
|
//
|
|
|
|
while (ulTemp--)
|
|
{
|
|
if ((pVideoTemp->NumberOfPlanes != 1 ) ||
|
|
!(pVideoTemp->AttributeFlags & VIDEO_MODE_GRAPHICS) ||
|
|
(pVideoTemp->AttributeFlags & VIDEO_MODE_LINEAR) ||
|
|
(pVideoTemp->BitsPerPlane != 16) ||
|
|
|
|
//
|
|
// This next condition says that either the mode doesn't
|
|
// require broken rasters, or else the ScreenStride has
|
|
// already been set to some funky value. Some miniports
|
|
// choose strides that have broken rasters, but they're
|
|
// limited to unused areas of video memory. I only know of
|
|
// 1928, so we'll special case that.
|
|
//
|
|
|
|
(BROKEN_RASTERS(pVideoTemp->ScreenStride,
|
|
pVideoTemp->VisScreenHeight) &&
|
|
(pVideoTemp->ScreenStride != 1928)))
|
|
|
|
{
|
|
pVideoTemp->Length = 0;
|
|
}
|
|
|
|
pVideoTemp = (PVIDEO_MODE_INFORMATION)
|
|
(((PUCHAR)pVideoTemp) + modes.ModeInformationLength);
|
|
}
|
|
|
|
return modes.NumModes;
|
|
|
|
}
|