/**************************************************************************\ * 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); }