mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
4430 lines
142 KiB
4430 lines
142 KiB
/**************************************************************************\
|
|
* Module Name: drvsup.c
|
|
*
|
|
* Contains all the code to initialize and manage state associated with the
|
|
* display drivers.
|
|
*
|
|
* Copyright (c) Microsoft Corp. 1990-1996 All Rights Reserved
|
|
*
|
|
* NOTES:
|
|
*
|
|
* Dealing with the DEVMODE structure is quite hard - especially because
|
|
* is of variable size, which the dmDriverExtra being variable. The goal in
|
|
* this module should always be to work with DEVMODEW structures which are
|
|
* the size the OS expects them to be. Only the high level APIS (such as
|
|
* EnumDisplaySettings and ProbeAndCaptureDevmode) should deal with massaging
|
|
* these structures to appropriate size. Other code should stay away from
|
|
* that.
|
|
*
|
|
* History:
|
|
* 1992-1996 Andre Vachon [andreva]
|
|
*
|
|
\**************************************************************************/
|
|
|
|
#include "precomp.h"
|
|
#pragma hdrstop
|
|
|
|
#include "ntddvdeo.h"
|
|
|
|
|
|
typedef enum _DISP_DRIVER_REGISTRY_TYPE {
|
|
DispDriverRegGlobal,
|
|
DispDriverRegHardwareProfile,
|
|
DispDriverRegHardwareProfileCreate
|
|
} DISP_DRIVER_REGISTRY_TYPE;
|
|
|
|
//
|
|
// BUGBUG
|
|
//
|
|
// For performance, we may want to use another lock to protect the contents
|
|
// of gphysinfo, since those calls can take quite a long time - compared to
|
|
// other window manager calls.
|
|
//
|
|
|
|
|
|
BOOL gbBaseVideo = FALSE;
|
|
BOOL bMultipleDisplaySystem = FALSE;
|
|
|
|
#define DEFAULT_POS_VALUE 0x80000000
|
|
|
|
#define DM_INTERNAL_VALID_FLAGS \
|
|
(DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT | DM_DISPLAYFREQUENCY | \
|
|
DM_DISPLAYFLAGS | DM_LOGPIXELS | DM_PANNINGWIDTH | DM_PANNINGHEIGHT)
|
|
|
|
//
|
|
// BUGBUG
|
|
// Goes in winuser.w
|
|
//
|
|
|
|
#define DISPLAY_DEVICE_VGA_COMPATIBLE 0x00000010
|
|
|
|
/**************************************************************************\
|
|
* ProbeAndCaptureDeviceName
|
|
*
|
|
* Captures a device name that comes from user mode.
|
|
*
|
|
* If the name is NULL, then the fucntion assumes the operation will execute
|
|
* on the current device on which the desktop is located.
|
|
*
|
|
* 25-Mar-1996 andreva created
|
|
\**************************************************************************/
|
|
|
|
BOOL
|
|
ProbeAndCaptureDeviceName(
|
|
PUNICODE_STRING Destination,
|
|
PUNICODE_STRING Source)
|
|
{
|
|
BOOL fFreeBuffer = FALSE;
|
|
|
|
Destination->Buffer = NULL;
|
|
Destination->Length = 0;
|
|
|
|
if (Source) {
|
|
|
|
try {
|
|
*Destination = ProbeAndReadUnicodeString(Source);
|
|
|
|
if (Destination->Length) {
|
|
|
|
#if defined(_X86_)
|
|
ProbeForRead(Destination->Buffer, Destination->Length, sizeof(BYTE));
|
|
#else
|
|
ProbeForRead(Destination->Buffer, Destination->Length, sizeof(WCHAR));
|
|
#endif
|
|
|
|
Destination->Buffer =
|
|
UserAllocPoolWithQuota(Destination->Length, TAG_TEXT2);
|
|
|
|
if (Destination->Buffer) {
|
|
fFreeBuffer = TRUE;
|
|
RtlCopyMemory(Destination->Buffer,
|
|
Source->Buffer,
|
|
Destination->Length);
|
|
} else {
|
|
ExRaiseStatus(STATUS_NO_MEMORY);
|
|
}
|
|
}
|
|
} except (EXCEPTION_EXECUTE_HANDLER) {
|
|
|
|
RIPNTERR0(GetExceptionCode(), RIP_VERBOSE, "");
|
|
|
|
if (fFreeBuffer) {
|
|
UserFreePool(Destination->Buffer);
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
if (Destination->Length == 0) {
|
|
|
|
PDESKTOP pdesk = PtiCurrent()->rpdesk;
|
|
LPWSTR DeviceName;
|
|
USHORT Length;
|
|
|
|
if (pdesk) {
|
|
/*
|
|
* Special case for boot-up time.
|
|
*/
|
|
DeviceName = pdesk->pDispInfo->pDevInfo->szNtDeviceName;
|
|
} else {
|
|
DeviceName = gpDispInfo->pDevInfo->szNtDeviceName;
|
|
}
|
|
|
|
Length = wcslen(DeviceName);
|
|
|
|
Destination->Buffer =
|
|
UserAllocPoolWithQuota(16 * sizeof(WCHAR), TAG_TEXT2);
|
|
|
|
if (Destination->Buffer) {
|
|
RtlCopyMemory(Destination->Buffer,
|
|
DeviceName,
|
|
16 * sizeof(WCHAR));
|
|
|
|
RtlInitUnicodeString(Destination, Destination->Buffer);
|
|
|
|
} else {
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
|
|
/**************************************************************************\
|
|
* UserSaveCurrentMode
|
|
*
|
|
* This routines maintains two DEVMODEs.
|
|
* One is assoicated with the desktop, if one was passed in.
|
|
* The second is assoicated with the device.
|
|
*
|
|
* We make the distinction between the two because we can have multiple
|
|
* desktops on the same device, each with different modes. We only want to
|
|
* switch modes when switching desktops if necessary. So we compare the
|
|
* desktop DEVMODE to the current DEVMODE when we do a ChangeDisplaySettings
|
|
* (which is done on each switch desktop).
|
|
*
|
|
* 10-Mar-1996 andreva created
|
|
\**************************************************************************/
|
|
|
|
VOID
|
|
UserSaveCurrentMode(
|
|
PDESKTOP pDesktop,
|
|
PPHYSICAL_DEV_INFO physinfo,
|
|
LPDEVMODEW lpdevmodeInformation
|
|
)
|
|
{
|
|
DWORD newSize = lpdevmodeInformation->dmSize +
|
|
lpdevmodeInformation->dmDriverExtra;
|
|
PDEVMODEW pDevmode;
|
|
|
|
if (pDesktop) {
|
|
|
|
pDevmode = UserAllocPool(newSize, TAG_DEVMODE);
|
|
|
|
if (pDevmode) {
|
|
|
|
RtlCopyMemory(pDevmode,
|
|
lpdevmodeInformation,
|
|
newSize);
|
|
|
|
if (pDesktop->pDesktopDevmode) {
|
|
UserFreePool(pDesktop->pDesktopDevmode);
|
|
} else {
|
|
RIPMSG0(RIP_ERROR, "UserSaveCurrentMode - previous DEVMODE missing !\n");
|
|
}
|
|
|
|
pDesktop->pDesktopDevmode = pDevmode;
|
|
}
|
|
|
|
}
|
|
|
|
if (physinfo) {
|
|
|
|
pDevmode = UserAllocPool(newSize, TAG_DEVMODE);
|
|
|
|
if (pDevmode) {
|
|
|
|
RtlCopyMemory(pDevmode,
|
|
lpdevmodeInformation,
|
|
newSize);
|
|
|
|
if (physinfo->pCurrentDevmode) {
|
|
UserFreePool(physinfo->pCurrentDevmode);
|
|
}
|
|
|
|
physinfo->pCurrentDevmode = pDevmode;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**************************************************************************\
|
|
* UserGetRegistryHandleFromDeviceMap
|
|
*
|
|
* Take a symbolic device name and gets the handle to the registry node for
|
|
* that driver.
|
|
*
|
|
* This function is called by the UserServer initialization and by the
|
|
* ChangeDisplaySettings functions.
|
|
*
|
|
* 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.
|
|
*
|
|
* CRIT not needed
|
|
*
|
|
* 30-Nov-1992 andreva created
|
|
\**************************************************************************/
|
|
|
|
HANDLE
|
|
UserGetRegistryHandleFromDeviceMap(
|
|
PUNICODE_STRING deviceName,
|
|
DISP_DRIVER_REGISTRY_TYPE ParamType,
|
|
BOOL bMatchBaseVideo,
|
|
PNTSTATUS pStatus)
|
|
{
|
|
HANDLE hkRegistry = NULL;
|
|
|
|
UNICODE_STRING UnicodeString;
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
NTSTATUS Status;
|
|
HANDLE handle;
|
|
ULONG cbStringSize;
|
|
|
|
TRACE_INIT(("UserInit: GetHandleFromMap: Enter\n"));
|
|
|
|
/*
|
|
* Initialize the handle
|
|
*/
|
|
|
|
/*
|
|
* Start by opening the registry devicemap for video.
|
|
*/
|
|
|
|
RtlInitUnicodeString(&UnicodeString,
|
|
L"\\Registry\\Machine\\Hardware\\DeviceMap\\Video");
|
|
|
|
InitializeObjectAttributes(&ObjectAttributes,
|
|
&UnicodeString,
|
|
OBJ_CASE_INSENSITIVE,
|
|
NULL,
|
|
NULL);
|
|
|
|
Status = ZwOpenKey(&handle, KEY_READ, &ObjectAttributes);
|
|
|
|
if (NT_SUCCESS(Status)) {
|
|
|
|
WCHAR driverRegistryPath[256];
|
|
WCHAR fullRegistryPath[256];
|
|
|
|
/*
|
|
* Get the name of the driver based on the device name.
|
|
*/
|
|
|
|
Status = ZwQueryValueKey(handle,
|
|
deviceName,
|
|
KeyValueFullInformation,
|
|
driverRegistryPath,
|
|
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 lpstrDriverRegistryPath;
|
|
LPWSTR lpstrEndPath;
|
|
UNICODE_STRING FullRegistryPath;
|
|
|
|
//
|
|
// We can use wcsstr since we are guaranteed to find "Services"
|
|
// in the string, and we won't run off the end of the string.
|
|
//
|
|
|
|
lpstrDriverRegistryPath = wcsstr((LPWSTR)((PUCHAR)driverRegistryPath +
|
|
((PKEY_VALUE_FULL_INFORMATION)driverRegistryPath)->DataOffset),
|
|
L"\\Services");
|
|
|
|
//
|
|
// Determine if the device for which we have the handle is a
|
|
// BASEVIDEO device.
|
|
//
|
|
|
|
if (bMatchBaseVideo)
|
|
{
|
|
TRACE_INIT(("UserInit: GetHandleFromMap: testing for basevideo device\n"));
|
|
|
|
if ((_wcsicmp(L"\\Services\\VgaSave\\Device0", lpstrDriverRegistryPath)) &&
|
|
(_wcsicmp(L"\\Services\\Vga\\Device0", lpstrDriverRegistryPath)) )
|
|
{
|
|
TRACE_INIT(("UserInit: GetHandleFromMap: basevideo match failed - Exit\n\n"));
|
|
|
|
ZwClose(handle);
|
|
|
|
if (pStatus) {
|
|
*pStatus = STATUS_NO_SUCH_DEVICE;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Start composing the fully qualified path name.
|
|
//
|
|
|
|
FullRegistryPath.Buffer = fullRegistryPath;
|
|
FullRegistryPath.Length = 0;
|
|
FullRegistryPath.MaximumLength = 255;
|
|
|
|
RtlAppendUnicodeToString(&FullRegistryPath,
|
|
L"\\Registry\\Machine\\System\\CurrentControlSet");
|
|
|
|
//
|
|
// If we want the hardware profile, insert the hardware profile
|
|
// in there
|
|
//
|
|
|
|
if ((ParamType == DispDriverRegHardwareProfile) ||
|
|
(ParamType == DispDriverRegHardwareProfileCreate))
|
|
{
|
|
TRACE_INIT(("UserInit: GetHandleFromMap: using a hardware profile\n"));
|
|
RtlAppendUnicodeToString(&FullRegistryPath,
|
|
L"\\Hardware Profiles\\Current\\System\\CurrentControlSet");
|
|
}
|
|
|
|
//
|
|
// If we have the create Options, we have to create the subkeys
|
|
// otherwise, just open thekey
|
|
//
|
|
|
|
InitializeObjectAttributes(&ObjectAttributes,
|
|
&FullRegistryPath,
|
|
OBJ_CASE_INSENSITIVE,
|
|
NULL,
|
|
NULL);
|
|
|
|
//
|
|
// Check if the subkeys need to be created.
|
|
//
|
|
|
|
if (ParamType == DispDriverRegHardwareProfileCreate)
|
|
{
|
|
TRACE_INIT(("UserInit: 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)
|
|
{
|
|
ZwClose(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(("UserInit: GetHandleFromMap: failed to create key\n"));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
RtlAppendUnicodeToString(&FullRegistryPath,
|
|
lpstrDriverRegistryPath);
|
|
|
|
Status = ZwOpenKey(&hkRegistry, KEY_READ, &ObjectAttributes);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
|
|
TRACE_INIT(("UserInit: 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(("UserInit: GetHandleFromMap: reg-key path =\n\t%ws\n",
|
|
fullRegistryPath));
|
|
}
|
|
|
|
|
|
ZwClose(handle);
|
|
}
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
|
|
TRACE_INIT(("UserInit: GetHandleFromMap: Error opening registry - status = %08lx\n",
|
|
Status));
|
|
|
|
}
|
|
|
|
if (pStatus) {
|
|
*pStatus = Status;
|
|
}
|
|
|
|
TRACE_INIT(("UserInit: GetHandleFromMap: Exit\n\n"));
|
|
|
|
return hkRegistry;
|
|
}
|
|
|
|
|
|
/**************************************************************************\
|
|
* __EnumDisplayQueryRoutine
|
|
*
|
|
* Callback to get the display driver name.
|
|
*
|
|
* CRIT not needed
|
|
*
|
|
* 12-Jan-1994 andreva created
|
|
\**************************************************************************/
|
|
|
|
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.
|
|
*/
|
|
|
|
if ((Context == NULL) &&
|
|
((ValueType == REG_SZ) || (ValueType == REG_MULTI_SZ)) ) {
|
|
|
|
*(PULONG)EntryContext = ValueLength;
|
|
|
|
} else {
|
|
|
|
RtlCopyMemory(Context, ValueData, ValueLength);
|
|
}
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
/**************************************************************************\
|
|
* UserGetDisplayDriverNames
|
|
*
|
|
* Get the display driver name out of the registry.
|
|
*
|
|
* CRIT not needed
|
|
*
|
|
* 12-Jan-1994 andreva created
|
|
\**************************************************************************/
|
|
|
|
LPWSTR
|
|
UserGetDisplayDriverNames(
|
|
PUNICODE_STRING deviceName
|
|
)
|
|
{
|
|
RTL_QUERY_REGISTRY_TABLE QueryTable[3];
|
|
DWORD status;
|
|
DWORD cb = 0;
|
|
LPWSTR lpdisplay = NULL;
|
|
HANDLE hRegistry;
|
|
|
|
if (hRegistry = UserGetRegistryHandleFromDeviceMap(deviceName,
|
|
DispDriverRegGlobal,
|
|
FALSE,
|
|
NULL)) {
|
|
|
|
/*
|
|
* Initialize the registry query table.
|
|
* Note : We specify NO_EXPAND so we can get a REG_MULTI_SZ back
|
|
* instead of multiple calls back with an REG_SZ
|
|
*/
|
|
QueryTable[0].QueryRoutine = __EnumDisplayQueryRoutine;
|
|
QueryTable[0].Flags = RTL_QUERY_REGISTRY_REQUIRED |
|
|
RTL_QUERY_REGISTRY_NOEXPAND;
|
|
QueryTable[0].Name = (PWSTR)L"InstalledDisplayDrivers";
|
|
QueryTable[0].EntryContext = &cb;
|
|
QueryTable[0].DefaultType = REG_NONE;
|
|
QueryTable[0].DefaultData = NULL;
|
|
QueryTable[0].DefaultLength = 0;
|
|
|
|
QueryTable[1].QueryRoutine = NULL;
|
|
QueryTable[1].Flags = 0;
|
|
QueryTable[1].Name = NULL;
|
|
|
|
/*
|
|
* Set the number of required bytes to zero and query the
|
|
* registry.
|
|
*/
|
|
cb = 0;
|
|
status = RtlQueryRegistryValues(RTL_REGISTRY_HANDLE,
|
|
(PWSTR)hRegistry,
|
|
&QueryTable[0],
|
|
NULL,
|
|
NULL);
|
|
|
|
/*
|
|
* If the specified key was found and has a value, then
|
|
* allocate a buffer for the data and query the registry
|
|
* again to get the actual data.
|
|
*/
|
|
if (cb != 0) {
|
|
|
|
if (lpdisplay = (LPWSTR)UserAllocPoolWithQuota(cb, TAG_SYSTEM)) {
|
|
|
|
status = RtlQueryRegistryValues(RTL_REGISTRY_HANDLE,
|
|
(PWSTR)hRegistry,
|
|
&QueryTable[0],
|
|
lpdisplay,
|
|
NULL);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
|
|
UserFreePool(lpdisplay);
|
|
lpdisplay = NULL;
|
|
}
|
|
}
|
|
|
|
} else {
|
|
RIPMSG1(RIP_ERROR, "No installed display driver: status = %08lx\n", status);
|
|
}
|
|
|
|
ZwClose(hRegistry);
|
|
}
|
|
|
|
return lpdisplay;
|
|
}
|
|
|
|
|
|
/**************************************************************************\
|
|
* UserLogDisplayDriverEvent
|
|
*
|
|
* 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
|
|
UserLogDisplayDriverEvent(
|
|
DISP_DRIVER_LOG MsgType
|
|
)
|
|
{
|
|
HANDLE hkRegistry;
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
UNICODE_STRING UnicodeString;
|
|
|
|
NTSTATUS Status;
|
|
DWORD dwValue = 1;
|
|
|
|
RtlInitUnicodeString(&UnicodeString,
|
|
L"\\Registry\\Machine\\System\\CurrentControlSet\\"
|
|
L"Control\\GraphicsDrivers\\InvalidDisplay");
|
|
|
|
InitializeObjectAttributes(&ObjectAttributes,
|
|
&UnicodeString,
|
|
OBJ_CASE_INSENSITIVE,
|
|
NULL,
|
|
NULL);
|
|
|
|
Status = ZwCreateKey(&hkRegistry,
|
|
GENERIC_READ | GENERIC_WRITE,
|
|
&ObjectAttributes,
|
|
0L,
|
|
NULL,
|
|
REG_OPTION_VOLATILE,
|
|
NULL);
|
|
|
|
if (NT_SUCCESS(Status)) {
|
|
|
|
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:
|
|
|
|
RIPMSG0(RIP_ERROR, "UserLogDisplayDriverEvent: Invalid error message\n");
|
|
return;
|
|
|
|
}
|
|
|
|
/*
|
|
* Write the optional data value under the key.
|
|
*/
|
|
|
|
(VOID) ZwSetValueKey(hkRegistry,
|
|
&UnicodeString,
|
|
0,
|
|
REG_DWORD,
|
|
&dwValue,
|
|
sizeof(DWORD));
|
|
|
|
(VOID)ZwClose(hkRegistry);
|
|
}
|
|
}
|
|
|
|
|
|
static
|
|
LPWSTR DefaultSettings[8] = {
|
|
L"DefaultSettings.BitsPerPel",
|
|
L"DefaultSettings.XResolution",
|
|
L"DefaultSettings.YResolution",
|
|
L"DefaultSettings.VRefresh",
|
|
L"DefaultSettings.Flags",
|
|
L"DefaultSettings.XPanning",
|
|
L"DefaultSettings.YPanning",
|
|
L"DefaultSettings.DriverExtra",
|
|
};
|
|
|
|
static
|
|
LPWSTR AttachedSettings[] = {
|
|
L"Attach.PrimaryDevice",
|
|
L"Attach.ToDesktop",
|
|
L"Attach.RelativeX",
|
|
L"Attach.RelativeY",
|
|
};
|
|
|
|
static
|
|
LPWSTR SoftwareSettings[] = {
|
|
L"MultiDisplayDriver",
|
|
L"MirroringDriver",
|
|
L"VgaCompatible",
|
|
};
|
|
|
|
NTSTATUS
|
|
UserDriverExtraCallback(
|
|
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;
|
|
}
|
|
|
|
/**************************************************************************\
|
|
* UserGetDisplayDriverParameters
|
|
*
|
|
* 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
|
|
UserGetDisplayDriverParameters(
|
|
PUNICODE_STRING deviceName,
|
|
PDEVMODEW pdevmode,
|
|
BOOL bEmptyDevmode)
|
|
{
|
|
ULONG i;
|
|
ULONG k;
|
|
NTSTATUS retStatus;
|
|
HANDLE hkRegistry;
|
|
|
|
DISP_DRIVER_REGISTRY_TYPE registryParam;
|
|
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[9] = {
|
|
|
|
{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},
|
|
|
|
// if the value is not there, we want the call to succeed anyway.
|
|
// so specify a vlue that is NULL modulo 64K !
|
|
|
|
{UserDriverExtraCallback, 0, NULL, pdevmode,
|
|
REG_DWORD, &nullValue, 0x10000},
|
|
|
|
{NULL, 0, NULL}
|
|
};
|
|
|
|
TRACE_INIT(("UserInit: 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.
|
|
*/
|
|
|
|
UserAssert(pdevmode->dmSize == 0xDDDD);
|
|
|
|
/*
|
|
* 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[7].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(("UserInit: GetDriverParams: Default (empty) DEVMODE\n"));
|
|
|
|
RtlZeroMemory(pdevmode, sizeof(DEVMODEW));
|
|
|
|
} else {
|
|
|
|
#if 0
|
|
/*
|
|
* Let's try to get the per-user settings first.
|
|
*/
|
|
|
|
TRACE_INIT(("UserInit: GetDriverParams: USER Settings\n"));
|
|
|
|
for (i=0; i < 8; i++)
|
|
{
|
|
QueryTable[i].Name = DefaultSettings[i];
|
|
}
|
|
|
|
retStatus = RtlQueryRegistryValues(RTL_REGISTRY_USER,
|
|
NULL,
|
|
&QueryTable[0],
|
|
NULL,
|
|
NULL);
|
|
if (NT_SUCCESS(retStatus))
|
|
|
|
#endif
|
|
|
|
TRACE_INIT(("UserInit: GetDriverParams: Hardware Profile 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.
|
|
*/
|
|
|
|
registryParam = DispDriverRegHardwareProfile;
|
|
|
|
for (k=1; k<=2; k++)
|
|
{
|
|
hkRegistry = UserGetRegistryHandleFromDeviceMap(deviceName,
|
|
registryParam,
|
|
FALSE,
|
|
NULL);
|
|
|
|
if (hkRegistry == NULL)
|
|
{
|
|
TRACE_INIT(("UserInit: GetDriverParams: failed - registry could not be opened\n"));
|
|
retStatus = STATUS_UNSUCCESSFUL;
|
|
}
|
|
else
|
|
{
|
|
for (i=0; i < 8; i++)
|
|
{
|
|
QueryTable[i].Name = DefaultSettings[i];
|
|
}
|
|
|
|
retStatus = RtlQueryRegistryValues(RTL_REGISTRY_HANDLE,
|
|
(PWSTR)hkRegistry,
|
|
&QueryTable[0],
|
|
NULL,
|
|
NULL);
|
|
|
|
ZwClose(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(("UserInit: GetDriverParams: get hardware profile failed - try global settings\n"));
|
|
registryParam = DispDriverRegGlobal;
|
|
}
|
|
|
|
}
|
|
|
|
/*
|
|
* 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 BASVIDEO, since the VGA
|
|
* BASEVIDEO driver need not be configured.
|
|
*/
|
|
|
|
if ((pdevmode->dmBitsPerPel == 0) &&
|
|
(pdevmode->dmPelsWidth == 0) &&
|
|
(pdevmode->dmPelsHeight == 0) &&
|
|
(pdevmode->dmDisplayFrequency == 0) &&
|
|
(pdevmode->dmDisplayFlags == 0) &&
|
|
(gbBaseVideo == FALSE))
|
|
{
|
|
UserLogDisplayDriverEvent(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 (gpDispInfo->cxPixelsPerInch)
|
|
{
|
|
pdevmode->dmLogPixels = gpDispInfo->cxPixelsPerInch;
|
|
}
|
|
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,
|
|
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,
|
|
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);
|
|
}
|
|
|
|
ZwClose(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;
|
|
// }
|
|
|
|
}
|
|
|
|
pdevmode->dmFields = DM_INTERNAL_VALID_FLAGS;
|
|
|
|
TRACE_INIT(("UserInit: GetDriverParams: DEVMODE\n"));
|
|
TRACE_INIT((" Size = %d\n", pdevmode->dmSize));
|
|
TRACE_INIT((" Fields = %08lx\n", pdevmode->dmFields));
|
|
TRACE_INIT((" XResolution = %d\n", pdevmode->dmPelsWidth));
|
|
TRACE_INIT((" YResolution = %d\n", pdevmode->dmPelsHeight));
|
|
TRACE_INIT((" Bpp = %d\n", pdevmode->dmBitsPerPel));
|
|
TRACE_INIT((" Frequency = %d\n", pdevmode->dmDisplayFrequency));
|
|
TRACE_INIT((" Flags = %d\n", pdevmode->dmDisplayFlags));
|
|
TRACE_INIT((" XPanning = %d\n", pdevmode->dmPanningWidth));
|
|
TRACE_INIT((" YPanning = %d\n", pdevmode->dmPanningHeight));
|
|
TRACE_INIT((" DPI = %d\n", pdevmode->dmLogPixels));
|
|
TRACE_INIT((" DriverExtra = %d", pdevmode->dmDriverExtra));
|
|
if (pdevmode->dmDriverExtra) {
|
|
TRACE_INIT((" - %08lx %08lx\n",
|
|
*(PULONG)(((PUCHAR)pdevmode)+pdevmode->dmSize),
|
|
*(PULONG)(((PUCHAR)pdevmode)+pdevmode->dmSize + 4)));
|
|
} else {
|
|
TRACE_INIT(("\n"));
|
|
}
|
|
|
|
} else {
|
|
|
|
TRACE_INIT(("UserInit: GetSetParms: Get failed\n\n"));
|
|
|
|
}
|
|
|
|
TRACE_INIT(("UserInit: GetDriverParams: Exit\n\n"));
|
|
|
|
return (retStatus);
|
|
}
|
|
|
|
|
|
/**************************************************************************\
|
|
* UserWriteDisplayDriverParameters
|
|
*
|
|
* Wites the resolution parameters to the registry.
|
|
*
|
|
* NOTE:
|
|
*
|
|
* CRIT not needed
|
|
*
|
|
* 13-Mar-1996 andreva created
|
|
\**************************************************************************/
|
|
|
|
NTSTATUS
|
|
UserWriteDisplayDriverParameters(
|
|
ULONG RelativeTo,
|
|
PWSTR Path,
|
|
PDEVMODEW pdevmode,
|
|
PRECT pRect)
|
|
{
|
|
ULONG i;
|
|
NTSTATUS retStatus ;
|
|
DWORD data[7];
|
|
|
|
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;
|
|
|
|
for (i=0; i < 7; i++) {
|
|
|
|
retStatus = RtlWriteRegistryValue(RelativeTo,
|
|
Path,
|
|
DefaultSettings[i],
|
|
REG_DWORD,
|
|
&data[i],
|
|
sizeof(DWORD));
|
|
if (!NT_SUCCESS(retStatus)) {
|
|
|
|
//
|
|
// If something failed, stop
|
|
//
|
|
|
|
return retStatus;
|
|
}
|
|
}
|
|
|
|
if (pdevmode->dmDriverExtra) {
|
|
|
|
retStatus = RtlWriteRegistryValue(RelativeTo,
|
|
Path,
|
|
DefaultSettings[7],
|
|
REG_BINARY,
|
|
((PUCHAR)pdevmode) + pdevmode->dmSize,
|
|
pdevmode->dmDriverExtra);
|
|
}
|
|
|
|
if (NT_SUCCESS(retStatus) && pRect) {
|
|
|
|
ULONG attach = 1;
|
|
|
|
if (pRect == (PRECT)-1) {
|
|
attach = 0;
|
|
}
|
|
|
|
data[1] = attach;
|
|
data[2] = attach ? (pRect->left + pRect->right) / 2 : 0;
|
|
data[3] = attach ? (pRect->top + pRect->bottom) / 2 : 0;
|
|
|
|
for (i=1; i < 4; i++) {
|
|
|
|
retStatus = RtlWriteRegistryValue(RelativeTo,
|
|
Path,
|
|
AttachedSettings[i],
|
|
REG_DWORD,
|
|
&data[i],
|
|
sizeof(DWORD));
|
|
if (!NT_SUCCESS(retStatus)) {
|
|
|
|
//
|
|
// If something failed, stop
|
|
//
|
|
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return retStatus;
|
|
}
|
|
|
|
/**************************************************************************\
|
|
* UserSetDisplayDriverParameters
|
|
*
|
|
* Wites the resolution parameters to the registry.
|
|
*
|
|
* NOTE:
|
|
*
|
|
* CRIT not needed
|
|
*
|
|
* 13-Mar-1996 andreva created
|
|
\**************************************************************************/
|
|
|
|
NTSTATUS
|
|
UserSetDisplayDriverParameters(
|
|
PUNICODE_STRING deviceName,
|
|
DISP_DRIVER_PARAM_TYPE ParamType,
|
|
PDEVMODEW pdevmode,
|
|
PRECT pRect)
|
|
{
|
|
|
|
NTSTATUS retStatus = STATUS_UNSUCCESSFUL;
|
|
HANDLE hkRegistry;
|
|
DISP_DRIVER_REGISTRY_TYPE registryParam = DispDriverRegHardwareProfileCreate;
|
|
|
|
TRACE_INIT(("UserInit: SetParms\n"));
|
|
|
|
switch (ParamType) {
|
|
|
|
case DispDriverParamDefault:
|
|
|
|
TRACE_INIT(("UserInit: 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 = UserGetRegistryHandleFromDeviceMap(deviceName,
|
|
registryParam,
|
|
FALSE,
|
|
NULL);
|
|
|
|
if (hkRegistry) {
|
|
|
|
retStatus = UserWriteDisplayDriverParameters(RTL_REGISTRY_HANDLE,
|
|
(LPWSTR) hkRegistry,
|
|
pdevmode,
|
|
pRect);
|
|
ZwClose(hkRegistry);
|
|
}
|
|
|
|
if ( (NT_SUCCESS(retStatus)) ||
|
|
(registryParam != DispDriverRegHardwareProfileCreate) ) {
|
|
break;
|
|
}
|
|
|
|
registryParam = DispDriverRegGlobal;
|
|
}
|
|
|
|
break;
|
|
|
|
case DispDriverParamUser:
|
|
|
|
TRACE_INIT(("UserInit: SetParms: USER Settings\n"));
|
|
|
|
retStatus = UserWriteDisplayDriverParameters(RTL_REGISTRY_USER,
|
|
L"BUGBUG",
|
|
pdevmode,
|
|
pRect);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
RIPMSG0(RIP_ERROR,
|
|
"UserSetDisplayDriverParameters - invalid type\n");
|
|
|
|
retStatus = STATUS_INVALID_PARAMETER;
|
|
|
|
break;
|
|
}
|
|
|
|
|
|
TRACE_INIT(("UserInit: SetParms: Exit\n\n"));
|
|
|
|
return (retStatus);
|
|
}
|
|
|
|
|
|
/**************************************************************************\
|
|
* UserLoadDisplayDriver
|
|
*
|
|
* CRIT not needed.
|
|
*
|
|
* 09-Jan-1992 andreva created
|
|
\**************************************************************************/
|
|
|
|
HDEV UserLoadDisplayDriver(
|
|
PPHYSICAL_DEV_INFO physinfo,
|
|
PUNICODE_STRING deviceName,
|
|
PUNICODE_STRING pstrDisplayDriver,
|
|
LPDEVMODEW lpdevmodeInformation,
|
|
BOOL bDefaultDisplay,
|
|
BOOL bMulti,
|
|
PDEVICE_LOCK *pDevLock)
|
|
{
|
|
|
|
HDEV hdev = NULL;
|
|
LPWSTR lpstrDisplayDriverName;
|
|
LPWSTR lpstrOrg;
|
|
|
|
TRACE_INIT(("UserInit: LoadDisplayDriver: Enter\n"));
|
|
|
|
/*
|
|
* Try to get the display driver list.
|
|
*/
|
|
|
|
lpstrOrg = lpstrDisplayDriverName = UserGetDisplayDriverNames(deviceName);
|
|
|
|
if (lpstrDisplayDriverName != NULL) {
|
|
|
|
TRACE_INIT(("UserInit: LoadDisplayDriver: Display driver list was present.\n"));
|
|
|
|
while (*lpstrDisplayDriverName != UNICODE_NULL) {
|
|
|
|
/*
|
|
* Try to load the driver
|
|
*/
|
|
|
|
TRACE_INIT(("UserInit: LoadDisplayDriver: Trying to load display driver %ws \n", lpstrDisplayDriverName));
|
|
|
|
hdev = GreCreateHDEV(lpstrDisplayDriverName,
|
|
lpdevmodeInformation,
|
|
physinfo->pDeviceHandle,
|
|
bDefaultDisplay,
|
|
pDevLock);
|
|
|
|
/*
|
|
* If this is a multi-display driver, then we have to call down
|
|
* with an MDEV also to complete initialization.
|
|
*
|
|
*
|
|
*/
|
|
|
|
if (hdev && (bMulti == FALSE) &&
|
|
(physinfo->stateFlags & DISPLAY_DEVICE_MULTI_DRIVER)) {
|
|
|
|
MDEV mdev;
|
|
|
|
mdev.mdevID = 'MDEV';
|
|
mdev.cmdev = 1;
|
|
mdev.mdevPos[0].hdev = hdev;
|
|
mdev.mdevPos[0].flags = 0;
|
|
mdev.mdevPos[0].rcPos.left = 0;
|
|
mdev.mdevPos[0].rcPos.top = 0;
|
|
mdev.mdevPos[0].rcPos.right = lpdevmodeInformation->dmPelsWidth;
|
|
mdev.mdevPos[0].rcPos.bottom = lpdevmodeInformation->dmPelsHeight;
|
|
|
|
hdev = GreCreateHDEV(lpstrDisplayDriverName,
|
|
(LPDEVMODEW) &mdev,
|
|
NULL,
|
|
bDefaultDisplay,
|
|
pDevLock);
|
|
}
|
|
|
|
if (hdev) {
|
|
|
|
if (pstrDisplayDriver) {
|
|
RtlCreateUnicodeString(pstrDisplayDriver, lpstrDisplayDriverName);
|
|
}
|
|
|
|
UserAssert(lpdevmodeInformation->dmSize == sizeof(DEVMODEW));
|
|
|
|
break;
|
|
}
|
|
|
|
|
|
TRACE_INIT(("UserInit LoadDisplayDriver: DisplayDriverLoad failed\n"));
|
|
|
|
/*
|
|
* Go to the next name in the list of displays to try again.
|
|
*/
|
|
while (*lpstrDisplayDriverName != UNICODE_NULL) {
|
|
lpstrDisplayDriverName++;
|
|
}
|
|
|
|
lpstrDisplayDriverName++;
|
|
|
|
}
|
|
|
|
UserFreePool(lpstrOrg);
|
|
}
|
|
|
|
TRACE_INIT(("UserInit: LoadDisplayDriver: Exit\n\n"));
|
|
|
|
return hdev;
|
|
|
|
}
|
|
|
|
/**************************************************************************\
|
|
* UserGetDeviceFromName
|
|
*
|
|
* 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.
|
|
*
|
|
* This function is called by the UserServer initialization, GDI CreateDC
|
|
* and by the EnumDisplayDeviceModes functions.
|
|
*
|
|
* returns a PPHYSICAL_DEV_INFO
|
|
*
|
|
* *** NOTE
|
|
* If the caller requests Exclusive access, the caller must call back and
|
|
* release the access once the device is no longer used.
|
|
*
|
|
* CRIT IS REQUIRED !
|
|
*
|
|
* 31-May-1994 andreva created
|
|
\**************************************************************************/
|
|
|
|
PPHYSICAL_DEV_INFO UserGetDeviceFromName(
|
|
PUNICODE_STRING pstrDeviceName,
|
|
ULONG bShareState)
|
|
{
|
|
ULONG i = 0;
|
|
NTSTATUS status;
|
|
PPHYSICAL_DEV_INFO physInfo = NULL;
|
|
PFILE_OBJECT pFileObject = NULL;
|
|
PDEVICE_OBJECT pDeviceObject = NULL;
|
|
UNICODE_STRING uString;
|
|
|
|
TRACE_INIT(("UserInit: GetDev: Enter\n"));
|
|
|
|
/*
|
|
* passing in a NULL string means the default device should be used.
|
|
*/
|
|
if ((pstrDeviceName == NULL) || (pstrDeviceName->Buffer == NULL)) {
|
|
|
|
RIPMSG0(RIP_ERROR, "UserInit: GetDev: NULL name passed in - Exit\n\n");
|
|
return NULL;
|
|
}
|
|
|
|
/*
|
|
* 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(pstrDeviceName,
|
|
&uString,
|
|
TRUE)) {
|
|
|
|
/*
|
|
* This is the VGA device !.
|
|
*/
|
|
|
|
i = 0;
|
|
pDeviceObject = gphysDevInfo[0].pDeviceHandle;
|
|
physInfo = &gphysDevInfo[0];
|
|
|
|
} else {
|
|
|
|
for (i = 1; i < cphysDevInfo; i++) {
|
|
|
|
RtlInitUnicodeString(&uString, gphysDevInfo[i].szNtDeviceName);
|
|
|
|
if (RtlEqualUnicodeString(pstrDeviceName,
|
|
&uString,
|
|
TRUE)) {
|
|
|
|
/*
|
|
* We have the handle to this device.
|
|
*/
|
|
|
|
pDeviceObject = gphysDevInfo[i].pDeviceHandle;
|
|
physInfo = &gphysDevInfo[i];
|
|
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (physInfo == NULL) {
|
|
|
|
RIPMSG0(RIP_WARNING, "UserDeviceFromName: Calling for a non-exsting device!\n");
|
|
return NULL;
|
|
}
|
|
|
|
/*
|
|
* NOTE:
|
|
* We depend on the value of 'i' coming out of the loop in the case
|
|
* we the pDeviceObject is NULL.
|
|
*/
|
|
|
|
TRACE_INIT(("UserInit: GetDev: Acquiring Device\n"));
|
|
|
|
if (pDeviceObject == NULL) {
|
|
|
|
/*
|
|
* Assume failure again by reseting phyinfo to NULL.
|
|
* work off the index 'i' in the gphysinfo array.
|
|
*/
|
|
physInfo = NULL;
|
|
|
|
/*
|
|
* If we are looking for the VGA device (i == 0), and the handle was
|
|
* NULL we can not really initialize it at this point. It may just not
|
|
* exist. So that will simply fail.
|
|
*
|
|
* Try to open any other device
|
|
*/
|
|
if (i != 0) {
|
|
|
|
HANDLE hkRegistry;
|
|
NTSTATUS Status;
|
|
ULONG vgaCompat = 0;
|
|
ULONG defaultValue = 0;
|
|
ULONG multiDriver = 0;
|
|
ULONG mirroring = 0;
|
|
|
|
/*
|
|
* No one owns this device. Let's try to open it.
|
|
*
|
|
|
|
/*
|
|
* Get the sofware configuration data for this driver from
|
|
* the registry, and store it in the physinfo.
|
|
*/
|
|
hkRegistry = UserGetRegistryHandleFromDeviceMap(
|
|
pstrDeviceName,
|
|
DispDriverRegGlobal,
|
|
FALSE,
|
|
&Status);
|
|
if (hkRegistry) {
|
|
|
|
RTL_QUERY_REGISTRY_TABLE multiQueryTable[] = {
|
|
{NULL, RTL_QUERY_REGISTRY_DIRECT, SoftwareSettings[0],
|
|
&multiDriver, REG_DWORD, &defaultValue, 4},
|
|
{NULL, RTL_QUERY_REGISTRY_DIRECT, SoftwareSettings[1],
|
|
&mirroring, REG_DWORD, &defaultValue, 4},
|
|
{NULL, RTL_QUERY_REGISTRY_DIRECT, SoftwareSettings[2],
|
|
&vgaCompat, REG_DWORD, &defaultValue, 4},
|
|
{NULL, 0, NULL}
|
|
};
|
|
|
|
RtlQueryRegistryValues(RTL_REGISTRY_HANDLE,
|
|
(PWSTR)hkRegistry,
|
|
&multiQueryTable[0],
|
|
NULL,
|
|
NULL);
|
|
|
|
ZwClose(hkRegistry);
|
|
|
|
if (multiDriver)
|
|
gphysDevInfo[i].stateFlags |= DISPLAY_DEVICE_MULTI_DRIVER;
|
|
if (mirroring)
|
|
gphysDevInfo[i].stateFlags |= DISPLAY_DEVICE_MIRRORING_DRIVER;
|
|
if (vgaCompat)
|
|
gphysDevInfo[i].stateFlags |= DISPLAY_DEVICE_VGA_COMPATIBLE;
|
|
|
|
TRACE_INIT(("UserInit: GetDev: Display driver is %sa multi display driver\n",
|
|
multiDriver ? "" : "NOT "));
|
|
TRACE_INIT(("UserInit: GetDev: Display driver is %smirroring the desktop\n",
|
|
mirroring ? "" : "NOT "));
|
|
TRACE_INIT(("UserInit: GetDev: Display driver is %sVga Compatible\n",
|
|
vgaCompat ? "" : "NOT "));
|
|
|
|
/*
|
|
* Opening a new device will however 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.
|
|
*/
|
|
if (gpDispInfo->hDev) {
|
|
TRACE_INIT(("UserInit: GetDev: Disabling Global Device\n"));
|
|
bDisableDisplay(gpDispInfo->hDev);
|
|
}
|
|
|
|
status = IoGetDeviceObjectPointer(pstrDeviceName,
|
|
(ACCESS_MASK) (0),
|
|
&pFileObject,
|
|
&pDeviceObject);
|
|
|
|
TRACE_INIT(("UserInit: GetDev: GetDeviceObject on %ws: returned %08lx\n",
|
|
pstrDeviceName->Buffer, pDeviceObject));
|
|
|
|
if (NT_SUCCESS(status)) {
|
|
|
|
/*
|
|
* This is a valid device.
|
|
*/
|
|
gphysDevInfo[i].pDeviceHandle = pDeviceObject;
|
|
gphysDevInfo[i].pFileObject = pFileObject;
|
|
|
|
physInfo = &gphysDevInfo[i];
|
|
|
|
}
|
|
|
|
if (gpDispInfo->hDev) {
|
|
TRACE_INIT(("UserInit: GetDev: Re-enabling global device\n"));
|
|
UserResetDisplayDevice(gpDispInfo->hDev);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* If we are getting the handle, don't let an exclusive request
|
|
* get an exclusive handle
|
|
*/
|
|
|
|
if (physInfo) {
|
|
|
|
/*
|
|
* Getting a NOTOWNED handle always succeeds
|
|
*/
|
|
if (bShareState != USER_DEVICE_NOTOWNED) {
|
|
|
|
if (physInfo->DevOwned == USER_DEVICE_EXCLUSIVE) {
|
|
|
|
/*
|
|
* Oops - failiure
|
|
*/
|
|
RIPMSG0(RIP_ERROR, "UserGetDeviceFromName: Exclusive request on already exclusive device\n");
|
|
physInfo = NULL;
|
|
|
|
} else {
|
|
|
|
if (bShareState == USER_DEVICE_EXCLUSIVE) {
|
|
|
|
if (physInfo->DevOwned == USER_DEVICE_SHARED) {
|
|
|
|
/*
|
|
* Oops - failiure
|
|
*/
|
|
RIPMSG0(RIP_ERROR, "UserGetDeviceFromName: Exclusive request on already exclusive device\n");
|
|
physInfo = NULL;
|
|
|
|
} else {
|
|
|
|
/*
|
|
* Mark the object as now being owned exclusively.
|
|
*/
|
|
physInfo->DevOwned = USER_DEVICE_EXCLUSIVE;
|
|
}
|
|
|
|
} else {
|
|
|
|
/*
|
|
* Mark it as being owned, but shared (so we can create multiple
|
|
* desktops on it.
|
|
*/
|
|
physInfo->DevOwned = USER_DEVICE_SHARED;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (physInfo) {
|
|
/*
|
|
* If the device was acquired properly, increment the share
|
|
* refcount
|
|
*/
|
|
physInfo->cOwnCount++;
|
|
}
|
|
|
|
TRACE_INIT(("UserInit: GetDev: Exit\n\n"));
|
|
|
|
return physInfo;
|
|
|
|
}
|
|
|
|
/**************************************************************************\
|
|
* UserFreeDevice
|
|
*
|
|
* This routine asks for the object exclusive.
|
|
*
|
|
* 11-Aug-1995 andreva created
|
|
\**************************************************************************/
|
|
|
|
VOID UserFreeDevice(
|
|
PPHYSICAL_DEV_INFO physInfo)
|
|
{
|
|
// EnterCrit();
|
|
|
|
if (physInfo == NULL) {
|
|
RIPMSG0(RIP_ERROR, "UserFreeDevice: Releasing a NULL Device!\n");
|
|
}
|
|
|
|
if (physInfo->cOwnCount == 0) {
|
|
RIPMSG0(RIP_ERROR, "UserFreeDevice: Own count is NULL - device not owned !\n");
|
|
}
|
|
|
|
if (--physInfo->cOwnCount == 0) {
|
|
|
|
//
|
|
// The device is no longer in use
|
|
//
|
|
|
|
physInfo->DevOwned = USER_DEVICE_NOTOWNED;
|
|
}
|
|
|
|
// LeaveCrit();
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* UserBuildDevmodeList
|
|
*
|
|
* Builds the list of DEVMODEs for a particular PHYSICAL_DEV_INFO structure
|
|
*
|
|
* CRIT must be held before this call is made.
|
|
*
|
|
* History:
|
|
* 10-Mar-1996 andreva Created.
|
|
\***************************************************************************/
|
|
|
|
VOID
|
|
UserBuildDevmodeList(
|
|
PPHYSICAL_DEV_INFO physinfo)
|
|
{
|
|
|
|
UNICODE_STRING us;
|
|
LPWSTR lpdisplayNames = NULL;
|
|
LPWSTR lpdisplay;
|
|
|
|
DWORD cbOutputSize;
|
|
LPDEVMODEW tmpBuffer;
|
|
PBYTE reallocBuffer;
|
|
|
|
|
|
/*
|
|
* Mirror devices do not report their modes
|
|
* Any operation that requires matching the modes with the device
|
|
* will fail.
|
|
*/
|
|
if (physinfo->stateFlags & DISPLAY_DEVICE_MIRRORING_DRIVER) {
|
|
|
|
UserAssert(physinfo->cbdevmodeInfo == 0);
|
|
UserAssert(physinfo->devmodeInfo == NULL);
|
|
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* 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 physinfo is returned.
|
|
* see InitLoadDriver().
|
|
*/
|
|
|
|
TRACE_INIT(("UserInit: BuildDevmode: Enter\n"));
|
|
|
|
if ( (physinfo->cbdevmodeInfo == 0) &&
|
|
(physinfo->devmodeInfo == NULL) ) {
|
|
|
|
TRACE_INIT(("UserInit: BuildDevmode: Rebuild List\n"));
|
|
|
|
RtlInitUnicodeString(&us, &(physinfo->szNtDeviceName[0]));
|
|
|
|
lpdisplayNames = UserGetDisplayDriverNames(&us);
|
|
|
|
if (lpdisplayNames) {
|
|
|
|
lpdisplay = lpdisplayNames;
|
|
|
|
/*
|
|
* For each Display Driver Name we have, call GDI to get the
|
|
* Devmode information.
|
|
* If the driver returns zero, assume no modes available and
|
|
* go on to the next driver.
|
|
* use a large 60K buffer to call down to the driver
|
|
*/
|
|
|
|
tmpBuffer = UserAllocPoolWithQuota(0xFF00, TAG_SYSTEM);
|
|
|
|
if (tmpBuffer) {
|
|
|
|
while (*lpdisplay != UNICODE_NULL) {
|
|
|
|
//
|
|
// BUGBUG 64K may not be large enough - we may want
|
|
// to retry with a larger buffer !
|
|
//
|
|
|
|
cbOutputSize = GreGetDriverModes(lpdisplay,
|
|
(HANDLE)physinfo->pDeviceHandle,
|
|
0xFF00,
|
|
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 = UserAllocPoolWithQuota(
|
|
physinfo->cbdevmodeInfo + cbOutputSize,
|
|
TAG_SYSTEM);
|
|
|
|
if (reallocBuffer) {
|
|
|
|
if (physinfo->cbdevmodeInfo) {
|
|
|
|
//
|
|
// Copt the contents of the olf buffer
|
|
// and free it
|
|
//
|
|
|
|
RtlCopyMemory(reallocBuffer,
|
|
physinfo->devmodeInfo,
|
|
physinfo->cbdevmodeInfo);
|
|
|
|
UserFreePool(physinfo->devmodeInfo);
|
|
}
|
|
|
|
RtlCopyMemory(reallocBuffer +
|
|
physinfo->cbdevmodeInfo,
|
|
tmpBuffer,
|
|
cbOutputSize);
|
|
|
|
physinfo->cbdevmodeInfo += cbOutputSize;
|
|
physinfo->devmodeInfo = (PDEVMODEW) reallocBuffer;
|
|
|
|
} else {
|
|
|
|
RIPERR0(ERROR_INVALID_PARAMETER, RIP_WARNING, "EnumDisplaySettings failed realloc\n");
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
RIPERR0(ERROR_INVALID_PARAMETER, RIP_WARNING, "EnumDisplaySettings - display driver not present\n");
|
|
|
|
}
|
|
|
|
/*
|
|
* Go to the next name.
|
|
*
|
|
* NOTE: Display driver names are a seried of
|
|
* UNICODE_NULL terminated strings stored in a
|
|
* REG_MULTI_SZ value, and therefore the end of
|
|
* the list is denoted by two
|
|
* consecutive UNICODE_NULL characters.
|
|
*/
|
|
|
|
while (*lpdisplay != UNICODE_NULL) {
|
|
lpdisplay++;
|
|
}
|
|
lpdisplay++;
|
|
|
|
}
|
|
|
|
UserFreePool(tmpBuffer);
|
|
|
|
} else {
|
|
|
|
RIPERR0(ERROR_INVALID_PARAMETER, RIP_WARNING, "EnumDisplaySettings Initial Alloc failed\n");
|
|
}
|
|
|
|
UserFreePool(lpdisplayNames);
|
|
}
|
|
|
|
if ( (physinfo->cbdevmodeInfo == 0) &&
|
|
(physinfo->devmodeInfo == NULL) ) {
|
|
|
|
UserLogDisplayDriverEvent(MsgInvalidDisplayDriver);
|
|
}
|
|
|
|
} else {
|
|
|
|
TRACE_INIT(("UserInit: BuildDevmode: Use cached list\n"));
|
|
|
|
}
|
|
|
|
TRACE_INIT(("UserInit: BuildDevmode: Exit\n\n"));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
/***************************************************************************\
|
|
* UserReleaseDevmodeList
|
|
*
|
|
* Releases the list of DEVMODEs for a particular PHYSICAL_DEV_INFO structure
|
|
*
|
|
* CRIT must be held until after this call is made.
|
|
*
|
|
* History:
|
|
* 10-Mar-1996 andreva Created.
|
|
\***************************************************************************/
|
|
|
|
VOID
|
|
UserReleaseDevmodeList(
|
|
PPHYSICAL_DEV_INFO physinfo)
|
|
{
|
|
/*
|
|
* Free up the resources - as long as it's not the VGA.
|
|
* Assume the VGA is always first
|
|
*/
|
|
|
|
if (physinfo != gphysDevInfo) {
|
|
|
|
physinfo->cbdevmodeInfo = 0;
|
|
|
|
if (physinfo->devmodeInfo) {
|
|
UserFreePool(physinfo->devmodeInfo);
|
|
physinfo->devmodeInfo = NULL;
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
/***************************************************************************\
|
|
* 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
|
|
ProbeAndCaptureDevmode(
|
|
PUNICODE_STRING pstrDeviceName,
|
|
PDEVMODEW *DestinationDevmode,
|
|
PDEVMODEW SourceDevmode,
|
|
BOOL bKernelMode)
|
|
{
|
|
NTSTATUS ntRet;
|
|
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;
|
|
|
|
|
|
TRACE_INIT(("UserInit: CaptMatchDevmode: Entering\n"));
|
|
|
|
*DestinationDevmode = NULL;
|
|
|
|
if (SourceDevmode == NULL) {
|
|
|
|
TRACE_INIT(("UserInit: CaptMatchDevmode: Exit DEVMODE NULL\n\n"));
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
partialDevmode = UserAllocPool(sizeof(DEVMODEW) + MAXUSHORT,
|
|
TAG_DEVMODE);
|
|
|
|
if (partialDevmode == NULL) {
|
|
|
|
TRACE_INIT(("UserInit: 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 (!bKernelMode) {
|
|
ProbeForRead(SourceDevmode,
|
|
FIELD_OFFSET(DEVMODEW, dmFields),
|
|
sizeof(DWORD));
|
|
}
|
|
|
|
/*
|
|
* Capture these so that they don't change right after the probe.
|
|
*/
|
|
|
|
sourceSize = SourceDevmode->dmSize;
|
|
sourceSizeExtra = SourceDevmode->dmDriverExtra;
|
|
|
|
if (!bKernelMode) {
|
|
ProbeForRead(SourceDevmode,
|
|
sourceSize + sourceSizeExtra,
|
|
sizeof(DWORD));
|
|
}
|
|
|
|
/*
|
|
* 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)) {
|
|
|
|
UNICODE_STRING uString;
|
|
|
|
/*
|
|
* 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;
|
|
|
|
RtlInitUnicodeString(&uString, L"VGACOMPATIBLE");
|
|
|
|
if (RtlEqualUnicodeString(pstrDeviceName,
|
|
&uString,
|
|
TRUE)) {
|
|
|
|
/*
|
|
* BUGBUG - need to verify these structures.
|
|
*/
|
|
|
|
TRACE_INIT(("UserInit: CaptMatchDevmode: DEVMODE for fullscreen\n\n"));
|
|
|
|
*partialDevmode = *SourceDevmode;
|
|
|
|
} else {
|
|
|
|
if (!NT_SUCCESS(UserGetDisplayDriverParameters(pstrDeviceName,
|
|
partialDevmode,
|
|
gbBaseVideo))) {
|
|
partialDevmode->dmDriverExtra = 0;
|
|
|
|
if (gpDispInfo->hdcScreen) {
|
|
/*
|
|
* Use the caps as a guess for this.
|
|
*/
|
|
|
|
RIPMSG0(RIP_WARNING, "UserInit: CaptMatchDevmode: Could not get current devmode\n");
|
|
|
|
partialDevmode->dmBitsPerPel =
|
|
GreGetDeviceCaps(gpDispInfo->hdcScreen, BITSPIXEL) *
|
|
GreGetDeviceCaps(gpDispInfo->hdcScreen, PLANES);
|
|
partialDevmode->dmPelsWidth =
|
|
GreGetDeviceCaps(gpDispInfo->hdcScreen, HORZRES);
|
|
partialDevmode->dmPelsHeight =
|
|
GreGetDeviceCaps(gpDispInfo->hdcScreen, VERTRES);
|
|
partialDevmode->dmDisplayFrequency =
|
|
GreGetDeviceCaps(gpDispInfo->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)) &&
|
|
(gpDispInfo->hdcScreen) &&
|
|
(partialDevmode->dmPelsWidth >
|
|
(USHORT) GreGetDeviceCaps(gpDispInfo->hdcScreen,
|
|
HORZRES))) {
|
|
|
|
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) {
|
|
if (SourceDevmode->dmPanningWidth > partialDevmode->dmPelsWidth) {
|
|
btmpError = TRUE;
|
|
}
|
|
tmpPanningWidth = SourceDevmode->dmPanningWidth;
|
|
|
|
} else if ((partialDevmode->dmFields & DM_PANNINGWIDTH) &&
|
|
(partialDevmode->dmPanningWidth <
|
|
partialDevmode->dmPelsWidth)) {
|
|
|
|
tmpPanningWidth = partialDevmode->dmPanningWidth;
|
|
}
|
|
|
|
if (SourceDevmode->dmFields & DM_PANNINGHEIGHT) {
|
|
if (SourceDevmode->dmPanningHeight > partialDevmode->dmPelsHeight) {
|
|
btmpError = TRUE;
|
|
}
|
|
tmpPanningHeight = SourceDevmode->dmPanningHeight;
|
|
|
|
} else if ((partialDevmode->dmFields & DM_PANNINGHEIGHT) &&
|
|
(partialDevmode->dmPanningHeight <
|
|
partialDevmode->dmPelsHeight)) {
|
|
|
|
tmpPanningHeight = partialDevmode->dmPanningHeight;
|
|
}
|
|
|
|
|
|
if (btmpError == TRUE) {
|
|
/*
|
|
* The panning values or the flags are invalid
|
|
*/
|
|
|
|
RIPMSG0(RIP_ERROR, "UserInit: 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;
|
|
}
|
|
|
|
if (matchedDevmode = UserAllocPool(sizeof(DEVMODEW) + sizeExtra,
|
|
TAG_DEVMODE)) {
|
|
|
|
/*
|
|
* Zero out the DEVMODE in case we only get data for part
|
|
* of it from the driver.
|
|
*/
|
|
|
|
RtlZeroMemory(matchedDevmode, sizeof(DEVMODEW));
|
|
|
|
/*
|
|
* 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(("UserInit: CaptMatchDevmode: Capture Complete\n"));
|
|
|
|
} except (EXCEPTION_EXECUTE_HANDLER) {
|
|
RIPNTERR0(GetExceptionCode(), RIP_VERBOSE, "");
|
|
|
|
/*
|
|
* If we hit an exception, free the buffer we have allocated.
|
|
*/
|
|
|
|
if (matchedDevmode) {
|
|
UserFreePool(matchedDevmode);
|
|
}
|
|
|
|
matchedDevmode = NULL;
|
|
}
|
|
|
|
/*
|
|
* This is our matching algorithm, based on requirements from Win95.
|
|
*
|
|
* As a rule, a value in the DEVMODE is only valid is 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) {
|
|
|
|
BOOL bFirstMatch = FALSE;
|
|
BOOL bMatch60 = FALSE;
|
|
BOOL bExactMatch = FALSE;
|
|
PPHYSICAL_DEV_INFO physinfo;
|
|
ULONG cbdevmodeInfo;
|
|
PDEVMODEW pdevmodeInfo;
|
|
|
|
TRACE_INIT(("UserInit: CaptMatchDevmode: Start matching\n"));
|
|
|
|
/*
|
|
* PERF - Can we use someething else to synchronize access to the
|
|
* list of modes ?
|
|
*/
|
|
|
|
physinfo = UserGetDeviceFromName(pstrDeviceName, USER_DEVICE_NOTOWNED);
|
|
|
|
if (physinfo) {
|
|
|
|
// EnterCrit();
|
|
|
|
/*
|
|
* We should never be doing a mode match on a MIRRORING_DRIVER
|
|
*/
|
|
UserAssert(!(physinfo->stateFlags & DISPLAY_DEVICE_MIRRORING_DRIVER));
|
|
|
|
UserBuildDevmodeList(physinfo);
|
|
|
|
cbdevmodeInfo = physinfo->cbdevmodeInfo;
|
|
pdevmodeInfo = physinfo->devmodeInfo;
|
|
|
|
/*
|
|
* If we did not find a mode because the caller was asking for the
|
|
* default mode, then just return the first mode.
|
|
*/
|
|
|
|
if ((partialDevmode->dmBitsPerPel == 0) &&
|
|
(partialDevmode->dmPelsWidth == 0) &&
|
|
(partialDevmode->dmPelsHeight == 0) &&
|
|
(physinfo->cbdevmodeInfo > 0)) {
|
|
|
|
|
|
RIPMSG0(RIP_WARNING, "UserInit: CaptMatchDevmode: DEFAULT DEVMODE returned\n");
|
|
|
|
bFirstMatch = TRUE;
|
|
RtlCopyMemory(matchedDevmode,
|
|
physinfo->devmodeInfo,
|
|
physinfo->devmodeInfo->dmSize);
|
|
|
|
cbdevmodeInfo = 0;
|
|
}
|
|
|
|
while (cbdevmodeInfo > 0) {
|
|
|
|
if ((partialDevmode->dmBitsPerPel ==
|
|
pdevmodeInfo->dmBitsPerPel) &&
|
|
(partialDevmode->dmPelsWidth ==
|
|
pdevmodeInfo->dmPelsWidth) &&
|
|
(partialDevmode->dmPelsHeight ==
|
|
pdevmodeInfo->dmPelsHeight)) {
|
|
|
|
/*
|
|
* 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 (bFirstMatch == FALSE) {
|
|
|
|
/*
|
|
* BUGBUG The driver DEVMODE size could be smaller than
|
|
* our current DEVMODE size.
|
|
*/
|
|
|
|
RtlCopyMemory(matchedDevmode,
|
|
pdevmodeInfo,
|
|
pdevmodeInfo->dmSize);
|
|
|
|
bFirstMatch = TRUE;
|
|
|
|
}
|
|
|
|
if ((bMatch60 == FALSE) &&
|
|
(pdevmodeInfo->dmDisplayFrequency == 60)) {
|
|
|
|
RtlCopyMemory(matchedDevmode,
|
|
pdevmodeInfo,
|
|
pdevmodeInfo->dmSize);
|
|
|
|
bMatch60 = TRUE;
|
|
}
|
|
|
|
if (partialDevmode->dmDisplayFrequency ==
|
|
pdevmodeInfo->dmDisplayFrequency) {
|
|
|
|
/*
|
|
* We found even better than 60 - an exact match !
|
|
*/
|
|
|
|
bMatch60 = TRUE;
|
|
bExactMatch = TRUE;
|
|
|
|
RtlCopyMemory(matchedDevmode,
|
|
pdevmodeInfo,
|
|
pdevmodeInfo->dmSize);
|
|
|
|
break;
|
|
|
|
/*
|
|
* For now, we ignore these other fields since they
|
|
* considered optional.
|
|
*/
|
|
|
|
// pdevmodeInfo->dmDisplayFlags;
|
|
// pdevmodeInfo->dmPanningWidth;
|
|
// pdevmodeInfo->dmPanningHeight;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
cbdevmodeInfo -= (pdevmodeInfo->dmSize +
|
|
pdevmodeInfo->dmDriverExtra);
|
|
|
|
pdevmodeInfo = (PDEVMODEW) ((PUCHAR) pdevmodeInfo +
|
|
pdevmodeInfo->dmSize +
|
|
pdevmodeInfo->dmDriverExtra);
|
|
}
|
|
|
|
/*
|
|
* 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 (bFirstMatch) {
|
|
|
|
matchedDevmode->dmDriverExtra = (WORD) sizeExtra;
|
|
matchedDevmode->dmLogPixels = 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) {
|
|
|
|
RIPMSG0(RIP_WARNING, "UserInit: CaptMatchDevmode: BAD DM FLAGS\n");
|
|
}
|
|
|
|
/*
|
|
* In the case of a good match, also use these extra values.
|
|
*/
|
|
|
|
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 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.
|
|
*/
|
|
/*
|
|
* UserReleaseDevmodeList(physinfo);
|
|
*/
|
|
|
|
/*
|
|
* LeaveCrit();
|
|
*/
|
|
|
|
UserFreeDevice(physinfo);
|
|
}
|
|
|
|
/*
|
|
* Exit path
|
|
*/
|
|
if (bFirstMatch == TRUE) {
|
|
|
|
TRACE_INIT(("UserInit: CaptMatchDevmode: Matched DEVMODE\n"));
|
|
|
|
TRACE_INIT((" Size = %d\n", matchedDevmode->dmSize));
|
|
TRACE_INIT((" Fields = %08lx\n", matchedDevmode->dmFields));
|
|
TRACE_INIT((" XResolution = %d\n", matchedDevmode->dmPelsWidth));
|
|
TRACE_INIT((" YResolution = %d\n", matchedDevmode->dmPelsHeight));
|
|
TRACE_INIT((" Bpp = %d\n", matchedDevmode->dmBitsPerPel));
|
|
TRACE_INIT((" Frequency = %d\n", matchedDevmode->dmDisplayFrequency));
|
|
TRACE_INIT((" Flags = %d\n", matchedDevmode->dmDisplayFlags));
|
|
TRACE_INIT((" XPanning = %d\n", matchedDevmode->dmPanningWidth));
|
|
TRACE_INIT((" YPanning = %d\n", matchedDevmode->dmPanningHeight));
|
|
TRACE_INIT((" DPI = %d\n", matchedDevmode->dmLogPixels));
|
|
TRACE_INIT((" DriverExtra = %d", matchedDevmode->dmDriverExtra));
|
|
if (matchedDevmode->dmDriverExtra) {
|
|
TRACE_INIT((" - %08lx %08lx\n",
|
|
*(PULONG)(((PUCHAR)matchedDevmode)+matchedDevmode->dmSize),
|
|
*(PULONG)(((PUCHAR)matchedDevmode)+matchedDevmode->dmSize + 4)));
|
|
} else {
|
|
TRACE_INIT(("\n"));
|
|
}
|
|
|
|
*DestinationDevmode = matchedDevmode;
|
|
|
|
ntRet = bExactMatch ? STATUS_SUCCESS : STATUS_RECEIVE_PARTIAL;
|
|
|
|
} else {
|
|
|
|
UserFreePool(matchedDevmode);
|
|
ntRet = STATUS_UNSUCCESSFUL;
|
|
}
|
|
}
|
|
|
|
UserFreePool(partialDevmode);
|
|
|
|
if (NT_SUCCESS(ntRet)) {
|
|
if (ntRet == STATUS_RECEIVE_PARTIAL) {
|
|
TRACE_INIT(("UserInit: CaptMatchDevmode: Exit partial success\n\n"));
|
|
} else {
|
|
TRACE_INIT(("UserInit: CaptMatchDevmode: Exit exact success\n\n"));
|
|
}
|
|
} else {
|
|
TRACE_INIT(("UserInit: CaptMatchDevmode: Exit error\n\n"));
|
|
}
|
|
|
|
return (ntRet);
|
|
}
|
|
|
|
|
|
/**************************************************************************\
|
|
* UserDestroyHDEV
|
|
*
|
|
* 20-Jun-1996 andreva created
|
|
\**************************************************************************/
|
|
|
|
VOID
|
|
UserDestroyHDEV(
|
|
HDEV hdev
|
|
)
|
|
{
|
|
GreDestroyHDEV(hdev);
|
|
}
|
|
|
|
/**************************************************************************\
|
|
* UserCreateHDEV
|
|
*
|
|
* 20-Oct-1995 andreva created
|
|
\**************************************************************************/
|
|
|
|
HDEV UserCreateHDEV(
|
|
PUNICODE_STRING pstrDevice,
|
|
LPDEVMODEW lpdevmodeInformation,
|
|
PPHYSICAL_DEV_INFO *physdevinfo,
|
|
PDEVICE_LOCK *pDevLock)
|
|
{
|
|
|
|
HDEV hdev = NULL;
|
|
UNICODE_STRING us;
|
|
PPHYSICAL_DEV_INFO physinfo;
|
|
|
|
TRACE_INIT(("UserInit: UserCreateHDEV: Enter\n"));
|
|
|
|
/*
|
|
* Determine if we have a different device to deal with
|
|
*/
|
|
|
|
physinfo = UserGetDeviceFromName(pstrDevice, USER_DEVICE_SHARED);
|
|
|
|
if (physinfo) {
|
|
|
|
/*
|
|
* Disable the old device since we may reprogramming the same piece
|
|
* of hardware
|
|
* BUGBUG - this needs to be fixed, by determining with which piece
|
|
* of hardware the VGA is assocaited to.
|
|
*/
|
|
|
|
bDisableDisplay(gpDispInfo->hDev);
|
|
|
|
/*
|
|
* Get the list of diplay drivers for this kernel driver.
|
|
*/
|
|
|
|
TRACE_INIT(("UserInit: UserCreateHDEV: Load Display Driver\n"));
|
|
|
|
RtlInitUnicodeString(&us, &physinfo->szNtDeviceName[0]);
|
|
|
|
hdev = UserLoadDisplayDriver(physinfo,
|
|
&us,
|
|
NULL,
|
|
lpdevmodeInformation,
|
|
FALSE,
|
|
FALSE,
|
|
pDevLock);
|
|
|
|
if (hdev) {
|
|
|
|
*physdevinfo = physinfo;
|
|
|
|
} else {
|
|
|
|
TRACE_INIT(("UserCreatePDEV: *** FAILED ***\n"));
|
|
|
|
UserResetDisplayDevice(gpDispInfo->hDev);
|
|
|
|
/*
|
|
* Release the handle to this device
|
|
*/
|
|
|
|
UserFreeDevice(physinfo);
|
|
}
|
|
}
|
|
|
|
TRACE_INIT(("UserInit: UserCreateHDEV: Exit\n\n"));
|
|
|
|
return hdev;
|
|
}
|
|
|
|
/**************************************************************************\
|
|
* UserCreateExclusiveDC
|
|
*
|
|
* 09-08-1995 andreva created
|
|
\**************************************************************************/
|
|
|
|
HDC UserCreateExclusiveDC(
|
|
PUNICODE_STRING pstrDeviceName,
|
|
PDEVMODEW pDevmode,
|
|
PVOID *ppDevice)
|
|
{
|
|
HDC hdc = NULL;
|
|
BYTE DeviceName[256];
|
|
ULONG Value;
|
|
UNICODE_STRING unicodeString;
|
|
UNICODE_STRING CaptDeviceName = *pstrDeviceName;
|
|
|
|
PPHYSICAL_DEV_INFO physinfo;
|
|
HDEV hdev;
|
|
PDEVICE_LOCK pDevLock;
|
|
|
|
|
|
TRACE_INIT(("UserInit: CreateExclusiveDC: Enter\n"));
|
|
|
|
//
|
|
// Attempt to get a handle to the kernel driver.
|
|
// NOTE: mess around with the name to get it the way USER
|
|
// wants it !
|
|
//
|
|
|
|
if (pstrDeviceName->Length > 250)
|
|
{
|
|
RIPERR0(ERROR_INVALID_PARAMETER, RIP_WARNING, "UserInit: CreateExclusiveDC: Exit\n\n");
|
|
|
|
return NULL;
|
|
}
|
|
|
|
//
|
|
// First check if the prefix is right.
|
|
//
|
|
|
|
CaptDeviceName.Length = sizeof(L"\\\\.\\DISPLAY") - sizeof(UNICODE_NULL);
|
|
|
|
RtlInitUnicodeString(&unicodeString,
|
|
L"\\\\.\\DISPLAY");
|
|
|
|
if (RtlEqualUnicodeString(&unicodeString,
|
|
&CaptDeviceName,
|
|
FALSE))
|
|
|
|
{
|
|
TRACE_INIT(("UserInit: CreateExclusiveDC: Generating device name\n"));
|
|
|
|
//
|
|
// Get the number of the video
|
|
//
|
|
|
|
CaptDeviceName = *pstrDeviceName;
|
|
CaptDeviceName.Buffer = (LPWSTR) (((PUCHAR)CaptDeviceName.Buffer) +
|
|
sizeof(L"\\\\.\\DISPLAY") -
|
|
sizeof(UNICODE_NULL));
|
|
|
|
CaptDeviceName.Length -= (sizeof(L"\\\\.\\DISPLAY") - sizeof(UNICODE_NULL));
|
|
|
|
RtlUnicodeStringToInteger(&CaptDeviceName,
|
|
10,
|
|
&Value);
|
|
|
|
//
|
|
// Put the prefix of the new string in the buffer.
|
|
//
|
|
|
|
|
|
RtlCopyMemory(DeviceName,
|
|
L"\\Device\\Video",
|
|
sizeof(L"\\Device\\Video"));
|
|
|
|
//
|
|
// Append the number at the end (number - 1 !!!)
|
|
//
|
|
|
|
unicodeString.Buffer = (LPWSTR) (((PUCHAR)DeviceName) +
|
|
sizeof(L"\\Device\\Video") -
|
|
sizeof(UNICODE_NULL));
|
|
unicodeString.Length =
|
|
unicodeString.MaximumLength = 256;
|
|
|
|
RtlIntegerToUnicodeString(Value - 1,
|
|
10,
|
|
&unicodeString);
|
|
|
|
//
|
|
// Reset the string size and pointer.
|
|
//
|
|
|
|
unicodeString.Buffer = ((LPWSTR)DeviceName);
|
|
unicodeString.Length += (sizeof(L"\\Device\\Video") - sizeof(UNICODE_NULL));
|
|
|
|
TRACE_INIT(("UserInit: CreateExclusiveDC: device Name %ws\n", DeviceName));
|
|
|
|
/*
|
|
* Grab the User Crit since we are going to access User data
|
|
*/
|
|
// EnterCrit();
|
|
|
|
/*
|
|
* Ask for the object exclusive.
|
|
*/
|
|
|
|
physinfo = UserGetDeviceFromName(&unicodeString, USER_DEVICE_EXCLUSIVE);
|
|
|
|
if (physinfo) {
|
|
|
|
PDEVMODEW pCaptDevmode;
|
|
|
|
TRACE_INIT(("UserInit: CreateExclusiveDC: Got the display device handle\n"));
|
|
|
|
UserAssert(pDevmode != NULL);
|
|
|
|
if (NT_SUCCESS(ProbeAndCaptureDevmode(&unicodeString,
|
|
&pCaptDevmode,
|
|
pDevmode,
|
|
TRUE))) {
|
|
|
|
hdev = UserLoadDisplayDriver(physinfo,
|
|
&unicodeString,
|
|
NULL,
|
|
pCaptDevmode,
|
|
FALSE,
|
|
FALSE,
|
|
&pDevLock);
|
|
|
|
if (hdev)
|
|
{
|
|
TRACE_INIT(("UserInit: CreateExclusiveDC: We have an hdev\n"));
|
|
|
|
hdc = GreCreateDisplayDC(hdev, DCTYPE_DIRECT, FALSE);
|
|
|
|
if (hdc == NULL)
|
|
{
|
|
TRACE_INIT(("UserInit: CreateExclusiveDC: Failed to get DC\n"));
|
|
GreDestroyHDEV(hdev);
|
|
}
|
|
}
|
|
|
|
UserFreePool(pCaptDevmode);
|
|
}
|
|
|
|
//
|
|
// We may have to free the device manually if an error occured
|
|
// part way through
|
|
// After SetPhysicalDevice is done, Freeing the Device is done
|
|
// as part of the PDEV destructor
|
|
//
|
|
|
|
if (hdc == NULL)
|
|
{
|
|
UserFreeDevice(physinfo);
|
|
*ppDevice = NULL;
|
|
}
|
|
else
|
|
{
|
|
*ppDevice = physinfo;
|
|
}
|
|
}
|
|
|
|
// LeaveCrit();
|
|
}
|
|
|
|
TRACE_INIT(("UserInit: CreateExclusiveDC: Exit\n\n"));
|
|
|
|
return (hdc);
|
|
}
|
|
|
|
/**************************************************************************\
|
|
* UserDeleteExclusiveDC
|
|
*
|
|
* This routine frees an exclusive DC.
|
|
* Actually, the DC will already be deleted - only the device needs to be
|
|
* freed
|
|
*
|
|
* 08-Sep-1995 andreva created
|
|
\**************************************************************************/
|
|
|
|
VOID UserDeleteExclusiveDC(
|
|
HDC hdc,
|
|
PVOID pDevice)
|
|
{
|
|
EnterCrit();
|
|
UserFreeDevice((PPHYSICAL_DEV_INFO) pDevice);
|
|
LeaveCrit();
|
|
|
|
return;
|
|
|
|
hdc;
|
|
}
|
|
|
|
|
|
|
|
/**************************************************************************\
|
|
* InitUserScreen
|
|
*
|
|
*
|
|
* 12-Jan-1994 andreva Created
|
|
* 23-Jan-1995 ChrisWil ChangeDisplaySettings work.
|
|
\**************************************************************************/
|
|
|
|
VOID InitUserScreen(VOID)
|
|
{
|
|
RECT rc;
|
|
|
|
TRACE_INIT(("UserInit: Initialize Screen\n"));
|
|
|
|
/*
|
|
* Create screen and memory dcs.
|
|
*/
|
|
gpDispInfo->hdcScreen = GreCreateDisplayDC(gpDispInfo->hDev, DCTYPE_DIRECT, FALSE);
|
|
GreSelectFont(gpDispInfo->hdcScreen, GreGetStockObject(SYSTEM_FONT));
|
|
GreSetDCOwner(gpDispInfo->hdcScreen, OBJECT_OWNER_PUBLIC);
|
|
|
|
gpDispInfo->hdcBits = GreCreateCompatibleDC(gpDispInfo->hdcScreen);
|
|
GreSelectFont(gpDispInfo->hdcBits, GreGetStockObject(SYSTEM_FONT));
|
|
GreSetDCOwner(gpDispInfo->hdcBits, OBJECT_OWNER_PUBLIC);
|
|
|
|
ghdcMem = GreCreateCompatibleDC(gpDispInfo->hdcScreen);
|
|
GreSetDCOwner(ghdcMem, OBJECT_OWNER_PUBLIC);
|
|
|
|
ghdcMem2 = GreCreateCompatibleDC(gpDispInfo->hdcScreen);
|
|
GreSetDCOwner(ghdcMem2, OBJECT_OWNER_PUBLIC);
|
|
|
|
/*
|
|
* We need this when we initialize the first client; winlogon
|
|
* which is before InitWinStaDevices is called
|
|
*/
|
|
gpDispInfo->cxPixelsPerInch = GreGetDeviceCaps(gpDispInfo->hdcScreen, LOGPIXELSX);
|
|
gpDispInfo->cyPixelsPerInch = GreGetDeviceCaps(gpDispInfo->hdcScreen, LOGPIXELSY);
|
|
gpDispInfo->cPlanes = GreGetDeviceCaps(gpDispInfo->hdcScreen, PLANES);
|
|
gpDispInfo->cBitsPixel = GreGetDeviceCaps(gpDispInfo->hdcScreen, BITSPIXEL);
|
|
|
|
SYSMET(CXSCREEN) = GreGetDeviceCaps(gpDispInfo->hdcScreen, HORZRES);
|
|
SYSMET(CYSCREEN) = GreGetDeviceCaps(gpDispInfo->hdcScreen, VERTRES);
|
|
|
|
SetRect(&gpDispInfo->rcScreen,
|
|
0,
|
|
0,
|
|
GreGetDeviceCaps(gpDispInfo->hdcScreen, DESKTOPHORZRES),
|
|
GreGetDeviceCaps(gpDispInfo->hdcScreen, DESKTOPVERTRES));
|
|
|
|
SetRect(&gpDispInfo->rcPrimaryScreen,
|
|
0,
|
|
0,
|
|
SYSMET(CXSCREEN),
|
|
SYSMET(CYSCREEN));
|
|
|
|
CopyRect(&(gpsi->rcWork), &gpDispInfo->rcScreen);
|
|
|
|
/*
|
|
* Do some initialization so we create the system colors.
|
|
*/
|
|
FastOpenProfileUserMapping();
|
|
|
|
/*
|
|
* Get the window sizing border width from WIN.INI.
|
|
*/
|
|
gpsi->gclBorder = FastGetProfileIntFromID(PMAP_DESKTOP, STR_BORDERWIDTH, 3);
|
|
if (gpsi->gclBorder < 1)
|
|
gpsi->gclBorder = 1;
|
|
else if (gpsi->gclBorder > 50)
|
|
gpsi->gclBorder = 50;
|
|
|
|
xxxLW_DCInit();
|
|
|
|
FastCloseProfileUserMapping();
|
|
|
|
/*
|
|
* Set up a desktop info structure that is visible in all
|
|
* clients.
|
|
*/
|
|
gpdiStatic = SharedAlloc(sizeof(DESKTOPINFO));
|
|
RtlZeroMemory(gpdiStatic, sizeof(*gpdiStatic));
|
|
|
|
/*
|
|
* Paint the screen background.
|
|
*/
|
|
SetRect(&rc, 0, 0, SYSMET(CXSCREEN), SYSMET(CYSCREEN));
|
|
FillRect(gpDispInfo->hdcScreen, &rc, SYSHBR(DESKTOP));
|
|
}
|
|
|
|
|
|
/***************************************************************************\
|
|
* InitLoadDriver
|
|
*
|
|
* This routine performs the driver-loader sequence.
|
|
*
|
|
* andreva Created
|
|
\***************************************************************************/
|
|
|
|
NTSTATUS InitLoadDriver(VOID)
|
|
{
|
|
DWORD i, ii, iii, k;
|
|
NTSTATUS Status;
|
|
PDEVMODEW pdevmodeInformation;
|
|
DEVMODEW sourceDevmodeInformation;
|
|
LPWSTR hardErrorString;
|
|
UNICODE_STRING UnicodeString;
|
|
UNICODE_STRING UnicodeDeviceName;
|
|
HANDLE hkRegistry = NULL;
|
|
BOOL bCheckForAttached;
|
|
BOOL bAttachMirroring = FALSE;
|
|
ULONG attached;
|
|
ULONG primary;
|
|
ULONG mdevMultiDriver;
|
|
ULONG mdevPrimary = (ULONG) -1;
|
|
BOOL mdevPrimaryset = FALSE;
|
|
BOOL displayInstalled = FALSE;
|
|
BOOL vgaInstalled = FALSE;
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
PPHYSICAL_DEV_INFO pphysinfo;
|
|
BOOL bKeepDevice;
|
|
BOOL gbBaseVideoold;
|
|
|
|
// TEMP
|
|
DISPLAYINFO localDispInfo[7] = {0};
|
|
MDEV mdev[7];
|
|
|
|
|
|
TRACE_INIT(("UserInit: Starting Display Driver Load Sequence\n"));
|
|
|
|
/*
|
|
* Lets determine if the user specified a primary output device in the
|
|
* case where they may be multiple video cards.
|
|
*/
|
|
TRACE_INIT(("UserInit: LoadDriver: Looking for a primary device\n"));
|
|
|
|
/*
|
|
* 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,
|
|
NULL,
|
|
NULL);
|
|
|
|
Status = ZwOpenKey(&hkRegistry,
|
|
KEY_READ,
|
|
&ObjectAttributes);
|
|
|
|
if (NT_SUCCESS( Status)) {
|
|
|
|
TRACE_INIT(("UserInit: LoadDriver: Found Basevideo\n"));
|
|
|
|
gbBaseVideo = TRUE;
|
|
ZwClose(hkRegistry);
|
|
|
|
bCheckForAttached = FALSE;
|
|
|
|
} else {
|
|
|
|
bCheckForAttached = TRUE;
|
|
|
|
}
|
|
|
|
hkRegistry = NULL;
|
|
|
|
/*
|
|
* First time through the loop - try to find BASEVIDEO, if needed.
|
|
* Second pass through the loop - find all the devices that are atached
|
|
* to the desktop.
|
|
* Third time through the loop - try to find any device that we can boot
|
|
* with.
|
|
* Fourth time through the loop - try to find any mirroring device.
|
|
*/
|
|
|
|
while (1) {
|
|
|
|
for (i = 1; i < cphysDevInfo; i++) {
|
|
|
|
/*
|
|
* NOTE:
|
|
* Because we have many continue, break etc commands, lets close
|
|
* our registry handle if we have one
|
|
*/
|
|
|
|
if (hkRegistry) {
|
|
ZwClose(hkRegistry);
|
|
hkRegistry = NULL;
|
|
}
|
|
|
|
bKeepDevice = FALSE;
|
|
|
|
/*****************************************************************
|
|
*****************************************************************
|
|
Get Device Information
|
|
*****************************************************************
|
|
*****************************************************************/
|
|
|
|
TRACE_INIT(("\nUserInit: LoadDriver: Trying to open device %ws \n", gphysDevInfo[i].szNtDeviceName));
|
|
|
|
RtlInitUnicodeString(&UnicodeDeviceName, gphysDevInfo[i].szNtDeviceName);
|
|
|
|
hkRegistry = UserGetRegistryHandleFromDeviceMap(&UnicodeDeviceName,
|
|
DispDriverRegGlobal,
|
|
gbBaseVideo,
|
|
&Status);
|
|
|
|
if (hkRegistry == NULL) {
|
|
|
|
/*
|
|
* Check the return code.
|
|
* If we just have bad configuration data, go to the next device.
|
|
*/
|
|
if (Status == STATUS_DEVICE_CONFIGURATION_ERROR) {
|
|
|
|
/*
|
|
* The registry is not configured properly for that device.
|
|
* go on to the next one.
|
|
*/
|
|
UserLogDisplayDriverEvent(MsgInvalidConfiguration);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
/*
|
|
* continue on a NO_SUCH_DEVICE because we are looking for
|
|
* a specific device, and we don't know it's number.
|
|
* We get a different error when there are no more devices.
|
|
*/
|
|
|
|
if (gbBaseVideo) {
|
|
|
|
if (Status == STATUS_NO_SUCH_DEVICE) {
|
|
continue;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* We must be out of devices. Exit the loop
|
|
*/
|
|
break;
|
|
}
|
|
|
|
/*
|
|
* Get the attached and primary data, which is per config (or also
|
|
* global if necessary.
|
|
*/
|
|
|
|
attached = 0;
|
|
primary = 0;
|
|
localDispInfo[i].rcScreen.left = DEFAULT_POS_VALUE;
|
|
localDispInfo[i].rcScreen.top = DEFAULT_POS_VALUE;
|
|
|
|
if (bCheckForAttached) {
|
|
|
|
HANDLE hk2Registry = NULL;
|
|
ULONG defaultValue = 0;
|
|
ULONG defaultPosValue = DEFAULT_POS_VALUE;
|
|
|
|
RTL_QUERY_REGISTRY_TABLE AttachedQueryTable[] = {
|
|
{NULL, RTL_QUERY_REGISTRY_DIRECT, AttachedSettings[0],
|
|
&primary, REG_DWORD, &defaultValue, 4},
|
|
{NULL, RTL_QUERY_REGISTRY_DIRECT, AttachedSettings[1],
|
|
&attached, REG_DWORD, &defaultValue, 4},
|
|
{NULL, RTL_QUERY_REGISTRY_DIRECT, AttachedSettings[2],
|
|
&localDispInfo[i].rcScreen.left, REG_DWORD, &defaultPosValue, 4},
|
|
{NULL, RTL_QUERY_REGISTRY_DIRECT, AttachedSettings[3],
|
|
&localDispInfo[i].rcScreen.top, REG_DWORD, &defaultPosValue, 4},
|
|
{NULL, 0, NULL}
|
|
};
|
|
|
|
hk2Registry = UserGetRegistryHandleFromDeviceMap(&UnicodeDeviceName,
|
|
DispDriverRegHardwareProfile,
|
|
FALSE,
|
|
NULL);
|
|
if (hk2Registry) {
|
|
|
|
RtlQueryRegistryValues(RTL_REGISTRY_HANDLE,
|
|
(PWSTR)hk2Registry,
|
|
&AttachedQueryTable[0],
|
|
NULL,
|
|
NULL);
|
|
|
|
ZwClose(hk2Registry);
|
|
|
|
} else {
|
|
|
|
RtlQueryRegistryValues(RTL_REGISTRY_HANDLE,
|
|
(PWSTR)hkRegistry,
|
|
&AttachedQueryTable[0],
|
|
NULL,
|
|
NULL);
|
|
}
|
|
|
|
TRACE_INIT(("UserInit: LoadDriver: Display driver is %sprimary on the desktop\n",
|
|
primary ? "" : "NOT "));
|
|
TRACE_INIT(("UserInit: LoadDriver: Display driver is %sattached to the desktop\n",
|
|
attached ? "" : "NOT "));
|
|
|
|
if (attached) {
|
|
TRACE_INIT(("UserInit: LoadDriver: Display driver is center positioned at %d, %d\n",
|
|
localDispInfo[i].rcScreen.left,
|
|
localDispInfo[i].rcScreen.top));
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Open the kernel driver if we need it for the display driver
|
|
* or for the VGA support.
|
|
* Open it shared so we can still create other desktops on
|
|
* the device.
|
|
*/
|
|
|
|
RtlInitUnicodeString(&UnicodeString, gphysDevInfo[i].szNtDeviceName);
|
|
|
|
pphysinfo = UserGetDeviceFromName(&UnicodeString, USER_DEVICE_SHARED);
|
|
|
|
/*
|
|
* If there is an error opening the kernel driver, go to the next
|
|
* driver.
|
|
*/
|
|
if (pphysinfo == NULL) {
|
|
RIPMSG0(RIP_WARNING, "UserInit: LoadDriver: Error opening kernel video driver");
|
|
continue;
|
|
}
|
|
|
|
if (pphysinfo != &(gphysDevInfo[i])) {
|
|
RIPMSG0(RIP_ERROR, "UserInit: LoadDriver: Inconsistent pphysinfo\n");
|
|
}
|
|
|
|
|
|
/*****************************************************************
|
|
*****************************************************************
|
|
VGA Compatibility
|
|
*****************************************************************
|
|
*****************************************************************/
|
|
|
|
/*
|
|
* If the vgaCompatible display is not installed, check this one.
|
|
* If it is the vgacompatible driver, set the installed flag to
|
|
* TRUE and save the info in the zeroth entry - reserved for VGA.
|
|
*/
|
|
#if defined (_X86_)
|
|
|
|
if ((vgaInstalled == FALSE) &&
|
|
(gphysDevInfo[i].stateFlags & DISPLAY_DEVICE_VGA_COMPATIBLE)) {
|
|
#else
|
|
if (0) {
|
|
#endif
|
|
VIDEO_NUM_MODES NumModes;
|
|
ULONG NumModesLength = sizeof(NumModes);
|
|
ULONG cbBuffer;
|
|
ULONG BytesReturned;
|
|
|
|
PVIDEO_MODE_INFORMATION lpModes;
|
|
PVIDEO_MODE_INFORMATION pVideoModeSave;
|
|
|
|
ULONG cbdevmodeInfo = 0;
|
|
LPDEVMODEW pDevmode;
|
|
LPDEVMODEW pDevmodeSave;
|
|
|
|
/*
|
|
* Build the list of text modes for this device
|
|
*/
|
|
TRACE_INIT(("UserInit: LoadDriver: get text modes\n"));
|
|
|
|
Status = GreDeviceIoControl(gphysDevInfo[i].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)
|
|
UserAllocPool(cbBuffer, TAG_SYSTEM)) )
|
|
{
|
|
Status = GreDeviceIoControl(gphysDevInfo[i].pDeviceHandle,
|
|
IOCTL_VIDEO_QUERY_AVAIL_MODES,
|
|
NULL,
|
|
0,
|
|
lpModes,
|
|
cbBuffer,
|
|
&BytesReturned);
|
|
|
|
pVideoModeSave = lpModes;
|
|
|
|
/*
|
|
* We will not support mode than three text modes.
|
|
* So just allocate enough for that.
|
|
*/
|
|
if ((NT_SUCCESS(Status)) &&
|
|
(pDevmode = (LPDEVMODEW)
|
|
UserAllocPool(3 * sizeof(DEVMODEW), TAG_SYSTEM))) {
|
|
|
|
pDevmodeSave = pDevmode;
|
|
|
|
memset(pDevmode, 0, 3 * sizeof(DEVMODEW));
|
|
|
|
TRACE_INIT(("UserInit: LoadDriver: parsing text modes\n"));
|
|
|
|
while (cbBuffer != 0) {
|
|
|
|
if ((lpModes->AttributeFlags & VIDEO_MODE_COLOR) &&
|
|
(!(lpModes->AttributeFlags & VIDEO_MODE_GRAPHICS)))
|
|
{
|
|
|
|
/*
|
|
* Make sure we have no more than 3 text modes
|
|
*/
|
|
if (cbdevmodeInfo == 3 * sizeof(DEVMODEW)) {
|
|
RIPMSG0(RIP_ERROR, "UserInit: VGA compatible device has too many text modes\n");
|
|
break;
|
|
}
|
|
|
|
RtlZeroMemory(pDevmode, sizeof(DEVMODEW));
|
|
|
|
memcpy(pDevmode->dmDeviceName,
|
|
L"FULLSCREEN CONSOLE",
|
|
sizeof(L"FULLSCREEN CONSOLE"));
|
|
|
|
pDevmode->dmSize = sizeof(DEVMODEW);
|
|
pDevmode->dmSpecVersion = DM_SPECVERSION;
|
|
pDevmode->dmDriverVersion = DM_SPECVERSION;
|
|
pDevmode->dmDisplayFlags = DMDISPLAYFLAGS_TEXTMODE;
|
|
|
|
pDevmode->dmPelsWidth =
|
|
lpModes->VisScreenWidth;
|
|
pDevmode->dmPelsHeight =
|
|
lpModes->VisScreenHeight;
|
|
pDevmode->dmBitsPerPel =
|
|
lpModes->NumberOfPlanes *
|
|
lpModes->BitsPerPlane;
|
|
|
|
pDevmode->dmFields = DM_BITSPERPEL |
|
|
DM_PELSWIDTH |
|
|
DM_PELSHEIGHT |
|
|
DM_DISPLAYFLAGS ;
|
|
|
|
/*
|
|
* NOTE !!!
|
|
* As a hack, lets store the mode number in
|
|
* a field we don't use
|
|
*/
|
|
pDevmode->dmOrientation =
|
|
(USHORT) lpModes->ModeIndex;
|
|
|
|
cbdevmodeInfo += sizeof(DEVMODEW);
|
|
pDevmode += 1;
|
|
|
|
}
|
|
|
|
cbBuffer -= NumModes.ModeInformationLength;
|
|
|
|
lpModes = (PVIDEO_MODE_INFORMATION)
|
|
(((PUCHAR)lpModes) + NumModes.ModeInformationLength);
|
|
}
|
|
}
|
|
|
|
UserFreePool(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 (cbdevmodeInfo) {
|
|
|
|
vgaInstalled = TRUE;
|
|
|
|
TRACE_INIT(("UserInit: LoadDriver: saving VGA compatible device\n"));
|
|
|
|
/*
|
|
* Copy the string and the handle ...
|
|
*/
|
|
RtlCopyMemory(gphysDevInfo[0].szNtDeviceName,
|
|
gphysDevInfo[i].szNtDeviceName,
|
|
sizeof(PHYSICAL_DEV_INFO));
|
|
|
|
gphysDevInfo[0].cbdevmodeInfo = cbdevmodeInfo;
|
|
gphysDevInfo[0].devmodeInfo = pDevmodeSave;
|
|
|
|
RtlWriteRegistryValue(RTL_REGISTRY_DEVICEMAP,
|
|
L"Video",
|
|
L"VgaCompatible",
|
|
REG_SZ,
|
|
UnicodeDeviceName.Buffer,
|
|
UnicodeDeviceName.Length +
|
|
sizeof(UNICODE_NULL));
|
|
|
|
/*
|
|
* Mark this device as being used
|
|
*/
|
|
bKeepDevice = TRUE;
|
|
} else {
|
|
RIPMSG0(RIP_ERROR, "UserInit: VGA compatible device has NO text modes!\n");
|
|
}
|
|
}
|
|
|
|
|
|
/*****************************************************************
|
|
*****************************************************************
|
|
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 ( (bCheckForAttached &&
|
|
attached &&
|
|
( (bAttachMirroring &&
|
|
(gphysDevInfo[i].stateFlags &
|
|
DISPLAY_DEVICE_MIRRORING_DRIVER))
|
|
|
|
||
|
|
|
|
(!bAttachMirroring &&
|
|
!(gphysDevInfo[i].stateFlags &
|
|
DISPLAY_DEVICE_MIRRORING_DRIVER))
|
|
)
|
|
)
|
|
|
|
||
|
|
|
|
(!bCheckForAttached && !displayInstalled)) {
|
|
|
|
/*
|
|
* 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 nto 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 (gphysDevInfo[i].stateFlags & DISPLAY_DEVICE_MIRRORING_DRIVER) {
|
|
|
|
/*
|
|
* In the case of mirroring, we want to use the same
|
|
* DEVMODE as was provided for the main display. We also
|
|
* want to make sure we do it after the proper displays
|
|
* have been loaded.
|
|
*/
|
|
|
|
/*
|
|
* If we have no primary at this point, we are in trouble !
|
|
*/
|
|
if (mdevPrimary == (ULONG) -1) {
|
|
UserAssert(mdevPrimary != (ULONG) -1);
|
|
break;
|
|
}
|
|
|
|
pdevmodeInformation = &sourceDevmodeInformation;
|
|
|
|
RtlCopyMemory(&sourceDevmodeInformation,
|
|
gphysDevInfo[mdevPrimary].pCurrentDevmode,
|
|
sizeof(DEVMODEW));
|
|
|
|
Status = STATUS_SUCCESS;
|
|
|
|
} else {
|
|
|
|
RtlZeroMemory(&sourceDevmodeInformation, sizeof(DEVMODEW));
|
|
sourceDevmodeInformation.dmSize = sizeof(DEVMODEW);
|
|
|
|
Status = ProbeAndCaptureDevmode(&UnicodeDeviceName,
|
|
&pdevmodeInformation,
|
|
&sourceDevmodeInformation,
|
|
TRUE);
|
|
}
|
|
|
|
if (NT_SUCCESS(Status)) {
|
|
|
|
if (Status == STATUS_RECEIVE_PARTIAL) {
|
|
|
|
UserLogDisplayDriverEvent(MsgInvalidDisplayMode);
|
|
}
|
|
|
|
localDispInfo[i].hDev = UserLoadDisplayDriver(&gphysDevInfo[i],
|
|
&UnicodeDeviceName,
|
|
&strDisplayDriver,
|
|
pdevmodeInformation,
|
|
// BUGBUG TRUE or FALSE for multi ?
|
|
TRUE,
|
|
TRUE,
|
|
(PDEVICE_LOCK *)&localDispInfo[i].pDevLock);
|
|
}
|
|
|
|
/*
|
|
* We failed to load a display driver with this devmode.
|
|
* Try to pick the first valid Devmode.
|
|
*
|
|
* The trick to do this is to turn on BaseVideo temporarily.
|
|
*/
|
|
|
|
if (!localDispInfo[i].hDev) {
|
|
|
|
UserLogDisplayDriverEvent(MsgInvalidDisplayMode);
|
|
|
|
/*
|
|
* Free memory allocated by ProbeAndCaptureDevmode
|
|
*/
|
|
|
|
if (pdevmodeInformation) {
|
|
|
|
/*
|
|
* Log an error saying the selected color or
|
|
* resolution is invalid.
|
|
*/
|
|
if (pdevmodeInformation->dmBitsPerPel == 0x4) {
|
|
|
|
UserLogDisplayDriverEvent(MsgInvalidDisplay16Colors);
|
|
}
|
|
|
|
|
|
if (pdevmodeInformation != &sourceDevmodeInformation) {
|
|
|
|
UserFreePool(pdevmodeInformation);
|
|
pdevmodeInformation = NULL;
|
|
}
|
|
}
|
|
|
|
TRACE_INIT(("UserInit: LoadDriver: Trying first DEVMODE\n"));
|
|
|
|
RtlZeroMemory(&sourceDevmodeInformation, sizeof(DEVMODEW));
|
|
sourceDevmodeInformation.dmSize = sizeof(DEVMODEW);
|
|
|
|
gbBaseVideoold = gbBaseVideo;
|
|
gbBaseVideo = TRUE;
|
|
|
|
if (ProbeAndCaptureDevmode(&UnicodeDeviceName,
|
|
&pdevmodeInformation,
|
|
&sourceDevmodeInformation,
|
|
TRUE))
|
|
{
|
|
gbBaseVideo = gbBaseVideoold;
|
|
|
|
localDispInfo[i].hDev = UserLoadDisplayDriver(&gphysDevInfo[i],
|
|
&UnicodeDeviceName,
|
|
&strDisplayDriver,
|
|
pdevmodeInformation,
|
|
TRUE,
|
|
TRUE,
|
|
(PDEVICE_LOCK *)&localDispInfo[i].pDevLock);
|
|
}
|
|
|
|
gbBaseVideo = gbBaseVideoold;
|
|
}
|
|
|
|
/*
|
|
* We failed everything - try the NULL DEVMODE which should always
|
|
* work.
|
|
*/
|
|
|
|
if (!localDispInfo[i].hDev) {
|
|
|
|
if (pdevmodeInformation &&
|
|
(pdevmodeInformation != &sourceDevmodeInformation)) {
|
|
|
|
UserFreePool(pdevmodeInformation);
|
|
pdevmodeInformation = NULL;
|
|
}
|
|
|
|
TRACE_INIT(("UserInit: LoadDriver: Trying default DEVMODE\n"));
|
|
|
|
RtlZeroMemory(&sourceDevmodeInformation, sizeof(DEVMODEW));
|
|
sourceDevmodeInformation.dmSize = 0xDDDD;
|
|
pdevmodeInformation = &sourceDevmodeInformation;
|
|
|
|
if (NT_SUCCESS(UserGetDisplayDriverParameters(&UnicodeDeviceName,
|
|
&sourceDevmodeInformation,
|
|
TRUE))) {
|
|
|
|
localDispInfo[i].hDev = UserLoadDisplayDriver(&gphysDevInfo[i],
|
|
&UnicodeDeviceName,
|
|
&strDisplayDriver,
|
|
pdevmodeInformation,
|
|
TRUE,
|
|
TRUE,
|
|
(PDEVICE_LOCK *)&localDispInfo[i].pDevLock);
|
|
}
|
|
}
|
|
|
|
if (localDispInfo[i].hDev) {
|
|
|
|
TRACE_INIT(("UserInit: LoadDriver: 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 used so we do not free it's
|
|
* handle.
|
|
*/
|
|
bKeepDevice = TRUE;
|
|
|
|
/*
|
|
* Mark this device as being part of the primary device
|
|
*/
|
|
if (attached)
|
|
gphysDevInfo[i].stateFlags |= DISPLAY_DEVICE_ATTACHED_TO_DESKTOP;
|
|
|
|
if (primary)
|
|
gphysDevInfo[i].stateFlags |= DISPLAY_DEVICE_PRIMARY_DEVICE;
|
|
|
|
/*
|
|
* Save the current mode for this device.
|
|
*/
|
|
UserSaveCurrentMode(NULL, &gphysDevInfo[i], pdevmodeInformation);
|
|
|
|
} else {
|
|
|
|
/*
|
|
* If no display driver initialized with the requested
|
|
* settings, put a message in the error log.
|
|
*
|
|
* However, lets try to load the following device (like
|
|
* vga or vga RISC) so the user has a chance to repair
|
|
* it
|
|
*/
|
|
UserLogDisplayDriverEvent(MsgInvalidDisplayDriver);
|
|
}
|
|
|
|
/*
|
|
* Free memory allocated by ProbeAndCaptureDevmode
|
|
*/
|
|
if (pdevmodeInformation &&
|
|
(pdevmodeInformation != &sourceDevmodeInformation)) {
|
|
|
|
UserFreePool(pdevmodeInformation);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Free the device if we are not going to use it.
|
|
*/
|
|
|
|
if (bKeepDevice == FALSE) {
|
|
UserFreeDevice(pphysinfo);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Close the final registry handle if one remains
|
|
*/
|
|
if (hkRegistry) {
|
|
ZwClose(hkRegistry);
|
|
hkRegistry = NULL;
|
|
}
|
|
|
|
|
|
/*****************************************************************
|
|
*****************************************************************
|
|
Accumulate devices - Set Primary
|
|
*****************************************************************
|
|
*****************************************************************/
|
|
|
|
|
|
/*
|
|
* If we have more than one device that is attached to the desktop,
|
|
* then we need to determine which is the primary device
|
|
*
|
|
* MultiDriver devices are special - we only want to count all the
|
|
* multi-devices as *1* device, and use the *primary* one as the key
|
|
* device. In a multiDriver system, we will initially require all
|
|
* devices attached to the desktop to be controlled by the multiDriver.
|
|
*/
|
|
|
|
mdevMultiDriver = (ULONG) -1;
|
|
|
|
for (i = 1; i < cphysDevInfo; i++) {
|
|
|
|
TRACE_INIT(("UserInit: LoadDriver: gphysDevInfo has %08lx hdev", localDispInfo[i].hDev));
|
|
|
|
if (localDispInfo[i].hDev) {
|
|
|
|
/*
|
|
* Check for multi drivers, and see if the state is consistent.
|
|
* Right now, we require that if nay driver is multi, then all
|
|
* loaded drivers must be.
|
|
*/
|
|
if (mdevMultiDriver == (ULONG) -1) {
|
|
mdevMultiDriver = gphysDevInfo[i].stateFlags & DISPLAY_DEVICE_MULTI_DRIVER;
|
|
}
|
|
|
|
if (mdevMultiDriver != (gphysDevInfo[i].stateFlags & DISPLAY_DEVICE_MULTI_DRIVER)) {
|
|
|
|
UserAssert(mdevMultiDriver != DISPLAY_DEVICE_MULTI_DRIVER);
|
|
break;
|
|
}
|
|
|
|
|
|
/*
|
|
* Keep track of the primary device.
|
|
* - Choose the first one, or even beter ...
|
|
* - Choose the first non-mirroring one, or even beter ...
|
|
* - Choose the one actually marked as primary
|
|
*/
|
|
|
|
if ((mdevPrimary == (ULONG) -1) ||
|
|
(gphysDevInfo[i].stateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE)) {
|
|
|
|
TRACE_INIT((" - marking as Primary"));
|
|
|
|
/*
|
|
* Raise an error if there are multiple primaries, unless
|
|
* it's ourself again !
|
|
*/
|
|
if (gphysDevInfo[i].stateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE) {
|
|
|
|
if (mdevPrimaryset && (mdevPrimary != i)) {
|
|
UserLogDisplayDriverEvent(MsgInvalidConfiguration);
|
|
}
|
|
mdevPrimaryset = TRUE;
|
|
}
|
|
|
|
|
|
/*
|
|
* Unmark the previous primary if necessary.
|
|
*/
|
|
|
|
if (mdevPrimary != (ULONG) -1) {
|
|
gphysDevInfo[mdevPrimary].stateFlags &= ~DISPLAY_DEVICE_PRIMARY_DEVICE;
|
|
}
|
|
|
|
mdevPrimary = i;
|
|
gpDispInfo->hDev = localDispInfo[i].hDev;
|
|
gpDispInfo->pDevLock = localDispInfo[i].pDevLock;
|
|
gpDispInfo->pDevInfo = &gphysDevInfo[i];
|
|
gphysDevInfo[i].stateFlags |= DISPLAY_DEVICE_PRIMARY_DEVICE;
|
|
|
|
}
|
|
|
|
/*
|
|
* Double check that we did not mark a mirror driver as primary
|
|
* when it was not specifically asked for.
|
|
* This could happen if the MIRROR driver was the *ONLY* driver
|
|
* that loaded on the system !
|
|
*/
|
|
|
|
if ((mdevPrimaryset == FALSE) &&
|
|
(gphysDevInfo[mdevPrimary].stateFlags &
|
|
DISPLAY_DEVICE_MIRRORING_DRIVER)) {
|
|
|
|
UserAssert(FALSE);
|
|
}
|
|
}
|
|
|
|
TRACE_INIT(("\n"));
|
|
}
|
|
|
|
|
|
/*****************************************************************
|
|
*****************************************************************
|
|
Handle loop exit conditions
|
|
*****************************************************************
|
|
*****************************************************************/
|
|
|
|
|
|
/*
|
|
* 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) &&
|
|
!gbBaseVideo) {
|
|
|
|
TRACE_INIT(("\n\nUserInit: LoadDriver: Look for Mirroring drivers\n\n"));
|
|
bAttachMirroring = TRUE;
|
|
bCheckForAttached = TRUE;
|
|
continue;
|
|
}
|
|
|
|
/*
|
|
* We must be done. So if we did install the display driver, just
|
|
* break out of this.
|
|
*/
|
|
if (displayInstalled) {
|
|
break;
|
|
}
|
|
|
|
/*
|
|
* If we were searching for a basevideo device and did not find
|
|
* it, then start the search at 1 again, and look for attached
|
|
* devices.
|
|
*/
|
|
if (gbBaseVideo) {
|
|
|
|
RIPMSG0(RIP_WARNING, "\n\nUserInit: LoadDriver: BaseVideo device not found - use default");
|
|
gbBaseVideo = FALSE;
|
|
bCheckForAttached = TRUE;
|
|
continue;
|
|
}
|
|
|
|
/*
|
|
* If we were searching for an attached device and did not find
|
|
* it, then start the search at 1 again, and look for anything.
|
|
* make sure we try all possible entries before giving up.
|
|
*
|
|
*/
|
|
if (bCheckForAttached) {
|
|
|
|
TRACE_INIT(("\n\nUserInit: LoadDriver: Attached device not found - use default\n\n"));
|
|
bCheckForAttached = FALSE;
|
|
continue;
|
|
}
|
|
|
|
|
|
/*
|
|
* There are no devices we can work with in the registry.
|
|
* We have a real failiure and take appropriate action.
|
|
*/
|
|
|
|
/*
|
|
* If we failed on the first driver, then we can assume their is no
|
|
* driver installed.
|
|
*/
|
|
if (i == 1) {
|
|
RIPMSG1(RIP_WARNING,
|
|
"UserInit: LoadDriver: No kernel driver entries under video reg-key: status=%#lx",
|
|
Status);
|
|
|
|
Status = STATUS_NO_SUCH_DEVICE;
|
|
hardErrorString = L"KERNEL_VIDEO_DRIVER.SYS";
|
|
goto userServerHardError;
|
|
}
|
|
|
|
/*
|
|
* If the display driver is not installed, then this is another
|
|
* bad failiure - report it.
|
|
*/
|
|
if (!displayInstalled) {
|
|
RIPMSG1(RIP_WARNING,
|
|
"UserInit: LoadDriver: Kernel driver not found in registry: status=%#lx",
|
|
Status);
|
|
|
|
Status = STATUS_NO_SUCH_DEVICE;
|
|
hardErrorString = L"DISPLAY_DRIVER.DLL";
|
|
goto userServerHardError;
|
|
}
|
|
|
|
/*
|
|
* Never get here !
|
|
*/
|
|
|
|
}
|
|
|
|
/*****************************************************************
|
|
*****************************************************************
|
|
Accumulate devices - build MDEV
|
|
*****************************************************************
|
|
*****************************************************************/
|
|
|
|
k = 0;
|
|
|
|
/*
|
|
* 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.
|
|
*/
|
|
|
|
TRACE_INIT(("\nUserInit: LoadDriver: Building MDEV\n\n"));
|
|
|
|
for (i = 1; i < cphysDevInfo; i++) {
|
|
|
|
if (localDispInfo[i].hDev) {
|
|
|
|
/*
|
|
* Build up the MDEV
|
|
*/
|
|
mdev->mdevID = 'MDEV';
|
|
mdev->cmdev = k + 1;
|
|
mdev->mdevPos[k].hdev = localDispInfo[i].hDev;
|
|
mdev->mdevPos[k].flags = (gphysDevInfo[i].stateFlags &
|
|
DISPLAY_DEVICE_PRIMARY_DEVICE) ? 1 : 0;
|
|
|
|
/*
|
|
* The top left is based on the registry coordinates
|
|
*/
|
|
mdev->mdevPos[k].rcPos.left =
|
|
(localDispInfo[i].rcScreen.left == DEFAULT_POS_VALUE) ? 0 :
|
|
localDispInfo[i].rcScreen.left -
|
|
(gphysDevInfo[i].pCurrentDevmode->dmPelsWidth / 2);
|
|
mdev->mdevPos[k].rcPos.top =
|
|
(localDispInfo[i].rcScreen.top == DEFAULT_POS_VALUE) ? 0 :
|
|
localDispInfo[i].rcScreen.top -
|
|
(gphysDevInfo[i].pCurrentDevmode->dmPelsHeight / 2);
|
|
|
|
/*
|
|
* The lower right is based on the size of the DEVMODE.
|
|
*/
|
|
mdev->mdevPos[k].rcPos.right =
|
|
mdev->mdevPos[k].rcPos.left +
|
|
gphysDevInfo[i].pCurrentDevmode->dmPelsWidth;
|
|
mdev->mdevPos[k].rcPos.bottom =
|
|
mdev->mdevPos[k].rcPos.top +
|
|
gphysDevInfo[i].pCurrentDevmode->dmPelsHeight;
|
|
|
|
TRACE_INIT(("\n\nUserInit: LoadDriver: multiDriver %d - %d, %d, %d, %d\n",
|
|
i,
|
|
mdev->mdevPos[k].rcPos.left, mdev->mdevPos[k].rcPos.top,
|
|
mdev->mdevPos[k].rcPos.right, mdev->mdevPos[k].rcPos.bottom));
|
|
|
|
/*
|
|
* Next driver.
|
|
*/
|
|
|
|
k++;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* If we have no primary at this point, we are in trouble !
|
|
*/
|
|
if ((k == 0) || (mdevPrimary == (ULONG) -1)) {
|
|
UserAssert(mdevPrimary != (ULONG) -1);
|
|
UserAssert(k != 0);
|
|
k = 0;
|
|
}
|
|
|
|
|
|
|
|
/*****************************************************************
|
|
*****************************************************************
|
|
Multi Driver Support
|
|
*****************************************************************
|
|
*****************************************************************/
|
|
|
|
/*
|
|
* If we have a multi-driver, we must first make sure all the rectangles
|
|
* actually make up a larger rectangle, since a META surface handled by a
|
|
* single driver must be rectangular.
|
|
*/
|
|
if (k && (mdevMultiDriver == DISPLAY_DEVICE_MULTI_DRIVER)) {
|
|
|
|
MDEV_RECT tmpRect[7];
|
|
RECTL emptyRect = {0};
|
|
ULONG crect = mdev->cmdev;
|
|
|
|
memcpy(&(tmpRect[0]), &(mdev->mdevPos[0]), mdev->cmdev * sizeof(MDEV_RECT));
|
|
|
|
TRACE_INIT(("\n\nUserInit: LoadDriver: multiDriver system\n\n\n"));
|
|
|
|
for (i=0; i < mdev->cmdev; i++) {
|
|
for (ii=0; ii < mdev->cmdev; ii++) {
|
|
for (iii=0; iii < mdev->cmdev; iii++) {
|
|
|
|
/*
|
|
* Don't merge the same rectangle together
|
|
*/
|
|
if (ii == iii)
|
|
continue;
|
|
|
|
/*
|
|
* Don't merge an empty rectangle
|
|
*/
|
|
if ((tmpRect[ii].rcPos.left == 0) &&
|
|
(tmpRect[ii].rcPos.right == 0))
|
|
break;
|
|
|
|
if ((tmpRect[iii].rcPos.left == tmpRect[ii].rcPos.left) &&
|
|
(tmpRect[iii].rcPos.right == tmpRect[ii].rcPos.right)) {
|
|
|
|
if (tmpRect[iii].rcPos.bottom == tmpRect[ii].rcPos.top) {
|
|
|
|
tmpRect[ii].rcPos.top = tmpRect[iii].rcPos.top;
|
|
tmpRect[iii].rcPos = emptyRect;
|
|
crect--;
|
|
continue;
|
|
}
|
|
|
|
if (tmpRect[ii].rcPos.bottom == tmpRect[iii].rcPos.top) {
|
|
|
|
tmpRect[iii].rcPos.top = tmpRect[ii].rcPos.top;
|
|
tmpRect[ii].rcPos = emptyRect;
|
|
crect--;
|
|
continue;
|
|
}
|
|
}
|
|
|
|
if ((tmpRect[iii].rcPos.top == tmpRect[ii].rcPos.top) &&
|
|
(tmpRect[iii].rcPos.bottom == tmpRect[ii].rcPos.bottom)) {
|
|
|
|
if (tmpRect[iii].rcPos.left == tmpRect[ii].rcPos.right) {
|
|
|
|
tmpRect[ii].rcPos.right = tmpRect[iii].rcPos.right;
|
|
tmpRect[iii].rcPos = emptyRect;
|
|
crect--;
|
|
continue;
|
|
}
|
|
|
|
if (tmpRect[ii].rcPos.left == tmpRect[iii].rcPos.right) {
|
|
|
|
tmpRect[iii].rcPos.right = tmpRect[ii].rcPos.right;
|
|
tmpRect[ii].rcPos = emptyRect;
|
|
crect--;
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* If we do not end up with a rectangle based at 0,0, we will want to
|
|
* boot with only one screen and let the user fix the configuration.
|
|
*/
|
|
|
|
TRACE_INIT(("\n"));
|
|
|
|
for (i=0; i < mdev->cmdev; i++) {
|
|
|
|
if ((tmpRect[i].rcPos.left != 0) ||
|
|
(tmpRect[i].rcPos.top != 0)) {
|
|
|
|
TRACE_INIT(("\n"));
|
|
crect = 0;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (crect != 1) {
|
|
|
|
UserAssert(crect == 1);
|
|
UserLogDisplayDriverEvent(MsgInvalidConfiguration);
|
|
|
|
/*
|
|
* Rebuild a one device MDEV with offset at zero, and the original
|
|
* devmode dimenstions (we know those are good).
|
|
*/
|
|
mdev->mdevID = 'MDEV';
|
|
mdev->cmdev = 1;
|
|
mdev->mdevPos[0].hdev = mdev->mdevPos[0].hdev;
|
|
mdev->mdevPos[0].flags = 0;
|
|
mdev->mdevPos[0].rcPos.right -= mdev->mdevPos[0].rcPos.left;
|
|
mdev->mdevPos[0].rcPos.bottom -= mdev->mdevPos[0].rcPos.top;
|
|
mdev->mdevPos[0].rcPos.left = 0;
|
|
mdev->mdevPos[0].rcPos.top = 0;
|
|
|
|
}
|
|
|
|
//
|
|
// BUGBUG NULL terminate the string
|
|
//
|
|
|
|
gpDispInfo->hDev = GreCreateHDEV(strDisplayDriver.Buffer,
|
|
(LPDEVMODEW) &mdev,
|
|
NULL,
|
|
TRUE,
|
|
(PDEVICE_LOCK *)&gpDispInfo->pDevLock);
|
|
|
|
|
|
bMultipleDisplaySystem = TRUE;
|
|
|
|
} else if (k > 1) {
|
|
|
|
|
|
/*****************************************************************
|
|
*****************************************************************
|
|
DDML Driver Support
|
|
*****************************************************************
|
|
*****************************************************************/
|
|
|
|
ULONG color = 0;
|
|
|
|
TRACE_INIT(("UserInit: LoadDriver: Got MDEV - parse MDEV data\n"));
|
|
|
|
/*
|
|
* Lets make sure all rectangles are at the same position for now.
|
|
* Lets also make sure the color depths match.
|
|
* If they are not, let's just default back to one display and bring
|
|
* up the display applet
|
|
*/
|
|
|
|
for (i = 1; i < cphysDevInfo; i++) {
|
|
|
|
if (localDispInfo[i].hDev) {
|
|
|
|
if (color == 0) {
|
|
color = gphysDevInfo[i].pCurrentDevmode->dmBitsPerPel;
|
|
|
|
} else if (color != gphysDevInfo[i].pCurrentDevmode->dmBitsPerPel) {
|
|
|
|
UserAssert(color != gphysDevInfo[i].pCurrentDevmode->dmBitsPerPel);
|
|
|
|
UserLogDisplayDriverEvent(MsgInvalidConfiguration);
|
|
k = 1;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
for (i = 1; i < mdev->cmdev; i++) {
|
|
|
|
if ((mdev->mdevPos[i].rcPos.left != 0) ||
|
|
(mdev->mdevPos[i].rcPos.top != 0) ||
|
|
(mdev->mdevPos[i].rcPos.right != mdev->mdevPos[i-1].rcPos.right) ||
|
|
(mdev->mdevPos[i].rcPos.bottom != mdev->mdevPos[i-1].rcPos.bottom))
|
|
{
|
|
UserAssert(FALSE);
|
|
|
|
/*
|
|
* Set k=1 which will cause us to bypass the HMDEV call
|
|
*/
|
|
UserLogDisplayDriverEvent(MsgInvalidConfiguration);
|
|
k = 1;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (k > 1) {
|
|
gpDispInfo->hDev = GreCreateHMDEV(mdev,
|
|
(PDEVICE_LOCK *)&gpDispInfo->pDevLock);
|
|
}
|
|
|
|
bMultipleDisplaySystem = TRUE;
|
|
}
|
|
|
|
if (k == 0) {
|
|
/*
|
|
* We did not find any display drivers.
|
|
* This is where we bugcheck !
|
|
*/
|
|
|
|
RIPMSG1(RIP_WARNING,
|
|
"UserInit: LoadDriver: no loaded display drivers: status=%#lx",
|
|
Status);
|
|
|
|
Status = STATUS_NO_SUCH_DEVICE;
|
|
hardErrorString = L"PRIMARY_DISPLAY_DRIVER.DLL";
|
|
goto userServerHardError;
|
|
}
|
|
|
|
/*
|
|
* Properly initialize the primary device.
|
|
*/
|
|
|
|
/*
|
|
* Fill up the devcaps in GDI shared memory
|
|
*/
|
|
GreUpdateSharedDevCaps(gpDispInfo->hDev);
|
|
|
|
/*
|
|
* Now init the rest of USER
|
|
*/
|
|
InitUserScreen();
|
|
|
|
|
|
|
|
|
|
/*****************************************************************
|
|
*****************************************************************
|
|
Exit
|
|
*****************************************************************
|
|
*****************************************************************/
|
|
|
|
|
|
#if DBG
|
|
/*
|
|
* If no VGA is found print a warning message.
|
|
*/
|
|
#if !defined(_MIPS_) && !defined(_ALPHA_) && !defined(_PPC_)
|
|
if (!vgaInstalled) {
|
|
RIPMSG0(RIP_WARNING, "UserInit: LoadDriver: No VGA driver found in the system");
|
|
}
|
|
#endif // _MIPS_ && _ALPHA_ && _PPC_
|
|
#endif // DBG
|
|
|
|
|
|
Status = STATUS_SUCCESS;
|
|
|
|
userServerHardError:
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
|
|
UNICODE_STRING ErrorString;
|
|
PUNICODE_STRING ErrorStringPointer = &ErrorString;
|
|
ULONG ErrorResponse;
|
|
|
|
TRACE_INIT(("UserInit: LoadDriver: No working display driver found\n"));
|
|
|
|
RtlInitUnicodeString(ErrorStringPointer, hardErrorString);
|
|
|
|
/*
|
|
* need to get image name
|
|
*/
|
|
ExRaiseHardError((NTSTATUS)STATUS_MISSING_SYSTEMFILE,
|
|
1,
|
|
0x00000001,
|
|
(PULONG) (&ErrorStringPointer),
|
|
OptionOk,
|
|
&ErrorResponse);
|
|
|
|
}
|
|
|
|
TRACE_INIT(("UserInit: LoadDriver: Display driver properly installed\n"));
|
|
TRACE_INIT(("UserInit: LoadDriver: Finished display driver loading sequence\n"));
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
/***************************************************************************\
|
|
* NtUserEnumDisplaySettings
|
|
*
|
|
* Routines that enumerate the list of modes available in the driver.
|
|
*
|
|
* We assuem the caller always passes down a structure of sizeof(DEVMODEW).
|
|
*
|
|
* andreva Created
|
|
\***************************************************************************/
|
|
|
|
|
|
NTSTATUS
|
|
NtUserEnumDisplaySettings(
|
|
IN PUNICODE_STRING pstrDeviceName,
|
|
IN DWORD iModeNum,
|
|
OUT LPDEVMODEW lpDevMode,
|
|
DWORD dwFalgs)
|
|
{
|
|
NTSTATUS retval = STATUS_INVALID_PARAMETER_1;
|
|
|
|
UNICODE_STRING strDevice;
|
|
UNICODE_STRING us;
|
|
PPHYSICAL_DEV_INFO physinfo = NULL;
|
|
USHORT DriverExtraSize;
|
|
|
|
//
|
|
// Probe the DeviceName and the DEVMODE.
|
|
//
|
|
|
|
EnterCrit();
|
|
|
|
try {
|
|
|
|
ProbeForRead(lpDevMode, sizeof(DEVMODEW), sizeof(USHORT));
|
|
|
|
DriverExtraSize = lpDevMode->dmDriverExtra;
|
|
|
|
ProbeForWrite(lpDevMode,
|
|
sizeof(DEVMODEW) + DriverExtraSize,
|
|
sizeof(USHORT));
|
|
|
|
|
|
if (lpDevMode->dmSize != sizeof(DEVMODEW))
|
|
{
|
|
LeaveCrit();
|
|
return STATUS_BUFFER_TOO_SMALL;
|
|
}
|
|
|
|
} except (EXCEPTION_EXECUTE_HANDLER) {
|
|
LeaveCrit();
|
|
return GetExceptionCode();
|
|
}
|
|
|
|
if (ProbeAndCaptureDeviceName(&strDevice, pstrDeviceName)) {
|
|
physinfo = UserGetDeviceFromName(&strDevice, USER_DEVICE_NOTOWNED);
|
|
|
|
if (strDevice.Buffer)
|
|
UserFreePool(strDevice.Buffer);
|
|
}
|
|
|
|
if (physinfo) {
|
|
|
|
//
|
|
// -2 means we want the registry DEVMODE to do matching on the
|
|
// client side.
|
|
//
|
|
|
|
if (iModeNum == (DWORD) -2) {
|
|
|
|
PDEVMODEW pdevmode;
|
|
|
|
TRACE_INIT(("NtUserEnumDisp: -2 mode\n"));
|
|
|
|
if (pdevmode = UserAllocPool(sizeof(DEVMODEW) + MAXUSHORT,
|
|
TAG_DEVMODE)) {
|
|
|
|
RtlZeroMemory(pdevmode, sizeof(DEVMODEW));
|
|
pdevmode->dmSize = 0xDDDD;
|
|
pdevmode->dmDriverExtra = MAXUSHORT;
|
|
|
|
RtlInitUnicodeString(&us, &(physinfo->szNtDeviceName[0]));
|
|
|
|
retval = UserGetDisplayDriverParameters(&us,
|
|
pdevmode,
|
|
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;
|
|
}
|
|
}
|
|
|
|
UserFreePool(pdevmode);
|
|
}
|
|
|
|
//
|
|
// -1 means returns the current device mode.
|
|
// We store the full DEVMODE in the
|
|
//
|
|
|
|
} else if (iModeNum == (DWORD) -1) {
|
|
|
|
TRACE_INIT(("NtUserEnumDisp: -1 mode\n"));
|
|
|
|
if (physinfo->pCurrentDevmode != NULL) {
|
|
|
|
try {
|
|
|
|
DriverExtraSize = min(DriverExtraSize,
|
|
physinfo->pCurrentDevmode->dmDriverExtra);
|
|
|
|
//
|
|
// We know the DEVMODE we called the driver with is of
|
|
// size sizeof(DEVMODEW)
|
|
//
|
|
|
|
RtlCopyMemory(lpDevMode + 1,
|
|
physinfo->pCurrentDevmode + 1,
|
|
DriverExtraSize);
|
|
|
|
RtlCopyMemory(lpDevMode,
|
|
physinfo->pCurrentDevmode,
|
|
sizeof(DEVMODEW));
|
|
|
|
retval = STATUS_SUCCESS;
|
|
|
|
} except(EXCEPTION_EXECUTE_HANDLER) {
|
|
|
|
retval = STATUS_INVALID_PARAMETER_3;
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
/*
|
|
* PERF - Can we use something else to synchronize access to the
|
|
* list of modes ?
|
|
*/
|
|
|
|
UserBuildDevmodeList(physinfo);
|
|
|
|
//
|
|
// now return the information
|
|
//
|
|
|
|
if ( (physinfo->cbdevmodeInfo == 0) ||
|
|
(physinfo->devmodeInfo == NULL) ) {
|
|
|
|
RIPERR0(ERROR_INVALID_PARAMETER, RIP_WARNING, "EnumDisplaySettings physinfo is inconsistent \n");
|
|
retval = STATUS_UNSUCCESSFUL;
|
|
|
|
} else {
|
|
|
|
DWORD dwTotalSize = 0;
|
|
LPDEVMODEW lpdm = physinfo->devmodeInfo;
|
|
DWORD i;
|
|
|
|
retval = STATUS_INVALID_PARAMETER_2;
|
|
|
|
for (i = 0; dwTotalSize < physinfo->cbdevmodeInfo; i++) {
|
|
|
|
if (i == iModeNum) {
|
|
|
|
try {
|
|
|
|
DriverExtraSize = min(DriverExtraSize,
|
|
lpdm->dmDriverExtra);
|
|
|
|
RtlZeroMemory(lpDevMode, sizeof(DEVMODEW));
|
|
|
|
//
|
|
// 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;
|
|
}
|
|
|
|
break;
|
|
|
|
} else {
|
|
|
|
dwTotalSize += lpdm->dmSize + lpdm->dmDriverExtra;
|
|
|
|
lpdm = (LPDEVMODEW) (((LPBYTE)lpdm) +
|
|
lpdm->dmSize +
|
|
lpdm->dmDriverExtra);
|
|
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
/*
|
|
* 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) {
|
|
|
|
UserReleaseDevmodeList(physinfo);
|
|
}
|
|
}
|
|
|
|
UserFreeDevice(physinfo);
|
|
}
|
|
|
|
/*
|
|
* Update the driver extra size
|
|
*/
|
|
|
|
if (retval == STATUS_SUCCESS)
|
|
{
|
|
try {
|
|
lpDevMode->dmDriverExtra = DriverExtraSize;
|
|
} except (EXCEPTION_EXECUTE_HANDLER) {
|
|
retval = GetExceptionCode();
|
|
}
|
|
}
|
|
|
|
TRACE("NtUserEnumDisplaySettings");
|
|
|
|
LeaveCrit();
|
|
|
|
return (retval);
|
|
}
|