|
|
/******************************Module*Header*******************************\
* Module Name: drvsup.c * * * * Copyright (c) 1990-1999 Microsoft Corporation * * * * Display Driver management routines * * * * Andre Vachon -Andreva- * \**************************************************************************/
#include "precomp.hxx"
// The declaration of AlignRects has been removed from usergdi.h
// and has been explicitly added here. [dchinn]
extern "C" { BOOL AlignRects( IN OUT LPRECT arc, IN DWORD cCount, IN DWORD iPrimary, IN DWORD dwFlags); }
extern VOID APIENTRY GreSuspendDirectDrawEx( HDEV hdev, ULONG fl );
extern VOID APIENTRY GreResumeDirectDrawEx( HDEV hdev, ULONG fl );
#pragma hdrstop
#include <wdmguid.h> // for GUID_DEVICE_INTERFACE_ARRIVAL/REMOVAL
#define INITGUID
#include <initguid.h>
#include "ntddvdeo.h"
#ifdef _HYDRA_
#include <regapi.h>
#include <winDDIts.h>
#include "muclean.hxx"
#include "winstaw.h"
extern PFILE_OBJECT G_RemoteVideoFileObject; extern PFILE_OBJECT G_RemoteConnectionFileObject; extern HANDLE G_RemoteConnectionChannel; extern PBYTE G_PerformanceStatistics; extern BOOL G_fConsole; extern BOOL G_fDoubleDpi; extern LPWSTR G_DisplayDriverNames;
#endif
#if TEXTURE_DEMO
/*
* Texture Demo */
ULONG gcTextures; // Count of textures
HDEV gahdevTexture[8]; // Array of texture PDEVs
BOOL gbTexture = FALSE; // TRUE if we're to do the texture demo
HDEV ghdevTextureParent; // Non-NULL if doing texture demo
LONG gcxTexture; // Texture size of TexEnablePDEV
LONG gcyTexture;
#define INDEX_DrvDemoTexture INDEX_DrvMovePanning
typedef struct _DEMOCOORDINATE { float fX; float fY; float fW; float fU; float fV; float fZ; } DEMOCOORDINATE;
typedef struct _DEMOQUAD { DEMOCOORDINATE V0; DEMOCOORDINATE V1; DEMOCOORDINATE V2; DEMOCOORDINATE V3; } DEMOQUAD;
BOOL APIENTRY DrvDemoTexture( SURFOBJ *psoDst, SURFOBJ *psoSrc, CLIPOBJ *pco, DEMOQUAD *pQuads, ULONG cQuads );
typedef BOOL (*PFN_DrvDemoTexture)(SURFOBJ*,SURFOBJ*,CLIPOBJ*,DEMOQUAD*,ULONG);
#endif // TEXTURE_DEMO
typedef enum _DISP_DRIVER_LOG { MsgInvalidConfiguration = 1, MsgInvalidDisplayDriver, MsgInvalidOldDriver, MsgInvalidDisplayMode, MsgInvalidDisplay16Colors, MsgInvalidUsingDefaultMode, } DISP_DRIVER_LOG;
typedef enum _DISP_DRIVER_REGISTRY_TYPE { DispDriverRegGlobal, DispDriverRegHardwareProfile, DispDriverRegHardwareProfileCreate, DispDriverRegKey } DISP_DRIVER_REGISTRY_TYPE;
typedef enum _GRAPHICS_STATE { GraphicsStateFull = 1, GraphicsStateNoAttach, GraphicsStateAttachDisconnect } GRAPHICS_STATE;
#define DM_INTERNAL_VALID_FLAGS \
(DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT | DM_DISPLAYFREQUENCY | \ DM_DISPLAYFLAGS | DM_LOGPIXELS | DM_PANNINGWIDTH | DM_PANNINGHEIGHT | \ DM_DISPLAYORIENTATION )
#define DDML_DRIVER -4
BOOL gbBaseVideo; BOOL gbUpdateMonitor; BOOL gbInvalidateDualView; USHORT gdmLogPixels; ULONG gcNextGlobalDeviceNumber; ULONG gcNextGlobalPhysicalOutputNumber; ULONG gcNextGlobalVirtualOutputNumber; PGRAPHICS_DEVICE gpGraphicsDeviceList; PGRAPHICS_DEVICE gpGraphicsDeviceListLast; PGRAPHICS_DEVICE gPhysDispVGA; // VGA driver hack
GRAPHICS_DEVICE gFullscreenGraphicsDevice; GRAPHICS_DEVICE gFeFullscreenGraphicsDevice; // #if DBG
ULONG gcFailedModeChanges = 0; // #endif
PPALETTE DrvRealizeHalftonePalette(HDEV hdevPalette, BOOL bForce);
BOOL DrvSetDisconnectedGraphicsDevice( BOOL bLocal);
VOID DrvCleanupOneGraphicsDevice(PGRAPHICS_DEVICE pGraphicsDeviceList);
BOOL DrvIsProtocolAlreadyKnown(VOID);
extern "C" USHORT gProtocolType;
ULONG gcRemoteNextGlobalDeviceNumber; ULONG gcLocalNextGlobalDeviceNumber; PGRAPHICS_DEVICE gpRemoteGraphicsDeviceList; PGRAPHICS_DEVICE gpLocalGraphicsDeviceList; PGRAPHICS_DEVICE gpRemoteGraphicsDeviceListLast; PGRAPHICS_DEVICE gpLocalGraphicsDeviceListLast; PGRAPHICS_DEVICE gpRemoteDiscGraphicsDevice; PGRAPHICS_DEVICE gpLocalDiscGraphicsDevice; ULONG gcLocalNextGlobalPhysicalOutputNumber = 1; ULONG gcLocalNextGlobalVirtualOutputNumber = 1; ULONG gcRemoteNextGlobalPhysicalOutputNumber = 1; ULONG gcRemoteNextGlobalVirtualOutputNumber = 1;
#if MDEV_STACK_TRACE_LENGTH
LONG glMDEVTrace = 0; MDEVRECORD gMDEVTrace[32]; const LONG gcMDEVTraceLength = sizeof(gMDEVTrace)/sizeof(gMDEVTrace[0]); #endif
//
// Global driver list. This pointer points to the first driver in a
// singly linked list of drivers.
//
// We use this list to determine when we are called to load a driver to
// determine if the the driver image is already loaded.
// If the image is already loaded, we will just increment the reference count
// and then create a new PDEV.
//
PLDEV gpldevDrivers;
#if DBG
#define TRACE_SWITCH(str) { if (GreTraceDisplayDriverLoad) { KdPrint(str); } }
#else
#define TRACE_SWITCH(str)
#endif
PUCHAR gpFullscreenFrameBufPtr; ULONG gpFullscreenFrameBufLength = 0;
LONG CModeChangeInProgress::lInModeChange = 0; LONG CModeChangeInProgress::lNeedSyncFlush = 0; LONG CModeChangeInProgress::lNeedTimerFlush = 0;
int ConvertOutputToOem( IN LPWSTR Source, IN int SourceLength, // in chars
OUT LPSTR Target, IN int TargetLength // in chars
) /*
Converts SourceLength Unicode characters from Source into not more than TargetLength Codepage characters at Target. Returns the number characters put in Target. (0 if failure)
[ntcon\server\misc.c] */
{ NTSTATUS Status; ULONG Length;
// Can do this in place
Status = RtlUnicodeToOemN(Target, TargetLength, &Length, Source, SourceLength * sizeof(WCHAR) ); if (NT_SUCCESS(Status)) { return Length; } else { return 0; } }
/***************************************************************************\
* TranslateOutputToOem * * routine to translate console PCHAR_INFO to the ASCII from Unicode * * [ntcon\server\fe\direct2.c] \***************************************************************************/
NTSTATUS TranslateOutputToOem( OUT PCHAR_INFO OutputBuffer, IN PCHAR_INFO InputBuffer, IN DWORD Length ) { CHAR AsciiDbcs[2]; ULONG NumBytes;
while (Length--) { if (InputBuffer->Attributes & COMMON_LVB_LEADING_BYTE) { if (Length >= 2) // Safe DBCS in buffer ?
{ Length--; NumBytes = sizeof(AsciiDbcs); NumBytes = ConvertOutputToOem(&InputBuffer->Char.UnicodeChar, 1, &AsciiDbcs[0], NumBytes); OutputBuffer->Char.AsciiChar = AsciiDbcs[0]; OutputBuffer->Attributes = InputBuffer->Attributes; OutputBuffer++; InputBuffer++; OutputBuffer->Char.AsciiChar = AsciiDbcs[1]; OutputBuffer->Attributes = InputBuffer->Attributes; OutputBuffer++; InputBuffer++; } else { OutputBuffer->Char.AsciiChar = ' '; OutputBuffer->Attributes = InputBuffer->Attributes & ~COMMON_LVB_SBCSDBCS; OutputBuffer++; InputBuffer++; } } else if (! (InputBuffer->Attributes & COMMON_LVB_SBCSDBCS)) { ConvertOutputToOem(&InputBuffer->Char.UnicodeChar, 1, &OutputBuffer->Char.AsciiChar, 1); OutputBuffer->Attributes = InputBuffer->Attributes; OutputBuffer++; InputBuffer++; } }
return STATUS_SUCCESS; }
/***************************************************************************\
* NtGdiFullscreenControl * * routine to support console calls to the video driver * * 01-Sep-1995 andreva Created \***************************************************************************/
NTSTATUS NtGdiFullscreenControl( IN FULLSCREENCONTROL FullscreenCommand, PVOID FullscreenInput, DWORD FullscreenInputLength, PVOID FullscreenOutput, PULONG FullscreenOutputLength) {
NTSTATUS Status = STATUS_SUCCESS;
ULONG BytesReturned; PVOID pCapBuffer = NULL; ULONG cCapBuffer = 0; ULONG ioctl = 0;
#define VERIFY_RANGE(base, length, max_length) \
(((ULONG_PTR)base < (ULONG_PTR)max_length) && \ ((ULONG_PTR)length < (ULONG_PTR)max_length) && \ (((ULONG_PTR)base + (ULONG_PTR)length) < (ULONG_PTR)max_length))
//
// If this is not CSR, then fail the API call.
//
if (PsGetCurrentProcess() != gpepCSRSS) { return STATUS_PRIVILEGE_NOT_HELD; }
//
// First validate the ioctl
//
switch(FullscreenCommand) {
case FullscreenControlEnable: ioctl = IOCTL_VIDEO_ENABLE_VDM; TRACE_SWITCH(("Switching: FullscreenControlEnable\n")); break;
case FullscreenControlDisable: ioctl = IOCTL_VIDEO_DISABLE_VDM; TRACE_SWITCH(("Switching: FullscreenControlDisable\n")); break;
case FullscreenControlSetCursorPosition: if (gFeFullscreenGraphicsDevice.pDeviceHandle != NULL) { ioctl = IOCTL_FSVIDEO_SET_CURSOR_POSITION; } else { ioctl = IOCTL_VIDEO_SET_CURSOR_POSITION; } TRACE_SWITCH(("Switching: FullscreenControlSetCursorPosition\n")); break;
case FullscreenControlSetCursorAttributes: ioctl = IOCTL_VIDEO_SET_CURSOR_ATTR; TRACE_SWITCH(("Switching: FullscreenControlSetCursorAttributes\n")); break;
case FullscreenControlRegisterVdm: ioctl = IOCTL_VIDEO_REGISTER_VDM; TRACE_SWITCH(("Switching: FullscreenControlRegisterVdm\n")); break;
case FullscreenControlSetPalette: ioctl = IOCTL_VIDEO_SET_PALETTE_REGISTERS; TRACE_SWITCH(("Switching: FullscreenControlSetPalette\n")); break;
case FullscreenControlSetColors: ioctl = IOCTL_VIDEO_SET_COLOR_REGISTERS; TRACE_SWITCH(("Switching: FullscreenControlSetColors\n")); break;
case FullscreenControlLoadFont: ioctl = IOCTL_VIDEO_LOAD_AND_SET_FONT; TRACE_SWITCH(("Switching: FullscreenControlLoadFont\n")); break;
case FullscreenControlRestoreHardwareState: ioctl = IOCTL_VIDEO_RESTORE_HARDWARE_STATE; TRACE_SWITCH(("Switching: FullscreenControlRestoreHardwareState\n")); break;
case FullscreenControlSaveHardwareState: ioctl = IOCTL_VIDEO_SAVE_HARDWARE_STATE; TRACE_SWITCH(("Switching: FullscreenControlSaveHardwareState\n")); break;
case FullscreenControlCopyFrameBuffer: case FullscreenControlReadFromFrameBuffer: case FullscreenControlWriteToFrameBuffer: case FullscreenControlReverseMousePointer: case FullscreenControlCopyFrameBufferDB: case FullscreenControlWriteToFrameBufferDB: case FullscreenControlReverseMousePointerDB:
// TRACE_SWITCH(("Switching: Fullscreen output command\n"));
if (gFeFullscreenGraphicsDevice.pDeviceHandle != NULL) { /*
* Console Full Screen Video driver is available. */ switch(FullscreenCommand) { case FullscreenControlCopyFrameBufferDB: ioctl = IOCTL_FSVIDEO_COPY_FRAME_BUFFER; break; case FullscreenControlWriteToFrameBufferDB: ioctl = IOCTL_FSVIDEO_WRITE_TO_FRAME_BUFFER; break; case FullscreenControlReverseMousePointerDB: ioctl = IOCTL_FSVIDEO_REVERSE_MOUSE_POINTER; break; } } break;
case FullscreenControlSetMode: TRACE_SWITCH(("Switching: Fullscreen setmode command\n")); break;
case FullscreenControlSetScreenInformation: if (gFeFullscreenGraphicsDevice.pDeviceHandle != NULL) { ioctl = IOCTL_FSVIDEO_SET_SCREEN_INFORMATION; } else { return STATUS_NOT_IMPLEMENTED; } break;
case FullscreenControlSpecificVideoControl: // for specific NEC PC-98
__try { ProbeForRead(FullscreenInput, sizeof(DWORD), sizeof(DWORD)); RtlCopyMemory(&ioctl, FullscreenInput, sizeof(DWORD));
FullscreenInput = (PVOID)((PBYTE)FullscreenInput + sizeof(DWORD)); FullscreenInputLength -= sizeof(DWORD); } __except (EXCEPTION_EXECUTE_HANDLER) { RIP("FullscreenControlSpecificVideoControl - error processing input buffer\n"); return STATUS_NOT_IMPLEMENTED; } break;
default: RIP("NtUserFullscreenControl: invalid IOCTL\n"); return STATUS_NOT_IMPLEMENTED;
}
//
// If this is a frame buffer function, that we can just deal with the
// device directly, and not send any IOCTL to the device.
//
if (ioctl == 0) { CHAR Attribute;
//
// First get the frame buffer pointer for the device.
//
PUCHAR pFrameBuf = gpFullscreenFrameBufPtr; ULONG_PTR FrameBufLen = (ULONG_PTR)gpFullscreenFrameBufLength; PCHAR_INFO pCharInfo; PCHAR_IMAGE_INFO pCharImageInfo; LPDEVMODEW pDevmode = gFullscreenGraphicsDevice.devmodeInfo; VIDEO_MODE VideoMode; BOOLEAN modeFound = FALSE; ULONG BytesReturned; ULONG i; DEVMODEW capturedDevMode;
//
// Assume success for all these operations.
//
Status = STATUS_SUCCESS;
switch(FullscreenCommand) {
case FullscreenControlSetMode:
//
// Fullscreen VGA modes require us to call the miniport driver
// directly.
//
// Lets check the VGA Device handle, which is in the first entry
//
__try { ProbeForRead(FullscreenInput, sizeof(DEVMODEW), sizeof(USHORT)); RtlCopyMemory(&capturedDevMode, FullscreenInput, sizeof(DEVMODEW)); } __except (EXCEPTION_EXECUTE_HANDLER) { RIP("Fullscreen control - error processing input/output buffer\n"); Status = STATUS_UNSUCCESSFUL; }
if ((Status != STATUS_SUCCESS) || (gFullscreenGraphicsDevice.pDeviceHandle == NULL)) { Status = STATUS_UNSUCCESSFUL; } else { //
// NOTE We know that if there is a vgacompatible device, then
// there are some text modes for it.
//
// NOTE !!!
// As a hack, lets use the mode number we stored in the DEVMODE
// a field we don't use
//
for (i = 0; i < gFullscreenGraphicsDevice.cbdevmodeInfo; i += sizeof(DEVMODEW), pDevmode += 1) {
//
// Check if this is the resolustion we are looking for.
//
if ((pDevmode->dmPelsWidth == capturedDevMode.dmPelsWidth) && (pDevmode->dmPelsHeight == capturedDevMode.dmPelsHeight) && (pDevmode->dmDisplayFlags == capturedDevMode.dmDisplayFlags) && (pDevmode->dmBitsPerPel == capturedDevMode.dmBitsPerPel) ) { //
// FullscreenInput->dwOrientation is 0.
//
VideoMode.RequestedMode = (ULONG) pDevmode->dmOrientation; modeFound = TRUE; break; } }
if (modeFound == FALSE) { RIP("ChangeDisplaySettings: Console passed in bad DEVMODE\n");
Status = STATUS_UNSUCCESSFUL; } else { //
// We have the mode number.
// Call the driver to set the mode
//
Status = GreDeviceIoControl(gFullscreenGraphicsDevice.pDeviceHandle, IOCTL_VIDEO_SET_CURRENT_MODE, &VideoMode, sizeof(VideoMode), NULL, 0, &BytesReturned);
if (NT_SUCCESS(Status)) { //
// We also map the memory so we can use it to
// process string commands from the console
//
VIDEO_MEMORY FrameBufferMap; VIDEO_MEMORY_INFORMATION FrameBufferInfo;
FrameBufferMap.RequestedVirtualAddress = NULL;
Status = GreDeviceIoControl(gFullscreenGraphicsDevice.pDeviceHandle, IOCTL_VIDEO_MAP_VIDEO_MEMORY, &FrameBufferMap, sizeof(FrameBufferMap), &FrameBufferInfo, sizeof(FrameBufferInfo), &BytesReturned);
if (NT_SUCCESS(Status)) { //
// get address of frame buffer
//
gpFullscreenFrameBufPtr = (PUCHAR) FrameBufferInfo.FrameBufferBase; gpFullscreenFrameBufLength = FrameBufferInfo.FrameBufferLength;
if (gFeFullscreenGraphicsDevice.pDeviceHandle != NULL) { FSVIDEO_MODE_INFORMATION FsVideoMode; //
// get current video mode
//
Status = GreDeviceIoControl(gFullscreenGraphicsDevice.pDeviceHandle, IOCTL_VIDEO_QUERY_CURRENT_MODE, NULL, 0, &FsVideoMode.VideoMode, sizeof(FsVideoMode.VideoMode), &BytesReturned); if (NT_SUCCESS(Status)) { FsVideoMode.VideoMemory = FrameBufferInfo;
//
// set current vide mode to full screen video driver
//
Status = GreDeviceIoControl(gFeFullscreenGraphicsDevice.pDeviceHandle, IOCTL_FSVIDEO_SET_CURRENT_MODE, &FsVideoMode, sizeof(FsVideoMode), NULL, 0, &BytesReturned); if (NT_SUCCESS(Status)) { } else { RIP("FSVGA setmode: fullscreen MODESET failed\n"); Status = STATUS_UNSUCCESSFUL; } } } } else {
RIP("Fullscreen setmode: memory mapping failed\n"); Status = STATUS_UNSUCCESSFUL; }
} else {
RIP("Fullscreen setmode: fullscreen MODESET failed\n"); Status = STATUS_UNSUCCESSFUL; } } }
break;
case FullscreenControlCopyFrameBuffer:
TRACE_SWITCH(("Switching: FullscreenControlCopyFrameBuffer\n"));
if ( VERIFY_RANGE(FullscreenInput, FullscreenInputLength, FrameBufLen) && VERIFY_RANGE(FullscreenOutput, FullscreenInputLength, FrameBufLen)) { RtlMoveMemory(pFrameBuf + (ULONG_PTR)FullscreenOutput, pFrameBuf + (ULONG_PTR)FullscreenInput, FullscreenInputLength); } else { RIP("Fullscreen control - error processing input/output buffer\n"); } break;
case FullscreenControlCopyFrameBufferDB:
TRACE_SWITCH(("Switching: FullscreenControlCopyFrameBufferDB\n"));
{ FSCNTL_SCREEN_INFO FsCntlSrc; FSCNTL_SCREEN_INFO FsCntlDest; ULONG_PTR offsetSrc, offsetDst, len;
__try { ProbeForRead(FullscreenInput, sizeof(FSCNTL_SCREEN_INFO), sizeof(USHORT)); RtlCopyMemory(&FsCntlSrc, FullscreenInput, sizeof(FSCNTL_SCREEN_INFO));
ProbeForRead(FullscreenOutput, sizeof(FSCNTL_SCREEN_INFO), sizeof(USHORT)); RtlCopyMemory(&FsCntlDest, FullscreenOutput, sizeof(FSCNTL_SCREEN_INFO)); } __except (EXCEPTION_EXECUTE_HANDLER) { RIP("Fullscreen control - error processing input/output buffer\n"); }
offsetDst = SCREEN_BUFFER_POINTER(0, FsCntlDest.Position.Y, FsCntlDest.ScreenSize.X, sizeof(VGA_CHAR)); offsetSrc = SCREEN_BUFFER_POINTER(0, FsCntlSrc.Position.Y, FsCntlSrc.ScreenSize.X, sizeof(VGA_CHAR)); len = FsCntlSrc.nNumberOfChars * sizeof(VGA_CHAR); if ( VERIFY_RANGE(offsetDst, len, FrameBufLen) && VERIFY_RANGE(offsetSrc, len, FrameBufLen)) { RtlMoveMemory(pFrameBuf + offsetDst, pFrameBuf + offsetSrc, len); } else { RIP("Fullscreen control - error processing input/output buffer\n"); }
} break;
case FullscreenControlReadFromFrameBuffer:
TRACE_SWITCH(("Switching: FullscreenControlReadFromFrameBuffer\n"));
FullscreenInputLength = (FullscreenInputLength / 2) * 2; if (VERIFY_RANGE(FullscreenInput, FullscreenInputLength, FrameBufLen)) { __try { ProbeForWrite(FullscreenOutput, sizeof(CHAR_INFO) * FullscreenInputLength/2, sizeof(UCHAR));
pFrameBuf += (ULONG_PTR) FullscreenInput; pCharInfo = (PCHAR_INFO) FullscreenOutput;
while (FullscreenInputLength) { pCharInfo->Char.AsciiChar = *pFrameBuf++; pCharInfo->Attributes = *pFrameBuf++; FullscreenInputLength -= 2; pCharInfo++; } } __except (EXCEPTION_EXECUTE_HANDLER) { RIP("Fullscreen control - error processing input/output buffer\n"); } } else { RIP("Fullscreen control - error processing input/output buffer\n"); }
break;
case FullscreenControlWriteToFrameBuffer:
TRACE_SWITCH(("Switching: FullscreenControlWriteToFrameBuffer\n"));
FullscreenInputLength = (FullscreenInputLength / 4) * 4; if (VERIFY_RANGE(FullscreenOutput, FullscreenInputLength/2, FrameBufLen)) { __try { ProbeForRead(FullscreenInput, sizeof(CHAR_INFO) * FullscreenInputLength/4, sizeof(UCHAR));
pFrameBuf += (ULONG_PTR) FullscreenOutput; pCharInfo = (PCHAR_INFO) FullscreenInput;
while (FullscreenInputLength) { *pFrameBuf++ = pCharInfo->Char.AsciiChar; *pFrameBuf++ = (UCHAR) (pCharInfo->Attributes); FullscreenInputLength -= 4; pCharInfo++; } } __except (EXCEPTION_EXECUTE_HANDLER) { RIP("Fullscreen control - error processing input/output buffer\n"); } } else { RIP("Fullscreen control - error processing input/output buffer\n"); }
break;
case FullscreenControlWriteToFrameBufferDB:
TRACE_SWITCH(("Switching: FullscreenControlWriteToFrameBufferDB\n"));
{ FSCNTL_SCREEN_INFO FsCntl; ULONG_PTR offset;
__try { ProbeForRead(FullscreenOutput, sizeof(FSCNTL_SCREEN_INFO), sizeof(USHORT)); RtlCopyMemory(&FsCntl, FullscreenOutput, sizeof(FSCNTL_SCREEN_INFO));
ProbeForRead(FullscreenInput, sizeof(CHAR_IMAGE_INFO) * FsCntl.nNumberOfChars, sizeof(USHORT)); } __except (EXCEPTION_EXECUTE_HANDLER) { RIP("Fullscreen control - error processing input/output buffer\n"); }
offset = SCREEN_BUFFER_POINTER(FsCntl.Position.X, FsCntl.Position.Y, FsCntl.ScreenSize.X, sizeof(VGA_CHAR)); if (VERIFY_RANGE(offset, FsCntl.nNumberOfChars*2, FrameBufLen)) { pFrameBuf += offset; pCharImageInfo = (PCHAR_IMAGE_INFO) FullscreenInput;
while (FsCntl.nNumberOfChars) { TranslateOutputToOem(&pCharImageInfo->CharInfo, &pCharImageInfo->CharInfo, 1); *pFrameBuf++ = pCharImageInfo->CharInfo.Char.AsciiChar; *pFrameBuf++ = (UCHAR) (pCharImageInfo->CharInfo.Attributes);
FsCntl.nNumberOfChars--; pCharImageInfo++; } } else { RIP("Fullscreen control - error processing input/output buffer\n"); }
} break;
case FullscreenControlReverseMousePointer:
TRACE_SWITCH(("Switching: FullscreenControlReverseMousePointer\n"));
if (VERIFY_RANGE(FullscreenInput, 1, FrameBufLen)) { pFrameBuf += (ULONG_PTR) FullscreenInput;
Attribute = (*(pFrameBuf + 1) & 0xF0) >> 4; Attribute |= (*(pFrameBuf + 1) & 0x0F) << 4; *(pFrameBuf + 1) = Attribute; } else { RIP("Fullscreen control - error processing input/output buffer\n"); }
break;
case FullscreenControlReverseMousePointerDB:
TRACE_SWITCH(("Switching: FullscreenControlReverseMousePointerDB\n"));
{ FSVIDEO_REVERSE_MOUSE_POINTER MousePointer; ULONG_PTR offset;
__try { ProbeForRead(FullscreenInput, sizeof(FSVIDEO_REVERSE_MOUSE_POINTER), sizeof(USHORT)); RtlCopyMemory(&MousePointer, FullscreenInput, sizeof(FSVIDEO_REVERSE_MOUSE_POINTER)); } __except (EXCEPTION_EXECUTE_HANDLER) { RIP("Fullscreen control - error processing input/output buffer\n"); }
offset = SCREEN_BUFFER_POINTER(MousePointer.Screen.Position.X, MousePointer.Screen.Position.Y, MousePointer.Screen.ScreenSize.X, sizeof(VGA_CHAR));
if (VERIFY_RANGE(offset, 1, FrameBufLen)) { pFrameBuf += offset; Attribute = (*(pFrameBuf + 1) & 0xF0) >> 4; Attribute |= (*(pFrameBuf + 1) & 0x0F) << 4; *(pFrameBuf + 1) = Attribute; } else { RIP("Fullscreen control - error processing input/output buffer\n"); } } break; } } else if (ioctl == IOCTL_FSVIDEO_COPY_FRAME_BUFFER) { PFSVIDEO_COPY_FRAME_BUFFER CopyFrameBuffer;
cCapBuffer = sizeof(FSVIDEO_COPY_FRAME_BUFFER); pCapBuffer = PALLOCNOZ(cCapBuffer, GDITAG_FULLSCREEN);
if (!pCapBuffer) { Status = STATUS_INSUFFICIENT_RESOURCES; } else { CopyFrameBuffer = (PFSVIDEO_COPY_FRAME_BUFFER) pCapBuffer; __try { ProbeForRead(FullscreenInput, sizeof(FSCNTL_SCREEN_INFO), sizeof(USHORT)); RtlCopyMemory(&CopyFrameBuffer->SrcScreen, FullscreenInput, sizeof(FSCNTL_SCREEN_INFO));
ProbeForRead(FullscreenOutput, sizeof(FSCNTL_SCREEN_INFO), sizeof(USHORT)); RtlCopyMemory(&CopyFrameBuffer->DestScreen, FullscreenOutput, sizeof(FSCNTL_SCREEN_INFO)); } __except (EXCEPTION_EXECUTE_HANDLER) { RIP("Fullscreen control - error processing input/output buffer\n"); }
Status = GreDeviceIoControl(gFeFullscreenGraphicsDevice.pDeviceHandle, ioctl, pCapBuffer, cCapBuffer, NULL, 0, &BytesReturned); } } else if (ioctl == IOCTL_FSVIDEO_WRITE_TO_FRAME_BUFFER) { PFSVIDEO_WRITE_TO_FRAME_BUFFER WriteFrameBuffer;
cCapBuffer = sizeof(FSVIDEO_WRITE_TO_FRAME_BUFFER) + FullscreenInputLength; pCapBuffer = PALLOCNOZ(cCapBuffer, GDITAG_FULLSCREEN);
if (!pCapBuffer) { Status = STATUS_INSUFFICIENT_RESOURCES; } else { WriteFrameBuffer = (PFSVIDEO_WRITE_TO_FRAME_BUFFER) pCapBuffer; __try { ProbeForRead(FullscreenInput, FullscreenInputLength, sizeof(USHORT)); WriteFrameBuffer->SrcBuffer = (PCHAR_IMAGE_INFO)((PBYTE)pCapBuffer + sizeof(FSVIDEO_WRITE_TO_FRAME_BUFFER)); RtlCopyMemory(WriteFrameBuffer->SrcBuffer, FullscreenInput, FullscreenInputLength);
ProbeForRead(FullscreenOutput, sizeof(FSCNTL_SCREEN_INFO), sizeof(USHORT)); RtlCopyMemory(&WriteFrameBuffer->DestScreen, FullscreenOutput, sizeof(FSCNTL_SCREEN_INFO)); } __except (EXCEPTION_EXECUTE_HANDLER) { RIP("Fullscreen control - error processing input/output buffer\n"); }
Status = GreDeviceIoControl(gFeFullscreenGraphicsDevice.pDeviceHandle, ioctl, pCapBuffer, cCapBuffer, NULL, 0, &BytesReturned); } } else if (ioctl == IOCTL_FSVIDEO_REVERSE_MOUSE_POINTER) { PFSVIDEO_REVERSE_MOUSE_POINTER MouseFrameBuffer;
cCapBuffer = sizeof(FSVIDEO_REVERSE_MOUSE_POINTER); pCapBuffer = PALLOCNOZ(cCapBuffer, GDITAG_FULLSCREEN);
if (!pCapBuffer) { Status = STATUS_INSUFFICIENT_RESOURCES; } else { MouseFrameBuffer = (PFSVIDEO_REVERSE_MOUSE_POINTER) pCapBuffer; __try { ProbeForRead(FullscreenInput, sizeof(FSVIDEO_REVERSE_MOUSE_POINTER), sizeof(USHORT)); RtlCopyMemory(MouseFrameBuffer, FullscreenInput, sizeof(FSVIDEO_REVERSE_MOUSE_POINTER)); } __except (EXCEPTION_EXECUTE_HANDLER) { RIP("Fullscreen control - error processing input/output buffer\n"); }
Status = GreDeviceIoControl(gFeFullscreenGraphicsDevice.pDeviceHandle, ioctl, pCapBuffer, cCapBuffer, NULL, 0, &BytesReturned); } } else if (ioctl == IOCTL_FSVIDEO_SET_SCREEN_INFORMATION) { PFSVIDEO_SCREEN_INFORMATION ScreenInformation;
cCapBuffer = sizeof(FSVIDEO_SCREEN_INFORMATION); pCapBuffer = PALLOCNOZ(cCapBuffer, GDITAG_FULLSCREEN);
if (!pCapBuffer) { Status = STATUS_INSUFFICIENT_RESOURCES; } else { ScreenInformation = (PFSVIDEO_SCREEN_INFORMATION) pCapBuffer; __try { ProbeForRead(FullscreenInput, sizeof(FSVIDEO_SCREEN_INFORMATION), sizeof(USHORT)); RtlCopyMemory(ScreenInformation, FullscreenInput, sizeof(FSVIDEO_SCREEN_INFORMATION)); } __except (EXCEPTION_EXECUTE_HANDLER) { RIP("Fullscreen control - error processing input/output buffer\n"); }
Status = GreDeviceIoControl(gFeFullscreenGraphicsDevice.pDeviceHandle, ioctl, pCapBuffer, cCapBuffer, NULL, 0, &BytesReturned); } } else if (ioctl == IOCTL_FSVIDEO_SET_CURSOR_POSITION) { PFSVIDEO_CURSOR_POSITION FsCursorPosition;
cCapBuffer = sizeof(FSVIDEO_CURSOR_POSITION); pCapBuffer = PALLOCNOZ(cCapBuffer, GDITAG_FULLSCREEN);
if (!pCapBuffer) { Status = STATUS_INSUFFICIENT_RESOURCES; } else { FsCursorPosition = (PFSVIDEO_CURSOR_POSITION) pCapBuffer; __try { ProbeForRead(FullscreenInput, sizeof(FSVIDEO_CURSOR_POSITION), sizeof(USHORT)); RtlCopyMemory(FsCursorPosition, FullscreenInput, sizeof(FSVIDEO_CURSOR_POSITION)); } __except (EXCEPTION_EXECUTE_HANDLER) { RIP("Fullscreen control - error processing input/output buffer\n"); }
Status = GreDeviceIoControl(gFeFullscreenGraphicsDevice.pDeviceHandle, ioctl, pCapBuffer, cCapBuffer, pCapBuffer, cCapBuffer, &BytesReturned);
if (!NT_SUCCESS(Status)) { /*
* If full screen video driver returns error, * do calls VGA mini port driver on this. */ ioctl = IOCTL_VIDEO_SET_CURSOR_POSITION; Status = GreDeviceIoControl(gFullscreenGraphicsDevice.pDeviceHandle, ioctl, &FsCursorPosition->Coord, sizeof(VIDEO_CURSOR_POSITION), &FsCursorPosition->Coord, sizeof(VIDEO_CURSOR_POSITION), &BytesReturned); }
if (cCapBuffer && FullscreenOutputLength && NT_SUCCESS(Status)) { __try { ProbeForWrite(FullscreenOutputLength, sizeof(ULONG), sizeof(UCHAR)); *FullscreenOutputLength = BytesReturned;
ProbeForWrite(FullscreenOutput, BytesReturned, sizeof(UCHAR)); RtlCopyMemory(FullscreenOutput, pCapBuffer, BytesReturned); } __except (EXCEPTION_EXECUTE_HANDLER) { RIP("Fullscreen control - error processing output buffer\n"); } } } } else { //
// For all real operations, check the output buffer parameters
//
if ((FullscreenOutput == NULL) != (FullscreenOutputLength == NULL)) { RIP("Fullscreen control - inconsistent output buffer information\n"); Status = STATUS_INVALID_PARAMETER_4; } else { //
// We must now capture the buffers so they can be safely passed down to the
// video miniport driver
//
cCapBuffer = FullscreenInputLength;
if (FullscreenOutputLength) { __try { ProbeForRead(FullscreenOutputLength, sizeof(ULONG), sizeof(UCHAR)); cCapBuffer = max(cCapBuffer,*FullscreenOutputLength); } __except (EXCEPTION_EXECUTE_HANDLER) { RIP("Fullscreen control - error processing input buffer\n"); } }
if (cCapBuffer) { pCapBuffer = PALLOCNOZ(cCapBuffer, GDITAG_FULLSCREEN);
if (!pCapBuffer) { Status = STATUS_INSUFFICIENT_RESOURCES; } else { __try { ProbeForRead(FullscreenInput, FullscreenInputLength, sizeof(UCHAR)); RtlCopyMemory(pCapBuffer, FullscreenInput, FullscreenInputLength); } __except (EXCEPTION_EXECUTE_HANDLER) { RIP("Fullscreen control - error processing input buffer\n"); } } }
//
// For now, the IOCTL will always be sent to the VGA compatible device.
// We have a global for the handle to this device.
//
if (NT_SUCCESS(Status)) { if (gFeFullscreenGraphicsDevice.pDeviceHandle != NULL && ioctl == IOCTL_VIDEO_SET_CURSOR_ATTR) { Status = GreDeviceIoControl(gFeFullscreenGraphicsDevice.pDeviceHandle, ioctl, pCapBuffer, cCapBuffer, pCapBuffer, cCapBuffer, &BytesReturned); if (!NT_SUCCESS(Status)) { /*
* If full screen video driver returns error, * do calls VGA mini port driver on this. */ Status = GreDeviceIoControl(gFullscreenGraphicsDevice.pDeviceHandle, ioctl, pCapBuffer, cCapBuffer, pCapBuffer, cCapBuffer, &BytesReturned); }
} else { Status = GreDeviceIoControl(gFullscreenGraphicsDevice.pDeviceHandle, ioctl, pCapBuffer, cCapBuffer, pCapBuffer, cCapBuffer, &BytesReturned);
TRACE_SWITCH(("Switching: FullscreenControl: IOCTL status is %08lx\n", Status));
if (cCapBuffer && FullscreenOutputLength && NT_SUCCESS(Status)) { __try { *FullscreenOutputLength = BytesReturned;
ProbeForWrite(FullscreenOutput, BytesReturned, sizeof(UCHAR)); RtlCopyMemory(FullscreenOutput, pCapBuffer, BytesReturned); } __except (EXCEPTION_EXECUTE_HANDLER) { RIP("Fullscreen control - error processing output buffer\n"); } } } } } }
if (pCapBuffer) { VFREEMEM(pCapBuffer); }
return (Status); }
/**************************************************************************\
* DrvLogDisplayDriverEvent * * We will save a piece of data in the registry so that winlogon can find * it and put up a popup if an error occured. * * CRIT not needed * * 03-Mar-1993 andreva created \**************************************************************************/
VOID DrvLogDisplayDriverEvent( DISP_DRIVER_LOG MsgType ) { HANDLE hkRegistry; OBJECT_ATTRIBUTES ObjectAttributes; UNICODE_STRING RegistryPath; UNICODE_STRING UnicodeString;
NTSTATUS Status; DWORD dwValue = 1;
#ifdef _HYDRA_
/*
* Whatever happens on a Session, don't affect the console. */ if ( !G_fConsole ) return; #endif
RtlInitUnicodeString(&UnicodeString, L"");
switch (MsgType) { case MsgInvalidUsingDefaultMode:
//RtlInitUnicodeString(&UnicodeString, L"DefaultMode");
break;
case MsgInvalidDisplayDriver:
//RtlInitUnicodeString(&UnicodeString, L"MissingDisplayDriver");
break;
case MsgInvalidOldDriver:
RtlInitUnicodeString(&UnicodeString, L"OldDisplayDriver"); break;
case MsgInvalidDisplay16Colors:
//RtlInitUnicodeString(&UnicodeString, L"16ColorMode");
break;
case MsgInvalidDisplayMode:
//RtlInitUnicodeString(&UnicodeString, L"BadMode");
break;
case MsgInvalidConfiguration:
//RtlInitUnicodeString(&UnicodeString, L"InvalidConfiguration");
break;
default:
WARNING("DrvLogDisplayDriverEvent: Invalid error message\n"); return;
}
if (UnicodeString.Length != 0) {
RtlInitUnicodeString(&RegistryPath, L"\\Registry\\Machine\\System\\CurrentControlSet\\" L"Control\\GraphicsDrivers\\InvalidDisplay");
InitializeObjectAttributes(&ObjectAttributes, &RegistryPath, OBJ_CASE_INSENSITIVE|OBJ_KERNEL_HANDLE, NULL, NULL);
Status = ZwCreateKey(&hkRegistry, MAXIMUM_ALLOWED, &ObjectAttributes, 0L, NULL, REG_OPTION_VOLATILE, NULL);
if (NT_SUCCESS(Status)) { //
// Write the optional data value under the key.
//
(VOID) ZwSetValueKey(hkRegistry, &UnicodeString, 0, REG_DWORD, &dwValue, sizeof(DWORD));
(VOID)ZwCloseKey(hkRegistry); } } }
/******************************Member*Function*****************************\
* bEARecovery * * This function checks to see if the EA Recovery mechanism is enabled * in the registry. * \**************************************************************************/
#define EARecovery L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Watchdog\\Display"
BOOL bEARecovery(VOID) { ULONG ulDefault = 0; ULONG ulEaRecovery = 0; ULONG ulFullRecovery = 0; RTL_QUERY_REGISTRY_TABLE queryTable[] = { {NULL, RTL_QUERY_REGISTRY_DIRECT, L"EaRecovery", &ulEaRecovery, REG_DWORD, &ulDefault, sizeof(ULONG)}, {NULL, RTL_QUERY_REGISTRY_DIRECT, L"FullRecovery", &ulFullRecovery, REG_DWORD, &ulDefault, sizeof(ULONG)}, {NULL, 0, NULL} };
RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE, EARecovery, queryTable, NULL, NULL);
return ulEaRecovery; }
extern PFN WatchdogTable[INDEX_LAST];
/******************************Member*Function*****************************\
* bFillFunctionTable * * Fills the dispatch table called by the system with a set of routines * which wrap the final driver entry points. This is done to allow us to * hook each of these calls. * \**************************************************************************/
BOOL bFillWatchdogTable( PFN *Dst, PFN *Src, LDEVTYPE ldevType) { ULONG i;
//
// This is required. At least for the final entries in the
// array which are the DX entry points.
//
RtlZeroMemory(Dst, INDEX_DD_LAST * sizeof(PFN));
//
// If EA recovery is enabled, and this is a display driver then
// add the watchdog hooking code. Note, we really don't want to
// hook remote drivers such as RDPDD. Unfortunately we don't know
// what driver is a remote driver and what isn't. There is a
// GCAPS2_REMOTEDRIVER flag that indicates this at DrvEnablePDEV time,
// but that is really to late.
//
// Fortunately this flag currently just indicates whether or not it
// is safe to hook DrvNineGrid. So I could just check for the existance
// of the DrvNineGrid function, and use that as a "remote driver" flag.
//
// Theoretically no "real" display driver is supposed to hook this
// function, so we shouldn't have to worry about a non-remote driver
// losing EA recovery support.
//
if (bEARecovery() && (ldevType == LDEV_DEVICE_DISPLAY) && (Src[INDEX_DrvNineGrid] == NULL)) {
for (i=0; i<INDEX_LAST; i++) {
if (*Src && WatchdogTable[i]) { *Dst = WatchdogTable[i]; } else { *Dst = *Src; }
Src++; Dst++; }
} else {
RtlCopyMemory(Dst, Src, INDEX_LAST * sizeof(PFN)); }
return TRUE; }
/******************************Member*Function*****************************\
* bFillFunctionTable * * Fills the dispatch table of the LDEV with function pointers from the * driver. * \**************************************************************************/
BOOL bFillFunctionTable( PDRVFN pdrvfn, ULONG cdrvfn, PFN* ppfnTable) { //
// fill with zero pointers to avoid possibility of accessing
// incorrect fields later
//
RtlZeroMemory(ppfnTable, INDEX_LAST*sizeof(PFN));
//
// Copy driver functions into our table.
//
while (cdrvfn--) { //
// Check the range of the index.
//
if (pdrvfn->iFunc >= INDEX_LAST) { return(FALSE); }
//
// Copy the pointer.
//
ppfnTable[pdrvfn->iFunc] = pdrvfn->pfn; pdrvfn++; }
return(TRUE); }
/******************************Member*Function*****************************\
* ldevbFillTable (ded) * * Fills the dispatch table of the LDEV with function pointers from the * driver. Checks that the required functions are present. * \**************************************************************************/
static const ULONG aiFuncRequired[] = { INDEX_DrvEnablePDEV, INDEX_DrvCompletePDEV, INDEX_DrvDisablePDEV, };
static const ULONG aiFuncPairs[][2] = { {INDEX_DrvCreateDeviceBitmap, INDEX_DrvDeleteDeviceBitmap}, {INDEX_DrvMovePointer, INDEX_DrvSetPointerShape} };
static const ULONG aiFuncRequiredFD[] = { INDEX_DrvQueryFont, INDEX_DrvQueryFontTree, INDEX_DrvQueryFontData, INDEX_DrvQueryFontCaps, INDEX_DrvLoadFontFile, INDEX_DrvUnloadFontFile, INDEX_DrvQueryFontFile };
BOOL ldevFillTable( PLDEV pldev, DRVENABLEDATA *pded, LDEVTYPE ldt) { //
// Get local copies of ded info and a pointer to the dispatch table.
//
ULONG cLeft = pded->c; PDRVFN pdrvfn = pded->pdrvfn; PFN *ppfnTable = pldev->apfnDriver;
//
// Store the driver version in the LDEV
//
pldev->ulDriverVersion = pded->iDriverVersion;
if (!bFillFunctionTable(pdrvfn, cLeft, ppfnTable)) { ASSERTGDI(FALSE,"ldevFillTable: bogus function index\n"); return(FALSE); }
//
// Check for required driver functions.
//
cLeft = sizeof(aiFuncRequired) / sizeof(ULONG); while (cLeft--) { if (ppfnTable[aiFuncRequired[cLeft]] == (PFN) NULL) { ASSERTGDI(FALSE,"ldevFillTable: a required function is missing from driver\n"); return(FALSE); } }
//
// Check for required font functions.
//
if (pldev->ldevType == LDEV_FONT) { cLeft = sizeof(aiFuncRequiredFD) / sizeof(ULONG); while (cLeft--) { if (ppfnTable[aiFuncRequiredFD[cLeft]] == (PFN) NULL) { ASSERTGDI(FALSE,"FillTable(): a required FD function is missing\n"); return(FALSE); } } }
//
// Check for functions that come in pairs.
//
cLeft = sizeof(aiFuncPairs) / sizeof(ULONG) / 2; while (cLeft--) { //
// Make sure that either both functions are hooked or both functions
// are not hooked.
//
if ((ppfnTable[aiFuncPairs[cLeft][0]] == (PFN) NULL) != (ppfnTable[aiFuncPairs[cLeft][1]] == (PFN) NULL)) { ASSERTGDI(FALSE,"ldevFillTable: one of pair of functions is missing from driver\n"); return(FALSE); } }
//
// The driver supplied function table looks good. Create another
// table which mirrors this one with new functions that can add
// monitoring code.
//
if (!bFillWatchdogTable((PFN*)&pldev->apfn, (PFN*)&pldev->apfnDriver, ldt)) {
return FALSE; }
return(TRUE); }
/******************************Member*Function*****************************\
* ldevLoadInternal * * Enable one of the statically linked font drivers via the LDEV. * \**************************************************************************/
PLDEV ldevLoadInternal( PFN pfnEnable, LDEVTYPE ldt) { GDIFunctionID(ldevLoadInternal);
PLDEV pldev;
TRACE_INIT(("ldevLoadInternal ENTERING\n"));
GreAcquireSemaphoreEx(ghsemDriverMgmt, SEMORDER_DRIVERMGMT, NULL);
//
// Allocate memory for the LDEV.
//
pldev = (PLDEV) PALLOCMEM(sizeof(LDEV), GDITAG_LDEV);
if (pldev) { //
// Call the Enable entry point.
//
DRVENABLEDATA ded;
if ((!((* (PFN_DrvEnableDriver) pfnEnable) (ENGINE_VERSION, sizeof(DRVENABLEDATA), &ded))) || (!ldevFillTable(pldev, &ded, ldt))) { VFREEMEM(pldev); pldev = NULL; } else { pldev->ldevType = ldt; pldev->cldevRefs = 1; pldev->bThreadStuck = FALSE;
//
// Initialize the rest of the LDEV.
//
if (gpldevDrivers) { gpldevDrivers->pldevPrev = pldev; }
pldev->pldevNext = gpldevDrivers; pldev->pldevPrev = NULL;
gpldevDrivers = pldev;
//
// Since this driver is statically linked in, there is no name or
// MODOBJ.
//
pldev->pGdiDriverInfo = NULL;
TRACE_INIT(("ldevLoadInternal: SUCCESS loaded static driver (font or DDML)\n")); } }
GreReleaseSemaphoreEx(ghsemDriverMgmt);
return pldev; }
/******************************Member*Function*****************************\
* ldevLoadImage * * Examines the list of loaded drivers and returns library handles (if any). * * Updates the ref cnt on driver usage. * * If the driver is not already loaded, a node is created and the dll is * loaded in the kernel. \**************************************************************************/
PLDEV ldevLoadImage( LPWSTR pwszDriver, BOOL bImage, PBOOL pbAlreadyLoaded, BOOL LoadInSessionSpace) {
PSYSTEM_GDI_DRIVER_INFORMATION pGdiDriverInfo = NULL; PLDEV pldev = NULL;
UNICODE_STRING usDriverName; PLDEV pldevList;
NTSTATUS Status; BOOLEAN OldHardErrorMode; BOOL bSearchAgain, bLoadAgain; BOOL bResetDriverNameToSystem32;
TRACE_INIT(("ldevLoadImage called on Image %ws\n", pwszDriver));
*pbAlreadyLoaded = FALSE;
//
// Only append the .dll if it's NOT an image.
//
if (MakeSystemRelativePath(pwszDriver, &usDriverName, !bImage)) { bSearchAgain = TRUE;
searchagain:
//
// Check both lists of drivers.
//
pldevList = gpldevDrivers;
TRACE_INIT(("ldevLoadImage - search for existing image %ws\n", usDriverName.Buffer));
while (pldevList != NULL) { //
// If there is a valid driver image, and if the types are compatible.
// bImage == TRUE means load an image, while bImage == FALSE means
// anything else (for now)
//
if ((pldevList->pGdiDriverInfo) && ((pldevList->ldevType == LDEV_IMAGE) == bImage)) { //
// Do a case insensitive compare since the printer driver name
// can come from different locations.
//
if (RtlEqualUnicodeString(&(pldevList->pGdiDriverInfo->DriverName), &usDriverName, TRUE)) { //
// If it's already loaded, increment the ref count
// and return that pointer.
//
TRACE_INIT(("ldevLoadImage found image. Inc ref count\n"));
pldevList->cldevRefs += 1;
*pbAlreadyLoaded = TRUE;
pldev = pldevList; break; } }
pldevList = pldevList->pldevNext; }
if (pldev == NULL) { if (!LoadInSessionSpace) { // If not a session load see if the Driver is from the
// \SystemRoot\System32\Drivers subdir. Ex dxapi.sys
if (bSearchAgain) { bSearchAgain = FALSE; PWSTR pOldBuffer = usDriverName.Buffer; bResetDriverNameToSystem32 = FALSE; if (MakeSystemDriversRelativePath(pwszDriver, &usDriverName, !bImage)) { bResetDriverNameToSystem32 = TRUE; VFREEMEM(pOldBuffer); goto searchagain; } }
if (bResetDriverNameToSystem32) { PWSTR pOldBuffer = usDriverName.Buffer; if (!MakeSystemRelativePath(pwszDriver, &usDriverName, !bImage)) { goto done; } VFREEMEM(pOldBuffer); } }
TRACE_INIT(("ldevLoadImage - attempting to load new image\n"));
pGdiDriverInfo = (PSYSTEM_GDI_DRIVER_INFORMATION) PALLOCNOZ(sizeof(SYSTEM_GDI_DRIVER_INFORMATION), GDITAG_LDEV);
pldev = (PLDEV) PALLOCMEM(sizeof(LDEV), GDITAG_LDEV);
bLoadAgain = TRUE;
if (pGdiDriverInfo && pldev) { loadagain: pGdiDriverInfo->DriverName = usDriverName;
if (LoadInSessionSpace) { Status = ZwSetSystemInformation(SystemLoadGdiDriverInformation, pGdiDriverInfo, sizeof(SYSTEM_GDI_DRIVER_INFORMATION)); } else { Status = ZwSetSystemInformation(SystemLoadGdiDriverInSystemSpace, pGdiDriverInfo, sizeof(SYSTEM_GDI_DRIVER_INFORMATION)); }
//
// If we get an OBJECT_NAME_NOT_FOUND we handle it the
// following way:
//
// (1) If its a session load then its an error.
//
// (2) If it is a non session load then we try again to load
// the driver from System32\Drivers subdirectory. We do
// this because DX can ask us to load dxapi.sys and
// it lives in drivers subdir.
//
// In general we should never get IMAGE_ALREADY_LOADED because
// we check for loaded images above.
//
// If we do get this status we handle them in the following
// manner:
//
// (1) If we get IMAGE_ALREADY_LOADED when LoadInSessionSpace
// is true it is an error. We fail the ldev creation. Why ?
// because the image may be loaded in another session
// space and not in ours.
//
// (2) If we get IMAGE_ALREADY_LOADED when LoadInSessionSpace
// is false (i.e load in non session space) we will fail
// to create the ldev for modules (dll/sys) that win32k.sys
// does not statically link to. Why ? because such modules
// can get unloaded without win32k.sys knowing about it.
// By makeing sure we succeed only statically linked
// modules we are gauranteed they wont get unloaded
// behind our back because of our static link dependancy.
// This also means for such ldevs we cant unload them
// in ldevUnloadImage's ZwSetSystemInformation. A
// bStaticImportLink BOOL has been added to the LDEV to
// handle this case.
//
if ((NT_SUCCESS( Status ))) { addstaticimport: TRACE_INIT(("ldevLoadImage SUCCESS with HANDLE %08lx\n", (ULONG_PTR)pGdiDriverInfo));
pldev->pGdiDriverInfo = pGdiDriverInfo; pldev->bArtificialIncrement = FALSE; pldev->cldevRefs = 1; pldev->bThreadStuck = FALSE;
// Assume image for now.
pldev->ldevType = LDEV_IMAGE;
pldev->ulDriverVersion = (ULONG) -1;
if (gpldevDrivers) { gpldevDrivers->pldevPrev = pldev; }
pldev->pldevNext = gpldevDrivers; pldev->pldevPrev = NULL;
gpldevDrivers = pldev;
//
// We exit with all resources allocated, after leaving the
// semaphore.
//
return (pldev); } else { if (!LoadInSessionSpace) { if (Status == STATUS_OBJECT_NAME_NOT_FOUND) { if(bLoadAgain) { bLoadAgain = FALSE;
PWSTR pOldBuffer = usDriverName.Buffer; if (MakeSystemDriversRelativePath(pwszDriver, &usDriverName, !bImage)) { VFREEMEM(pOldBuffer); goto loadagain; } } }
if (Status == STATUS_IMAGE_ALREADY_LOADED) { //
// We allow this load to work only if the module is
// in win32k.sys static import lib list.
//
RTL_PROCESS_MODULES ModuleInformation; DWORD cbModuleInformation; DWORD ReturnedLength; PRTL_PROCESS_MODULES pModuleInformation = 0; DWORD i; ANSI_STRING asDriver; UNICODE_STRING uTmp; BOOL bFoundDriver = FALSE; BOOL bFreeAsDriver = FALSE; WCHAR *pwszDriverFileName = 0;
pwszDriverFileName = wcsrchr(pwszDriver,L'\\');
if (pwszDriverFileName) pwszDriverFileName++; else pwszDriverFileName = pwszDriver;
RtlInitUnicodeString(&uTmp, pwszDriverFileName);
Status = RtlUnicodeStringToAnsiString(&asDriver,&uTmp,TRUE);
//
// 1) Locate asDriver name in system Module list:
//
if (NT_SUCCESS(Status)) { bFreeAsDriver = TRUE;
Status = ZwQuerySystemInformation(SystemModuleInformation, &ModuleInformation, sizeof(ModuleInformation), &ReturnedLength); if (NT_SUCCESS(Status) || (Status == STATUS_INFO_LENGTH_MISMATCH)) { cbModuleInformation = offsetof(RTL_PROCESS_MODULES, Modules); cbModuleInformation += ModuleInformation.NumberOfModules * sizeof(RTL_PROCESS_MODULE_INFORMATION);
pModuleInformation = (PRTL_PROCESS_MODULES)PALLOCNOZ(cbModuleInformation, 'pmtG');
if (pModuleInformation) { Status = ZwQuerySystemInformation(SystemModuleInformation, pModuleInformation, cbModuleInformation, &ReturnedLength); if (NT_SUCCESS(Status)) { for (i = 0; i < ModuleInformation.NumberOfModules; i++) { CHAR *FullPathName = (CHAR*)(pModuleInformation->Modules[i].FullPathName); USHORT OffsetToFileName = pModuleInformation->Modules[i].OffsetToFileName;
if(!_strnicmp(&FullPathName[OffsetToFileName], asDriver.Buffer, asDriver.Length)) { bFoundDriver = TRUE; break; } } } } } }
//
// 2) Found it in System Module list? then locate it in win32k.sys static import list
//
if (bFoundDriver) { bFoundDriver = FALSE;
PIMAGE_IMPORT_DESCRIPTOR ImportDescriptor; ULONG ImportSize; PSZ ImportName;
ImportDescriptor = (PIMAGE_IMPORT_DESCRIPTOR) RtlImageDirectoryEntryToData(gpvWin32kImageBase, TRUE, IMAGE_DIRECTORY_ENTRY_IMPORT, &ImportSize); while (ImportDescriptor && ImportDescriptor->Name && ImportDescriptor->OriginalFirstThunk) { ImportName = (PSZ)((PCHAR)gpvWin32kImageBase + ImportDescriptor->Name);
if (!_strnicmp(ImportName, asDriver.Buffer, asDriver.Length)) { bFoundDriver = TRUE; break; }
ImportDescriptor += 1; } }
//
// 3) Found it in both system Module list and win32k.sys static import list ?
// then gather GDISystemInformation and add pldev to gpLdevList:
if (bFoundDriver) { PVOID ImageBaseAddress = pModuleInformation->Modules[i].ImageBase; ULONG_PTR EntryPoint; ULONG Size;
pGdiDriverInfo->ExportSectionPointer = (PIMAGE_EXPORT_DIRECTORY) RtlImageDirectoryEntryToData(ImageBaseAddress, TRUE, IMAGE_DIRECTORY_ENTRY_EXPORT, &Size);
PIMAGE_NT_HEADERS NtHeaders = RtlImageNtHeader(ImageBaseAddress); EntryPoint = NtHeaders->OptionalHeader.AddressOfEntryPoint; EntryPoint += (ULONG_PTR)ImageBaseAddress;
pGdiDriverInfo->ImageAddress = ImageBaseAddress; pGdiDriverInfo->SectionPointer = 0; pGdiDriverInfo->EntryPoint = (PVOID)EntryPoint;
}
if (pModuleInformation) VFREEMEM(pModuleInformation); if (bFreeAsDriver) RtlFreeAnsiString(&asDriver);
if (bFoundDriver) { pldev->bStaticImportLink = TRUE; goto addstaticimport; } } }
//
// If MmLoadSystemImage failed to load the driver because
// of unresolved imports, this is likely an old driver
// being linked against something other than win32k.sys.
// Call user to log the error.
if (Status == STATUS_PROCEDURE_NOT_FOUND) { DrvLogDisplayDriverEvent(MsgInvalidOldDriver); } } }
//
// Either success due to a cached entry, or failure.
// In either case, we can free all the resources we allocatred.
//
if (pGdiDriverInfo) VFREEMEM(pGdiDriverInfo);
if (pldev) VFREEMEM(pldev);
pldev = NULL;
} done: VFREEMEM(usDriverName.Buffer); }
TRACE_INIT(("ldevLoadImage %ws with HANDLE %08lx\n", pldev ? L"SUCCESS" : L"FAILED", pldev));
return (pldev);
}
/******************************Member*Function*****************************\
* ldevUnloadImage() * * Decrements the refcnt on driver usage. * If the refcnt is zero { * Deletes an LDEV. Disables and unloads the driver. * } \**************************************************************************/
VOID ldevUnloadImage( PLDEV pldev) { GDIFunctionID(ldevUnloadImage);
LPWSTR pDriverFile = NULL, pCopyDriverFile = NULL; ULONG cbDriverFile;
//
// Hold the LDEV semaphore until after the module is unloaded.
//
GreAcquireSemaphoreEx(ghsemDriverMgmt, SEMORDER_DRIVERMGMT, NULL);
if (--pldev->cldevRefs == 0) { //
// Make sure that there is exactly one reference to this LDEV.
//
TRACE_INIT(("ldevUnloadImage: ENTERING\n"));
//
// Call the driver unload routine if it exists.
//
PFN_DrvDisableDriver pfnDisableDriver = (PFN_DrvDisableDriver) pldev->apfn[INDEX_DrvDisableDriver];
if (pfnDisableDriver) { (*pfnDisableDriver)(); }
//
// If the module handle exists, we need to unload the module. (Does not exist
// for the statically linked font drivers).
//
if (pldev->pGdiDriverInfo) { //
// Tell the module to unload.
//
TRACE_INIT(("ldevUnloadImage called on Image %08lx, %ws\n", (ULONG_PTR) pldev, pldev->pGdiDriverInfo->DriverName.Buffer));
if (!(pldev->bStaticImportLink)) { ZwSetSystemInformation(SystemUnloadGdiDriverInformation, &(pldev->pGdiDriverInfo->SectionPointer), sizeof(ULONG_PTR)); }
//
// If a printer driver is being unloaded, the spooler must be informed
// so that it may perform driver upgrades.
//
if ((pldev->ldevType == LDEV_DEVICE_PRINTER) && (pldev->bArtificialIncrement == FALSE)) { // Copy the driver file name into a temp buffer
// This will be used to notify the spooler of the driver unload
// from outside the semaphore
pDriverFile = pldev->pGdiDriverInfo->DriverName.Buffer;
// Check for invalid printer driver names.
if (pDriverFile && *pDriverFile) { // Copy the driver name into another buffer.
cbDriverFile = (wcslen(pDriverFile) + 1) * sizeof(WCHAR); pCopyDriverFile = (LPWSTR) PALLOCMEM(cbDriverFile, 'lpsG');
if (pCopyDriverFile) { memcpy(pCopyDriverFile, pDriverFile, cbDriverFile); } } }
}
//
// Remove the ldev from the linker list.
//
if (pldev->pldevNext) { pldev->pldevNext->pldevPrev = pldev->pldevPrev; }
if (pldev->pldevPrev) { pldev->pldevPrev->pldevNext = pldev->pldevNext; } else { gpldevDrivers = pldev->pldevNext; }
GreReleaseSemaphoreEx(ghsemDriverMgmt);
//
// Free the ldev
//
if (pldev->pGdiDriverInfo) { //
// Free the memory associated with the module.
//
VFREEMEM(pldev->pGdiDriverInfo->DriverName.Buffer); VFREEMEM(pldev->pGdiDriverInfo);
} VFREEMEM(pldev); } else { TRACE_INIT(("ldevUnloadImage - refcount decremented\n")); GreReleaseSemaphoreEx(ghsemDriverMgmt); }
if (pCopyDriverFile) { GrePrinterDriverUnloadW(pCopyDriverFile); VFREEMEM(pCopyDriverFile); }
return; }
/******************************Member*Function*****************************\
* ldevLoadDriver * * Locate an existing driver or load a new one. Increase its reference * count. * \**************************************************************************/
PLDEV ldevLoadDriver( LPWSTR pwszDriver, LDEVTYPE ldt) { GDIFunctionID(ldevLoadDriver);
NTSTATUS Status = STATUS_INSUFFICIENT_RESOURCES; PLDEV pldev; BOOL bLoaded;
//
// Check for a bogus driver name.
//
if ((pwszDriver == NULL) || (*pwszDriver == L'\0')) { WARNING("ldevLoadDriver: bogus driver name\n"); return NULL; }
#if DBG
//
// Check for bogus driver type
//
if ((ldt != LDEV_FONT) && (ldt != LDEV_DEVICE_DISPLAY) && (ldt != LDEV_DEVICE_PRINTER) && (ldt != LDEV_DEVICE_MIRROR)) { WARNING("ldevLoadDriver: bad LDEVTYPE\n"); return NULL; } #endif
GreAcquireSemaphoreEx(ghsemDriverMgmt, SEMORDER_DRIVERMGMT, NULL);
pldev = ldevLoadImage(pwszDriver, FALSE, &bLoaded, TRUE);
if (pldev) { if (bLoaded) { TRACE_INIT(("ldevLoadDriver: SUCCESS, Driver already loaded\n"));
GreReleaseSemaphoreEx(ghsemDriverMgmt); } else { DRVENABLEDATA ded = {0,0,(DRVFN *) NULL};
if ((pldev->pGdiDriverInfo->EntryPoint != NULL) && ((PFN_DrvEnableDriver) pldev->pGdiDriverInfo->EntryPoint)( ENGINE_VERSION, sizeof(DRVENABLEDATA), &ded) && (ded.iDriverVersion <= ENGINE_VERSION) && (ded.iDriverVersion >= ENGINE_VERSIONSUR) && ldevFillTable(pldev, &ded, ldt)) {
//
// Make sure the name and type of the ldev is initialized
//
pldev->ldevType = ldt;
//
// For printer drivers increment the refcnt to 2. This will keep
// the drivers loaded until they are upgraded by the spooler. The
// artificial increment will be undone when the spooler sends the
// appropriate message.
//
if (ldt == LDEV_DEVICE_PRINTER) { if (!pldev->bArtificialIncrement) { pldev->cldevRefs += 1; pldev->bArtificialIncrement = TRUE; } }
GreReleaseSemaphoreEx(ghsemDriverMgmt);
#ifdef _HYDRA_
/*
* For remote video driver, call connect entry point to pass the * Client data and the thinwire cache data area pointer. * * Only do this once. We don't support multiple drivers. */
PFN_DrvConnect pConnectCall;
pConnectCall = (PFN_DrvConnect)((pldev->apfn[INDEX_DrvConnect]));
if ( pConnectCall ) { ASSERT(gProtocolType != PROTOCOL_DISCONNECT);
BOOL Result;
Result = (*pConnectCall) ( G_RemoteConnectionChannel, G_RemoteConnectionFileObject, G_RemoteVideoFileObject, G_PerformanceStatistics ); if ( !Result ) { //
// Error exit path
//
ldevUnloadImage(pldev);
pldev = NULL;
TRACE_INIT(("LDEVREF::LDEVREF: CONNECT FAILIURE\n")); return pldev; }
} #endif
TRACE_INIT(("ldevLoadDriver: SUCCESS\n")); } else { GreReleaseSemaphoreEx(ghsemDriverMgmt);
//
// Error exit path
//
ldevUnloadImage(pldev);
pldev = NULL;
TRACE_INIT(("ldevLoadDriver: FAILURE\n")); } } } else { GreReleaseSemaphoreEx(ghsemDriverMgmt); }
return pldev; }
/******************************Member*Function*****************************\
* ldevArtificialDecrement * * Removes the artificial increment on printer drivers. * \**************************************************************************/
BOOL ldevArtificialDecrement( LPWSTR pwszDriver) { GDIFunctionID(ldevArtificialDecrement);
PLDEV pldev = NULL, pldevList; BOOL bReturn = FALSE; UNICODE_STRING usDriverName;
PSYSTEM_GDI_DRIVER_INFORMATION pGdiDriverInfo = NULL;
//
// Check for invalid driver name.
//
if (!pwszDriver || !*pwszDriver) { return bReturn; }
TRACE_INIT(("ldevArtificialDecrement called on Image %ws\n", pwszDriver));
//
// Append .dll for printer drivers
//
if (MakeSystemRelativePath(pwszDriver, &usDriverName, TRUE)) { //
// Check both list of drivers.
//
GreAcquireSemaphoreEx(ghsemDriverMgmt, SEMORDER_DRIVERMGMT, NULL);
pldevList = gpldevDrivers;
TRACE_INIT(("ldevArtificialDecrement - search for existing image %ws\n", usDriverName.Buffer));
while (pldevList != NULL) { //
// Check for loaded printer drivers.
//
if ((pldevList->pGdiDriverInfo) && (pldevList->ldevType == LDEV_DEVICE_PRINTER)) { //
// Do a case insensitive compare since the printer driver name
// can come from different locations.
//
if (RtlEqualUnicodeString(&(pldevList->pGdiDriverInfo->DriverName), &usDriverName, TRUE)) { //
// If the driver is found and has an artificial increment on it,
// call ldevUnloadImage once and reset the bArtificialIncrement
// flag.
//
TRACE_INIT(("ldevArtificialIncrement found the driver.\n"));
if (pldevList->bArtificialIncrement) { pldev = pldevList; pldev->bArtificialIncrement = FALSE; }
break; } }
pldevList = pldevList->pldevNext; }
GreReleaseSemaphoreEx(ghsemDriverMgmt);
VFREEMEM(usDriverName.Buffer); }
if (pldev) { // Spooler will be sent a message when the driver is unloaded.
ldevUnloadImage(pldev); } else { // Return TRUE if the driver is not loaded.
bReturn = TRUE; }
return bReturn; }
/******************************Public*Routine******************************\
* EngLoadImage * * Loads an image that a display of printers driver can then call to execute * code * \**************************************************************************/
HANDLE APIENTRY EngLoadImage( LPWSTR pwszDriver ) { GDIFunctionID(EngLoadImage);
BOOL bLoaded; HANDLE h;
GreAcquireSemaphoreEx(ghsemDriverMgmt, SEMORDER_DRIVERMGMT, NULL);
h = ldevLoadImage(pwszDriver, TRUE, &bLoaded, TRUE);
GreReleaseSemaphoreEx(ghsemDriverMgmt);
return h; }
/******************************Public*Routine******************************\
* EngFindImageProcAddress * * Returns the address of the specified functions in the module. * Special DrvEnableDriver since it is the entry point. * \**************************************************************************/
typedef struct _NEWPROCADDRESS { LPSTR lpstrName; PVOID pvAddress; } NEWPROCADDRESS;
// The following define expands 'NEWPROC(x)' to '"x", x':
#define NEWPROC(x) #x, x
// Table of Eng functions that are new since NT 4.0:
NEWPROCADDRESS gaNewProcAddresses[] = { NEWPROC(EngQueryPalette), NEWPROC(EngSaveFloatingPointState), NEWPROC(EngRestoreFloatingPointState), NEWPROC(EngSetPointerShape), NEWPROC(EngMovePointer), NEWPROC(EngSetPointerTag), NEWPROC(EngCreateEvent), NEWPROC(EngDeleteEvent), NEWPROC(EngMapEvent), NEWPROC(EngUnmapEvent), NEWPROC(EngSetEvent), NEWPROC(EngClearEvent), NEWPROC(EngReadStateEvent), NEWPROC(EngWaitForSingleObject), NEWPROC(EngDeleteWnd), NEWPROC(EngInitializeSafeSemaphore), NEWPROC(EngDeleteSafeSemaphore), NEWPROC(HeapVidMemAllocAligned), NEWPROC(VidMemFree), NEWPROC(EngAlphaBlend), NEWPROC(EngGradientFill), NEWPROC(EngStretchBltROP), NEWPROC(EngPlgBlt), NEWPROC(EngTransparentBlt), NEWPROC(EngControlSprites), NEWPROC(EngLockDirectDrawSurface), NEWPROC(EngUnlockDirectDrawSurface), NEWPROC(EngMapFile), NEWPROC(EngUnmapFile), NEWPROC(EngDeleteFile), NEWPROC(EngLpkInstalled), NEWPROC(BRUSHOBJ_hGetColorTransform), NEWPROC(XLATEOBJ_hGetColorTransform), NEWPROC(FONTOBJ_pjOpenTypeTablePointer), NEWPROC(FONTOBJ_pwszFontFilePaths), NEWPROC(FONTOBJ_pfdg), NEWPROC(FONTOBJ_pQueryGlyphAttrs), NEWPROC(STROBJ_fxCharacterExtra), NEWPROC(STROBJ_fxBreakExtra), NEWPROC(STROBJ_bGetAdvanceWidths), NEWPROC(STROBJ_bEnumPositionsOnly), NEWPROC(EngGetPrinterDriver), NEWPROC(EngMapFontFileFD), NEWPROC(EngUnmapFontFileFD), NEWPROC(EngQuerySystemAttribute), NEWPROC(HT_Get8BPPMaskPalette), #if !defined(_GDIPLUS_)
NEWPROC(EngGetTickCount), NEWPROC(EngFileWrite), NEWPROC(EngFileIoControl), #endif
NEWPROC(EngDitherColor), NEWPROC(EngModifySurface), NEWPROC(EngQueryDeviceAttribute), NEWPROC(EngHangNotification), NEWPROC(EngNineGrid), NEWPROC(EngBugCheckEx), };
PVOID APIENTRY EngFindImageProcAddress( HANDLE hModule, LPSTR lpProcName ) { PSYSTEM_GDI_DRIVER_INFORMATION pGdiDriverInfo;
PULONG NameTableBase; USHORT OrdinalNumber; PUSHORT NameOrdinalTableBase; ULONG NumberOfNames; PULONG AddressTableBase; ULONG i;
if (!hModule) { // An 'hModule' of zero means that the driver wants to find
// the address of a GDI 'Eng' function. Note that this didn't
// work in the final release of NT 4.0 (this routine would
// access violate if passed an 'hModule' of zero), so drivers
// must check GDI's engine version to make sure it's not 4.0,
// before calling this function.
//
// Unfortunately, the Base can't handle loading of 'win32k.sys'
// at the time of this writing, so we'll just special-case here
// all the Eng functions that are new since 4.0. This allows
// drivers to take advantage of NT 4.0 SP3 call-backs when
// running on SP3, but to still load and run NT 4.0 SP2.
for (i=0; i < sizeof(gaNewProcAddresses)/sizeof(NEWPROCADDRESS); i++) { if (!strcmp(lpProcName, gaNewProcAddresses[i].lpstrName)) { return gaNewProcAddresses[i].pvAddress; } }
return NULL;
} else {
pGdiDriverInfo = ((PLDEV)hModule)->pGdiDriverInfo; }
if (!strncmp(lpProcName, "DrvEnableDriver", strlen(lpProcName))) { return (pGdiDriverInfo->EntryPoint); }
if (pGdiDriverInfo->ExportSectionPointer) { NameTableBase = (PULONG)((ULONG_PTR)pGdiDriverInfo->ImageAddress + (ULONG)pGdiDriverInfo->ExportSectionPointer->AddressOfNames); NameOrdinalTableBase = (PUSHORT)((ULONG_PTR)pGdiDriverInfo->ImageAddress + (ULONG)pGdiDriverInfo->ExportSectionPointer->AddressOfNameOrdinals);
NumberOfNames = pGdiDriverInfo->ExportSectionPointer->NumberOfNames;
AddressTableBase = (PULONG)((ULONG_PTR)pGdiDriverInfo->ImageAddress + (ULONG_PTR)pGdiDriverInfo->ExportSectionPointer->AddressOfFunctions);
for (i=0; i < NumberOfNames; i++) { if (!strncmp(lpProcName, (PCHAR) (NameTableBase[i] + (ULONG_PTR)pGdiDriverInfo->ImageAddress), strlen(lpProcName))) { OrdinalNumber = NameOrdinalTableBase[i];
return ((PVOID) ((ULONG_PTR)pGdiDriverInfo->ImageAddress + AddressTableBase[OrdinalNumber])); } } }
return NULL; }
/******************************Public*Routine******************************\
* EngUnloadImage * * Unloads an image loaded using EngLoadImage. * \**************************************************************************/
VOID APIENTRY EngUnloadImage( HANDLE hModule ) { ldevUnloadImage((PLDEV)hModule); }
/******************************Public*Routine******************************\
* EngHangNotification * * This is the engine entry point to notify system that the given device * is no longer operable or responsive. * * hDev must always be a valid device. * * This call will return EHN_RESTORED if the device has been restored to * working order or EHN_ERROR otherwise. * * * History: * 12-Sep-2000 -by- Jason Hartman jasonha * Wrote it. \**************************************************************************/
ULONG APIENTRY EngHangNotification( HDEV hdev, PVOID Reserved ) { GDIFunctionID(EngHangNotification);
ULONG Result = EHN_ERROR; PDEVOBJ pdo(hdev);
if (pdo.bValid()) { PGRAPHICS_DEVICE PhysDisp = pdo.ppdev->pGraphicsDevice; PIO_ERROR_LOG_PACKET perrLogEntry; PCWSTR pwszDevice, pwszDesc; ULONG cbDevice, cbDesc;
if (PhysDisp == (PGRAPHICS_DEVICE) DDML_DRIVER || PhysDisp == NULL) { RIP("Invalid HDEV.\n"); return Result; }
DbgPrint("GDI: EngHangNotification: %ls is not responding.\n", PhysDisp->szWinDeviceName);
pwszDevice = PhysDisp->szNtDeviceName; cbDevice = (wcslen(pwszDevice)+1)*sizeof(WCHAR); pwszDesc = PhysDisp->DeviceDescription; cbDesc = (wcslen(pwszDesc)+1)*sizeof(WCHAR);
/*
* Allocate an error packet, fill it out, and write it to the log. */ perrLogEntry = (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry(gpWin32kDriverObject, (UCHAR)(cbDevice + cbDesc + FIELD_OFFSET(IO_ERROR_LOG_PACKET, DumpData))); if (perrLogEntry) { perrLogEntry->ErrorCode = STATUS_INVALID_DEVICE_STATE;
perrLogEntry->NumberOfStrings = 2; perrLogEntry->StringOffset = FIELD_OFFSET(IO_ERROR_LOG_PACKET, DumpData); RtlCopyMemory(perrLogEntry->DumpData, pwszDevice, cbDevice); RtlCopyMemory((PBYTE)perrLogEntry->DumpData + cbDevice, pwszDesc, cbDesc);
IoWriteErrorLogEntry(perrLogEntry); } else { WARNING("Failed to create error log entry.\n"); }
if (PPFNVALID(pdo,ResetDevice) && (*PPFNDRV(pdo,ResetDevice))(pdo.dhpdev(), NULL) == DRD_SUCCESS) { Result = EHN_RESTORED; } else { RIP("Unable to recover device.\n"); } }
return Result; }
/******************************Public*Routine******************************\
* ldevGetDriverModes * * Loads the device driver long enough to pass the DrvGetModes call to it. * \**************************************************************************/
ULONG ldevGetDriverModes( LPWSTR pwszDriver, HANDLE hDriver, PDEVMODEW *pdm ) { PLDEV pldev; ULONG ulRet = 0;
TRACE_INIT(("ldevGetDriverModes: Entering\n"));
*pdm = NULL;
//
// Temporarily locate and load the driver.
//
pldev = ldevLoadDriver(pwszDriver, LDEV_DEVICE_DISPLAY);
if (pldev) { //
// Locate the function and call it.
//
PFN_DrvGetModes pfn = (PFN_DrvGetModes) pldev->apfn[INDEX_DrvGetModes];
if (pfn != NULL) { ULONG cjSize;
if (cjSize = (*pfn)(hDriver, 0, NULL)) { // get modelist size
//
// In NT4 we passed in a buffer of 64K. In NT5 we try to
// pass in a buffer size based on the number of modes the
// driver will actually use. However, some drivers are
// buggy and don't properly return the amount of buffer
// space they need. So we'll always pass in a buffer
// at least 64K in length.
//
if (pldev->ulDriverVersion < DDI_DRIVER_VERSION_NT5) { cjSize = max(cjSize, 0x10000); }
if (*pdm = (PDEVMODEW) PALLOCNOZ(cjSize, GDITAG_DRVSUP)) { ulRet = (*pfn)(hDriver,cjSize,*pdm); } else { WARNING("ldevGetDriverModes failed to alloc mem for mode list\n"); } } }
ldevUnloadImage(pldev); }
#define MAPDEVMODE_FLAGS (DM_BITSPERPEL | DM_PELSWIDTH | \
DM_PELSHEIGHT | DM_DISPLAYFREQUENCY | DM_DISPLAYFLAGS)
if (ulRet) { if (((*pdm)->dmFields & MAPDEVMODE_FLAGS) != MAPDEVMODE_FLAGS) { ASSERTGDI(FALSE,"DrvGetModes did not set the dmFields value!\n"); ulRet = 0; } }
TRACE_INIT(("ldevGetDriverModes: Leaving\n"));
//
// Return the driver's result.
//
return(ulRet); }
#define REGSTR_CCS L"\\Registry\\Machine\\System\\CurrentControlSet"
#define REGSTR_HP_CCS L"\\Hardware Profiles\\Current\\System\\CurrentControlSet"
/**************************************************************************\
* DrvGetRegistryHandleFromDeviceMap * * Gets the handle to the registry node for that driver. * * returns a HANDLE * * * lpMatchString is passed in when the caller wants to make sure the device * name (\Device\video0) matches a certain physical device in the registry * (\Services\Weitekp9\Device0). We call this routine in a loop with a * specific lpMatchString to find that device in the list in DeviceMap. * * 30-Nov-1992 andreva created \**************************************************************************/
HANDLE DrvGetRegistryHandleFromDeviceMap( PGRAPHICS_DEVICE PhysDisp, DISP_DRIVER_REGISTRY_TYPE ParamType, PULONG pSubId, LPWSTR pDriverName, PNTSTATUS pStatus, USHORT ProtocolType) { HANDLE hkRegistry = NULL;
UNICODE_STRING UnicodeString; OBJECT_ATTRIBUTES ObjectAttributes; NTSTATUS Status; HANDLE handle; ULONG cbStringSize; WCHAR *pdriverRegistryPath = NULL; WCHAR *pfullRegistryPath = NULL; #ifdef _HYDRA_
WCHAR *pTerminalServerVideoRegistryPath; #endif
TRACE_INIT(("Drv_Trace: GetHandleFromMap: Enter\n"));
//
// Initialize the handle
//
//
// Start by opening the registry devicemap for video.
//
#ifdef _HYDRA_
if ((pTerminalServerVideoRegistryPath = (WCHAR*)PALLOCMEM(256*sizeof(WCHAR), 'pmtG')) == NULL) { if (pStatus) *pStatus = ERROR_NOT_ENOUGH_MEMORY; goto Exit; }
/*
* Look in TerminalServer VIDEO section for the video driver type as given by client. * */ if (ProtocolType != PROTOCOL_CONSOLE && ProtocolType != PROTOCOL_DISCONNECT) {
UnicodeString.Buffer = pTerminalServerVideoRegistryPath; UnicodeString.Length = 0; UnicodeString.MaximumLength = 255*sizeof(WCHAR);
RtlAppendUnicodeToString(&UnicodeString, NTAPI_VIDEO_REG_NAME L"\\" ); RtlAppendUnicodeToString(&UnicodeString, G_DisplayDriverNames); } else #endif
RtlInitUnicodeString(&UnicodeString, L"\\Registry\\Machine\\Hardware\\DeviceMap\\Video");
TRACE_INIT(("Video Registry path is %ws\n", UnicodeString.Buffer));
InitializeObjectAttributes(&ObjectAttributes, &UnicodeString, OBJ_CASE_INSENSITIVE|OBJ_KERNEL_HANDLE, NULL, NULL);
Status = ZwOpenKey(&handle, KEY_READ, &ObjectAttributes);
if (NT_SUCCESS(Status)) { pdriverRegistryPath = (WCHAR*)PALLOCMEM(2*256*sizeof(WCHAR), 'pmtG'); if (pdriverRegistryPath == NULL) { if (pStatus) *pStatus = ERROR_NOT_ENOUGH_MEMORY; goto Exit; } pfullRegistryPath = pdriverRegistryPath + 256; if (ProtocolType != PROTOCOL_CONSOLE && ProtocolType != PROTOCOL_DISCONNECT) { //
//We may have several remote display drivers
//in the same list, but only one per protocol.
//They are all registered in the registry as
//"\Device\Video0"
//
RtlInitUnicodeString(&UnicodeString, L"\\Device\\Video0");
} else {
RtlInitUnicodeString(&UnicodeString, PhysDisp->szNtDeviceName); }
//
// Get the name of the driver based on the device name.
//
Status = ZwQueryValueKey(handle, &UnicodeString, KeyValueFullInformation, pdriverRegistryPath, 512, &cbStringSize);
if (NT_SUCCESS(Status)) { //
// Look up in the registry for the kernel driver node (it
// is a full path to the driver node) so we can get the
// display driver info.
//
LPWSTR lpstrStart; LPWSTR lpstrDriverRegistryPath; LPWSTR lpstrEndPath; UNICODE_STRING FullRegistryPath;
//
// We can use wcsstr since we are guaranteed to find "Control" or
// "Services" in the string, and we won't run off the end of the
// string. Capitalize it so we don't have problems with different
// types of paths.
//
lpstrStart = (LPWSTR)((PUCHAR)pdriverRegistryPath + ((PKEY_VALUE_FULL_INFORMATION)pdriverRegistryPath)->DataOffset);
// We only want RegKey here
if (ParamType == DispDriverRegKey) { wcsncpy(pDriverName, lpstrStart, 127); ZwCloseKey(handle); if (pStatus) *pStatus = Status; goto Exit; }
while (*lpstrStart) { *lpstrStart = (USHORT)(toupper(*lpstrStart)); lpstrStart++; }
lpstrDriverRegistryPath = wcsstr((LPWSTR)((PUCHAR)pdriverRegistryPath + ((PKEY_VALUE_FULL_INFORMATION)pdriverRegistryPath)->DataOffset), L"\\CONTROL\\");
if (lpstrDriverRegistryPath == NULL) {
lpstrDriverRegistryPath = wcsstr((LPWSTR)((PUCHAR)pdriverRegistryPath + ((PKEY_VALUE_FULL_INFORMATION)pdriverRegistryPath)->DataOffset), L"\\SERVICES"); }
//
// Save the service name as the description in case it's needed
// later
//
if (pDriverName) { LPWSTR pName = pDriverName; ULONG i = 31; HANDLE CommonSubkeyHandle; LPWSTR CommonSubkeyBuffer = NULL; LPWSTR pSubkeyBuffer = NULL; LONG BufferLen = 0, RegistryPathLen = 0;
//
// Get the registry path and find the last '\'
//
RegistryPathLen = wcslen((LPWSTR)((PUCHAR)pdriverRegistryPath + ((PKEY_VALUE_FULL_INFORMATION)pdriverRegistryPath)->DataOffset)); BufferLen = (max(RegistryPathLen + 6, 32) * sizeof(WCHAR));
CommonSubkeyBuffer = (LPWSTR) PALLOCMEM(BufferLen, GDITAG_DRVSUP);
if (CommonSubkeyBuffer) { RtlZeroMemory(CommonSubkeyBuffer, BufferLen); wcscpy(CommonSubkeyBuffer, (LPWSTR)((PUCHAR)pdriverRegistryPath + ((PKEY_VALUE_FULL_INFORMATION)pdriverRegistryPath)->DataOffset));
pSubkeyBuffer = CommonSubkeyBuffer + RegistryPathLen - 1; while ((pSubkeyBuffer > CommonSubkeyBuffer) && (*pSubkeyBuffer != L'\\')) { pSubkeyBuffer--; } if (*pSubkeyBuffer == L'\\') { pSubkeyBuffer++; //
// Open the Video subkey
//
wcscpy(pSubkeyBuffer, L"Video"); RtlInitUnicodeString(&UnicodeString, CommonSubkeyBuffer); InitializeObjectAttributes(&ObjectAttributes, &UnicodeString, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL); Status = ZwOpenKey(&CommonSubkeyHandle, KEY_READ, &ObjectAttributes); if (NT_SUCCESS(Status)) { ULONG cbLegacyRegistryPathSize; //
// Get the service name
//
RtlInitUnicodeString(&UnicodeString, L"Service"); RtlZeroMemory(CommonSubkeyBuffer, BufferLen); Status = ZwQueryValueKey(CommonSubkeyHandle, &UnicodeString, KeyValueFullInformation, CommonSubkeyBuffer, BufferLen, &cbLegacyRegistryPathSize); if (NT_SUCCESS(Status)) { //
// Convert to upper chars ...
//
pSubkeyBuffer = CommonSubkeyBuffer; while (*pSubkeyBuffer) { *pSubkeyBuffer = (USHORT)(toupper(*pSubkeyBuffer)); pSubkeyBuffer++; } //
// Copy the service name
//
pSubkeyBuffer = CommonSubkeyBuffer; while ((i--) && (*pSubkeyBuffer != NULL)) { *pName++ = *pSubkeyBuffer++; if ((i == 28) && (_wcsnicmp(pDriverName, L"VGA", 3) == 0)) { break; } } } ZwCloseKey(CommonSubkeyHandle); } } else { //
// This should not happen ...
//
ASSERTGDI(FALSE, "invalid registry key\n"); }
VFREEMEM(CommonSubkeyBuffer); } *pName = UNICODE_NULL;
//
// Make sure we do not set a remote device or the disconnect device as the VGA device.
//
if (!(PhysDisp->stateFlags &(DISPLAY_DEVICE_REMOTE | DISPLAY_DEVICE_DISCONNECT) ) ) { gPhysDispVGA = PhysDisp; } }
//
// This sectione is for per Monitor settings. Each monitor has UID.
// So we save under Servive\XXXX\DeviceX\UID
//
if (pSubId) { swprintf(lpstrDriverRegistryPath+wcslen(lpstrDriverRegistryPath), L"\\Mon%08X", *pSubId); }
//
// Start composing the fully qualified path name.
//
FullRegistryPath.Buffer = pfullRegistryPath; FullRegistryPath.Length = 0; FullRegistryPath.MaximumLength = 255*sizeof(WCHAR);
RtlAppendUnicodeToString(&FullRegistryPath, REGSTR_CCS);
//
// If we want the hardware profile, insert the hardware profile
// in there
//
if ((ParamType == DispDriverRegHardwareProfile) || (ParamType == DispDriverRegHardwareProfileCreate)) { TRACE_INIT(("Drv_Trace: GetHandleFromMap: using a hardware profile\n")); RtlAppendUnicodeToString(&FullRegistryPath, REGSTR_HP_CCS); }
//
// If we have the create Options, we have to create the subkeys
// otherwise, just open the key
//
InitializeObjectAttributes(&ObjectAttributes, &FullRegistryPath, OBJ_CASE_INSENSITIVE|OBJ_KERNEL_HANDLE, NULL, NULL);
//
// Check if the subkeys need to be created.
//
if (ParamType == DispDriverRegHardwareProfileCreate) { TRACE_INIT(("Drv_Trace: GetHandleFromMap: creating a hardware profile\n"));
//
// We are guaranteed to go through the loop at least once,
// which will ensure the status is set properly.
//
// Basically, find the '\' replace it by NULL and add that
// partial string to the full path (so we can create that
// subkey), put back the '\' and keep on going for the next
// string. We must also add the end of the string.
//
do { lpstrEndPath = wcschr(lpstrDriverRegistryPath + 1, L'\\');
if (lpstrEndPath != NULL) { *lpstrEndPath = UNICODE_NULL; }
RtlAppendUnicodeToString(&FullRegistryPath, lpstrDriverRegistryPath);
//
// Close the previous key if necessary.
//
if (hkRegistry) { ZwCloseKey(hkRegistry); }
//
// Create the Key.
//
Status = ZwCreateKey(&hkRegistry, (ACCESS_MASK) NULL, &ObjectAttributes, 0, NULL, 0, NULL);
if (!NT_SUCCESS(Status)) { hkRegistry = NULL; break; }
//
// Check to see if we need to loop again.
//
if (lpstrEndPath == NULL) { break; } else { *lpstrEndPath = L'\\'; lpstrDriverRegistryPath = lpstrEndPath; }
} while(1);
if (!NT_SUCCESS(Status)) { TRACE_INIT(("Drv_Trace: GetHandleFromMap: failed to create key\n")); } } else { RtlAppendUnicodeToString(&FullRegistryPath, lpstrDriverRegistryPath);
Status = ZwOpenKey(&hkRegistry, KEY_READ, &ObjectAttributes);
if (!NT_SUCCESS(Status)) { TRACE_INIT(("Drv_Trace: GetHandleFromMap: failed to open key\n"));
//
// We set this special status so the looping code in the
// video port can handle unconfigured devices properly
// (in the case where the second video card entry may not
// be present).
//
Status = STATUS_DEVICE_CONFIGURATION_ERROR; } }
TRACE_INIT(("Drv_Trace: GetHandleFromMap: reg-key path =\n\t%ws\n", pfullRegistryPath)); }
ZwCloseKey(handle); }
if (!NT_SUCCESS(Status)) { TRACE_INIT(("Drv_Trace: GetHandleFromMap: Error opening registry - status = %08lx\n", Status)); }
if (pStatus) { *pStatus = Status; }
TRACE_INIT(("Drv_Trace: GetHandleFromMap: Exit\n\n"));
Exit:
#ifdef _HYDRA_
if (pTerminalServerVideoRegistryPath) VFREEMEM(pTerminalServerVideoRegistryPath); #endif
if (pdriverRegistryPath) VFREEMEM(pdriverRegistryPath); return hkRegistry; }
/**************************************************************************\
* DrvPrepareForEARecovery * * Remove all devices other than the VGA device from the graphics * device list. * * In multi-mon we could just disable the now "dead" display. In single * mon we need to disable the "high-res" display and switch to VGA. * * 27-Mar-2002 ericks created \**************************************************************************/
VOID DrvPrepareForEARecovery( VOID )
{ ULONG ulBytes;
if (gPhysDispVGA) {
GreDeviceIoControl(gPhysDispVGA->pDeviceHandle, IOCTL_VIDEO_PREPARE_FOR_EARECOVERY, NULL, 0, NULL, 0, &ulBytes); }
return; }
/**************************************************************************\
* DrvGetDisplayDriverNames * * Get the display driver name out of the registry. * * 12-Jan-1994 andreva created \**************************************************************************/
typedef struct _DRV_NAMES { ULONG cNames; struct { HANDLE hDriver; LPWSTR lpDisplayName; } D[1]; } DRV_NAMES, *PDRV_NAMES;
PDRV_NAMES DrvGetDisplayDriverNames( PGRAPHICS_DEVICE PhysDisp ) { DWORD status; LPWSTR lptmpdisplay; DWORD cCountNames; DWORD cCountNamesDevice; PDRV_NAMES lpNames = NULL; ULONG cb = 0; ULONG cbVga = 0;
//
// At this point, create the array, and put in the VGA driver
// if necessary. (We morphed this from the ModeX hack.)
//
if (PhysDisp->DisplayDriverNames) { //
// Count the names in the list (first for PhysDisp)
//
cCountNames = 0; lptmpdisplay = PhysDisp->DisplayDriverNames;
while (*lptmpdisplay != UNICODE_NULL) { cCountNames++;
while (*lptmpdisplay != UNICODE_NULL) { lptmpdisplay++; cb += 2; }
lptmpdisplay++; cb += 2; }
//
// Track the number of display driver names for the root device
//
cCountNamesDevice = cCountNames;
//
// Now if this PhysDisp is associated with the VGA, then add
// the VGA display drivers as well.
//
if (PhysDisp->pVgaDevice && gFullscreenGraphicsDevice.pDeviceHandle && PhysDisp->pVgaDevice->DisplayDriverNames) {
lptmpdisplay = PhysDisp->pVgaDevice->DisplayDriverNames;
while (*lptmpdisplay != UNICODE_NULL) { cCountNames++;
while (*lptmpdisplay != UNICODE_NULL) { lptmpdisplay++; cbVga += 2; }
lptmpdisplay++; cbVga += 2; } cbVga += 2; }
//
// Alocate the names structure.
//
if (lpNames = (PDRV_NAMES) PALLOCNOZ(cb + cbVga + 2 + sizeof(DRV_NAMES) * (cCountNames + 1), GDITAG_DRVSUP)) { lptmpdisplay = (LPWSTR) (((PUCHAR)lpNames) + sizeof(DRV_NAMES) * (cCountNames + 1));
RtlCopyMemory(lptmpdisplay, PhysDisp->DisplayDriverNames, cb + 2);
if (cbVga) {
RtlCopyMemory((LPWSTR)((ULONG_PTR)lptmpdisplay + cb), PhysDisp->pVgaDevice->DisplayDriverNames, cbVga + 2); }
//
// Set all the names pointers in the names structure
//
lpNames->cNames = 0;
while (*lptmpdisplay != UNICODE_NULL) { lpNames->D[lpNames->cNames].lpDisplayName = lptmpdisplay;
if (lpNames->cNames < cCountNamesDevice) { lpNames->D[lpNames->cNames].hDriver = PhysDisp->pDeviceHandle; } else { lpNames->D[lpNames->cNames].hDriver = PhysDisp->pVgaDevice->pDeviceHandle;
//
// For now, only return the first in the list of vga
// display driver names (vga.dll)
//
lpNames->cNames++; break; } lpNames->cNames++;
while (*lptmpdisplay != UNICODE_NULL) { lptmpdisplay++; } lptmpdisplay++; } } }
return lpNames; }
//
// We need to update monitor PDOs whenever reenumaration of devices has been occured
// This function has to be called every time before PhysDisp->MonitorDevices is to be used
//
VOID UpdateMonitorDevices(VOID) { PGRAPHICS_DEVICE PhysDisp; ULONG numMonitorDevice, i;
for (PhysDisp = gpGraphicsDeviceList; PhysDisp != NULL; PhysDisp = PhysDisp->pNextGraphicsDevice) { PVIDEO_MONITOR_DEVICE pMonitorDevices = NULL; BOOL bNoMonitor = TRUE;
if ((PhysDisp->pDeviceHandle != NULL ) && NT_SUCCESS(GreDeviceIoControl(PhysDisp->pDeviceHandle, IOCTL_VIDEO_ENUM_MONITOR_PDO, NULL, 0, &pMonitorDevices, sizeof(PVOID), &numMonitorDevice)) ) { if (pMonitorDevices != NULL) { numMonitorDevice = 0; while (pMonitorDevices[numMonitorDevice].pdo != NULL) { ObDereferenceObject(pMonitorDevices[numMonitorDevice].pdo); numMonitorDevice++; }
//
// The buffer always grows
//
if (PhysDisp->numMonitorDevice < numMonitorDevice) { if (PhysDisp->MonitorDevices) { VFREEMEM(PhysDisp->MonitorDevices); } PhysDisp->MonitorDevices = (PVIDEO_MONITOR_DEVICE)PALLOCMEM(sizeof(VIDEO_MONITOR_DEVICE) * numMonitorDevice, GDITAG_GDEVICE); //
// If fail, do cleanup here
//
if (PhysDisp->MonitorDevices == NULL) { PhysDisp->numMonitorDevice = 0;
ExFreePool(pMonitorDevices); return; } }
PhysDisp->numMonitorDevice = numMonitorDevice;
for (i = 0; i < numMonitorDevice; i++) { PhysDisp->MonitorDevices[i].flag = 0; if (pMonitorDevices[i].flag & VIDEO_CHILD_ACTIVE) { PhysDisp->MonitorDevices[i].flag |= DISPLAY_DEVICE_ACTIVE; } if ((pMonitorDevices[i].flag & VIDEO_CHILD_DETACHED) == 0) { PhysDisp->MonitorDevices[i].flag |= DISPLAY_DEVICE_ATTACHED; } if ((pMonitorDevices[i].flag & VIDEO_CHILD_NOPRUNE_FREQ) == 0) { PhysDisp->MonitorDevices[i].flag |= DISPLAY_DEVICE_PRUNE_FREQ; } if ((pMonitorDevices[i].flag & VIDEO_CHILD_NOPRUNE_RESOLUTION) == 0) { PhysDisp->MonitorDevices[i].flag |= DISPLAY_DEVICE_PRUNE_RESOLUTION; } PhysDisp->MonitorDevices[i].pdo = pMonitorDevices[i].pdo; PhysDisp->MonitorDevices[i].HwID = pMonitorDevices[i].HwID;
bNoMonitor = FALSE; }
ExFreePool(pMonitorDevices); } }
if (bNoMonitor) { if (PhysDisp->MonitorDevices) { VFREEMEM(PhysDisp->MonitorDevices); } PhysDisp->numMonitorDevice = 0; PhysDisp->MonitorDevices = NULL; } } }
VOID dbgDumpDevmode( PDEVMODEW pdm ) { TRACE_INIT((" Size = %d\n", pdm->dmSize)); TRACE_INIT((" Fields = %08lx\n", pdm->dmFields)); TRACE_INIT((" XPosition = %d\n", pdm->dmPosition.x)); TRACE_INIT((" YPosition = %d\n", pdm->dmPosition.y)); TRACE_INIT((" Orientation = %d\n", pdm->dmDisplayOrientation)); TRACE_INIT((" FixedOutput = %d\n", pdm->dmDisplayFixedOutput)); TRACE_INIT((" XResolution = %d\n", pdm->dmPelsWidth)); TRACE_INIT((" YResolution = %d\n", pdm->dmPelsHeight)); TRACE_INIT((" Bpp = %d\n", pdm->dmBitsPerPel)); TRACE_INIT((" Frequency = %d\n", pdm->dmDisplayFrequency)); TRACE_INIT((" Flags = %d\n", pdm->dmDisplayFlags)); TRACE_INIT((" XPanning = %d\n", pdm->dmPanningWidth)); TRACE_INIT((" YPanning = %d\n", pdm->dmPanningHeight)); TRACE_INIT((" DPI = %d\n", pdm->dmLogPixels)); TRACE_INIT((" DriverExtra = %d", pdm->dmDriverExtra)); if (pdm->dmDriverExtra) { TRACE_INIT((" - %08lx %08lx\n", *(PULONG)(((PUCHAR)pdm)+pdm->dmSize), *(PULONG)(((PUCHAR)pdm)+pdm->dmSize + 4))); } else { TRACE_INIT(("\n")); } }
#define NUM_DISPLAY_PARAMETERS 13
#define NUM_DISPLAY_DRIVER_EXTRA (NUM_DISPLAY_PARAMETERS - 1)
static LPWSTR DefaultSettings[NUM_DISPLAY_PARAMETERS] = { L"DefaultSettings.BitsPerPel", L"DefaultSettings.XResolution", L"DefaultSettings.YResolution", L"DefaultSettings.VRefresh", L"DefaultSettings.Flags", L"DefaultSettings.XPanning", L"DefaultSettings.YPanning", L"DefaultSettings.Orientation", L"DefaultSettings.FixedOutput", L"Attach.RelativeX", L"Attach.RelativeY", L"Attach.ToDesktop", L"DefaultSettings.DriverExtra" // MUST be at the end
};
static LPWSTR AttachedSettings[] = { L"Attach.PrimaryDevice", L"Attach.ToDesktop", };
static LPWSTR SoftwareSettings[] = { L"DriverDesc", L"InstalledDisplayDrivers", L"MultiDisplayDriver", L"MirrorDriver", L"VgaCompatible", L"Device Description", L"HardwareInformation.AdapterString", L"HardwareInformation.ChipType", };
NTSTATUS DrvDriverExtraCallback( PWSTR ValueName, ULONG ValueType, PVOID ValueData, ULONG ValueLength, PVOID Context, PVOID EntryContext)
{
PDEVMODEW pdevmode = (PDEVMODEW) EntryContext;
//
// Put the driver extra data in the right place, if necessary.
//
pdevmode->dmDriverExtra = min(pdevmode->dmDriverExtra, (USHORT)ValueLength);
RtlMoveMemory(pdevmode+1, ValueData, pdevmode->dmDriverExtra);
return STATUS_SUCCESS;
UNREFERENCED_PARAMETER(Context); UNREFERENCED_PARAMETER(ValueType); UNREFERENCED_PARAMETER(ValueName); }
/**************************************************************************\
* DrvGetDisplayDriverParameters * * Reads the resolution parameters from the registry. * * NOTE: * We assume the caller has initialized the DEVMODE to zero, * and that the DEVMODE is the current size for the system. * We only look at the dmDriverExtra field to determine any extra size. * We do check the dmSize for debugging purposes. * * CRIT not needed * * 25-Jan-1995 andreva created \**************************************************************************/
NTSTATUS DrvGetDisplayDriverParameters( PGRAPHICS_DEVICE PhysDisp, PDEVMODEW pdevmode, BOOL bEmptyDevmode, BOOL bFromMonitor ) { ULONG i, k; NTSTATUS retStatus; HANDLE hkRegistry; ULONG attached = 0;
DISP_DRIVER_REGISTRY_TYPE registryParam = DispDriverRegHardwareProfile; DWORD nullValue = 0;
//
// Our current algorithm is to save or get things from the hardware profile
// first, and then try the global profile as a backup.
//
// NOTE ??? For saving, should we always back propagate the changes to the
// global settings also ? We do this at this point.
//
RTL_QUERY_REGISTRY_TABLE QueryTable[] = {
{NULL, RTL_QUERY_REGISTRY_DIRECT, NULL, &pdevmode->dmBitsPerPel, REG_NONE, NULL, 0},
{NULL, RTL_QUERY_REGISTRY_DIRECT, NULL, &pdevmode->dmPelsWidth, REG_NONE, NULL, 0},
{NULL, RTL_QUERY_REGISTRY_DIRECT, NULL, &pdevmode->dmPelsHeight, REG_NONE, NULL, 0},
{NULL, RTL_QUERY_REGISTRY_DIRECT, NULL, &pdevmode->dmDisplayFrequency, REG_NONE, NULL, 0},
{NULL, RTL_QUERY_REGISTRY_DIRECT, NULL, &pdevmode->dmDisplayFlags, REG_NONE, NULL, 0},
{NULL, RTL_QUERY_REGISTRY_DIRECT, NULL, &pdevmode->dmPanningWidth, REG_NONE, NULL, 0},
{NULL, RTL_QUERY_REGISTRY_DIRECT, NULL, &pdevmode->dmPanningHeight, REG_NONE, NULL, 0},
{NULL, RTL_QUERY_REGISTRY_DIRECT, NULL, &pdevmode->dmDisplayOrientation, REG_NONE, NULL, 0},
{NULL, RTL_QUERY_REGISTRY_DIRECT, NULL, &pdevmode->dmDisplayFixedOutput, REG_NONE, NULL, 0},
{NULL, RTL_QUERY_REGISTRY_DIRECT, NULL, &pdevmode->dmPosition.x, REG_NONE, NULL, 0},
{NULL, RTL_QUERY_REGISTRY_DIRECT, NULL, &pdevmode->dmPosition.y, REG_NONE, NULL, 0},
{NULL, RTL_QUERY_REGISTRY_DIRECT, NULL, &attached, REG_NONE, NULL, 0},
// if the value is not there, we want the call to succeed anyway.
// so specify a vlue that is NULL modulo 64K !
{DrvDriverExtraCallback, 0, NULL, pdevmode, REG_DWORD, &nullValue, 0x10000},
{NULL, 0, NULL} };
TRACE_INIT(("Drv_Trace: GetDriverParams\n"));
//
// Special debug code to ensure that anyone who calls this API
// knows what they are doing, and we don't end up in here with a
// "random" devmode that does not ensure sizes.
//
ASSERTGDI(pdevmode->dmSize == 0xDDDD, "DEVMODE not set to DDDD\n");
//
// If there is no place for the Driver Extra data, don't ask for it.
// This will just cause the code not to read that value
//
if (pdevmode->dmDriverExtra == 0) { QueryTable[NUM_DISPLAY_PARAMETERS - 1].Flags = 0; pdevmode->dmDriverExtra = 0; }
//
// We assume that the DEVMODE was previously zeroed out by the caller
//
retStatus = STATUS_SUCCESS;
if (bEmptyDevmode) { //
// We want an empty DEVMODE (except for the LogPixels).
//
TRACE_INIT(("Drv_Trace: GetDriverParams: Default (empty) DEVMODE\n"));
RtlZeroMemory(pdevmode, sizeof(DEVMODEW)); } else {
#if LATER
//
// Let's try to get the per-user settings first.
//
TRACE_INIT(("Drv_Trace: GetDriverParams: USER Settings\n"));
for (i=0; i < NUM_DISPLAY_PARAMETERS; i++) { QueryTable[i].Name = DefaultSettings[i]; }
retStatus = RtlQueryRegistryValues(RTL_REGISTRY_USER, NULL, &QueryTable[0], NULL, NULL); if (!NT_SUCCESS(retStatus))
#endif
TRACE_INIT(("Drv_Trace: GetDriverParams: Hardware Profile Settings\n"));
for (i = 0; i < NUM_DISPLAY_PARAMETERS; i++) QueryTable[i].Name = (PWSTR)DefaultSettings[i];
if (bFromMonitor) { //
// We retrieve from per-monitor settings first, only if failed then we go to old registry
// And if we have multiple active monitors, we pick the smaller mode
//
UpdateMonitorDevices();
DEVMODEW tmpDevMode, pickedDevMode;
// Save original pdevmode away. We are using pdevmode to retrieve registry
RtlCopyMemory(&tmpDevMode, pdevmode, sizeof(DEVMODEW)); pdevmode->dmBitsPerPel = 0; pdevmode->dmPelsWidth = 0; pdevmode->dmPelsHeight = 0; pdevmode->dmDisplayFrequency = 0; pdevmode->dmDisplayFlags = 0; pdevmode->dmPanningWidth = 0; pdevmode->dmPanningHeight = 0; pdevmode->dmPosition.x = 0; pdevmode->dmPosition.y = 0; pdevmode->dmDisplayOrientation = 0; pdevmode->dmDisplayFixedOutput = 0; RtlZeroMemory(&pickedDevMode, sizeof(DEVMODEW));
k = PhysDisp->numMonitorDevice; for (i = 0; i < PhysDisp->numMonitorDevice; i++) { if (IS_ATTACHED_ACTIVE(PhysDisp->MonitorDevices[i].flag)) { hkRegistry = DrvGetRegistryHandleFromDeviceMap(PhysDisp, registryParam, &PhysDisp->MonitorDevices[i].HwID, NULL, NULL, gProtocolType); if (hkRegistry) { retStatus = RtlQueryRegistryValues(RTL_REGISTRY_HANDLE, (PWSTR)hkRegistry, &QueryTable[0], NULL, NULL); ZwCloseKey(hkRegistry); } else continue;
if (!NT_SUCCESS(retStatus)) continue;
if ((pdevmode->dmBitsPerPel == 0) || (pdevmode->dmPelsWidth == 0) || (pdevmode->dmPelsHeight == 0) ) continue;
//
// Pick the smallest mode
//
if (pickedDevMode.dmPelsWidth == 0 || pdevmode->dmPelsWidth < pickedDevMode.dmPelsWidth || (pdevmode->dmPelsWidth == pickedDevMode.dmPelsWidth && pdevmode->dmPelsHeight < pickedDevMode.dmPelsHeight) ) { k = i; pickedDevMode.dmPelsWidth = pdevmode->dmPelsWidth; pickedDevMode.dmPelsHeight = pdevmode->dmPelsHeight; } } }
// Restore original pdevmode
pdevmode->dmDriverExtra = tmpDevMode.dmDriverExtra; pdevmode->dmBitsPerPel = tmpDevMode.dmBitsPerPel; pdevmode->dmPelsWidth = tmpDevMode.dmPelsWidth; pdevmode->dmPelsHeight = tmpDevMode.dmPelsHeight; pdevmode->dmDisplayFrequency = tmpDevMode.dmDisplayFrequency; pdevmode->dmDisplayFlags = tmpDevMode.dmDisplayFlags; pdevmode->dmPanningWidth = tmpDevMode.dmPanningWidth; pdevmode->dmPanningHeight = tmpDevMode.dmPanningHeight; pdevmode->dmPosition.x = tmpDevMode.dmPosition.x; pdevmode->dmPosition.y = tmpDevMode.dmPosition.y; pdevmode->dmDisplayOrientation = tmpDevMode.dmDisplayOrientation; pdevmode->dmDisplayFixedOutput = tmpDevMode.dmDisplayFixedOutput; }
if (k < PhysDisp->numMonitorDevice && bFromMonitor) { //
// Come here if we succeed to get per monitor settings
//
retStatus = STATUS_UNSUCCESSFUL;
hkRegistry = DrvGetRegistryHandleFromDeviceMap(PhysDisp, registryParam, &PhysDisp->MonitorDevices[k].HwID, NULL, NULL, gProtocolType ); if (hkRegistry) { retStatus = RtlQueryRegistryValues(RTL_REGISTRY_HANDLE, (PWSTR)hkRegistry, &QueryTable[0], NULL, NULL); ZwCloseKey(hkRegistry); } if (!NT_SUCCESS(retStatus)) { ASSERTGDI(FALSE, "Failed to get Monitor Settings\n"); return retStatus; } } else { //
// If we failed to get per monitor settings,
// try the hardware profile first and see if we can get parameters
// from that. If that fails, fall back to getting the system
// parameters.
//
for (k=1; k<=2; k++) { hkRegistry = DrvGetRegistryHandleFromDeviceMap(PhysDisp, registryParam, NULL, NULL, NULL, gProtocolType);
if (hkRegistry == NULL) { TRACE_INIT(("Drv_Trace: GetDriverParams: failed - registry could not be opened\n")); retStatus = STATUS_UNSUCCESSFUL; } else { retStatus = RtlQueryRegistryValues(RTL_REGISTRY_HANDLE, (PWSTR)hkRegistry, &QueryTable[0], NULL, NULL);
ZwCloseKey(hkRegistry); }
//
// If something failed for the hardware profile, try
// to get the global settings
// If everything is OK, just exit the loop
//
if (NT_SUCCESS(retStatus)) { break; } else { TRACE_INIT(("Drv_Trace: GetDriverParams: get hardware profile failed - try global settings\n")); registryParam = DispDriverRegGlobal; } } }
//
// AndreVa - do we still need this information passed back to the
// applet ?
//
//
// Other common fields to the DEVMODEs
//
if (NT_SUCCESS(retStatus)) { //
// Lets check if the DEVMODE we got is all NULLs (like when
// the driver just got installed).
// If it is, the driver should be reconfigured
//
// We will only do this if we are NOT in BaseVideo, since the VGA
// BaseVideo driver need not be configured.
//
if ((attached) && (pdevmode->dmBitsPerPel == 0) && (pdevmode->dmPelsWidth == 0) && (pdevmode->dmPelsHeight == 0) && (pdevmode->dmDisplayFrequency == 0) && (pdevmode->dmDisplayFlags == 0) && (gbBaseVideo == FALSE)) { DrvLogDisplayDriverEvent(MsgInvalidUsingDefaultMode); } }
}
//
// Let's fill out all the other fields of the DEVMODE that ALWAYS
// need to be initialized.
//
if (NT_SUCCESS(retStatus)) { //
// Set versions and size.
//
pdevmode->dmSpecVersion = DM_SPECVERSION; pdevmode->dmDriverVersion = DM_SPECVERSION; pdevmode->dmSize = sizeof(DEVMODEW);
//
// Currently, the logpixel value should not be changed on the fly.
// So once it has been read out of the registry at boot time, keep
// that same value and ignore the registry.
//
if (gdmLogPixels) { pdevmode->dmLogPixels = gdmLogPixels; } else { //
// Get the devices pelDPI out of the registry
//
UNICODE_STRING us; OBJECT_ATTRIBUTES ObjectAttributes; NTSTATUS Status; HANDLE hKey; DWORD cbSize; BYTE Buf[sizeof(KEY_VALUE_PARTIAL_INFORMATION) + sizeof(DWORD)];
pdevmode->dmLogPixels = 96;
//
// Look in the Hardware Profile for the current font size.
// If that fails, look in the global software location.
//
RtlInitUnicodeString(&us, L"\\Registry\\Machine\\System" L"\\CurrentControlSet\\Hardware Profiles" L"\\Current\\Software\\Fonts");
InitializeObjectAttributes(&ObjectAttributes, &us, OBJ_CASE_INSENSITIVE|OBJ_KERNEL_HANDLE, NULL, NULL);
Status = ZwOpenKey(&hKey, KEY_READ, &ObjectAttributes);
if (!NT_SUCCESS(Status)) { RtlInitUnicodeString(&us, L"\\Registry\\Machine\\Software" L"\\Microsoft\\Windows NT" L"\\CurrentVersion\\FontDPI");
InitializeObjectAttributes(&ObjectAttributes, &us, OBJ_CASE_INSENSITIVE|OBJ_KERNEL_HANDLE, NULL, NULL);
Status = ZwOpenKey(&hKey, KEY_READ, &ObjectAttributes); }
if (NT_SUCCESS(Status)) { RtlInitUnicodeString(&us, L"LogPixels");
Status = ZwQueryValueKey(hKey, &us, KeyValuePartialInformation, (PKEY_VALUE_PARTIAL_INFORMATION)Buf, sizeof(Buf), &cbSize);
if (NT_SUCCESS(Status)) { pdevmode->dmLogPixels = *((PUSHORT)((PKEY_VALUE_PARTIAL_INFORMATION)Buf)->Data); }
ZwCloseKey(hKey); }
//
// For non high-res mode, let's force small font size so
// that various dialogs are not clipped out.
//
if (pdevmode->dmPelsHeight < 600) { pdevmode->dmLogPixels = 96; }
gdmLogPixels = pdevmode->dmLogPixels;
}
//
// Set all the appropriate DEVMODE flags.
//
pdevmode->dmFields = DM_INTERNAL_VALID_FLAGS;
if (attached) { pdevmode->dmFields |= DM_POSITION; }
if (pdevmode->dmDisplayFixedOutput != DMDFO_DEFAULT) { pdevmode->dmFields |= DM_DISPLAYFIXEDOUTPUT; }
TRACE_INIT(("Drv_Trace: GetDriverParams: DEVMODE\n")); dbgDumpDevmode(pdevmode);
if ((PhysDisp->stateFlags & DISPLAY_DEVICE_DISCONNECT) != 0 ) { DEVMODEW disconnectDevmode;
disconnectDevmode.dmFields = 0; UserGetDisconnectDeviceResolutionHint(&disconnectDevmode); if (disconnectDevmode.dmFields & DM_PELSWIDTH && disconnectDevmode.dmFields & DM_PELSHEIGHT) { pdevmode->dmFields |= DM_PELSWIDTH | DM_PELSHEIGHT; pdevmode->dmPelsWidth = disconnectDevmode.dmPelsWidth; pdevmode->dmPelsHeight = disconnectDevmode.dmPelsHeight; } } } else { TRACE_INIT(("Drv_Trace: GetSetParms: Get failed\n\n"));
}
TRACE_INIT(("Drv_Trace: GetDriverParams: Exit\n\n"));
return (retStatus); }
/**************************************************************************\
* DrvWriteDisplayDriverParameters * * Wites the resolution parameters to the registry. * * 13-Mar-1996 andreva created \**************************************************************************/
NTSTATUS DrvWriteDisplayDriverParameters( ULONG RelativeTo, PWSTR Path, PDEVMODEW pdevmode, BOOL bDetach) { ULONG i; NTSTATUS retStatus = STATUS_SUCCESS; DWORD data[NUM_DISPLAY_DRIVER_EXTRA]; DWORD numData = NUM_DISPLAY_DRIVER_EXTRA - 1; DWORD dataval;
//
// If we are deteaching, shortcircuit and just write that value out.
//
if (bDetach) { dataval = 0;
ASSERTGDI(pdevmode == NULL, "Detach should have NULL DEVMODE\n");
return RtlWriteRegistryValue(RelativeTo, Path, (PWSTR)AttachedSettings[1], REG_DWORD, &dataval, sizeof(DWORD)); }
//
// DM_POSITION determine whether or not we write the attach values
//
if (pdevmode->dmFields & DM_POSITION) { //
// Determine what we want to set the attached value to.
//
dataval = 1;
retStatus = RtlWriteRegistryValue(RelativeTo, Path, (PWSTR)AttachedSettings[1], REG_DWORD, &dataval, sizeof(DWORD)); } else { //
// Don't write the Position values if we are not attaching
//
numData -= 2; }
//
// Write all the reset of the data
//
data[0] = pdevmode->dmBitsPerPel; data[1] = pdevmode->dmPelsWidth; data[2] = pdevmode->dmPelsHeight; data[3] = pdevmode->dmDisplayFrequency; data[4] = pdevmode->dmDisplayFlags; data[5] = pdevmode->dmPanningWidth; data[6] = pdevmode->dmPanningHeight; data[7] = pdevmode->dmDisplayOrientation; data[8] = pdevmode->dmDisplayFixedOutput; data[9] = pdevmode->dmPosition.x; data[10]= pdevmode->dmPosition.y;
for (i=0; NT_SUCCESS(retStatus) && (i < numData); i++) { retStatus = RtlWriteRegistryValue(RelativeTo, Path, (PWSTR)DefaultSettings[i], REG_DWORD, &data[i], sizeof(DWORD)); }
if (NT_SUCCESS(retStatus) && pdevmode->dmDriverExtra) { retStatus = RtlWriteRegistryValue(RelativeTo, Path, (PWSTR)DefaultSettings[NUM_DISPLAY_DRIVER_EXTRA], REG_BINARY, ((PUCHAR)pdevmode) + pdevmode->dmSize, pdevmode->dmDriverExtra); }
return retStatus; }
NTSTATUS DrvUpdateDisplayDriverParameters( PGRAPHICS_DEVICE PhysDisp, LPDEVMODEW pdevmodeInformation, BOOL bDetach, BOOL bUpdateMonitors) { HANDLE hkRegistry; ULONG i; NTSTATUS retStatus = STATUS_UNSUCCESSFUL; DISP_DRIVER_REGISTRY_TYPE registryParam = DispDriverRegHardwareProfileCreate;
//
// Change the settings for the whole machine or for the user.
//
// CDS_GLOBAL is the default right now.
// When we store the settings on a per-user basis, then this flag
// will override that behaviour.
//
// if (ChangeGlobalSettings)
{ TRACE_INIT(("Drv_Trace: SetParms: Default Settings\n"));
//
// try the hardware profile first and see if we can get parameters
// from that. If that fails, fall back to getting the system
// parameters.
//
while (1) { hkRegistry = DrvGetRegistryHandleFromDeviceMap(PhysDisp, registryParam, NULL, NULL, NULL, gProtocolType);
if (hkRegistry) { retStatus = DrvWriteDisplayDriverParameters(RTL_REGISTRY_HANDLE, (LPWSTR) hkRegistry, pdevmodeInformation, bDetach); ZwCloseKey(hkRegistry); }
if ( (NT_SUCCESS(retStatus)) || (registryParam != DispDriverRegHardwareProfileCreate) ) break;
registryParam = DispDriverRegGlobal; } }
//
// Update per-monitor setting
//
if (NT_SUCCESS(retStatus) && bUpdateMonitors) { UpdateMonitorDevices();
for (i = 0; i < PhysDisp->numMonitorDevice; i++) { if (IS_ATTACHED_ACTIVE(PhysDisp->MonitorDevices[i].flag)) { hkRegistry = DrvGetRegistryHandleFromDeviceMap(PhysDisp, registryParam, &PhysDisp->MonitorDevices[i].HwID, NULL, NULL, gProtocolType); if (hkRegistry) { // We don't need to check the status here. Per adapter settings plays
// as a backup
DrvWriteDisplayDriverParameters(RTL_REGISTRY_HANDLE, (LPWSTR) hkRegistry, pdevmodeInformation, bDetach); ZwCloseKey(hkRegistry); } } } }
TRACE_INIT(("Drv_Trace: SetParms: Exit\n\n"));
return retStatus; }
/**************************************************************************\
* DrvGetHdevName * * Returns the name of the device associated with an HDEV so GetMonitorInfo * can return this information * * 07-Jul-1998 andreva created \**************************************************************************/
BOOL DrvGetHdevName( HDEV hdev, PWCHAR DeviceName ) { PDEVOBJ pdo(hdev);
RtlCopyMemory(DeviceName, pdo.ppdev->pGraphicsDevice->szWinDeviceName, sizeof(pdo.ppdev->pGraphicsDevice->szWinDeviceName));
return TRUE; }
/**************************************************************************\
* DrvGetDeviceFromName * * Given the name of a device, returns a pointer to a structure describing * the device. * * Specifying NULL tells the system to return the information for the default * device on which the application is running. * * returns a PGRAPHICS_DEVICE * * *** NOTE * If the caller requests Exclusive access, the caller must call back and * release the access once the device is no longer used. * * 31-May-1994 andreva created \**************************************************************************/
PGRAPHICS_DEVICE DrvGetDeviceFromName( PUNICODE_STRING pstrDeviceName, MODE PreviousMode) { ULONG i = 0; NTSTATUS status; PGRAPHICS_DEVICE PhysDisp; PDEVICE_OBJECT pDeviceObject = NULL; UNICODE_STRING uCapturedString; UNICODE_STRING uString; BOOL fDisableSuccess;
TRACE_INIT(("Drv_Trace: GetDev: Enter"));
__try { if (PreviousMode == UserMode) { uCapturedString.Length = 0;
if (pstrDeviceName) { ProbeForRead(pstrDeviceName, sizeof(UNICODE_STRING), sizeof(CHAR)); uCapturedString = *pstrDeviceName; }
if (uCapturedString.Length) { ProbeForRead(uCapturedString.Buffer, uCapturedString.Length, sizeof(BYTE)); } else {
#if DONT_CHECKIN
PDESKTOP pdesk = PtiCurrent()->rpdesk; PDISPLAYINFO pDispInfo;
if (pdesk) { //
// Special case for boot-up time.
//
pDispInfo = pdesk->pDispInfo; } else { pDispInfo = G_TERM(pDispInfo); }
RtlInitUnicodeString(&uCapturedString, pDispInfo->pDevInfo->szWinDeviceName); #endif
} } else { ASSERTGDI(pstrDeviceName >= (PUNICODE_STRING const)MM_USER_PROBE_ADDRESS, "Bad kernel mode address\n"); uCapturedString = *pstrDeviceName; }
//
// Look for an existing handle in our handle table.
// Start by looking for the VGACOMPATIBLE string, which is
// our VgaCompatible device
//
RtlInitUnicodeString(&uString, L"VGACOMPATIBLE");
if (RtlEqualUnicodeString(&uCapturedString, &uString, TRUE)) { PhysDisp = &gFullscreenGraphicsDevice; } else { for (PhysDisp = gpGraphicsDeviceList; PhysDisp; PhysDisp = PhysDisp->pNextGraphicsDevice) {
RtlInitUnicodeString(&uString, &(PhysDisp->szWinDeviceName[0]));
if (RtlEqualUnicodeString(&uCapturedString, &uString, TRUE)) { break; } } }
} __except (EXCEPTION_EXECUTE_HANDLER) { PhysDisp = NULL; }
if (PhysDisp == NULL) { WARNING("DrvGetDeviceFromName: Calling for a non-exsting device!"); return NULL; }
TRACE_INIT((" - Exit\n"));
return PhysDisp; }
/**************************************************************************\
* PruneModesByMonitors * * Read the EDID from regstry first. Retrieve the Monitor capabilities. * And prune mode list based on Monitor capability. \**************************************************************************/
int compModeCap(LPMODECAP pModeCap1, LPMODECAP pModeCap2) { if (pModeCap1->dmWidth != pModeCap2->dmWidth) { return (pModeCap1->dmWidth - pModeCap2->dmWidth); } return (pModeCap1->dmHeight - pModeCap2->dmHeight); }
ULONG InsertModecapList(LPMODECAP pmc, LPMODECAP ModeCaps, ULONG numModeCaps) { ULONG i; int comp = -1; for (i = 0; i < numModeCaps; i++) { comp = compModeCap(pmc, &ModeCaps[i]); if (comp > 0) { continue; } if (comp == 0) { //
// For duplicated entries, pick the bigger one
//
if (ModeCaps[i].freq < pmc->freq) { ModeCaps[i].freq = pmc->freq; ModeCaps[i].MinVFreq = pmc->MinVFreq; } if (ModeCaps[i].MaxHFreq < pmc->MaxHFreq) { ModeCaps[i].MaxHFreq = pmc->MaxHFreq; ModeCaps[i].MinHFreq = pmc->MinHFreq; } return numModeCaps; }
//
// If buffer size reaches the limit, do nothing and return
//
if (numModeCaps >= MAX_MODE_CAPABILITY) { return numModeCaps; }
RtlMoveMemory(&ModeCaps[i+1], &ModeCaps[i], (numModeCaps-i)*sizeof(MODECAP)); ModeCaps[i] = *pmc; return (numModeCaps+1); } ModeCaps[numModeCaps] = *pmc; return (numModeCaps+1); }
ULONG xwtol(LPWSTR wptr) { for (ULONG v = 0; (*wptr >= L'0' && *wptr <= L'9') || *wptr == L' '; *wptr++) { if (*wptr != L' ') v = v*10 + (*wptr - L'0'); } return v; }
BOOL ParseModeCap(LPWSTR wstr, LPMODECAP pmc, BOOL bFreq) { LPWSTR wptr1, wptr2, wptr3; ULONG v[4] = {0, 0xFFFFFFFF, 0, 0xFFFFFFFF}, i; for (wptr1 = wptr2 = wstr, i = 0; wptr2 != NULL && i < 4; wptr1 = wptr2+1, i++) { wptr2 = wcschr(wptr1, L','); if (wptr2 != NULL) { *wptr2 = 0; } if (bFreq) { wptr3 = wcschr(wptr1, L'-'); if (wptr3 != NULL) { *wptr3 = 0; v[i] = xwtol(wptr1); wptr1 = wptr3+1; } else { v[i] = 0; } i++; } v[i] = xwtol(wptr1); } if (bFreq) { pmc->MinVFreq = max(pmc->MinVFreq, v[2]); pmc->freq = min(pmc->freq, v[3]); pmc->MinHFreq = max(pmc->MinHFreq, v[0] * 1000); pmc->MaxHFreq = min(pmc->MaxHFreq, v[1] * 1000); } else { if (v[0] == 0 || v[1] == 0xFFFFFFFF) { return FALSE; } pmc->dmWidth = v[0]; pmc->dmHeight = v[1]; pmc->freq = v[2]; } return TRUE; }
ULONG GetMonitorCapabilityFromInf(PDEVICE_OBJECT pdo, LPMODECAP ModeCaps) { HANDLE hkRegistry, hkRegistry1, hkRegistry2;
if ( !NT_SUCCESS(IoOpenDeviceRegistryKey(pdo, PLUGPLAY_REGKEY_DRIVER, KEY_READ, &hkRegistry)) ) { return 0; }
ULONG numModeCaps = 0; OBJECT_ATTRIBUTES ObjectAttributes; UNICODE_STRING UnicodeString;
RtlInitUnicodeString(&UnicodeString, L"MODES"); InitializeObjectAttributes(&ObjectAttributes, &UnicodeString, OBJ_CASE_INSENSITIVE|OBJ_KERNEL_HANDLE, hkRegistry, NULL); if ( NT_SUCCESS (ZwOpenKey(&hkRegistry1, KEY_READ, &ObjectAttributes)) ) { WCHAR data[128], buf[128]; ULONG i = 0, size; MODECAP mc;
while (NT_SUCCESS(ZwEnumerateKey(hkRegistry1, i, KeyBasicInformation, data, sizeof(data), &size))) { i++;
UnicodeString.Buffer = ((PKEY_BASIC_INFORMATION) data)->Name; UnicodeString.Length = (USHORT) ((PKEY_BASIC_INFORMATION) data)->NameLength; UnicodeString.MaximumLength = (USHORT) ((PKEY_BASIC_INFORMATION) data)->NameLength;
//
// 1024, 768
//
wcsncpy(buf, UnicodeString.Buffer, min(UnicodeString.Length, sizeof(buf))/sizeof(WCHAR)); if (UnicodeString.Length < sizeof(buf) ) buf[UnicodeString.Length/sizeof(WCHAR)] = 0; buf[sizeof(buf)/sizeof(WCHAR)-1] = 0; if (!ParseModeCap(buf, &mc, FALSE)) continue;
InitializeObjectAttributes(&ObjectAttributes, &UnicodeString, OBJ_CASE_INSENSITIVE|OBJ_KERNEL_HANDLE, hkRegistry1, NULL);
if (NT_SUCCESS (ZwOpenKey(&hkRegistry2, MAXIMUM_ALLOWED, &ObjectAttributes))) { WCHAR modeStr[] = L"Mode1"; BOOL bSucceed = FALSE;
for (ULONG j = 0; j < 9; j++) { RtlInitUnicodeString(&UnicodeString, modeStr);
if (NT_SUCCESS(ZwQueryValueKey(hkRegistry2, &UnicodeString, KeyValueFullInformation, data, sizeof(data), &size)) ) { wcsncpy(buf, (LPWSTR)((PBYTE)data + ((PKEY_VALUE_FULL_INFORMATION)data)->DataOffset), sizeof(buf)/sizeof(WCHAR)-1); //
// MinHFreq MaxHFreq MinVFreq MaxVFreq
// 31.0 - 82.0, 55.0 - 100.0, +,+
//
mc.MinVFreq = MIN_REFRESH_RATE; mc.freq = 0xFFFFFFFF; mc.MinHFreq = 0; mc.MaxHFreq = 0xFFFFFFFF; if (ParseModeCap(buf, &mc, TRUE)) { numModeCaps = InsertModecapList(&mc, ModeCaps, numModeCaps); }
bSucceed = TRUE; } else if (bSucceed) { break; }
modeStr[4]++; } ZwCloseKey(hkRegistry2); } }
ZwCloseKey(hkRegistry1); } ZwCloseKey(hkRegistry); return numModeCaps; }
BOOL GetRegEDID(PDEVICE_OBJECT pdo, PBYTE pBuffer, PBYTE *ppEdid) { HANDLE hkRegistry; NTSTATUS status;
// Get EDID information from registry
if ( !NT_SUCCESS(IoOpenDeviceRegistryKey(pdo, PLUGPLAY_REGKEY_DEVICE, KEY_READ, &hkRegistry)) ) { TRACE_INIT(("Drv_Trace: GetMonitorCapability: Failed to retrieve EDID\n")); return FALSE; }
UNICODE_STRING UnicodeString; ULONG cbSize; RtlInitUnicodeString(&UnicodeString, L"EDID");
status = ZwQueryValueKey(hkRegistry, &UnicodeString, KeyValueFullInformation, pBuffer, 400, &cbSize);
if (NT_SUCCESS(status)) { if ( (((PKEY_VALUE_FULL_INFORMATION)pBuffer)->DataLength) < 256) status = STATUS_UNSUCCESSFUL; else *ppEdid = (PBYTE)(pBuffer + ((PKEY_VALUE_FULL_INFORMATION)pBuffer)->DataOffset); } (VOID)ZwCloseKey(hkRegistry);
if (!NT_SUCCESS(status)) return FALSE;
return TRUE; }
BOOL GetValuesFromInf(PDEVICE_OBJECT pdo, ULONG op, LPMODECAP pmc) { if (op > 1) return FALSE;
HANDLE hkRegistry; static LPWSTR ValueName[] = { L"PreferredMode", L"ClearType" };
if ( !NT_SUCCESS(IoOpenDeviceRegistryKey(pdo, PLUGPLAY_REGKEY_DRIVER, KEY_READ, &hkRegistry)) ) return FALSE;
UNICODE_STRING UnicodeString; WCHAR data[128], buf[128]; ULONG size;
// Assuming return failure
BOOL bRet = FALSE; RtlInitUnicodeString(&UnicodeString, ValueName[op]); if (NT_SUCCESS(ZwQueryValueKey(hkRegistry, &UnicodeString, KeyValueFullInformation, data, sizeof(data), &size)) ) { switch (op) { case 0: // GetPreferredMode
wcsncpy(buf, (LPWSTR)((PBYTE)data + ((PKEY_VALUE_FULL_INFORMATION)data)->DataOffset), sizeof(buf)/sizeof(WCHAR)-1); // 1024,768,60
if (ParseModeCap(buf, pmc, FALSE)) { if (pmc->dmWidth != 0 && pmc->dmHeight != 0 && pmc->freq != 0) bRet = TRUE; } break; case 1: // Get ClearType Capability
pmc->dmWidth = *(PULONG) ( (PBYTE)data + ((PKEY_VALUE_FULL_INFORMATION)data)->DataOffset ); bRet = TRUE; break; default: break; } }
ZwCloseKey(hkRegistry);
return bRet; }
/**************************************************************************\
* GetDefaultFrequencyRange * * Routine Description: * * Returns default frequency range for the monitor. * * Arguments: * * pFrequencyRange - Points to storage for monitor frequency limits. * * Returns: * * Default monitor frequency limits returned in pFrequencyRange. * * 08-Oct-1999 mmacie created \**************************************************************************/
VOID GetDefaultFrequencyRange( OUT PFREQUENCY_RANGE pFrequencyRange ) { ASSERT(NULL != pFrequencyRange);
pFrequencyRange->ulMinVerticalRate = MIN_REFRESH_RATE; pFrequencyRange->ulMaxVerticalRate = 0xffffffff; pFrequencyRange->ulMinHorizontalRate = 0; pFrequencyRange->ulMaxHorizontalRate = 0xffffffff; pFrequencyRange->ulMinPixelClock = 0; pFrequencyRange->ulMaxPixelClock = 0xffffffff; }
/**************************************************************************\
* GetMonitorCapability2 * * Routine Description: * * Parsing routine for EDID Version 2. * * Arguments: * * pEdid2 - Points to EDID Version 2 data. * pModeCaps - Points to storage for monitor cap details. * pFrequencyRange - Points to storage for monitor frequency limits. * * Returns: * * Number of mode capabilites. * - Mode cap data returned in pModeCaps. * - Monitor frequency limits returned in pFrequencyRange. * * 21-Sep-1999 mmacie created \**************************************************************************/
ULONG GetMonitorCapability2( IN PEDID2 pEdid2, OUT PMODECAP pModeCaps, OUT PFREQUENCY_RANGE pFrequencyRange ) { ULONG ulNumberOfModeCaps; ULONG ulNumberOfLuminanceTables; ULONG ulNumberOfFrequencyRanges; ULONG ulNumberOfDetailTimingRanges; ULONG ulNumberOfTimingCodes; ULONG ulNumberOfDetailTimings; ULONG ulEdidOffset; ULONG ulTemp;
ASSERT(NULL != pEdid2); ASSERT(NULL != pModeCaps); ASSERT(NULL != pFrequencyRange); ASSERT(0x20 == pEdid2->ucEdidVersionRevision); // Make sure EDID Version 2
//
// Parse map of timings.
//
ulNumberOfLuminanceTables = (pEdid2->ucaMapOfTiming[0] & EDID2_MOT0_LUMINANCE_TABLE_MASK) >> EDID2_MOT0_LUMINANCE_TABLE_SHIFT;
ulNumberOfFrequencyRanges = (pEdid2->ucaMapOfTiming[0] & EDID2_MOT0_FREQUENCY_RANGE_MASK) >> EDID2_MOT0_FREQUENCY_RANGE_SHIFT;
ulNumberOfDetailTimingRanges = (pEdid2->ucaMapOfTiming[0] & EDID2_MOT0_DETAIL_TIMING_RANGE_MASK) >> EDID2_MOT0_DETAIL_TIMING_RANGE_SHIFT;
ulNumberOfTimingCodes = (pEdid2->ucaMapOfTiming[1] & EDID2_MOT1_TIMING_CODE_MASK) >> EDID2_MOT1_TIMING_CODE_SHIFT;
ulNumberOfDetailTimings = (pEdid2->ucaMapOfTiming[1] & EDID2_MOT1_DETAIL_TIMING_MASK) >> EDID2_MOT1_DETAIL_TIMING_SHIFT;
TRACE_INIT(("win32k!GetMonitorCapability2: NumberOfLuminanceTables = %lu\n", ulNumberOfLuminanceTables)); TRACE_INIT(("win32k!GetMonitorCapability2: NumberOfFrequencyRanges = %lu\n", ulNumberOfFrequencyRanges)); TRACE_INIT(("win32k!GetMonitorCapability2: NumberOfDetailTimingRanges = %lu\n", ulNumberOfDetailTimingRanges)); TRACE_INIT(("win32k!GetMonitorCapability2: NumberOfDetailTimingCodes = %lu\n", ulNumberOfTimingCodes)); TRACE_INIT(("win32k!GetMonitorCapability2: NumberOfDetailTimings = %lu\n", ulNumberOfDetailTimings));
//
// Check for bad EDIDs.
//
if ((ulNumberOfLuminanceTables > EDID2_MAX_LUMINANCE_TABLES) || (ulNumberOfFrequencyRanges > EDID2_MAX_FREQUENCY_RANGES) || (ulNumberOfDetailTimingRanges > EDID2_MAX_DETAIL_TIMING_RANGES) || (ulNumberOfTimingCodes > EDID2_MAX_TIMING_CODES) || (ulNumberOfDetailTimings > EDID2_MAX_DETAIL_TIMINGS)) { WARNING("Bad EDID2\n"); GetDefaultFrequencyRange(pFrequencyRange); return 0; }
ulEdidOffset = EDID2_LUMINANCE_TABLE_OFFSET;
//
// Move over luminance tables.
//
if (ulNumberOfLuminanceTables) { PUCHAR pucLuminanceTable;
for (ulTemp = 0; ulTemp < ulNumberOfLuminanceTables; ulTemp++) { //
// Check for bad EDIDs.
//
if (ulEdidOffset >= (sizeof (EDID2) - 1)) { WARNING("Bad EDID2\n"); GetDefaultFrequencyRange(pFrequencyRange); return 0; }
pucLuminanceTable = (PUCHAR)pEdid2 + ulEdidOffset;
ulEdidOffset += (((*pucLuminanceTable & EDID2_LT0_SUB_CHANNELS_FLAG) ? 3 : 1) * ((*pucLuminanceTable & EDID2_LT0_ENTRIES_MASK) >> EDID2_LT0_ENTRIES_SHIFT) + 1); } }
//
// Parse frequency ranges.
//
if (ulNumberOfFrequencyRanges) { PEDID2_FREQUENCY_RANGE pEdidRange; ULONG ulRate;
//
// Currently the mode prunning code cannot handle multiple
// frequency ranges but EDID Version 2 can supply them.
// We're hacking around here by merging all of them into a single
// "super frequency range".
//
//
// Make sure we pick up the first range.
//
pFrequencyRange->ulMinVerticalRate = 0xffffffff; pFrequencyRange->ulMaxVerticalRate = 0; pFrequencyRange->ulMinHorizontalRate = 0xffffffff; pFrequencyRange->ulMaxHorizontalRate = 0; pFrequencyRange->ulMinPixelClock = 0xffffffff; pFrequencyRange->ulMaxPixelClock = 0;
for (ulTemp = 0; ulTemp < ulNumberOfFrequencyRanges; ulTemp++, ulEdidOffset += sizeof (EDID2_FREQUENCY_RANGE)) { //
// Check for bad EDIDs.
//
if (ulEdidOffset >= (sizeof (EDID2) - sizeof (EDID2_FREQUENCY_RANGE))) { WARNING("Bad EDID2\n"); GetDefaultFrequencyRange(pFrequencyRange); return 0; }
pEdidRange = (PEDID2_FREQUENCY_RANGE)((PUCHAR)pEdid2 + ulEdidOffset);
ulRate = (ULONG)(pEdidRange->ucMinFrameFieldRateBits9_2) << 2; ulRate += (pEdidRange->ucFrameFieldLineRatesBits1_0 & 0xc0) >> 6;
if (ulRate < pFrequencyRange->ulMinVerticalRate) pFrequencyRange->ulMinVerticalRate = ulRate;
ulRate = (ULONG)(pEdidRange->ucMaxFrameFieldRateBits9_2) << 2; ulRate += (pEdidRange->ucFrameFieldLineRatesBits1_0 & 0x30) >> 4;
if (ulRate > pFrequencyRange->ulMaxVerticalRate) pFrequencyRange->ulMaxVerticalRate = ulRate;
ulRate = (ULONG)(pEdidRange->ucMinLineRateBits9_2) << 2; ulRate += (pEdidRange->ucFrameFieldLineRatesBits1_0 & 0x0c) >> 2; ulRate *= 1000;
if (ulRate < pFrequencyRange->ulMinHorizontalRate) pFrequencyRange->ulMinHorizontalRate = ulRate;
ulRate = (ULONG)(pEdidRange->ucMaxLineRateBits9_2) << 2; ulRate += (pEdidRange->ucFrameFieldLineRatesBits1_0 & 0x03); ulRate *= 1000;
if (ulRate > pFrequencyRange->ulMaxHorizontalRate) pFrequencyRange->ulMaxHorizontalRate = ulRate;
ulRate = (ULONG)((pEdidRange->ucPixelRatesBits11_8) & 0xf0) << 4; ulRate += pEdidRange->ucMinPixelRateBits7_0; ulRate *= 1000000;
if (ulRate < pFrequencyRange->ulMinPixelClock) pFrequencyRange->ulMinPixelClock = ulRate;
ulRate = (ULONG)((pEdidRange->ucPixelRatesBits11_8) & 0x0f) << 8; ulRate += pEdidRange->ucMaxPixelRateBits7_0; ulRate *= 1000000;
if (ulRate > pFrequencyRange->ulMaxPixelClock) pFrequencyRange->ulMaxPixelClock = ulRate;
//
// Check for bad EDIDs.
//
if ((pFrequencyRange->ulMinVerticalRate > pFrequencyRange->ulMaxVerticalRate) || (pFrequencyRange->ulMinHorizontalRate > pFrequencyRange->ulMaxHorizontalRate) || (pFrequencyRange->ulMinPixelClock > pFrequencyRange->ulMaxPixelClock) || (pFrequencyRange->ulMaxVerticalRate < 60) || (pFrequencyRange->ulMaxHorizontalRate < (60*480)) || (pFrequencyRange->ulMaxPixelClock < (60*480*640)) ) { WARNING("Bad EDID2\n"); GetDefaultFrequencyRange(pFrequencyRange); } } }
ulNumberOfModeCaps = 0;
//
// Parse detail timing ranges.
//
if (ulNumberOfDetailTimingRanges) { PEDID2_DETAIL_TIMING_RANGE pEdidRange; MODECAP modeCap; ULONG ulHorizontalTotal; ULONG ulVerticalTotal; ULONG ulPixelClock;
//
// Currently the mode prunning code cannot handle detailed
// timing ranges but EDID Version 2 can supply them.
// We're hacking around here by taking maximum values only.
//
modeCap.MinVFreq = MIN_REFRESH_RATE; modeCap.MinHFreq = 0; modeCap.MaxHFreq = 0xffffffff;
for (ulTemp = 0; ulTemp < ulNumberOfDetailTimingRanges; ulTemp++, ulEdidOffset += sizeof (EDID2_DETAIL_TIMING_RANGE)) { //
// Check for bad EDIDs.
//
if (ulEdidOffset >= (sizeof (EDID2) - sizeof (EDID2_DETAIL_TIMING_RANGE))) { WARNING("Bad EDID2\n"); GetDefaultFrequencyRange(pFrequencyRange); return 0; }
pEdidRange = (PEDID2_DETAIL_TIMING_RANGE)((PUCHAR)pEdid2 + ulEdidOffset);
modeCap.dmWidth = (ULONG)(pEdidRange->ucActiveHighBits & 0xf0) << 4; modeCap.dmWidth += pEdidRange->ucHorizontalActiveLowByte;
modeCap.dmHeight = (ULONG)(pEdidRange->ucActiveHighBits & 0x0f) << 8; modeCap.dmHeight += pEdidRange->ucVerticalActiveLowByte;
ulHorizontalTotal = (ULONG)(pEdidRange->ucMaxBlankHighBits & 0xf0) << 4; ulHorizontalTotal += pEdidRange->ucMaxHorizontalBlankLowByte + modeCap.dmWidth;
ulVerticalTotal = (ULONG)(pEdidRange->ucMaxBlankHighBits & 0x0f) << 8; ulVerticalTotal += pEdidRange->ucMaxVerticalBlankLowByte + modeCap.dmHeight;
//
// Make sure we won't divide by zero in case of bad EDID.
//
if ((0 == ulHorizontalTotal) || (0 == ulVerticalTotal)) { WARNING("Bad EDID2\n"); GetDefaultFrequencyRange(pFrequencyRange); return 0; }
ulPixelClock = (ULONG)(pEdidRange->usMaxPixelClock) * 10000;
//
// Calculate refresh rate rounding to the nearest integer.
//
modeCap.freq = (((10 * ulPixelClock) / (ulHorizontalTotal * ulVerticalTotal)) + 5) / 10;
if (pEdidRange->ucFlags & EDID2_DT_INTERLACED) modeCap.freq /= 2;
TRACE_INIT(("win32k!GetMonitorCapability2: Detailed range %lux%lu at %luHz\n", modeCap.dmWidth, modeCap.dmHeight, modeCap.freq));
ulNumberOfModeCaps = InsertModecapList(&modeCap, pModeCaps, ulNumberOfModeCaps); } }
//
// Parse timing codes.
//
if (ulNumberOfTimingCodes) { PEDID2_TIMING_CODE pTimingCode; MODECAP modeCap;
modeCap.MinVFreq = MIN_REFRESH_RATE; modeCap.MinHFreq = 0; modeCap.MaxHFreq = 0xffffffff;
for (ulTemp = 0; ulTemp < ulNumberOfTimingCodes; ulTemp++, ulEdidOffset += sizeof (EDID2_TIMING_CODE)) { //
// Check for bad EDIDs.
//
if (ulEdidOffset >= (sizeof (EDID2) - sizeof (EDID2_TIMING_CODE))) { WARNING("Bad EDID2\n"); GetDefaultFrequencyRange(pFrequencyRange); return 0; }
pTimingCode = (PEDID2_TIMING_CODE)((PUCHAR)pEdid2 + ulEdidOffset);
modeCap.dmWidth = 16 * pTimingCode->ucHorizontalActive + 256; modeCap.dmHeight = (100 * modeCap.dmWidth) / pTimingCode->ucAspectRatio; modeCap.freq = pTimingCode->ucRefreshRate;
if (pTimingCode->ucFlags & EDID2_TC_INTERLACED) modeCap.freq /= 2;
TRACE_INIT(("win32k!GetMonitorCapability2: Timing code %lux%lu at %luHz\n", modeCap.dmWidth, modeCap.dmHeight, modeCap.freq));
ulNumberOfModeCaps = InsertModecapList(&modeCap, pModeCaps, ulNumberOfModeCaps); } }
//
// Parse detail timings.
//
if (ulNumberOfDetailTimings) { PEDID2_DETAIL_TIMING pDetailTiming; MODECAP modeCap; ULONG ulHorizontalTotal; ULONG ulVerticalTotal; ULONG ulPixelClock;
modeCap.MinVFreq = MIN_REFRESH_RATE; modeCap.MinHFreq = 0; modeCap.MaxHFreq = 0xffffffff;
for (ulTemp = 0; ulTemp < ulNumberOfDetailTimings; ulTemp++, ulEdidOffset += sizeof (EDID2_DETAIL_TIMING)) { //
// Check for bad EDIDs.
//
if (ulEdidOffset >= (sizeof (EDID2) - sizeof (EDID2_DETAIL_TIMING))) { WARNING("Bad EDID2\n"); GetDefaultFrequencyRange(pFrequencyRange); return 0; }
pDetailTiming = (PEDID2_DETAIL_TIMING)((PUCHAR)pEdid2 + ulEdidOffset);
modeCap.dmWidth = (ULONG)(pDetailTiming->ucHorizontalHighBits & 0xf0) << 4; modeCap.dmWidth += pDetailTiming->ucHorizontalActiveLowByte;
modeCap.dmHeight = (ULONG)(pDetailTiming->ucVerticalHighBits & 0xf0) << 4; modeCap.dmHeight += pDetailTiming->ucVerticalActiveLowByte;
ulHorizontalTotal = (ULONG)(pDetailTiming->ucHorizontalHighBits & 0x0f) << 8; ulHorizontalTotal += pDetailTiming->ucHorizontalBlankLowByte + modeCap.dmWidth;
ulVerticalTotal = (ULONG)(pDetailTiming->ucVerticalHighBits & 0x0f) << 8; ulVerticalTotal += pDetailTiming->ucVerticalBlankLowByte + modeCap.dmHeight;
//
// Make sure we won't divide by zero in case of bad EDID.
//
if ((0 == ulHorizontalTotal) || (0 == ulVerticalTotal)) { WARNING("Bad EDID2\n"); GetDefaultFrequencyRange(pFrequencyRange); return 0; }
ulPixelClock = (ULONG)(pDetailTiming->usPixelClock) * 10000;
//
// Calculate refresh rate rounding to the nearest integer.
//
modeCap.freq = (((10 * ulPixelClock) / (ulHorizontalTotal * ulVerticalTotal)) + 5) / 10;
if (pDetailTiming->ucFlags & EDID2_DT_INTERLACED) modeCap.freq /= 2;
TRACE_INIT(("win32k!GetMonitorCapability2: Detailed timing %lux%lu at %luHz\n", modeCap.dmWidth, modeCap.dmHeight, modeCap.freq));
ulNumberOfModeCaps = InsertModecapList(&modeCap, pModeCaps, ulNumberOfModeCaps); } }
//
// Define monitor frequency limits in case EDID didn't have it.
//
if (0 == ulNumberOfFrequencyRanges) { GetDefaultFrequencyRange(pFrequencyRange); }
TRACE_INIT(("win32k!GetMonitorCapability2: MinVerticalRate = %lu\n", pFrequencyRange->ulMinVerticalRate)); TRACE_INIT(("win32k!GetMonitorCapability2: MaxVerticalRate = %lu\n", pFrequencyRange->ulMaxVerticalRate)); TRACE_INIT(("win32k!GetMonitorCapability2: MinHorizontalRate = %lu\n", pFrequencyRange->ulMinHorizontalRate)); TRACE_INIT(("win32k!GetMonitorCapability2: MaxHorizontalRate = %lu\n", pFrequencyRange->ulMaxHorizontalRate)); TRACE_INIT(("win32k!GetMonitorCapability2: MinPixelClock = %lu\n", pFrequencyRange->ulMinPixelClock)); TRACE_INIT(("win32k!GetMonitorCapability2: MaxPixelClock = %lu\n", pFrequencyRange->ulMaxPixelClock));
//
// Cascade refresh rates.
//
for (ulTemp = ulNumberOfModeCaps; ulTemp > 1; ulTemp--) { if (pModeCaps[ulTemp - 2].freq < pModeCaps[ulTemp - 1].freq) pModeCaps[ulTemp - 2].freq = pModeCaps[ulTemp - 1].freq; }
return ulNumberOfModeCaps; }
/**************************************************************************\
* GetMonitorCapability1 * * Routine Description: * * Parsing routine for EDID Version 1.x * * Arguments: * * pEdid - Points to EDID Version 1 data. * pModeCaps - Points to storage for monitor cap details. * pFrequencyRange - Points to storage for monitor frequency limits. * * Returns: * * Number of mode capabilites. * - Mode cap data returned in pModeCaps. * - Monitor frequency limits returned in pFrequencyRange. * * 21-Sep-1999 dennyd created \**************************************************************************/
ULONG GetMonitorCapability1( IN PBYTE pEdid, OUT PMODECAP pModeCaps, OUT PFREQUENCY_RANGE pFrequencyRange ) { ULONG numModeCaps = 0; MODECAP mc; PBYTE ptr; BYTE c; int i; int r1[] = {1, 4, 5, 16}, r2[] = {1, 3, 4, 9}; UCHAR ucaEdid1Header[] = {0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00};
GetDefaultFrequencyRange(pFrequencyRange);
//
// Check if EDID Version 1.
//
for (i = 0; i < (sizeof (ucaEdid1Header) / sizeof (UCHAR)); i++) { if (pEdid[i] != ucaEdid1Header[i]) return 0; }
// Handle established timings
MODECAP mcArray[] = {{1280, 1024, 75}, {1024, 768, 75}, {1024, 768, 70}, {1024, 768, 60}, {1024, 768, 87}, {800, 600, 75}, {800, 600, 72}, {800, 600, 60}, {800, 600, 56}, {640, 480, 75}, {640, 480, 72}, {640, 480, 67}, {640, 480, 60} }; pEdid[0x24] = ((((pEdid[0x24] & 0xc0) >> 1) & 0x60) | (pEdid[0x24] & 0x1f)) & 0x7f; for (i = 0; i < 13; i++) { mcArray[i].MinVFreq = MIN_REFRESH_RATE; mcArray[i].MinHFreq = 0; mcArray[i].MaxHFreq = 0xFFFFFFFF; if ((pEdid[0x24-i/7] >> (i%7)) & 0x01) numModeCaps = InsertModecapList(&mcArray[i], pModeCaps, numModeCaps); }
mc.MinVFreq = MIN_REFRESH_RATE; mc.MinHFreq = 0; mc.MaxHFreq = 0xFFFFFFFF; // Standard Timing
for (i = 0, ptr = &pEdid[0x26]; i < 8; i++, ptr += 2) { if (*ptr == 0 || *ptr == 1) continue;
mc.dmWidth = ((ULONG)ptr[0] + 31) << 3; c = (ptr[1] >> 6 ) & 0x03; mc.dmHeight = mc.dmWidth * r2[c] / r1[c]; mc.freq = (ULONG)(ptr[1] & 0x3F) + 60;
numModeCaps = InsertModecapList(&mc, pModeCaps, numModeCaps); }
// Detailed timing/Monitor Descriptor
for (int k = 0; k < 4; k++) { ptr = &pEdid[0x36+ 18*k]; if ((ptr[0] != 0 || ptr[1] != 0) && ptr[4] != 0) { // Detailed timing Descriptor
mc.dmWidth = (ULONG)ptr[2] + ((ULONG)(ptr[4]&0xF0)) * 0x10; mc.dmHeight = (ULONG)ptr[5] + ((ULONG)(ptr[7]&0xF0)) * 0x10; if (mc.dmWidth == 0 || mc.dmHeight == 0) continue;
mc.freq = ((ULONG)ptr[0] + ((ULONG)ptr[1]) * 0x100) * 10000; mc.freq /= (mc.dmWidth + (ULONG)ptr[3] + ((ULONG)(ptr[4]&0x0F)) * 0x100) * (mc.dmHeight+ (ULONG)ptr[6] + ((ULONG)(ptr[7]&0x0F)) * 0x100); // If it's interlaced mode
if (ptr[17] & 0x80) mc.freq >>= 1;
numModeCaps = InsertModecapList(&mc, pModeCaps, numModeCaps); } else if (ptr[3] == 0xFA) { // Monitor Descriptor--Standard Timing
for (i = 0, ptr += 5; i < 6; i++, ptr += 2) { if (*ptr == 0 || *ptr == 1) continue;
mc.dmWidth = ((ULONG)ptr[0] + 31) << 3; c = (ptr[1] >> 6 ) & 0x03; mc.dmHeight = mc.dmWidth * r2[c] / r1[c]; mc.freq = (ULONG)(ptr[1] & 0x3F) + 60;
numModeCaps = InsertModecapList(&mc, pModeCaps, numModeCaps); } } else if (ptr[3] == 0xFD) { pFrequencyRange->ulMinVerticalRate = (ULONG)ptr[5]; pFrequencyRange->ulMaxVerticalRate = (ULONG)ptr[6]; pFrequencyRange->ulMinHorizontalRate = ((ULONG)ptr[7]) * 1000; pFrequencyRange->ulMaxHorizontalRate = ((ULONG)ptr[8]) * 1000; pFrequencyRange->ulMinPixelClock = 0; pFrequencyRange->ulMaxPixelClock = ((ULONG)ptr[9]) * 10000000; } }
for (i = (int)numModeCaps-2; i >= 0; i--) { if (pModeCaps[i].freq < pModeCaps[i+1].freq) pModeCaps[i].freq = pModeCaps[i+1].freq; }
return numModeCaps; }
ULONG GetMonitorCapability(PDEVICE_OBJECT pdo, LPMODECAP ModeCaps, PFREQUENCY_RANGE pFrequencyRange) { BYTE pBuffer[512], *pEdid; ULONG numModeCaps = 0;
//
// Predefine monitor frequency limits in case we won't get it.
//
GetDefaultFrequencyRange(pFrequencyRange);
numModeCaps = GetMonitorCapabilityFromInf(pdo, ModeCaps);
if (numModeCaps) { pFrequencyRange->ulMinVerticalRate = ModeCaps[0].MinVFreq; pFrequencyRange->ulMaxVerticalRate = ModeCaps[0].freq; return numModeCaps; } else { TRACE_INIT(("Drv_Trace: GetMonitorCapabilityFromInf: Failed to retrieve Monitor inf\n")); }
if (GetRegEDID(pdo, pBuffer, &pEdid) == 0) { TRACE_INIT(("Drv_Trace: GetMonitorCapability: Failed to get EDID capability\n")); return 0; }
//
// Check if EDID Version 2.
//
if (0x20 == pEdid[0]) { return GetMonitorCapability2((PEDID2)pEdid, ModeCaps, pFrequencyRange); }
//
// Otherwise always assume it's EDID 1.x
//
return GetMonitorCapability1(pEdid, ModeCaps, pFrequencyRange); }
BOOL PruneMode(PDEVMODEW pdm, LPMODECAP pModeCaps, int numModeCaps, PFREQUENCY_RANGE pMaxFreqs, ULONG flag) { ULONG f, f1, freq = pdm->dmDisplayFrequency; BOOL bSwapWH = FALSE;
if (pdm->dmFields & DM_DISPLAYORIENTATION) { if (pdm->dmDisplayOrientation == DMDO_90 || pdm->dmDisplayOrientation == DMDO_270) { bSwapWH = TRUE; } }
//
// For Inf, MaxFreq = {56, 0xFFFFFFFF, 0, 0xFFFFFFFF, 0, 0xFFFFFFFF}
// The following block only effective to EDID
//
if (freq > 1 && (flag & DISPLAY_DEVICE_PRUNE_FREQ)) // Non Driver-default frequency
{ if (freq < pMaxFreqs->ulMinVerticalRate) { return TRUE; }
if (freq > pMaxFreqs->ulMaxVerticalRate && freq > 61) { return TRUE; }
f = (LONG)(freq * pdm->dmPelsHeight); if (f < pMaxFreqs->ulMinHorizontalRate && freq < 60) { return TRUE; } if (f > pMaxFreqs->ulMaxHorizontalRate && freq > 61) { return TRUE; } //
// ISSUE: We should check against MinPixelClock too. Fix in NT 5.1.
//
if ((pdm->dmPelsWidth*f) > pMaxFreqs->ulMaxPixelClock) { return TRUE; }
// 1.05 is a fudge factor that corrects for vetical retrace time.
// From Win98
f1 = f * ((pdm->dmPelsHeight > 600) ? 107 : 105) / 100; }
MODECAP mc = { bSwapWH ? pdm->dmPelsHeight : pdm->dmPelsWidth, bSwapWH ? pdm->dmPelsWidth : pdm->dmPelsHeight, freq}; LPMODECAP pModeCap;
// Found weird case of 1200x1600
if (numModeCaps && (flag & DISPLAY_DEVICE_PRUNE_RESOLUTION)) { if (mc.dmHeight > pModeCaps[numModeCaps-1].dmHeight) return TRUE; } for (int i = 0; i < numModeCaps; i++) { int comp = compModeCap(&mc, &pModeCaps[i]); if (comp > 0) { if (i >= (numModeCaps-1)) { if (flag & DISPLAY_DEVICE_PRUNE_RESOLUTION) { return TRUE; } } else continue; }
if (freq > 1 && (flag & DISPLAY_DEVICE_PRUNE_FREQ)) // Non Driver-default frequency
{ pModeCap = (comp == 0 || i == 0) ? &pModeCaps[i] : &pModeCaps[i-1];
if (freq > pModeCap->freq && freq > 61 && (comp == 0 || i > 0)) { return TRUE; }
//
// For EDID, pModeCap = {width, height, freq, 56, 0, 0xFFFFFFFF}.
// So the following block of code is only effective for INF
//
if (freq < pModeCap->MinVFreq) { return TRUE; } if (f1 < pModeCap->MinHFreq && freq < 60) { return TRUE; } // Sometimes the fulge value downgrades maximum freq below 60, which will lead
// all modes not supported. Freq 60 has to be supported
if (f1 > pModeCap->MaxHFreq && freq > 61) { return TRUE; } }
return FALSE; }
return TRUE; }
//
// Return Value
// Number of effective modes
//
ULONG PruneModesByMonitors(PGRAPHICS_DEVICE PhysDisp, ULONG numRawModes, PDEVMODEMARK pdevmodeMarks) { PULONG pNumModeCaps; ULONG i, numEffectiveModes; PMODECAP pModeCaps = NULL; FREQUENCY_RANGE MaxFreqs = { MIN_REFRESH_RATE, // This is to prune out interlaced modes
0xffffffff, 0, 0xffffffff, 0, 0xffffffff };
PhysDisp->stateFlags &= ~DISPLAY_DEVICE_MODESPRUNED;
if (PhysDisp->numMonitorDevice == 0) return numRawModes;
pNumModeCaps = (PULONG) PALLOCMEM((MAX_MODE_CAPABILITY * sizeof(MODECAP) + sizeof(ULONG)) * PhysDisp->numMonitorDevice, GDITAG_DEVMODE); if (pNumModeCaps == NULL) return numRawModes; pModeCaps = (PMODECAP)((PBYTE)pNumModeCaps + sizeof(ULONG) * PhysDisp->numMonitorDevice);
TRACE_INIT(("Drv_Trace: PruneModesByMonitors: Enter-- Number of raw modes=%d\n", numRawModes));
UpdateMonitorDevices(); numEffectiveModes = 0; for (i = 0; i < PhysDisp->numMonitorDevice; i++) { pNumModeCaps[i] = 0; if (IS_ATTACHED_ACTIVE(PhysDisp->MonitorDevices[i].flag)) { FREQUENCY_RANGE freqs;
pNumModeCaps[i] = GetMonitorCapability((PDEVICE_OBJECT)PhysDisp->MonitorDevices[i].pdo, pModeCaps, &freqs); if (pNumModeCaps[i] == 0) { TRACE_INIT(("Drv_Trace: GetMonitorCapability Failed for device %08lx\n", PhysDisp->MonitorDevices[i].pdo)); }
//
// Intersect frequency ranges for all display devices.
//
MaxFreqs.ulMinVerticalRate = max(MaxFreqs.ulMinVerticalRate, freqs.ulMinVerticalRate); MaxFreqs.ulMaxVerticalRate = min(MaxFreqs.ulMaxVerticalRate, freqs.ulMaxVerticalRate); MaxFreqs.ulMinHorizontalRate = max(MaxFreqs.ulMinHorizontalRate, freqs.ulMinHorizontalRate); MaxFreqs.ulMaxHorizontalRate = min(MaxFreqs.ulMaxHorizontalRate, freqs.ulMaxHorizontalRate); MaxFreqs.ulMinPixelClock = max(MaxFreqs.ulMinPixelClock, freqs.ulMinPixelClock); MaxFreqs.ulMaxPixelClock = min(MaxFreqs.ulMaxPixelClock, freqs.ulMaxPixelClock); } pModeCaps += pNumModeCaps[i]; numEffectiveModes += pNumModeCaps[i]; }
// If get nothing to prune
if (numEffectiveModes == 0) { VFREEMEM(pNumModeCaps); return numRawModes; }
numEffectiveModes = 0; for ( ; numRawModes > 0; numRawModes--) { PDEVMODEW pdevMode = pdevmodeMarks[numRawModes-1].pDevMode;
TRACE_INIT(("Drv_Trace: PruneMode Width=%d, Height=%d, Freq=%d\n", pdevMode->dmPelsWidth, pdevMode->dmPelsHeight, pdevMode->dmDisplayFrequency));
pModeCaps = (PMODECAP)((PBYTE)pNumModeCaps + sizeof(ULONG) * PhysDisp->numMonitorDevice); for (i = 0; i < PhysDisp->numMonitorDevice; i++) { if (pNumModeCaps[i] == 0) continue; if (PruneMode(pdevMode, pModeCaps, pNumModeCaps[i], &MaxFreqs, PhysDisp->MonitorDevices[i].flag)) { TRACE_INIT(("---Pruned\n")); pdevmodeMarks[numRawModes-1].bPruned = TRUE; PhysDisp->stateFlags |= DISPLAY_DEVICE_MODESPRUNED; break; } pModeCaps += pNumModeCaps[i]; } if (i == PhysDisp->numMonitorDevice) numEffectiveModes++; }
TRACE_INIT(("Drv_Trace: PruneModesByMonitors: Effective Mode Number=%d\n", numEffectiveModes));
VFREEMEM(pNumModeCaps);
return numEffectiveModes; }
BOOL CalculateDefaultPreferredModeFromEdid(PDEVICE_OBJECT pdo, LPMODECAP pmc) { //
// Try to set our default preferred mode to 800x600x60
// We try 60Hz only to prevent some crappy EDID from screwing the screen
// right after Setup, for example, some external LCDs.
//
FREQUENCY_RANGE MaxFreqs; PMODECAP pModeCaps = (PMODECAP) PALLOCMEM(MAX_MODE_CAPABILITY * sizeof(MODECAP), GDITAG_DEVMODE); BOOL bGotMode = FALSE;
if (pModeCaps == NULL) { return FALSE; }
ULONG NumModeCaps = GetMonitorCapability(pdo, pModeCaps, &MaxFreqs);
if (NumModeCaps) { DEVMODEW dm; ULONG Freqs[] = {85, 82, 75, 72, 70, 60};
pmc->dmWidth = dm.dmPelsWidth = 800 ; pmc->dmHeight = dm.dmPelsHeight = 600 ;
for (ULONG i = 0; i < sizeof(Freqs)/sizeof(ULONG); i++) { pmc->freq = dm.dmDisplayFrequency = Freqs[i]; if (!PruneMode(&dm, pModeCaps, NumModeCaps, &MaxFreqs, DISPLAY_DEVICE_PRUNE_FREQ | DISPLAY_DEVICE_PRUNE_RESOLUTION)) { bGotMode = TRUE; break; } } } VFREEMEM(pModeCaps);
if (!bGotMode) { return FALSE; } TRACE_INIT(("win32k!GetPreferredModeFromEdid1: Detailed timing %lux%lu at %luHz\n", pmc->dmWidth, pmc->dmHeight, pmc->freq));
return TRUE; }
BOOL CalculatePreferredModeFromEdid1 (PBYTE pEdid, PDEVICE_OBJECT pdo, LPMODECAP pmc) { PBYTE ptr = &pEdid[0x36]; ULONG count, area;
//
// If EDID has preferrred mode bit
// This function calculates a preferred mode based on the data in
// the first detailed timing block. If that data indicates that we can do
// 800x600x85hz, return that as the preferred mode. Otherwise, just
// return FALSE indicating that we should fall back to normal default
// behavior.
//
// Otherwise
// This function returns the preferred mode from the first detailed timing
// block in the EDID.
//
for (count = 0; count < 4; count++) { ptr += count * 18; if ((ptr[0] != 0 || ptr[1] != 0) && ptr[4] != 0) { pmc->dmWidth = (ULONG) ptr[2] + ((ULONG)(ptr[4] & 0xF0)) * 0x10; pmc->dmHeight = (ULONG) ptr[5] + ((ULONG)(ptr[7] & 0xF0)) * 0x10 ; pmc->freq = ((ULONG)ptr[0] + ((ULONG)ptr[1]) * 0x100) * 10000; area = (pmc->dmWidth + (ULONG)ptr[3] + ((ULONG)(ptr[4]&0x0F)) * 0x100) * (pmc->dmHeight+ (ULONG)ptr[6] + ((ULONG)(ptr[7]&0x0F)) * 0x100); if (area == 0) { ASSERT (FALSE); return FALSE; } pmc->freq /= area; if ((pEdid[0x18] & 0x02)) { TRACE_INIT(("win32k!GetPreferredModeFromEdid1: Detailed timing %lux%lu at %luHz\n", pmc->dmWidth, pmc->dmHeight, pmc->freq)); return TRUE; } else { break; } } }
return CalculateDefaultPreferredModeFromEdid(pdo, pmc); }
BOOL CalculatePreferredModeFromEdid2 (PEDID2 pEdid2, PDEVICE_OBJECT pdo, LPMODECAP pmc) { ULONG ulEdidOffset = EDID2_LUMINANCE_TABLE_OFFSET, count;
//
// No detailed timing block
//
if ((pEdid2->ucaMapOfTiming[1] & EDID2_MOT1_DETAIL_TIMING_MASK) == 0) { return FALSE; }
PUCHAR pucLuminanceTable = (PUCHAR)pEdid2 + ulEdidOffset;
//
// Luminance Table
//
ulEdidOffset += (((*pucLuminanceTable & EDID2_LT0_SUB_CHANNELS_FLAG) ? 3 : 1) * (*pucLuminanceTable & EDID2_LT0_ENTRIES_MASK) + 1);
//
// Frequency Ranges
//
ulEdidOffset += ((pEdid2->ucaMapOfTiming[0] & EDID2_MOT0_FREQUENCY_RANGE_MASK) >> EDID2_MOT0_FREQUENCY_RANGE_SHIFT) * sizeof (EDID2_FREQUENCY_RANGE);
//
// Detailed Range Limits
//
ulEdidOffset += ((pEdid2->ucaMapOfTiming[0] & EDID2_MOT0_DETAIL_TIMING_RANGE_MASK) >> EDID2_MOT0_DETAIL_TIMING_RANGE_SHIFT) * sizeof(EDID2_DETAIL_TIMING_RANGE);
//
// Timing Codes
//
ulEdidOffset += ((pEdid2->ucaMapOfTiming[1] & EDID2_MOT1_TIMING_CODE_MASK) >> EDID2_MOT1_TIMING_CODE_SHIFT) * sizeof(EDID2_TIMING_CODE);
ULONG ulNumberOfDetailTimings = (pEdid2->ucaMapOfTiming[1] & EDID2_MOT1_DETAIL_TIMING_MASK) >> EDID2_MOT1_DETAIL_TIMING_SHIFT; for (count = 0; count < ulNumberOfDetailTimings; count++) { ulEdidOffset += count*sizeof(EDID2_DETAIL_TIMING); if ((ulEdidOffset + sizeof(EDID2_DETAIL_TIMING)) >= sizeof (EDID2)) { ASSERT(FALSE); return FALSE; }
PEDID2_DETAIL_TIMING pDetailTiming = (PEDID2_DETAIL_TIMING)((PUCHAR)pEdid2 + ulEdidOffset);
pmc->dmWidth = ((ULONG)(pDetailTiming->ucHorizontalHighBits & 0xf0) << 4) + pDetailTiming->ucHorizontalActiveLowByte;
pmc->dmHeight = ((ULONG)(pDetailTiming->ucVerticalHighBits & 0xf0) << 4) + pDetailTiming->ucVerticalActiveLowByte;
ULONG ulHorizontalTotal = ((ULONG)(pDetailTiming->ucHorizontalHighBits & 0x0f) << 8) + pDetailTiming->ucHorizontalBlankLowByte + pmc->dmWidth;
ULONG ulVerticalTotal = ((ULONG)(pDetailTiming->ucVerticalHighBits & 0x0f) << 8) + pDetailTiming->ucVerticalBlankLowByte + pmc->dmHeight;
//
// Make sure we won't divide by zero in case of bad EDID.
//
if ((0 == ulHorizontalTotal) || (0 == ulVerticalTotal)) { ASSERT(FALSE); return FALSE; }
//
// Calculate refresh rate rounding to the nearest integer.
//
pmc->freq = ((((ULONG)(pDetailTiming->usPixelClock) * 100000) / (ulHorizontalTotal * ulVerticalTotal)) + 5) / 10;
if (pDetailTiming->ucFlags & EDID2_DT_INTERLACED) { pmc->freq /= 2; }
if (pEdid2->ucaMapOfTiming[0] & EDID2_MOT0_PREFFERED_MODE_FLAG) { TRACE_INIT(("win32k!GetPreferredModeFromEdid2: Detailed timing %lux%lu at %luHz\n", pmc->dmWidth, pmc->dmHeight, pmc->freq)); return TRUE; } else { break; } }
return CalculateDefaultPreferredModeFromEdid(pdo, pmc); }
BOOL GetPreferredModeFromEdid(PDEVICE_OBJECT pdo, LPMODECAP pmc) { BYTE pBuffer[512], *pEdid; if (!GetRegEDID(pdo, pBuffer, &pEdid)) return FALSE;
//
// It's EDID2
//
if (0x20 == pEdid[0]) { return CalculatePreferredModeFromEdid2((PEDID2)pEdid, pdo, pmc); }
if (pEdid[0] != 0 || pEdid[7] != 0) { return FALSE; }
for (int i = 1; i < 7; i++) { if (pEdid[i] != 0xFF) return FALSE; }
return (CalculatePreferredModeFromEdid1 (pEdid, pdo, pmc)); }
/***************************************************************************\
* DrvGetPreferredMode * * Routine that returns the prefered mode. * \***************************************************************************/
NTSTATUS DrvGetPreferredMode( LPDEVMODEW lpDevMode, PGRAPHICS_DEVICE PhysDisp ) { NTSTATUS retval = STATUS_INVALID_PARAMETER_1; DWORD iModeNum;
ASSERTGDI((lpDevMode != NULL), "Invalid lpDevMode\n"); ASSERTGDI((PhysDisp != NULL), "Invalid PhysDisp\n");
UpdateMonitorDevices();
__try { lpDevMode->dmPelsWidth = lpDevMode->dmPelsHeight = lpDevMode->dmDisplayFrequency = 0x7FFF;
for (iModeNum = 0; iModeNum < PhysDisp->numMonitorDevice; iModeNum++) { if (IS_ATTACHED_ACTIVE(PhysDisp->MonitorDevices[iModeNum].flag)) { MODECAP mc; if (!GetValuesFromInf((PDEVICE_OBJECT)PhysDisp->MonitorDevices[iModeNum].pdo, 0, &mc)) { if (!GetPreferredModeFromEdid((PDEVICE_OBJECT)PhysDisp->MonitorDevices[iModeNum].pdo, &mc)) { lpDevMode->dmDisplayFrequency = 60; continue; } } //
// To be safe, always pick the smaller refresh rate
//
if (mc.freq < lpDevMode->dmDisplayFrequency) lpDevMode->dmDisplayFrequency = mc.freq;
if (mc.dmWidth > lpDevMode->dmPelsWidth) continue; if (mc.dmWidth == lpDevMode->dmPelsWidth && mc.dmHeight > lpDevMode->dmPelsHeight) continue;
lpDevMode->dmPelsWidth = mc.dmWidth; lpDevMode->dmPelsHeight = mc.dmHeight; lpDevMode->dmFields = DM_PELSWIDTH | DM_PELSHEIGHT | DM_DISPLAYFREQUENCY; }
}
if (lpDevMode->dmPelsWidth == 0x7FFF) retval = STATUS_INVALID_PARAMETER_3; else retval = STATUS_SUCCESS; } __except (EXCEPTION_EXECUTE_HANDLER) { }
return retval; }
/***************************************************************************\
* DrvBuildDevmodeList * * Builds the list of DEVMODEs for a particular GRAPHICS_DEVICE structure * * CRIT must be held before this call is made. * * History: * 10-Mar-1996 andreva Created. \***************************************************************************/
VOID DrvBuildDevmodeList( PGRAPHICS_DEVICE PhysDisp, BOOL bUpdateCache) { GDIFunctionID(DrvBuildDevmodeList);
ULONG i, j; PDRV_NAMES lpNames = NULL; DWORD cbOutputSize; LPDEVMODEW tmpBuffer; PUCHAR reallocBuffer;
//
// check if the information is cached already
// if not, then get the information from the drivers.
//
// NOTE : we may want to synchronize access to this list
// of modes so that we can dynamically update the list
// when plug - and - play arrives.
//
// NOTE : the list of text modes is built at boot time, and we depend
// on that list being valid if the PhysDisp is returned.
// see DrvInitConsole().
//
TRACE_INIT(("Drv_Trace: BuildDevmode: Enter"));
// If HYDRA Remote session we don't want to cache the mode as
// we can be in a reconnect with a different resolution.
// It these case the driver's only mode has changed so
// we want to query him to get latest valid mode
//
// bUpdateCache = TRUE only when display switching occured. At this time,
// we need to update mode list
//
if ((PhysDisp->stateFlags & DISPLAY_DEVICE_REMOTE) || bUpdateCache) { if ( (PhysDisp != &gFullscreenGraphicsDevice) && ( (PhysDisp->cbdevmodeInfo != 0) && (PhysDisp->devmodeInfo != NULL)) ) { if (PhysDisp->devmodeInfo) { VFREEMEM(PhysDisp->devmodeInfo); PhysDisp->devmodeInfo = NULL; } PhysDisp->cbdevmodeInfo = 0; if (PhysDisp->devmodeMarks) { VFREEMEM(PhysDisp->devmodeMarks); PhysDisp->devmodeMarks = NULL; } } }
if ( (PhysDisp != &gFullscreenGraphicsDevice) && (PhysDisp->cbdevmodeInfo == 0) && (PhysDisp->devmodeInfo == NULL) ) { TRACE_INIT(("\nDrv_Trace: BuildDevmode: Rebuild List\n"));
PhysDisp->numRawModes = 0;
lpNames = DrvGetDisplayDriverNames(PhysDisp);
if (lpNames) { for (i = 0; i < lpNames->cNames; i++) {
cbOutputSize = ldevGetDriverModes(lpNames->D[i].lpDisplayName, lpNames->D[i].hDriver, &tmpBuffer);
if (cbOutputSize) { //
// create a new buffer copy the old data into it
// and append the new data at the end - we want
// a continuous buffer for all the data.
//
reallocBuffer = (PUCHAR) PALLOCNOZ(PhysDisp->cbdevmodeInfo + cbOutputSize, GDITAG_DRVSUP);
if (reallocBuffer) { if (PhysDisp->cbdevmodeInfo) { //
// Copy the contents of the old buffer
// and free it
//
RtlCopyMemory(reallocBuffer, PhysDisp->devmodeInfo, PhysDisp->cbdevmodeInfo);
VFREEMEM(PhysDisp->devmodeInfo); }
RtlCopyMemory(reallocBuffer + PhysDisp->cbdevmodeInfo, tmpBuffer, cbOutputSize);
PhysDisp->cbdevmodeInfo += cbOutputSize; PhysDisp->devmodeInfo = (PDEVMODEW) reallocBuffer; } else { WARNING("failed realloc\n"); } } else { WARNING("display driver not present\n"); }
if (tmpBuffer) { VFREEMEM(tmpBuffer); } }
VFREEMEM(lpNames); }
if ( (PhysDisp->cbdevmodeInfo == 0) && (PhysDisp->devmodeInfo == NULL) ) { DrvLogDisplayDriverEvent(MsgInvalidDisplayDriver); } else { PDEVMODEW lpdm, lpdm1; for (i = 0, cbOutputSize = 0; cbOutputSize < PhysDisp->cbdevmodeInfo; i++) { lpdm = (LPDEVMODEW)(((LPBYTE)PhysDisp->devmodeInfo) + cbOutputSize); cbOutputSize += lpdm->dmSize + lpdm->dmDriverExtra; }
PhysDisp->devmodeMarks = (PDEVMODEMARK)PALLOCMEM(i * sizeof(DEVMODEMARK), GDITAG_DRVSUP); if (PhysDisp->devmodeMarks == NULL) { PhysDisp->cbdevmodeInfo = 0; VFREEMEM(PhysDisp->devmodeInfo); PhysDisp->devmodeInfo = NULL; WARNING("failed allocate lookside list\n"); DrvLogDisplayDriverEvent(MsgInvalidDisplayDriver); } else { PhysDisp->numRawModes = i; for (i = 0, cbOutputSize = 0; cbOutputSize < PhysDisp->cbdevmodeInfo; i++) { lpdm = (LPDEVMODEW)(((LPBYTE)PhysDisp->devmodeInfo) + cbOutputSize);
// jasonha 07/13/2001 Display Orientation Support
if (!(lpdm->dmFields & DM_DISPLAYORIENTATION)) { lpdm->dmFields |= DM_DISPLAYORIENTATION; if (lpdm->dmDisplayOrientation != 0) { WARNING("driver reported non-zero dmDisplayOrientation, but not DM_DISPLAYORIENTATION flag.\n"); } lpdm->dmDisplayOrientation = DMDO_DEFAULT; } else if (lpdm->dmDisplayOrientation > DMDO_LAST) { WARNING("driver reported invalid dmDisplayOrientation.\n"); lpdm->dmDisplayOrientation = DMDO_DEFAULT; }
// jasonha 09/17/2001 Display Fixed Output Support
if (!(lpdm->dmFields & DM_DISPLAYFIXEDOUTPUT)) { if (lpdm->dmDisplayFixedOutput != 0) { WARNING("driver reported non-zero dmDisplayFixedOutput, but not DM_DISPLAYFIXEDOUTPUT flag.\n"); } lpdm->dmDisplayFixedOutput = DMDFO_DEFAULT; } else if (lpdm->dmDisplayFixedOutput == DMDFO_DEFAULT || lpdm->dmDisplayFixedOutput > DMDFO_LAST) { WARNING("driver reported invalid dmDisplayFixedOutput.\n"); lpdm->dmFields &= ~DM_DISPLAYFIXEDOUTPUT; lpdm->dmDisplayFixedOutput = DMDFO_DEFAULT; }
PhysDisp->devmodeMarks[i].bPruned = FALSE; PhysDisp->devmodeMarks[i].pDevMode = lpdm; cbOutputSize += lpdm->dmSize + lpdm->dmDriverExtra; }
// 11/26/98 Ignore miniport default refresh rate
// But if the default rate is the only mode in the list, we still keep it
// For example, VGA and mnmdd
for (i = 1; i <= PhysDisp->numRawModes; i++) { lpdm = PhysDisp->devmodeMarks[i-1].pDevMode; if (lpdm->dmDisplayFrequency == 1) { for (j = 1; j <= PhysDisp->numRawModes; j++) { if (j == i) continue; lpdm1 = PhysDisp->devmodeMarks[j-1].pDevMode; if (lpdm->dmBitsPerPel != lpdm1->dmBitsPerPel) continue; if (lpdm->dmPelsWidth != lpdm1->dmPelsWidth) continue; if (lpdm->dmPelsHeight != lpdm1->dmPelsHeight) continue; if ((lpdm->dmDisplayFlags & DMDISPLAYFLAGS_TEXTMODE) != (lpdm1->dmDisplayFlags & DMDISPLAYFLAGS_TEXTMODE)) continue; if (lpdm->dmDisplayOrientation != lpdm1->dmDisplayOrientation) continue; if (lpdm->dmDisplayFixedOutput != lpdm1->dmDisplayFixedOutput) continue; // We find a duplicated mode, so cut off this mode
if (PhysDisp->numRawModes > i) RtlMoveMemory(&PhysDisp->devmodeMarks[i-1], &PhysDisp->devmodeMarks[i], sizeof(DEVMODEMARK) * (PhysDisp->numRawModes-i)); PhysDisp->numRawModes--; i--; break; } } }
if ((PhysDisp->stateFlags & DISPLAY_DEVICE_REMOTE) == 0 && (PhysDisp->stateFlags & DISPLAY_DEVICE_DISCONNECT) == 0 && (PhysDisp->stateFlags & DISPLAY_DEVICE_MIRRORING_DRIVER) == 0) cbOutputSize = PruneModesByMonitors(PhysDisp, PhysDisp->numRawModes, PhysDisp->devmodeMarks);
if (cbOutputSize == 0) DrvLogDisplayDriverEvent(MsgInvalidDisplayDriver);
//
// Expand all 32bpp modes to double the effective dots-per-inch.
// Panning.cxx handles the actual downsizing.
//
if (G_fDoubleDpi) { for (i = 0, cbOutputSize = 0; cbOutputSize < PhysDisp->cbdevmodeInfo; i++) { lpdm = (LPDEVMODEW)(((LPBYTE)PhysDisp->devmodeInfo) + cbOutputSize); if (lpdm->dmBitsPerPel == 32) { lpdm->dmPelsWidth *= 2; lpdm->dmPelsHeight *= 2; } cbOutputSize += lpdm->dmSize + lpdm->dmDriverExtra; } } } } } else { TRACE_INIT((" - Use cache")); }
TRACE_INIT((" - Exit\n"));
return; }
#define DIFF(x, y) ( ((x) >= (y)) ? ((x)-(y)) : ((y)-(x)) )
// Orientation Difference Table
// Table lookup returns matching level for two dmDisplayOrientation values.
// Lower number mean a better match.
// Exact match => 0
// 180 rotation => 1
// 90/270 rotation => 2
DWORD dwOrientationDiffTable[4][4] = { { 0, 2, 1, 2}, { 2, 0, 2, 1}, { 1, 2, 0, 2}, { 2, 1, 2, 0} };
#define ORIENTATION_DIFF(x, y) dwOrientationDiffTable[y][x]
LPDEVMODEW GetClosestMode(PGRAPHICS_DEVICE PhysDisp, LPDEVMODEW pOrgDevMode, BOOL bPrune) { DEVMODEW diffMode; LPDEVMODEW lpdm, lpModePicked = NULL, lpModeWanted = NULL; ULONG diff;
diffMode.dmBitsPerPel = 0xFFFFFFFF; diffMode.dmPelsWidth = 0xFFFFFFFF; diffMode.dmPelsHeight = 0xFFFFFFFF; diffMode.dmDisplayFrequency = 0xFFFFFFFF; diffMode.dmDisplayOrientation = 0xFFFFFFFF; diffMode.dmDisplayFixedOutput = 0xFFFFFFFF;
if (pOrgDevMode->dmDisplayFrequency == 0) pOrgDevMode->dmDisplayFrequency = 60; if (pOrgDevMode->dmBitsPerPel == 0) pOrgDevMode->dmBitsPerPel = 32; if ( !(pOrgDevMode->dmFields & DM_DISPLAYORIENTATION) ) pOrgDevMode->dmDisplayOrientation = DMDO_DEFAULT; if ( !(pOrgDevMode->dmFields & DM_DISPLAYFIXEDOUTPUT) ) pOrgDevMode->dmDisplayFixedOutput = DMDFO_DEFAULT;
//
// Do 2 rounds of search.
// First round, only find smaller or exact mode. Done if exact match.
// Second round is used done if:
// Orientation doesn't match or
// Mode is smalller than 640x480x60 (480x640x60 for rotated modes)
//
for (ULONG k = 0; k < 2; k++) { if (lpModeWanted && diffMode.dmDisplayOrientation == 0 && ((lpModeWanted->dmPelsWidth >= lpModeWanted->dmPelsHeight) ? (lpModeWanted->dmPelsWidth >= 640 && lpModeWanted->dmPelsHeight>= 480) : (lpModeWanted->dmPelsWidth >= 480 && lpModeWanted->dmPelsHeight>= 640)) && lpModeWanted->dmDisplayFrequency >= 60) { break; } for (ULONG i = 0; i < PhysDisp->numRawModes; i++) { if (bPrune && PhysDisp->devmodeMarks[i].bPruned) continue; lpdm = PhysDisp->devmodeMarks[i].pDevMode;
if (pOrgDevMode->dmFields & DM_DISPLAYORIENTATION) { diff = ORIENTATION_DIFF(pOrgDevMode->dmDisplayOrientation, lpdm->dmDisplayOrientation);
if (diffMode.dmDisplayOrientation < diff) continue;
if (diffMode.dmDisplayOrientation > diff) { lpModePicked = lpdm; } }
if (pOrgDevMode->dmPelsWidth && lpModePicked != lpdm) { diff = DIFF(pOrgDevMode->dmPelsWidth, lpdm->dmPelsWidth); if (diffMode.dmPelsWidth < diff) continue; else if (diffMode.dmPelsWidth > diff) { lpModePicked = lpdm; } } if (pOrgDevMode->dmPelsHeight && lpModePicked != lpdm) { diff = DIFF(pOrgDevMode->dmPelsHeight, lpdm->dmPelsHeight); if (diffMode.dmPelsHeight < diff) continue; else if (diffMode.dmPelsHeight > diff) { lpModePicked = lpdm; } } if (lpModePicked != lpdm) { diff = DIFF(pOrgDevMode->dmBitsPerPel, lpdm->dmBitsPerPel); if (diffMode.dmBitsPerPel < diff) continue; else if (diffMode.dmBitsPerPel > diff) { lpModePicked = lpdm; } } if (lpModePicked != lpdm) { diff = (pOrgDevMode->dmDisplayFixedOutput != lpdm->dmDisplayFixedOutput) ? 1 : 0; if (diffMode.dmDisplayFixedOutput < diff) continue; else if (diffMode.dmDisplayFixedOutput > diff) { lpModePicked = lpdm; } } if (lpModePicked != lpdm) { diff = DIFF(pOrgDevMode->dmDisplayFrequency, lpdm->dmDisplayFrequency); if (diffMode.dmDisplayFrequency < diff) continue; else if (diffMode.dmDisplayFrequency > diff) { lpModePicked = lpdm; } }
// continue if we haven't found a better match
if (lpModePicked != lpdm) continue;
if (k == 0) { // skip larger or higher frequency modes (first round only)
if (lpModePicked->dmPelsWidth > pOrgDevMode->dmPelsWidth && pOrgDevMode->dmPelsWidth) continue; if (lpModePicked->dmPelsHeight > pOrgDevMode->dmPelsHeight && pOrgDevMode->dmPelsHeight != 0) continue; if (lpModePicked->dmDisplayFrequency > pOrgDevMode->dmDisplayFrequency) continue; } lpModeWanted = lpModePicked; diffMode.dmDisplayOrientation = ORIENTATION_DIFF(pOrgDevMode->dmDisplayOrientation, lpdm->dmDisplayOrientation); diffMode.dmPelsWidth = DIFF(pOrgDevMode->dmPelsWidth, lpdm->dmPelsWidth); diffMode.dmPelsHeight = DIFF(pOrgDevMode->dmPelsHeight, lpdm->dmPelsHeight); diffMode.dmBitsPerPel = DIFF(pOrgDevMode->dmBitsPerPel, lpdm->dmBitsPerPel); diffMode.dmDisplayFixedOutput = (pOrgDevMode->dmDisplayFixedOutput != lpdm->dmDisplayFixedOutput) ? 1 : 0; diffMode.dmDisplayFrequency = DIFF(pOrgDevMode->dmDisplayFrequency, lpdm->dmDisplayFrequency); if (diffMode.dmDisplayOrientation == 0 && diffMode.dmBitsPerPel == 0 && diffMode.dmPelsWidth == 0 && diffMode.dmPelsHeight == 0 && diffMode.dmDisplayFixedOutput == 0 && diffMode.dmDisplayFrequency == 0) break; } }
#if DBG
if (lpModeWanted == NULL) { WARNING("Drv_Trace: GetClosestMode: The PhysDisp driver has Zero mode\n"); } #endif
return lpModeWanted; }
/***************************************************************************\
* ProbeAndCaptureDevmode * * Maps a partial DEVMODE (for example, may only contain width and height) * to a complete DEVMODE that the kernel routines will like. * * CRIT need not be held when calling. * * History: * 10-Mar-1996 andreva Created. \***************************************************************************/
NTSTATUS DrvProbeAndCaptureDevmode( PGRAPHICS_DEVICE PhysDisp, PDEVMODEW *DestinationDevmode, BOOL *bDetach, PDEVMODEW SourceDevmode, BOOL bDefaultMode, MODE PreviousMode, BOOL bPrune, BOOL bClosest, BOOL bFromMonitor ) { NTSTATUS ntRet = STATUS_UNSUCCESSFUL; BOOL bRet = FALSE; BOOL btmpError; ULONG sourceSize; ULONG sourceSizeExtra; ULONG sizeExtra; PDEVMODEW matchedDevmode = NULL; PDEVMODEW partialDevmode;
DWORD tmpDisplayFlags = 0; DWORD tmpPanningWidth = 0; DWORD tmpPanningHeight = 0; DWORD tmpPositionX = 0; DWORD tmpPositionY = 0; BOOL tmpPosition; BOOL bOrientationSpecified = FALSE; BOOL bFixedOutputSpecified = FALSE;
TRACE_INIT(("Drv_Trace: CaptMatchDevmode: Entering\n"));
*DestinationDevmode = NULL; *bDetach = FALSE;
if (SourceDevmode == NULL) { TRACE_INIT(("Drv_Trace: CaptMatchDevmode: Exit DEVMODE NULL\n\n")); return STATUS_SUCCESS; }
TRACE_INIT(("\n")); TRACE_INIT((" pDevMode %08lx\n", SourceDevmode));
partialDevmode = (PDEVMODEW) PALLOCNOZ(sizeof(DEVMODEW) + MAXUSHORT, GDITAG_DEVMODE);
if (partialDevmode == NULL) { TRACE_INIT(("Drv_Trace: CaptMatchDevmode: Could not allocate partial DEVMODE\n\n")); return STATUS_UNSUCCESSFUL; }
//
// Put everything in a try except so we can always reference the original
// passed in structure.
//
__try { if (PreviousMode == UserMode) { ProbeForRead(SourceDevmode, FIELD_OFFSET(DEVMODEW, dmFields), sizeof(DWORD)); } else { ASSERTGDI(SourceDevmode >= (PDEVMODEW const)MM_USER_PROBE_ADDRESS, "Bad kernel mode address\n"); }
//
// Capture these so that they don't change right after the probe.
//
sourceSize = SourceDevmode->dmSize; sourceSizeExtra = SourceDevmode->dmDriverExtra;
if (PreviousMode == UserMode) { ProbeForRead(SourceDevmode, sourceSize + sourceSizeExtra, sizeof(DWORD)); }
dbgDumpDevmode(SourceDevmode);
if (SourceDevmode->dmFields == 0) bClosest = TRUE;
//
// At the introduction time of this API, the DEVMODE already contained
// up to the dmDisplayFrequency field. We will fail is the DEVMODE is
// smaller than that.
//
if (sourceSize >= FIELD_OFFSET(DEVMODEW, dmICMMethod)) { //
// Determine if the position reflects a detach operation
//
// If the size of the rectangle is NULL, that means the device
// needs to be detached from the desktop.
//
if ((SourceDevmode->dmFields & DM_POSITION) && (SourceDevmode->dmFields & DM_PELSWIDTH) && (SourceDevmode->dmPelsWidth == 0) && (SourceDevmode->dmFields & DM_PELSHEIGHT) && (SourceDevmode->dmPelsHeight == 0)) { *bDetach = TRUE; VFREEMEM(partialDevmode); return STATUS_SUCCESS; }
//
// Lets build a temporary DEVMODE that will contain the
// "wished for" DEVMODE, based on matching from the registry.
// Only match the basic devmode. Other fields (optional ones
// will be added later)
//
// NOTE special case VGA mode so that we don't try to match to the
// current screen mode.
//
RtlZeroMemory(partialDevmode, sizeof(DEVMODEW)); partialDevmode->dmSize = 0xDDDD; partialDevmode->dmDriverExtra = MAXUSHORT;
if (PhysDisp == &gFullscreenGraphicsDevice) { //
// We should never get called to probe the fullscreen modes
// since they are only called by the console
//
ASSERTGDI(FALSE, "ProbeAndCaptureDEVMODE called with VGA device\n"); VFREEMEM(partialDevmode); return STATUS_UNSUCCESSFUL; } else if (bDefaultMode) { //
// We just want to pick the default mode from the driver.
//
// Leave the partial DEVMODE with all NULLs
//
DrvGetDisplayDriverParameters(PhysDisp, partialDevmode, TRUE, bFromMonitor); } else { if (!NT_SUCCESS(DrvGetDisplayDriverParameters(PhysDisp, partialDevmode, gbBaseVideo, bFromMonitor))) { partialDevmode->dmDriverExtra = 0;
/*
* If the above should fail (it seemed to under low memory conditions), * then we'd better have a valid size or the following memory copies * will be wrong. */ partialDevmode->dmSize = sizeof(DEVMODEW);
// if (G_TERM(pDispInfo)->hdcScreen)
// {
// //
// // Use the caps as a guess for this.
// //
//
// WARNING("Drv_Trace: CaptMatchDevmode: Could not get current devmode\n");
//
// partialDevmode->dmBitsPerPel =
// GreGetDeviceCaps(G_TERM(pDispInfo)->hdcScreen, BITSPIXEL) *
// GreGetDeviceCaps(G_TERM(pDispInfo)->hdcScreen, PLANES);
// partialDevmode->dmPelsWidth =
// GreGetDeviceCaps(G_TERM(pDispInfo)->hdcScreen, HORZRES);
// partialDevmode->dmPelsHeight =
// GreGetDeviceCaps(G_TERM(pDispInfo)->hdcScreen, VERTRES);
// partialDevmode->dmDisplayFrequency =
// GreGetDeviceCaps(G_TERM(pDispInfo)->hdcScreen, VREFRESH);
// }
}
if ((SourceDevmode->dmFields & DM_BITSPERPEL) && (SourceDevmode->dmBitsPerPel != 0)) { partialDevmode->dmBitsPerPel = SourceDevmode->dmBitsPerPel; }
if ((SourceDevmode->dmFields & DM_PELSWIDTH) && (SourceDevmode->dmPelsWidth != 0)) { partialDevmode->dmPelsWidth = SourceDevmode->dmPelsWidth; }
if ((SourceDevmode->dmFields & DM_PELSHEIGHT) && (SourceDevmode->dmPelsHeight != 0)) { partialDevmode->dmPelsHeight = SourceDevmode->dmPelsHeight; }
if ((SourceDevmode->dmFields & DM_DISPLAYFREQUENCY) && (SourceDevmode->dmDisplayFrequency != 0)) { partialDevmode->dmDisplayFrequency = SourceDevmode->dmDisplayFrequency; } else { //
// Only use the registry refresh rate if we are going
// down in resolution. If we are going up in resolution,
// we will want to pick the lowest refresh rate that
// makes sense.
//
// The exception to this is if we have resetting the mode
// to the regsitry mode (passing in all 0's), in which case
// we want exactly what is in the registry.
//
if ( ((SourceDevmode->dmPelsWidth != 0) || (SourceDevmode->dmPelsHeight != 0)) ) { partialDevmode->dmDisplayFrequency = 0; } } }
btmpError = FALSE;
//
// These fields are somewhat optional.
// We capture them if they are valid. Otherwise, they will
// be initialized back to zero.
//
//
// Pick whichever set of flags we can. Source is first choice,
// registry is second.
//
if (SourceDevmode->dmFields & DM_DISPLAYFLAGS) { if (SourceDevmode->dmDisplayFlags & (~DMDISPLAYFLAGS_VALID)) { btmpError = TRUE; } tmpDisplayFlags = SourceDevmode->dmDisplayFlags; } else if ((partialDevmode->dmFields & DM_DISPLAYFLAGS) && (partialDevmode->dmDisplayFlags & (~DMDISPLAYFLAGS_VALID))) { tmpDisplayFlags = partialDevmode->dmDisplayFlags; }
//
// If the caller specified panning keep the value, unless it was
// bigger than the resolution, which is an error.
//
// Otherwise, use the value from the registry if it makes sense
// (i.e. panning is still smaller than the resolution).
//
if ((SourceDevmode->dmFields & DM_PANNINGWIDTH) && (SourceDevmode->dmFields & DM_PANNINGHEIGHT)) { if ((SourceDevmode->dmPanningWidth > partialDevmode->dmPelsWidth) || (SourceDevmode->dmPanningHeight > partialDevmode->dmPelsHeight)) { btmpError = TRUE; } tmpPanningWidth = SourceDevmode->dmPanningWidth; tmpPanningHeight = SourceDevmode->dmPanningHeight; } else if ((partialDevmode->dmFields & DM_PANNINGWIDTH) && (partialDevmode->dmFields & DM_PANNINGHEIGHT) && (partialDevmode->dmPanningHeight < partialDevmode->dmPelsHeight) && (partialDevmode->dmPanningWidth < partialDevmode->dmPelsWidth)) { tmpPanningWidth = partialDevmode->dmPanningWidth; tmpPanningHeight = partialDevmode->dmPanningHeight; }
//
// Check the orientation.
//
if (SourceDevmode->dmFields & DM_DISPLAYORIENTATION) { bOrientationSpecified = TRUE; partialDevmode->dmDisplayOrientation = SourceDevmode->dmDisplayOrientation;
if (SourceDevmode->dmDisplayOrientation > DMDO_LAST) { btmpError = TRUE; } }
//
// Check fixed output mode.
//
if (SourceDevmode->dmFields & DM_DISPLAYFIXEDOUTPUT) { partialDevmode->dmDisplayFixedOutput = SourceDevmode->dmDisplayFixedOutput;
// DMDFO_DEFAULT means the first driver reported devmode
// matching the other parameters is to be picked; so, in
// that case bFixedOutputSpecified remains FALSE.
if (SourceDevmode->dmDisplayFixedOutput != DMDFO_DEFAULT) { bFixedOutputSpecified = TRUE; if (SourceDevmode->dmDisplayFixedOutput > DMDFO_LAST) { btmpError = TRUE; } } }
//
// Capture the position.
//
// If the size of the rectangle is NULL, that means the device
// needs to be detached from the desktop.
//
if (SourceDevmode->dmFields & DM_POSITION) { tmpPosition = TRUE; tmpPositionX = SourceDevmode->dmPosition.x; tmpPositionY = SourceDevmode->dmPosition.y; } else { tmpPosition = partialDevmode->dmFields & DM_POSITION; tmpPositionX = partialDevmode->dmPosition.x; tmpPositionY = partialDevmode->dmPosition.y; }
//
// If the PhysDisp attaches to a device which removable, never put
// the primary desktop on it. And never put origin (0,0) on it
//
if (PhysDisp->stateFlags & DISPLAY_DEVICE_REMOVABLE) { if (tmpPosition && tmpPositionX == 0 && tmpPositionY == 0 ) { TRACE_INIT(("Drv_Trace: CaptMatchDevmode: User tried to put the primary desktop on a removable device.\n"));
VFREEMEM(partialDevmode); return STATUS_UNSUCCESSFUL; } }
if (btmpError == TRUE) { //
// The panning values or the flags are invalid
//
RIP("Drv_Trace: CaptMatchDevmode: Invalid Optional DEVMODE fields\n"); } else { //
// Allocate enough memory so we can store the whole devmode.
//
sizeExtra = sourceSizeExtra; if (sizeExtra == 0) { sizeExtra = partialDevmode->dmDriverExtra; }
matchedDevmode = (PDEVMODEW) PALLOCMEM(sizeof(DEVMODEW) + sizeExtra, GDITAG_DEVMODE);
if (matchedDevmode) { //
// Let's copy any DriverExtra information that the
// application may have passed down while we are still in
// the try\except. If we fail the call later, the memory
// will get deallocated anyways.
//
// If the application did not specify any such data, then
// copy it from the registry.
//
if (sourceSizeExtra) { RtlCopyMemory(matchedDevmode + 1, (PUCHAR)SourceDevmode + sourceSize, sizeExtra); } else if (partialDevmode->dmDriverExtra) { RtlCopyMemory(matchedDevmode + 1, (PUCHAR)partialDevmode + partialDevmode->dmSize, sizeExtra); } } } }
TRACE_INIT(("Drv_Trace: CaptMatchDevmode: Capture Complete\n")); } __except (EXCEPTION_EXECUTE_HANDLER) { WARNINGX(101);
//
// If we hit an exception, free the buffer we have allocated.
//
if (matchedDevmode) { VFREEMEM(matchedDevmode); }
matchedDevmode = NULL; }
//
// This is our matching algorithm, based on requirements from Win95.
//
// As a rule, a value in the DEVMODE is only valid when BOTH the value is
// non-zero, and the dmFields flag is set. Otherwise, the value from the
// registry must be used
//
// For X, Y and color depth, we will follow this rule.
//
// For the refresh rate, we are just trying to find something that works
// for the screen. We are far from guaranteed that the refresh rate in
// the registry will be found for the X and Y we have since refresh rates
// vary a lot from mode to mode.
//
// So if the value is not specifically set and we do not find the exact
// value from the reigstry in the new resolution, Then we will try 60 Hz.
// We just want to get something that works MOST of the time so that the
// user does not get a mode that does not work.
//
// For the other fields (dmDisplayFlags, and panning), we just pass on what
// the application specified, and it's up to the driver to parse those,
// fields appropriatly.
//
//
// Now lets enumerate all the DEVMODEs and see if we have one
// that matches what we need.
//
if (matchedDevmode) { typedef enum { NO_MATCH, DEFAULT_MATCH, EXACT_MATCH } MatchLevel;
PDEVMODEW pdevmodeMatch = NULL; MatchLevel eOrientationMatch = NO_MATCH; MatchLevel eFixedOutputMatch = NO_MATCH; MatchLevel eFrequencyMatch = NO_MATCH; BOOL bExactMatch = FALSE; PDEVMODEW pdevmodeInfo;
TRACE_INIT(("Drv_Trace: CaptMatchDevmode: Start matching\n"));
DrvBuildDevmodeList(PhysDisp, FALSE);
pdevmodeInfo = PhysDisp->devmodeInfo;
//
// If we can not find a mode because the caller was asking for the
// default mode, then just pick any 640x480 mode.
// We are not worried about picking a nice default because the applet
// generally takes care of that during configuration.
//
// In the case of hydra, the first mode in the driver is picked - why ?
//
// For mirroring, the mode for the primary device should be used.
// A special error code will be used for that
//
if ((partialDevmode->dmBitsPerPel == 0) && (partialDevmode->dmPelsWidth == 0) && (partialDevmode->dmPelsHeight == 0) && (partialDevmode->dmDisplayOrientation == DMDO_DEFAULT)) { WARNING("Drv_Trace: CaptMatchDevmode: DEFAULT DEVMODE picked\n");
if (PhysDisp->stateFlags & (DISPLAY_DEVICE_DISCONNECT | DISPLAY_DEVICE_REMOTE)) { //
// Hydra only supports one mode.
//
if (PhysDisp->devmodeInfo) { partialDevmode->dmBitsPerPel = PhysDisp->devmodeInfo->dmBitsPerPel; partialDevmode->dmPelsWidth = PhysDisp->devmodeInfo->dmPelsWidth; partialDevmode->dmPelsHeight = PhysDisp->devmodeInfo->dmPelsHeight; partialDevmode->dmDisplayFrequency = PhysDisp->devmodeInfo->dmDisplayFrequency; partialDevmode->dmDisplayOrientation = PhysDisp->devmodeInfo->dmDisplayOrientation; partialDevmode->dmDisplayFixedOutput = PhysDisp->devmodeInfo->dmDisplayFixedOutput; } } else if (PhysDisp->stateFlags & DISPLAY_DEVICE_MIRRORING_DRIVER) { //
// For the mirror driver:
// If we have no modes in the driver, fail.
// Otherwise, return the default mode the driver provides.
//
if (PhysDisp->cbdevmodeInfo == 0) { ntRet = STATUS_INVALID_PARAMETER_MIX; } } else { partialDevmode->dmBitsPerPel = 0; partialDevmode->dmPelsWidth = 640; partialDevmode->dmPelsHeight = 480; if (bClosest) { LPDEVMODEW pdm = GetClosestMode(PhysDisp, partialDevmode, bPrune); if (pdm != NULL) { partialDevmode->dmBitsPerPel = pdm->dmBitsPerPel; partialDevmode->dmPelsWidth = pdm->dmPelsWidth; partialDevmode->dmPelsHeight = pdm->dmPelsHeight; partialDevmode->dmDisplayFrequency = pdm->dmDisplayFrequency; partialDevmode->dmDisplayOrientation = pdm->dmDisplayOrientation; partialDevmode->dmDisplayFixedOutput = pdm->dmDisplayFixedOutput; } } } } //
// For mirror drivers:
// If the driver return no modes but something was specified in the
// registry, return that to the driver.
//
else if ((PhysDisp->stateFlags & DISPLAY_DEVICE_MIRRORING_DRIVER) && (PhysDisp->cbdevmodeInfo == 0)) { pdevmodeMatch = partialDevmode;
ASSERTGDI(PhysDisp->cbdevmodeInfo == 0, "MIRROR driver must have no modes\n"); } else if (bClosest) { LPDEVMODEW pdm = GetClosestMode(PhysDisp, partialDevmode, bPrune); if (pdm != NULL) { partialDevmode->dmBitsPerPel = pdm->dmBitsPerPel; partialDevmode->dmPelsWidth = pdm->dmPelsWidth; partialDevmode->dmPelsHeight = pdm->dmPelsHeight; partialDevmode->dmDisplayFrequency = pdm->dmDisplayFrequency; partialDevmode->dmDisplayOrientation = pdm->dmDisplayOrientation; partialDevmode->dmDisplayFixedOutput = pdm->dmDisplayFixedOutput; } }
for (ULONG i = 0; i < PhysDisp->numRawModes; i++) { if (bPrune && PhysDisp->devmodeMarks[i].bPruned) continue; pdevmodeInfo = PhysDisp->devmodeMarks[i].pDevMode; if (((partialDevmode->dmBitsPerPel == 0) || (partialDevmode->dmBitsPerPel == pdevmodeInfo->dmBitsPerPel)) && (partialDevmode->dmPelsWidth == pdevmodeInfo->dmPelsWidth) && (partialDevmode->dmPelsHeight == pdevmodeInfo->dmPelsHeight) && ((partialDevmode->dmDisplayOrientation == pdevmodeInfo->dmDisplayOrientation) || ( (eOrientationMatch != EXACT_MATCH) && !bOrientationSpecified && ( (eOrientationMatch != DEFAULT_MATCH) || (pdevmodeInfo->dmDisplayOrientation == DMDO_DEFAULT)) )) && (!bFixedOutputSpecified || (partialDevmode->dmDisplayFixedOutput == pdevmodeInfo->dmDisplayFixedOutput)) ) { //
// Pick at least the first mode that matches the resolution
// so that we at least have a chance at working.
//
// Then pick 60 Hz if we find it.
//
// Even better, pick the refresh that matches the current
// refresh (we assume that what's in the registry has the
// best chance of working.
//
if (pdevmodeMatch == NULL) { pdevmodeMatch = pdevmodeInfo; }
if ((eOrientationMatch == NO_MATCH) && (pdevmodeInfo->dmDisplayOrientation == DMDO_DEFAULT)) { pdevmodeMatch = pdevmodeInfo;
eOrientationMatch = DEFAULT_MATCH; eFixedOutputMatch = NO_MATCH; eFrequencyMatch = NO_MATCH; }
if ((eOrientationMatch != EXACT_MATCH) && (partialDevmode->dmDisplayOrientation == pdevmodeInfo->dmDisplayOrientation)) { pdevmodeMatch = pdevmodeInfo;
eOrientationMatch = EXACT_MATCH; eFixedOutputMatch = NO_MATCH; eFrequencyMatch = NO_MATCH; }
// Fixed Output setting only matches exactly when specified,
// but matches first when not specified (when field flag isn't
// set or dmDisplayFixedOutput == DMDFO_DEFAULT.)
if ((eFixedOutputMatch != EXACT_MATCH) && (!bFixedOutputSpecified || (partialDevmode->dmDisplayFixedOutput == pdevmodeInfo->dmDisplayFixedOutput) )) { pdevmodeMatch = pdevmodeInfo;
eFixedOutputMatch = EXACT_MATCH; eFrequencyMatch = NO_MATCH; }
if ((eFrequencyMatch == NO_MATCH) && (pdevmodeInfo->dmDisplayFrequency == 60)) { pdevmodeMatch = pdevmodeInfo;
eFrequencyMatch = DEFAULT_MATCH; }
if ((eFrequencyMatch != EXACT_MATCH) && (partialDevmode->dmDisplayFrequency == pdevmodeInfo->dmDisplayFrequency)) { //
// We found even better than 60 - an exact frequency match !
//
eFrequencyMatch = EXACT_MATCH;
pdevmodeMatch = pdevmodeInfo;
if (eOrientationMatch == EXACT_MATCH && eFixedOutputMatch == EXACT_MATCH) { bExactMatch = TRUE; break; }
//
// For now, we ignore these other fields since they
// considered optional.
//
// pdevmodeInfo->dmDisplayFlags;
// pdevmodeInfo->dmPanningWidth;
// pdevmodeInfo->dmPanningHeight;
} } }
//
// Always set these flags since we initialize the values.
// We need consistent flags all the time to avoid extra modesets
//
// Also, force font size to be static for now.
//
if (pdevmodeMatch != NULL) { RtlCopyMemory(matchedDevmode, pdevmodeMatch, pdevmodeMatch->dmSize);
matchedDevmode->dmDriverExtra = (WORD) sizeExtra; matchedDevmode->dmLogPixels = (partialDevmode->dmLogPixels == 0) ? 96 : partialDevmode->dmLogPixels;
matchedDevmode->dmFields |= (DM_PANNINGHEIGHT | DM_PANNINGWIDTH | DM_DISPLAYFLAGS | DM_LOGPIXELS);
//
// Check that the display driver specified all the other
// flags (res, color, frequency) properly.
//
if ((matchedDevmode->dmFields & DM_INTERNAL_VALID_FLAGS) != DM_INTERNAL_VALID_FLAGS) { RIP("Drv_Trace: CaptMatchDevmode: BAD DM FLAGS\n"); }
//
// Extra flag that determines if we should set the attach or
// detach flag
//
matchedDevmode->dmFields |= ((tmpPosition) ? DM_POSITION : 0);
//
// In the case of a good match, also use these extra values.
//
matchedDevmode->dmPosition.x = tmpPositionX; matchedDevmode->dmPosition.y = tmpPositionY; matchedDevmode->dmDisplayFlags = tmpDisplayFlags; matchedDevmode->dmPanningWidth = tmpPanningWidth; matchedDevmode->dmPanningHeight = tmpPanningHeight; }
//
// MAJOR optimization : Do not free the list at this point.
// Many apps call EnumDisplaySettings, and for each mode call
// ChangeDisplaySettings with it to see if it can be changed
// dynamically. When we free the list here, it causes us to recreate
// the list for each mode we have in the list, which can take on
// the order of 30 seconds if there are multiple display drivers
// involved.
// Even if we keep the list here, it should properly get freed
// at the end of EnumDisplaySettings.
//
//
// Exit path
//
if (pdevmodeMatch != NULL) { TRACE_INIT(("Drv_Trace: CaptMatchDevmode: Matched DEVMODE\n")); dbgDumpDevmode(matchedDevmode);
*DestinationDevmode = matchedDevmode;
ntRet = (bExactMatch) ? STATUS_SUCCESS : (((eFrequencyMatch != EXACT_MATCH) && partialDevmode->dmDisplayFrequency) ? STATUS_INVALID_PARAMETER : ((eFrequencyMatch == EXACT_MATCH) ? STATUS_SUCCESS : STATUS_RECEIVE_PARTIAL)); } else { VFREEMEM(matchedDevmode); } }
VFREEMEM(partialDevmode);
if (NT_SUCCESS(ntRet)) { if (ntRet == STATUS_RECEIVE_PARTIAL) { TRACE_INIT(("Drv_Trace: CaptMatchDevmode: Exit partial success\n\n")); } else { TRACE_INIT(("Drv_Trace: CaptMatchDevmode: Exit exact success\n\n")); } } else { TRACE_INIT(("Drv_Trace: CaptMatchDevmode: Exit error\n\n")); }
return (ntRet); }
/***************************************************************************\
* DrvGetVideoPowerState * * History: * 02-Dec-1996 AndreVa Created. \***************************************************************************/
NTSTATUS DrvGetMonitorPowerState( PMDEV pmdev, DEVICE_POWER_STATE PowerState) { NTSTATUS Status = STATUS_UNSUCCESSFUL; VIDEO_POWER_STATE VideoPowerState = (VIDEO_POWER_STATE) PowerState; ULONG BytesReturned; ULONG i;
#ifdef _HYDRA_
if (gProtocolType != PROTOCOL_CONSOLE ) { //
// Don't Call this for remote video drivers
//
return STATUS_UNSUCCESSFUL; } #endif
for (i = 0; i < pmdev->chdev; i++) { PDEVOBJ pdo(pmdev->Dev[i].hdev);
if ((pdo.ppdev->pGraphicsDevice->stateFlags & DISPLAY_DEVICE_DISCONNECT) != 0 ) { //
// Don't Call this for disconnect drivers
//
ASSERT(pdo.ppdev->pGraphicsDevice->pDeviceHandle == NULL ); continue; }
Status = GreDeviceIoControl(pdo.ppdev->pGraphicsDevice->pDeviceHandle, IOCTL_VIDEO_GET_OUTPUT_DEVICE_POWER_STATE, &VideoPowerState, sizeof(VideoPowerState), NULL, 0, &BytesReturned);
if (!NT_SUCCESS(Status)) { break; } }
return Status; }
/***************************************************************************\
* DrvSetVideoPowerState * * History: * 02-Dec-1996 AndreVa Created. \***************************************************************************/
NTSTATUS DrvSetMonitorPowerState( PMDEV pmdev, DEVICE_POWER_STATE PowerState) { NTSTATUS Status = STATUS_UNSUCCESSFUL; VIDEO_POWER_STATE VideoPowerState = (VIDEO_POWER_STATE) PowerState; ULONG BytesReturned; ULONG i;
#ifdef _HYDRA_
if (gProtocolType != PROTOCOL_CONSOLE ) { //
// Don't Call this for remote video drivers
//
return STATUS_UNSUCCESSFUL; } #endif
for (i = 0; i < pmdev->chdev; i++) { PDEVOBJ pdo(pmdev->Dev[i].hdev);
#ifdef _HYDRA_
if (pdo.ppdev->pGraphicsDevice->stateFlags & DISPLAY_DEVICE_DISCONNECT) { //
// Don't Call this for disconnect drivers
//
if (pdo.ppdev->pGraphicsDevice->pDeviceHandle) { TRACE_INIT(("DrvSetMonitorPowerState: Disconnect DD has a Device Handle = %p!\n", pdo.ppdev->pGraphicsDevice->pDeviceHandle)); #if DBG
DbgBreakPoint(); #endif
} continue; } #endif
Status = GreDeviceIoControl(pdo.ppdev->pGraphicsDevice->pDeviceHandle, IOCTL_VIDEO_SET_OUTPUT_DEVICE_POWER_STATE, &VideoPowerState, sizeof(VideoPowerState), NULL, 0, &BytesReturned);
// !!! partial state problem ...
if (!NT_SUCCESS(Status)) { break; } }
return Status; }
/***************************************************************************\
* DrvQueryMDEVPowerState( * * History: * 26-Jul-1998 AndreVa Created. \***************************************************************************/
BOOL DrvQueryMDEVPowerState( PMDEV pmdev ) { ULONG i; HDEV hdev;
for (i=0; i < pmdev->chdev; i++) { PDEVOBJ pdo(pmdev->Dev[i].hdev);
if (pdo.ppdev->pGraphicsDevice->stateFlags & DISPLAY_DEVICE_POWERED_OFF) { TRACE_INIT(("Drv_Trace: DrvQueryMDEVPowerState is OFF\n")); return FALSE; } }
TRACE_INIT(("Drv_Trace: DrvQueryMDEVPowerState is ON\n")); return TRUE; }
VOID DrvSetMDEVPowerState( PMDEV pmdev, BOOL On ) { TRACE_INIT(("Drv_Trace: DrvSetMDEVPowerState MDEV %p %s\n", pmdev, On ? "ON" : "OFF"));
ULONG i; HDEV hdev;
for (i=0; i < pmdev->chdev; i++) { PDEVOBJ pdo(pmdev->Dev[i].hdev);
if (On) { pdo.ppdev->pGraphicsDevice->stateFlags &= ~DISPLAY_DEVICE_POWERED_OFF; } else { pdo.ppdev->pGraphicsDevice->stateFlags |= DISPLAY_DEVICE_POWERED_OFF; } } }
/***************************************************************************\
* DrvDisplaySwitchHandler() * * Return Value: * TRUE: System needs to update to a new mode * FALSE: The current mode works fine * * History: * Dennyd Created \***************************************************************************/ #define PRUNEMODE_REGKEY L"PruningMode" // PruneMode Flag
#define PRUNEMODE_BUFSIZE (sizeof(KEY_VALUE_FULL_INFORMATION) + sizeof(PRUNEMODE_REGKEY) + sizeof(DWORD))
BOOL DrvGetPruneFlag(PGRAPHICS_DEVICE PhysDisp) { HANDLE hkRegistry; DWORD PrunningMode = 1; BYTE buffer[PRUNEMODE_BUFSIZE]; PKEY_VALUE_FULL_INFORMATION Information = (PKEY_VALUE_FULL_INFORMATION)buffer; ULONG Length = PRUNEMODE_BUFSIZE;
hkRegistry = DrvGetRegistryHandleFromDeviceMap( PhysDisp, DispDriverRegGlobal, NULL, NULL, NULL, gProtocolType);
if (hkRegistry) { UNICODE_STRING UnicodeString; RtlInitUnicodeString(&UnicodeString, PRUNEMODE_REGKEY);
if (NT_SUCCESS(ZwQueryValueKey(hkRegistry, &UnicodeString, KeyValueFullInformation, Information, Length, &Length))) { PrunningMode = *(LPDWORD) ((((PUCHAR)Information) + Information->DataOffset)); } ZwCloseKey(hkRegistry); } return (PrunningMode != 0); }
BOOL DrvDisplaySwitchHandler( PVOID physDisp, // IN
PUNICODE_STRING pstrDeviceName, // OUT
LPDEVMODEW pNewMode, // OUT
PULONG pPrune // OUT
) { DEVMODEW srcMode; LPDEVMODEW lpModeWanted; PGRAPHICS_DEVICE PhysDisp = (PGRAPHICS_DEVICE)physDisp; ULONG i; BOOL uu, bPrune;
TRACE_INIT(("DrvDisplaySwitchHandler: Enter\n"));
gbUpdateMonitor = TRUE; UpdateMonitorDevices();
//
// On display switching, update mode list according to new active displays
//
DrvBuildDevmodeList(PhysDisp, TRUE);
bPrune = DrvGetPruneFlag(PhysDisp); *pPrune = bPrune;
//
// Check if the mode in registry complies with the new mode list
// This is neccessary because when the system was first setup, there is no reg value
// under per monitor registry.
//
RtlZeroMemory(&srcMode, sizeof(DEVMODEW)); srcMode.dmSize = sizeof(DEVMODEW); if (NT_SUCCESS (DrvProbeAndCaptureDevmode(PhysDisp, &lpModeWanted, &uu, &srcMode, FALSE, KernelMode, bPrune, TRUE, TRUE) ) ) { TRACE_INIT(("DrvDisplaySwitchHandler: Pick reg mode B=%d W=%d H=%d F=%d R=%lu\n", lpModeWanted->dmBitsPerPel, lpModeWanted->dmPelsWidth, lpModeWanted->dmPelsHeight, lpModeWanted->dmDisplayFrequency, lpModeWanted->dmDisplayOrientation*90));
RtlCopyMemory(pNewMode, lpModeWanted, sizeof(DEVMODEW)); RtlInitUnicodeString(pstrDeviceName, &(PhysDisp->szWinDeviceName[0]));
{ //
// If there is only one output device, update per monitor settings as well
//
ULONG activePdos = 0; for (i = 0; i < PhysDisp->numMonitorDevice; i++) { if (IS_ATTACHED_ACTIVE(PhysDisp->MonitorDevices[i].flag)) { activePdos++; } } DrvUpdateDisplayDriverParameters(PhysDisp, lpModeWanted, FALSE, (activePdos == 1)); }
VFREEMEM(lpModeWanted);
return TRUE; }
return FALSE; }
PVOID DrvWakeupHandler( HANDLE *ppdo // OUT
) { PGRAPHICS_DEVICE PhysDisp;
for (PhysDisp = gpGraphicsDeviceList; PhysDisp != NULL; PhysDisp = PhysDisp->pNextGraphicsDevice) { if (PhysDisp->stateFlags & DISPLAY_DEVICE_ACPI) { break; } }
if (PhysDisp) { *ppdo = PhysDisp->pPhysDeviceHandle; }
return (PVOID)PhysDisp; }
/***************************************************************************\
* * DrvSendPnPIrp * * History: \***************************************************************************/
NTSTATUS DrvSendPnPIrp( PDEVICE_OBJECT pDeviceObject, DEVICE_RELATION_TYPE relationType, PDEVICE_RELATIONS *pDeviceRelations) { NTSTATUS status; PIRP Irp; PIO_STACK_LOCATION IrpSp; KEVENT event; IO_STATUS_BLOCK IoStatusBlock; //
// Anything else is illegal.
//
ASSERT(relationType == TargetDeviceRelation);
KeInitializeEvent(&event, SynchronizationEvent, FALSE);
Irp = IoBuildSynchronousFsdRequest(IRP_MJ_PNP, pDeviceObject, NULL, 0, NULL, &event, &IoStatusBlock);
if (Irp == NULL) {
return STATUS_INSUFFICIENT_RESOURCES; }
//
// Set the default error code.
//
Irp->IoStatus.Status = IoStatusBlock.Status = STATUS_NOT_SUPPORTED;
IrpSp = IoGetNextIrpStackLocation(Irp); IrpSp->MajorFunction = IRP_MJ_PNP; IrpSp->MinorFunction = IRP_MN_QUERY_DEVICE_RELATIONS;
IrpSp->Parameters.QueryDeviceRelations.Type = relationType;
//
// Call the filter driver.
//
status = IoCallDriver(pDeviceObject, Irp);
if (status == STATUS_PENDING) {
KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
status = IoStatusBlock.Status;
}
if (NT_SUCCESS(status)) { *pDeviceRelations = (PDEVICE_RELATIONS) IoStatusBlock.Information; }
return status; }
/**************************************************************************\
* __EnumDisplayQueryRoutine * * Callback to get the display driver name. * * CRIT not needed * * 12-Jan-1994 andreva created \**************************************************************************/
NTSTATUS __DisplayDriverQueryRoutine( IN PWSTR ValueName, IN ULONG ValueType, IN PVOID ValueData, IN ULONG ValueLength, IN PVOID Context, IN PVOID EntryContext) { //
// If the context value is NULL and the entry type is correct, then store
// the length of the value. Otherwise, copy the value to the specified
// memory.
//
PGRAPHICS_DEVICE PhysDisp = (PGRAPHICS_DEVICE) Context;
//
// Include workaround for vendors that don't understand MULTI_SZ !
//
if (ValueType != REG_MULTI_SZ) { ASSERT(FALSE); }
TRACE_INIT(("Drv_Trace: __DisplayDriverQueryRoutine MULTISZ %ws = %ws\n", ValueName, ValueData));
if (!(PhysDisp->DisplayDriverNames = (LPWSTR) PALLOCNOZ(ValueLength + 2, GDITAG_DRVSUP))) { return STATUS_INSUFFICIENT_RESOURCES; }
RtlCopyMemory(PhysDisp->DisplayDriverNames, ValueData, ValueLength); *((LPWSTR) (((PUCHAR)PhysDisp->DisplayDriverNames) + ValueLength)) = UNICODE_NULL;
return STATUS_SUCCESS;
UNREFERENCED_PARAMETER(ValueName); UNREFERENCED_PARAMETER(EntryContext); }
NTSTATUS __EnumDisplayQueryRoutine( IN PWSTR ValueName, IN ULONG ValueType, IN PVOID ValueData, IN ULONG ValueLength, IN PVOID Context, IN PVOID EntryContext) { //
// If the context value is NULL and the entry type is correct, then store
// the length of the value. Otherwise, copy the value to the specified
// memory.
//
PGRAPHICS_DEVICE PhysDisp = (PGRAPHICS_DEVICE) Context; NTSTATUS status = STATUS_SUCCESS;
//
// If the value is a string with only a NULL value, then keep going
// to the next possible string.
// So only try to save the string for > 2 characters.
//
if (ValueLength > 2) { if (ValueType == REG_SZ) { if (PhysDisp->DeviceDescription == NULL) { TRACE_INIT(("Drv_Trace: __EnumDisplayQueryRoutine SZ %ws = %ws\n", ValueName, ValueData));
if (PhysDisp->DeviceDescription = (LPWSTR) PALLOCNOZ(ValueLength, GDITAG_DRVSUP)) { RtlCopyMemory(PhysDisp->DeviceDescription, ValueData, ValueLength); } else { status = STATUS_INSUFFICIENT_RESOURCES; } } } else if (ValueType == REG_BINARY) { if (PhysDisp->DeviceDescription == NULL) { TRACE_INIT(("Drv_Trace: __EnumDisplayQueryRoutine BINARY %ws = %ws\n", ValueName, ValueData));
if (PhysDisp->DeviceDescription = (LPWSTR) PALLOCNOZ(ValueLength + sizeof(WCHAR), GDITAG_DRVSUP)) { RtlCopyMemory(PhysDisp->DeviceDescription, ValueData, ValueLength); *((LPWSTR)((LPBYTE)PhysDisp->DeviceDescription + ValueLength)) = UNICODE_NULL; } else { status = STATUS_INSUFFICIENT_RESOURCES; } } } else { ASSERTGDI(FALSE, "Drv_Trace: __EnumDisplayQueryRoutine: Invalid callout type\n");
status = STATUS_SUCCESS; } }
return status;
UNREFERENCED_PARAMETER(ValueName); UNREFERENCED_PARAMETER(EntryContext); }
/***************************************************************************\
* IsVgaDevice * * Determine if the given PhysDisp is for the VGA. * * 13-Oct-1999 ericks Created \***************************************************************************/
BOOLEAN IsVgaDevice( PGRAPHICS_DEVICE PhysDisp )
{ BOOLEAN Result = FALSE; ULONG bytesReturned; NTSTATUS status;
status = GreDeviceIoControl(PhysDisp->pDeviceHandle, IOCTL_VIDEO_IS_VGA_DEVICE, NULL, 0, &Result, sizeof(Result), &bytesReturned);
if (NT_SUCCESS(status)) { return Result; }
return FALSE; }
/**************************************************************************\
* DrvGetDeviceConfigurationInformation * * Get the registry parameters for the driver * * 30-Apr-1998 andreva created \**************************************************************************/
VOID DrvGetDeviceConfigurationInformation( PGRAPHICS_DEVICE PhysDisp, HANDLE hkRegistry, BOOL bIsPdo ) { NTSTATUS status;
ULONG defaultValue = 0; ULONG multiDriver = 0; ULONG mirroring = 0; ULONG vgaCompat = 0;
RTL_QUERY_REGISTRY_TABLE multiQueryTable[] = { {__EnumDisplayQueryRoutine, RTL_QUERY_REGISTRY_REQUIRED | RTL_QUERY_REGISTRY_NOEXPAND, SoftwareSettings[0], NULL, REG_NONE, NULL, 0}, {NULL, RTL_QUERY_REGISTRY_SUBKEY, L"Settings", NULL, REG_NONE, NULL, 0}, {__DisplayDriverQueryRoutine, RTL_QUERY_REGISTRY_REQUIRED | RTL_QUERY_REGISTRY_NOEXPAND, SoftwareSettings[1], NULL, REG_NONE, NULL, 0}, {NULL, RTL_QUERY_REGISTRY_DIRECT, SoftwareSettings[2], &multiDriver, REG_DWORD, &defaultValue, 4}, {NULL, RTL_QUERY_REGISTRY_DIRECT, SoftwareSettings[3], &mirroring, REG_DWORD, &defaultValue, 4}, {NULL, RTL_QUERY_REGISTRY_DIRECT, SoftwareSettings[4], &vgaCompat, REG_DWORD, &defaultValue, 4},
// Device Description is optional, for 4.0 legacy only
{__EnumDisplayQueryRoutine, RTL_QUERY_REGISTRY_NOEXPAND, SoftwareSettings[5], NULL, REG_NONE, NULL, 0}, {__EnumDisplayQueryRoutine, RTL_QUERY_REGISTRY_NOEXPAND, SoftwareSettings[6], NULL, REG_NONE, NULL, 0}, {__EnumDisplayQueryRoutine, RTL_QUERY_REGISTRY_NOEXPAND, SoftwareSettings[7], NULL, REG_NONE, NULL, 0}, {NULL, 0, NULL} };
status = RtlQueryRegistryValues(RTL_REGISTRY_HANDLE, (PWSTR)hkRegistry, bIsPdo ? &multiQueryTable[0] : &multiQueryTable[2], PhysDisp, NULL);
if (NT_SUCCESS(status))
{ if (multiDriver) PhysDisp->stateFlags |= DISPLAY_DEVICE_MULTI_DRIVER; if (mirroring) PhysDisp->stateFlags |= DISPLAY_DEVICE_MIRRORING_DRIVER;
//
// We must determine which graphics device actually has the VGA resources
//
if (vgaCompat && IsVgaDevice(PhysDisp)) PhysDisp->stateFlags |= DISPLAY_DEVICE_VGA_COMPATIBLE;
TRACE_INIT(("DrvGetDeviceConfigurationInformation: Display driver is %sa multi display driver\n", multiDriver ? "" : "NOT ")); TRACE_INIT(("DrvGetDeviceConfigurationInformation: Display driver is %smirroring the desktop\n", mirroring ? "" : "NOT ")); TRACE_INIT(("DrvGetDeviceConfigurationInformation: Display driver is %sVga Compatible\n", vgaCompat ? "" : "NOT ")); } else { //
//
// An error occured - this device is miss-configured.
//
TRACE_INIT(("DrvGetDeviceConfigurationInformation: Device is misconfigured\n"));
DrvLogDisplayDriverEvent(MsgInvalidConfiguration);
if (PhysDisp->DisplayDriverNames) { VFREEMEM(PhysDisp->DisplayDriverNames); PhysDisp->DisplayDriverNames = NULL; } if (PhysDisp->DeviceDescription) { VFREEMEM(PhysDisp->DeviceDescription); PhysDisp->DeviceDescription = NULL; } }
return; }
/**************************************************************************\
* DrvSetSingleDisplay * * Remove all physical displays except for specified primary. * If PhysDispPrimary == NULL, the list physical displays is * searched for the marked display and secondly any one. * * 25-May-2000 jasonha created \**************************************************************************/
BOOL bPrunedDisplayDevice = FALSE; // Was a secondary display devcice rejected?
PGRAPHICS_DEVICE DrvSetSingleDisplay( PGRAPHICS_DEVICE PhysDispPrimary ) { GDIFunctionID(DrvSetSingleDisplay);
PGRAPHICS_DEVICE PhysDispTemp; PGRAPHICS_DEVICE PhysDispPrev = NULL; PGRAPHICS_DEVICE PhysDispNext = NULL;
// Confirm the given primary is in the list
// or identify the marked primary.
for (PhysDispTemp = gpGraphicsDeviceList; PhysDispTemp != NULL; PhysDispTemp = PhysDispTemp->pNextGraphicsDevice) { if (! (PhysDispTemp->stateFlags & (DISPLAY_DEVICE_MIRRORING_DRIVER | DISPLAY_DEVICE_REMOTE | DISPLAY_DEVICE_DISCONNECT))) { if (PhysDispPrimary == NULL) { if (PhysDispTemp->stateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE) { PhysDispPrimary = PhysDispTemp; break; } } else { if (PhysDispTemp == PhysDispPrimary) { break; } } } }
// If we haven't identified a primary,
// select any physical display.
if (PhysDispPrimary == NULL) { for (PhysDispTemp = gpGraphicsDeviceList; PhysDispTemp != NULL; PhysDispTemp = PhysDispTemp->pNextGraphicsDevice) { if (! (PhysDispTemp->stateFlags & (DISPLAY_DEVICE_MIRRORING_DRIVER | DISPLAY_DEVICE_REMOTE | DISPLAY_DEVICE_DISCONNECT))) { PhysDispPrimary = PhysDispTemp; break; } } }
// If we didn't find the specified primary or a
// suitable one, then there is nothing to do.
if (PhysDispTemp == NULL) { return NULL; }
// Remove all physical secondary displays
PhysDispPrev = NULL;
for (PhysDispTemp = gpGraphicsDeviceList; PhysDispTemp != NULL; PhysDispTemp = PhysDispNext) { PhysDispNext = PhysDispTemp->pNextGraphicsDevice;
if (PhysDispTemp != PhysDispPrimary && ! (PhysDispTemp->stateFlags & (DISPLAY_DEVICE_MIRRORING_DRIVER | DISPLAY_DEVICE_REMOTE | DISPLAY_DEVICE_DISCONNECT))) { ASSERTGDI(PhysDispTemp != gPhysDispVGA, "Removing VGA as a secondary.\n"); bPrunedDisplayDevice = TRUE;
// Remove from list
if (PhysDispPrev == NULL) { gpGraphicsDeviceList = PhysDispTemp->pNextGraphicsDevice; } else { PhysDispPrev->pNextGraphicsDevice = PhysDispTemp->pNextGraphicsDevice; }
if (PhysDispTemp == gpGraphicsDeviceListLast) { gpGraphicsDeviceListLast = PhysDispPrev; }
// Cleanup any allocations
if (PhysDispTemp->DisplayDriverNames) VFREEMEM(PhysDispTemp->DisplayDriverNames);
if (PhysDispTemp->DeviceDescription) VFREEMEM(PhysDispTemp->DeviceDescription);
if (PhysDispTemp->MonitorDevices) VFREEMEM(PhysDispTemp->MonitorDevices);
if (PhysDispTemp->devmodeInfo) VFREEMEM(PhysDispTemp->devmodeInfo);
if (PhysDispTemp->devmodeMarks) VFREEMEM(PhysDispTemp->devmodeMarks);
VFREEMEM(PhysDispTemp);
// Reuse output numbers so next added display is in order.
gcNextGlobalPhysicalOutputNumber--; } else { PhysDispPrev = PhysDispTemp; } }
// Set Primary markings
if (PhysDispPrimary) { PhysDispPrimary->stateFlags |= DISPLAY_DEVICE_PRIMARY_DEVICE;
// Make sure this is display 1 for app compat.
wcscpy(&(PhysDispPrimary->szWinDeviceName[0]), L"\\\\.\\DISPLAY1");
// If we loaded VGA and it is not the primary display, then
// rename it to display 2. It can't actually be referenced
// from APIs, but we can keep the numbers in order.
if (gPhysDispVGA && gPhysDispVGA != PhysDispPrimary) { // Rename VGA's WinDeviceName
wcscpy(&(gPhysDispVGA->szWinDeviceName[0]), L"\\\\.\\DISPLAY2");
ASSERTGDI(gcNextGlobalPhysicalOutputNumber == 3, "gcNextGlobalPhysicalOutputNumber != 3\n"); } else { ASSERTGDI(gcNextGlobalPhysicalOutputNumber == 2, "gcNextGlobalPhysicalOutputNumber != 2\n"); } }
return PhysDispPrimary; }
/**************************************************************************\
* DrvUpdateVgaDevice * * Update the VGA graphics device in the machine. * * 01-Apr-1998 andreva created \**************************************************************************/
PGRAPHICS_DEVICE DrvUpdateVgaDevice() { PGRAPHICS_DEVICE PhysDispIsVga; PGRAPHICS_DEVICE PhysDispMarkVga; PGRAPHICS_DEVICE PhysDispTmp;
NTSTATUS Status; VIDEO_NUM_MODES NumModes; ULONG NumModesLength = sizeof(NumModes); ULONG cbBuffer; ULONG BytesReturned;
PVIDEO_MODE_INFORMATION lpModes; PVIDEO_MODE_INFORMATION pVideoModeSave;
ULONG cTextModes = 0; ULONG cGraphicsModes = 0;
LPDEVMODEW pUsDevmode; LPDEVMODEW ptmpDevmode; LPDEVMODEMARK pUsDevmodeMark;
BOOLEAN PrimaryExists = FALSE; BOOL VGAInUse = FALSE;
TRACE_INIT(("Drv_Trace: DrvUpdateVgaDevice: Finding VGA device\n"));
//
// Find the VGA compatible driver for the console.
//
// NOTE - These fullscreen modes are only supported on X86
//
//
// Clear out the VGA, and the VGA flag of the parent if necessary
//
for (PhysDispTmp = gpGraphicsDeviceList; PhysDispTmp != NULL; PhysDispTmp = PhysDispTmp->pNextGraphicsDevice) { PhysDispTmp->pVgaDevice = NULL;
if ((PhysDispTmp->stateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE) && (PhysDispTmp != gPhysDispVGA)) {
//
// Determine if this device is currently a primary, and it
// is not the VGA. (The VGA may later be removed).
//
PrimaryExists = TRUE; } }
//
// If there is no primary device yet, lets choose the vga.
//
if (PrimaryExists == FALSE) {
for (PhysDispTmp = gpGraphicsDeviceList; PhysDispTmp != NULL; PhysDispTmp = PhysDispTmp->pNextGraphicsDevice) {
if (IsVgaDevice(PhysDispTmp)) {
PhysDispTmp->stateFlags |= DISPLAY_DEVICE_PRIMARY_DEVICE; PrimaryExists = TRUE;
break; } } }
//
// Find the VGA compatible device
//
for (PhysDispIsVga = gpGraphicsDeviceList; PhysDispIsVga != NULL; PhysDispIsVga = PhysDispIsVga->pNextGraphicsDevice) { //
// The vga driver is here for compatibility.
// Look for all other possibilities, and revert to VGA as a last
// possibility
//
if (PhysDispIsVga == gPhysDispVGA) { continue; }
if (PhysDispIsVga->stateFlags & DISPLAY_DEVICE_VGA_COMPATIBLE) { break; } }
//
// If no vga device was found, use the vga driver
//
if (PhysDispIsVga == NULL) { PhysDispIsVga = gPhysDispVGA; }
//
// On some machines, with TGA for example, it's possible to have no
// VGA compatible device.
//
if (PhysDispIsVga == NULL) { return NULL; }
//
// Now determine if there is a duplicate device (like VGA)
//
// HACK - we only support the VGA as a duplicate device right now.
// We need more info for cirrus + #9
//
// VGA is a duplicate if there is ANOTHER driver in the machine, excluding
// for MIRROR DEVICES, Disconnected device and remote devices. Personal
// Windows also requires the driver to be the VGA device driver.
//
PhysDispMarkVga = PhysDispIsVga;
if (gPhysDispVGA) { PPDEV ppdev;
// Determine if VGA device is being used.
// We have to hold ghsemDriverMgmt to be sure its
// status doesn't change.
GreAcquireSemaphoreEx(ghsemDriverMgmt, SEMORDER_DRIVERMGMT, NULL);
for (ppdev = gppdevList; ppdev != NULL; ppdev = ppdev->ppdevNext) { if (ppdev->pGraphicsDevice == gPhysDispVGA) { VGAInUse = TRUE; break; } }
// If the VGA device's driver is non-VGA compatible
// (DISPLAY_DEVICE_VGA_COMPATIBLE was not marked on
// any device so
// PhysDispMarkVga = PhysDispIsVga = gPhysDispVGA),
// then search for it so it may be marked as the VGA
if (PhysDispMarkVga == gPhysDispVGA) { // Look for the real VGA device
for (PhysDispMarkVga = gpGraphicsDeviceList; PhysDispMarkVga != NULL; PhysDispMarkVga = PhysDispMarkVga->pNextGraphicsDevice ) { if ((PhysDispMarkVga != gPhysDispVGA) && ((PhysDispMarkVga->stateFlags & (DISPLAY_DEVICE_MIRRORING_DRIVER | DISPLAY_DEVICE_DISCONNECT | DISPLAY_DEVICE_REMOTE) ) == 0) && IsVgaDevice(PhysDispMarkVga) ) break; }
// If no real VGA device was found and
// the VGA device isn't in use and
// this is not Personal Windows, choose
// any display to be marked as the VGA
if (PhysDispMarkVga == NULL && !VGAInUse && !((USER_SHARED_DATA->NtProductType == NtProductWinNt) && (USER_SHARED_DATA->SuiteMask & (1 << Personal)))) { for (PhysDispMarkVga = gpGraphicsDeviceList; PhysDispMarkVga != NULL; PhysDispMarkVga = PhysDispMarkVga->pNextGraphicsDevice ) { if ((PhysDispMarkVga != gPhysDispVGA) && ((PhysDispMarkVga->stateFlags & (DISPLAY_DEVICE_MIRRORING_DRIVER | DISPLAY_DEVICE_DISCONNECT | DISPLAY_DEVICE_REMOTE) ) == 0) ) break; }
}
// No real VGA device was found,
// so we'll use VGA.sys device.
if (PhysDispMarkVga == NULL) { PhysDispMarkVga = gPhysDispVGA; } }
//
// Remove the VGA.sys device from the list of devices if it is a duplicate.
//
if (gPhysDispVGA != PhysDispMarkVga) { //
// Take this device out of the list.
//
// Handle the case where the device is already removed
//
if (gpGraphicsDeviceList == gPhysDispVGA) { gpGraphicsDeviceList = gPhysDispVGA->pNextGraphicsDevice; } else { PhysDispTmp = gpGraphicsDeviceList;
while (PhysDispTmp) { if (PhysDispTmp->pNextGraphicsDevice != gPhysDispVGA) { PhysDispTmp = PhysDispTmp->pNextGraphicsDevice; continue; }
PhysDispTmp->pNextGraphicsDevice = gPhysDispVGA->pNextGraphicsDevice;
if (PhysDispTmp->pNextGraphicsDevice == NULL) { gpGraphicsDeviceListLast = PhysDispTmp; }
break; } }
//
// Mark the VGA as a VGA so we can do easy test later to match
// graphics devices.
//
gPhysDispVGA->pVgaDevice = gPhysDispVGA;
//
// If VGA device is in use, replace all ppdev
// references to it with the new device and
// update state on new device.
//
if (VGAInUse) { DWORD VGATransferFlags = (DISPLAY_DEVICE_ATTACHED_TO_DESKTOP | DISPLAY_DEVICE_PRIMARY_DEVICE);
PhysDispMarkVga->stateFlags |= gPhysDispVGA->stateFlags & VGATransferFlags; gPhysDispVGA->stateFlags &= ~VGATransferFlags;
for (ppdev = gppdevList; ppdev != NULL; ppdev = ppdev->ppdevNext) { if (ppdev->pGraphicsDevice == gPhysDispVGA) { ppdev->pGraphicsDevice = PhysDispMarkVga; } } } }
GreReleaseSemaphoreEx(ghsemDriverMgmt); }
//
// Save the VGA device
//
PhysDispMarkVga->pVgaDevice = PhysDispIsVga;
//
// Build the list of text modes for this device
//
TRACE_INIT(("Drv_Trace: LoadDriver: get text modes\n"));
Status = GreDeviceIoControl(PhysDispIsVga->pDeviceHandle, IOCTL_VIDEO_QUERY_NUM_AVAIL_MODES, NULL, 0, &NumModes, NumModesLength, &BytesReturned);
cbBuffer = NumModes.NumModes * NumModes.ModeInformationLength;
if ( (NT_SUCCESS(Status)) && (lpModes = (PVIDEO_MODE_INFORMATION) PALLOCMEM(cbBuffer, GDITAG_DRVSUP)) ) { Status = GreDeviceIoControl(PhysDispIsVga->pDeviceHandle, IOCTL_VIDEO_QUERY_AVAIL_MODES, NULL, 0, lpModes, cbBuffer, &BytesReturned);
pVideoModeSave = lpModes;
//
// We will not support more than three text modes.
// So just allocate enough for that.
//
if ((NT_SUCCESS(Status)) && (pUsDevmode = (LPDEVMODEW)PALLOCMEM(3 * sizeof(DEVMODEW), GDITAG_DRVSUP)) && (pUsDevmodeMark = (LPDEVMODEMARK)PALLOCMEM(3 * sizeof(DEVMODEMARK), GDITAG_DRVSUP)) ) { TRACE_INIT(("Drv_Trace: LoadDriver: parsing fullscreen modes\n"));
while (cbBuffer != 0) { if (lpModes->AttributeFlags & VIDEO_MODE_COLOR) { if (lpModes->AttributeFlags & VIDEO_MODE_GRAPHICS) { if (cGraphicsModes) { goto ConsoleNextMode; }
ptmpDevmode = pUsDevmode + 2;
//
// Make sure we have only one graphics mode
//
if (IsNEC_98) { if ((lpModes->VisScreenWidth != 640) || (lpModes->VisScreenHeight != 480) || ((lpModes->NumberOfPlanes * lpModes->BitsPerPlane) != 8)) { goto ConsoleNextMode; } } else if ((lpModes->VisScreenWidth != 640) || (lpModes->VisScreenHeight != 480) || ((lpModes->NumberOfPlanes * lpModes->BitsPerPlane) != 4)) { goto ConsoleNextMode; }
TRACE_INIT(("Drv_Trace: DrvInitConsole: VGA graphics mode\n")); cGraphicsModes++; } else { ptmpDevmode = pUsDevmode + cTextModes;
//
// Make sure we have only 2 text modes
//
if (cTextModes == 2) { RIP("Drv_Trace: VGA compatible device has too many text modes\n");
goto ConsoleNextMode; }
TRACE_INIT(("Drv_Trace: DrvInitConsole: VGA text mode\n")); cTextModes++; }
RtlZeroMemory(ptmpDevmode, sizeof(DEVMODEW));
if (!(lpModes->AttributeFlags & VIDEO_MODE_GRAPHICS)) { ptmpDevmode->dmDisplayFlags = DMDISPLAYFLAGS_TEXTMODE; }
memcpy(ptmpDevmode->dmDeviceName, L"FULLSCREEN CONSOLE", sizeof(L"FULLSCREEN CONSOLE"));
ptmpDevmode->dmSize = sizeof(DEVMODEW); ptmpDevmode->dmSpecVersion = DM_SPECVERSION; ptmpDevmode->dmDriverVersion = DM_SPECVERSION;
ptmpDevmode->dmPelsWidth = lpModes->VisScreenWidth; ptmpDevmode->dmPelsHeight = lpModes->VisScreenHeight; ptmpDevmode->dmBitsPerPel = lpModes->NumberOfPlanes * lpModes->BitsPerPlane; ptmpDevmode->dmDisplayOrientation = DMDO_DEFAULT; ptmpDevmode->dmDisplayFixedOutput = DMDFO_DEFAULT;
ptmpDevmode->dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT | DM_DISPLAYFREQUENCY | DM_DISPLAYFLAGS | DM_DISPLAYORIENTATION;
//
// NOTE !!!
// As a hack, lets store the mode number in
// a field we don't use
//
ptmpDevmode->dmOrientation = (USHORT) lpModes->ModeIndex; }
ConsoleNextMode: cbBuffer -= NumModes.ModeInformationLength; lpModes = (PVIDEO_MODE_INFORMATION) (((PUCHAR)lpModes) + NumModes.ModeInformationLength); } }
VFREEMEM(pVideoModeSave); }
//
// if everything went OK with that, then we can save this
// device as vga compatible !
//
// If no modes are available, do not setup this device.
// Otherwise, EnumDisplaySettings will end up trying to get
// the list of modes for this device, which it can not do.
//
if ((cGraphicsModes == 1) && (cTextModes == 2)) { UNICODE_STRING DeviceName; HANDLE pDeviceHandle; PVOID pFileObject;
TRACE_INIT(("Drv_Trace: LoadDriver: saving VGA compatible device\n"));
//
// Copy the string and the handle ...
//
RtlCopyMemory(&gFullscreenGraphicsDevice, PhysDispIsVga, sizeof(GRAPHICS_DEVICE));
//
// 2 text modes + 1 graphics mode.
//
gFullscreenGraphicsDevice.cbdevmodeInfo = 3 * sizeof(DEVMODEW); gFullscreenGraphicsDevice.devmodeInfo = pUsDevmode; gFullscreenGraphicsDevice.numRawModes = 3; gFullscreenGraphicsDevice.devmodeMarks = pUsDevmodeMark; for (ULONG i = 0; i < 3; i++) { pUsDevmodeMark[i].bPruned = 0; pUsDevmodeMark[i].pDevMode = &pUsDevmode[i]; }
//
// Write the name of the fullscreen device in the registry.
//
RtlInitUnicodeString(&DeviceName, gFullscreenGraphicsDevice.szNtDeviceName);
RtlWriteRegistryValue(RTL_REGISTRY_DEVICEMAP, L"Video", L"VgaCompatible", REG_SZ, DeviceName.Buffer, DeviceName.Length + sizeof(UNICODE_NULL));
//
// Now create the FE fullscreen device.
//
RtlInitUnicodeString(&DeviceName, DD_FULLSCREEN_VIDEO_DEVICE_NAME);
Status = IoGetDeviceObjectPointer(&DeviceName, (ACCESS_MASK) (0), (PFILE_OBJECT *) &pFileObject, (PDEVICE_OBJECT *) &pDeviceHandle);
if (NT_SUCCESS(Status)) { gFeFullscreenGraphicsDevice.hkClassDriverConfig = 0; gFeFullscreenGraphicsDevice.pDeviceHandle = pDeviceHandle;
RtlCopyMemory(&gFeFullscreenGraphicsDevice, DD_FULLSCREEN_VIDEO_DEVICE_NAME, sizeof(DD_FULLSCREEN_VIDEO_DEVICE_NAME)); } }
//
// Make VGA the head of list, so that VGA always get processed first upon mode change
// And make it "\\.\Display1" for compatibility purpose
//
if (PhysDispMarkVga != gpGraphicsDeviceList) { for (PhysDispTmp = gpGraphicsDeviceList; PhysDispTmp != NULL; PhysDispTmp = PhysDispTmp->pNextGraphicsDevice) { if (PhysDispTmp->pNextGraphicsDevice == PhysDispMarkVga) { break; } }
ASSERTGDI (PhysDispTmp != NULL, "VGA device should alway be in gpGraphicsDeviceList chain\n");
PhysDispTmp->pNextGraphicsDevice = PhysDispMarkVga->pNextGraphicsDevice; PhysDispMarkVga->pNextGraphicsDevice = gpGraphicsDeviceList; gpGraphicsDeviceList = PhysDispMarkVga; if (gpGraphicsDeviceListLast == PhysDispMarkVga) gpGraphicsDeviceListLast = PhysDispTmp;
} if (wcscmp(gpGraphicsDeviceList->szWinDeviceName, L"\\\\.\\DISPLAY1") != 0) { for (PhysDispTmp = gpGraphicsDeviceList; PhysDispTmp != NULL; PhysDispTmp = PhysDispTmp->pNextGraphicsDevice) { if (wcscmp(PhysDispTmp->szWinDeviceName, L"\\\\.\\DISPLAY1") == 0) { wcscpy(PhysDispTmp->szWinDeviceName, gpGraphicsDeviceList->szWinDeviceName); } } wcscpy(gpGraphicsDeviceList->szWinDeviceName, L"\\\\.\\DISPLAY1"); }
return PhysDispMarkVga; }
#ifdef IOCTL_VIDEO_USE_DEVICE_IN_SESSION
BOOL bSetDeviceSessionUsage( PGRAPHICS_DEVICE PhysDisp, BOOL bEnable ) { GDIFunctionID(bSetDeviceSessionUsage);
ASSERTGDI(PhysDisp != NULL, "NULL Graphics Device\n");
BOOL bRet;
// Virtual devices (meta, mirror, remote, and disconnect) have the
// capability of being used in multiple sessions since there is no
// physical device.
// NOTE: What are the implications for mirroring drivers?
if (PhysDisp != (PGRAPHICS_DEVICE) DDML_DRIVER && !(PhysDisp->stateFlags & (DISPLAY_DEVICE_MIRRORING_DRIVER | DISPLAY_DEVICE_REMOTE | DISPLAY_DEVICE_DISCONNECT))) { NTSTATUS Status; DWORD dwBytesReturned; VIDEO_DEVICE_SESSION_STATUS vdSessionStatus = { bEnable, FALSE };
ASSERTGDI(PhysDisp->pDeviceHandle != NULL, "Physical device has NULL handle.");
Status = GreDeviceIoControl(PhysDisp->pDeviceHandle, IOCTL_VIDEO_USE_DEVICE_IN_SESSION, &vdSessionStatus, sizeof(vdSessionStatus), &vdSessionStatus, sizeof(vdSessionStatus), &dwBytesReturned);
if (NT_SUCCESS(Status)) { if (!vdSessionStatus.bSuccess) { if (bEnable) { DbgPrint("Trying to enable physical device already in use.\n"); } else { DbgPrint("Trying to disable physical device not enabled in this session.\n"); } }
bRet = vdSessionStatus.bSuccess; } else { WARNING("IOCTL_VIDEO_USE_DEVICE_IN_SESSION requested failed."); bRet = TRUE; } } else { bRet = TRUE; }
return bRet; }
#endif IOCTL_VIDEO_USE_DEVICE_IN_SESSION
extern "C" VOID CloseLocalGraphicsDevices() {
PGRAPHICS_DEVICE PhysDisp = NULL;
TRACE_INIT(("CloseLocalGraphicsDevices\n"));
if (gpLocalGraphicsDeviceList == NULL) { TRACE_INIT(("CloseLocalGraphicsDevices - gpLocalGraphicsDeviceList is not st yet\n")); return; }
for (PhysDisp = gpLocalGraphicsDeviceList; PhysDisp != NULL; PhysDisp = PhysDisp->pNextGraphicsDevice) { if (PhysDisp->pFileObject != NULL) { TRACE_INIT(("CloseLocalGraphicsDevices, Closing : %ws\n", PhysDisp->szNtDeviceName)); ObDereferenceObject(PhysDisp->pFileObject); PhysDisp->pDeviceHandle = NULL; PhysDisp->pFileObject = NULL; }
}
// If there is a separate VGA device close it too
if ( (gPhysDispVGA != NULL) && (gPhysDispVGA->pFileObject != NULL) ) { ObDereferenceObject(gPhysDispVGA->pFileObject); gPhysDispVGA->pDeviceHandle = NULL; gPhysDispVGA->pFileObject = NULL; } }
extern "C" VOID OpenLocalGraphicsDevices() {
UNICODE_STRING DeviceName; PGRAPHICS_DEVICE PhysDisp = NULL; NTSTATUS status; BOOL bVgaDeviceInList = FALSE;
TRACE_INIT(("OpenLocalGraphicsDevices\n"));
if (gpLocalGraphicsDeviceList == NULL) { TRACE_INIT(("OpenLocalGraphicsDevices - gpLocalGraphicsDeviceList is not st yet\n")); return; }
for (PhysDisp = gpLocalGraphicsDeviceList; PhysDisp != NULL; PhysDisp = PhysDisp->pNextGraphicsDevice) { if (PhysDisp->pFileObject == NULL) {
TRACE_INIT(("OpenLocalGraphicsDevices opening : %ws\n", PhysDisp->szNtDeviceName)); RtlInitUnicodeString(&DeviceName, PhysDisp->szNtDeviceName); status = IoGetDeviceObjectPointer(&DeviceName, (ACCESS_MASK) (0), (PFILE_OBJECT *) &PhysDisp->pFileObject, (PDEVICE_OBJECT *)&PhysDisp->pDeviceHandle); if (PhysDisp == gPhysDispVGA ) { bVgaDeviceInList = TRUE; } if (!NT_SUCCESS(status)) { TRACE_INIT(("OpenLocalGraphicsDevices failed with status %0x\n", status)); } else{ TRACE_INIT(("OpenLocalGraphicsDevices OK\n")); } }
}
// If there is a separate VGA device, Open it too
if (!bVgaDeviceInList && (gPhysDispVGA != NULL)) { RtlInitUnicodeString(&DeviceName, gPhysDispVGA->szNtDeviceName); status = IoGetDeviceObjectPointer(&DeviceName, (ACCESS_MASK) (0), (PFILE_OBJECT *) &gPhysDispVGA->pFileObject, (PDEVICE_OBJECT *)&gPhysDispVGA->pDeviceHandle); if (!NT_SUCCESS(status)) { TRACE_INIT(("OpenLocalGraphicsDevices failed to ope VGA device with status %0x\n", status)); } else{ TRACE_INIT(("OpenLocalGraphicsDevices, open VGA device OK\n")); } } }
extern "C" BOOL DrvSetGraphicsDevices(PWSTR pDisplayDriverName) {
BOOL bLocal;
if (gProtocolType == PROTOCOL_CONSOLE) { bLocal = TRUE; } else { bLocal = FALSE; } wcscpy(G_DisplayDriverNames, pDisplayDriverName);
return (DrvUpdateGraphicsDeviceList(TRUE,FALSE,bLocal));
}
/**************************************************************************\
* DrvUpdateGraphicsDeviceList * * Update the list of devices in the PhysDisp linked list. * * This function return TRUE for SUCCESS * If the functions returns FALSE, the it means the active HDEV should be * disabled, and we should get called back With the parameter being set to TRUE. * * 09-Oct-1996 andreva created * Updates the local graphics device list or the remote graphics device list. * This function is called on InitVideo but also by xxxRemoteReconnect since * At reconnect the list may change ( case of reconnecting a session with a * client from a different protocol or case of reconnecting the console session * to a remote client or reconnecting an inialy remote session to the local * console video. \**************************************************************************/
BOOL DrvUpdateGraphicsDeviceList( BOOL bDefaultDisplayDisabled, BOOL bReenumerationNeeded, BOOL bLocal) { ULONG deviceNumber = 0; BOOL newDevice = FALSE; WCHAR devName[32]; UNICODE_STRING DeviceName; PDEVICE_OBJECT pDeviceHandle = NULL; PVOID pFileObject;
PWSTR *SymbolicLinkList; BOOL bGotMonitorPdos; PDEVICE_RELATIONS pDeviceRelations;
NTSTATUS status; PGRAPHICS_DEVICE PhysDisp = NULL; HANDLE hkRegistry = NULL;
VIDEO_WIN32K_CALLBACKS videoCallback; ULONG bytesReturned; BOOL bReturn = TRUE;
TRACE_INIT(("Drv_Trace: DrvUpdateGraphicsDeviceList: Enter\n"));
//
// ISSUE - we don't handle deletions !!!
//
//
// If the maximum value has increased for video device objects, then
// go open the new ones.
//
if ( bLocal ) { gcNextGlobalDeviceNumber = gcLocalNextGlobalDeviceNumber; gpGraphicsDeviceList = gpLocalGraphicsDeviceList; gpGraphicsDeviceListLast =gpLocalGraphicsDeviceListLast; gcNextGlobalPhysicalOutputNumber = gcLocalNextGlobalPhysicalOutputNumber; gcNextGlobalVirtualOutputNumber = gcLocalNextGlobalVirtualOutputNumber; ULONG defaultValue = 0;
RTL_QUERY_REGISTRY_TABLE QueryTable[] = { {NULL, RTL_QUERY_REGISTRY_DIRECT, L"MaxObjectNumber", &deviceNumber, REG_DWORD, &defaultValue, 4}, {NULL, 0, NULL} };
RtlQueryRegistryValues(RTL_REGISTRY_DEVICEMAP, L"VIDEO", &QueryTable[0], NULL, NULL); } else{ gcNextGlobalDeviceNumber = gcRemoteNextGlobalDeviceNumber; gpGraphicsDeviceList = gpRemoteGraphicsDeviceList; gpGraphicsDeviceListLast =gpRemoteGraphicsDeviceListLast; gcNextGlobalPhysicalOutputNumber = gcRemoteNextGlobalPhysicalOutputNumber; gcNextGlobalVirtualOutputNumber = gcRemoteNextGlobalVirtualOutputNumber;
//
// If we don't yet have this protocol in our remote device list,
// Set deviceNumber in a way that we'll iterate once to create
// a GRAPHICS_DEVICE for it, otherwise set to zero so that we don't
// create a new GRAPHICS_DEVICE.
//
if (gProtocolType != PROTOCOL_DISCONNECT && !DrvIsProtocolAlreadyKnown()) { deviceNumber = gcRemoteNextGlobalDeviceNumber; } }
// IoGetDeviceInterfaces(GUID_DISPLAY_INTERFACE_STANDARD,
// NULL,
// 0,
// &SymbolicLinkList);
while (gProtocolType != PROTOCOL_DISCONNECT && gcNextGlobalDeviceNumber <= deviceNumber) { TRACE_INIT(("Drv_Trace:DrvUpdateGraphicsDeviceList: Device %d\n", gcNextGlobalDeviceNumber));
if (bDefaultDisplayDisabled == FALSE) {
TRACE_INIT(("Drv_Trace:DrvUpdateGraphicsDeviceList: Exit RETRY\n\n"));
return FALSE; }
newDevice = TRUE;
swprintf(devName, L"\\Device\\Video%d", gcNextGlobalDeviceNumber);
RtlInitUnicodeString(&DeviceName, devName);
TRACE_INIT(("Drv_Trace: \tNewDevice: Try creating device %ws\n", devName));
if ( !bLocal ) { //
// FOR HYDRA
//
pFileObject = (PFILE_OBJECT)G_RemoteVideoFileObject; pDeviceHandle = IoGetRelatedDeviceObject ((PFILE_OBJECT)pFileObject);
if (pDeviceHandle) { status = STATUS_SUCCESS; } else { status = STATUS_OBJECT_NAME_NOT_FOUND; } //deviceNumber = 0; //Only one display driver for remote sessions
} else { //
// Opening a new device will cause the Initialize
// routine of a miniport driver to be called.
// This may cause the driver to change some state, which could
// affect the state of another driver on the same device
// (opening the weitek driver if the vga is running.
//
// For that reason, the other device should be temporarily
// closed down when we do the create, and then reinitialized
// afterwards.
//
// Handle special case when we are opening initial device and
// gpDispInfo->hDev does not exist yet.
//
status = IoGetDeviceObjectPointer(&DeviceName, (ACCESS_MASK) (0), (PFILE_OBJECT *) &pFileObject, &pDeviceHandle); }
//
// if we got a configuration error from the device (HwInitialize
// routine failed, then just go on to the next device.
//
if (!NT_SUCCESS(status)) { TRACE_INIT(("Drv_Trace: \tNewDevice: No such device - Status is %0x\n",status));
//
// For remote devices, we don't want to increment the Next device number
// if we are not creating the device. The reason is that remote devices
// do not have a fixed number and we want to use a device number only
// if we are really creating a remote device for it.
if (bLocal) { gcNextGlobalDeviceNumber++; continue; } break; }
//
// Allocate a buffer if necessary:
//
if (PhysDisp == NULL) { PhysDisp = (PGRAPHICS_DEVICE) PALLOCMEM(sizeof(GRAPHICS_DEVICE), GDITAG_GDEVICE); }
if (PhysDisp) { PhysDisp->numMonitorDevice = 0; PhysDisp->MonitorDevices = NULL; PhysDisp->pDeviceHandle = (HANDLE) pDeviceHandle; PhysDisp->ProtocolType = gProtocolType; if (!bLocal) { PhysDisp->stateFlags |= DISPLAY_DEVICE_REMOTE; }
if (bLocal) { PhysDisp->pFileObject = pFileObject; } else { PhysDisp->pFileObject = NULL; }
bGotMonitorPdos = FALSE;
if (bLocal) { //
// Tell the video port driver about us so we can
// do power management notifucations
//
RtlZeroMemory(&videoCallback, sizeof(VIDEO_WIN32K_CALLBACKS)); videoCallback.PhysDisp = PhysDisp; videoCallback.Callout = VideoPortCallout;
status = GreDeviceIoControl(PhysDisp->pDeviceHandle, IOCTL_VIDEO_INIT_WIN32K_CALLBACKS, &videoCallback, sizeof(VIDEO_WIN32K_CALLBACKS), &videoCallback, sizeof(VIDEO_WIN32K_CALLBACKS), &bytesReturned);
if (videoCallback.bACPI) { PhysDisp->stateFlags |= DISPLAY_DEVICE_ACPI; } if (videoCallback.DualviewFlags & VIDEO_DUALVIEW_REMOVABLE) { PhysDisp->stateFlags |= DISPLAY_DEVICE_REMOVABLE; } if (videoCallback.DualviewFlags & (VIDEO_DUALVIEW_PRIMARY | VIDEO_DUALVIEW_SECONDARY)) { PhysDisp->stateFlags |= DISPLAY_DEVICE_DUALVIEW; }
PhysDisp->pPhysDeviceHandle = videoCallback.pPhysDeviceObject;
ASSERT(NT_SUCCESS(status)); }
//
// For a PnP Driver, get the PDO so we can enumerate the monitors
//
status = DrvSendPnPIrp(pDeviceHandle, TargetDeviceRelation, &pDeviceRelations);
if (NT_SUCCESS(status)) { PDEVICE_OBJECT pdoVideoChip = pDeviceRelations->Objects[0]; PDEVICE_OBJECT pdoChild; PDEVICE_OBJECT *pActivePdos, *pPdos; ULONG_PTR cCount = 0; ULONG i; WCHAR className[8]; NTSTATUS status2;
ASSERTGDI(pDeviceRelations->Count == 1, "TargetDeviceRelation should only get one PDO\n");
//
// Note: free with ExFreePool rather than GdiFreePool
// because pDeviceRelations is allocated by IoAllocateIrp
// (ntos\io\iosubs.c) in DrvSendPnPIrp.
//
ExFreePool(pDeviceRelations);
//
// In 5.0, the driver configuration data is stored under
// Class\GUID\xxx
//
TRACE_INIT(("Drv_Trace: \tNewDevice: Get device Configuration from Class Key\n"));
status = IoOpenDeviceRegistryKey(pdoVideoChip, PLUGPLAY_REGKEY_DRIVER, MAXIMUM_ALLOWED, &hkRegistry);
if (NT_SUCCESS(status)) { PVIDEO_MONITOR_DEVICE pMonitorDevices = NULL; ULONG numMonitorDevice = 0;
//
// Force all the monitors on this device to be enumerated.
//
if (bReenumerationNeeded) { IoSynchronousInvalidateDeviceRelations(pdoVideoChip, BusRelations); }
if (NT_SUCCESS(GreDeviceIoControl(pDeviceHandle, IOCTL_VIDEO_ENUM_MONITOR_PDO, NULL, 0, &pMonitorDevices, sizeof(PVOID), &bytesReturned)) && pMonitorDevices != NULL) { bGotMonitorPdos = TRUE;
//
// Get the number of PDOs
//
numMonitorDevice = 0; while (pMonitorDevices[numMonitorDevice].pdo != NULL) { ObDereferenceObject(pMonitorDevices[numMonitorDevice].pdo); numMonitorDevice++; } }
//
// Create the standard graphics device
//
TRACE_INIT(("Drv_Trace: \tNewDevice: Get display Configuration from Class Key\n"));
DrvGetDeviceConfigurationInformation(PhysDisp, hkRegistry, TRUE);
//
// Per Monitor Settings
//
if (bGotMonitorPdos && numMonitorDevice) { PhysDisp->numMonitorDevice = numMonitorDevice; PhysDisp->MonitorDevices = (PVIDEO_MONITOR_DEVICE) PALLOCMEM(sizeof(VIDEO_MONITOR_DEVICE) * numMonitorDevice, GDITAG_GDEVICE); for (cCount = 0; cCount < numMonitorDevice; cCount++) { PhysDisp->MonitorDevices[cCount].flag = 0; if (pMonitorDevices[cCount].flag & VIDEO_CHILD_ACTIVE) { PhysDisp->MonitorDevices[cCount].flag |= DISPLAY_DEVICE_ACTIVE; } if ((pMonitorDevices[cCount].flag & VIDEO_CHILD_DETACHED) == 0) { PhysDisp->MonitorDevices[cCount].flag |= DISPLAY_DEVICE_ATTACHED; } if ((pMonitorDevices[cCount].flag & VIDEO_CHILD_NOPRUNE_FREQ) == 0) { PhysDisp->MonitorDevices[cCount].flag |= DISPLAY_DEVICE_PRUNE_FREQ; } if ((pMonitorDevices[cCount].flag & VIDEO_CHILD_NOPRUNE_RESOLUTION) == 0) { PhysDisp->MonitorDevices[cCount].flag |= DISPLAY_DEVICE_PRUNE_RESOLUTION; } PhysDisp->MonitorDevices[cCount].pdo = pMonitorDevices[cCount].pdo; PhysDisp->MonitorDevices[cCount].HwID = pMonitorDevices[cCount].HwID; } }
if (bGotMonitorPdos) { ExFreePool(pMonitorDevices); }
ZwCloseKey(hkRegistry); }
ObDereferenceObject(pdoVideoChip); } else if ((PhysDisp->stateFlags & DISPLAY_DEVICE_DUALVIEW) && PhysDisp->pPhysDeviceHandle ) { //
// For Dualview secondary, there is no real PDO
//
status = IoOpenDeviceRegistryKey((PDEVICE_OBJECT)PhysDisp->pPhysDeviceHandle, PLUGPLAY_REGKEY_DRIVER, MAXIMUM_ALLOWED, &hkRegistry); if (NT_SUCCESS(status)) { DrvGetDeviceConfigurationInformation(PhysDisp, hkRegistry, TRUE); ZwCloseKey(hkRegistry); } }
//
// Do this here as this field must be initialized for the next
// function call.
//
swprintf(&(PhysDisp->szNtDeviceName[0]), L"\\Device\\Video%d", gcNextGlobalDeviceNumber++);
//
// If the software key information could not be obtained,
// try the legacy location
// In 4.0, the driver configuration data was located in
// <services>\DeviceX
//
if (!NT_SUCCESS(status)) { TRACE_INIT(("Drv_Trace: \tNewDevice: Failed to get PDO device Configuration info\n"));
hkRegistry = DrvGetRegistryHandleFromDeviceMap( PhysDisp, DispDriverRegGlobal, NULL, NULL, &status, gProtocolType);
//
// Start at entry 2 in the list because we want to skip the
// subdirectory
//
if (NT_SUCCESS(status)) { DrvGetDeviceConfigurationInformation(PhysDisp, hkRegistry, FALSE); ZwCloseKey(hkRegistry); } }
//
// VGA driver and other old, MS detected drivers may have no
// description string. Add *something*.
//
if ((NT_SUCCESS(status)) && (PhysDisp->DeviceDescription == NULL)) { if (PhysDisp->DeviceDescription = (LPWSTR) PALLOCNOZ(32, GDITAG_DRVSUP)) { hkRegistry = DrvGetRegistryHandleFromDeviceMap( PhysDisp, DispDriverRegGlobal, NULL, PhysDisp->DeviceDescription, &status, gProtocolType); if (hkRegistry) { ZwCloseKey(hkRegistry); } } else { status = STATUS_INSUFFICIENT_RESOURCES; } }
if (PhysDisp->DeviceDescription == NULL) { WARNING("\nDisplay Device Description is NULL!\n"); }
//
// If the device exists, keep it open and try the next one.
// Here we give Mirroring driver different names. Many applications assumes
// "\\.\Display1" as their primary display. But sometimes, mirroring driver
// gets loaded first, thus makes the assumption go complete bogus.
//
if (PhysDisp->stateFlags & DISPLAY_DEVICE_MIRRORING_DRIVER) { swprintf(&(PhysDisp->szWinDeviceName[0]), L"\\\\.\\DISPLAYV%d", gcNextGlobalVirtualOutputNumber++); } else { swprintf(&(PhysDisp->szWinDeviceName[0]), L"\\\\.\\DISPLAY%d", gcNextGlobalPhysicalOutputNumber++); }
//
// Link the new device at the end so we can enumerate
// in the right order. For remote devices, link the
// device to the list only if everything worked fine.
//
if (bLocal || NT_SUCCESS(status)) { if (gpGraphicsDeviceList == NULL) { gpGraphicsDeviceList = PhysDisp; gpGraphicsDeviceListLast = PhysDisp; } else { gpGraphicsDeviceListLast->pNextGraphicsDevice = PhysDisp; gpGraphicsDeviceListLast = PhysDisp; } //
// We have successfully installed a GRAPHICS_DEVICE for a new
// remote protocol : increment known protocols count.
//
if (!bLocal) { gcRemoteNextGlobalDeviceNumber++; } } else { DrvCleanupOneGraphicsDevice(PhysDisp); gcNextGlobalPhysicalOutputNumber--; PhysDisp = NULL; bReturn = FALSE; }
PhysDisp = NULL; } }
//
// Update the VGA device on the console.
//
if (bLocal && newDevice) { PGRAPHICS_DEVICE PhysDispVGA = DrvUpdateVgaDevice();
if (gbBaseVideo) { DrvSetSingleDisplay(PhysDispVGA); } }
// Create the entry for the Disconnect graphics device
if (DrvSetDisconnectedGraphicsDevice(bLocal)) { TRACE_INIT(("DrvSetDisconnectedGraphicsDevice succeeded!\n")); } else{ TRACE_INIT(("DrvSetDisconnectedGraphicsDevice Failed!\n")); }
// write any change back to device lists
if ( bLocal ) { gcLocalNextGlobalDeviceNumber = gcNextGlobalDeviceNumber; gpLocalGraphicsDeviceList = gpGraphicsDeviceList; gpLocalGraphicsDeviceListLast = gpGraphicsDeviceListLast; gcLocalNextGlobalPhysicalOutputNumber = gcNextGlobalPhysicalOutputNumber; gcLocalNextGlobalVirtualOutputNumber = gcNextGlobalVirtualOutputNumber; } else{ //gcRemoteNextGlobalDeviceNumber = gcNextGlobalDeviceNumber;
gpRemoteGraphicsDeviceList = gpGraphicsDeviceList; gpRemoteGraphicsDeviceListLast = gpGraphicsDeviceListLast; gcRemoteNextGlobalPhysicalOutputNumber = gcNextGlobalPhysicalOutputNumber; gcRemoteNextGlobalVirtualOutputNumber = gcNextGlobalVirtualOutputNumber; }
TRACE_INIT(("DrvUpdateGraphicsDeviceList - gpGraphicsDeviceList : %x\n",gpGraphicsDeviceList)); TRACE_INIT(("DrvUpdateGraphicsDeviceList - gpLocalGraphicsDeviceList : %x\n",gpLocalGraphicsDeviceList)); TRACE_INIT(("DrvUpdateGraphicsDeviceList - gpRemoteGraphicsDeviceList : %x\n",gpRemoteGraphicsDeviceList)); TRACE_INIT(("Drv_Trace:DrvUpdateGraphicsDeviceList: Exit\n\n"));
return bReturn; }
/***************************************************************************\
* DrvSetDisconnectedGraphicsDevice * Creates an Entry for the disconnect grapgics device (either for the local * or for the remote list. \***************************************************************************/ BOOL DrvSetDisconnectedGraphicsDevice( BOOL bLocal) { const WCHAR DisconnectDeviceName[] = L"\\Device\\Disc"; NTSTATUS status; PGRAPHICS_DEVICE PhysDisp = NULL; HANDLE hkRegistry = NULL; BOOL bReturn = FALSE;
TRACE_INIT(("Drv_Trace:DrvSetDisconnectedGraphicsDevice: \n"));
if ((bLocal && gpLocalDiscGraphicsDevice != NULL ) || (!bLocal && gpRemoteDiscGraphicsDevice != NULL)) { TRACE_INIT(("DrvSetDisconnectedGraphicsDevice - Device already set")); return TRUE; }
//
// Allocate a buffer .
//
PhysDisp = (PGRAPHICS_DEVICE) PALLOCMEM(sizeof(GRAPHICS_DEVICE), GDITAG_GDEVICE); if (PhysDisp) { UNICODE_STRING DeviceName;
//
// Assign NtDeviceName as "\\Device\\Disc".
// This has to be have an entry in DEVICEMAP\Video
//
RtlInitUnicodeString(&DeviceName, L"\\REGISTRY\\Machine\\System\\CurrentControlSet\\Services\\TSDDD\\Device0"); RtlWriteRegistryValue(RTL_REGISTRY_DEVICEMAP, L"VIDEO", DisconnectDeviceName, REG_SZ, DeviceName.Buffer, DeviceName.Length + sizeof(UNICODE_NULL));
RtlCopyMemory(&(PhysDisp->szNtDeviceName[0]), DisconnectDeviceName, sizeof(DisconnectDeviceName));
PhysDisp->numMonitorDevice = 0; PhysDisp->MonitorDevices = NULL; PhysDisp->stateFlags |= DISPLAY_DEVICE_DISCONNECT; PhysDisp->ProtocolType = PROTOCOL_DISCONNECT;
// Read device Configuration from registry
hkRegistry = DrvGetRegistryHandleFromDeviceMap( PhysDisp, DispDriverRegGlobal, NULL, NULL, &status, PROTOCOL_DISCONNECT);
if (NT_SUCCESS(status)) { DrvGetDeviceConfigurationInformation(PhysDisp, hkRegistry, FALSE); ZwCloseKey(hkRegistry); bReturn = TRUE; }
//
// If we haven't specified a device description set it to something.
//
if ((NT_SUCCESS(status)) && (PhysDisp->DeviceDescription == NULL)) { if (PhysDisp->DeviceDescription = (LPWSTR) PALLOCNOZ(32, GDITAG_DRVSUP)) { hkRegistry = DrvGetRegistryHandleFromDeviceMap(PhysDisp, DispDriverRegGlobal, NULL, PhysDisp->DeviceDescription, &status, PROTOCOL_DISCONNECT); if (hkRegistry) { ZwCloseKey(hkRegistry); } } else { status = STATUS_INSUFFICIENT_RESOURCES; } }
if (!NT_SUCCESS(status)) { if (PhysDisp->DisplayDriverNames != NULL) { VFREEMEM(PhysDisp->DisplayDriverNames); } VFREEMEM(PhysDisp); return FALSE; }
//
// Set WinDeviceName (name for extenal reference; usually \\.\DISPLAY#)
//
swprintf(&(PhysDisp->szWinDeviceName[0]),L"WinDisc");
PhysDisp->pDeviceHandle = (HANDLE) NULL;
//
// Link the new device at the end so we can enumerate
// in the right order.
//
if (gpGraphicsDeviceList == NULL) { gpGraphicsDeviceList = PhysDisp; gpGraphicsDeviceListLast = PhysDisp; } else { gpGraphicsDeviceListLast->pNextGraphicsDevice = PhysDisp; gpGraphicsDeviceListLast = PhysDisp; }
if (bLocal) { gpLocalDiscGraphicsDevice = PhysDisp; } else { gpRemoteDiscGraphicsDevice = PhysDisp; } }
return bReturn; }
/***************************************************************************\
* DrvEnumDisplaySettings * * Routines that enumerate the list of modes available in the driver. * * andreva Created \***************************************************************************/
NTSTATUS DrvEnumDisplaySettings( PUNICODE_STRING pstrDeviceName, HDEV hdevPrimary, DWORD iModeNum, LPDEVMODEW lpDevMode, DWORD dwFlags) { GDIFunctionID(DrvEnumDisplaySettings);
NTSTATUS retval = STATUS_INVALID_PARAMETER_1; PGRAPHICS_DEVICE PhysDisp = NULL; USHORT DriverExtraSize;
TRACE_INIT(("Drv_Trace: DrvEnumDisplaySettings\n"));
//
// Probe the DeviceName and the DEVMODE.
//
__try { ProbeForRead(lpDevMode, sizeof(DEVMODEW), sizeof(USHORT));
DriverExtraSize = lpDevMode->dmDriverExtra;
ProbeForWrite(lpDevMode, sizeof(DEVMODEW) + DriverExtraSize, sizeof(USHORT));
if (lpDevMode->dmSize != sizeof(DEVMODEW)) { return STATUS_BUFFER_TOO_SMALL; } } __except (EXCEPTION_EXECUTE_HANDLER) { return GetExceptionCode(); }
if (pstrDeviceName) { PhysDisp = DrvGetDeviceFromName(pstrDeviceName, UserMode); } else { PDEVOBJ pdo(hdevPrimary);
if (pdo.bValid()) { PhysDisp = pdo.ppdev->pGraphicsDevice; } }
if (PhysDisp) { //
// -3 means we want the Monitor prefered DEVMODE
//
if (iModeNum == (DWORD) -3) // ENUM_MONITOR_PREFERED
{ retval = DrvGetPreferredMode(lpDevMode, PhysDisp); }
//
// -2 means we want the registry DEVMODE to do matching on the
// client side.
//
else if (iModeNum == (DWORD) -2) // ENUM_REGISTRY_SETTINGS
{ PDEVMODEW pdevmode;
TRACE_INIT(("DrvEnumDisp: -2 mode\n"));
pdevmode = (PDEVMODEW) PALLOCMEM(sizeof(DEVMODEW) + MAXUSHORT, GDITAG_DEVMODE);
if (pdevmode) { pdevmode->dmSize = 0xDDDD; pdevmode->dmDriverExtra = MAXUSHORT;
retval = DrvGetDisplayDriverParameters(PhysDisp, pdevmode, FALSE, FALSE);
if (NT_SUCCESS(retval)) { __try { DriverExtraSize = min(DriverExtraSize, pdevmode->dmDriverExtra);
RtlCopyMemory(lpDevMode + 1, pdevmode + 1, DriverExtraSize);
RtlCopyMemory(lpDevMode, pdevmode, sizeof(DEVMODEW));
} __except(EXCEPTION_EXECUTE_HANDLER) { retval = STATUS_INVALID_PARAMETER_3; } } VFREEMEM(pdevmode); }
} //
// -1 means returns the current device mode.
// We store the full DEVMODE in the
//
else if (iModeNum == (DWORD) -1) // ENUM_CURRENT_SETTINGS
{ PPDEV ppdev;
TRACE_INIT(("DrvEnumDisp: -1 mode\n"));
//
// Since we are accessing variable fields off of this device,
// acquire the lock for them.
//
GreAcquireSemaphoreEx(ghsemDriverMgmt, SEMORDER_DRIVERMGMT, NULL);
//
// Find the currently adtive PDEV on this device.
//
for (ppdev = gppdevList; ppdev != NULL; ppdev = ppdev->ppdevNext) { PDEVOBJ po((HDEV) ppdev);
//
// Also need to check VGA(alias) device
//
if (((po.ppdev->pGraphicsDevice == PhysDisp) || ((po.ppdev->pGraphicsDevice == PhysDisp->pVgaDevice) && (po.ppdev->pGraphicsDevice != NULL))) && (!po.bDeleted())) { __try { DriverExtraSize = min(DriverExtraSize, po.ppdev->ppdevDevmode->dmDriverExtra);
//
// We know the DEVMODE we called the driver with is of
// size sizeof(DEVMODEW)
//
RtlCopyMemory(lpDevMode + 1, po.ppdev->ppdevDevmode + 1, DriverExtraSize);
RtlCopyMemory(lpDevMode, po.ppdev->ppdevDevmode, sizeof(DEVMODEW));
retval = STATUS_SUCCESS;
} __except(EXCEPTION_EXECUTE_HANDLER) { retval = STATUS_INVALID_PARAMETER_3; }
break; } }
GreReleaseSemaphoreEx(ghsemDriverMgmt); } else { //
// We don't need synchronize access to the list of modes.
// Who cares.
//
DrvBuildDevmodeList(PhysDisp, FALSE);
//
// now return the information
//
if ( (PhysDisp->cbdevmodeInfo == 0) || (PhysDisp->devmodeInfo == NULL) ) { WARNING("EnumDisplaySettings PhysDisp is inconsistent\n"); retval = STATUS_UNSUCCESSFUL; } else { LPDEVMODEW lpdm = NULL; DWORD i, count;
retval = STATUS_INVALID_PARAMETER_2;
if (iModeNum < PhysDisp->numRawModes) { if (dwFlags & EDS_RAWMODE) lpdm = PhysDisp->devmodeMarks[iModeNum].pDevMode; else { for (i = 0, count = 0; i < PhysDisp->numRawModes; i++) { if (PhysDisp->devmodeMarks[i].bPruned) continue; if (count == iModeNum) { lpdm = PhysDisp->devmodeMarks[i].pDevMode; break; } count++; } } }
if (lpdm) { __try { DriverExtraSize = min(DriverExtraSize, lpdm->dmDriverExtra);
RtlZeroMemory(lpDevMode, sizeof(*lpDevMode));
//
// Check the size since the devmode returned
// by the driver can be smaller than the current
// size.
//
RtlCopyMemory(lpDevMode + 1, ((PUCHAR)lpdm) + lpdm->dmSize, DriverExtraSize);
RtlCopyMemory(lpDevMode, lpdm, min(sizeof(DEVMODEW), lpdm->dmSize));
retval = STATUS_SUCCESS; } __except(EXCEPTION_EXECUTE_HANDLER) { retval = STATUS_INVALID_PARAMETER_3; } } }
//
// As an acceleration, we will only free the list if the call
// failed because "i" was too large, so that listing all the modes
// does not require building the list each time.
//
if (retval == STATUS_INVALID_PARAMETER_2) { //
// Free up the resources - as long as it's not the VGA.
// Assume the VGA is always first
//
if (PhysDisp != &gFullscreenGraphicsDevice) { PhysDisp->cbdevmodeInfo = 0;
if (PhysDisp->devmodeInfo) { VFREEMEM(PhysDisp->devmodeInfo); PhysDisp->devmodeInfo = NULL; } if (PhysDisp->devmodeMarks) { VFREEMEM(PhysDisp->devmodeMarks); PhysDisp->devmodeMarks = NULL; } PhysDisp->numRawModes = 0; } } } }
//
// Update the driver extra size
//
if (retval == STATUS_SUCCESS) { __try { lpDevMode->dmDriverExtra = DriverExtraSize; } __except (EXCEPTION_EXECUTE_HANDLER) { retval = GetExceptionCode(); } }
return (retval); }
/***************************************************************************\
* * DrvEnumDisplayDevices * * History: \***************************************************************************/
NTSTATUS DrvEnumDisplayDevices( PUNICODE_STRING pstrDeviceName, HDEV hdevPrimary, DWORD iDevNum, LPDISPLAY_DEVICEW lpDisplayDevice, DWORD dwFlags, MODE PreviousMode) { PGRAPHICS_DEVICE PhysDisp; ULONG cbSize; ULONG cCount = 0; PDEVICE_OBJECT pdo = NULL; NTSTATUS retStatus = STATUS_SUCCESS;
UNREFERENCED_PARAMETER(dwFlags); UNREFERENCED_PARAMETER(hdevPrimary);
if (pstrDeviceName == NULL) { //
// Start enumerating at 0 ...
//
for (PhysDisp = gpGraphicsDeviceList; PhysDisp != NULL; PhysDisp = PhysDisp->pNextGraphicsDevice, cCount++) { //
// Do not enumerate the disconnected DD for user mode callers.
// Also if we are not on the physical console, do not enumerate
// drivers other than current protocol driver.
//
if (PreviousMode != KernelMode) { if((PhysDisp->stateFlags & DISPLAY_DEVICE_DISCONNECT) || (gProtocolType != PROTOCOL_CONSOLE && PhysDisp->ProtocolType != gProtocolType)) { cCount--; continue; }
} if (cCount == iDevNum) break; }
if (PhysDisp == NULL) { return STATUS_UNSUCCESSFUL; }
PDEVICE_RELATIONS pDeviceRelations;
//pDeviceHandle migth be NULL in the case of the disconnected DD which
//has no associated miniport.
if (PhysDisp->pPhysDeviceHandle) { pdo = (PDEVICE_OBJECT)PhysDisp->pPhysDeviceHandle; } else if ((PDEVICE_OBJECT)PhysDisp->pDeviceHandle != NULL) { if (NT_SUCCESS(DrvSendPnPIrp((PDEVICE_OBJECT)PhysDisp->pDeviceHandle, TargetDeviceRelation, &pDeviceRelations) ) ) { pdo = pDeviceRelations->Objects[0]; ASSERTGDI(pDeviceRelations->Count == 1, "TargetDeviceRelation should only get one PDO\n");
ExFreePool(pDeviceRelations); } }else{ TRACE_INIT(("DrvEnumDisplayDevices - processing the disconnected GRAPHICS_DEVICE\n")); } } else { UpdateMonitorDevices();
PhysDisp = DrvGetDeviceFromName(pstrDeviceName, PreviousMode); if (PhysDisp == NULL) return STATUS_UNSUCCESSFUL; if (iDevNum >= PhysDisp->numMonitorDevice) return STATUS_UNSUCCESSFUL; pdo = (PDEVICE_OBJECT)PhysDisp->MonitorDevices[iDevNum].pdo; }
//
// We found the device, so the call will be successful unless
// we except later on.
//
__try { PVOID pBuffer; NTSTATUS status;
//
// Capture the input buffer length
//
TRACE_INIT(("Drv_Trace: DrvEnumDisplayDevices %d\n", iDevNum));
if (PreviousMode == UserMode) { cbSize = ProbeAndReadUlong(&(lpDisplayDevice->cb)); ProbeForWrite(lpDisplayDevice, cbSize, sizeof(DWORD)); } else { ASSERTGDI(lpDisplayDevice >= (LPDISPLAY_DEVICEW const)MM_USER_PROBE_ADDRESS, "Bad kernel mode address\n");
cbSize = lpDisplayDevice->cb; }
RtlZeroMemory(lpDisplayDevice, cbSize);
if (cbSize >= FIELD_OFFSET(DISPLAY_DEVICEW, DeviceName)) { lpDisplayDevice->cb = FIELD_OFFSET(DISPLAY_DEVICEW, DeviceName); } if (cbSize >= FIELD_OFFSET(DISPLAY_DEVICEW, DeviceString)) { lpDisplayDevice->cb = FIELD_OFFSET(DISPLAY_DEVICEW, DeviceString);
if (pstrDeviceName == NULL) RtlCopyMemory(lpDisplayDevice->DeviceName, PhysDisp->szWinDeviceName, sizeof(PhysDisp->szWinDeviceName)); else swprintf(lpDisplayDevice->DeviceName, L"%ws\\Monitor%d", PhysDisp->szWinDeviceName, iDevNum); lpDisplayDevice->DeviceName[31] = 0; } if (cbSize >= FIELD_OFFSET(DISPLAY_DEVICEW, StateFlags)) {
lpDisplayDevice->cb = FIELD_OFFSET(DISPLAY_DEVICEW, StateFlags); lpDisplayDevice->DeviceString[0] = 0;
if (pstrDeviceName == NULL) { if (PhysDisp->DeviceDescription) wcsncpy(lpDisplayDevice->DeviceString, PhysDisp->DeviceDescription, 127); } else if (pdo) { //
// Get the name for this device.
// Documentation says to try in a loop.
//
cCount = 256; while (1) { pBuffer = PALLOCNOZ(cCount, 'ddeG'); if (pBuffer == NULL) { retStatus = STATUS_INSUFFICIENT_RESOURCES; break; } status = IoGetDeviceProperty(pdo, DevicePropertyDeviceDescription, cCount, pBuffer, &cCount); if (status == STATUS_BUFFER_TOO_SMALL) { VFREEMEM(pBuffer); continue; } else if (status == STATUS_SUCCESS) { wcsncpy(lpDisplayDevice->DeviceString, (LPWSTR)pBuffer, 127); VFREEMEM(pBuffer); break; } VFREEMEM(pBuffer); break; } } lpDisplayDevice->DeviceString[127] = 0; } if (cbSize >= FIELD_OFFSET(DISPLAY_DEVICEW, DeviceID)) { lpDisplayDevice->cb = FIELD_OFFSET(DISPLAY_DEVICEW, DeviceID);
if (pstrDeviceName == NULL) lpDisplayDevice->StateFlags = PhysDisp->stateFlags & 0x0FFFFFFF; else lpDisplayDevice->StateFlags = PhysDisp->MonitorDevices[iDevNum].flag & 0x0FFFFFFF; }
if (cbSize >= FIELD_OFFSET(DISPLAY_DEVICEW, DeviceKey)) { lpDisplayDevice->cb = FIELD_OFFSET(DISPLAY_DEVICEW, DeviceKey);
lpDisplayDevice->DeviceID[0] = 0;
if (pdo) { cCount = 256; while (1) { pBuffer = PALLOCNOZ(cCount, 'ddeG'); if (pBuffer == NULL) { retStatus = STATUS_INSUFFICIENT_RESOURCES; break; }
status = IoGetDeviceProperty(pdo, DevicePropertyHardwareID, cCount, pBuffer, &cCount); if (status == STATUS_BUFFER_TOO_SMALL) { VFREEMEM(pBuffer); continue; } else if (status == STATUS_SUCCESS) { wcsncpy(lpDisplayDevice->DeviceID, (LPWSTR)pBuffer, 127); VFREEMEM(pBuffer); break; } VFREEMEM(pBuffer); break; } // For Monitor devices, we will make the ID unique.
// Applet and GDIs are expecting this behavior.
if (pstrDeviceName != NULL) { lpDisplayDevice->DeviceID[127] = 0; cCount = wcslen(lpDisplayDevice->DeviceID)+1; if (cCount < 126) { lpDisplayDevice->DeviceID[cCount-1] = L'\\'; status = IoGetDeviceProperty(pdo, DevicePropertyDriverKeyName, (127-cCount)*sizeof(WCHAR), (PBYTE)(lpDisplayDevice->DeviceID+cCount), &cCount); } } } lpDisplayDevice->DeviceID[127] = 0; } if (cbSize >= sizeof(DISPLAY_DEVICEW)) { lpDisplayDevice->cb = sizeof(DISPLAY_DEVICEW);
lpDisplayDevice->DeviceKey[0] = 0;
if (pstrDeviceName == NULL) { DrvGetRegistryHandleFromDeviceMap(PhysDisp, DispDriverRegKey, NULL, lpDisplayDevice->DeviceKey, NULL, gProtocolType); } else { NTSTATUS Status; WCHAR driverRegistryPath[127];
Status = IoGetDeviceProperty(pdo, DevicePropertyDriverKeyName, 127*sizeof(WCHAR), (PBYTE)driverRegistryPath, &cCount); if (NT_SUCCESS(Status)) { wcscpy(lpDisplayDevice->DeviceKey, REGSTR_CCS); cCount = wcslen(lpDisplayDevice->DeviceKey); wcsncpy(lpDisplayDevice->DeviceKey+cCount, L"\\Control\\Class\\", 127-cCount); cCount = wcslen(lpDisplayDevice->DeviceKey); wcsncpy(lpDisplayDevice->DeviceKey+cCount, driverRegistryPath, 127-cCount); } } lpDisplayDevice->DeviceKey[127] = 0; } } __except (EXCEPTION_EXECUTE_HANDLER) { WARNINGX(100); retStatus = STATUS_UNSUCCESSFUL; }
if (pstrDeviceName == NULL && pdo && (PhysDisp->pPhysDeviceHandle == NULL)) { ObDereferenceObject(pdo); }
return retStatus; }
/******************************Public*Routine******************************\
* DrvGetDriverAccelerationsLevel() * * Reads the driver acceleration 'filter' level from the registry. This * values determines how we let the display driver do in terms of * accelerations, where a value of 0 means full acceleration. * * 20-Aug-1998 -by- Hideyuki Nagase [hideyukn] * Lifted it from AndrewGo's code. \**************************************************************************/
#define ACCEL_REGKEY L"Acceleration.Level"
#define CAPABLE_REGKEY L"CapabilityOverride" // Driver capable override
#define ACCEL_BUFSIZE (sizeof(KEY_VALUE_FULL_INFORMATION) + sizeof(ACCEL_REGKEY) + sizeof(DWORD))
#define CAPABLE_BUFSIZE (sizeof(KEY_VALUE_FULL_INFORMATION) + sizeof(CAPABLE_REGKEY) + sizeof(DWORD))
DWORD DrvGetDriverAccelerationsLevel( PGRAPHICS_DEVICE pGraphicsDevice ) { HANDLE hkRegistry; UNICODE_STRING UnicodeString; DWORD dwReturn = DRIVER_ACCELERATIONS_INVALID; BYTE buffer[ACCEL_BUFSIZE]; ULONG Length = ACCEL_BUFSIZE; PKEY_VALUE_FULL_INFORMATION Information = (PKEY_VALUE_FULL_INFORMATION) buffer; WCHAR aszValuename[] = ACCEL_REGKEY;
if (pGraphicsDevice == (PGRAPHICS_DEVICE) DDML_DRIVER) { dwReturn = 0; }
if (dwReturn == DRIVER_ACCELERATIONS_INVALID) { //
// See adaptor specific setting first.
//
hkRegistry = DrvGetRegistryHandleFromDeviceMap( pGraphicsDevice, DispDriverRegGlobal, NULL, NULL, NULL, gProtocolType);
if (hkRegistry) { RtlInitUnicodeString(&UnicodeString, aszValuename);
if (NT_SUCCESS(ZwQueryValueKey(hkRegistry, &UnicodeString, KeyValueFullInformation, Information, Length, &Length))) { dwReturn = *(LPDWORD) ((((PUCHAR)Information) + Information->DataOffset)); }
ZwCloseKey(hkRegistry); } }
if (dwReturn == DRIVER_ACCELERATIONS_INVALID) { //
// If there is nothing specified, assume full acceleration.
//
dwReturn = DRIVER_ACCELERATIONS_FULL; } else if (dwReturn > DRIVER_ACCELERATIONS_NONE) { //
// If there is something invalid value, assume no acceleration.
//
dwReturn = DRIVER_ACCELERATIONS_NONE; }
if (G_fDoubleDpi) { //
// Always set accelerations to 'none' when operating in double-the-
// dpi mode, so that panning.cxx can create a virtual display
// larger than the actual physical display.
//
dwReturn = DRIVER_ACCELERATIONS_NONE; }
#if DBG
if (pGraphicsDevice != (PGRAPHICS_DEVICE) DDML_DRIVER) { DbgPrint("GDI: DriverAccelerationLevel on %ws is %d\n", pGraphicsDevice->szWinDeviceName, dwReturn); } #endif
return(dwReturn); }
DWORD DrvGetDriverCapableOverRide( PGRAPHICS_DEVICE pGraphicsDevice ) { HANDLE hkRegistry; UNICODE_STRING UnicodeString; DWORD dwReturn = DRIVER_CAPABLE_ALL; BYTE buffer[CAPABLE_BUFSIZE]; ULONG ulLength = CAPABLE_BUFSIZE; ULONG ulActualLength; PKEY_VALUE_FULL_INFORMATION Information = (PKEY_VALUE_FULL_INFORMATION)buffer; WCHAR aszValuename[] = CAPABLE_REGKEY;
if ( pGraphicsDevice == (PGRAPHICS_DEVICE)DDML_DRIVER ) { return DRIVER_CAPABLE_ALL; }
//
// See adaptor specific setting first.
//
hkRegistry = DrvGetRegistryHandleFromDeviceMap( pGraphicsDevice, DispDriverRegGlobal, NULL, NULL, NULL, gProtocolType);
if ( hkRegistry ) { RtlInitUnicodeString(&UnicodeString, aszValuename);
if ( NT_SUCCESS(ZwQueryValueKey(hkRegistry, &UnicodeString, KeyValueFullInformation, Information, ulLength, &ulActualLength)) ) { dwReturn = *(LPDWORD)((((PUCHAR)Information) + Information->DataOffset)); }
ZwClose(hkRegistry); }
#if DBG
if ( pGraphicsDevice != (PGRAPHICS_DEVICE) DDML_DRIVER ) { DbgPrint("GDI: DriverCapableOverride on %ws is %d\n", pGraphicsDevice->szWinDeviceName, dwReturn); } #endif
return(dwReturn); }// DrvGetDriverCapableOverRide()
VOID DrvUpdateAttachFlag(PGRAPHICS_DEVICE PhysDisp, DWORD attach) { HANDLE hkRegistry = DrvGetRegistryHandleFromDeviceMap(PhysDisp, DispDriverRegHardwareProfileCreate, NULL, NULL, NULL, gProtocolType); if (hkRegistry) { RtlWriteRegistryValue(RTL_REGISTRY_HANDLE, (PCWSTR)hkRegistry, (PWSTR)AttachedSettings[1], REG_DWORD, &attach, sizeof(DWORD)); ZwCloseKey(hkRegistry); } }
/***************************************************************************\
* * DrvEnableMDEV * * Enables a display MDEV. * * Should only be called from USER under the global CRIT * \***************************************************************************/
ULONG gtmpAssertModeFailed;
BOOL DrvEnableDisplay( HDEV hdev ) { PDEVOBJ po(hdev);
TRACE_INIT(("\nDrv_Trace: DrvEnableDisplay: Enter\n"));
ASSERTGDI(po.bValid(), "HDEV failure\n"); ASSERTGDI(po.bDisplayPDEV(), "HDEV is not a display device\n"); ASSERTGDI(po.bDisabled(), "HDEV must be disabled to call enable\n"); ASSERTGDI(po.ppdev->pGraphicsDevice, "HDEV must be on a device\n");
//
// Acquire the display locks here because we may get called from within
// ChangeDisplaySettings to enable\disable a particular device when
// creating the new HDEVs.
//
GreAcquireSemaphoreEx(ghsemShareDevLock, SEMORDER_SHAREDEVLOCK, NULL); GreAcquireSemaphoreEx(po.hsemDevLock(), SEMORDER_DEVLOCK, NULL); GreAcquireSemaphoreEx(po.hsemPointer(), SEMORDER_POINTER, po.hsemDevLock()); GreEnterMonitoredSection(po.ppdev, WD_DEVLOCK);
//
// Enable the screen
// Repeat the call until it works.
//
bSetDeviceSessionUsage(po.ppdev->pGraphicsDevice, TRUE);
gtmpAssertModeFailed = 0; while (!((*PPFNDRV(po,AssertMode))(po.dhpdev(), TRUE))) { gtmpAssertModeFailed = 1; }
//
// Clear the PDEV for use
//
po.bDisabled(FALSE);
GreExitMonitoredSection(po.ppdev, WD_DEVLOCK); GreReleaseSemaphoreEx(po.hsemPointer()); GreReleaseSemaphoreEx(po.hsemDevLock()); GreReleaseSemaphoreEx(ghsemShareDevLock);
//
// Allow DirectDraw to be reenabled.
//
GreResumeDirectDraw(hdev, FALSE);
TRACE_INIT(("Drv_Trace: DrvEnableDisplay: Leave\n"));
return TRUE; }
BOOL DrvEnableMDEV( PMDEV pmdev, BOOL bHardware ) { GDIFunctionID(DrvEnableMDEV);
ULONG i; ERESOURCE_THREAD lockOwner;
TRACE_INIT(("\nDrv_Trace: DrvEnableMDEV: Enter\n"));
PDEVOBJ poParent(pmdev->hdevParent);
#if MDEV_STACK_TRACE_LENGTH
LONG lMDEVTraceEntry, lMDEVTraceEntryNext; ULONG StackEntries, UserStackEntry;
do { lMDEVTraceEntry = glMDEVTrace; lMDEVTraceEntryNext = lMDEVTraceEntry + 1; if (lMDEVTraceEntryNext >= gcMDEVTraceLength) lMDEVTraceEntryNext = 0; } while (InterlockedCompareExchange(&glMDEVTrace, lMDEVTraceEntryNext, lMDEVTraceEntry) != lMDEVTraceEntry);
RtlZeroMemory(&gMDEVTrace[lMDEVTraceEntry], sizeof(gMDEVTrace[lMDEVTraceEntry])); gMDEVTrace[lMDEVTraceEntry].pMDEV = pmdev; gMDEVTrace[lMDEVTraceEntry].API = ((bHardware) ? DrvEnableMDEV_HWOn : DrvEnableMDEV_FromGRE); StackEntries = sizeof(gMDEVTrace[lMDEVTraceEntry].Trace)/sizeof(gMDEVTrace[lMDEVTraceEntry].Trace[0]); UserStackEntry = RtlWalkFrameChain((PVOID *)gMDEVTrace[lMDEVTraceEntry].Trace, StackEntries, 0); StackEntries -= UserStackEntry; RtlWalkFrameChain((PVOID *)&gMDEVTrace[lMDEVTraceEntry].Trace[UserStackEntry], StackEntries, 1); #endif
for (i = 0; i < pmdev->chdev; i++) { PDEVOBJ po(pmdev->Dev[i].hdev); if (bHardware || ((po.ppdev->pGraphicsDevice->stateFlags & DISPLAY_DEVICE_DUALVIEW) && gbInvalidateDualView && po.bDisabled()) ) { DrvEnableDisplay(po.hdev()); } }
//
// Wait for the display to become available and unlock it.
//
GreAcquireSemaphoreEx(ghsemShareDevLock, SEMORDER_SHAREDEVLOCK, NULL); GreAcquireSemaphoreEx(poParent.hsemDevLock(), SEMORDER_DEVLOCK, NULL); GreAcquireSemaphoreEx(poParent.hsemPointer(), SEMORDER_POINTER, poParent.hsemDevLock()); GreEnterMonitoredSection(poParent.ppdev, WD_DEVLOCK);
if (bHardware) { poParent.bDisabled(FALSE); }
//
// Get the palette
//
XEPALOBJ pal(poParent.ppalSurf()); ASSERTGDI(pal.bValid(), "EPALOBJ failure\n");
if (pal.bIsPalManaged()) { ASSERTGDI(PPFNVALID(poParent,SetPalette), "ERROR palette is not managed");
(*PPFNDRV(poParent,SetPalette))(poParent.dhpdev(), (PALOBJ *) &pal, 0, 0, pal.cEntries()); } else if (pmdev->chdev > 1) { //
// Only for multi-monitor case.
//
PDEVOBJ pdoChild;
for (i = 0; i < pmdev->chdev; i++) { pdoChild.vInit(pmdev->Dev[i].hdev);
if (pdoChild.bIsPalManaged()) { XEPALOBJ palChild(pdoChild.ppalSurf());
// Don't use PPFNDRV(pdoChild,...) since need to send
// this through DDML.
pdoChild.pfnSetPalette()(pdoChild.dhpdevParent(), (PALOBJ *) &palChild, 0, 0, palChild.cEntries());
break; }
pdoChild.vInit(NULL); }
// Even if parent is not pal-managed, but any of children are palette
// managed, need to reset one of them (only 1 is enough, since
// colour table is shared across all device palette)
//
// Realize halftone palette to secondary device
if (pdoChild.bValid()) { KdPrint(("GDI DDML: Primary is not 8bpp, but one of display is 8bpp\n"));
if (!DrvRealizeHalftonePalette(pdoChild.hdev(),TRUE)) { KdPrint(("GDI DDML: Failed to realize HT palette on secondary\n")); } } }
GreExitMonitoredSection(poParent.ppdev, WD_DEVLOCK); GreReleaseSemaphoreEx(poParent.hsemPointer()); GreReleaseSemaphoreEx(poParent.hsemDevLock()); GreReleaseSemaphoreEx(ghsemShareDevLock);
if (bHardware) { //
// Allow DirectDraw to be reenabled.
//
GreResumeDirectDraw(pmdev->hdevParent, FALSE); }
TRACE_INIT(("Drv_Trace: DrvEnableMDEV: Leave\n"));
return TRUE; }
/***************************************************************************\
* * DrvDisableDisplay * * Disables a display device. * \***************************************************************************/
BOOL DrvDisableDisplay( HDEV hdev, BOOL bClear ) { GDIFunctionID(DrvDisableDisplay);
BOOL bRet; PDEVOBJ po(hdev);
TRACE_INIT(("\nDrv_Trace: DrvDisableDisplay: Enter\n"));
ASSERTGDI(po.bValid(), "HDEV failure\n"); ASSERTGDI(po.bDisplayPDEV(), "HDEV is not a display device\n"); ASSERTGDI(!po.bDisabled(), "HDEV must be enabled to call disable\n");
//
// Disable DirectDraw.
//
GreSuspendDirectDraw(hdev, FALSE);
//
// Acquire the display locks here because we may get called from within
// ChangeDisplaySettings to enable\disable a particular device when
// creating the new HDEVs.
//
GreAcquireSemaphoreEx(ghsemShareDevLock, SEMORDER_SHAREDEVLOCK, NULL); GreAcquireSemaphoreEx(po.hsemDevLock(), SEMORDER_DEVLOCK, NULL); GreAcquireSemaphoreEx(po.hsemPointer(), SEMORDER_POINTER, po.hsemDevLock()); GreEnterMonitoredSection(po.ppdev, WD_DEVLOCK);
if (bClear && !po.bDisabled()) {
PDEV *pdev = (PDEV*)hdev; ERECTL erclDst(0,0,pdev->pSurface->sizl().cx, pdev->pSurface->sizl().cy);
//
// The display is about to be disabled, but some
// display drivers don't blank the display.
// We explicitly blank the display here.
//
(*(pdev->pSurface->pfnBitBlt()))(pdev->pSurface->pSurfobj(), (SURFOBJ *) NULL, (SURFOBJ *) NULL, NULL, NULL, &erclDst, (POINTL *) NULL, (POINTL *) NULL, NULL, NULL, 0 ); }
//
// The device may have something going on, synchronize with it first
//
po.vSync(po.pSurface()->pSurfobj(), NULL, 0);
//
// Disable the screen
//
bRet = (*PPFNDRV(po,AssertMode))(po.dhpdev(), FALSE);
if (bRet) { //
// Mark the PDEV as disabled
//
bSetDeviceSessionUsage(po.ppdev->pGraphicsDevice, FALSE);
po.bDisabled(TRUE);
gtmpAssertModeFailed = 0; } else { gtmpAssertModeFailed = 1; }
GreExitMonitoredSection(po.ppdev, WD_DEVLOCK); GreReleaseSemaphoreEx(po.hsemPointer()); GreReleaseSemaphoreEx(po.hsemDevLock()); GreReleaseSemaphoreEx(ghsemShareDevLock);
if (!bRet) { //
// We have to undo our 'GreSuspendDirectDraw' call:
//
GreResumeDirectDraw(hdev, FALSE); }
TRACE_INIT(("Drv_Trace: DrvDisableDisplay: Leave\n"));
return (bRet); }
/***************************************************************************\
* * DrvDisableMDEV * * Disables a display MDEV. * * Should only be called from USER under the global CRIT * \***************************************************************************/
BOOL DrvDisableMDEV( PMDEV pmdev, BOOL bHardware ) { GDIFunctionID(DrvDisableMDEV);
BOOL bSuccess = TRUE;
#if MDEV_STACK_TRACE_LENGTH
LONG lMDEVTraceEntry, lMDEVTraceEntryNext; ULONG StackEntries, UserStackEntry;
do { lMDEVTraceEntry = glMDEVTrace; lMDEVTraceEntryNext = lMDEVTraceEntry + 1; if (lMDEVTraceEntryNext >= gcMDEVTraceLength) lMDEVTraceEntryNext = 0; } while (InterlockedCompareExchange(&glMDEVTrace, lMDEVTraceEntryNext, lMDEVTraceEntry) != lMDEVTraceEntry);
RtlZeroMemory(&gMDEVTrace[lMDEVTraceEntry], sizeof(gMDEVTrace[lMDEVTraceEntry])); gMDEVTrace[lMDEVTraceEntry].pMDEV = pmdev; gMDEVTrace[lMDEVTraceEntry].API = ((bHardware) ? DrvDisableMDEV_HWOff : DrvDisableMDEV_FromGRE); StackEntries = sizeof(gMDEVTrace[lMDEVTraceEntry].Trace)/sizeof(gMDEVTrace[lMDEVTraceEntry].Trace[0]); UserStackEntry = RtlWalkFrameChain((PVOID *)gMDEVTrace[lMDEVTraceEntry].Trace, StackEntries, 0); StackEntries -= UserStackEntry; RtlWalkFrameChain((PVOID *)&gMDEVTrace[lMDEVTraceEntry].Trace[UserStackEntry], StackEntries, 1); #endif
#if TEXTURE_DEMO
if (ghdevTextureParent) { WARNING("DrvDisableDisplay: Refused by texture demo"); return(FALSE); } #endif
TRACE_INIT(("\nDrv_Trace: DrvDisableMDEV: Enter\n"));
PDEVOBJ poParent(pmdev->hdevParent);
if (bHardware) { //
// Disable DirectDraw.
//
GreSuspendDirectDraw(pmdev->hdevParent, FALSE); }
//
// Wait for the display to become available and unlock it.
//
GreAcquireSemaphoreEx(ghsemShareDevLock, SEMORDER_SHAREDEVLOCK, NULL); GreAcquireSemaphoreEx(poParent.hsemDevLock(), SEMORDER_DEVLOCK, NULL); GreAcquireSemaphoreEx(poParent.hsemPointer(), SEMORDER_POINTER, poParent.hsemDevLock()); GreEnterMonitoredSection(poParent.ppdev, WD_DEVLOCK);
ULONG i, j;
for (i = 0; i < pmdev->chdev; i++) { //
// If Dualview, disable the view anyway
//
if (bHardware || ((((PDEV *) pmdev->Dev[i].hdev)->pGraphicsDevice->stateFlags & DISPLAY_DEVICE_DUALVIEW) && gbInvalidateDualView) ) { if ((bSuccess = DrvDisableDisplay(pmdev->Dev[i].hdev, !bHardware)) == FALSE) { break; } } }
//
// If we have a failure while disabling the device, try to reenable the
// devices that were already disabled.
//
if (bSuccess == FALSE) { for (j = 0; j < i; j++) { if (bHardware || ((((PDEV *)pmdev->Dev[i].hdev)->pGraphicsDevice->stateFlags & DISPLAY_DEVICE_DUALVIEW) && gbInvalidateDualView) ) { while (DrvEnableDisplay(pmdev->Dev[j].hdev) == FALSE) { ASSERTGDI(FALSE, "We are hosed in Disable MDEV - try again!\n"); } } } }
if (bSuccess) { if (bHardware) { poParent.bDisabled(TRUE); } }
GreExitMonitoredSection(poParent.ppdev, WD_DEVLOCK); GreReleaseSemaphoreEx(poParent.hsemPointer()); GreReleaseSemaphoreEx(poParent.hsemDevLock()); GreReleaseSemaphoreEx(ghsemShareDevLock);
if (!bSuccess) { //
// We have to undo our 'GreSuspendDirectDraw' call:
//
GreResumeDirectDraw(pmdev->hdevParent, FALSE); }
TRACE_INIT(("Drv_Trace: DrvDisableMDEV: Leave\n"));
return(bSuccess); }
/******************************************************************************
* * DrvDestroyMDEV * * Deletes a display MDEV. * \***************************************************************************/
VOID DrvDestroyMDEV( PMDEV pmdev ) { GDIFunctionID(DrvDestroyMDEV);
ULONG i;
// WinBug #306290 2-8-2001 jasonha STRESS: GDI: Two PDEVs using same semaphore as their DevLock
// WinBug #24003 7-24-2000 jasonha MULTIDISPLAY: Deadlock in DrvDestroyMDEV
// ghsemDriverManagement used to be held throughout DrvDestroyMDEV
// even when calling vUnreferencePdev, which might acquire a device
// lock. This would have been ok if the device had a unique device
// lock, but when changing from multiple displays to one display, the
// shared device lock is retained by the PDEVs no being freed. If the
// new primary display grabs the device lock and then tries to grab
// ghsemDriverMgmt as in GreCreateDisplayDC we could deadlock.
// ghsemDriverMgmt only needs to be held during accesses to cPdevOpenRefs.
TRACE_INIT(("\n\nDrv_Trace: DrvDestroyMDEV: Enter\n\n"));
for (i = 0; i < pmdev->chdev; i++) { PDEVOBJ po(pmdev->Dev[i].hdev);
// !!! What about outstanding bitmaps?
GreAcquireSemaphoreEx(ghsemDriverMgmt, SEMORDER_DRIVERMGMT, NULL);
ASSERTGDI(!po.bDeleted(), "Deleting an already-deleted PDEV");
// Decrease the OpenRefCount which will
// mark the PDEV as being deleted so that we can also stop DrvEscape
// calls from going down (ExtEscape ignores the 'bDisabled()' flag):
if (--po.ppdev->cPdevOpenRefs == 0) { // The PDEV should already be disabled.
// Otherwise, we have no way of detecting whether or not we are just
// reducing the refcount on the PDEV or not.
if (G_fConsole) { ASSERTGDI(po.bDisabled(), "Deleting an enabled PDEV"); } }
GreReleaseSemaphoreEx(ghsemDriverMgmt);
// Once all the DCs open specifically on the PDEV (if there are any)
// are destroyed, free the PDEV:
po.vUnreferencePdev(); }
// If this is multimon system, destroy parent. Otherwise
// just skip here, since parent is same as its children
// in signle monitor system.
if (pmdev->chdev > 1) { PDEVOBJ po(pmdev->hdevParent);
// !!! What about outstanding bitmaps?
GreAcquireSemaphoreEx(ghsemDriverMgmt, SEMORDER_DRIVERMGMT, NULL);
ASSERTGDI(!po.bDeleted(), "Deleting an already-deleted Parent PDEV");
// Decrease the OpenRefCount which will
// mark the PDEV as being deleted so that we can also stop DrvEscape
// calls from going down (ExtEscape ignores the 'bDisabled()' flag):
if (--po.ppdev->cPdevOpenRefs == 0) { // The PDEV should already be disabled.
// Otherwise, we have no way of detecting whether or not we are just
// reducing the refcount on the PDEV or not.
if (G_fConsole) { ASSERTGDI(po.bDisabled(), "Deleting an enabled Parent PDEV"); } }
GreReleaseSemaphoreEx(ghsemDriverMgmt);
// Once all the DCs open specifically on the PDEV (if there are any)
// are destroyed, free the PDEV:
po.vUnreferencePdev(); }
TRACE_INIT(("\n\nDrv_Trace: DrvDestroyMDEV: Leave\n\n")); }
/******************************************************************************
* * DrvBackoutMDEV * * This routine basically undoes all changes made by a ChangeDisplaySettings * call. * \***************************************************************************/
VOID DrvBackoutMDEV( PMDEV pmdev) { GDIFunctionID(DrvBackoutMDEV);
ULONG i; HDEV hdev;
//
// First disable all the HDEVs we created.
//
for (i = 0; i < pmdev->chdev; i++) { hdev = pmdev->Dev[i].hdev; PDEVOBJ po(hdev);
if (po.ppdev->cPdevOpenRefs == 1) { if (!DrvDisableDisplay(hdev, FALSE)) { ASSERTGDI(FALSE, "Failed Undoing CreateMDEV - we are hosed !!!\n"); } }
//
// Remove the references so this object can go away
//
GreAcquireSemaphoreEx(ghsemDriverMgmt, SEMORDER_DRIVERMGMT, NULL);
po.ppdev->cPdevOpenRefs--; po.vUnreferencePdev();
GreReleaseSemaphoreEx(ghsemDriverMgmt); }
//
// Restore the old HDEVs
//
for (i = 0; i < pmdev->chdev; i++) { if ((hdev = pmdev->Dev[i].Reserved) != NULL) { PDEVOBJ po(hdev);
//
// Reenable the display
//
if (po.ppdev->cPdevOpenRefs == 1) { if (!DrvEnableDisplay(hdev)) { ASSERTGDI(FALSE, "Failed Undoing CreateMDEV - we are hosed !!!\n"); } } } } }
//*****************************************************************************
//
// hCreateHDEV
//
// Creates a PDEV that the window manager will use to open display DCs.
// This call is made by the window manager to open a new display surface
// for use. Any number of display surfaces may be open at one time.
//
// pDesktopId - Unique identifier to determine the Desktop the PDEV
// will be associated with.
//
// flags
//
// GCH_DEFAULT_DISPLAY
// - Whether or not this is the inital display device (on
// which the default bitmap will be located).
//
// GCH_DDML
// - The name of the display is the DDML entrypoint
//
// GCH_PANNING
// - The name of the display is the PANNING entrypoint
//
//*****************************************************************************
// !!! should be partly incorporate in PDEVOBJ::PDEVOBJ since many fields
// !!! are destroyed by that destructor
HDEV hCreateHDEV( PGRAPHICS_DEVICE PhysDisp, PDRV_NAMES lpDisplayNames, PDEVMODEW pdriv, PVOID pDesktopId, DWORD dwOverride, DWORD dwAccelLevel, BOOL bNoDisable, FLONG flags, HDEV *phDevDisabled ) { GDIFunctionID(hCreateHDEV);
ULONG i; PDEV *ppdev; PDEV *ppdevMatch = NULL; PLDEV pldev; BOOL bError = FALSE;
//
// Search through the entire PDEV cache to see if we have PDEVs on the
// same device. If any such a PDEV is active, we need to disable it.
//
// All see if a PDEV matches the given mode and is for the same device.
// If so, simply return that.
//
// To be a Match, the PDEV has to match:
// - The device
// - The devmode (except for position)
// - The desktop on which it is located
//
ASSERTGDI(lpDisplayNames != NULL, "NULL name to hCreateHDEV\n");
#if !defined(_GDIPLUS_)
ASSERTGDI(PhysDisp != NULL, "NULL physdisp to hCreateHDEV\n"); #endif
*phDevDisabled = NULL;
if (PhysDisp != (PGRAPHICS_DEVICE) DDML_DRIVER) { if (pdriv == NULL) return NULL;
GreAcquireSemaphoreEx(ghsemDriverMgmt, SEMORDER_DRIVERMGMT, NULL);
for (ppdev = gppdevList; ppdev != NULL; ppdev = ppdev->ppdevNext) { PDEVOBJ po((HDEV) ppdev); PGRAPHICS_DEVICE pGraphicsDevice = po.ppdev->pGraphicsDevice;
//
// Check if we are on the same actual device.
// We have to check the VGA device also, in case we are loading
// the S3 driver dynamically, and the main PhysDisp became a
// child physdisp on the fly.
//
// The VGA check is complex due to the following scenario:
// - Machine boots in VGA, so the pdev is on the VGA device.
// - The C&T driver is loaded on the fly, so the pVgaDevice becomes
// the C&T driver.
// - We change the mode on the fly, so now we would like to diable
// the vga pdev. -->> check if our device and the pdev are both
// on a VGA device.
//
if ((pGraphicsDevice != NULL) && (pGraphicsDevice != (PGRAPHICS_DEVICE) DDML_DRIVER) && ((PhysDisp == pGraphicsDevice) || (PhysDisp->pVgaDevice && pGraphicsDevice->pVgaDevice))) { po.ppdev->cPdevRefs++; GreReleaseSemaphoreEx(ghsemDriverMgmt); GreAcquireSemaphoreEx(ghsemShareDevLock, SEMORDER_SHAREDEVLOCK, NULL); GreAcquireSemaphoreEx(po.hsemDevLock(), SEMORDER_DEVLOCK, NULL); GreEnterMonitoredSection(po.ppdev, WD_DEVLOCK);
//
// If this is the matching device, just remember it here because
// we have to check for all active PDEVs.
// This also allows us to not disable\reenable the same device
// if we were not switching.
//
// But for Dualview, always reset the mode
//
if ((((PhysDisp->stateFlags & DISPLAY_DEVICE_DUALVIEW) == 0) || (!gbInvalidateDualView) || (bNoDisable == TRUE)) && (!(po.bCloneDriver())) && /* don't pick clone pdev from cache */ (po.ppdev->pDesktopId == pDesktopId) && (po.ppdev->dwDriverCapableOverride == dwOverride) && (po.ppdev->dwDriverAccelerationLevel == dwAccelLevel) && RtlEqualMemory(pdriv, po.ppdev->ppdevDevmode, sizeof(DEVMODEW)) ) { ASSERTGDI(ppdevMatch == NULL, "Multiple cached PDEV matching the current mode.\n");
po.vReferencePdev(); ppdevMatch = ppdev; } else { //
// Don't disable the PDEV for an independant desktop open
//
if (bNoDisable == TRUE) { bError = TRUE; } else { //
// If there is an enabled PDEV in this same PhysDisp, then
// we must disable it.
// Only one HDEV per device at any one time.
//
// There may be multiple active in the case where outstanding
// Opens have been made (multiple display case only).
//
if (po.bDisabled() == FALSE) { ASSERTGDI(*phDevDisabled == NULL, "Multiple active PDEVs on same device\n");
TRACE_INIT(("hCreateHDEV: disabling ppdev %08lx\n", ppdev));
if (DrvDisableDisplay((HDEV) ppdev, FALSE)) { *phDevDisabled = (HDEV) ppdev; } else { bError = TRUE; } } } }
GreExitMonitoredSection(po.ppdev, WD_DEVLOCK); GreReleaseSemaphoreEx(po.hsemDevLock()); GreReleaseSemaphoreEx(ghsemShareDevLock); GreAcquireSemaphoreEx(ghsemDriverMgmt, SEMORDER_DRIVERMGMT, NULL); po.vUnreferencePdev(); } }
GreReleaseSemaphoreEx(ghsemDriverMgmt);
if (bError) { //
// There was an error trying to disable the device.
// return NULL;
//
if (ppdevMatch != NULL) { PDEVOBJ po((HDEV) ppdevMatch);
po.vUnreferencePdev(); }
return NULL; }
//
// If we found a match, reenable and refcount the device, as necessary.
//
if (ppdevMatch) { TRACE_INIT(("hCreateHDEV: Found a ppdev cache match\n"));
PDEVOBJ po((HDEV) ppdevMatch);
//
// Increment the Open count of the device
//
GreAcquireSemaphoreEx(ghsemShareDevLock, SEMORDER_SHAREDEVLOCK, NULL); GreAcquireSemaphoreEx(po.hsemDevLock(), SEMORDER_DEVLOCK, NULL);
GreAcquireSemaphoreEx(ghsemDriverMgmt, SEMORDER_DRIVERMGMT, NULL);
po.ppdev->cPdevOpenRefs++;
GreReleaseSemaphoreEx(ghsemDriverMgmt);
GreEnterMonitoredSection(po.ppdev, WD_DEVLOCK);
//
// Check for Software panning modes.
//
//
// If the Device was disabled, just reenable it.
//
if (po.bDisabled()) { ASSERTGDI(po.ppdev->cPdevOpenRefs == 1, "Inconsistent Open count on disabled PDEV\n");
DrvEnableDisplay((HDEV) ppdevMatch); }
//
// Reset the offset appropriately.
//
GreExitMonitoredSection(po.ppdev, WD_DEVLOCK); GreReleaseSemaphoreEx(po.hsemDevLock()); GreReleaseSemaphoreEx(ghsemShareDevLock);
return((HDEV) ppdevMatch); } }
//
// No existing PDEV in our list. Let's create a new one.
//
if (lpDisplayNames == NULL) { WARNING(("Drv_Trace: LoadDisplayDriver: Display driver list was not present.\n")); }
//
// Make a fake DC so we can pass in the needed info to vInitBrush.
// We use allocation instead of stack since sizeof(DC) is about 1.5k
// WINBUG 393269
//
DC *pdc = (DC*)PALLOCMEM(sizeof(DC), 'pmtG');
if (pdc == NULL) { WARNING("hCreateHDEV: DC memory allocation failed\n"); goto Exit; }
for (i = 0; i < lpDisplayNames->cNames; i++) { //
// Load the display driver image.
//
switch (flags) { case GCH_DEFAULT_DISPLAY:
pldev = ldevLoadDriver(lpDisplayNames->D[i].lpDisplayName, LDEV_DEVICE_DISPLAY); break;
case GCH_DDML:
pldev = ldevLoadInternal((PFN)(lpDisplayNames->D[i].lpDisplayName), LDEV_DEVICE_META); break;
case GCH_GDIPLUS_DISPLAY:
pldev = ldevLoadInternal((PFN)(lpDisplayNames->D[i].lpDisplayName), LDEV_DEVICE_META); break;
case GCH_MIRRORING:
pldev = ldevLoadDriver(lpDisplayNames->D[i].lpDisplayName, LDEV_DEVICE_MIRROR); break;
case GCH_PANNING:
ASSERTGDI(FALSE, "Software Panning not implemented yet\n"); pldev = NULL; break;
default:
ASSERTGDI(FALSE, "Unknown driver type\n"); pldev = NULL; break; }
if (pldev == NULL) { TRACE_INIT(("hCreateHDEV: failed ldevLoadDriver\n")); } else { bSetDeviceSessionUsage(PhysDisp, TRUE);
PDEVOBJ po(pldev, pdriv, NULL, // no logical address
NULL, // no data file
lpDisplayNames->D[i].lpDisplayName, // device name is the display driver name
// necessary for hook drivers.
lpDisplayNames->D[i].hDriver, NULL, // no remote typeone info (this isn't font driver)
0, // prmr.bValid() ? prmr.GdiInfo() : NULL,
0, // prmr.bValid() ? prmr.pdevinfo() : NULL
FALSE, // not UMPD driver
dwOverride, // Capable Override
dwAccelLevel); // acceleration level.
if (!po.bValid()) { TRACE_INIT(("hCreateHDEV: PDEVOBJ::po failed\n")); bSetDeviceSessionUsage(PhysDisp, FALSE); ldevUnloadImage(pldev); } else {
#ifdef DDI_WATCHDOG
//
// Watchdog objects require DEVICE_OBJECT now and we are associating DEVICE_OBJECT
// with PDEV here (i.e. we don't know DEVICE_OBJECT in PDEVOBJ::PDEVOBJ).
// Beacuse of this we have to delay creation of watchdog objects till we get here.
// It would be nice to keep all this stuff in PDEVOBJ::PDEVOBJ constructor.
//
//
// Create watchdogs for display or mirror device.
//
if ((po.ppdev->pldev->ldevType == LDEV_DEVICE_DISPLAY) || (po.ppdev->pldev->ldevType == LDEV_DEVICE_MIRROR)) { if ((NULL == po.ppdev->pWatchdogData) && PhysDisp) { PDEVICE_OBJECT pDeviceObject;
pDeviceObject = (PDEVICE_OBJECT)(PhysDisp->pDeviceHandle);
if (pDeviceObject) { po.ppdev->pWatchdogData = GreCreateWatchdogs(pDeviceObject, WD_NUMBER, DDI_TIMEOUT, WdDdiWatchdogDpcCallback, lpDisplayNames->D[i].lpDisplayName, lpDisplayNames->D[i].hDriver, &gpldevDrivers); } } }
#endif // DDI_WATCHDOG
TRACE_INIT(("hCreateHDEV: about to call pr:bMakeSurface\n"));
if (po.bMakeSurface()) { #if DBG
//
// Check the surface created by driver is same as what we want.
//
if (po.pSurface() && pdriv && (flags == GCH_DEFAULT_DISPLAY)) { if ((pdriv->dmPelsWidth != (ULONG) po.pSurface()->sizl().cx) || (pdriv->dmPelsHeight != (ULONG) po.pSurface()->sizl().cy)) { DbgPrint("hCreateHDEV() - DEVMODE %d,%d, SURFACE %d,%d\n", pdriv->dmPelsWidth, pdriv->dmPelsHeight, po.pSurface()->sizl().cx, po.pSurface()->sizl().cy); } } #endif // DBG
//
// Realize the Gray pattern brush used for drag rectangles.
//
po.pbo()->vInit();
PBRUSH pbrGrayPattern;
pbrGrayPattern = (PBRUSH)HmgShareCheckLock((HOBJ)ghbrGrayPattern, BRUSH_TYPE); pdc->pDCAttr = &pdc->dcattr; pdc->crTextClr(0x00000000); pdc->crBackClr(0x00FFFFFF); pdc->lIcmMode(DC_ICM_OFF); pdc->hcmXform(NULL); po.pbo()->vInitBrush(pdc, pbrGrayPattern, (XEPALOBJ) ppalDefault, (XEPALOBJ) po.ppdev->pSurface->ppal(), po.ppdev->pSurface);
DEC_SHARE_REF_CNT_LAZY0 (pbrGrayPattern);
//
// Now set the global default bitmaps pdev to equal
// that of our global display device.
//
PSURFACE pSurfDefault = SURFACE::pdibDefault;
if (pSurfDefault->hdev() == NULL) { pSurfDefault->hdev(po.hdev()); }
po.ppdev->pGraphicsDevice = PhysDisp; po.ppdev->pDesktopId = pDesktopId;
//
// Keep the DEVMODE, if this is a real display device
//
if ((flags != GCH_DDML) && (flags != GCH_GDIPLUS_DISPLAY)) { po.ppdev->ppdevDevmode = (PDEVMODEW) PALLOCNOZ(pdriv->dmSize + pdriv->dmDriverExtra, GDITAG_DEVMODE);
if (po.ppdev->ppdevDevmode) { RtlMoveMemory(po.ppdev->ppdevDevmode, pdriv, pdriv->dmSize + pdriv->dmDriverExtra);
//
// At this moment, this device must be attached. DM_POSITION indicates that
//
po.ppdev->ppdevDevmode->dmFields |= DM_POSITION; DrvUpdateAttachFlag(PhysDisp, 1); } else { bError = TRUE; } }
//
// Mark the PDEV as now being ready for use. This has to
// be one of the last steps, because GCAPS2_SYNCFLUSH and
// GCAPS2_SYNCTIMER asynchronously loop through the PDEV
// list and call the driver if 'bDisabled' is not set.
//
po.bDisabled(FALSE);
//
// Profile driver
//
// We can not profile meta (= DDML) driver, and while we
// are creating meta driver, we don't ssync'ed devlock
// with its children, so we can not call anything which
// will dispatch to its children.
//
if (!po.bMetaDriver()) { po.vProfileDriver(); }
if (bError) { // There was an error of memory allocation.
po.vUnreferencePdev(); break; } VFREEMEM(pdc); return(po.hdev()); } else { TRACE_INIT(("hCreateHDEV: bMakeSurface failed\n")); bSetDeviceSessionUsage(PhysDisp, FALSE); }
//
// Destroy everything if something fails.
// This will remove the Surface, PDEV and image.
//
po.vUnreferencePdev(); } } }
Exit: if (pdc) VFREEMEM(pdc); //
// There was an error creating the new device.
// Reenable the old one if we disabled it.
//
if (*phDevDisabled) { if ((PhysDisp->stateFlags & DISPLAY_DEVICE_DUALVIEW) == 0 || !gbInvalidateDualView) { DrvEnableDisplay(*phDevDisabled); } }
return NULL; }
#if TEXTURE_DEMO
DHPDEV TexEnablePDEV( DEVMODEW *pdm, // Actually, the HDEV
LPWSTR pwszLogAddress, ULONG cPat, HSURF *phsurfPatterns, ULONG cjCaps, GDIINFO *pdevcaps, ULONG cjDevInfo, DEVINFO *pdi, HDEV hdev, LPWSTR pwszDeviceName, HANDLE hDriver) { HDEV hdevParent = (HDEV) pdm;
PDEVOBJ poParent(hdevParent); PDEVOBJ po(hdev);
pdevcaps->ulHorzRes = gcxTexture; pdevcaps->ulVertRes = gcyTexture;
ghdevTextureParent = poParent.hdev();
return(poParent.dhpdev()); }
HSURF TexEnableSurface(DHPDEV dhpdev) { PDEVOBJ poPrimary(ghdevTextureParent);
DEVLOCKOBJ dlo(poPrimary);
HSURF hsurf = hsurfCreateCompatibleSurface(poPrimary.hdev(), poPrimary.pSurface()->iFormat(), poPrimary.bIsPalManaged() ? NULL : (HPALETTE) poPrimary.ppalSurf()->hGet(), 512, 512, TRUE);
return(hsurf); }
VOID TexDisablePDEV(DHPDEV dhpdev) { }
VOID TexCompletePDEV( DHPDEV dhpdev, HDEV hdev) { }
VOID TexDisableSurface(DHPDEV dhpdev) { }
typedef struct _DEMOTEXTURE { HDC hdc; ULONG iTexture; BOOL bCopy; DEMOQUAD Quad; } DEMOTEXTURE;
BOOL TexTexture( VOID* pvBuffer, ULONG cjBuffer) { BOOL bRet = FALSE; DEMOTEXTURE tex; KFLOATING_SAVE fsFpState;
if (cjBuffer < sizeof(DEMOTEXTURE)) { WARNING("TexTexture: Buffer too small"); return(FALSE); }
tex = *((DEMOTEXTURE*) pvBuffer);
if (ghdevTextureParent == NULL) { WARNING1("TexTexture: Texturing not enabled"); return(FALSE); }
if (tex.iTexture >= gcTextures) { WARNING("TexTexture: Bad texture identifier"); return(FALSE); }
if (!NT_SUCCESS(KeSaveFloatingPointState(&fsFpState))) { WARNING("TexTexture: Couldn't save floating point state"); return(FALSE); }
DCOBJ dco(tex.hdc); if (dco.bValid()) { DEVLOCKOBJ dlo(dco); if (dlo.bValid()) { PDEVOBJ poParent(ghdevTextureParent); PDEVOBJ po(gahdevTexture[tex.iTexture]);
if (1) // dco.pSurface()->hdev() == po.pSurface()->hdev())
{ ECLIPOBJ eco; ERECTL erclBig(-10000, -10000, 10000, 10000);
eco.vSetup(dco.prgnEffRao(), erclBig); if (!eco.erclExclude().bEmpty()) { if (tex.bCopy) { ERECTL erclDst(0, 0, dco.pdc->sizl().cx, dco.pdc->sizl().cy);
PPFNGET(po, CopyBits, dco.pSurface()->flags()) (dco.pSurface()->pSurfobj(), po.pSurface()->pSurfobj(), &eco, NULL, &erclDst, (POINTL*) &erclDst); bRet = TRUE; } else { if (PPFNVALID(poParent, DemoTexture)) { PPFNDRV(po, DemoTexture)(dco.pSurface()->pSurfobj(), po.pSurface()->pSurfobj(), &eco, &tex.Quad, 1); bRet = TRUE; } else { WARNING("TexTexture: DrvDemoTexture not hooked"); } } } } else { WARNING("TexTexture: Mismatched HDEVs"); } } else { WARNING("TexTexture: Bad devlock"); } } else { WARNING("TexTexture: Bad DC"); }
KeRestoreFloatingPointState(&fsFpState);
return(bRet); }
HDC hdcTexture( ULONG iTexture ) { HDC hdc; HDEV hdev;
hdc = 0; hdev = 0;
if (iTexture == (ULONG) -1) { hdev = ghdevTextureParent; } else if (iTexture < gcTextures) { hdev = gahdevTexture[iTexture]; }
if (hdev != NULL) { hdc = GreCreateDisplayDC(hdev, DCTYPE_DIRECT, FALSE); } else { WARNING("hdcTexture: Bad parameter"); }
return(hdc); }
HDEV hCreateTextureHDEV( HDEV hdevOwner ) { PLDEV pldev;
PDEVOBJ poOwner(hdevOwner);
pldev = (PLDEV) PALLOCMEM(sizeof(LDEV), GDITAG_LDEV); if (!pldev) { WARNING("hCreateTextureHDEV: LDEV alloc failed."); return(0); }
RtlCopyMemory(pldev, poOwner.ppdev->pldev, sizeof(LDEV));
pldev->apfn[INDEX_DrvEnablePDEV] = (PFN) TexEnablePDEV; pldev->apfn[INDEX_DrvEnableSurface] = (PFN) TexEnableSurface; pldev->apfn[INDEX_DrvCompletePDEV] = (PFN) TexCompletePDEV; pldev->apfn[INDEX_DrvDisablePDEV] = (PFN) TexDisablePDEV; pldev->apfn[INDEX_DrvDisableSurface] = (PFN) TexDisableSurface;
pldev->apfn[INDEX_DrvAssertMode] = NULL; pldev->apfn[INDEX_DrvCreateDeviceBitmap] = NULL; pldev->apfn[INDEX_DrvDeleteDeviceBitmap] = NULL; pldev->apfn[INDEX_DrvSetPalette] = NULL; pldev->apfn[INDEX_DrvSetPointerShape] = NULL; pldev->apfn[INDEX_DrvSaveScreenBits] = NULL; pldev->apfn[INDEX_DrvIcmSetDeviceGammaRamp] = NULL; pldev->apfn[INDEX_DrvGetDirectDrawInfo] = NULL;
PDEVOBJ po(pldev, (PDEVMODEW) hdevOwner, NULL, // no logical address
NULL, // no data file
NULL, // device name is the display driver name
// necessary for hook drivers.
NULL, // driver handle
NULL, poOwner.GdiInfo(), poOwner.pdevinfo());
if (!po.bValid()) { WARNING("hCreateTextureHDEV failed"); return(0); } else { TRACE_INIT(("hCreateTextureHDEV: about to call pr:bMakeSurface\n"));
if (po.bMakeSurface()) { //
// Make a fake DC so we can pass in the needed info to vInitBrush.
// Watch out that this is a bit big (about 1k of stack space).
//
DC *pdc = (DC*)PALLOCMEM(sizeof(DC), 'pmtG');
if (pdc == NULL) { po.vUnreferencePdev(); WARNING("hCreateTextureHDEV: DC memory allocation failed\n"); return(0); }
//
// Realize the gray pattern brush used for drag rectangles.
//
po.pbo()->vInit();
PBRUSH pbrGrayPattern;
pbrGrayPattern = (PBRUSH)HmgShareCheckLock((HOBJ)ghbrGrayPattern, BRUSH_TYPE);
pdc->pDCAttr = &pdc->dcattr;
pdc->crTextClr(0x00000000); pdc->crBackClr(0x00FFFFFF);
pdc->lIcmMode(DC_ICM_OFF);
pdc->hcmXform(NULL);
po.pbo()->vInitBrush(pdc, pbrGrayPattern, (XEPALOBJ) ppalDefault, (XEPALOBJ) po.ppdev->pSurface->ppal(), po.ppdev->pSurface);
DEC_SHARE_REF_CNT_LAZY0 (pbrGrayPattern);
//
// Now set the global default bitmaps pdev to equal
// that of our global display device.
//
PSURFACE pSurfDefault = SURFACE::pdibDefault;
if (pSurfDefault->hdev() == NULL) { pSurfDefault->hdev(po.hdev()); }
po.ppdev->pGraphicsDevice = poOwner.ppdev->pGraphicsDevice; po.ppdev->pDesktopId = poOwner.ppdev->pDesktopId;
po.bDisabled(FALSE);
po.vProfileDriver();
VFREEMEM(pDC);
return(po.hdev()); } else { TRACE_INIT(("hCreateHDEV: bMakeSurface failed\n")); }
//
// Destroy everything if something fails.
// This will remove the Surface, PDEV and image.
//
po.vUnreferencePdev(); }
return NULL; }
PMDEV pmdevSetupTextureDemo( PMDEV pmdev) { ULONG i;
if ((gbTexture) && (pmdev) && (pmdev->chdev == 1)) { PMDEV pmdevTmp;
//
// We allocate and copy too much, but we don't care ...
//
pmdevTmp = (PMDEV) PALLOCNOZ(sizeof(MDEV) * (pmdev->chdev + 8), GDITAG_DRVSUP);
if (pmdevTmp) { PDEVOBJ poPrimary(pmdev->Dev[0].hdev);
//
// Copy the MDEV list
//
RtlMoveMemory(pmdevTmp, pmdev, sizeof(MDEV) * pmdev->chdev);
//
// Position the surfaces consecutively to the right of the primary.
//
LONG xLeft = pmdev->Dev[0].rect.left; LONG yTop = pmdev->Dev[0].rect.bottom;
//
// Hard code them to 512x512.
//
for (i = 0; i < 3; i++) { //
// Create a clone of the PDEV.
//
HDEV hdevTexture = hCreateTextureHDEV(poPrimary.hdev()); if (!hdevTexture) { //
// Delete all the hdevs we have created. and restore the old
// ones.
//
DrvBackoutMDEV(pmdev); VFREEMEM(pmdev); pmdev = NULL; return(pmdev); }
PDEVOBJ poTexture(hdevTexture);
//
// Point the surface's HDEV to its true owner, so that
// software cursors work. I hope.
//
poTexture.pSurface()->hdev(hdevTexture);
gahdevTexture[i] = hdevTexture;
poTexture.ppdev->ptlOrigin.x = xLeft; poTexture.ppdev->ptlOrigin.y = yTop;
gcxTexture = 512; gcyTexture = 512;
pmdevTmp->Dev[1 + i].hdev = hdevTexture; pmdevTmp->Dev[1 + i].rect.left = xLeft; pmdevTmp->Dev[1 + i].rect.top = yTop; pmdevTmp->Dev[1 + i].rect.right = xLeft + gcxTexture; pmdevTmp->Dev[1 + i].rect.bottom = yTop + gcyTexture; pmdevTmp->Dev[1 + i].Reserved = NULL;
pmdevTmp->chdev++; gcTextures++;
yTop += gcyTexture; }
VFREEMEM(pmdev);
pmdev = pmdevTmp; } else { VFREEMEM(pmdevTmp); } }
return(pmdev); }
#endif // TEXTURE_DEMO
/***************************************************************************\
* DrvGetHDEV * * routine to find out HDEV for specified device name * * 01-Oct-1997 hideyukn Created \***************************************************************************/
HDEV DrvGetHDEV( PUNICODE_STRING pstrDeviceName) { GDIFunctionID(DrvGetHDEV);
HDEV hdev = NULL;
if (pstrDeviceName) { PGRAPHICS_DEVICE PhysDisp;
PhysDisp = DrvGetDeviceFromName(pstrDeviceName, KernelMode);
if (PhysDisp) { PDEV *ppdev; PDEV *ppdevDisabled = NULL;
GreAcquireSemaphoreEx(ghsemDriverMgmt, SEMORDER_DRIVERMGMT, NULL);
for (ppdev = gppdevList; ppdev != NULL; ppdev = ppdev->ppdevNext) { PDEVOBJ po((HDEV) ppdev);
if ((po.ppdev->pGraphicsDevice != 0) && (po.ppdev->pGraphicsDevice == PhysDisp)) { if (!(po.bDisabled())) { po.ppdev->cPdevRefs++; hdev = po.hdev(); break; } else if (ppdevDisabled == NULL) { //
// We found a matching PDEV but it is disabled. Save
// a pointer to it; in case we don't find an enabled
// PDEV we will use this:
//
ppdevDisabled = ppdev; } } }
if ((ppdev == NULL) && (ppdevDisabled != NULL)) { //
// We could not find a matching, enabled PDEV but did find a
// matching disabled PDEV, so just use it:
//
PDEVOBJ po((HDEV) ppdevDisabled);
po.ppdev->cPdevRefs++; hdev = po.hdev(); }
GreReleaseSemaphoreEx(ghsemDriverMgmt); } }
return hdev; }
/***************************************************************************\
* DrvReleaseHDEV * * routine to release an HDEV for specified device name * * 02-Mar-1999 a-oking Created \***************************************************************************/
void DrvReleaseHDEV( PUNICODE_STRING pstrDeviceName) { if (pstrDeviceName) { PGRAPHICS_DEVICE PhysDisp;
PhysDisp = DrvGetDeviceFromName(pstrDeviceName, KernelMode);
if (PhysDisp) { PDEV *ppdev;
GreAcquireSemaphoreEx(ghsemDriverMgmt, SEMORDER_DRIVERMGMT, NULL);
for (ppdev = gppdevList; ppdev != NULL; ppdev = ppdev->ppdevNext) { PDEVOBJ po((HDEV) ppdev);
if ((po.ppdev->pGraphicsDevice != 0) && (po.ppdev->pGraphicsDevice == PhysDisp)) { po.ppdev->cPdevRefs--; break; } }
GreReleaseSemaphoreEx(ghsemDriverMgmt); } }
return; }
/***************************************************************************\
* DrvCreateCloneHDEV * * create clone of passed HDEV. * * 27-Feb-1998 hideyukn Created \***************************************************************************/
#define DRV_CLONE_DEREFERENCE_ORG 0x0001
HDEV DrvCreateCloneHDEV( HDEV hdevOrg, ULONG ulFlags) { GDIFunctionID(DrvCreateCloneHDEV);
HDEV hdevClone = NULL;
PDEVOBJ pdoOrg(hdevOrg);
ASSERTGDI(!pdoOrg.bDisabled(), "DrvCreateCloneHDEV(): hdevOrg must be enabled");
// Grab the SPRITELOCK. This is important in case sprites are still
// hooked at this point because the surface type and flags have been
// altered by the sprite code, and unless we grab the SPRITELOCK here
// they will be recorded incorrectly in the SPRITESTATE of the new PDEV
// during the call to bSpEnableSprites. See bug #266112 for details.
SPRITELOCK slock(pdoOrg);
// Create clone PDEVOBJ.
PDEVOBJ pdoClone(hdevOrg,GCH_CLONE_DISPLAY);
if (pdoClone.bValid()) { BOOL bRet;
//
// Allocate a temporary DC so we can pass in the needed info to
// vInitBrush. We allocate on the heap since this is a big
// structure.
//
DC *pdc = (DC*)PALLOCMEM(sizeof(DC), 'pmtG');
if (pdc == NULL) { WARNING("DrvCreateCloneHDEV: DC memory allocation failed\n"); }
//
// Enable Sprites on new PDEV.
//
if ((pdc != NULL) && bSpEnableSprites(pdoClone.hdev())) { vEnableSynchronize(pdoClone.hdev());
// Realize the Gray pattern brush used for drag rectangles.
pdc->pDCAttr = &pdc->dcattr; pdc->crTextClr(0x00000000); pdc->crBackClr(0x00FFFFFF); pdc->lIcmMode(DC_ICM_OFF); pdc->hcmXform(NULL);
PBRUSH pbrGrayPattern = (PBRUSH)HmgShareCheckLock( (HOBJ)ghbrGrayPattern, BRUSH_TYPE); pdoClone.pbo()->vInit(); pdoClone.pbo()->vInitBrush(pdc, pbrGrayPattern, (XEPALOBJ)ppalDefault, (XEPALOBJ)pdoClone.ppdev->pSurface->ppal(), pdoClone.ppdev->pSurface);
DEC_SHARE_REF_CNT_LAZY0 (pbrGrayPattern);
// Dereference original HDEV, if nessesary.
if (ulFlags & DRV_CLONE_DEREFERENCE_ORG) { GreAcquireSemaphoreEx(ghsemDriverMgmt, SEMORDER_DRIVERMGMT, NULL);
ASSERTGDI(pdoOrg.ppdev->cPdevOpenRefs > 1, "DrvCreateCloneHDEV: cPdevOpenRefs <= 1\n"); ASSERTGDI(pdoOrg.ppdev->cPdevRefs > 1, "DrvCreateCloneHDEV: cPdevRefs <= 1\n");
pdoOrg.ppdev->cPdevOpenRefs--; pdoOrg.vUnreferencePdev();
GreReleaseSemaphoreEx(ghsemDriverMgmt); }
// Mirror the status.
pdoClone.bDisabled(pdoOrg.bDisabled());
// Obtain cloned HDEV handle.
hdevClone = pdoClone.hdev(); } else { pdoClone.vUnreferencePdev(); } if (NULL != pdc) { VFREEMEM(pdc); } }
return (hdevClone); }
BOOL GetPrimaryAttachFlags( PGRAPHICS_DEVICE PhysDisp, PULONG pPrimary, PULONG pAttached ) { HANDLE hkRegistry = NULL; ULONG defaultValue = 0; USHORT usProtocolType;
*pPrimary = *pAttached = 0; //
// Get the attached and primary data, which is per config (or
// also global if necessary.
//
RTL_QUERY_REGISTRY_TABLE AttachedQueryTable[] = { {NULL, RTL_QUERY_REGISTRY_DIRECT, AttachedSettings[0], pPrimary, REG_DWORD, &defaultValue, 4}, {NULL, RTL_QUERY_REGISTRY_DIRECT, AttachedSettings[1], pAttached, REG_DWORD, &defaultValue, 4}, {NULL, 0, NULL} };
if (PhysDisp->stateFlags & DISPLAY_DEVICE_DISCONNECT){ usProtocolType = PROTOCOL_DISCONNECT; } else if (PhysDisp->stateFlags & DISPLAY_DEVICE_REMOTE) { usProtocolType = gProtocolType; } else { usProtocolType = PROTOCOL_CONSOLE; }
hkRegistry = DrvGetRegistryHandleFromDeviceMap(PhysDisp, DispDriverRegHardwareProfile, NULL, NULL, NULL, usProtocolType); if (hkRegistry) { RtlQueryRegistryValues(RTL_REGISTRY_HANDLE, (PWSTR)hkRegistry, &AttachedQueryTable[0], NULL, NULL);
ZwCloseKey(hkRegistry); } else { hkRegistry = DrvGetRegistryHandleFromDeviceMap(PhysDisp, DispDriverRegGlobal, NULL, NULL, NULL, usProtocolType); if (hkRegistry) { NTSTATUS ntStatus;
ntStatus = RtlQueryRegistryValues(RTL_REGISTRY_HANDLE, (PWSTR)hkRegistry, &AttachedQueryTable[0], NULL, NULL);
ZwCloseKey(hkRegistry);
if (!NT_SUCCESS(ntStatus)) { return FALSE; } } else { return FALSE; } }
switch (gProtocolType) { case PROTOCOL_CONSOLE: if ((PhysDisp->stateFlags & DISPLAY_DEVICE_DISCONNECT) || (PhysDisp->stateFlags & DISPLAY_DEVICE_REMOTE)) *pAttached = 0;
break;
case PROTOCOL_DISCONNECT: if (!(PhysDisp->stateFlags & DISPLAY_DEVICE_DISCONNECT)){ *pAttached = 0; } else{ *pAttached = 1; } break;
default: if (!(PhysDisp->stateFlags & DISPLAY_DEVICE_REMOTE) || (PhysDisp->ProtocolType != gProtocolType)){ *pAttached = 0; } else{ *pAttached = 1; }
}
TRACE_INIT(("Drv_Trace: DrvCreateMDEV: Display driver is %sprimary on the desktop\n", *pPrimary ? "" : "NOT ")); TRACE_INIT(("Drv_Trace: DrvCreateMDEV: Display driver is %sattached to the desktop\n", *pAttached ? "" : "NOT "));
return TRUE; }
/***************************************************************************\
* DrvCreateMDEV * * Initialize an MDEV structure * * * andreva Created \***************************************************************************/
PMDEV DrvCreateMDEV( PUNICODE_STRING pstrDeviceName, LPDEVMODEW lpdevmodeInformation, PVOID pDesktopId, ULONG ulFlags, PMDEV pMdevOrg, MODE PreviousMode, DWORD PruneFlag, BOOL bClosest ) { GDIFunctionID(DrvCreateMDEV);
NTSTATUS retStatus = STATUS_SUCCESS; BOOL bAttachMirroring = FALSE; BOOL displayInstalled = FALSE; BOOL bLoad; PMDEV pmdev; BOOL bNoDisable = (ulFlags & GRE_DISP_CREATE_NODISABLE); BOOL bModeChange = (pMdevOrg != NULL); BOOL bPrune = (PruneFlag != GRE_RAWMODE); PGRAPHICS_DEVICE PhysDisp;
TRACE_INIT(("\nDrv_Trace: DrvCreateMDEV: Enter\n"));
GRAPHICS_STATE GraphicsState = GraphicsStateFull;
if (pstrDeviceName) { //
// Check if CreateDC on Dualview.
// Since opening a DualView must affect the other view,
// so if a Dualview is not opened in orginal MDEV, don't allow it to open
//
PhysDisp = DrvGetDeviceFromName(pstrDeviceName, PreviousMode); if (PhysDisp && (PhysDisp->stateFlags & DISPLAY_DEVICE_DUALVIEW)) { PPDEV ppdev;
for (ppdev = gppdevList; ppdev != NULL; ppdev = ppdev->ppdevNext) { PDEVOBJ po((HDEV) ppdev); if (po.ppdev->pGraphicsDevice == PhysDisp) { break; } } if (ppdev == NULL) return NULL; } }
//
// First pass through the loop - find all the devices that should be
// are atached.
// If not attached devices, go through the loop again to find a default
// device.
// Thirdly - try to find any mirroring devices.
//
//
// Allocate new MDEV (with zero initialization)
//
pmdev = (PMDEV) PALLOCMEM(sizeof(MDEV), GDITAG_DRVSUP);
if (pmdev == NULL) { return NULL; }
pmdev->chdev = 0; pmdev->pDesktopId = pDesktopId;
while (1) { BOOL bMultiDevice = TRUE; HDEV hDev; HDEV hDevDisabled; PGRAPHICS_DEVICE PhysDispOfDeviceName = NULL; DWORD devNum = 0; NTSTATUS tmpStatus;
HANDLE hkRegistry = NULL; ULONG defaultValue = 0; ULONG attached = 0; ULONG primary = 0; PDRV_NAMES lpDisplayNames;
while (bMultiDevice && (retStatus == STATUS_SUCCESS)) { PhysDisp = NULL; hDev = NULL; hDevDisabled = NULL;
if (pstrDeviceName && (PhysDispOfDeviceName == NULL)) { PhysDispOfDeviceName = PhysDisp = DrvGetDeviceFromName(pstrDeviceName, PreviousMode);
//
// If we are under mode change, and device name specified. it
// means caller want to change the mode for specified device
// and leave other device as is. so we will still look for
// other device in > 2 loops.
//
if (!bModeChange) { bMultiDevice = FALSE; } } else { if (PhysDispOfDeviceName && bModeChange) { //
// We are here when ...
//
// + DrvCreateMDEV get called with specific device name,
// AND
// + During mode change.
//
// so get device from original MDEV instead of enumerate,
//
if (devNum < pMdevOrg->chdev) { hDev = pMdevOrg->Dev[devNum++].hdev;
PDEVOBJ pdo(hDev);
PhysDisp = pdo.ppdev->pGraphicsDevice;
//
// If this device is already attached (in 1st loop),
// don't need to attach again.
//
if (PhysDisp == PhysDispOfDeviceName) { continue; }
//
// If we are in context of "adding mirroring driver"
// and this is mirroring
// device continue to add it, otherwise forget this.
//
if ((PhysDisp->stateFlags & DISPLAY_DEVICE_MIRRORING_DRIVER) ? (!bAttachMirroring) : bAttachMirroring) { continue; }
//
// Increment the Open count of the device
//
GreAcquireSemaphoreEx(ghsemShareDevLock, SEMORDER_SHAREDEVLOCK, NULL); GreAcquireSemaphoreEx(pdo.hsemDevLock(), SEMORDER_DEVLOCK, NULL);
GreAcquireSemaphoreEx(ghsemDriverMgmt, SEMORDER_DRIVERMGMT, NULL);
pdo.ppdev->cPdevOpenRefs++; pdo.ppdev->cPdevRefs++;
GreReleaseSemaphoreEx(ghsemDriverMgmt);
GreEnterMonitoredSection(pdo.ppdev, WD_DEVLOCK);
//
// If the Device was disabled, just reenable it.
// But for dualview, we want to delay the enable until new MDEV is created
//
if (pdo.bDisabled() && (((PhysDisp->stateFlags & DISPLAY_DEVICE_DUALVIEW) == 0) || !gbInvalidateDualView) ) { ASSERTGDI(pdo.ppdev->cPdevOpenRefs == 1, "Inconsistent Open count on disabled PDEV\n");
DrvEnableDisplay((HDEV) pdo.ppdev); }
GreExitMonitoredSection(pdo.ppdev, WD_DEVLOCK); GreReleaseSemaphoreEx(pdo.hsemDevLock()); GreReleaseSemaphoreEx(ghsemShareDevLock);
primary = (PhysDisp->stateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE) ? 1 : 0; attached = 1; // since already attached.
} else { break; } } else { DWORD cCount = 0; for (PhysDisp = gpGraphicsDeviceList; PhysDisp != NULL; PhysDisp = PhysDisp->pNextGraphicsDevice, cCount++) { if (cCount == devNum) break; } devNum++;
//
// For BaseVideo, on a default boot (as opposed to a test
// in the applet), just look for the VGA driver.
//
if (gbBaseVideo && PhysDisp) { PhysDisp = PhysDisp->pVgaDevice;
if (PhysDisp == NULL) { continue; } } } }
if (PhysDisp == NULL) { break; }
if (PruneFlag == GRE_DEFAULT) { bPrune = DrvGetPruneFlag(PhysDisp); }
ASSERTGDI(PhysDisp, "Can not have NULL PhysDisp here\n");
if (!hDev) { /*****************************************************************
***************************************************************** Get Device Information ***************************************************************** *****************************************************************/
TRACE_INIT(("\nDrv_Trace: DrvCreateMDEV: Trying to open device %ws \n", &(PhysDisp->szNtDeviceName[0])));
if (!GetPrimaryAttachFlags(PhysDisp, &primary, &attached)) { break; }
/*****************************************************************
***************************************************************** Load Display Drivers ***************************************************************** *****************************************************************/
//
// Try to open the display driver associated to the kernel driver.
//
// We want to do this if we are looking for an attached device (taking
// into account mirror devices properly) or if we are just looking
// for any device.
//
if (GraphicsState == GraphicsStateFull) { bLoad = attached && ((PhysDisp->stateFlags & DISPLAY_DEVICE_MIRRORING_DRIVER) ? bAttachMirroring : (!bAttachMirroring)); } else if (GraphicsState == GraphicsStateNoAttach) { if (PhysDisp->stateFlags & DISPLAY_DEVICE_MIRRORING_DRIVER) { bLoad = (attached && bAttachMirroring); } else if (PhysDisp->stateFlags & DISPLAY_DEVICE_DISCONNECT) { bLoad = FALSE; } else { ASSERTGDI(displayInstalled || gProtocolType != PROTOCOL_DISCONNECT, "Failed to load disconnected driver while in disconnect mode.\n");
bLoad = (!displayInstalled && (gProtocolType != PROTOCOL_DISCONNECT)); } } else if (GraphicsState == GraphicsStateAttachDisconnect) { if (PhysDisp->stateFlags & DISPLAY_DEVICE_MIRRORING_DRIVER) { bLoad = (attached && bAttachMirroring); } else { bLoad = (!displayInstalled); } } else { bLoad = (PhysDisp->stateFlags & DISPLAY_DEVICE_MIRRORING_DRIVER) ? FALSE : (!displayInstalled); }
if (bLoad && (lpDisplayNames = DrvGetDisplayDriverNames(PhysDisp))) { PDEVMODEW pdevmodeInformation; DEVMODEW sourceDevmodeInformation; DWORD dwAccelLevel; DWORD dwOverride; BOOL uu; FLONG flag = (PhysDisp->stateFlags & DISPLAY_DEVICE_MIRRORING_DRIVER) ? GCH_MIRRORING : GCH_DEFAULT_DISPLAY;
if (flag == GCH_DEFAULT_DISPLAY) { dwOverride = DrvGetDriverCapableOverRide(PhysDisp); dwAccelLevel = DrvGetDriverAccelerationsLevel(PhysDisp); } else { dwOverride = DRIVER_CAPABLE_ALL; dwAccelLevel = 0; }
//
// We will try to load the driver using the information in the
// registry. If it matches perfectly with a mode from the driver -
// great. If it's a loose match, the we just give a warning.
//
// If that does not work, we will want to try the first mode
// in the list - which we get by matching with 0,0,0
//
// If that also fails, we want to boot with the default DEVMODE
// that we pass to the driver.
//
if (lpdevmodeInformation) { tmpStatus = DrvProbeAndCaptureDevmode(PhysDisp, &pdevmodeInformation, &uu, lpdevmodeInformation, FALSE, PreviousMode, bPrune, bClosest, FALSE); } else { RtlZeroMemory(&sourceDevmodeInformation, sizeof(DEVMODEW)); sourceDevmodeInformation.dmSize = sizeof(DEVMODEW);
tmpStatus = DrvProbeAndCaptureDevmode(PhysDisp, &pdevmodeInformation, &uu, &sourceDevmodeInformation, FALSE, KernelMode, bPrune, bClosest, FALSE); }
if (tmpStatus == STATUS_RECEIVE_PARTIAL) { DrvLogDisplayDriverEvent(MsgInvalidDisplayMode); } else if (tmpStatus == STATUS_INVALID_PARAMETER_MIX) { ASSERTGDI(PhysDisp->stateFlags & DISPLAY_DEVICE_MIRRORING_DRIVER, "Only mirror drivers can return this error code\n");
//
// In the case of mirroring, we want to use the same
// parameters as were provided for the main display.
// We do this by passing the HDEV of the device we are
// duplicating which will actually allow the driver to
// get all the details about the other device
//
PDEVOBJ pdo(pmdev->Dev[0].hdev); PDEVMODEW pdm = pdo.ppdev->ppdevDevmode;
if (pdevmodeInformation && pdevmodeInformation != &sourceDevmodeInformation) { VFREEMEM(pdevmodeInformation); pdevmodeInformation = NULL; } tmpStatus = DrvProbeAndCaptureDevmode(PhysDisp, &pdevmodeInformation, &uu, pdm, FALSE, PreviousMode, bPrune, bClosest, FALSE); }
//
// hCreateHDEV will appropriately compare the current mode
// to the device, and disable the current PDEV if necessary
//
if (NT_SUCCESS(tmpStatus)) { hDev = hCreateHDEV(PhysDisp, lpDisplayNames, pdevmodeInformation, pDesktopId, dwOverride, dwAccelLevel, bNoDisable, flag, &hDevDisabled); }
//
// We failed to load a display driver with this devmode.
// Try to pick the first valid Devmode, unless the user
// requested a specific devmode.
//
// If it still fails, try 640x480x4 VGA mode. We must get
// something to set
//
if (!(PhysDisp->stateFlags & DISPLAY_DEVICE_MIRRORING_DRIVER) && (lpdevmodeInformation == NULL)) { if (!hDev) { DrvLogDisplayDriverEvent(MsgInvalidDisplayMode);
//
// Free memory allocated by DrvProbeAndCaptureDevmode
//
if (pdevmodeInformation) { //
// Log an error saying the selected color or
// resolution is invalid.
//
if (pdevmodeInformation->dmBitsPerPel == 0x4) { DrvLogDisplayDriverEvent(MsgInvalidDisplay16Colors); }
if (pdevmodeInformation != &sourceDevmodeInformation) { VFREEMEM(pdevmodeInformation); pdevmodeInformation = NULL; } }
TRACE_INIT(("Drv_Trace: DrvCreateMDEV: Trying first DEVMODE\n"));
RtlZeroMemory(&sourceDevmodeInformation, sizeof(DEVMODEW)); sourceDevmodeInformation.dmSize = sizeof(DEVMODEW);
if (NT_SUCCESS(DrvProbeAndCaptureDevmode(PhysDisp, &pdevmodeInformation, &uu, &sourceDevmodeInformation, TRUE, KernelMode, bPrune, bClosest, FALSE))) { hDev = hCreateHDEV(PhysDisp, lpDisplayNames, pdevmodeInformation, pDesktopId, dwOverride, dwAccelLevel, bNoDisable, GCH_DEFAULT_DISPLAY, &hDevDisabled);
//
// At last try 640x480x4bpp. With Framebuf driver,
// 640x480x4 will never be picked by DrvProbeAndCapture().
// And it's very likely that the mode set can be failed.
//
if (hDev == NULL && pdevmodeInformation->dmBitsPerPel != 0x4) { if (pdevmodeInformation && pdevmodeInformation != &sourceDevmodeInformation) { VFREEMEM(pdevmodeInformation); pdevmodeInformation = NULL; } RtlZeroMemory(&sourceDevmodeInformation, sizeof(DEVMODEW)); sourceDevmodeInformation.dmSize = sizeof(DEVMODEW); sourceDevmodeInformation.dmBitsPerPel = 0x4; sourceDevmodeInformation.dmPelsWidth = 640; sourceDevmodeInformation.dmPelsHeight = 480; sourceDevmodeInformation.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
if (NT_SUCCESS(DrvProbeAndCaptureDevmode(PhysDisp, &pdevmodeInformation, &uu, &sourceDevmodeInformation, FALSE, KernelMode, bPrune, bClosest, FALSE))) { hDev = hCreateHDEV(PhysDisp, lpDisplayNames, pdevmodeInformation, pDesktopId, dwOverride, dwAccelLevel, bNoDisable, GCH_DEFAULT_DISPLAY, &hDevDisabled); } } } } }
if (!hDev) { //
// If no display driver initialized with the requested
// settings, put a message in the error log.
// (unless this was a change display settings call).
//
if (lpdevmodeInformation == NULL) { DrvLogDisplayDriverEvent(MsgInvalidDisplayDriver); } }
//
// Free memory allocated by DrvProbeAndCaptureDevmode
//
if (pdevmodeInformation && (pdevmodeInformation != &sourceDevmodeInformation)) { VFREEMEM(pdevmodeInformation); }
VFREEMEM(lpDisplayNames); } }
if (hDev) { PMDEV pmdevTmp;
TRACE_INIT(("Drv_Trace: DrvCreateMDEV: Display Driver Loaded successfully\n"));
//
// We installed a display driver successfully, so we
// know to exit out of the loop successfully.
//
displayInstalled = TRUE;
//
// Mark this device as being part of the primary device
//
if (primary) { PhysDisp->stateFlags |= DISPLAY_DEVICE_PRIMARY_DEVICE;
} else { //
// Otherwise, mask off it, since if this physical display
// was primary previously, it still keeps it, so need to
// mask of it.
//
PhysDisp->stateFlags &= ~DISPLAY_DEVICE_PRIMARY_DEVICE;
}
//
// If we haven't found the previously enabled hdev for this device
// look for it in the original mdev's list.
//
if (hDevDisabled == NULL && pMdevOrg != NULL) { for (ULONG i = 0; i < pMdevOrg->chdev; i++) { PDEVOBJ po((HDEV) pMdevOrg->Dev[i].hdev); PGRAPHICS_DEVICE pGraphicsDevice = po.ppdev->pGraphicsDevice;
if (PhysDisp == pGraphicsDevice) { hDevDisabled = pMdevOrg->Dev[i].hdev; } } } pmdev->Dev[pmdev->chdev].hdev = hDev; pmdev->Dev[pmdev->chdev].Reserved = hDevDisabled; pmdev->chdev += 1;
pmdevTmp = pmdev;
//
// We allocate and copy too much, but we don't care ...
//
pmdev = (PMDEV) PALLOCMEM(sizeof(MDEV) * (pmdevTmp->chdev + 1), GDITAG_DRVSUP);
if (pmdev) { //
// Compiler bug workaround MoveMemory instead of Copy
//
RtlMoveMemory(pmdev, pmdevTmp, sizeof(MDEV) * pmdevTmp->chdev);
VFREEMEM(pmdevTmp); } else { //
// We will exit the loop since we had a memory
// allocation failure.
//
pmdev = pmdevTmp; retStatus = STATUS_INSUFFICIENT_RESOURCES; } } }
/*****************************************************************
***************************************************************** Handle loop exit conditions ***************************************************************** *****************************************************************/
//
// If an error occured, we want to bring back the devices to their
// normal state.
//
if (!NT_SUCCESS(retStatus)) { break; }
//
// If there is no attached display drivers, then go to compatibility
// mode and load any display device except Disconnect driver.
// If still fails(only applies to local session, check it's headless
// server and try to load Disconnect driver
//
if (!displayInstalled && (GraphicsState == GraphicsStateFull)) { TRACE_INIT(("\n\nDrv_Trace: No attached device: Look for any device except dummy driver.\n\n")); GraphicsState = GraphicsStateNoAttach; continue; }
if (!displayInstalled && (GraphicsState == GraphicsStateNoAttach) && (gProtocolType == PROTOCOL_CONSOLE )) { TRACE_INIT(("\n\nDrv_Trace: No attached device: Look for any device including dummy driver.\n\n")); GraphicsState = GraphicsStateAttachDisconnect; continue; }
//
// If the display drivers have been installed, then look for the
// Mirroring devices - as long as we are not in basevideo !
//
if (displayInstalled && (bAttachMirroring == FALSE)) { TRACE_INIT(("\n\nDrv_Trace: DrvCreateMDEV: Look for Mirroring drivers\n\n")); bAttachMirroring = TRUE; continue; }
//
// We must be done. So if we did install the display driver, just
// break out of this.
//
if (displayInstalled) { retStatus = STATUS_SUCCESS; break; }
//
// There are no devices we can work with in the registry.
// We have a real failure and take appropriate action.
//
//
// If we failed on the first driver, then we can assume their is no
// driver installed.
//
if (devNum == 0) { WARNING("No kernel drivers initialized"); retStatus = STATUS_DEVICE_DOES_NOT_EXIST; break; }
//
// If the display driver is not installed, then this is another
// bad failure - report it.
//
if (!displayInstalled) { //This RIP is hit often in stress.
//RIP("Drv_Trace: DrvCreateMDEV: No display drivers loaded");
retStatus = STATUS_DRIVER_UNABLE_TO_LOAD; break; }
//
// Never get here !
//
retStatus = STATUS_UNSUCCESSFUL; }
/*****************************************************************
***************************************************************** Check Flags and calculate rectangles ***************************************************************** *****************************************************************/
TRACE_INIT(("\nDrv_Trace: DrvCreateMDEV: Check flags and rectangles\n"));
if (retStatus == STATUS_SUCCESS) { if (ulFlags & GRE_DISP_NOT_APARTOF_DESKTOP) { //
// This MDEV is created for additional secondary use.
// Don't change any attribute in PDEV based on this MDEV,
// since these PDEV could be a part of other MDEV which
// ,for example, represents current desktop.
//
} else { ULONG i; LPRECT pSrcRect = NULL; LPRECT pDstRect = NULL; PGRAPHICS_DEVICE PhysDisp; ULONG primary = 0; PGRAPHICS_DEVICE primaryPhysDisp = NULL; ULONG size;
//
// Make sure there is only one primary.
//
for (i = 0; i < pmdev->chdev; i++) { PDEVOBJ pdo(pmdev->Dev[i].hdev);
PhysDisp = pdo.ppdev->pGraphicsDevice;
//
// The first non-removable PhysDisp would be a primary candicate
//
if (PhysDisp->stateFlags & (DISPLAY_DEVICE_REMOVABLE | DISPLAY_DEVICE_MIRRORING_DRIVER)) { if (PhysDisp->stateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE) { TRACE_INIT(("Drv_Trace: DrvCreateMDEV: The primary desktop is on a removable or Mirror device.\n"));
PhysDisp->stateFlags &= ~DISPLAY_DEVICE_PRIMARY_DEVICE; } } else { if (primaryPhysDisp == NULL) { primary = i; } }
if (PhysDisp->stateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE) { if (primaryPhysDisp == NULL) { primaryPhysDisp = PhysDisp; primary = i; } else { ASSERTGDI(FALSE, "Two primary devices\n");
PhysDisp->stateFlags &= ~DISPLAY_DEVICE_PRIMARY_DEVICE;
retStatus = STATUS_DEVICE_CONFIGURATION_ERROR; } } }
//
// Create a list of rects which we can align.
//
size = pmdev->chdev * sizeof(RECT);
pSrcRect = (LPRECT) PALLOCNOZ(size, GDITAG_DRVSUP); pDstRect = (LPRECT) PALLOCNOZ(size, GDITAG_DRVSUP);
if (pSrcRect && pDstRect) { ULONG ci = 0;
for (i = 0; i < pmdev->chdev; i++) { PDEVOBJ pdo(pmdev->Dev[i].hdev); PDEVMODEW pdm = pdo.ppdev->ppdevDevmode;
//
// Reset the position rect with the real values.
//
(pSrcRect + i)->left = pdm->dmPosition.x; (pSrcRect + i)->top = pdm->dmPosition.y; (pSrcRect + i)->right = pdm->dmPosition.x + pdm->dmPelsWidth; (pSrcRect + i)->bottom = pdm->dmPosition.y + pdm->dmPelsHeight;
if (pdo.ppdev->pGraphicsDevice->stateFlags & DISPLAY_DEVICE_MIRRORING_DRIVER) {
} else { //
// Find a primary if we don't already have one.
// The first device with 0,0 as the origin will be it.
//
if ( (primaryPhysDisp == NULL) && (pdm->dmPosition.x == 0) && (pdm->dmPosition.y == 0) && ((pdo.ppdev->pGraphicsDevice->stateFlags & DISPLAY_DEVICE_REMOVABLE) == 0)) { primary = i; primaryPhysDisp = pdo.ppdev->pGraphicsDevice; }
ci++; } }
RtlCopyMemory(pDstRect, pSrcRect, size);
//
// Set the primary
//
PDEVOBJ pdo(pmdev->Dev[primary].hdev); pdo.ppdev->pGraphicsDevice->stateFlags |= DISPLAY_DEVICE_PRIMARY_DEVICE;
//
// NOTE
// CUDR_NOSNAPTOGRID == 1 in winuser.w
//
if (AlignRects(pDstRect, ci, primary, 1) == FALSE) { //
// Devices could not be aligned.
//
}
if (!RtlEqualMemory(pDstRect, pSrcRect, ci * sizeof(RECT))) { //
// Devices were repositioned
//
WARNING("GDI DDML: Device positions are adjusted"); }
//
// Let's save all these rectangles
//
TRACE_INIT(("Drv_Trace: DrvCreateMDEV: Reseting device positions\n"));
for (i = 0; i < pmdev->chdev; i++) { PDEVOBJ pdo(pmdev->Dev[i].hdev);
TRACE_INIT(("\t%ws: ", pdo.ppdev->pGraphicsDevice->szNtDeviceName));
//
// Set the surface's origin
//
pdo.ppdev->ptlOrigin = *((PPOINTL) (pDstRect + i));
//
// Notify the surface's origin to driver.
//
if (PPFNDRV(pdo,Notify)) { PPFNDRV(pdo,Notify)(pdo.pSurface()->pSurfobj(), DN_DEVICE_ORIGIN, (PVOID)(&(pdo.ppdev->ptlOrigin))); }
//
// Save the rectangle back into the mdev structure.
//
pmdev->Dev[i].rect = *(pDstRect + i);
#if DBG_BASIC
DbgPrint("GDI DDML: Device %d, position %d, %d, %d, %d, rotation %lu\n", i, pdo.pptlOrigin()->x, pdo.pptlOrigin()->y, pdo.pptlOrigin()->x + pdo.ppdev->ppdevDevmode->dmPelsWidth, pdo.pptlOrigin()->y + pdo.ppdev->ppdevDevmode->dmPelsHeight, pdo.ppdev->ppdevDevmode->dmDisplayOrientation * 90 );
if (pmdev->Dev[i].rect.left != pdo.pptlOrigin()->x) { DbgPrint("GDI DDML: Inconsistent rect left (%d) - origin left (%d)\n", pmdev->Dev[i].rect.left,pdo.pptlOrigin()->x); }
if (pmdev->Dev[i].rect.top != pdo.pptlOrigin()->y) { DbgPrint("GDI DDML: Inconsistent rect top (%d) - origin top (%d)\n", pmdev->Dev[i].rect.top,pdo.pptlOrigin()->y); }
if ((ULONG) pmdev->Dev[i].rect.right != pdo.pptlOrigin()->x + pdo.ppdev->ppdevDevmode->dmPelsWidth) { DbgPrint("GDI DDML: Inconsistent rect right (%d) - devmode right (%d)\n", pmdev->Dev[i].rect.right, pdo.pptlOrigin()->x + pdo.ppdev->ppdevDevmode->dmPelsWidth); }
if ((ULONG) pmdev->Dev[i].rect.bottom != pdo.pptlOrigin()->y + pdo.ppdev->ppdevDevmode->dmPelsHeight) { DbgPrint("GDI DDML: Inconsistent rect bottom (%d) - devmode bottom (%d)\n", pmdev->Dev[i].rect.bottom, pdo.pptlOrigin()->y + pdo.ppdev->ppdevDevmode->dmPelsHeight); } #endif
} }
if (pSrcRect) { VFREEMEM(pSrcRect); }
if (pDstRect) { VFREEMEM(pDstRect); } } }
if (!NT_SUCCESS(retStatus)) { //
// Delete all the hdevs we have created. and restore the old
// ones.
//
DrvBackoutMDEV(pmdev); VFREEMEM(pmdev); pmdev = NULL; }
#if TEXTURE_DEMO
pmdev = pmdevSetupTextureDemo(pmdev); #endif
//
// Dump the MDEV structure.
//
TRACE_INIT(("DrvCreateMDEV: Resulting MDEV\n")); TRACE_INIT(("pmdev = %08lx\n", pmdev));
if (pmdev) { ULONG i;
for (i = 0; i < pmdev->chdev; i++) { TRACE_INIT(("\t[%d].hdev = %08lx\n", i, pmdev->Dev[i].hdev)); TRACE_INIT(("\t[%d].rect = %d, %d, %d, %d,\n", i, pmdev->Dev[i].rect.left, pmdev->Dev[i].rect.top, pmdev->Dev[i].rect.right, pmdev->Dev[i].rect.bottom)); } }
return (pmdev); }
/***************************************************************************\
* DrvSetBaseVideo * * Initialize the graphics components of the system * * andreva Created \***************************************************************************/
VOID DrvSetBaseVideo( BOOL bSet ) { gbBaseVideo = bSet; }
/***************************************************************************\
* DrvCheckUpgradeSettings * * Check first boot from upgrade. If so, get last settings and move it * into normal setting registry. Otherwise, check if have registry settings * already, if not, move preferred mode into normal setting registry. * * dennyd Created \***************************************************************************/
DEFINE_GUID(GUID_DISPLAY_ADAPTER_INTERFACE, 0x5b45201d, 0xf2f2, 0x4f3b, 0x85, 0xbb, 0x30, 0xff, 0x1f, 0x95, 0x35, 0x99);
VOID DrvCheckUpgradeSettings(VOID) { PGRAPHICS_DEVICE PhysDisp; PWSTR SymbolicLinkList; UNICODE_STRING SymbolicLinkName; HANDLE hkRegistry = NULL; NTSTATUS Status; USHORT DualviewIndex; DEVMODEW devMode; BOOL bUpgraded; UNICODE_STRING SubKeyName; HANDLE hkSubKey = NULL; OBJECT_ATTRIBUTES ObjectAttributes; DWORD UsePreferredMode;
for (PhysDisp = gpGraphicsDeviceList; PhysDisp != NULL; PhysDisp = PhysDisp->pNextGraphicsDevice) { GUID Guid = GUID_DISPLAY_ADAPTER_INTERFACE; bUpgraded = FALSE; UsePreferredMode = 0; DualviewIndex = 0;
if (PhysDisp->pPhysDeviceHandle == NULL) continue; //
// Check if it's DualView second, assign an index to it
//
if (PhysDisp->stateFlags & DISPLAY_DEVICE_DUALVIEW) { PGRAPHICS_DEVICE PhysDisp1; for (PhysDisp1 = gpGraphicsDeviceList; PhysDisp1 != PhysDisp; PhysDisp1 = PhysDisp1->pNextGraphicsDevice) { if ((PhysDisp->stateFlags & DISPLAY_DEVICE_DUALVIEW) && (PhysDisp->pPhysDeviceHandle == PhysDisp1->pPhysDeviceHandle)) { DualviewIndex++; } } }
if (NT_SUCCESS(IoGetDeviceInterfaces(&Guid, (PDEVICE_OBJECT)PhysDisp->pPhysDeviceHandle, 0, &SymbolicLinkList)) ) { if (SymbolicLinkList[0] != L'\0') { WCHAR wstrSubKey[4];
RtlInitUnicodeString(&SymbolicLinkName, SymbolicLinkList);
if (NT_SUCCESS(IoOpenDeviceInterfaceRegistryKey(&SymbolicLinkName, KEY_ALL_ACCESS, &hkRegistry))) { ULONG defaultValue = 0, Attached;
//
// Read and delete the display settings
//
RtlZeroMemory(&devMode, sizeof(devMode)); swprintf(wstrSubKey, L"%d", DualviewIndex);
RTL_QUERY_REGISTRY_TABLE QueryTable[] = { {NULL, RTL_QUERY_REGISTRY_SUBKEY, wstrSubKey, NULL, REG_NONE, NULL, 0}, {NULL, RTL_QUERY_REGISTRY_DIRECT|RTL_QUERY_REGISTRY_DELETE, L"UsePreferredMode", &UsePreferredMode, REG_DWORD, &defaultValue, 4}, {NULL, RTL_QUERY_REGISTRY_DIRECT|RTL_QUERY_REGISTRY_DELETE, DefaultSettings[0], &devMode.dmBitsPerPel, REG_DWORD, &defaultValue, 4}, {NULL, RTL_QUERY_REGISTRY_DIRECT|RTL_QUERY_REGISTRY_DELETE, DefaultSettings[1], &devMode.dmPelsWidth, REG_DWORD, &defaultValue, 4}, {NULL, RTL_QUERY_REGISTRY_DIRECT|RTL_QUERY_REGISTRY_DELETE, DefaultSettings[2], &devMode.dmPelsHeight, REG_DWORD, &defaultValue, 4}, {NULL, RTL_QUERY_REGISTRY_DIRECT|RTL_QUERY_REGISTRY_DELETE, DefaultSettings[3], &devMode.dmDisplayFrequency, REG_DWORD, &defaultValue, 4}, {NULL, RTL_QUERY_REGISTRY_DIRECT|RTL_QUERY_REGISTRY_DELETE, DefaultSettings[4], &devMode.dmDisplayFlags, REG_DWORD, &defaultValue, 4}, {NULL, RTL_QUERY_REGISTRY_DIRECT|RTL_QUERY_REGISTRY_DELETE, DefaultSettings[7], &devMode.dmDisplayOrientation, REG_DWORD, &defaultValue, 4}, {NULL, RTL_QUERY_REGISTRY_DIRECT|RTL_QUERY_REGISTRY_DELETE, DefaultSettings[8], &devMode.dmDisplayFixedOutput, REG_DWORD, &defaultValue, 4}, {NULL, RTL_QUERY_REGISTRY_DIRECT|RTL_QUERY_REGISTRY_DELETE, DefaultSettings[9], &devMode.dmPosition.x, REG_DWORD, &defaultValue, 4}, {NULL, RTL_QUERY_REGISTRY_DIRECT|RTL_QUERY_REGISTRY_DELETE, DefaultSettings[10], &devMode.dmPosition.y, REG_DWORD, &defaultValue, 4}, {NULL, RTL_QUERY_REGISTRY_DIRECT|RTL_QUERY_REGISTRY_DELETE, DefaultSettings[11], &Attached, REG_DWORD, &defaultValue, 4}, {NULL, 0, NULL} };
if (NT_SUCCESS(RtlQueryRegistryValues(RTL_REGISTRY_HANDLE, (PWSTR)hkRegistry, &QueryTable[0], NULL, NULL)) && (devMode.dmPelsWidth != 0) && (!UsePreferredMode) ) { if (Attached) { devMode.dmFields |= DM_POSITION; }
DrvUpdateDisplayDriverParameters(PhysDisp, &devMode, (Attached == 0), TRUE); bUpgraded = TRUE; }
//
// Delete the subkey containing the display settings
//
RtlInitUnicodeString(&SubKeyName, wstrSubKey);
InitializeObjectAttributes(&ObjectAttributes, &SubKeyName, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, hkRegistry, NULL);
if (NT_SUCCESS(ZwOpenKey(&hkSubKey, KEY_ALL_ACCESS, &ObjectAttributes)) ) { ZwDeleteKey(hkSubKey); }
//
// Close the device interface registry key
//
ZwClose(hkRegistry); } } ExFreePool((PVOID)SymbolicLinkList); }
if (PhysDisp->stateFlags & DISPLAY_DEVICE_MIRRORING_DRIVER) { continue; }
//
// Check if there are still registry settings.
// If not, put preferred mode there.
//
PDEVMODEW pDevmode = (PDEVMODEW) PALLOCNOZ(sizeof(DEVMODEW) + MAXUSHORT, GDITAG_DEVMODE); if (pDevmode == NULL) { continue; }
RtlZeroMemory(pDevmode, sizeof(DEVMODEW)); pDevmode->dmSize = 0xDDDD; pDevmode->dmDriverExtra = MAXUSHORT;
if (UsePreferredMode || (!bUpgraded && (!NT_SUCCESS(DrvGetDisplayDriverParameters(PhysDisp, pDevmode, FALSE, FALSE)) || (pDevmode->dmPelsWidth == 0) ) ) ) { RtlZeroMemory(pDevmode, sizeof(DEVMODEW)); pDevmode->dmSize = sizeof(DEVMODEW);
if (NT_SUCCESS(DrvGetPreferredMode(pDevmode, PhysDisp))) { pDevmode->dmBitsPerPel = 32; pDevmode->dmFields |= DM_BITSPERPEL; DrvUpdateDisplayDriverParameters(PhysDisp, pDevmode, FALSE, TRUE); } }
VFREEMEM(pDevmode); } }
/***************************************************************************\
* DrvInitConsole * * Initialize the graphics components of the system * * andreva Created \***************************************************************************/
VOID DrvInitConsole( BOOL bEnumerationNeeded) { UNICODE_STRING UnicodeString; OBJECT_ATTRIBUTES ObjectAttributes; HANDLE hkRegistry = NULL; NTSTATUS Status; PGRAPHICS_DEVICE PhysDisp; PVOID RegistrationHandle;
/*****************************************************************
***************************************************************** BaseVideo ***************************************************************** *****************************************************************/
//
// Basevideo is considered a primary device in that the user will run
// the vga driver. This does override any other primary selection
// the user may have put in the registry.
//
RtlInitUnicodeString(&UnicodeString, L"\\Registry\\Machine\\System\\CurrentControlSet\\" L"Control\\GraphicsDrivers\\BaseVideo");
InitializeObjectAttributes(&ObjectAttributes, &UnicodeString, OBJ_CASE_INSENSITIVE|OBJ_KERNEL_HANDLE, NULL, NULL);
Status = ZwOpenKey(&hkRegistry, KEY_READ, &ObjectAttributes); #ifdef _HYDRA_
/*
* No base video for WinStations */ if ( !G_fConsole ) Status = STATUS_OBJECT_NAME_NOT_FOUND; #endif
if (NT_SUCCESS( Status)) { TRACE_INIT(("Drv_Trace: DrvInitConsole: Basevideo - FOUND\n"));
DrvSetBaseVideo(TRUE);
if (hkRegistry) ZwCloseKey(hkRegistry); } else { TRACE_INIT(("Drv_Trace: DrvInitConsole: Basevideo - NOT FOUND\n"));
DrvSetBaseVideo(FALSE); }
/*****************************************************************
***************************************************************** Device List ***************************************************************** *****************************************************************/
RtlZeroMemory(&gFullscreenGraphicsDevice, sizeof(GRAPHICS_DEVICE)); RtlZeroMemory(&gFeFullscreenGraphicsDevice, sizeof(GRAPHICS_DEVICE));
//
// Register for new device notifucations
//
#if 0
TRACE_INIT(("Drv_Trace: DrvInitConsole: Registering GUIDs\n"));
_asm {int 3};
Status = IoRegisterPlugPlayNotification ( EventCategoryDeviceInterfaceChange, PNPNOTIFY_DEVICE_INTERFACE_INCLUDE_EXISTING_INTERFACES, (LPGUID) &GUID_DISPLAY_DEVICE_INTERFACE_STANDARD, gpWin32kDriverObject, (PDRIVER_NOTIFICATION_CALLBACK_ROUTINE)DrvNewDisplayDevice, NULL, &RegistrationHandle);
if (!NT_SUCCESS(Status)) { ASSERTGDI(FALSE, "IoRegisterPlugPlayNotification(display) failed"); return; }
Status = IoRegisterPlugPlayNotification ( EventCategoryDeviceInterfaceChange, PNPNOTIFY_DEVICE_INTERFACE_INCLUDE_EXISTING_INTERFACES, (LPGUID) &GUID_DISPLAY_OUTPUT_INTERFACE_STANDARD, gpWin32kDriverObject, (PDRIVER_NOTIFICATION_CALLBACK_ROUTINE)DrvNewDisplayOutput, NULL, &RegistrationHandle);
if (!NT_SUCCESS(Status)) { ASSERTGDI(FALSE, "IoRegisterPlugPlayNotification(output) failed"); return; } #endif
DrvUpdateGraphicsDeviceList(TRUE, bEnumerationNeeded, gProtocolType == PROTOCOL_CONSOLE);
DrvCheckUpgradeSettings();
#if 0
DrvGetMirrorDrivers(); #endif
return; }
/***************************************************************************\
* DrvSetSharedDevLock * * routine to share devlock between parent and children. * * 05-Mar-1998 hideyukn Created \***************************************************************************/
VOID DrvSetSharedDevLock(PMDEV pmdev) { PDEVOBJ pdoParent(pmdev->hdevParent);
// Parent's DEVLOCK should not be shared.
ASSERTGDI(!pdoParent.bUseParentDevLock(), "DrvSetSharedDevLock():Parent PDEV has shared devlock\n");
for (ULONG i = 0; i < pmdev->chdev; i++) { PDEVOBJ pdo(pmdev->Dev[i].hdev);
// Set Parent PDEV as parent to each of the PDEVs that we'll manage.
pdo.ppdev->ppdevParent = (PDEV *) pmdev->hdevParent;
// Switch to use the shared DEVLOCK with parent.
pdo.vUseParentDevLock(); } }
/***************************************************************************\
* DrvRealizeHalftonePalette * * routine to realize halftone palette onto given device. * * 22-Apr-1998 hideyukn Created \***************************************************************************/
PPALETTE gppalHalftone = NULL; ULONG gulPalTimeForDDML = 0;
PPALETTE DrvRealizeHalftonePalette(HDEV hdevPalette, BOOL bForce) { BOOL bRet = FALSE;
PDEVOBJ pdoPalette(hdevPalette); XEPALOBJ palSurfObj(pdoPalette.ppalSurf());
if (bForce || (gulPalTimeForDDML != palSurfObj.ulTime())) { //
// Create display DC for palette device.
//
HDC hdcDevice = GreCreateDisplayDC(hdevPalette,DCTYPE_DIRECT,FALSE);
if (hdcDevice) { if (gppalHalftone == NULL) { //
// Create Win98 compatible halftone palette.
//
HPALETTE hPalette = GreCreateCompatibleHalftonePalette(hdcDevice);
if (hPalette) { EPALOBJ palObj(hPalette);
if (GreSetPaletteOwner(hPalette, OBJECT_OWNER_PUBLIC)) { //
// Put it into Global variable.
//
gppalHalftone = palObj.ppalGet(); } else { bDeletePalette((HPAL)hPalette,TRUE); } } else { WARNING("DrvRealizeHalftonePalette():Failed on GreCreateCompatibleHalftonePalette()"); } }
if (gppalHalftone) { //
// Selet the global halftone palette into the palette device.
//
HPALETTE hPalOld = GreSelectPalette(hdcDevice, (HPALETTE)gppalHalftone->hGet(), TRUE); // ForceBackgound
if (hPalOld) { XEPALOBJ palHTObj(gppalHalftone);
//
// Strip translation table.
//
palHTObj.vMakeNoXlate();
//
// Realize halftone palette on device. (device palette might be changed)
//
if (GreRealizePalette(hdcDevice)) { KdPrint(("DrvRealizeHalftonePalette():Device palette has been changed\n")); }
//
// Update palette time.
//
gulPalTimeForDDML = palSurfObj.ulTime();
//
// Select back old one.
//
GreSelectPalette(hdcDevice,hPalOld,FALSE);
bRet = TRUE; } else { WARNING("DrvRealizeHalftonePalette():Failed on GreSelectPalette()"); } } else { WARNING("DrvRealizeHalftonePalette():gppalHalftone is NULL"); }
bDeleteDCInternal(hdcDevice,TRUE,FALSE); } else { WARNING("DrvRealizeHalftonePalette():Failed on GreCreateDisplayDC()"); } } else { //
// Realization is still effective.
//
bRet = TRUE; }
//
// If we could not have halftone palette, just use default palette.
//
return (bRet ? gppalHalftone : ppalDefault); }
/***************************************************************************\
* DrvSetSharedPalette * * routine to share palette between parent and children. * * 22-Apr-1998 hideyukn Created \***************************************************************************/
BOOL MulSetPalette(DHPDEV,PALOBJ *,FLONG,ULONG,ULONG);
HDEV DrvSetSharedPalette(PMDEV pmdev) { HDEV hdevPalette = NULL;
//
// ToddLa's law - Palette should be shared with all paletaized monitors.
//
PDEVOBJ pdoParent(pmdev->hdevParent);
//ASSERTGDI((PPFNDRV(pdoParent,SetPalette)) == MulSetPalette,
// "DrvSetSharedPalette(): SetPalette != MulSetPalette\n");
PPALETTE ppalShared = NULL;
if (pdoParent.bIsPalManaged()) { //
// If parent is palette device, we shared it
// with all paletaized children.
//
ppalShared = pdoParent.ppalSurf();
//
// Remember the hdev which owns palette.
//
hdevPalette = pdoParent.hdev(); }
for (UINT i = 0; i < pmdev->chdev; i++) { PDEVOBJ pdoChild(pmdev->Dev[i].hdev);
if (pdoChild.bIsPalManaged()) { //
// Change pointer to DrvSetPalette to
// DDML, so that palette can be changed
// to a specific hdev, will be dispatch
// to every paletaized device.
//
pdoChild.pfnSetPalette(MulSetPalette);
if (ppalShared == NULL) { //
// Parent is not palette device, but
// this is palette device which we
// encounter first in the children,
// so we will share this palette.
//
ppalShared = pdoChild.ppalSurf();
//
// Remember the hdev which owns palette.
//
hdevPalette = pdoChild.hdev(); } else if (pdoChild.ppalSurf() != ppalShared) { //
// If the palette in hdev is already same as
// parent (mostly it is primary device, if
// primary is palette device.), don't
// need to update it. Otherwise update it here.
//
XEPALOBJ palChild(pdoChild.ppalSurf());
//
// Set colour table to shared palette.
//
palChild.apalColorSet(ppalShared); } } }
return (hdevPalette); }
/***************************************************************************\
* DrvTransferGdiObjects() * * Transfer belonging gdi object from a hdev to other. * * 04-Jul-1998 hideyukn Created \***************************************************************************/
#define DRV_TRANS_DC_TYPE 0x0001
#define DRV_TRANS_SURF_TYPE 0x0002
#define DRV_TRANS_DRVOBJ_TYPE 0x0004
#define DRV_TRANS_WNDOBJ_TYPE 0x0008
#define DRV_TRANS_ALL_TYPE 0x000F
#define DRV_TRANS_TO_CLONE 0x1000
VOID DrvTransferGdiObjects(HDEV hdevNew, HDEV hdevOld, ULONG ulFlags) { //
// 1) Change owner of DC_TYPE object.
//
// 2) Change owner of SURF_TYPE object.
//
// + ATI driver, for example, creates engine
// bitmap for thier banking, off-screen
// bitmap and ..., so need to change owner
// of those bitmap to clone's hdev.
//
// 3) Change owner of DRVOBJ_TYPE object.
//
// 4) Exchange WNDOBJ.
//
PDEVOBJ pdoNew(hdevNew); PDEVOBJ pdoOld(hdevOld);
ASSERTGDI(pdoNew.pSurface() == pdoOld.pSurface(), "DrvTransferGdiObjects():pSurface does not match\n");
ASSERTGDI(pdoNew.dhpdev() == pdoOld.dhpdev(), "DrvTransferGdiObjects():dhpdev does not match\n");
GreAcquireHmgrSemaphore();
HOBJ hobj = 0;
//
// Transfer DC which own by hdevCloned to hdevClone.
//
if (ulFlags & DRV_TRANS_DC_TYPE) { PDC pdc = NULL; hobj = 0;
while (pdc = (DC*) HmgSafeNextObjt(hobj, DC_TYPE)) { hobj = (HOBJ) pdc->hGet();
if ((HDEV)pdc->ppdev() == hdevOld) { KdPrint(("Transfer DC %x - hdevNew %x hdevOld %x \n", pdc->hGet(),hdevNew,hdevOld));
pdc->ppdev((PDEV *)pdoNew.hdev());
if (ulFlags & DRV_TRANS_TO_CLONE) { pdc->fsSet(DC_IN_CLONEPDEV); } else { pdc->fsClr(DC_IN_CLONEPDEV); }
pdoNew.vReferencePdev(); pdoOld.vUnreferencePdev(); } } }
//
// Transfer surface which own by old pdev to new pdev.
//
if (ulFlags & DRV_TRANS_SURF_TYPE) { SURFACE *pSurface = NULL; hobj = 0;
while (pSurface = (SURFACE*) HmgSafeNextObjt(hobj, SURF_TYPE)) { hobj = (HOBJ) pSurface->hGet();
if ((pSurface->hdev() == hdevOld) /* && pSurface->bDriverCreated() */) { KdPrint(("Transfer surface %x - hdevNew %x hdevOld %x \n", pSurface->hGet(),hdevNew,hdevOld));
pSurface->hdev(hdevNew); } } }
//
// Transfer DRVOBJ.
//
if (ulFlags & DRV_TRANS_DRVOBJ_TYPE) { DRVOBJ *pdrvo = NULL; hobj = 0;
while (pdrvo = (DRVOBJ*) HmgSafeNextObjt(hobj, DRVOBJ_TYPE)) { hobj = (HOBJ) pdrvo->hGet();
if (pdrvo->hdev == hdevOld) { KdPrint(("Transfer drvobj %x - hdevNew %x hdevOld %x \n", pdrvo->hGet(),hdevNew,hdevOld));
pdrvo->hdev = hdevNew; pdoNew.vReferencePdev(); pdoOld.vUnreferencePdev(); } } }
//
// Transfer WNDOBJ.
//
if (ulFlags & DRV_TRANS_WNDOBJ_TYPE) { vTransferWndObjs(pdoNew.pSurface(),pdoOld.hdev(),pdoNew.hdev()); }
GreReleaseHmgrSemaphore(); }
/***************************************************************************\
* DrvEnableDirectDrawForModeChange() * * 01-Aug-1998 hideyukn Created \***************************************************************************/
VOID DrvEnableDirectDrawForModeChange( HDEV *phdevList, BOOL bAlloc ) { ASSERTGDI(GreIsSemaphoreOwnedByCurrentThread(ghsemShareDevLock), "ShareDevlock must be held be before calling EnableDirectDraw");
ULONG chdev = (ULONG)(ULONG_PTR)(*phdevList); HDEV *phdev = phdevList + 1;
for (ULONG i = 0; i < chdev; i++) { GreResumeDirectDraw(*phdev, FALSE); phdev++; }
if (bAlloc) { VFREEMEM(phdevList); } }
/***************************************************************************\
* DrvDisableDirectDrawForModeChange() * * 01-Aug-1998 hideyukn Created \***************************************************************************/
HDEV * DrvDisableDirectDrawForModeChange( PMDEV pmdev1, PMDEV pmdev2, HDEV *phdevQuickList, ULONG chdevQuickList ) { HDEV *phdevList, *phdev; ULONG chdevList;
ASSERTGDI(GreIsSemaphoreOwnedByCurrentThread(ghsemShareDevLock), "ShareDevlock must be held be before calling DisableDirectDraw");
chdevList = pmdev1->chdev + pmdev2->chdev + 2;
if (chdevQuickList >= chdevList) { phdevList = phdevQuickList; } else { phdevList = (HDEV *)PALLOCNOZ(chdevList * sizeof(HDEV), 'pmtG');
if (phdevList == NULL) { return (NULL); } }
phdev = phdevList + 1; chdevList = 0;
if (pmdev1->hdevParent) { *phdev = pmdev1->hdevParent; phdev++; chdevList++; }
for (ULONG i = 0; i < pmdev1->chdev; i++) { *phdev = pmdev1->Dev[i].hdev; phdev++; chdevList++; }
if (pmdev2->hdevParent) { *phdev = pmdev2->hdevParent; phdev++; chdevList++; }
for (i = 0; i < pmdev2->chdev; i++) { *phdev = pmdev2->Dev[i].hdev; phdev++; chdevList++; }
*phdevList = (HDEV)ULongToPtr( chdevList );
for (i = 0; i < chdevList; i++) { PDEVOBJ pdo(phdevList[i+1]);
// Devlock must *not* be held.
pdo.vAssertNoDevLock();
GreSuspendDirectDrawEx(phdevList[i+1], DXG_SR_DDRAW_MODECHANGE); }
return (phdevList); }
//
// This function checks which Dualview Views will be attached. Then send a SWITCH_DUALVIEW
// notification to driver for setting of Video memory.
// It also checks if current DUALVIEW attachment state will be changed. The caller can decide
// if a PDEV can be reused or not.
//
// Return Value:
// DualviewNoSwitch: The DUALVIEW attachment state remains same
// DualviewSwitch: The DUALVIEW attachment state will be changed.
// DualviewFail: The DUALVIEW attachment state will be changed.
// And related PhysDisps have outstanding refcount and may get reused later
//
typedef enum _DUALVIEW_STATE { DualviewNoSwitch = 0, DualviewSwitch, DualviewFail } DUALVIEW_STATE;
DUALVIEW_STATE CheckAndNotifyDualView( PUNICODE_STRING pstrDeviceName, PMDEV pMdevOrg, MODE PreviousMode ) { PGRAPHICS_DEVICE PhysDisp; ULONG bResetAll, bytesReturned; ULONG primary, attach = 0; ULONG numDualViews = 0, i, j; BOOL bNoneToAttach = TRUE, bNoneAttached = TRUE; BOOL bChangeDualviewState = FALSE, bHasOutstanding = FALSE; DUALVIEW_STATE retVal;
typedef struct { PGRAPHICS_DEVICE PhysDisp; ULONG Attached; ULONG ToAttach; } ATTACHPHYSDISP, *PATTACHPHYSDISP; for (PhysDisp = gpGraphicsDeviceList; PhysDisp != NULL; PhysDisp = PhysDisp->pNextGraphicsDevice) { if (PhysDisp->stateFlags & DISPLAY_DEVICE_DUALVIEW) { numDualViews++; } }
if (numDualViews == 0) return DualviewNoSwitch;
PATTACHPHYSDISP AttachPhysDisp = (PATTACHPHYSDISP) PALLOCMEM(sizeof(ATTACHPHYSDISP)*numDualViews, GDITAG_DRVSUP);
if (AttachPhysDisp == NULL) return DualviewFail;
numDualViews = 0; for (PhysDisp = gpGraphicsDeviceList; PhysDisp != NULL; PhysDisp = PhysDisp->pNextGraphicsDevice) { if (PhysDisp->stateFlags & (DISPLAY_DEVICE_MIRRORING_DRIVER | DISPLAY_DEVICE_DISCONNECT)) { continue; }
if(!GetPrimaryAttachFlags(PhysDisp, &primary, &attach)) { VFREEMEM(AttachPhysDisp); return DualviewFail; } if (attach) { bNoneToAttach = FALSE; }
if (PhysDisp->stateFlags & DISPLAY_DEVICE_DUALVIEW) { AttachPhysDisp[numDualViews].PhysDisp = PhysDisp; AttachPhysDisp[numDualViews].ToAttach = (attach) ? 1 : 0; //
// Check if the PhysDisp is already attached in pMdevOrg
//
AttachPhysDisp[numDualViews].Attached = 0; if (pMdevOrg) { for (i = 0; i < pMdevOrg->chdev; i++) { PDEVOBJ po(pMdevOrg->Dev[i].hdev); if ((po.ppdev->pGraphicsDevice) == PhysDisp) { AttachPhysDisp[numDualViews].Attached = 1; bNoneAttached = FALSE; } } }
numDualViews++; } }
//
// A little patch for Attach flag from Registry. If all of PhysDisp are NotAttach
// in registry, CreateMDEV will pick the first PhysDisp to Attach. It is a typical
// situation right after clean setup.
//
if (bNoneToAttach) { for (PhysDisp = gpGraphicsDeviceList; PhysDisp != NULL; PhysDisp = PhysDisp->pNextGraphicsDevice) { if (!(PhysDisp->stateFlags & (DISPLAY_DEVICE_MIRRORING_DRIVER | DISPLAY_DEVICE_DISCONNECT))) { if (PhysDisp->stateFlags & DISPLAY_DEVICE_DUALVIEW) { AttachPhysDisp[0].ToAttach = 1; } break; } } }
if (!pstrDeviceName) {
for (i = 0; i < numDualViews; i++) { if (AttachPhysDisp[i].Attached != AttachPhysDisp[i].ToAttach || pMdevOrg == NULL) { bChangeDualviewState = TRUE; } } } else { //
// Never allow ChangeDisplaySettings("\\.\DisplayX") to attach/detach one of Dualview
//
PhysDisp = DrvGetDeviceFromName(pstrDeviceName, PreviousMode); if (PhysDisp) { for (i = 0; i < numDualViews; i++) { if (PhysDisp == AttachPhysDisp[i].PhysDisp) { if (AttachPhysDisp[i].Attached != AttachPhysDisp[i].ToAttach || pMdevOrg == NULL) { bChangeDualviewState = TRUE; bHasOutstanding = TRUE; } break; } } } }
if (bChangeDualviewState) { if (bHasOutstanding) { retVal = DualviewFail; //
// If we cannot change mode due to Dualview, restore the original
// attch state in case of surprise mode change later. Since CPL
// won't restore te attach flag.
//
if (pMdevOrg) { for (i = 0; i < numDualViews; i++) { DrvUpdateAttachFlag(PhysDisp, AttachPhysDisp[i].Attached); } } } else { retVal = DualviewSwitch; //
// Send driver the Dualview state change notification
//
if (!pstrDeviceName) { for (i = 0; i < numDualViews; i++) { GreDeviceIoControl(AttachPhysDisp[i].PhysDisp->pDeviceHandle, IOCTL_VIDEO_SWITCH_DUALVIEW, &(AttachPhysDisp[i].ToAttach), sizeof(ULONG), NULL, 0, &bytesReturned); } } else { ASSERTGDI(FALSE, "Trying to attach/detach a view by ChangeDisplaySettings(DisplayX)\n"); } } } else { retVal = DualviewNoSwitch; }
//
// After sending the notification, the the driver may change mode list internally.
// Force PhysDisp to update mode list here
//
for (i = 0; i < numDualViews; i++) { DrvBuildDevmodeList(AttachPhysDisp[i].PhysDisp, TRUE); } VFREEMEM(AttachPhysDisp);
return retVal; }
/***************************************************************************\
* DrvChangeDisplaySettings * * Routines to change the settings of a display device. * * andreva Created \***************************************************************************/
BOOL MulEnableDriver(ULONG,ULONG,PDRVENABLEDATA); BOOL PanEnableDriver(ULONG,ULONG,PDRVENABLEDATA);
LONG DrvChangeDisplaySettings( PUNICODE_STRING pstrDeviceName, HDEV hdevPrimary, LPDEVMODEW lpDevMode, PVOID pDesktopId, MODE PreviousMode, BOOL bUpdateRegistry, BOOL bSetMode, PMDEV pOrgMdev, PMDEV *pNewMdev, DWORD PruneFlag, BOOL bTryClosest ) { GDIFunctionID(DrvChangeDisplaySettings);
PGRAPHICS_DEVICE PhysDisp = NULL; UNICODE_STRING DeviceName; PDEVMODEW pdevmodeInformation = NULL; BOOL bDetach = FALSE; LONG status = GRE_DISP_CHANGE_SUCCESSFUL; ULONG defaultValue = 0; ULONG disableAll; ULONG i, j; PMDEV pmdev; BOOL bPrune = (PruneFlag != GRE_RAWMODE); #if DBG
ULONG oldTrace; #endif
RTL_QUERY_REGISTRY_TABLE QueryTable[] = { {NULL, RTL_QUERY_REGISTRY_DIRECT, L"DisableAll", &disableAll, REG_DWORD, &defaultValue, 4}, {NULL, 0, NULL} };
TRACE_INIT(("Drv_Trace: DrvChangeDisplaySettings - Enter\n"));
*pNewMdev = NULL; gbInvalidateDualView = FALSE;
//
// Let's find the device on which the operation must be performed.
//
if (pstrDeviceName) { PhysDisp = DrvGetDeviceFromName(pstrDeviceName, PreviousMode);
if (PhysDisp == NULL) { TRACE_INIT(("Drv_Trace: DrvChangeDisplaySettings - Leave - Bad Device\n")); return GRE_DISP_CHANGE_BADPARAM; } } else { //
// If (NULL, NULL) is passed in, then we want to change the
// default desktop back to what it was ...
// Otherwise, for compatibility, (NULL, DEVMODE) affect only the
// primary device.
//
if (lpDevMode) { PDEVOBJ pdo(hdevPrimary);
if (pdo.bValid()) { PhysDisp = pdo.ppdev->pGraphicsDevice; }
if (PhysDisp == NULL) { TRACE_INIT(("Drv_Trace: DrvChangeDisplaySettings - Leave - Bad Device\n")); return GRE_DISP_CHANGE_BADPARAM; } } }
if (PhysDisp == (PGRAPHICS_DEVICE) DDML_DRIVER) { ASSERTGDI(FALSE, "Trying to change settings for DDML layer\n"); return GRE_DISP_CHANGE_BADPARAM; }
if (PhysDisp != NULL) {
if (PruneFlag == GRE_DEFAULT) bPrune = DrvGetPruneFlag(PhysDisp);
RtlInitUnicodeString(&DeviceName, PhysDisp->szWinDeviceName); pstrDeviceName = &DeviceName;
if (lpDevMode != NULL) { #if DBG
//
// less debug output for DirectDraw :
//
oldTrace = GreTraceDisplayDriverLoad;
if (!bUpdateRegistry && !bSetMode) { GreTraceDisplayDriverLoad &= 0xFFFFFFF0; } #endif
//
// Get the new DEVMODE.
//
if (!NT_SUCCESS(DrvProbeAndCaptureDevmode(PhysDisp, &pdevmodeInformation, &bDetach, lpDevMode, FALSE, PreviousMode, bPrune, bTryClosest, FALSE))) { if (pdevmodeInformation) { VFREEMEM(pdevmodeInformation); }
TRACE_INIT(("Drv_Trace: DrvChangeDisplaySettings - Leave - Bad Devmode\n")); return GRE_DISP_CHANGE_BADMODE; }
if (lpDevMode->dmFields == 0) bTryClosest = TRUE;
#if DBG
GreTraceDisplayDriverLoad = oldTrace; #endif
} else{ // For registry settings, always use closest
bTryClosest = TRUE; } }
//
// At this point we have validated all data.
// So if the user just tested the mode, the call would now be successful
//
// Let's see if we actually need to do something with this mode.
//
//
// Write the data to the registry.
//
// This is not supported for the vgacompatible device - so it should just fail.
//
if (bUpdateRegistry && (PhysDisp != NULL) && (lpDevMode != NULL) && (gProtocolType == PROTOCOL_CONSOLE)) { //
// Check if the Administrator has disabled this privilege.
// It is on by default.
//
disableAll = 0;
RtlQueryRegistryValues(RTL_REGISTRY_CONTROL, L"GraphicsDrivers\\PermanentSettingChanges", &QueryTable[0], NULL, NULL);
if (disableAll) { status = GRE_DISP_CHANGE_NOTUPDATED; } else { NTSTATUS retStatus = DrvUpdateDisplayDriverParameters(PhysDisp, pdevmodeInformation, bDetach, TRUE);
if (!NT_SUCCESS(retStatus)) { status = GRE_DISP_CHANGE_BADMODE; if (retStatus == STATUS_INVALID_PARAMETER_4) { status = GRE_DISP_CHANGE_BADPARAM; } } }
TRACE_INIT(("Drv_Trace: DrvChangeDisplaySettings - Save Params status %d\n", status)); }
//
// Set the mode dynamically
//
if (bSetMode && (status == GRE_DISP_CHANGE_SUCCESSFUL)) { ASSERTGDI(pOrgMdev == NULL || DrvQueryMDEVPowerState(pOrgMdev), "DrvChangeDisplaySettings called with powered off MDEV.\n");
#if MDEV_STACK_TRACE_LENGTH
LONG lMDEVTraceEntry, lMDEVTraceEntryNext; ULONG StackEntries, UserStackEntry;
do { lMDEVTraceEntry = glMDEVTrace; lMDEVTraceEntryNext = lMDEVTraceEntry + 1; if (lMDEVTraceEntryNext >= gcMDEVTraceLength) lMDEVTraceEntryNext = 0; } while (InterlockedCompareExchange(&glMDEVTrace, lMDEVTraceEntryNext, lMDEVTraceEntry) != lMDEVTraceEntry);
RtlZeroMemory(&gMDEVTrace[lMDEVTraceEntry], sizeof(gMDEVTrace[lMDEVTraceEntry])); gMDEVTrace[lMDEVTraceEntry].pMDEV = pOrgMdev; gMDEVTrace[lMDEVTraceEntry].API = DrvChangeDisplaySettings_SetMode; StackEntries = sizeof(gMDEVTrace[lMDEVTraceEntry].Trace)/sizeof(gMDEVTrace[lMDEVTraceEntry].Trace[0]); UserStackEntry = RtlWalkFrameChain((PVOID *)gMDEVTrace[lMDEVTraceEntry].Trace, StackEntries, 0); StackEntries -= UserStackEntry; RtlWalkFrameChain((PVOID *)&gMDEVTrace[lMDEVTraceEntry].Trace[UserStackEntry], StackEntries, 1); #endif
//
// First things first, acquire share dev lock. This must
// be acquired before any other dev locks are acquired.
//
GreAcquireSemaphoreEx(ghsemShareDevLock, SEMORDER_SHAREDEVLOCK, NULL); CModeChangeInProgress mcip;
//
// Check if there are restrictions on changing the resolution
// dymanically
// Restriction don't apply for booting the machine though ...
//
pmdev = NULL; status = GRE_DISP_CHANGE_FAILED; disableAll = 0;
RtlQueryRegistryValues(RTL_REGISTRY_CONTROL, L"GraphicsDrivers\\TemporarySettingChanges", &QueryTable[0], NULL, NULL);
if ((disableAll == 0) || (pOrgMdev == NULL)) { //
// Lets create a new MDEV
//
if (pOrgMdev) { PDEVOBJ pdoTmp(pOrgMdev->hdevParent); ASSERTGDI(pdoTmp.cPdevRefs() > 10, "curent MDEV is not the main one !\n");
//
// Dualview preprocess. We probe the registry first to see if
// the second view is about to be attached. The we notify the miniport
// before the first PDEV is created.
//
// If DUALVIEW attachment state changes, all PDEVs has to be regenerated.
// Even a PDEV with same settings cannot be reused.
//
// However, if there is D3D running, a PDEV cannot be simply regenerated
// due to ALT-TAB feature (a PDEV has an extra refcount for D3D apps). We
// cannot do anything but fail
//
switch (CheckAndNotifyDualView(pstrDeviceName, pOrgMdev, PreviousMode)) { case DualviewNoSwitch: gbInvalidateDualView = FALSE; break; case DualviewSwitch: gbInvalidateDualView = TRUE; bTryClosest = TRUE; break; default: mcip.vDone(); GreReleaseSemaphoreEx(ghsemShareDevLock); return GRE_DISP_CHANGE_BADDUALVIEW; }
//
// Disable current MDEV.
//
// FALSE here, means ONLY meta PDEV will be disabled in
// multi monitor case. And hardware will not be disabled
// in single monitor cases.
//
if (DrvDisableMDEV(pOrgMdev, FALSE)) { //
// Create new MDEV
//
// If we will create new HDEV which device is used
// in current (= old) MDEV. HDEV in old MDEV will
// be disabled, and stored in MDEV.Dev[x].Reserved
// for recover current config in error case later.
//
pmdev = DrvCreateMDEV(pstrDeviceName, pdevmodeInformation, pDesktopId, 0, pOrgMdev, KernelMode, PruneFlag, bTryClosest);
if (!pmdev) {
// At this point, we have failed to create MDEV based on
// new configuration, so status continue to keep
// GRE_DISP_CHANGE_FAILED. And re-enable original MDEV.
//
DrvEnableMDEV(pOrgMdev, FALSE); } else { //
// At this point, we have all the hdevs involved in the
// switch.
//
// On entering this functions
// pOrgMdev - list of original hdevs
// pmdev - list of new hdevs
// reserved fields have the hdevs that were disabled
//
// On exit
// pmdev - list of old (permanent) and new hdevs for user
// pOrgMdev - unused
//
status = GRE_DISP_CHANGE_NO_CHANGE;
//
// Determine if anything changed in the two structures
//
if (pmdev->chdev != pOrgMdev->chdev) { status = GRE_DISP_CHANGE_SUCCESSFUL; } else { for (i=0 ; i <pmdev->chdev; i++) { if ((pmdev->Dev[i].hdev != pOrgMdev->Dev[i].hdev) || (!RtlEqualMemory(&(pmdev->Dev[i].rect), &(pOrgMdev->Dev[i].rect), sizeof(RECT)))) { status = GRE_DISP_CHANGE_SUCCESSFUL; } } } } } } else { TRACE_INIT(("DrvChangeDisplaySettings - no original MDEV, create one\n"));
//
// Dualview preprocess.
//
CheckAndNotifyDualView(pstrDeviceName, NULL, PreviousMode); gbInvalidateDualView = TRUE;
pmdev = DrvCreateMDEV(pstrDeviceName, pdevmodeInformation, pDesktopId, 0, NULL, KernelMode, PruneFlag, bTryClosest);
if (pmdev) { status = GRE_DISP_CHANGE_SUCCESSFUL; } } }
*pNewMdev = pmdev;
//
// If everything worked, but the two structures are not identical, do
// the switching around.
//
// Handle the four seperate case :
// 1-1, 1-many, many-1 and many-many
//
BOOL bSwitchError = FALSE;
HDEV hdevTmp; HDEV hdevClone = NULL; HDEV hdevCloned = NULL;
BOOL bSwitchParentAndChild = FALSE; BOOL bEnableClone = FALSE;
if (status == GRE_DISP_CHANGE_SUCCESSFUL) { ULONG iClonehdev = 0; HDEV *phdevDDLock = NULL; HDEV ahdevDDLockQuick[7];
MULTIDEVLOCKOBJ mdloMdev; MULTIDEVLOCKOBJ mdloOrgMdev;
HSEMAPHORE hsemCloneHdevDevLock = NULL; HSEMAPHORE hsemOrgMdevDevLock = NULL; HSEMAPHORE hsemOrgMdevPointer = NULL;
if (pOrgMdev) { BOOL bLockSemaphore = FALSE;
//
// Disable DirectDraw on both MDEV's. This must be done
// before we acquire the Devlock.
//
phdevDDLock = DrvDisableDirectDrawForModeChange( pOrgMdev,pmdev, (HDEV *)ahdevDDLockQuick, sizeof(ahdevDDLockQuick)/sizeof(HDEV));
if (phdevDDLock == NULL) { bSwitchError = TRUE; } else { //
// The following lock rules must be abided, otherwise deadlocks may
// arise:
//
// o DevLock must be acquired after the ShareDevLock
// o Pointer lock must be acquired after Devlock (GreSetPointer);
// o RFont list lock must be acquired after Devlock (TextOut);
// o Handle manager lock must be acquired after Devlock (old
// CvtDFB2DIB);
// o Handle manager lock must be acquired after Palette Semaphore
// (GreSetPaletteEntries)
// o Palette Semaphore must be acquired after Devlock (BitBlt)
// o Palette Semaphore must be acquired after driver semaphore
// (bDeletePalette)
//
// So we acquire locks in the following order (note that the
// vAssertDynaLock() routines should be modified if this list ever
// changes):
//
//
// At this point, we have *not* ssyned devlock for new MDEV, yet,
// so lock all children. During the mode change. we don't want to
// anything change in its children.
//
mdloOrgMdev.vInit(pOrgMdev); mdloMdev.vInit(pmdev);
if (mdloMdev.bValid() && mdloOrgMdev.bValid()) { PDEVOBJ pdoTmp;
pdoTmp.vInit(pOrgMdev->hdevParent); hsemOrgMdevDevLock = pdoTmp.hsemDevLock(); hsemOrgMdevPointer = pdoTmp.hsemPointer();
//
// Lock the parent of MDEV.
//
GreAcquireSemaphoreEx(hsemOrgMdevDevLock, SEMORDER_DEVLOCK, NULL);
//
// Lock the pointer in old mdev's parent.
//
GreAcquireSemaphoreEx(hsemOrgMdevPointer, SEMORDER_POINTER, hsemOrgMdevDevLock);
//
// Lock the children in MDEVs
//
mdloOrgMdev.vLock(); // No drawing to any dynamic surfaces
mdloMdev.vLock(); // No drawing to any dynamic surfaces
// WinBug #301042 3-1-2001 jasonha
// GDI: SPRITESTATE duplicated and inconsistent when cloning
// When cloning is used two PDEV (and therefore two SPRITESTATEs)
// try to manage the same display (psoScreen). Hooking one
// while 'Inside' the other will confuse the state. Hooking
// will only change if there are visible sprites; so we
// will temporarily hide them all. Later we will unhide all
// sprites on the whichever MDEV will remain active.
//
// Hide all sprites
//
vSpHideSprites(pOrgMdev->hdevParent, TRUE);
//
// Fixup new and old MDEVs.
//
if ((pmdev->chdev == 1) && (pOrgMdev->chdev != 1)) { //
// Many to 1
//
for (i=0 ; i <pOrgMdev->chdev; i++) { if (pOrgMdev->Dev[i].hdev == pmdev->Dev[0].hdev) { TRACE_INIT(("DrvChangeDisplaySettings: creating clone\n"));
//
// DrvCreateCloneHDEV will creates exactly same HDEV with
// different handle.
//
hdevClone = DrvCreateCloneHDEV( pmdev->Dev[0].hdev, DRV_CLONE_DEREFERENCE_ORG);
if (hdevClone) { //
// Replace the hdev with clone, and save original
// into reserved fields for later to back out
// mode change if error happens.
//
pOrgMdev->Dev[i].hdev = hdevClone; pOrgMdev->Dev[i].Reserved = pmdev->Dev[0].hdev;
hdevCloned = pmdev->Dev[0].hdev; iClonehdev = i; } else { bSwitchError = TRUE; }
//
// Shouldn't be another same HDEV in MDEV,
// so, just go out loop here...
//
break; } } } else if ((pmdev->chdev != 1) && (pOrgMdev->chdev == 1)) { //
// 1 to Many
//
//
// [Case 1] - Attach new monitor, and some change has been made on existing
//
// At this case, new MDEV will everything new HDEV, like...
//
// Org MDEV - ATI: 800x600 8bpp (HDEV is A)
//
// New MDEV - ATI: 1024x768 24bpp (HDEV is B)
// MGA: 1024x768 32bpp (HDEV is C)
// Parent: Created based on B and C (HDEV is D)
// then,
//
// 1) mode change between "A" and "D".
// 2) flip handle (set "A" to where "D" is, and set "D" to where "A" is).
//
// So that finally "A" becomes a parent of "B" and "C". then delete "D".
//
// [Case 2] - Attach new monitor.
//
// At this case, new MDEV will contains previous HDEV, since original
// monitor is nothing changed, so it looks like...
//
// Org MDEV - ATI: 1024x768 24bpp (HDEV is A)
//
// New MDEV - ATI: 1024x768 24bpp (HDEV is A)
// MGA: 1024x768 32bpp (HDEV is C)
// Parent: Created based on A and C (HDEV is D)
//
// In this case, we can *not* mode change, because if we do mode
// change between "A" and "D", then we flip the handle, "A"
// becomes a parent of "A" and "C" (since when we create "D", it
// children are "A" and "C". when we create parent, parent can know
// and cache into thier local, who is thier children.
// (see Multi.cxx MulEnablePDEV()) "A" can not be a parent of "A".
//
// Thus, how we do there is just create a clone (= "B") of "A", and replace
// "A" with "B" in new MDEV, so new MDEV will be like,
//
// New MDEV - ATI: 1024x768 24bpp (HDEV is B) (clone of A)
// MGA: 1024x768 32bpp (HDEV is C)
// Parent: Created based on B and C (HDEV is D)
//
// Of course we can do notify to parent driver to one of thier
// child "A" is replaced with "D" and do same for new MDEV, to
// avoid to create clone. But it too complex to re-initialized
// parent "A" based on "D" and "C", and what-else will problem later on.
// So here we just create a clone, so that we can take a same
// code path as 1) except create a clone, here.
//
// Then, (actually here is same as case 1)
//
// 1) mode change between "A" and "D".
// 2) flip handle (set "A" to where "D" is, and set "D" to where "A" is).
//
// So that finally "A" becomes a parent of "B" and "C". then delete "D".
//
//
// Do we have any re-used original HDEV in new MDEV ?
//
for (i=0 ; i <pmdev->chdev; i++) { if (pmdev->Dev[i].hdev == pOrgMdev->Dev[0].hdev) { TRACE_INIT(("DrvChangeDisplaySettings: creating clone\n"));
//
// DrvCreateCloneHDEV will creates exactly same HDEV with
// different handle.
//
hdevClone = DrvCreateCloneHDEV( pOrgMdev->Dev[0].hdev, DRV_CLONE_DEREFERENCE_ORG);
if (hdevClone) { //
// Replace the hdev with clone, and save original
// into reserved fields for later to back out
// mode change if error happens.
//
pmdev->Dev[i].hdev = hdevClone; pmdev->Dev[i].Reserved = pOrgMdev->Dev[0].hdev;
hdevCloned = pOrgMdev->Dev[0].hdev;
//
// Later we need copy data to Clone from Cloned.
//
bEnableClone = TRUE; } else { bSwitchError = TRUE; }
//
// Shouldn't be another same HDEV in MDEV,
// so, just go out loop here...
//
break; } }
if (bSwitchError == FALSE) { //
// We will switch between parent and children
//
bSwitchParentAndChild = TRUE; } } else { //
// 1 to 1, Many to Many
//
}
if (hdevClone) { pdoTmp.vInit(hdevClone); hsemCloneHdevDevLock = pdoTmp.hsemDevLock();
//
// If we creates any clone device, hold devlock here.
//
GreAcquireSemaphoreEx(hsemCloneHdevDevLock, SEMORDER_DEVLOCK, NULL); }
if (bSwitchError == FALSE) { //
// Lock rest of semaphores which we should hold during mode change.
//
GreAcquireSemaphoreEx(ghsemDriverMgmt, SEMORDER_DRIVERMGMT, NULL); // No driver loading/unloading
GreAcquireSemaphoreEx(ghsemPalette, SEMORDER_DRIVERMGMT, NULL); // No SaveDC/RestoreDC
GreAcquireSemaphoreEx(ghsemPublicPFT, SEMORDER_PUBLICPFT, NULL); // Nobody else uses the font table
GreAcquireSemaphoreEx(ghsemRFONTList, SEMORDER_RFONTLIST, NULL); // Nobody else uses the RFONT list
//
// Lock handle manager to prevent new handle being created, or
// deleting existing handle. so that we can safely walk through
// handle manager list.
//
GreAcquireHmgrSemaphore();
bLockSemaphore = TRUE; } } else { bSwitchError = TRUE; } }
if (bSwitchError == FALSE) { ASSERTGDI(bLockSemaphore == TRUE, "DrvChangeDisplaySettings(): Semaphores is not locked\n");
//
// Do the mode change for children device.
//
if (pmdev->chdev == 1) { if (pOrgMdev->chdev == 1) { //
// 1 to 1
//
TRACE_INIT(("Drv_Trace: DrvChangeDisplaySettings: Mode Change 1 -> 1.\n"));
if (bDynamicModeChange(pOrgMdev->Dev[0].hdev, pmdev->Dev[0].hdev) == TRUE) { hdevTmp = pOrgMdev->Dev[0].hdev; pOrgMdev->Dev[0].hdev = pmdev->Dev[0].hdev; pmdev->Dev[0].hdev = hdevTmp; } else { // Error occured
bSwitchError = TRUE; } } else { //
// Many to 1
//
TRACE_INIT(("Drv_Trace: DrvChangeDisplaySettings: Mode Change Many -> 1.\n"));
if (bSwitchError == FALSE) { #ifdef DONT_CHECKIN
if (hdevClone) { //
// Transfer DC_TYPE objects to clone.
//
DrvTransferGdiObjects(pOrgMdev->Dev[iClonehdev].hdev, pmdev->Dev[0].hdev, DRV_TRANS_DC_TYPE | DRV_TRANS_TO_CLONE); } #endif
if (bDynamicModeChange(pOrgMdev->hdevParent, pmdev->Dev[0].hdev) == TRUE) { hdevTmp = pOrgMdev->hdevParent; pOrgMdev->hdevParent = pmdev->Dev[0].hdev; pmdev->Dev[0].hdev = hdevTmp;
if (hdevClone) { hdevCloned = hdevTmp;
#ifdef DONT_CHECKIN
//
// Transfer back DC_TYPE objects in clone to original.
//
DrvTransferGdiObjects(pmdev->Dev[0].hdev, pOrgMdev->Dev[iClonehdev].hdev, DRV_TRANS_DC_TYPE); #endif
} } else { // Error occured
bSwitchError = TRUE; } } } } else { if (pOrgMdev->chdev == 1) { //
// 1 to Many
//
TRACE_INIT(("Drv_Trace: DrvChangeDisplaySettings: Mode Change 1 -> Many.\n")); } else { //
// Many to Many
//
TRACE_INIT(("Drv_Trace: DrvChangeDisplaySettings: Mode Change Many -> Many.\n"));
for (i=0 ; i <pmdev->chdev; i++) { PDEVOBJ pdo1(pmdev->Dev[i].hdev);
for (j=0 ; j <pOrgMdev->chdev; j++) { PDEVOBJ pdo2(pOrgMdev->Dev[j].hdev);
if (pdo1.ppdev->pGraphicsDevice == pdo2.ppdev->pGraphicsDevice) { if (pmdev->Dev[i].hdev == pOrgMdev->Dev[j].hdev) { // Same hdev, nothing need to do.
} else if (bDynamicModeChange(pOrgMdev->Dev[j].hdev, pmdev->Dev[i].hdev) == TRUE) { hdevTmp = pOrgMdev->Dev[j].hdev; pOrgMdev->Dev[j].hdev = pmdev->Dev[i].hdev; pmdev->Dev[i].hdev = hdevTmp; } else { // Error occured
bSwitchError = TRUE; }
break; } } } } }
//
// Release handle manager lock.
//
GreReleaseHmgrSemaphore();
//
// Now, we are finished all mode changes for parent and children
// so we are safe to unlock it.
//
GreReleaseSemaphoreEx(ghsemRFONTList); GreReleaseSemaphoreEx(ghsemPublicPFT); GreReleaseSemaphoreEx(ghsemPalette); GreReleaseSemaphoreEx(ghsemDriverMgmt);
//
// Mark as unlocked.
//
bLockSemaphore = FALSE; } }
//
// If we need to create a new parent and do a switch, now is
// the time.
//
if (bSwitchError == FALSE) { //
// Setup the parent hdev for old MDEV (if old MDEV is provided).
//
if (pOrgMdev) { if (pOrgMdev->chdev == 1) { //
// 1 to 1, 1 to Many.
//
pOrgMdev->hdevParent = pOrgMdev->Dev[0].hdev; pOrgMdev->Reserved = pOrgMdev->Dev[0].Reserved; // actually not nessesary...
} else { //
// Many to 1, Many to Many.
//
} }
//
// Setup the parent hdev for new MDEV.
//
if (pmdev->chdev == 1) { //
// 1 to 1, Many to 1.
//
TRACE_INIT(("Drv_Trace: DrvCompleteMDEV: Single Device\n"));
pmdev->hdevParent = pmdev->Dev[0].hdev; pmdev->Reserved = pmdev->Dev[0].Reserved; } else { //
// 1 to Many, Many to Many.
//
TRACE_INIT(("Drv_Trace: DrvChangeDisplaySettings: Create new Parent MDEV (Many/1 -> Many)\n"));
//
// If we have more than one device that is attached to the
// desktop, then we need to create the META structure for
// that device, initialize it, and use that as the primary
// device.
//
DRV_NAMES drvName; HDEV hdevDisabled;
TRACE_INIT(("Drv_Trace: DrvCompleteMDEV: Create HMDEV\n"));
drvName.cNames = 1; drvName.D[0].hDriver = NULL; drvName.D[0].lpDisplayName = (LPWSTR)MulEnableDriver;
pmdev->hdevParent = hCreateHDEV((PGRAPHICS_DEVICE) DDML_DRIVER, &drvName, ((PDEVMODEW)(pmdev)), pmdev->pDesktopId, DRIVER_CAPABLE_ALL, DRIVER_ACCELERATIONS_FULL, TRUE, // ignored in this case
GCH_DDML, &hdevDisabled);
if (!pmdev->hdevParent) { RIP("Drv_Trace: DrvCompleteMDEV: DDML failed"); bSwitchError = TRUE; } else { if (pOrgMdev != NULL) { PDEVOBJ pdoParent(pmdev->hdevParent); HSEMAPHORE hsemParentDevLock = pdoParent.hsemDevLock();
//
// During the mode change devlock should be hold for parent
//
GreAcquireSemaphoreEx(hsemParentDevLock, SEMORDER_DEVLOCK, NULL); GreAcquireSemaphoreEx(ghsemDriverMgmt, SEMORDER_DRIVERMGMT, NULL); GreAcquireSemaphoreEx(ghsemPalette, SEMORDER_PALETTE, NULL); GreAcquireSemaphoreEx(ghsemPublicPFT, SEMORDER_PUBLICPFT, NULL); // Nobody else uses the font table
GreAcquireSemaphoreEx(ghsemRFONTList, SEMORDER_RFONTLIST, NULL); GreAcquireHmgrSemaphore();
if (bSwitchParentAndChild) { //
// Mode change between new parent (meta) HDEV and
// old HDEV, so that old HDEV becomes new parent
// (meta) HDEV which has children.
//
if (bDynamicModeChange(pOrgMdev->Dev[0].hdev, pmdev->hdevParent) == TRUE) { hdevTmp = pmdev->hdevParent; pmdev->hdevParent = pOrgMdev->Dev[0].hdev; pOrgMdev->hdevParent = hdevTmp; pOrgMdev->Dev[0].hdev = hdevTmp;
if (hdevClone) { hdevCloned = hdevTmp; } } else { // Error occured
bSwitchError = TRUE; } } else { //
// Switch the mode between parents (DDML).
//
if (bDynamicModeChange(pOrgMdev->hdevParent, pmdev->hdevParent) == TRUE) { hdevTmp = pOrgMdev->hdevParent; pOrgMdev->hdevParent = pmdev->hdevParent; pmdev->hdevParent = hdevTmp; } else { // Error occured
bSwitchError = TRUE; } }
//
// Release semaphores.
//
GreReleaseHmgrSemaphore(); GreReleaseSemaphoreEx(ghsemRFONTList); GreReleaseSemaphoreEx(ghsemPublicPFT); // Nobody else uses the font table
GreReleaseSemaphoreEx(ghsemPalette); GreReleaseSemaphoreEx(ghsemDriverMgmt); GreReleaseSemaphoreEx(hsemParentDevLock); } } } }
//
// Below code is only for mode change case.
//
if (pOrgMdev) { //
// Finalize clone hdev stuff (if created)
//
if ((bSwitchError == FALSE) && hdevClone && hdevCloned) { PDEV *pdevNew = (PDEV *) hdevClone; PDEV *pdevOld = (PDEV *) hdevCloned;
PDEVOBJ pdoNew(hdevClone); PDEVOBJ pdoOld(hdevCloned);
ASSERTGDI(pdevOld->pSurface != NULL, "DrvChangeDisplaySettings():Original has null surface\n");
ASSERTGDI(pdevNew->pSurface == pdevOld->pSurface, "DrvChangeDisplaySettings():Clone has wrong surface\n");
ASSERTGDI(pdevNew->dhpdev == pdevOld->dhpdev, "DrvChangeDisplaySettings():Clone has wrong dhpdev\n");
ASSERTGDI(!pdoOld.bCloneDriver(), "DrvChangeDisplaySettings():Original should not marked as clone\n");
ASSERTGDI(pdoNew.bCloneDriver(), "DrvChangeDisplaySettings():Clone should have marked as clone\n");
ASSERTGDI(pdevOld->pGraphicsDevice == pdevNew->pGraphicsDevice, "DrvChangeDisplaySettings():Clone should have same graphics device\n");
if (bEnableClone) { //
// Inform the driver that the PDEV is complete.
//
TRACE_INIT(("DrvChangeDisplaySettings(): Enabling clone pdev\n"));
//
// Transfer device surface to clone from cloned PDEV.
//
pdevNew->pSurface = pdevOld->pSurface;
//
// Set new hdev into surface.
//
if (pdevNew->pSurface) { pdevNew->pSurface->hdev(pdoNew.hdev()); }
//
// Transsfer dhpdev from cloned to clone
//
pdevNew->dhpdev = pdevOld->dhpdev;
//
// Transfer DirectDraw driver state from cloned to clone.
//
DxDdDynamicModeChange(pdoOld.hdev(), pdoNew.hdev(), DXG_MODECHANGE_TRANSFER);
//
// Transfer other surface and other objects which own by hdevCloned to hdevClone.
//
// Transfer the objects belonging to cloned pdev to clone,
// transfer between clone and cloned is completely seemless
// from driver. So we need to change owner of those object
// by ourselves.
//
DrvTransferGdiObjects(pdoNew.hdev(),pdoOld.hdev(),DRV_TRANS_ALL_TYPE);
//
// Invalidate surface in cloned pdev, so that this won't deleted.
//
pdevOld->pSurface = NULL;
//
// Invalidate dhpdev in cloned.
//
pdevOld->dhpdev = NULL;
//
// Now, clone device has everything grab from original, so
// mark original as clone, and mark clone as original.
//
pdoOld.bCloneDriver(TRUE); pdoNew.bCloneDriver(FALSE);
//
// Disabling old pdev.
//
pdoOld.bDisabled(TRUE);
//
// call device driver to let them knows new hdev.
//
pdoNew.CompletePDEV(pdoNew.dhpdev(),pdoNew.hdev());
//
// Make sure pdoOld which going to be delete, does not have any reference.
//
// KdPrint(("GDI DDML: 1 to Many monitor video mode change\n"));
// KdPrint(("GDI DDML: Open ref count in ppdevOld = %d\n", pdevOld->cPdevOpenRefs));
// KdPrint(("GDI DDML: Pdev ref count in ppdevOld = %d\n", pdevOld->cPdevRefs));
} else { TRACE_INIT(("DrvChangeDisplaySettings(): Disabling clone pdev\n"));
//
// Clone was created for temporary purpose.
//
// Invalidate surface in clone pdev, so that this won't deleted.
//
pdevNew->pSurface = NULL;
//
// Disable clone PDEV.
//
pdoNew.bDisabled(TRUE);
// KdPrint(("GDI DDML: Many to 1 monitor video mode change\n"));
// KdPrint(("GDI DDML: Open ref count in ppdevOld = %d\n", pdevNew->cPdevOpenRefs));
// KdPrint(("GDI DDML: Pdev ref count in ppdevOld = %d\n", pdevNew->cPdevRefs));
} }
//
// Disable old parant pdev if its meta driver.
// Since meta PDEV never be reused in new MDEV.
//
PDEVOBJ pdoOldParent(pOrgMdev->hdevParent);
if (pdoOldParent.bMetaDriver()) { pdoOldParent.bDisabled(TRUE); }
//
// Reactivate sprites on whichever MDEV will be used
//
vSpHideSprites(((bSwitchError == FALSE) ? pmdev : pOrgMdev)->hdevParent, FALSE);
//
// If we hold clone's devlock, now safe to release.
//
if (hsemCloneHdevDevLock) { GreReleaseSemaphoreEx(hsemCloneHdevDevLock); }
//
// Release MDEV's lock.
//
mdloMdev.vUnlock(); mdloOrgMdev.vUnlock(); }
//
// Finalize new MDEV.
//
if (bSwitchError == FALSE) { PDEVOBJ poP(pmdev->hdevParent);
if (pmdev->chdev != 1) { HDEV hdevPalette;
//
// Do devlock sharing
//
DrvSetSharedDevLock(pmdev);
//
// Do palette sharing
//
hdevPalette = DrvSetSharedPalette(pmdev);
if (!poP.bIsPalManaged() && hdevPalette) { //
// If parent is not pal-managed, but if there is any
// pal-managed device, realize halftone palette on there.
//
DrvRealizeHalftonePalette(hdevPalette,TRUE); } } else { //
// For single monitor case, make sure ppdevParent points itself.
//
PPDEV ppdev = (PPDEV) poP.hdev(); XEPALOBJ palObj(poP.ppalSurf());
if (ppdev->ppdevParent != ppdev) { WARNING("ChangeDisplaySettings: ppdev->parent != ppdev, fixing it\n");
ppdev->ppdevParent = ppdev; }
//
// Correct palette pointer to driver entry.
//
poP.pfnSetPalette(PPFNDRV(poP, SetPalette));
//
// Unshared palette table entry.
//
palObj.apalResetColorTable(); } }
if (hsemOrgMdevDevLock) { ASSERTGDI(hsemOrgMdevPointer, "DrvChangeDisplaySettings():Pointer Lock is NULL\n");
if (bSwitchError == FALSE) { PDEVOBJ pdoParent(pmdev->hdevParent);
//
// If mode change has been successfully done, make sure the primary
// devlock has not been changed through the mode change.
//
ASSERTGDI(hsemOrgMdevDevLock == pdoParent.hsemDevLock(), "DrvChangeDisplaySettings():DevLock has been changed !\n"); }
//
// Unlock the pointer
//
GreReleaseSemaphoreEx(hsemOrgMdevPointer);
//
// Unlock the parent of MDEV.
//
GreReleaseSemaphoreEx(hsemOrgMdevDevLock); }
//
// Resume DirectDraw, this can not do while devlock is hold
//
if (phdevDDLock) { DrvEnableDirectDrawForModeChange( phdevDDLock, phdevDDLock != ahdevDDLockQuick); }
//
// If we succeed, return the new data strucutre.
//
if (bSwitchError == FALSE) { PDEVOBJ pdo;
//
// Dump the old MDEV structure.
//
if (pOrgMdev != NULL) { TRACE_INIT(("OLD pmdev = %08lx\n", pOrgMdev));
TRACE_INIT(("\tOLD hdevParent = %08lx\n", pOrgMdev->hdevParent)); TRACE_INIT(("\tOLD chdev = %d\n", pOrgMdev->chdev));
for (i = 0; i < pOrgMdev->chdev; i++) { pdo.vInit(pOrgMdev->Dev[i].hdev);
TRACE_INIT(("\tOLD [%d].hdev = %08lx\n", i, pOrgMdev->Dev[i].hdev));
ASSERTGDI(pdo.ppdev->pGraphicsDevice != (PGRAPHICS_DEVICE) DDML_DRIVER, "OLD MDEV has DDML_DRIVER as child hdev");
//
// Unmark old MDEV as part of the desktop.
//
pdo.ppdev->pGraphicsDevice->stateFlags &= ~DISPLAY_DEVICE_ATTACHED_TO_DESKTOP; } }
//
// Clear the primary flag
//
for (PGRAPHICS_DEVICE PhysDispTemp = gpGraphicsDeviceList; PhysDispTemp != NULL; PhysDispTemp = PhysDispTemp->pNextGraphicsDevice) { PhysDispTemp->stateFlags &= ~DISPLAY_DEVICE_PRIMARY_DEVICE; }
//
// Dump the new MDEV structure.
//
TRACE_INIT(("NEW pmdev = %08lx\n", pmdev));
TRACE_INIT(("\tNEW hdevParent = %08lx\n", pmdev->hdevParent)); TRACE_INIT(("\tNEW chdev = %d\n", pmdev->chdev));
for (i = 0; i < pmdev->chdev; i++) { pdo.vInit(pmdev->Dev[i].hdev); PDEVMODEW pdm = pdo.ppdev->ppdevDevmode;
TRACE_INIT(("\tNEW [%d].hdev = %08lx\n", i, pmdev->Dev[i].hdev)); TRACE_INIT(("\tNEW [%d].rect = %d, %d, %d, %d,\n", i, pmdev->Dev[i].rect.left, pmdev->Dev[i].rect.top, pmdev->Dev[i].rect.right, pmdev->Dev[i].rect.bottom));
ASSERTGDI(pdo.ppdev->pGraphicsDevice != (PGRAPHICS_DEVICE) DDML_DRIVER, "NEW MDEV has DDML_DRIVER as child hdev");
//
// Mark new MDEV as part of the desktop.
//
pdo.ppdev->pGraphicsDevice->stateFlags |= DISPLAY_DEVICE_ATTACHED_TO_DESKTOP;
//
// Adjust the position and mark the primary device
//
pdm->dmPosition.x = pmdev->Dev[i].rect.left; pdm->dmPosition.y = pmdev->Dev[i].rect.top;
if ((pdm->dmPosition.x == 0) && (pdm->dmPosition.y == 0)) { pdo.ppdev->pGraphicsDevice->stateFlags |= DISPLAY_DEVICE_PRIMARY_DEVICE; } }
//
// Update the DeviceCaps for the new HDEV
//
GreUpdateSharedDevCaps(pmdev->hdevParent); } else { //
// We had a problem with the mode switch.
// Revert to the old configuration.
//
// We must make sure pOrgMdev is still what is
// currently active.
//
// ISSUE: Is this multmon safe ?? shared devlock ??
// ISSUE: Is this clone-pdev safe ?? (of course, no).
DrvBackoutMDEV(pmdev); VFREEMEM(pmdev); *pNewMdev = NULL;
if (pOrgMdev != NULL) { DrvEnableMDEV(pOrgMdev, FALSE); }
gcFailedModeChanges++;
status = GRE_DISP_CHANGE_RESTART; } } else if (status == GRE_DISP_CHANGE_NO_CHANGE) { //
// If nothing has been changed, just copy Parent HDEV from original.
//
pmdev->hdevParent = pOrgMdev->hdevParent; pmdev->Reserved = pOrgMdev->Reserved;
//
// If parent HDEV is DDML, Increment OpenRef count. otheriwse parent
// hdev is same as its child, so OpenRef is already incremented in
// hCreateHDEV().
//
if (pmdev->chdev > 1) { GreAcquireSemaphoreEx(ghsemDriverMgmt, SEMORDER_DRIVERMGMT, NULL);
PDEVOBJ pdo(pmdev->hdevParent);
pdo.ppdev->cPdevOpenRefs++; pdo.ppdev->cPdevRefs++;
GreReleaseSemaphoreEx(ghsemDriverMgmt); }
ASSERTGDI(pmdev->chdev == pOrgMdev->chdev, "DrvChangeDisplaySettings():Status is no change, but chdev is different\n"); ASSERTGDI(pmdev->pDesktopId == pOrgMdev->pDesktopId, "DrvChangeDisplaySettings():Status is no change, but pDesktopId is different\n"); }
//
// Reenable the HDEVs (whether we fail or succeed) so
// DirectDraw and other functionality is reestablished.
//
// If the call succeeded, the destroy the old HDEVs
//
if (pOrgMdev) { if ( (status == GRE_DISP_CHANGE_SUCCESSFUL) || (status == GRE_DISP_CHANGE_NO_CHANGE) ) { //
// Enable new MDEV.
//
DrvEnableMDEV(pmdev, FALSE);
//
// ISSUE: Reset the state of the DISPLAY_DEVICE_ flags when we
// destroy the pdev on the device.
//
if (status == GRE_DISP_CHANGE_SUCCESSFUL) { //
// When we are success to do mode change,
// In multi monitor system, it is possible
// to happen pOrgMdev still contains "enabled"
// device. Because ,for example, system has 2
// monitors attached, but only 1 monitor enabled,
// other one is disabled. so User decided to enable
// one and disable 'currently enabled' monitor.
// In this case, we do '1 -> 1' mode change, since
// there is only 1 monitor before and after mode change.
// and CreateHDEV() only disable display when it is
// same pGraphicsDevice. thus this case, old display
// will be disabled.
// So here, we scan hdev in Old MDEV, and if there is
// 'enabled' device which is not used in New MDEV, we
// disable it.
//
for (i = 0; i < pOrgMdev->chdev; i++) { PDEV *pdevOld = (PDEV *) pOrgMdev->Dev[i].hdev;
//
// Dualview has already been cleared and disabled
//
if ((pdevOld->pGraphicsDevice->stateFlags & DISPLAY_DEVICE_DUALVIEW) && gbInvalidateDualView) { continue; }
for (j = 0; j < pmdev->chdev; j++) { PDEV *pdevNew = (PDEV *) pmdev->Dev[j].hdev;
//
// Don't disable this old pdev \ device if we
// are still using it
//
if ((pdevOld->pGraphicsDevice == pdevNew->pGraphicsDevice) || (pdevOld->pGraphicsDevice->pVgaDevice && pdevNew->pGraphicsDevice->pVgaDevice)) { break; } }
if (j == pmdev->chdev) { DrvDisableDisplay(pOrgMdev->Dev[i].hdev, TRUE); } } }
//
// Get rid of old MDEV.
//
DrvDestroyMDEV(pOrgMdev); } } mcip.vDone(); GreReleaseSemaphoreEx(ghsemShareDevLock);
TRACE_INIT(("Drv_Trace: DrvChangeDisplaySettings - Mode Switch status %d\n", status)); }
if (pdevmodeInformation) { VFREEMEM(pdevmodeInformation); }
TRACE_INIT(("Drv_Trace: DrvChangeDisplaySettings - Leave - status = %d\n", status));
gbInvalidateDualView = FALSE;
return status; }
/***************************************************************************\
* DrvSetVideoParameters * * Routine used to pass video parameters structure down to video miniports. * * ericks Created \***************************************************************************/
LONG DrvSetVideoParameters( PUNICODE_STRING pstrDeviceName, HDEV hdevPrimary, MODE PreviousMode, PVOID lParam ) { NTSTATUS status = GRE_DISP_CHANGE_BADPARAM; PGRAPHICS_DEVICE PhysDisp = NULL;
if (pstrDeviceName) { PhysDisp = DrvGetDeviceFromName(pstrDeviceName, PreviousMode);
if (PhysDisp == NULL) { TRACE_INIT(("Drv_Trace: DrvSetVideoParameters - Leave - Bad Device\n")); return GRE_DISP_CHANGE_BADPARAM; } } else { PDEVOBJ pdo(hdevPrimary);
if (pdo.bValid()) { PhysDisp = pdo.ppdev->pGraphicsDevice; }
if (PhysDisp == NULL) { TRACE_INIT(("Drv_Trace: DrvSetVideoParameters - Leave - Bad Device\n")); return GRE_DISP_CHANGE_BADPARAM; } }
if (PhysDisp == (PGRAPHICS_DEVICE) DDML_DRIVER) { ASSERTGDI(FALSE, "Trying to change TV settings for DDML layer\n"); return GRE_DISP_CHANGE_BADPARAM; }
if (PhysDisp != NULL) {
ULONG bytesReturned; PVIDEOPARAMETERS CapturedData;
CapturedData = (PVIDEOPARAMETERS) PALLOCNOZ(2 * sizeof(VIDEOPARAMETERS), GDITAG_DRVSUP);
if (CapturedData == NULL) { return GRE_DISP_CHANGE_FAILED; }
//
// Make sure lParam is valid!
//
__try { ProbeForRead(lParam, sizeof(VIDEOPARAMETERS), sizeof(UCHAR)); memcpy(CapturedData, lParam, sizeof(VIDEOPARAMETERS)); } __except (EXCEPTION_EXECUTE_HANDLER) { VFREEMEM(CapturedData); return GRE_DISP_CHANGE_BADPARAM; }
status = GreDeviceIoControl(PhysDisp->pDeviceHandle, IOCTL_VIDEO_HANDLE_VIDEOPARAMETERS, CapturedData, sizeof(VIDEOPARAMETERS), CapturedData, sizeof(VIDEOPARAMETERS), &bytesReturned);
if (status != NO_ERROR) { status = GRE_DISP_CHANGE_BADPARAM; } else { ASSERTGDI(bytesReturned == sizeof(VIDEOPARAMETERS), "DrvSetVideoParameters: Not enough data returned\n"); }
__try { memcpy(lParam, CapturedData, sizeof(VIDEOPARAMETERS)); } __except (EXCEPTION_EXECUTE_HANDLER) { status = GRE_DISP_CHANGE_BADPARAM; }
VFREEMEM(CapturedData); }
return status; }
/***************************************************************************\
* NtGdiGetMonitorID * * Return Monitor ID for the given HDC. * * 14-Dec-1998 hideyukn Created \***************************************************************************/
BOOL NtGdiGetMonitorID ( HDC hdc, DWORD dwSize, LPWSTR pszMonitorID ) { BOOL bRet = FALSE; NTSTATUS Status;
DISPLAY_DEVICEW DisplayDevice;
//
// We don't want the session to switch from local to remote or remote to local
// while we are enumerating display device. Device lock won't prevent this from
// hapening so we need to grab the User session switch lock.
//
Status = UserSessionSwitchEnterCrit(); if (Status != STATUS_SUCCESS) { return FALSE; }
XDCOBJ dco(hdc);
if (dco.bValid()) { PDEVOBJ pdo(dco.hdev()); DEVLOCKOBJ dlo(pdo);
if (dlo.bValid()) { PGRAPHICS_DEVICE pGraphicsDevice = NULL;
if (pdo.bMetaDriver()) { //
// If this is meta driver, use primary.
//
PVDEV pvdev = (PVDEV) pdo.dhpdev();
pGraphicsDevice = ((PPDEV)(pvdev->hdevPrimary))->pGraphicsDevice; } else { pGraphicsDevice = ((PPDEV)pdo.hdev())->pGraphicsDevice; }
if (pGraphicsDevice) { UNICODE_STRING DeviceName; NTSTATUS NtStatus;
RtlInitUnicodeString(&DeviceName, pGraphicsDevice->szWinDeviceName);
DisplayDevice.cb = sizeof(DisplayDevice);
//
// Get monitor data attached to this display device.
//
NtStatus = DrvEnumDisplayDevices(&DeviceName,NULL,0,&DisplayDevice,NULL,KernelMode);
if (NT_SUCCESS(NtStatus)) { bRet = TRUE; } } }
dco.vUnlockFast(); }
if (bRet) { DWORD dwLenToBeCopied = (wcslen(DisplayDevice.DeviceID) + 1) * sizeof(WCHAR);
if (dwLenToBeCopied <= dwSize) { __try { ProbeForWrite(pszMonitorID, dwSize, sizeof(BYTE)); RtlCopyMemory(pszMonitorID,DisplayDevice.DeviceID,dwLenToBeCopied); } __except(EXCEPTION_EXECUTE_HANDLER) { WARNINGX(64); bRet = FALSE; } } else { bRet = FALSE; } } //
// Release the session switch lock.
//
UserSessionSwitchLeaveCrit(); return (bRet); }
#ifdef _HYDRA_
//
//!!! Currently, the graphics device list (see drvsup.cxx) is allocated
//!!! per-Hydra session. AndreVa has proposed that they be allocated
//!!! globally. He's probably right, but until this changes we need to
//!!! clean them up during Hydra shutdown.
//!!!
//!!! To enable cleanup of the per-Hydra graphics device lists, define
//!!! _PER_SESSION_GDEVLIST_ in muclean.hxx.
//
#ifdef _PER_SESSION_GDEVLIST_
/******************************Public*Routine******************************\
* MultiUserDrvCleanupGraphicsDeviceList * * For MultiUserNtGreCleanup (Hydra) cleanup. * * Cleanup the graphics device list. * * History: * 21-Feb-1998 -by- Gilman Wong [gilmanw] * Wrote it. \**************************************************************************/
VOID DrvCleanupOneGraphicsDevice(PGRAPHICS_DEVICE PhysDispVictim) { //
// Delete the graphics device data buffers if they exist.
//
if (PhysDispVictim->devmodeInfo) VFREEMEM(PhysDispVictim->devmodeInfo);
if (PhysDispVictim->devmodeMarks) VFREEMEM(PhysDispVictim->devmodeMarks);
if (PhysDispVictim->DeviceDescription) VFREEMEM(PhysDispVictim->DeviceDescription);
if (PhysDispVictim->DisplayDriverNames) VFREEMEM(PhysDispVictim->DisplayDriverNames);
if (PhysDispVictim->MonitorDevices) VFREEMEM(PhysDispVictim->MonitorDevices);
if (PhysDispVictim->pFileObject) ObDereferenceObject(PhysDispVictim->pFileObject);
VFREEMEM(PhysDispVictim); }
VOID DrvCleanupGraphicsDeviceList(PGRAPHICS_DEVICE pGraphicsDeviceList) { PGRAPHICS_DEVICE PhysDispVictim; PGRAPHICS_DEVICE PhysDispNext;
//
// Run the list and delete resources.
//
for (PhysDispVictim = pGraphicsDeviceList; PhysDispVictim != NULL; PhysDispVictim = PhysDispNext) { PhysDispNext = PhysDispVictim->pNextGraphicsDevice;
//
// Does this graphics device have a VGA device chained off of it
// (and is it not self referential)?
//
if ((PhysDispVictim->pVgaDevice) && (PhysDispVictim->pVgaDevice != PhysDispVictim) && (PhysDispVictim->pVgaDevice != &gFullscreenGraphicsDevice) && (PhysDispVictim->pVgaDevice != gPhysDispVGA)) { DrvCleanupOneGraphicsDevice(PhysDispVictim->pVgaDevice); }
if ((PhysDispVictim != &gFullscreenGraphicsDevice) && (PhysDispVictim != gPhysDispVGA)) { DrvCleanupOneGraphicsDevice(PhysDispVictim); } } }
VOID MultiUserDrvCleanupGraphicsDeviceList() {
// Cleanup local graphics device list
DrvCleanupGraphicsDeviceList(gpLocalGraphicsDeviceList); gpLocalGraphicsDeviceList = NULL;
// Cleanup remote graphics device list
DrvCleanupGraphicsDeviceList(gpRemoteGraphicsDeviceList); gpRemoteGraphicsDeviceList = NULL;
gpGraphicsDeviceList = NULL;
//
// If WinStation, cleanup driver name allocated in
// GreMultiUserInitSession (misc.cxx).
//
if (!G_fConsole) { //
// If we never made it to GreMultiUserInitSession then don't
// call FreePool on a static variable (look in misc.cxx)
//
if (G_DisplayDriverNames && G_RemoteVideoFileObject != NULL) { GdiFreePool(G_DisplayDriverNames); } }
if (gPhysDispVGA) { DrvCleanupOneGraphicsDevice(gPhysDispVGA); gPhysDispVGA = NULL; }
if (gFullscreenGraphicsDevice.devmodeInfo) { VFREEMEM(gFullscreenGraphicsDevice.devmodeInfo); gFullscreenGraphicsDevice.devmodeInfo = NULL; }
if (gFullscreenGraphicsDevice.devmodeMarks) { VFREEMEM(gFullscreenGraphicsDevice.devmodeMarks); gFullscreenGraphicsDevice.devmodeMarks = NULL; }
}
BOOL DrvIsProtocolAlreadyKnown(VOID) { PGRAPHICS_DEVICE PhysDisp = gpGraphicsDeviceList; while (PhysDisp != NULL) { if (gProtocolType == PhysDisp->ProtocolType) { return TRUE; } PhysDisp = PhysDisp->pNextGraphicsDevice; } return FALSE; } #endif
#endif
|