From 8b7770aa2ce57ecd2b25a520aa9449852191d8d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Herv=C3=A9=20Poussineau?= Date: Wed, 7 Feb 2024 20:20:22 +0100 Subject: [PATCH] [WIN32SS:ENG] Rework EngpUpdateGraphicsDeviceList - choose VGA adapter outside of driver initialization loop - choose primary adapter outside of driver initialization loop - link VGA adapter to primary adapter at the end - only set DISPLAY_DEVICE_PRIMARY_DEVICE in this function Also mark VgaSave driver as SystemStart instead of Disabled, so it is available if main display driver doesn't work. CORE-7728, CORE-19224 --- boot/bootdata/hiveinst.inf | 3 - win32ss/drivers/miniport/vga/vga_reg.inf | 2 +- win32ss/gdi/eng/device.c | 129 +++++++++++++++-------- win32ss/gdi/eng/pdevobj.c | 2 +- win32ss/user/ntuser/display.c | 13 +-- 5 files changed, 91 insertions(+), 58 deletions(-) diff --git a/boot/bootdata/hiveinst.inf b/boot/bootdata/hiveinst.inf index bdd4d49c6f0..228b68931d9 100644 --- a/boot/bootdata/hiveinst.inf +++ b/boot/bootdata/hiveinst.inf @@ -7,6 +7,3 @@ Signature = "$Windows NT$" ; ; Display driver section ; - -; VGA miniport driver -HKLM,"SYSTEM\CurrentControlSet\Services\VgaSave","Start",0x00010001,0x00000001 diff --git a/win32ss/drivers/miniport/vga/vga_reg.inf b/win32ss/drivers/miniport/vga/vga_reg.inf index 617afe6e038..528a5916b7f 100644 --- a/win32ss/drivers/miniport/vga/vga_reg.inf +++ b/win32ss/drivers/miniport/vga/vga_reg.inf @@ -3,7 +3,7 @@ HKLM,"SYSTEM\CurrentControlSet\Services\VgaSave","ErrorControl",0x00010001,0x00000000 HKLM,"SYSTEM\CurrentControlSet\Services\VgaSave","Group",0x00000000,"Video Save" HKLM,"SYSTEM\CurrentControlSet\Services\VgaSave","ImagePath",0x00020000,"system32\drivers\vga.sys" -HKLM,"SYSTEM\CurrentControlSet\Services\VgaSave","Start",0x00010001,0x00000004 +HKLM,"SYSTEM\CurrentControlSet\Services\VgaSave","Start",0x00010001,0x00000001 HKLM,"SYSTEM\CurrentControlSet\Services\VgaSave","Type",0x00010001,0x00000001 HKLM,"SYSTEM\CurrentControlSet\Services\VgaSave","Tag",0x00010001,0x00000002 HKLM,"SYSTEM\CurrentControlSet\Services\VgaSave\Video","Service",0x00000000,"VgaSave" diff --git a/win32ss/gdi/eng/device.c b/win32ss/gdi/eng/device.c index d9f6b8a9465..601aaa5b840 100644 --- a/win32ss/gdi/eng/device.c +++ b/win32ss/gdi/eng/device.c @@ -98,6 +98,30 @@ EngpHasVgaDriver( return (_wcsnicmp(awcServiceName, L"VGA", 3) == 0); } +static +BOOLEAN +EngpIsVgaDevice( + _In_ PGRAPHICS_DEVICE pGraphicsDevice) +{ + BOOLEAN IsVgaDevice; + ULONG ulReturn; + NTSTATUS Status; + + Status = (NTSTATUS)EngDeviceIoControl((HANDLE)pGraphicsDevice->DeviceObject, + IOCTL_VIDEO_IS_VGA_DEVICE, + NULL, 0, + &IsVgaDevice, sizeof(IsVgaDevice), + &ulReturn); + if (Status != ERROR_SUCCESS) + { + ERR("EngDeviceIoControl(0x%p, IOCTL_VIDEO_IS_VGA_DEVICE) failed, Status 0x%lx\n", + pGraphicsDevice->DeviceObject, Status); + return FALSE; + } + TRACE("'%S' is%s VGA device\n", pGraphicsDevice->szNtDeviceName, IsVgaDevice ? "" : " NOT"); + return IsVgaDevice; +} + /* * Add a device to gpGraphicsDeviceFirst/gpGraphicsDeviceLast list (if not already present). */ @@ -170,16 +194,24 @@ EngpUnlinkGraphicsDevice( } } +/* Goal of this function is to: + * - detect new graphic devices (from registry) and initialize them + * - set DISPLAY_DEVICE_VGA_COMPATIBLE flag on compatible devices + * - set gpVgaGraphicsDevice + * - handle gbBaseVideo global flag + * - set DISPLAY_DEVICE_PRIMARY_DEVICE on at least one device + * - set gpPrimaryGraphicsDevice + * - link primary device and VGA device (if available) using pVgaDevice field + */ NTSTATUS EngpUpdateGraphicsDeviceList(VOID) { - ULONG iDevNum, iVGACompatible = -1, ulMaxObjectNumber = 0; + ULONG iDevNum, ulMaxObjectNumber = 0; WCHAR awcDeviceName[20], awcWinDeviceName[20]; UNICODE_STRING ustrDeviceName; WCHAR awcBuffer[256]; NTSTATUS Status; - PGRAPHICS_DEVICE pGraphicsDevice; - BOOLEAN bFoundNewDevice = FALSE; + PGRAPHICS_DEVICE pGraphicsDevice, pNewPrimaryGraphicsDevice = NULL; ULONG cbValue; HKEY hkey; @@ -191,15 +223,6 @@ EngpUpdateGraphicsDeviceList(VOID) return Status; } - /* Read the name of the VGA adapter */ - cbValue = sizeof(awcDeviceName); - Status = RegQueryValue(hkey, L"VgaCompatible", REG_SZ, awcDeviceName, &cbValue); - if (NT_SUCCESS(Status)) - { - iVGACompatible = _wtoi(&awcDeviceName[sizeof("\\Device\\Video")-1]); - ERR("VGA adapter = %lu\n", iVGACompatible); - } - /* Get the maximum number of adapters */ if (!RegReadDWORD(hkey, L"MaxObjectNumber", &ulMaxObjectNumber)) { @@ -208,7 +231,7 @@ EngpUpdateGraphicsDeviceList(VOID) TRACE("Found %lu devices\n", ulMaxObjectNumber + 1); - /* Loop through all adapters */ + /* Loop through all adapters, to detect new ones */ for (iDevNum = 0; iDevNum <= ulMaxObjectNumber; iDevNum++) { /* Create the adapter's key name */ @@ -237,43 +260,29 @@ EngpUpdateGraphicsDeviceList(VOID) /* Initialize the driver for this device */ pGraphicsDevice = InitDisplayDriver(awcDeviceName, awcBuffer); if (!pGraphicsDevice) continue; - - /* Check if this is a VGA compatible adapter */ - if (pGraphicsDevice->StateFlags & DISPLAY_DEVICE_VGA_COMPATIBLE) - { - /* Save this as the VGA adapter */ - if (!gpVgaGraphicsDevice) - { - gpVgaGraphicsDevice = pGraphicsDevice; - TRACE("gpVgaGraphicsDevice = %p\n", gpVgaGraphicsDevice); - } - } - bFoundNewDevice = TRUE; - - /* Set the first one as primary device */ - if (!gpPrimaryGraphicsDevice || EngpHasVgaDriver(gpPrimaryGraphicsDevice)) - { - gpPrimaryGraphicsDevice = pGraphicsDevice; - TRACE("gpPrimaryGraphicsDevice = %p\n", gpPrimaryGraphicsDevice); - } } /* Close the device map registry key */ ZwClose(hkey); - /* Can we link VGA device to primary device? */ - if (gpPrimaryGraphicsDevice && - gpVgaGraphicsDevice && - gpPrimaryGraphicsDevice != gpVgaGraphicsDevice && - !gpPrimaryGraphicsDevice->pVgaDevice) + /* Choose a VGA device */ + /* Try a device with DISPLAY_DEVICE_VGA_COMPATIBLE flag. If not found, + * fall back to current VGA device */ + for (pGraphicsDevice = gpGraphicsDeviceFirst; + pGraphicsDevice; + pGraphicsDevice = pGraphicsDevice->pNextGraphicsDevice) { - /* Yes. Remove VGA device from global list, and attach it to primary device */ - TRACE("Linking VGA device %S to primary device %S\n", gpVgaGraphicsDevice->szNtDeviceName, gpPrimaryGraphicsDevice->szNtDeviceName); - EngpUnlinkGraphicsDevice(gpVgaGraphicsDevice); - gpPrimaryGraphicsDevice->pVgaDevice = gpVgaGraphicsDevice; + if (pGraphicsDevice == gpVgaGraphicsDevice) + continue; + if (pGraphicsDevice->StateFlags & DISPLAY_DEVICE_VGA_COMPATIBLE && EngpIsVgaDevice(pGraphicsDevice)) + { + gpVgaGraphicsDevice = pGraphicsDevice; + break; + } } - if (bFoundNewDevice && gbBaseVideo) + /* Handle gbBaseVideo */ + if (gbBaseVideo) { PGRAPHICS_DEVICE pToDelete; @@ -307,6 +316,42 @@ EngpUpdateGraphicsDeviceList(VOID) EngReleaseSemaphore(ghsemGraphicsDeviceList); } + /* Choose a primary device (if none already exists) */ + if (!gpPrimaryGraphicsDevice) + { + for (pGraphicsDevice = gpGraphicsDeviceFirst; + pGraphicsDevice; + pGraphicsDevice = pGraphicsDevice->pNextGraphicsDevice) + { + if (EngpHasVgaDriver(pGraphicsDevice)) + { + pNewPrimaryGraphicsDevice = pGraphicsDevice; + break; + } + } + if (!pNewPrimaryGraphicsDevice) + pNewPrimaryGraphicsDevice = gpGraphicsDeviceFirst; + if (pNewPrimaryGraphicsDevice) + { + pNewPrimaryGraphicsDevice->StateFlags |= DISPLAY_DEVICE_PRIMARY_DEVICE; + gpPrimaryGraphicsDevice = pNewPrimaryGraphicsDevice; + } + } + + /* Can we link VGA device to primary device? */ + if (gpPrimaryGraphicsDevice && + gpVgaGraphicsDevice && + gpPrimaryGraphicsDevice != gpVgaGraphicsDevice && + !gpPrimaryGraphicsDevice->pVgaDevice) + { + /* Yes. Remove VGA device from global list, and attach it to primary device */ + TRACE("Linking VGA device %S to primary device %S\n", gpVgaGraphicsDevice->szNtDeviceName, gpPrimaryGraphicsDevice->szNtDeviceName); + EngAcquireSemaphore(ghsemGraphicsDeviceList); + EngpUnlinkGraphicsDevice(gpVgaGraphicsDevice); + gpPrimaryGraphicsDevice->pVgaDevice = gpVgaGraphicsDevice; + EngReleaseSemaphore(ghsemGraphicsDeviceList); + } + return STATUS_SUCCESS; } diff --git a/win32ss/gdi/eng/pdevobj.c b/win32ss/gdi/eng/pdevobj.c index ed6fc630e76..880178287e1 100644 --- a/win32ss/gdi/eng/pdevobj.c +++ b/win32ss/gdi/eng/pdevobj.c @@ -543,7 +543,7 @@ PDEVOBJ_Create( { RtlCopyMemory(ppdev->pdmwDev, pdm, pdm->dmSize + pdm->dmDriverExtra); /* FIXME: this must be done in a better way */ - pGraphicsDevice->StateFlags |= DISPLAY_DEVICE_PRIMARY_DEVICE | DISPLAY_DEVICE_ATTACHED_TO_DESKTOP; + pGraphicsDevice->StateFlags |= DISPLAY_DEVICE_ATTACHED_TO_DESKTOP; } } diff --git a/win32ss/user/ntuser/display.c b/win32ss/user/ntuser/display.c index 8ce655fbb27..b894217867d 100644 --- a/win32ss/user/ntuser/display.c +++ b/win32ss/user/ntuser/display.c @@ -171,17 +171,8 @@ InitVideo(VOID) /* Check if we had any success */ if (!gpPrimaryGraphicsDevice) { - /* Check if there is a VGA device we skipped */ - if (gpVgaGraphicsDevice) - { - /* There is, use the VGA device */ - gpPrimaryGraphicsDevice = gpVgaGraphicsDevice; - } - else - { - ERR("No usable display driver was found.\n"); - return STATUS_UNSUCCESSFUL; - } + ERR("No usable display driver was found.\n"); + return STATUS_UNSUCCESSFUL; } InitSysParams();