[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
This commit is contained in:
Hervé Poussineau 2024-02-07 20:20:22 +01:00
parent 2ad5e1cd69
commit 8b7770aa2c
5 changed files with 91 additions and 58 deletions

View File

@ -7,6 +7,3 @@ Signature = "$Windows NT$"
;
; Display driver section
;
; VGA miniport driver
HKLM,"SYSTEM\CurrentControlSet\Services\VgaSave","Start",0x00010001,0x00000001

View File

@ -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"

View File

@ -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;
}

View File

@ -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;
}
}

View File

@ -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();