2004-01-19 15:56:53 +00:00
|
|
|
/*
|
2003-02-15 19:16:34 +00:00
|
|
|
* VideoPort driver
|
|
|
|
*
|
2007-12-20 12:31:39 +00:00
|
|
|
* Copyright (C) 2002-2004, 2007 ReactOS Team
|
2004-01-19 15:56:53 +00:00
|
|
|
*
|
|
|
|
* This library is free software; you can redistribute it and/or
|
2009-10-27 10:34:16 +00:00
|
|
|
* modify it under the terms of the GNU Lesser General Public
|
2004-01-19 15:56:53 +00:00
|
|
|
* License as published by the Free Software Foundation; either
|
2009-10-27 10:34:16 +00:00
|
|
|
* version 2.1 of the License, or (at your option) any later version.
|
2004-01-19 15:56:53 +00:00
|
|
|
*
|
|
|
|
* This library is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
2009-10-27 10:34:16 +00:00
|
|
|
* Lesser General Public License for more details.
|
2004-01-19 15:56:53 +00:00
|
|
|
*
|
2009-10-27 10:34:16 +00:00
|
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
|
|
* License along with this library; if not, write to the Free Software
|
|
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
2004-01-19 15:56:53 +00:00
|
|
|
*
|
2003-02-15 19:16:34 +00:00
|
|
|
*/
|
|
|
|
|
2004-01-19 15:56:53 +00:00
|
|
|
#include "videoprt.h"
|
2003-02-15 19:16:34 +00:00
|
|
|
|
2014-02-04 17:15:06 +00:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <ndk/exfuncs.h>
|
2019-12-24 12:51:20 +00:00
|
|
|
#include <ndk/obfuncs.h>
|
2014-02-04 17:15:06 +00:00
|
|
|
#include <ndk/rtlfuncs.h>
|
|
|
|
|
|
|
|
#define NDEBUG
|
|
|
|
#include <debug.h>
|
|
|
|
|
2004-03-19 20:58:32 +00:00
|
|
|
/* GLOBAL VARIABLES ***********************************************************/
|
|
|
|
|
2020-09-15 12:24:42 +00:00
|
|
|
ULONG VideoDebugLevel = 0;
|
|
|
|
|
2019-12-24 12:51:20 +00:00
|
|
|
BOOLEAN VpBaseVideo = FALSE;
|
|
|
|
BOOLEAN VpNoVesa = FALSE;
|
|
|
|
|
[WIN32K][VIDEOPRT] Improve initialization and interfacing with INBV.
CORE-12149
VIDEOPRT:
=========
Improve interfacing with INBV, so as to detect when an external module
acquired INBV display ownership, and whether ownership is being released
later on. (This does NOT rely on hooking!)
For this purpose we improve the IntVideoPortResetDisplayParameters(Ex)
callback that gets registered with an InbvNotifyDisplayOwnershipLost()
call during initialization, and we add a monitoring thread.
The callback is called whenever an external module calls
InbvAcquireDisplayOwnership(), for example the bugcheck code or the KDBG
debugger in SCREEN mode. When this happens, a flag that tells the
monitoring thread to start monitoring INBV is set (ReactOS-specific),
and the display adapters get reset with HwResetHw() (as done on Windows).
Due to the fact that this INBV callback can be called at *ANY* IRQL, we
cannot use dispatcher synchronization mechanisms such as events to tell
the INBV monitoring thread to start its operations, so we need to rely
instead on a flag to be set. And, since INBV doesn't provide with any
proper callback/notification system either, we need to actively monitor
its state by pooling. To reduce the load on the system the monitoring
thread performs 1-second waits between each check for the flag set by
the INBV callback, and during checking the INBV ownership status.
When the INBV ownership is detected to be released by an external module,
the INBV callback is re-registered (this is *MANDATORY* since the
external module has called InbvNotifyDisplayOwnershipLost() with a
different callback parameter!), and then we callout to Win32k for
re-enabling the display.
This has the virtue of correctly resetting the display once the KDBG
debugger in SCREEN mode is being exited, and fixes CORE-12149 .
The following additional fixes were needed:
VIDEOPRT & WIN32K:
==================
Remove the registration with INBV that was previously done in a ReactOS-
specific hacked IRP_MJ_WRITE call; it is now done correctly during the
video device opening done by EngpRegisterGraphicsDevice() in the VIDEOPRT's
IRP_MJ_CREATE handler, as done on Windows.
WIN32K:
=======
- Stub the VideoPortCallout() support, for VIDEOPRT -> WIN32 callbacks.
This function gets registered with VIDEOPRT through an
IOCTL_VIDEO_INIT_WIN32K_CALLBACKS call in EngpRegisterGraphicsDevice().
- Only partially implement the 'VideoFindAdapterCallout' case, that just
re-enables the primary display by refreshing it (using the new function
UserRefreshDisplay()).
VIDEOPRT:
=========
- PVIDEO_WIN32K_CALLOUT is an NTAPI (stdcall) callback.
- In the IntVideoPortResetDisplayParameters(Ex) callback, reset all the
"resettable" adapters registered in the HwResetAdaptersList list.
We thus get rid of the global ResetDisplayParametersDeviceExtension.
- Make the IntVideoPortResetDisplayParameters(Ex) callback slightly more
robust (using SEH) against potential HwResetListEntry list corruption
or invalid DriverExtension->InitializationData.HwResetHw() that would
otherwise trigger a BSOD, and this would be disastrous since that
callback is precisely called when INBV is acquired, typically when the
BSOD code initializes the display for displaying its information...
Extras:
- Validate the IrpStack->MajorFunction in IntVideoPortDispatchDeviceControl()
and implement IRP_MJ_SHUTDOWN handling. Stub out the other IOCTLs that
are handled by VIDEOPRT only (and not by the miniports).
- VIDEOPRT doesn't require IRP_MJ_INTERNAL_DEVICE_CONTROL (unused).
- Implement IOCTL_VIDEO_PREPARE_FOR_EARECOVERY that just resets the
display to standard VGA 80x25 text mode.
2019-11-26 01:49:35 +00:00
|
|
|
PKPROCESS CsrProcess = NULL;
|
2021-07-03 19:26:57 +00:00
|
|
|
static ULONG VideoPortMaxObjectNumber = -1;
|
2022-01-23 20:11:59 +00:00
|
|
|
BOOLEAN VideoPortUseNewKey = FALSE;
|
2017-05-18 21:29:24 +00:00
|
|
|
KMUTEX VideoPortInt10Mutex;
|
2019-12-03 01:08:34 +00:00
|
|
|
KSPIN_LOCK HwResetAdaptersLock;
|
[WIN32K][VIDEOPRT] Improve initialization and interfacing with INBV.
CORE-12149
VIDEOPRT:
=========
Improve interfacing with INBV, so as to detect when an external module
acquired INBV display ownership, and whether ownership is being released
later on. (This does NOT rely on hooking!)
For this purpose we improve the IntVideoPortResetDisplayParameters(Ex)
callback that gets registered with an InbvNotifyDisplayOwnershipLost()
call during initialization, and we add a monitoring thread.
The callback is called whenever an external module calls
InbvAcquireDisplayOwnership(), for example the bugcheck code or the KDBG
debugger in SCREEN mode. When this happens, a flag that tells the
monitoring thread to start monitoring INBV is set (ReactOS-specific),
and the display adapters get reset with HwResetHw() (as done on Windows).
Due to the fact that this INBV callback can be called at *ANY* IRQL, we
cannot use dispatcher synchronization mechanisms such as events to tell
the INBV monitoring thread to start its operations, so we need to rely
instead on a flag to be set. And, since INBV doesn't provide with any
proper callback/notification system either, we need to actively monitor
its state by pooling. To reduce the load on the system the monitoring
thread performs 1-second waits between each check for the flag set by
the INBV callback, and during checking the INBV ownership status.
When the INBV ownership is detected to be released by an external module,
the INBV callback is re-registered (this is *MANDATORY* since the
external module has called InbvNotifyDisplayOwnershipLost() with a
different callback parameter!), and then we callout to Win32k for
re-enabling the display.
This has the virtue of correctly resetting the display once the KDBG
debugger in SCREEN mode is being exited, and fixes CORE-12149 .
The following additional fixes were needed:
VIDEOPRT & WIN32K:
==================
Remove the registration with INBV that was previously done in a ReactOS-
specific hacked IRP_MJ_WRITE call; it is now done correctly during the
video device opening done by EngpRegisterGraphicsDevice() in the VIDEOPRT's
IRP_MJ_CREATE handler, as done on Windows.
WIN32K:
=======
- Stub the VideoPortCallout() support, for VIDEOPRT -> WIN32 callbacks.
This function gets registered with VIDEOPRT through an
IOCTL_VIDEO_INIT_WIN32K_CALLBACKS call in EngpRegisterGraphicsDevice().
- Only partially implement the 'VideoFindAdapterCallout' case, that just
re-enables the primary display by refreshing it (using the new function
UserRefreshDisplay()).
VIDEOPRT:
=========
- PVIDEO_WIN32K_CALLOUT is an NTAPI (stdcall) callback.
- In the IntVideoPortResetDisplayParameters(Ex) callback, reset all the
"resettable" adapters registered in the HwResetAdaptersList list.
We thus get rid of the global ResetDisplayParametersDeviceExtension.
- Make the IntVideoPortResetDisplayParameters(Ex) callback slightly more
robust (using SEH) against potential HwResetListEntry list corruption
or invalid DriverExtension->InitializationData.HwResetHw() that would
otherwise trigger a BSOD, and this would be disastrous since that
callback is precisely called when INBV is acquired, typically when the
BSOD code initializes the display for displaying its information...
Extras:
- Validate the IrpStack->MajorFunction in IntVideoPortDispatchDeviceControl()
and implement IRP_MJ_SHUTDOWN handling. Stub out the other IOCTLs that
are handled by VIDEOPRT only (and not by the miniports).
- VIDEOPRT doesn't require IRP_MJ_INTERNAL_DEVICE_CONTROL (unused).
- Implement IOCTL_VIDEO_PREPARE_FOR_EARECOVERY that just resets the
display to standard VGA 80x25 text mode.
2019-11-26 01:49:35 +00:00
|
|
|
RTL_STATIC_LIST_HEAD(HwResetAdaptersList);
|
2004-03-06 22:25:22 +00:00
|
|
|
|
2004-03-19 20:58:32 +00:00
|
|
|
/* PRIVATE FUNCTIONS **********************************************************/
|
2003-02-15 19:16:34 +00:00
|
|
|
|
2013-11-13 21:32:16 +00:00
|
|
|
ULONG
|
|
|
|
NTAPI
|
2004-03-19 20:58:32 +00:00
|
|
|
DriverEntry(
|
2013-11-13 21:32:16 +00:00
|
|
|
IN PVOID Context1,
|
|
|
|
IN PVOID Context2)
|
2003-02-15 19:16:34 +00:00
|
|
|
{
|
2013-11-13 21:32:16 +00:00
|
|
|
return STATUS_SUCCESS;
|
2003-02-15 19:16:34 +00:00
|
|
|
}
|
|
|
|
|
2021-07-03 19:26:57 +00:00
|
|
|
static
|
|
|
|
NTSTATUS
|
|
|
|
IntVideoPortAddDeviceMapLink(
|
|
|
|
PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension)
|
|
|
|
{
|
2022-01-23 20:11:59 +00:00
|
|
|
PUNICODE_STRING RegistryPath;
|
2021-07-03 19:26:57 +00:00
|
|
|
WCHAR DeviceBuffer[20];
|
|
|
|
UNICODE_STRING DeviceName;
|
|
|
|
WCHAR SymlinkBuffer[20];
|
|
|
|
UNICODE_STRING SymlinkName;
|
|
|
|
ULONG DeviceNumber;
|
|
|
|
NTSTATUS Status;
|
|
|
|
|
|
|
|
/* Create a unicode device name. */
|
|
|
|
DeviceNumber = DeviceExtension->DeviceNumber;
|
|
|
|
swprintf(DeviceBuffer, L"\\Device\\Video%lu", DeviceNumber);
|
|
|
|
|
2022-01-23 20:11:59 +00:00
|
|
|
if (VideoPortUseNewKey)
|
|
|
|
RegistryPath = &DeviceExtension->NewRegistryPath;
|
|
|
|
else
|
|
|
|
RegistryPath = &DeviceExtension->RegistryPath;
|
|
|
|
|
2021-07-03 19:26:57 +00:00
|
|
|
/* Add entry to DEVICEMAP\VIDEO key in registry. */
|
|
|
|
Status = RtlWriteRegistryValue(RTL_REGISTRY_DEVICEMAP,
|
|
|
|
L"VIDEO",
|
|
|
|
DeviceBuffer,
|
|
|
|
REG_SZ,
|
2022-01-23 20:11:59 +00:00
|
|
|
RegistryPath->Buffer,
|
|
|
|
RegistryPath->Length + sizeof(UNICODE_NULL));
|
2021-07-03 19:26:57 +00:00
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
2022-01-24 21:46:01 +00:00
|
|
|
ERR_(VIDEOPRT, "Failed to create DEVICEMAP registry entry: 0x%X\n", Status);
|
2021-07-03 19:26:57 +00:00
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
|
|
|
Status = RtlWriteRegistryValue(RTL_REGISTRY_DEVICEMAP,
|
|
|
|
L"VIDEO",
|
|
|
|
L"MaxObjectNumber",
|
|
|
|
REG_DWORD,
|
2021-07-10 17:01:11 +00:00
|
|
|
&DeviceNumber,
|
|
|
|
sizeof(DeviceNumber));
|
2021-07-03 19:26:57 +00:00
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
ERR_(VIDEOPRT, "Failed to write MaxObjectNumber: 0x%X\n", Status);
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Create symbolic link "\??\DISPLAYx" */
|
|
|
|
swprintf(SymlinkBuffer, L"\\??\\DISPLAY%lu", DeviceNumber + 1);
|
|
|
|
RtlInitUnicodeString(&SymlinkName, SymlinkBuffer);
|
|
|
|
RtlInitUnicodeString(&DeviceName, DeviceBuffer);
|
|
|
|
Status = IoCreateSymbolicLink(&SymlinkName, &DeviceName);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
2021-07-10 17:01:11 +00:00
|
|
|
ERR_(VIDEOPRT, "Failed to create symbolic link: 0x%X\n", Status);
|
2021-07-03 19:26:57 +00:00
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Update MaxObjectNumber */
|
|
|
|
VideoPortMaxObjectNumber = DeviceNumber;
|
|
|
|
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2013-11-13 21:32:16 +00:00
|
|
|
PVOID
|
|
|
|
NTAPI
|
2004-03-19 20:58:32 +00:00
|
|
|
IntVideoPortImageDirectoryEntryToData(
|
2013-11-13 21:32:16 +00:00
|
|
|
PVOID BaseAddress,
|
|
|
|
ULONG Directory)
|
2003-02-15 19:16:34 +00:00
|
|
|
{
|
2013-11-13 21:32:16 +00:00
|
|
|
PIMAGE_NT_HEADERS NtHeader;
|
|
|
|
ULONG Va;
|
2005-05-08 02:16:32 +00:00
|
|
|
|
2013-11-13 21:32:16 +00:00
|
|
|
NtHeader = RtlImageNtHeader(BaseAddress);
|
|
|
|
if (NtHeader == NULL)
|
|
|
|
return NULL;
|
2005-05-08 02:16:32 +00:00
|
|
|
|
2013-11-13 21:32:16 +00:00
|
|
|
if (Directory >= NtHeader->OptionalHeader.NumberOfRvaAndSizes)
|
|
|
|
return NULL;
|
2005-05-08 02:16:32 +00:00
|
|
|
|
2013-11-13 21:32:16 +00:00
|
|
|
Va = NtHeader->OptionalHeader.DataDirectory[Directory].VirtualAddress;
|
|
|
|
if (Va == 0)
|
|
|
|
return NULL;
|
2005-05-08 02:16:32 +00:00
|
|
|
|
2013-11-13 21:32:16 +00:00
|
|
|
return (PVOID)((ULONG_PTR)BaseAddress + Va);
|
2003-02-15 19:16:34 +00:00
|
|
|
}
|
|
|
|
|
2013-11-13 21:32:16 +00:00
|
|
|
VOID
|
|
|
|
NTAPI
|
2004-03-19 20:58:32 +00:00
|
|
|
IntVideoPortDeferredRoutine(
|
2013-11-13 21:32:16 +00:00
|
|
|
IN PKDPC Dpc,
|
|
|
|
IN PVOID DeferredContext,
|
|
|
|
IN PVOID SystemArgument1,
|
|
|
|
IN PVOID SystemArgument2)
|
2003-02-15 19:16:34 +00:00
|
|
|
{
|
2013-11-13 21:32:16 +00:00
|
|
|
PVOID HwDeviceExtension =
|
|
|
|
&((PVIDEO_PORT_DEVICE_EXTENSION)DeferredContext)->MiniPortDeviceExtension;
|
|
|
|
((PMINIPORT_DPC_ROUTINE)SystemArgument1)(HwDeviceExtension, SystemArgument2);
|
2003-02-15 19:16:34 +00:00
|
|
|
}
|
|
|
|
|
2013-11-13 21:32:16 +00:00
|
|
|
NTSTATUS
|
|
|
|
NTAPI
|
2005-01-07 01:03:34 +00:00
|
|
|
IntVideoPortCreateAdapterDeviceObject(
|
2020-06-08 20:45:45 +00:00
|
|
|
_In_ PDRIVER_OBJECT DriverObject,
|
|
|
|
_In_ PVIDEO_PORT_DRIVER_EXTENSION DriverExtension,
|
|
|
|
_In_opt_ PDEVICE_OBJECT PhysicalDeviceObject,
|
2021-07-03 20:59:30 +00:00
|
|
|
_In_ USHORT AdapterNumber,
|
|
|
|
_In_ USHORT DisplayNumber,
|
2020-06-08 20:45:45 +00:00
|
|
|
_Out_opt_ PDEVICE_OBJECT *DeviceObject)
|
2003-02-15 19:16:34 +00:00
|
|
|
{
|
2013-11-13 21:32:16 +00:00
|
|
|
PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension;
|
|
|
|
ULONG DeviceNumber;
|
|
|
|
ULONG PciSlotNumber;
|
|
|
|
PCI_SLOT_NUMBER SlotNumber;
|
|
|
|
ULONG Size;
|
|
|
|
NTSTATUS Status;
|
|
|
|
WCHAR DeviceBuffer[20];
|
|
|
|
UNICODE_STRING DeviceName;
|
|
|
|
PDEVICE_OBJECT DeviceObject_;
|
|
|
|
|
|
|
|
if (DeviceObject == NULL)
|
|
|
|
DeviceObject = &DeviceObject_;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Find the first free device number that can be used for video device
|
|
|
|
* object names and symlinks.
|
|
|
|
*/
|
2021-07-03 19:26:57 +00:00
|
|
|
DeviceNumber = VideoPortMaxObjectNumber + 1;
|
|
|
|
if (DeviceNumber == (ULONG)-1)
|
2013-11-13 21:32:16 +00:00
|
|
|
{
|
|
|
|
WARN_(VIDEOPRT, "Can't find free device number\n");
|
|
|
|
return STATUS_UNSUCCESSFUL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Create the device object.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* Create a unicode device name. */
|
|
|
|
swprintf(DeviceBuffer, L"\\Device\\Video%lu", DeviceNumber);
|
|
|
|
RtlInitUnicodeString(&DeviceName, DeviceBuffer);
|
|
|
|
|
|
|
|
INFO_(VIDEOPRT, "HwDeviceExtension size is: 0x%x\n",
|
|
|
|
DriverExtension->InitializationData.HwDeviceExtensionSize);
|
|
|
|
|
|
|
|
/* Create the device object. */
|
2013-11-16 18:40:24 +00:00
|
|
|
Size = sizeof(VIDEO_PORT_DEVICE_EXTENSION) +
|
|
|
|
DriverExtension->InitializationData.HwDeviceExtensionSize;
|
|
|
|
Status = IoCreateDevice(DriverObject,
|
|
|
|
Size,
|
|
|
|
&DeviceName,
|
|
|
|
FILE_DEVICE_VIDEO,
|
|
|
|
0,
|
|
|
|
TRUE,
|
|
|
|
DeviceObject);
|
2013-11-13 21:32:16 +00:00
|
|
|
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
WARN_(VIDEOPRT, "IoCreateDevice call failed with status 0x%08x\n", Status);
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Set the buffering strategy here. If you change this, remember
|
|
|
|
* to change VidDispatchDeviceControl too.
|
|
|
|
*/
|
|
|
|
|
|
|
|
(*DeviceObject)->Flags |= DO_BUFFERED_IO;
|
|
|
|
|
|
|
|
/* Initialize device extension. */
|
|
|
|
DeviceExtension = (PVIDEO_PORT_DEVICE_EXTENSION)((*DeviceObject)->DeviceExtension);
|
|
|
|
DeviceExtension->Common.Fdo = TRUE;
|
|
|
|
DeviceExtension->DeviceNumber = DeviceNumber;
|
|
|
|
DeviceExtension->DriverObject = DriverObject;
|
|
|
|
DeviceExtension->PhysicalDeviceObject = PhysicalDeviceObject;
|
|
|
|
DeviceExtension->FunctionalDeviceObject = *DeviceObject;
|
|
|
|
DeviceExtension->DriverExtension = DriverExtension;
|
2013-11-22 11:36:22 +00:00
|
|
|
DeviceExtension->SessionId = -1;
|
2021-07-03 20:59:30 +00:00
|
|
|
DeviceExtension->AdapterNumber = AdapterNumber;
|
|
|
|
DeviceExtension->DisplayNumber = DisplayNumber;
|
2013-11-13 21:32:16 +00:00
|
|
|
|
|
|
|
InitializeListHead(&DeviceExtension->ChildDeviceList);
|
|
|
|
|
2013-11-16 18:40:24 +00:00
|
|
|
/* Get the registry path associated with this device. */
|
2013-11-13 21:32:16 +00:00
|
|
|
Status = IntCreateRegistryPath(&DriverExtension->RegistryPath,
|
2021-07-03 20:59:30 +00:00
|
|
|
DeviceExtension->AdapterNumber,
|
2013-11-13 21:32:16 +00:00
|
|
|
&DeviceExtension->RegistryPath);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
WARN_(VIDEOPRT, "IntCreateRegistryPath() call failed with status 0x%08x\n", Status);
|
2022-10-15 13:02:36 +00:00
|
|
|
goto Failure;
|
2013-11-13 21:32:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (PhysicalDeviceObject != NULL)
|
|
|
|
{
|
|
|
|
/* Get bus number from the upper level bus driver. */
|
|
|
|
Size = sizeof(ULONG);
|
2013-11-16 18:40:24 +00:00
|
|
|
Status = IoGetDeviceProperty(PhysicalDeviceObject,
|
|
|
|
DevicePropertyBusNumber,
|
|
|
|
Size,
|
|
|
|
&DeviceExtension->SystemIoBusNumber,
|
|
|
|
&Size);
|
2013-11-13 21:32:16 +00:00
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
WARN_(VIDEOPRT, "Couldn't get an information from bus driver. We will try to\n"
|
|
|
|
"use legacy detection method, but even that doesn't mean that\n"
|
|
|
|
"it will work.\n");
|
|
|
|
DeviceExtension->PhysicalDeviceObject = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
DeviceExtension->AdapterInterfaceType =
|
|
|
|
DriverExtension->InitializationData.AdapterInterfaceType;
|
|
|
|
|
|
|
|
if (PhysicalDeviceObject != NULL)
|
|
|
|
{
|
|
|
|
/* Get bus type from the upper level bus driver. */
|
|
|
|
Size = sizeof(ULONG);
|
|
|
|
IoGetDeviceProperty(PhysicalDeviceObject,
|
|
|
|
DevicePropertyLegacyBusType,
|
|
|
|
Size,
|
|
|
|
&DeviceExtension->AdapterInterfaceType,
|
|
|
|
&Size);
|
|
|
|
|
|
|
|
/* Get bus device address from the upper level bus driver. */
|
|
|
|
Size = sizeof(ULONG);
|
|
|
|
IoGetDeviceProperty(PhysicalDeviceObject,
|
|
|
|
DevicePropertyAddress,
|
|
|
|
Size,
|
|
|
|
&PciSlotNumber,
|
|
|
|
&Size);
|
2007-06-27 18:05:04 +00:00
|
|
|
|
|
|
|
/* Convert slotnumber to PCI_SLOT_NUMBER */
|
|
|
|
SlotNumber.u.AsULONG = 0;
|
|
|
|
SlotNumber.u.bits.DeviceNumber = (PciSlotNumber >> 16) & 0xFFFF;
|
|
|
|
SlotNumber.u.bits.FunctionNumber = PciSlotNumber & 0xFFFF;
|
|
|
|
DeviceExtension->SystemIoSlotNumber = SlotNumber.u.AsULONG;
|
2013-11-13 21:32:16 +00:00
|
|
|
}
|
2003-10-24 21:39:59 +00:00
|
|
|
|
2013-11-13 21:32:16 +00:00
|
|
|
InitializeListHead(&DeviceExtension->AddressMappingListHead);
|
|
|
|
InitializeListHead(&DeviceExtension->DmaAdapterList);
|
2010-10-01 17:43:03 +00:00
|
|
|
|
2013-11-13 21:32:16 +00:00
|
|
|
KeInitializeDpc(&DeviceExtension->DpcObject,
|
|
|
|
IntVideoPortDeferredRoutine,
|
|
|
|
DeviceExtension);
|
2004-03-19 20:58:32 +00:00
|
|
|
|
2013-11-13 21:32:16 +00:00
|
|
|
KeInitializeMutex(&DeviceExtension->DeviceLock, 0);
|
2005-01-07 01:03:34 +00:00
|
|
|
|
2013-11-13 21:32:16 +00:00
|
|
|
/* Attach the device. */
|
2021-07-04 18:26:32 +00:00
|
|
|
if ((PhysicalDeviceObject != NULL) && (DisplayNumber == 0))
|
2013-11-13 21:32:16 +00:00
|
|
|
DeviceExtension->NextDeviceObject = IoAttachDeviceToDeviceStack(
|
|
|
|
*DeviceObject,
|
|
|
|
PhysicalDeviceObject);
|
2005-01-07 01:03:34 +00:00
|
|
|
|
2021-07-03 20:59:30 +00:00
|
|
|
Status = IntCreateNewRegistryPath(DeviceExtension);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
ERR_(VIDEOPRT, "IntCreateNewRegistryPath() failed with status 0x%08x\n", Status);
|
2022-10-15 13:02:36 +00:00
|
|
|
goto Failure;
|
2021-07-03 20:59:30 +00:00
|
|
|
}
|
|
|
|
|
2013-11-16 18:40:24 +00:00
|
|
|
IntSetupDeviceSettingsKey(DeviceExtension);
|
|
|
|
|
2023-06-07 20:53:10 +00:00
|
|
|
/* Remove the initializing flag */
|
2013-11-13 21:32:16 +00:00
|
|
|
(*DeviceObject)->Flags &= ~DO_DEVICE_INITIALIZING;
|
2021-07-03 19:26:57 +00:00
|
|
|
|
|
|
|
/* Set up the VIDEO/DEVICEMAP registry keys */
|
|
|
|
Status = IntVideoPortAddDeviceMapLink(DeviceExtension);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
ERR_(VIDEOPRT, "IntVideoPortAddDeviceMapLink() failed with status 0x%08x\n", Status);
|
2022-10-15 13:02:36 +00:00
|
|
|
goto Failure;
|
2021-07-03 19:26:57 +00:00
|
|
|
}
|
|
|
|
|
2021-07-03 20:59:30 +00:00
|
|
|
if (DisplayNumber == 0)
|
|
|
|
{
|
|
|
|
DriverExtension->InitializationData.StartingDeviceNumber++;
|
|
|
|
}
|
|
|
|
|
2013-11-13 21:32:16 +00:00
|
|
|
return STATUS_SUCCESS;
|
2022-10-15 13:02:36 +00:00
|
|
|
|
|
|
|
Failure:
|
|
|
|
if (DeviceExtension->NextDeviceObject)
|
|
|
|
IoDetachDevice(DeviceExtension->NextDeviceObject);
|
|
|
|
IoDeleteDevice(*DeviceObject);
|
|
|
|
*DeviceObject = NULL;
|
|
|
|
return Status;
|
2005-01-07 01:03:34 +00:00
|
|
|
}
|
|
|
|
|
2023-06-07 20:53:10 +00:00
|
|
|
/**
|
|
|
|
* @brief
|
|
|
|
* A PIO_QUERY_DEVICE_ROUTINE callback for IoQueryDeviceDescription()
|
|
|
|
* to return success when an enumerated bus has been found.
|
|
|
|
**/
|
|
|
|
static NTSTATUS
|
|
|
|
NTAPI
|
|
|
|
IntVideoPortEnumBusCallback(
|
|
|
|
_In_ PVOID Context,
|
|
|
|
_In_ PUNICODE_STRING PathName,
|
|
|
|
_In_ INTERFACE_TYPE BusType,
|
|
|
|
_In_ ULONG BusNumber,
|
|
|
|
_In_ PKEY_VALUE_FULL_INFORMATION* BusInformation,
|
|
|
|
_In_ CONFIGURATION_TYPE ControllerType,
|
|
|
|
_In_ ULONG ControllerNumber,
|
|
|
|
_In_ PKEY_VALUE_FULL_INFORMATION* ControllerInformation,
|
|
|
|
_In_ CONFIGURATION_TYPE PeripheralType,
|
|
|
|
_In_ ULONG PeripheralNumber,
|
|
|
|
_In_ PKEY_VALUE_FULL_INFORMATION* PeripheralInformation)
|
|
|
|
{
|
|
|
|
UNREFERENCED_PARAMETER(Context);
|
|
|
|
UNREFERENCED_PARAMETER(PathName);
|
|
|
|
UNREFERENCED_PARAMETER(BusType);
|
|
|
|
UNREFERENCED_PARAMETER(BusNumber);
|
|
|
|
UNREFERENCED_PARAMETER(BusInformation);
|
|
|
|
UNREFERENCED_PARAMETER(ControllerType);
|
|
|
|
UNREFERENCED_PARAMETER(ControllerNumber);
|
|
|
|
UNREFERENCED_PARAMETER(ControllerInformation);
|
|
|
|
UNREFERENCED_PARAMETER(PeripheralType);
|
|
|
|
UNREFERENCED_PARAMETER(PeripheralNumber);
|
|
|
|
UNREFERENCED_PARAMETER(PeripheralInformation);
|
|
|
|
|
|
|
|
/* The bus has been found */
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief
|
|
|
|
* Enumerates all supported buses on the system.
|
|
|
|
**/
|
|
|
|
static NTSTATUS
|
|
|
|
IntVideoPortEnumBuses(
|
|
|
|
_In_ INTERFACE_TYPE AdapterInterfaceType,
|
|
|
|
_Inout_ PULONG BusNumber)
|
|
|
|
{
|
|
|
|
// TODO: Forward-compatibility with Windows 7+:
|
|
|
|
// In case AdapterInterfaceType == PCIBus, check for the
|
|
|
|
// \Registry\HARDWARE\DESCRIPTION\System\VideoAdapterBusses
|
|
|
|
// key (created by pci.sys) that enumerates the PCI buses that
|
|
|
|
// are known to have video display adapters on them.
|
|
|
|
// This is a handy shortcut for videoprt, that would otherwise
|
|
|
|
// have to enumerate all the PCI buses (PCI_MAX_BRIDGE_NUMBER)
|
|
|
|
// to locate any video adapter.
|
|
|
|
// Otherwise, fall back to the usual method done below.
|
|
|
|
|
|
|
|
/* Find the next bus of the given type */
|
|
|
|
return IoQueryDeviceDescription(&AdapterInterfaceType,
|
|
|
|
BusNumber,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
IntVideoPortEnumBusCallback,
|
|
|
|
NULL);
|
|
|
|
}
|
2005-01-07 01:03:34 +00:00
|
|
|
|
2013-11-13 21:32:16 +00:00
|
|
|
NTSTATUS
|
|
|
|
NTAPI
|
2005-01-07 01:03:34 +00:00
|
|
|
IntVideoPortFindAdapter(
|
2013-11-13 21:32:16 +00:00
|
|
|
IN PDRIVER_OBJECT DriverObject,
|
|
|
|
IN PVIDEO_PORT_DRIVER_EXTENSION DriverExtension,
|
|
|
|
IN PDEVICE_OBJECT DeviceObject)
|
2005-01-07 01:03:34 +00:00
|
|
|
{
|
2013-11-13 21:32:16 +00:00
|
|
|
PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension;
|
|
|
|
NTSTATUS Status;
|
2021-10-09 05:21:53 +00:00
|
|
|
VP_STATUS vpStatus;
|
2013-11-13 21:32:16 +00:00
|
|
|
VIDEO_PORT_CONFIG_INFO ConfigInfo;
|
|
|
|
SYSTEM_BASIC_INFORMATION SystemBasicInfo;
|
|
|
|
UCHAR Again = FALSE;
|
|
|
|
BOOL LegacyDetection = FALSE;
|
|
|
|
|
|
|
|
DeviceExtension = (PVIDEO_PORT_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
|
|
|
|
|
|
|
|
/* Setup a ConfigInfo structure that we will pass to HwFindAdapter. */
|
|
|
|
RtlZeroMemory(&ConfigInfo, sizeof(VIDEO_PORT_CONFIG_INFO));
|
|
|
|
ConfigInfo.Length = sizeof(VIDEO_PORT_CONFIG_INFO);
|
|
|
|
ConfigInfo.AdapterInterfaceType = DeviceExtension->AdapterInterfaceType;
|
|
|
|
if (ConfigInfo.AdapterInterfaceType == PCIBus)
|
|
|
|
ConfigInfo.InterruptMode = LevelSensitive;
|
|
|
|
else
|
|
|
|
ConfigInfo.InterruptMode = Latched;
|
|
|
|
ConfigInfo.DriverRegistryPath = DriverExtension->RegistryPath.Buffer;
|
|
|
|
ConfigInfo.VideoPortGetProcAddress = IntVideoPortGetProcAddress;
|
|
|
|
ConfigInfo.SystemIoBusNumber = DeviceExtension->SystemIoBusNumber;
|
|
|
|
ConfigInfo.BusInterruptLevel = DeviceExtension->InterruptLevel;
|
|
|
|
ConfigInfo.BusInterruptVector = DeviceExtension->InterruptVector;
|
|
|
|
|
|
|
|
Status = ZwQuerySystemInformation(SystemBasicInformation,
|
|
|
|
&SystemBasicInfo,
|
2017-08-18 08:44:08 +00:00
|
|
|
sizeof(SystemBasicInfo),
|
|
|
|
NULL);
|
2013-11-13 21:32:16 +00:00
|
|
|
if (NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
ConfigInfo.SystemMemorySize = SystemBasicInfo.NumberOfPhysicalPages *
|
|
|
|
SystemBasicInfo.PageSize;
|
|
|
|
}
|
|
|
|
|
2020-09-15 12:24:42 +00:00
|
|
|
// FIXME: Check the adapter key and update VideoDebugLevel variable.
|
|
|
|
|
2013-11-13 21:32:16 +00:00
|
|
|
/*
|
|
|
|
* Call miniport HwVidFindAdapter entry point to detect if
|
|
|
|
* particular device is present. There are two possible code
|
|
|
|
* paths. The first one is for Legacy drivers (NT4) and cases
|
|
|
|
* when we don't have information about what bus we're on. The
|
|
|
|
* second case is the standard one for Plug & Play drivers.
|
|
|
|
*/
|
|
|
|
if (DeviceExtension->PhysicalDeviceObject == NULL)
|
|
|
|
{
|
|
|
|
LegacyDetection = TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (LegacyDetection)
|
|
|
|
{
|
2023-06-07 20:53:10 +00:00
|
|
|
ULONG BusNumber;
|
2013-11-13 21:32:16 +00:00
|
|
|
|
2023-06-07 20:53:10 +00:00
|
|
|
/* Suppose first we may not find any suitable device */
|
|
|
|
vpStatus = ERROR_DEV_NOT_EXIST; // ERROR_NO_MORE_DEVICES;
|
2013-11-13 21:32:16 +00:00
|
|
|
|
2023-06-07 20:53:10 +00:00
|
|
|
/* Enumerate all buses of the given type, call HwFindAdapter for each
|
|
|
|
* to find whether a video adapter is recognized there. Stop when an
|
|
|
|
* adapter has been found. */
|
|
|
|
for (BusNumber = 0;
|
|
|
|
(BusNumber < MAXULONG) &&
|
|
|
|
NT_SUCCESS(IntVideoPortEnumBuses(DeviceExtension->AdapterInterfaceType,
|
|
|
|
&BusNumber));
|
|
|
|
++BusNumber)
|
2013-11-13 21:32:16 +00:00
|
|
|
{
|
2023-06-07 20:53:10 +00:00
|
|
|
DPRINT("Bus Type %lu, Number %lu\n",
|
|
|
|
DeviceExtension->AdapterInterfaceType, BusNumber);
|
|
|
|
|
2013-11-13 21:32:16 +00:00
|
|
|
DeviceExtension->SystemIoBusNumber =
|
|
|
|
ConfigInfo.SystemIoBusNumber = BusNumber;
|
|
|
|
|
|
|
|
RtlZeroMemory(&DeviceExtension->MiniPortDeviceExtension,
|
|
|
|
DriverExtension->InitializationData.HwDeviceExtensionSize);
|
|
|
|
|
|
|
|
/* FIXME: Need to figure out what string to pass as param 3. */
|
2023-06-07 20:53:10 +00:00
|
|
|
// FIXME: Handle the 'Again' parameter for legacy detection.
|
2021-10-09 05:21:53 +00:00
|
|
|
vpStatus = DriverExtension->InitializationData.HwFindAdapter(
|
2013-11-13 21:32:16 +00:00
|
|
|
&DeviceExtension->MiniPortDeviceExtension,
|
|
|
|
DriverExtension->HwContext,
|
|
|
|
NULL,
|
|
|
|
&ConfigInfo,
|
|
|
|
&Again);
|
|
|
|
|
2021-10-09 05:21:53 +00:00
|
|
|
if (vpStatus == ERROR_DEV_NOT_EXIST)
|
2013-11-13 21:32:16 +00:00
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2021-10-09 05:21:53 +00:00
|
|
|
break;
|
2013-11-13 21:32:16 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* FIXME: Need to figure out what string to pass as param 3. */
|
2021-10-09 05:21:53 +00:00
|
|
|
vpStatus = DriverExtension->InitializationData.HwFindAdapter(
|
2013-11-13 21:32:16 +00:00
|
|
|
&DeviceExtension->MiniPortDeviceExtension,
|
|
|
|
DriverExtension->HwContext,
|
|
|
|
NULL,
|
|
|
|
&ConfigInfo,
|
|
|
|
&Again);
|
|
|
|
}
|
|
|
|
|
2021-10-09 05:21:53 +00:00
|
|
|
if (vpStatus != NO_ERROR)
|
2013-11-13 21:32:16 +00:00
|
|
|
{
|
2021-10-09 05:21:53 +00:00
|
|
|
ERR_(VIDEOPRT, "HwFindAdapter call failed with error 0x%X\n", vpStatus);
|
|
|
|
Status = STATUS_UNSUCCESSFUL;
|
2013-11-16 18:40:24 +00:00
|
|
|
goto Failure;
|
2013-11-13 21:32:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Now we know the device is present, so let's do all additional tasks
|
|
|
|
* such as creating symlinks or setting up interrupts and timer.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* FIXME: Allocate hardware resources for device. */
|
|
|
|
|
|
|
|
/* Allocate interrupt for device. */
|
|
|
|
if (!IntVideoPortSetupInterrupt(DeviceObject, DriverExtension, &ConfigInfo))
|
|
|
|
{
|
2013-11-16 18:40:24 +00:00
|
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
goto Failure;
|
2013-11-13 21:32:16 +00:00
|
|
|
}
|
|
|
|
|
2013-11-16 18:40:24 +00:00
|
|
|
/* Allocate timer for device. */
|
2013-11-13 21:32:16 +00:00
|
|
|
if (!IntVideoPortSetupTimer(DeviceObject, DriverExtension))
|
|
|
|
{
|
|
|
|
if (DeviceExtension->InterruptObject != NULL)
|
|
|
|
IoDisconnectInterrupt(DeviceExtension->InterruptObject);
|
|
|
|
ERR_(VIDEOPRT, "IntVideoPortSetupTimer failed\n");
|
2013-11-16 18:40:24 +00:00
|
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
goto Failure;
|
2013-11-13 21:32:16 +00:00
|
|
|
}
|
|
|
|
|
[WIN32K][VIDEOPRT] Improve initialization and interfacing with INBV.
CORE-12149
VIDEOPRT:
=========
Improve interfacing with INBV, so as to detect when an external module
acquired INBV display ownership, and whether ownership is being released
later on. (This does NOT rely on hooking!)
For this purpose we improve the IntVideoPortResetDisplayParameters(Ex)
callback that gets registered with an InbvNotifyDisplayOwnershipLost()
call during initialization, and we add a monitoring thread.
The callback is called whenever an external module calls
InbvAcquireDisplayOwnership(), for example the bugcheck code or the KDBG
debugger in SCREEN mode. When this happens, a flag that tells the
monitoring thread to start monitoring INBV is set (ReactOS-specific),
and the display adapters get reset with HwResetHw() (as done on Windows).
Due to the fact that this INBV callback can be called at *ANY* IRQL, we
cannot use dispatcher synchronization mechanisms such as events to tell
the INBV monitoring thread to start its operations, so we need to rely
instead on a flag to be set. And, since INBV doesn't provide with any
proper callback/notification system either, we need to actively monitor
its state by pooling. To reduce the load on the system the monitoring
thread performs 1-second waits between each check for the flag set by
the INBV callback, and during checking the INBV ownership status.
When the INBV ownership is detected to be released by an external module,
the INBV callback is re-registered (this is *MANDATORY* since the
external module has called InbvNotifyDisplayOwnershipLost() with a
different callback parameter!), and then we callout to Win32k for
re-enabling the display.
This has the virtue of correctly resetting the display once the KDBG
debugger in SCREEN mode is being exited, and fixes CORE-12149 .
The following additional fixes were needed:
VIDEOPRT & WIN32K:
==================
Remove the registration with INBV that was previously done in a ReactOS-
specific hacked IRP_MJ_WRITE call; it is now done correctly during the
video device opening done by EngpRegisterGraphicsDevice() in the VIDEOPRT's
IRP_MJ_CREATE handler, as done on Windows.
WIN32K:
=======
- Stub the VideoPortCallout() support, for VIDEOPRT -> WIN32 callbacks.
This function gets registered with VIDEOPRT through an
IOCTL_VIDEO_INIT_WIN32K_CALLBACKS call in EngpRegisterGraphicsDevice().
- Only partially implement the 'VideoFindAdapterCallout' case, that just
re-enables the primary display by refreshing it (using the new function
UserRefreshDisplay()).
VIDEOPRT:
=========
- PVIDEO_WIN32K_CALLOUT is an NTAPI (stdcall) callback.
- In the IntVideoPortResetDisplayParameters(Ex) callback, reset all the
"resettable" adapters registered in the HwResetAdaptersList list.
We thus get rid of the global ResetDisplayParametersDeviceExtension.
- Make the IntVideoPortResetDisplayParameters(Ex) callback slightly more
robust (using SEH) against potential HwResetListEntry list corruption
or invalid DriverExtension->InitializationData.HwResetHw() that would
otherwise trigger a BSOD, and this would be disastrous since that
callback is precisely called when INBV is acquired, typically when the
BSOD code initializes the display for displaying its information...
Extras:
- Validate the IrpStack->MajorFunction in IntVideoPortDispatchDeviceControl()
and implement IRP_MJ_SHUTDOWN handling. Stub out the other IOCTLs that
are handled by VIDEOPRT only (and not by the miniports).
- VIDEOPRT doesn't require IRP_MJ_INTERNAL_DEVICE_CONTROL (unused).
- Implement IOCTL_VIDEO_PREPARE_FOR_EARECOVERY that just resets the
display to standard VGA 80x25 text mode.
2019-11-26 01:49:35 +00:00
|
|
|
/* If the device can be reset, insert it in the list of resettable adapters */
|
|
|
|
InitializeListHead(&DeviceExtension->HwResetListEntry);
|
|
|
|
if (DriverExtension->InitializationData.HwResetHw != NULL)
|
|
|
|
{
|
2019-12-03 01:08:34 +00:00
|
|
|
ExInterlockedInsertTailList(&HwResetAdaptersList,
|
|
|
|
&DeviceExtension->HwResetListEntry,
|
|
|
|
&HwResetAdaptersLock);
|
[WIN32K][VIDEOPRT] Improve initialization and interfacing with INBV.
CORE-12149
VIDEOPRT:
=========
Improve interfacing with INBV, so as to detect when an external module
acquired INBV display ownership, and whether ownership is being released
later on. (This does NOT rely on hooking!)
For this purpose we improve the IntVideoPortResetDisplayParameters(Ex)
callback that gets registered with an InbvNotifyDisplayOwnershipLost()
call during initialization, and we add a monitoring thread.
The callback is called whenever an external module calls
InbvAcquireDisplayOwnership(), for example the bugcheck code or the KDBG
debugger in SCREEN mode. When this happens, a flag that tells the
monitoring thread to start monitoring INBV is set (ReactOS-specific),
and the display adapters get reset with HwResetHw() (as done on Windows).
Due to the fact that this INBV callback can be called at *ANY* IRQL, we
cannot use dispatcher synchronization mechanisms such as events to tell
the INBV monitoring thread to start its operations, so we need to rely
instead on a flag to be set. And, since INBV doesn't provide with any
proper callback/notification system either, we need to actively monitor
its state by pooling. To reduce the load on the system the monitoring
thread performs 1-second waits between each check for the flag set by
the INBV callback, and during checking the INBV ownership status.
When the INBV ownership is detected to be released by an external module,
the INBV callback is re-registered (this is *MANDATORY* since the
external module has called InbvNotifyDisplayOwnershipLost() with a
different callback parameter!), and then we callout to Win32k for
re-enabling the display.
This has the virtue of correctly resetting the display once the KDBG
debugger in SCREEN mode is being exited, and fixes CORE-12149 .
The following additional fixes were needed:
VIDEOPRT & WIN32K:
==================
Remove the registration with INBV that was previously done in a ReactOS-
specific hacked IRP_MJ_WRITE call; it is now done correctly during the
video device opening done by EngpRegisterGraphicsDevice() in the VIDEOPRT's
IRP_MJ_CREATE handler, as done on Windows.
WIN32K:
=======
- Stub the VideoPortCallout() support, for VIDEOPRT -> WIN32 callbacks.
This function gets registered with VIDEOPRT through an
IOCTL_VIDEO_INIT_WIN32K_CALLBACKS call in EngpRegisterGraphicsDevice().
- Only partially implement the 'VideoFindAdapterCallout' case, that just
re-enables the primary display by refreshing it (using the new function
UserRefreshDisplay()).
VIDEOPRT:
=========
- PVIDEO_WIN32K_CALLOUT is an NTAPI (stdcall) callback.
- In the IntVideoPortResetDisplayParameters(Ex) callback, reset all the
"resettable" adapters registered in the HwResetAdaptersList list.
We thus get rid of the global ResetDisplayParametersDeviceExtension.
- Make the IntVideoPortResetDisplayParameters(Ex) callback slightly more
robust (using SEH) against potential HwResetListEntry list corruption
or invalid DriverExtension->InitializationData.HwResetHw() that would
otherwise trigger a BSOD, and this would be disastrous since that
callback is precisely called when INBV is acquired, typically when the
BSOD code initializes the display for displaying its information...
Extras:
- Validate the IrpStack->MajorFunction in IntVideoPortDispatchDeviceControl()
and implement IRP_MJ_SHUTDOWN handling. Stub out the other IOCTLs that
are handled by VIDEOPRT only (and not by the miniports).
- VIDEOPRT doesn't require IRP_MJ_INTERNAL_DEVICE_CONTROL (unused).
- Implement IOCTL_VIDEO_PREPARE_FOR_EARECOVERY that just resets the
display to standard VGA 80x25 text mode.
2019-11-26 01:49:35 +00:00
|
|
|
}
|
|
|
|
|
2013-11-13 21:32:16 +00:00
|
|
|
INFO_(VIDEOPRT, "STATUS_SUCCESS\n");
|
|
|
|
return STATUS_SUCCESS;
|
2013-11-16 18:40:24 +00:00
|
|
|
|
|
|
|
Failure:
|
|
|
|
RtlFreeUnicodeString(&DeviceExtension->RegistryPath);
|
|
|
|
if (DeviceExtension->NextDeviceObject)
|
|
|
|
IoDetachDevice(DeviceExtension->NextDeviceObject);
|
|
|
|
IoDeleteDevice(DeviceObject);
|
|
|
|
return Status;
|
2003-11-05 22:31:50 +00:00
|
|
|
}
|
|
|
|
|
2013-11-13 21:32:16 +00:00
|
|
|
VOID
|
|
|
|
FASTCALL
|
|
|
|
IntAttachToCSRSS(
|
2013-11-16 18:40:24 +00:00
|
|
|
PKPROCESS *CallingProcess,
|
2013-11-13 21:32:16 +00:00
|
|
|
PKAPC_STATE ApcState)
|
2005-05-08 02:16:32 +00:00
|
|
|
{
|
2013-11-13 21:32:16 +00:00
|
|
|
*CallingProcess = (PKPROCESS)PsGetCurrentProcess();
|
[WIN32K][VIDEOPRT] Improve initialization and interfacing with INBV.
CORE-12149
VIDEOPRT:
=========
Improve interfacing with INBV, so as to detect when an external module
acquired INBV display ownership, and whether ownership is being released
later on. (This does NOT rely on hooking!)
For this purpose we improve the IntVideoPortResetDisplayParameters(Ex)
callback that gets registered with an InbvNotifyDisplayOwnershipLost()
call during initialization, and we add a monitoring thread.
The callback is called whenever an external module calls
InbvAcquireDisplayOwnership(), for example the bugcheck code or the KDBG
debugger in SCREEN mode. When this happens, a flag that tells the
monitoring thread to start monitoring INBV is set (ReactOS-specific),
and the display adapters get reset with HwResetHw() (as done on Windows).
Due to the fact that this INBV callback can be called at *ANY* IRQL, we
cannot use dispatcher synchronization mechanisms such as events to tell
the INBV monitoring thread to start its operations, so we need to rely
instead on a flag to be set. And, since INBV doesn't provide with any
proper callback/notification system either, we need to actively monitor
its state by pooling. To reduce the load on the system the monitoring
thread performs 1-second waits between each check for the flag set by
the INBV callback, and during checking the INBV ownership status.
When the INBV ownership is detected to be released by an external module,
the INBV callback is re-registered (this is *MANDATORY* since the
external module has called InbvNotifyDisplayOwnershipLost() with a
different callback parameter!), and then we callout to Win32k for
re-enabling the display.
This has the virtue of correctly resetting the display once the KDBG
debugger in SCREEN mode is being exited, and fixes CORE-12149 .
The following additional fixes were needed:
VIDEOPRT & WIN32K:
==================
Remove the registration with INBV that was previously done in a ReactOS-
specific hacked IRP_MJ_WRITE call; it is now done correctly during the
video device opening done by EngpRegisterGraphicsDevice() in the VIDEOPRT's
IRP_MJ_CREATE handler, as done on Windows.
WIN32K:
=======
- Stub the VideoPortCallout() support, for VIDEOPRT -> WIN32 callbacks.
This function gets registered with VIDEOPRT through an
IOCTL_VIDEO_INIT_WIN32K_CALLBACKS call in EngpRegisterGraphicsDevice().
- Only partially implement the 'VideoFindAdapterCallout' case, that just
re-enables the primary display by refreshing it (using the new function
UserRefreshDisplay()).
VIDEOPRT:
=========
- PVIDEO_WIN32K_CALLOUT is an NTAPI (stdcall) callback.
- In the IntVideoPortResetDisplayParameters(Ex) callback, reset all the
"resettable" adapters registered in the HwResetAdaptersList list.
We thus get rid of the global ResetDisplayParametersDeviceExtension.
- Make the IntVideoPortResetDisplayParameters(Ex) callback slightly more
robust (using SEH) against potential HwResetListEntry list corruption
or invalid DriverExtension->InitializationData.HwResetHw() that would
otherwise trigger a BSOD, and this would be disastrous since that
callback is precisely called when INBV is acquired, typically when the
BSOD code initializes the display for displaying its information...
Extras:
- Validate the IrpStack->MajorFunction in IntVideoPortDispatchDeviceControl()
and implement IRP_MJ_SHUTDOWN handling. Stub out the other IOCTLs that
are handled by VIDEOPRT only (and not by the miniports).
- VIDEOPRT doesn't require IRP_MJ_INTERNAL_DEVICE_CONTROL (unused).
- Implement IOCTL_VIDEO_PREPARE_FOR_EARECOVERY that just resets the
display to standard VGA 80x25 text mode.
2019-11-26 01:49:35 +00:00
|
|
|
if (*CallingProcess != CsrProcess)
|
2013-11-13 21:32:16 +00:00
|
|
|
{
|
[WIN32K][VIDEOPRT] Improve initialization and interfacing with INBV.
CORE-12149
VIDEOPRT:
=========
Improve interfacing with INBV, so as to detect when an external module
acquired INBV display ownership, and whether ownership is being released
later on. (This does NOT rely on hooking!)
For this purpose we improve the IntVideoPortResetDisplayParameters(Ex)
callback that gets registered with an InbvNotifyDisplayOwnershipLost()
call during initialization, and we add a monitoring thread.
The callback is called whenever an external module calls
InbvAcquireDisplayOwnership(), for example the bugcheck code or the KDBG
debugger in SCREEN mode. When this happens, a flag that tells the
monitoring thread to start monitoring INBV is set (ReactOS-specific),
and the display adapters get reset with HwResetHw() (as done on Windows).
Due to the fact that this INBV callback can be called at *ANY* IRQL, we
cannot use dispatcher synchronization mechanisms such as events to tell
the INBV monitoring thread to start its operations, so we need to rely
instead on a flag to be set. And, since INBV doesn't provide with any
proper callback/notification system either, we need to actively monitor
its state by pooling. To reduce the load on the system the monitoring
thread performs 1-second waits between each check for the flag set by
the INBV callback, and during checking the INBV ownership status.
When the INBV ownership is detected to be released by an external module,
the INBV callback is re-registered (this is *MANDATORY* since the
external module has called InbvNotifyDisplayOwnershipLost() with a
different callback parameter!), and then we callout to Win32k for
re-enabling the display.
This has the virtue of correctly resetting the display once the KDBG
debugger in SCREEN mode is being exited, and fixes CORE-12149 .
The following additional fixes were needed:
VIDEOPRT & WIN32K:
==================
Remove the registration with INBV that was previously done in a ReactOS-
specific hacked IRP_MJ_WRITE call; it is now done correctly during the
video device opening done by EngpRegisterGraphicsDevice() in the VIDEOPRT's
IRP_MJ_CREATE handler, as done on Windows.
WIN32K:
=======
- Stub the VideoPortCallout() support, for VIDEOPRT -> WIN32 callbacks.
This function gets registered with VIDEOPRT through an
IOCTL_VIDEO_INIT_WIN32K_CALLBACKS call in EngpRegisterGraphicsDevice().
- Only partially implement the 'VideoFindAdapterCallout' case, that just
re-enables the primary display by refreshing it (using the new function
UserRefreshDisplay()).
VIDEOPRT:
=========
- PVIDEO_WIN32K_CALLOUT is an NTAPI (stdcall) callback.
- In the IntVideoPortResetDisplayParameters(Ex) callback, reset all the
"resettable" adapters registered in the HwResetAdaptersList list.
We thus get rid of the global ResetDisplayParametersDeviceExtension.
- Make the IntVideoPortResetDisplayParameters(Ex) callback slightly more
robust (using SEH) against potential HwResetListEntry list corruption
or invalid DriverExtension->InitializationData.HwResetHw() that would
otherwise trigger a BSOD, and this would be disastrous since that
callback is precisely called when INBV is acquired, typically when the
BSOD code initializes the display for displaying its information...
Extras:
- Validate the IrpStack->MajorFunction in IntVideoPortDispatchDeviceControl()
and implement IRP_MJ_SHUTDOWN handling. Stub out the other IOCTLs that
are handled by VIDEOPRT only (and not by the miniports).
- VIDEOPRT doesn't require IRP_MJ_INTERNAL_DEVICE_CONTROL (unused).
- Implement IOCTL_VIDEO_PREPARE_FOR_EARECOVERY that just resets the
display to standard VGA 80x25 text mode.
2019-11-26 01:49:35 +00:00
|
|
|
KeStackAttachProcess(CsrProcess, ApcState);
|
2013-11-13 21:32:16 +00:00
|
|
|
}
|
2005-05-08 02:16:32 +00:00
|
|
|
}
|
|
|
|
|
2013-11-13 21:32:16 +00:00
|
|
|
VOID
|
|
|
|
FASTCALL
|
|
|
|
IntDetachFromCSRSS(
|
|
|
|
PKPROCESS *CallingProcess,
|
|
|
|
PKAPC_STATE ApcState)
|
2005-05-08 02:16:32 +00:00
|
|
|
{
|
[WIN32K][VIDEOPRT] Improve initialization and interfacing with INBV.
CORE-12149
VIDEOPRT:
=========
Improve interfacing with INBV, so as to detect when an external module
acquired INBV display ownership, and whether ownership is being released
later on. (This does NOT rely on hooking!)
For this purpose we improve the IntVideoPortResetDisplayParameters(Ex)
callback that gets registered with an InbvNotifyDisplayOwnershipLost()
call during initialization, and we add a monitoring thread.
The callback is called whenever an external module calls
InbvAcquireDisplayOwnership(), for example the bugcheck code or the KDBG
debugger in SCREEN mode. When this happens, a flag that tells the
monitoring thread to start monitoring INBV is set (ReactOS-specific),
and the display adapters get reset with HwResetHw() (as done on Windows).
Due to the fact that this INBV callback can be called at *ANY* IRQL, we
cannot use dispatcher synchronization mechanisms such as events to tell
the INBV monitoring thread to start its operations, so we need to rely
instead on a flag to be set. And, since INBV doesn't provide with any
proper callback/notification system either, we need to actively monitor
its state by pooling. To reduce the load on the system the monitoring
thread performs 1-second waits between each check for the flag set by
the INBV callback, and during checking the INBV ownership status.
When the INBV ownership is detected to be released by an external module,
the INBV callback is re-registered (this is *MANDATORY* since the
external module has called InbvNotifyDisplayOwnershipLost() with a
different callback parameter!), and then we callout to Win32k for
re-enabling the display.
This has the virtue of correctly resetting the display once the KDBG
debugger in SCREEN mode is being exited, and fixes CORE-12149 .
The following additional fixes were needed:
VIDEOPRT & WIN32K:
==================
Remove the registration with INBV that was previously done in a ReactOS-
specific hacked IRP_MJ_WRITE call; it is now done correctly during the
video device opening done by EngpRegisterGraphicsDevice() in the VIDEOPRT's
IRP_MJ_CREATE handler, as done on Windows.
WIN32K:
=======
- Stub the VideoPortCallout() support, for VIDEOPRT -> WIN32 callbacks.
This function gets registered with VIDEOPRT through an
IOCTL_VIDEO_INIT_WIN32K_CALLBACKS call in EngpRegisterGraphicsDevice().
- Only partially implement the 'VideoFindAdapterCallout' case, that just
re-enables the primary display by refreshing it (using the new function
UserRefreshDisplay()).
VIDEOPRT:
=========
- PVIDEO_WIN32K_CALLOUT is an NTAPI (stdcall) callback.
- In the IntVideoPortResetDisplayParameters(Ex) callback, reset all the
"resettable" adapters registered in the HwResetAdaptersList list.
We thus get rid of the global ResetDisplayParametersDeviceExtension.
- Make the IntVideoPortResetDisplayParameters(Ex) callback slightly more
robust (using SEH) against potential HwResetListEntry list corruption
or invalid DriverExtension->InitializationData.HwResetHw() that would
otherwise trigger a BSOD, and this would be disastrous since that
callback is precisely called when INBV is acquired, typically when the
BSOD code initializes the display for displaying its information...
Extras:
- Validate the IrpStack->MajorFunction in IntVideoPortDispatchDeviceControl()
and implement IRP_MJ_SHUTDOWN handling. Stub out the other IOCTLs that
are handled by VIDEOPRT only (and not by the miniports).
- VIDEOPRT doesn't require IRP_MJ_INTERNAL_DEVICE_CONTROL (unused).
- Implement IOCTL_VIDEO_PREPARE_FOR_EARECOVERY that just resets the
display to standard VGA 80x25 text mode.
2019-11-26 01:49:35 +00:00
|
|
|
if (*CallingProcess != CsrProcess)
|
2013-11-13 21:32:16 +00:00
|
|
|
{
|
|
|
|
KeUnstackDetachProcess(ApcState);
|
|
|
|
}
|
2005-05-08 02:16:32 +00:00
|
|
|
}
|
2004-03-19 20:58:32 +00:00
|
|
|
|
2019-12-24 12:51:20 +00:00
|
|
|
VOID
|
|
|
|
FASTCALL
|
|
|
|
IntLoadRegistryParameters(VOID)
|
|
|
|
{
|
|
|
|
NTSTATUS Status;
|
|
|
|
HANDLE KeyHandle;
|
2022-01-23 20:11:59 +00:00
|
|
|
UNICODE_STRING UseNewKeyPath = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\GraphicsDrivers\\UseNewKey");
|
2022-01-24 17:55:26 +00:00
|
|
|
UNICODE_STRING Path = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\System\\CurrentControlSet\\Control");
|
2019-12-24 12:51:20 +00:00
|
|
|
UNICODE_STRING ValueName = RTL_CONSTANT_STRING(L"SystemStartOptions");
|
|
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
|
|
PKEY_VALUE_PARTIAL_INFORMATION KeyInfo;
|
|
|
|
ULONG Length, NewLength;
|
|
|
|
|
2022-01-23 20:11:59 +00:00
|
|
|
/* Check if we need to use new registry */
|
|
|
|
InitializeObjectAttributes(&ObjectAttributes,
|
|
|
|
&UseNewKeyPath,
|
|
|
|
OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
|
|
|
|
NULL,
|
|
|
|
NULL);
|
|
|
|
Status = ZwOpenKey(&KeyHandle,
|
|
|
|
GENERIC_READ | GENERIC_WRITE,
|
|
|
|
&ObjectAttributes);
|
|
|
|
if (NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
VideoPortUseNewKey = TRUE;
|
|
|
|
ZwClose(KeyHandle);
|
|
|
|
}
|
|
|
|
|
2019-12-24 12:51:20 +00:00
|
|
|
/* Initialize object attributes with the path we want */
|
|
|
|
InitializeObjectAttributes(&ObjectAttributes,
|
|
|
|
&Path,
|
|
|
|
OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
|
|
|
|
NULL,
|
|
|
|
NULL);
|
|
|
|
|
|
|
|
/* Open the key */
|
|
|
|
Status = ZwOpenKey(&KeyHandle,
|
|
|
|
KEY_QUERY_VALUE,
|
|
|
|
&ObjectAttributes);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
VideoPortDebugPrint(Error, "ZwOpenKey failed (0x%x)\n", Status);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Find out how large our buffer should be */
|
|
|
|
Status = ZwQueryValueKey(KeyHandle,
|
|
|
|
&ValueName,
|
|
|
|
KeyValuePartialInformation,
|
|
|
|
NULL,
|
|
|
|
0,
|
|
|
|
&Length);
|
|
|
|
if (Status != STATUS_BUFFER_OVERFLOW && Status != STATUS_BUFFER_TOO_SMALL)
|
|
|
|
{
|
|
|
|
VideoPortDebugPrint(Error, "ZwQueryValueKey failed (0x%x)\n", Status);
|
|
|
|
ObCloseHandle(KeyHandle, KernelMode);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Allocate it */
|
|
|
|
KeyInfo = ExAllocatePoolWithTag(PagedPool, Length, TAG_VIDEO_PORT);
|
|
|
|
if (!KeyInfo)
|
|
|
|
{
|
|
|
|
VideoPortDebugPrint(Error, "Out of memory\n");
|
|
|
|
ObCloseHandle(KeyHandle, KernelMode);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Now for real this time */
|
|
|
|
Status = ZwQueryValueKey(KeyHandle,
|
|
|
|
&ValueName,
|
|
|
|
KeyValuePartialInformation,
|
|
|
|
KeyInfo,
|
|
|
|
Length,
|
|
|
|
&NewLength);
|
|
|
|
ObCloseHandle(KeyHandle, KernelMode);
|
|
|
|
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
VideoPortDebugPrint(Error, "ZwQueryValueKey failed (0x%x)\n", Status);
|
|
|
|
ExFreePoolWithTag(KeyInfo, TAG_VIDEO_PORT);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Sanity check */
|
|
|
|
if (KeyInfo->Type != REG_SZ)
|
|
|
|
{
|
|
|
|
VideoPortDebugPrint(Error, "Invalid type for SystemStartOptions\n");
|
|
|
|
ExFreePoolWithTag(KeyInfo, TAG_VIDEO_PORT);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Check if BASEVIDEO or NOVESA is present in the start options */
|
|
|
|
if (wcsstr((PWCHAR)KeyInfo->Data, L"BASEVIDEO"))
|
|
|
|
VpBaseVideo = TRUE;
|
|
|
|
if (wcsstr((PWCHAR)KeyInfo->Data, L"NOVESA"))
|
|
|
|
VpNoVesa = TRUE;
|
|
|
|
|
|
|
|
ExFreePoolWithTag(KeyInfo, TAG_VIDEO_PORT);
|
|
|
|
|
|
|
|
/* FIXME: Old ReactOS-compatibility... */
|
|
|
|
if (VpBaseVideo) VpNoVesa = TRUE;
|
|
|
|
|
|
|
|
if (VpNoVesa)
|
|
|
|
VideoPortDebugPrint(Info, "VESA mode disabled\n");
|
|
|
|
else
|
|
|
|
VideoPortDebugPrint(Info, "VESA mode enabled\n");
|
|
|
|
|
|
|
|
/* If we are in BASEVIDEO, create the volatile registry key for Win32k */
|
|
|
|
if (VpBaseVideo)
|
|
|
|
{
|
|
|
|
RtlInitUnicodeString(&Path, L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\GraphicsDrivers\\BaseVideo");
|
|
|
|
|
|
|
|
InitializeObjectAttributes(&ObjectAttributes,
|
|
|
|
&Path,
|
|
|
|
OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
|
|
|
|
NULL,
|
|
|
|
NULL);
|
|
|
|
|
|
|
|
Status = ZwCreateKey(&KeyHandle,
|
2022-01-06 01:04:09 +00:00
|
|
|
READ_CONTROL, // Non-0 placeholder: no use for this handle.
|
2019-12-24 12:51:20 +00:00
|
|
|
&ObjectAttributes,
|
|
|
|
0,
|
|
|
|
NULL,
|
|
|
|
REG_OPTION_VOLATILE,
|
|
|
|
NULL);
|
|
|
|
if (NT_SUCCESS(Status))
|
|
|
|
ObCloseHandle(KeyHandle, KernelMode);
|
|
|
|
else
|
|
|
|
ERR_(VIDEOPRT, "Failed to create the BaseVideo key (0x%x)\n", Status);
|
|
|
|
}
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2004-03-19 20:58:32 +00:00
|
|
|
/* PUBLIC FUNCTIONS ***********************************************************/
|
2003-07-10 21:12:40 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* @implemented
|
|
|
|
*/
|
2013-11-13 21:32:16 +00:00
|
|
|
ULONG
|
|
|
|
NTAPI
|
2004-03-19 20:58:32 +00:00
|
|
|
VideoPortInitialize(
|
2013-11-13 21:32:16 +00:00
|
|
|
IN PVOID Context1,
|
|
|
|
IN PVOID Context2,
|
|
|
|
IN PVIDEO_HW_INITIALIZATION_DATA HwInitializationData,
|
|
|
|
IN PVOID HwContext)
|
2003-02-15 19:16:34 +00:00
|
|
|
{
|
2013-11-13 21:32:16 +00:00
|
|
|
PDRIVER_OBJECT DriverObject = Context1;
|
|
|
|
PUNICODE_STRING RegistryPath = Context2;
|
|
|
|
NTSTATUS Status;
|
|
|
|
PVIDEO_PORT_DRIVER_EXTENSION DriverExtension;
|
|
|
|
BOOLEAN PnpDriver = FALSE, LegacyDetection = FALSE;
|
2019-12-03 01:08:34 +00:00
|
|
|
static BOOLEAN FirstInitialization;
|
2013-11-13 21:32:16 +00:00
|
|
|
|
|
|
|
TRACE_(VIDEOPRT, "VideoPortInitialize\n");
|
|
|
|
|
2019-12-03 01:08:34 +00:00
|
|
|
if (!FirstInitialization)
|
2017-05-18 21:29:24 +00:00
|
|
|
{
|
2019-12-24 12:51:20 +00:00
|
|
|
FirstInitialization = TRUE;
|
2017-05-18 21:29:24 +00:00
|
|
|
KeInitializeMutex(&VideoPortInt10Mutex, 0);
|
2019-12-03 01:08:34 +00:00
|
|
|
KeInitializeSpinLock(&HwResetAdaptersLock);
|
2019-12-24 12:51:20 +00:00
|
|
|
IntLoadRegistryParameters();
|
2017-05-18 21:29:24 +00:00
|
|
|
}
|
|
|
|
|
2013-11-13 21:32:16 +00:00
|
|
|
/* As a first thing do parameter checks. */
|
|
|
|
if (HwInitializationData->HwInitDataSize > sizeof(VIDEO_HW_INITIALIZATION_DATA))
|
|
|
|
{
|
|
|
|
ERR_(VIDEOPRT, "Invalid HwInitializationData\n");
|
|
|
|
return STATUS_REVISION_MISMATCH;
|
|
|
|
}
|
|
|
|
|
2013-11-16 18:40:24 +00:00
|
|
|
if ((HwInitializationData->HwFindAdapter == NULL) ||
|
|
|
|
(HwInitializationData->HwInitialize == NULL) ||
|
|
|
|
(HwInitializationData->HwStartIO == NULL))
|
2013-11-13 21:32:16 +00:00
|
|
|
{
|
|
|
|
ERR_(VIDEOPRT, "Invalid HwInitializationData\n");
|
|
|
|
return STATUS_INVALID_PARAMETER;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (HwInitializationData->HwInitDataSize)
|
|
|
|
{
|
2023-06-07 20:53:10 +00:00
|
|
|
/*
|
|
|
|
* NT4 drivers are special case, because we must use legacy method
|
|
|
|
* of detection instead of the Plug & Play one.
|
|
|
|
*/
|
2013-11-13 21:32:16 +00:00
|
|
|
case SIZE_OF_NT4_VIDEO_HW_INITIALIZATION_DATA:
|
|
|
|
INFO_(VIDEOPRT, "We were loaded by a Windows NT miniport driver.\n");
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SIZE_OF_W2K_VIDEO_HW_INITIALIZATION_DATA:
|
|
|
|
INFO_(VIDEOPRT, "We were loaded by a Windows 2000 miniport driver.\n");
|
|
|
|
break;
|
|
|
|
|
|
|
|
case sizeof(VIDEO_HW_INITIALIZATION_DATA):
|
|
|
|
INFO_(VIDEOPRT, "We were loaded by a Windows XP or later miniport driver.\n");
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
ERR_(VIDEOPRT, "Invalid HwInitializationData size.\n");
|
|
|
|
return STATUS_UNSUCCESSFUL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Set dispatching routines */
|
|
|
|
DriverObject->MajorFunction[IRP_MJ_CREATE] = IntVideoPortDispatchOpen;
|
|
|
|
DriverObject->MajorFunction[IRP_MJ_CLOSE] = IntVideoPortDispatchClose;
|
|
|
|
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] =
|
|
|
|
IntVideoPortDispatchDeviceControl;
|
[WIN32K][VIDEOPRT] Improve initialization and interfacing with INBV.
CORE-12149
VIDEOPRT:
=========
Improve interfacing with INBV, so as to detect when an external module
acquired INBV display ownership, and whether ownership is being released
later on. (This does NOT rely on hooking!)
For this purpose we improve the IntVideoPortResetDisplayParameters(Ex)
callback that gets registered with an InbvNotifyDisplayOwnershipLost()
call during initialization, and we add a monitoring thread.
The callback is called whenever an external module calls
InbvAcquireDisplayOwnership(), for example the bugcheck code or the KDBG
debugger in SCREEN mode. When this happens, a flag that tells the
monitoring thread to start monitoring INBV is set (ReactOS-specific),
and the display adapters get reset with HwResetHw() (as done on Windows).
Due to the fact that this INBV callback can be called at *ANY* IRQL, we
cannot use dispatcher synchronization mechanisms such as events to tell
the INBV monitoring thread to start its operations, so we need to rely
instead on a flag to be set. And, since INBV doesn't provide with any
proper callback/notification system either, we need to actively monitor
its state by pooling. To reduce the load on the system the monitoring
thread performs 1-second waits between each check for the flag set by
the INBV callback, and during checking the INBV ownership status.
When the INBV ownership is detected to be released by an external module,
the INBV callback is re-registered (this is *MANDATORY* since the
external module has called InbvNotifyDisplayOwnershipLost() with a
different callback parameter!), and then we callout to Win32k for
re-enabling the display.
This has the virtue of correctly resetting the display once the KDBG
debugger in SCREEN mode is being exited, and fixes CORE-12149 .
The following additional fixes were needed:
VIDEOPRT & WIN32K:
==================
Remove the registration with INBV that was previously done in a ReactOS-
specific hacked IRP_MJ_WRITE call; it is now done correctly during the
video device opening done by EngpRegisterGraphicsDevice() in the VIDEOPRT's
IRP_MJ_CREATE handler, as done on Windows.
WIN32K:
=======
- Stub the VideoPortCallout() support, for VIDEOPRT -> WIN32 callbacks.
This function gets registered with VIDEOPRT through an
IOCTL_VIDEO_INIT_WIN32K_CALLBACKS call in EngpRegisterGraphicsDevice().
- Only partially implement the 'VideoFindAdapterCallout' case, that just
re-enables the primary display by refreshing it (using the new function
UserRefreshDisplay()).
VIDEOPRT:
=========
- PVIDEO_WIN32K_CALLOUT is an NTAPI (stdcall) callback.
- In the IntVideoPortResetDisplayParameters(Ex) callback, reset all the
"resettable" adapters registered in the HwResetAdaptersList list.
We thus get rid of the global ResetDisplayParametersDeviceExtension.
- Make the IntVideoPortResetDisplayParameters(Ex) callback slightly more
robust (using SEH) against potential HwResetListEntry list corruption
or invalid DriverExtension->InitializationData.HwResetHw() that would
otherwise trigger a BSOD, and this would be disastrous since that
callback is precisely called when INBV is acquired, typically when the
BSOD code initializes the display for displaying its information...
Extras:
- Validate the IrpStack->MajorFunction in IntVideoPortDispatchDeviceControl()
and implement IRP_MJ_SHUTDOWN handling. Stub out the other IOCTLs that
are handled by VIDEOPRT only (and not by the miniports).
- VIDEOPRT doesn't require IRP_MJ_INTERNAL_DEVICE_CONTROL (unused).
- Implement IOCTL_VIDEO_PREPARE_FOR_EARECOVERY that just resets the
display to standard VGA 80x25 text mode.
2019-11-26 01:49:35 +00:00
|
|
|
DriverObject->MajorFunction[IRP_MJ_SHUTDOWN] =
|
2013-11-13 21:32:16 +00:00
|
|
|
IntVideoPortDispatchDeviceControl;
|
|
|
|
DriverObject->DriverUnload = IntVideoPortUnload;
|
|
|
|
|
|
|
|
/* Determine type of the miniport driver */
|
|
|
|
if ((HwInitializationData->HwInitDataSize >=
|
2013-11-16 18:40:24 +00:00
|
|
|
FIELD_OFFSET(VIDEO_HW_INITIALIZATION_DATA, HwQueryInterface)) &&
|
|
|
|
(HwInitializationData->HwSetPowerState != NULL) &&
|
|
|
|
(HwInitializationData->HwGetPowerState != NULL) &&
|
|
|
|
(HwInitializationData->HwGetVideoChildDescriptor != NULL))
|
2013-11-13 21:32:16 +00:00
|
|
|
{
|
|
|
|
INFO_(VIDEOPRT, "The miniport is a PnP miniport driver\n");
|
|
|
|
PnpDriver = TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Check if legacy detection should be applied */
|
|
|
|
if (!PnpDriver || HwContext)
|
|
|
|
{
|
|
|
|
INFO_(VIDEOPRT, "Legacy detection for adapter interface %d\n",
|
|
|
|
HwInitializationData->AdapterInterfaceType);
|
|
|
|
|
|
|
|
/* FIXME: Move the code for legacy detection
|
|
|
|
to another function and call it here */
|
|
|
|
LegacyDetection = TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* NOTE:
|
|
|
|
* The driver extension can be already allocated in case that we were
|
|
|
|
* called by legacy driver and failed detecting device. Some miniport
|
|
|
|
* drivers in that case adjust parameters and call VideoPortInitialize
|
|
|
|
* again.
|
|
|
|
*/
|
|
|
|
DriverExtension = IoGetDriverObjectExtension(DriverObject, DriverObject);
|
|
|
|
if (DriverExtension == NULL)
|
|
|
|
{
|
2013-11-16 18:40:24 +00:00
|
|
|
Status = IoAllocateDriverObjectExtension(DriverObject,
|
|
|
|
DriverObject,
|
|
|
|
sizeof(VIDEO_PORT_DRIVER_EXTENSION),
|
|
|
|
(PVOID *)&DriverExtension);
|
2013-11-13 21:32:16 +00:00
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
ERR_(VIDEOPRT, "IoAllocateDriverObjectExtension failed 0x%x\n", Status);
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Save the registry path. This should be done only once even if
|
|
|
|
* VideoPortInitialize is called multiple times.
|
|
|
|
*/
|
|
|
|
if (RegistryPath->Length != 0)
|
|
|
|
{
|
|
|
|
DriverExtension->RegistryPath.Length = 0;
|
|
|
|
DriverExtension->RegistryPath.MaximumLength =
|
|
|
|
RegistryPath->Length + sizeof(UNICODE_NULL);
|
|
|
|
DriverExtension->RegistryPath.Buffer =
|
|
|
|
ExAllocatePoolWithTag(
|
|
|
|
PagedPool,
|
|
|
|
DriverExtension->RegistryPath.MaximumLength,
|
|
|
|
'RTSU');
|
|
|
|
if (DriverExtension->RegistryPath.Buffer == NULL)
|
|
|
|
{
|
|
|
|
RtlInitUnicodeString(&DriverExtension->RegistryPath, NULL);
|
|
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
}
|
|
|
|
|
|
|
|
RtlCopyUnicodeString(&DriverExtension->RegistryPath, RegistryPath);
|
2022-01-24 17:55:26 +00:00
|
|
|
|
|
|
|
/* There is a bug in Spice guest agent, which searches 'System' case-sensitively.
|
|
|
|
* Replace 'SYSTEM' by 'System' to fix that.
|
|
|
|
* Probably for similar reason, Windows also replaces 'MACHINE' by 'Machine'.
|
|
|
|
*/
|
|
|
|
wcsncpy(wcsstr(DriverExtension->RegistryPath.Buffer, L"\\SYSTEM\\"), L"\\System\\", ARRAYSIZE(L"\\SYSTEM\\") - 1);
|
|
|
|
wcsncpy(wcsstr(DriverExtension->RegistryPath.Buffer, L"\\MACHINE\\"), L"\\Machine\\", ARRAYSIZE(L"\\MACHINE\\") - 1);
|
|
|
|
|
2013-11-13 21:32:16 +00:00
|
|
|
INFO_(VIDEOPRT, "RegistryPath: %wZ\n", &DriverExtension->RegistryPath);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2005-08-24 21:29:24 +00:00
|
|
|
RtlInitUnicodeString(&DriverExtension->RegistryPath, NULL);
|
2013-11-13 21:32:16 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-11-16 18:40:24 +00:00
|
|
|
/* Copy the correct miniport initialization data to the device extension. */
|
2013-11-13 21:32:16 +00:00
|
|
|
RtlCopyMemory(&DriverExtension->InitializationData,
|
|
|
|
HwInitializationData,
|
|
|
|
HwInitializationData->HwInitDataSize);
|
|
|
|
if (HwInitializationData->HwInitDataSize <
|
|
|
|
sizeof(VIDEO_HW_INITIALIZATION_DATA))
|
|
|
|
{
|
|
|
|
RtlZeroMemory((PVOID)((ULONG_PTR)&DriverExtension->InitializationData +
|
|
|
|
HwInitializationData->HwInitDataSize),
|
|
|
|
sizeof(VIDEO_HW_INITIALIZATION_DATA) -
|
|
|
|
HwInitializationData->HwInitDataSize);
|
|
|
|
}
|
|
|
|
DriverExtension->HwContext = HwContext;
|
|
|
|
|
|
|
|
/*
|
[WIN32K][VIDEOPRT] Improve initialization and interfacing with INBV.
CORE-12149
VIDEOPRT:
=========
Improve interfacing with INBV, so as to detect when an external module
acquired INBV display ownership, and whether ownership is being released
later on. (This does NOT rely on hooking!)
For this purpose we improve the IntVideoPortResetDisplayParameters(Ex)
callback that gets registered with an InbvNotifyDisplayOwnershipLost()
call during initialization, and we add a monitoring thread.
The callback is called whenever an external module calls
InbvAcquireDisplayOwnership(), for example the bugcheck code or the KDBG
debugger in SCREEN mode. When this happens, a flag that tells the
monitoring thread to start monitoring INBV is set (ReactOS-specific),
and the display adapters get reset with HwResetHw() (as done on Windows).
Due to the fact that this INBV callback can be called at *ANY* IRQL, we
cannot use dispatcher synchronization mechanisms such as events to tell
the INBV monitoring thread to start its operations, so we need to rely
instead on a flag to be set. And, since INBV doesn't provide with any
proper callback/notification system either, we need to actively monitor
its state by pooling. To reduce the load on the system the monitoring
thread performs 1-second waits between each check for the flag set by
the INBV callback, and during checking the INBV ownership status.
When the INBV ownership is detected to be released by an external module,
the INBV callback is re-registered (this is *MANDATORY* since the
external module has called InbvNotifyDisplayOwnershipLost() with a
different callback parameter!), and then we callout to Win32k for
re-enabling the display.
This has the virtue of correctly resetting the display once the KDBG
debugger in SCREEN mode is being exited, and fixes CORE-12149 .
The following additional fixes were needed:
VIDEOPRT & WIN32K:
==================
Remove the registration with INBV that was previously done in a ReactOS-
specific hacked IRP_MJ_WRITE call; it is now done correctly during the
video device opening done by EngpRegisterGraphicsDevice() in the VIDEOPRT's
IRP_MJ_CREATE handler, as done on Windows.
WIN32K:
=======
- Stub the VideoPortCallout() support, for VIDEOPRT -> WIN32 callbacks.
This function gets registered with VIDEOPRT through an
IOCTL_VIDEO_INIT_WIN32K_CALLBACKS call in EngpRegisterGraphicsDevice().
- Only partially implement the 'VideoFindAdapterCallout' case, that just
re-enables the primary display by refreshing it (using the new function
UserRefreshDisplay()).
VIDEOPRT:
=========
- PVIDEO_WIN32K_CALLOUT is an NTAPI (stdcall) callback.
- In the IntVideoPortResetDisplayParameters(Ex) callback, reset all the
"resettable" adapters registered in the HwResetAdaptersList list.
We thus get rid of the global ResetDisplayParametersDeviceExtension.
- Make the IntVideoPortResetDisplayParameters(Ex) callback slightly more
robust (using SEH) against potential HwResetListEntry list corruption
or invalid DriverExtension->InitializationData.HwResetHw() that would
otherwise trigger a BSOD, and this would be disastrous since that
callback is precisely called when INBV is acquired, typically when the
BSOD code initializes the display for displaying its information...
Extras:
- Validate the IrpStack->MajorFunction in IntVideoPortDispatchDeviceControl()
and implement IRP_MJ_SHUTDOWN handling. Stub out the other IOCTLs that
are handled by VIDEOPRT only (and not by the miniports).
- VIDEOPRT doesn't require IRP_MJ_INTERNAL_DEVICE_CONTROL (unused).
- Implement IOCTL_VIDEO_PREPARE_FOR_EARECOVERY that just resets the
display to standard VGA 80x25 text mode.
2019-11-26 01:49:35 +00:00
|
|
|
* Plug & Play drivers registers the device in AddDevice routine.
|
|
|
|
* For legacy drivers we must do it now.
|
2013-11-13 21:32:16 +00:00
|
|
|
*/
|
|
|
|
if (LegacyDetection)
|
|
|
|
{
|
|
|
|
PDEVICE_OBJECT DeviceObject;
|
|
|
|
|
|
|
|
if (HwInitializationData->HwInitDataSize != SIZE_OF_NT4_VIDEO_HW_INITIALIZATION_DATA)
|
|
|
|
{
|
[WIN32K][VIDEOPRT] Improve initialization and interfacing with INBV.
CORE-12149
VIDEOPRT:
=========
Improve interfacing with INBV, so as to detect when an external module
acquired INBV display ownership, and whether ownership is being released
later on. (This does NOT rely on hooking!)
For this purpose we improve the IntVideoPortResetDisplayParameters(Ex)
callback that gets registered with an InbvNotifyDisplayOwnershipLost()
call during initialization, and we add a monitoring thread.
The callback is called whenever an external module calls
InbvAcquireDisplayOwnership(), for example the bugcheck code or the KDBG
debugger in SCREEN mode. When this happens, a flag that tells the
monitoring thread to start monitoring INBV is set (ReactOS-specific),
and the display adapters get reset with HwResetHw() (as done on Windows).
Due to the fact that this INBV callback can be called at *ANY* IRQL, we
cannot use dispatcher synchronization mechanisms such as events to tell
the INBV monitoring thread to start its operations, so we need to rely
instead on a flag to be set. And, since INBV doesn't provide with any
proper callback/notification system either, we need to actively monitor
its state by pooling. To reduce the load on the system the monitoring
thread performs 1-second waits between each check for the flag set by
the INBV callback, and during checking the INBV ownership status.
When the INBV ownership is detected to be released by an external module,
the INBV callback is re-registered (this is *MANDATORY* since the
external module has called InbvNotifyDisplayOwnershipLost() with a
different callback parameter!), and then we callout to Win32k for
re-enabling the display.
This has the virtue of correctly resetting the display once the KDBG
debugger in SCREEN mode is being exited, and fixes CORE-12149 .
The following additional fixes were needed:
VIDEOPRT & WIN32K:
==================
Remove the registration with INBV that was previously done in a ReactOS-
specific hacked IRP_MJ_WRITE call; it is now done correctly during the
video device opening done by EngpRegisterGraphicsDevice() in the VIDEOPRT's
IRP_MJ_CREATE handler, as done on Windows.
WIN32K:
=======
- Stub the VideoPortCallout() support, for VIDEOPRT -> WIN32 callbacks.
This function gets registered with VIDEOPRT through an
IOCTL_VIDEO_INIT_WIN32K_CALLBACKS call in EngpRegisterGraphicsDevice().
- Only partially implement the 'VideoFindAdapterCallout' case, that just
re-enables the primary display by refreshing it (using the new function
UserRefreshDisplay()).
VIDEOPRT:
=========
- PVIDEO_WIN32K_CALLOUT is an NTAPI (stdcall) callback.
- In the IntVideoPortResetDisplayParameters(Ex) callback, reset all the
"resettable" adapters registered in the HwResetAdaptersList list.
We thus get rid of the global ResetDisplayParametersDeviceExtension.
- Make the IntVideoPortResetDisplayParameters(Ex) callback slightly more
robust (using SEH) against potential HwResetListEntry list corruption
or invalid DriverExtension->InitializationData.HwResetHw() that would
otherwise trigger a BSOD, and this would be disastrous since that
callback is precisely called when INBV is acquired, typically when the
BSOD code initializes the display for displaying its information...
Extras:
- Validate the IrpStack->MajorFunction in IntVideoPortDispatchDeviceControl()
and implement IRP_MJ_SHUTDOWN handling. Stub out the other IOCTLs that
are handled by VIDEOPRT only (and not by the miniports).
- VIDEOPRT doesn't require IRP_MJ_INTERNAL_DEVICE_CONTROL (unused).
- Implement IOCTL_VIDEO_PREPARE_FOR_EARECOVERY that just resets the
display to standard VGA 80x25 text mode.
2019-11-26 01:49:35 +00:00
|
|
|
/* Power management */
|
2013-11-13 21:32:16 +00:00
|
|
|
DriverObject->MajorFunction[IRP_MJ_POWER] = IntVideoPortDispatchPower;
|
|
|
|
}
|
2013-11-16 18:40:24 +00:00
|
|
|
|
2013-11-13 21:32:16 +00:00
|
|
|
Status = IntVideoPortCreateAdapterDeviceObject(DriverObject,
|
|
|
|
DriverExtension,
|
|
|
|
NULL,
|
2021-07-03 20:59:30 +00:00
|
|
|
DriverExtension->InitializationData.StartingDeviceNumber,
|
|
|
|
0,
|
2013-11-13 21:32:16 +00:00
|
|
|
&DeviceObject);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
ERR_(VIDEOPRT, "IntVideoPortCreateAdapterDeviceObject returned 0x%x\n", Status);
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
|
|
|
Status = IntVideoPortFindAdapter(DriverObject, DriverExtension, DeviceObject);
|
2021-07-03 19:26:57 +00:00
|
|
|
if (!NT_SUCCESS(Status))
|
2013-11-13 21:32:16 +00:00
|
|
|
ERR_(VIDEOPRT, "IntVideoPortFindAdapter returned 0x%x\n", Status);
|
|
|
|
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
DriverObject->DriverExtension->AddDevice = IntVideoPortAddDevice;
|
|
|
|
DriverObject->MajorFunction[IRP_MJ_PNP] = IntVideoPortDispatchPnp;
|
|
|
|
DriverObject->MajorFunction[IRP_MJ_POWER] = IntVideoPortDispatchPower;
|
|
|
|
DriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = IntVideoPortDispatchSystemControl;
|
|
|
|
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
}
|
2003-02-15 19:16:34 +00:00
|
|
|
}
|
|
|
|
|
2003-07-10 21:12:40 +00:00
|
|
|
/*
|
|
|
|
* @implemented
|
|
|
|
*/
|
2004-03-19 20:58:32 +00:00
|
|
|
VOID
|
|
|
|
VideoPortDebugPrint(
|
2013-11-13 21:32:16 +00:00
|
|
|
IN VIDEO_DEBUG_LEVEL DebugPrintLevel,
|
|
|
|
IN PCHAR DebugMessage,
|
|
|
|
...)
|
2003-02-15 19:16:34 +00:00
|
|
|
{
|
2013-11-13 21:32:16 +00:00
|
|
|
va_list ap;
|
2003-02-25 23:08:54 +00:00
|
|
|
|
2020-09-15 12:24:42 +00:00
|
|
|
if (VideoDebugLevel >= DebugPrintLevel)
|
|
|
|
DebugPrintLevel = Error;
|
|
|
|
|
2013-11-13 21:32:16 +00:00
|
|
|
va_start(ap, DebugMessage);
|
|
|
|
vDbgPrintEx(DPFLTR_IHVVIDEO_ID, DebugPrintLevel, DebugMessage, ap);
|
|
|
|
va_end(ap);
|
2003-02-15 19:16:34 +00:00
|
|
|
}
|
|
|
|
|
2003-07-10 21:12:40 +00:00
|
|
|
/*
|
|
|
|
* @unimplemented
|
|
|
|
*/
|
2013-11-13 21:32:16 +00:00
|
|
|
VOID
|
|
|
|
NTAPI
|
2004-03-19 20:58:32 +00:00
|
|
|
VideoPortLogError(
|
2013-11-13 21:32:16 +00:00
|
|
|
IN PVOID HwDeviceExtension,
|
|
|
|
IN PVIDEO_REQUEST_PACKET Vrp OPTIONAL,
|
|
|
|
IN VP_STATUS ErrorCode,
|
|
|
|
IN ULONG UniqueId)
|
2003-02-15 19:16:34 +00:00
|
|
|
{
|
2007-12-28 14:47:03 +00:00
|
|
|
UNIMPLEMENTED;
|
|
|
|
|
|
|
|
INFO_(VIDEOPRT, "VideoPortLogError ErrorCode %d (0x%x) UniqueId %lu (0x%lx)\n",
|
|
|
|
ErrorCode, ErrorCode, UniqueId, UniqueId);
|
|
|
|
if (Vrp)
|
|
|
|
INFO_(VIDEOPRT, "Vrp->IoControlCode %lu (0x%lx)\n", Vrp->IoControlCode, Vrp->IoControlCode);
|
2003-02-15 19:16:34 +00:00
|
|
|
}
|
|
|
|
|
2003-07-10 21:12:40 +00:00
|
|
|
/*
|
|
|
|
* @implemented
|
|
|
|
*/
|
2013-11-13 21:32:16 +00:00
|
|
|
UCHAR
|
|
|
|
NTAPI
|
2004-03-19 20:58:32 +00:00
|
|
|
VideoPortGetCurrentIrql(VOID)
|
|
|
|
{
|
2013-11-13 21:32:16 +00:00
|
|
|
return KeGetCurrentIrql();
|
2003-02-15 19:16:34 +00:00
|
|
|
}
|
|
|
|
|
2004-03-19 20:58:32 +00:00
|
|
|
typedef struct QueryRegistryCallbackContext
|
|
|
|
{
|
2013-11-13 21:32:16 +00:00
|
|
|
PVOID HwDeviceExtension;
|
|
|
|
PVOID HwContext;
|
|
|
|
PMINIPORT_GET_REGISTRY_ROUTINE HwGetRegistryRoutine;
|
2004-03-19 20:58:32 +00:00
|
|
|
} QUERY_REGISTRY_CALLBACK_CONTEXT, *PQUERY_REGISTRY_CALLBACK_CONTEXT;
|
2003-07-10 21:12:40 +00:00
|
|
|
|
2013-11-13 21:32:16 +00:00
|
|
|
static
|
|
|
|
NTSTATUS
|
|
|
|
NTAPI
|
2004-03-19 20:58:32 +00:00
|
|
|
QueryRegistryCallback(
|
2013-11-13 21:32:16 +00:00
|
|
|
IN PWSTR ValueName,
|
|
|
|
IN ULONG ValueType,
|
|
|
|
IN PVOID ValueData,
|
|
|
|
IN ULONG ValueLength,
|
|
|
|
IN PVOID Context,
|
|
|
|
IN PVOID EntryContext)
|
2003-02-15 19:16:34 +00:00
|
|
|
{
|
2013-11-13 21:32:16 +00:00
|
|
|
PQUERY_REGISTRY_CALLBACK_CONTEXT CallbackContext = (PQUERY_REGISTRY_CALLBACK_CONTEXT) Context;
|
2004-03-19 20:58:32 +00:00
|
|
|
|
2013-11-13 21:32:16 +00:00
|
|
|
INFO_(VIDEOPRT, "Found registry value for name %S: type %d, length %d\n",
|
2004-03-19 20:58:32 +00:00
|
|
|
ValueName, ValueType, ValueLength);
|
2013-11-13 21:32:16 +00:00
|
|
|
return (*(CallbackContext->HwGetRegistryRoutine))(
|
|
|
|
CallbackContext->HwDeviceExtension,
|
|
|
|
CallbackContext->HwContext,
|
|
|
|
ValueName,
|
|
|
|
ValueData,
|
|
|
|
ValueLength);
|
2003-02-15 19:16:34 +00:00
|
|
|
}
|
|
|
|
|
2003-07-10 21:12:40 +00:00
|
|
|
/*
|
2004-03-19 20:58:32 +00:00
|
|
|
* @unimplemented
|
2003-07-10 21:12:40 +00:00
|
|
|
*/
|
2004-03-19 20:58:32 +00:00
|
|
|
|
2013-11-13 21:32:16 +00:00
|
|
|
VP_STATUS
|
|
|
|
NTAPI
|
2004-03-19 20:58:32 +00:00
|
|
|
VideoPortGetRegistryParameters(
|
2013-11-13 21:32:16 +00:00
|
|
|
IN PVOID HwDeviceExtension,
|
|
|
|
IN PWSTR ParameterName,
|
|
|
|
IN UCHAR IsParameterFileName,
|
|
|
|
IN PMINIPORT_GET_REGISTRY_ROUTINE GetRegistryRoutine,
|
|
|
|
IN PVOID HwContext)
|
2003-02-15 19:16:34 +00:00
|
|
|
{
|
2013-11-13 21:32:16 +00:00
|
|
|
RTL_QUERY_REGISTRY_TABLE QueryTable[2] = {{0}};
|
|
|
|
QUERY_REGISTRY_CALLBACK_CONTEXT Context;
|
|
|
|
PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension;
|
|
|
|
NTSTATUS Status;
|
|
|
|
|
|
|
|
DeviceExtension = VIDEO_PORT_GET_DEVICE_EXTENSION(HwDeviceExtension);
|
|
|
|
|
|
|
|
TRACE_(VIDEOPRT, "VideoPortGetRegistryParameters ParameterName %S, RegPath: %wZ\n",
|
|
|
|
ParameterName, &DeviceExtension->RegistryPath);
|
|
|
|
|
|
|
|
Context.HwDeviceExtension = HwDeviceExtension;
|
|
|
|
Context.HwContext = HwContext;
|
|
|
|
Context.HwGetRegistryRoutine = GetRegistryRoutine;
|
|
|
|
|
|
|
|
QueryTable[0].QueryRoutine = QueryRegistryCallback;
|
|
|
|
QueryTable[0].Flags = RTL_QUERY_REGISTRY_REQUIRED;
|
|
|
|
QueryTable[0].Name = ParameterName;
|
|
|
|
|
|
|
|
Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
|
|
|
|
DeviceExtension->RegistryPath.Buffer,
|
|
|
|
QueryTable,
|
|
|
|
&Context,
|
|
|
|
NULL);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
WARN_(VIDEOPRT, "VideoPortGetRegistryParameters could not find the "
|
|
|
|
"requested parameter\n");
|
|
|
|
return ERROR_INVALID_PARAMETER;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (IsParameterFileName)
|
|
|
|
{
|
|
|
|
/* FIXME: need to read the contents of the file */
|
|
|
|
UNIMPLEMENTED;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NO_ERROR;
|
2003-02-15 19:16:34 +00:00
|
|
|
}
|
|
|
|
|
2003-07-10 21:12:40 +00:00
|
|
|
/*
|
2004-03-19 20:58:32 +00:00
|
|
|
* @implemented
|
2003-07-10 21:12:40 +00:00
|
|
|
*/
|
2013-11-13 21:32:16 +00:00
|
|
|
VP_STATUS
|
|
|
|
NTAPI
|
2004-03-19 20:58:32 +00:00
|
|
|
VideoPortSetRegistryParameters(
|
2013-11-13 21:32:16 +00:00
|
|
|
IN PVOID HwDeviceExtension,
|
|
|
|
IN PWSTR ValueName,
|
|
|
|
IN PVOID ValueData,
|
|
|
|
IN ULONG ValueLength)
|
2003-06-21 14:25:30 +00:00
|
|
|
{
|
2013-11-13 21:32:16 +00:00
|
|
|
PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension;
|
|
|
|
VP_STATUS Status;
|
|
|
|
|
|
|
|
DeviceExtension = VIDEO_PORT_GET_DEVICE_EXTENSION(HwDeviceExtension);
|
|
|
|
TRACE_(VIDEOPRT, "VideoPortSetRegistryParameters ParameterName %S, RegPath: %wZ\n",
|
|
|
|
ValueName,
|
|
|
|
&DeviceExtension->RegistryPath);
|
|
|
|
ASSERT_IRQL_LESS_OR_EQUAL(PASSIVE_LEVEL);
|
|
|
|
Status = RtlWriteRegistryValue(RTL_REGISTRY_ABSOLUTE,
|
|
|
|
DeviceExtension->RegistryPath.Buffer,
|
|
|
|
ValueName,
|
|
|
|
REG_BINARY,
|
|
|
|
ValueData,
|
|
|
|
ValueLength);
|
|
|
|
if (Status != NO_ERROR)
|
|
|
|
WARN_(VIDEOPRT, "VideoPortSetRegistryParameters error 0x%x\n", Status);
|
|
|
|
|
|
|
|
return Status;
|
2003-06-21 14:25:30 +00:00
|
|
|
}
|
2003-02-15 19:16:34 +00:00
|
|
|
|
2004-01-19 15:56:53 +00:00
|
|
|
/*
|
|
|
|
* @implemented
|
2005-05-08 02:16:32 +00:00
|
|
|
*/
|
2013-11-13 21:32:16 +00:00
|
|
|
VP_STATUS
|
|
|
|
NTAPI
|
2004-03-19 20:58:32 +00:00
|
|
|
VideoPortGetVgaStatus(
|
2013-11-13 21:32:16 +00:00
|
|
|
IN PVOID HwDeviceExtension,
|
|
|
|
OUT PULONG VgaStatus)
|
2004-01-19 15:56:53 +00:00
|
|
|
{
|
2013-11-13 21:32:16 +00:00
|
|
|
PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension;
|
|
|
|
|
|
|
|
TRACE_(VIDEOPRT, "VideoPortGetVgaStatus\n");
|
|
|
|
|
|
|
|
DeviceExtension = VIDEO_PORT_GET_DEVICE_EXTENSION(HwDeviceExtension);
|
|
|
|
if (KeGetCurrentIrql() == PASSIVE_LEVEL)
|
|
|
|
{
|
|
|
|
if (DeviceExtension->AdapterInterfaceType == PCIBus)
|
|
|
|
{
|
|
|
|
/* VgaStatus: 0 == VGA not enabled, 1 == VGA enabled. */
|
|
|
|
/* Assumed for now */
|
|
|
|
*VgaStatus = 1;
|
|
|
|
return NO_ERROR;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return ERROR_INVALID_FUNCTION;
|
2004-01-19 15:56:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* @implemented
|
|
|
|
*/
|
2013-11-13 21:32:16 +00:00
|
|
|
PVOID
|
|
|
|
NTAPI
|
2004-03-19 20:58:32 +00:00
|
|
|
VideoPortGetRomImage(
|
2013-11-13 21:32:16 +00:00
|
|
|
IN PVOID HwDeviceExtension,
|
|
|
|
IN PVOID Unused1,
|
|
|
|
IN ULONG Unused2,
|
|
|
|
IN ULONG Length)
|
2004-01-19 15:56:53 +00:00
|
|
|
{
|
2013-11-13 21:32:16 +00:00
|
|
|
static PVOID RomImageBuffer = NULL;
|
|
|
|
PKPROCESS CallingProcess;
|
|
|
|
KAPC_STATE ApcState;
|
|
|
|
|
|
|
|
TRACE_(VIDEOPRT, "VideoPortGetRomImage(HwDeviceExtension 0x%X Length 0x%X)\n",
|
|
|
|
HwDeviceExtension, Length);
|
|
|
|
|
|
|
|
/* If the length is zero then free the existing buffer. */
|
|
|
|
if (Length == 0)
|
|
|
|
{
|
|
|
|
if (RomImageBuffer != NULL)
|
|
|
|
{
|
|
|
|
ExFreePool(RomImageBuffer);
|
|
|
|
RomImageBuffer = NULL;
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* The DDK says we shouldn't use the legacy C0000 method but get the
|
|
|
|
* rom base address from the corresponding pci or acpi register but
|
|
|
|
* lets ignore that and use C0000 anyway. We have already mapped the
|
|
|
|
* bios area into memory so we'll copy from there.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* Copy the bios. */
|
|
|
|
Length = min(Length, 0x10000);
|
|
|
|
if (RomImageBuffer != NULL)
|
|
|
|
{
|
|
|
|
ExFreePool(RomImageBuffer);
|
|
|
|
}
|
|
|
|
|
|
|
|
RomImageBuffer = ExAllocatePool(PagedPool, Length);
|
|
|
|
if (RomImageBuffer == NULL)
|
|
|
|
{
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
IntAttachToCSRSS(&CallingProcess, &ApcState);
|
|
|
|
RtlCopyMemory(RomImageBuffer, (PUCHAR)0xC0000, Length);
|
|
|
|
IntDetachFromCSRSS(&CallingProcess, &ApcState);
|
|
|
|
|
|
|
|
return RomImageBuffer;
|
|
|
|
}
|
2004-03-19 20:58:32 +00:00
|
|
|
}
|
2003-06-21 14:25:30 +00:00
|
|
|
|
2004-03-19 20:58:32 +00:00
|
|
|
/*
|
|
|
|
* @implemented
|
|
|
|
*/
|
2013-11-13 21:32:16 +00:00
|
|
|
BOOLEAN
|
|
|
|
NTAPI
|
2004-03-19 20:58:32 +00:00
|
|
|
VideoPortScanRom(
|
2013-11-13 21:32:16 +00:00
|
|
|
IN PVOID HwDeviceExtension,
|
|
|
|
IN PUCHAR RomBase,
|
|
|
|
IN ULONG RomLength,
|
|
|
|
IN PUCHAR String)
|
2004-03-19 20:58:32 +00:00
|
|
|
{
|
2019-05-26 13:00:21 +00:00
|
|
|
SIZE_T StringLength;
|
2013-11-13 21:32:16 +00:00
|
|
|
BOOLEAN Found;
|
|
|
|
PUCHAR SearchLocation;
|
|
|
|
|
|
|
|
TRACE_(VIDEOPRT, "VideoPortScanRom RomBase %p RomLength 0x%x String %s\n", RomBase, RomLength, String);
|
|
|
|
|
|
|
|
StringLength = strlen((PCHAR)String);
|
|
|
|
Found = FALSE;
|
|
|
|
for (SearchLocation = RomBase;
|
|
|
|
!Found && SearchLocation < RomBase + RomLength - StringLength;
|
|
|
|
SearchLocation++)
|
|
|
|
{
|
|
|
|
Found = (RtlCompareMemory(SearchLocation, String, StringLength) == StringLength);
|
|
|
|
if (Found)
|
|
|
|
{
|
|
|
|
INFO_(VIDEOPRT, "Match found at %p\n", SearchLocation);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return Found;
|
2003-02-15 19:16:34 +00:00
|
|
|
}
|
|
|
|
|
2004-03-19 20:58:32 +00:00
|
|
|
/*
|
|
|
|
* @implemented
|
|
|
|
*/
|
2013-11-13 21:32:16 +00:00
|
|
|
BOOLEAN
|
|
|
|
NTAPI
|
2004-03-19 20:58:32 +00:00
|
|
|
VideoPortSynchronizeExecution(
|
2013-11-13 21:32:16 +00:00
|
|
|
IN PVOID HwDeviceExtension,
|
|
|
|
IN VIDEO_SYNCHRONIZE_PRIORITY Priority,
|
|
|
|
IN PMINIPORT_SYNCHRONIZE_ROUTINE SynchronizeRoutine,
|
|
|
|
OUT PVOID Context)
|
2003-02-15 19:16:34 +00:00
|
|
|
{
|
2013-11-13 21:32:16 +00:00
|
|
|
BOOLEAN Ret;
|
|
|
|
PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension;
|
|
|
|
KIRQL OldIrql;
|
|
|
|
|
|
|
|
switch (Priority)
|
|
|
|
{
|
|
|
|
case VpLowPriority:
|
2004-03-19 20:58:32 +00:00
|
|
|
Ret = (*SynchronizeRoutine)(Context);
|
2013-11-13 21:32:16 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case VpMediumPriority:
|
|
|
|
DeviceExtension = VIDEO_PORT_GET_DEVICE_EXTENSION(HwDeviceExtension);
|
|
|
|
if (DeviceExtension->InterruptObject == NULL)
|
|
|
|
Ret = (*SynchronizeRoutine)(Context);
|
|
|
|
else
|
|
|
|
Ret = KeSynchronizeExecution(
|
|
|
|
DeviceExtension->InterruptObject,
|
|
|
|
SynchronizeRoutine,
|
|
|
|
Context);
|
|
|
|
break;
|
2004-03-19 20:58:32 +00:00
|
|
|
|
2013-11-13 21:32:16 +00:00
|
|
|
case VpHighPriority:
|
|
|
|
OldIrql = KeGetCurrentIrql();
|
|
|
|
if (OldIrql < SYNCH_LEVEL)
|
|
|
|
KeRaiseIrql(SYNCH_LEVEL, &OldIrql);
|
2004-03-19 20:58:32 +00:00
|
|
|
|
2013-11-13 21:32:16 +00:00
|
|
|
Ret = (*SynchronizeRoutine)(Context);
|
2004-03-19 20:58:32 +00:00
|
|
|
|
2013-11-13 21:32:16 +00:00
|
|
|
if (OldIrql < SYNCH_LEVEL)
|
|
|
|
KeLowerIrql(OldIrql);
|
|
|
|
break;
|
2004-03-19 20:58:32 +00:00
|
|
|
|
2013-11-13 21:32:16 +00:00
|
|
|
default:
|
|
|
|
Ret = FALSE;
|
|
|
|
}
|
2004-03-06 01:22:04 +00:00
|
|
|
|
2013-11-13 21:32:16 +00:00
|
|
|
return Ret;
|
2003-02-25 23:08:54 +00:00
|
|
|
}
|
|
|
|
|
2004-03-19 20:58:32 +00:00
|
|
|
/*
|
2005-01-07 01:03:34 +00:00
|
|
|
* @implemented
|
2004-03-08 04:09:02 +00:00
|
|
|
*/
|
2022-01-02 20:31:29 +00:00
|
|
|
NTSTATUS NTAPI
|
|
|
|
IntVideoPortEnumerateChildren(
|
|
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
|
|
IN PIRP Irp)
|
2004-03-06 08:39:06 +00:00
|
|
|
{
|
2013-11-13 21:32:16 +00:00
|
|
|
PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension;
|
|
|
|
ULONG Status;
|
|
|
|
VIDEO_CHILD_ENUM_INFO ChildEnumInfo;
|
|
|
|
BOOLEAN bHaveLastMonitorID = FALSE;
|
|
|
|
UCHAR LastMonitorID[10];
|
|
|
|
ULONG Unused;
|
|
|
|
UINT i;
|
|
|
|
PDEVICE_OBJECT ChildDeviceObject;
|
|
|
|
PVIDEO_PORT_CHILD_EXTENSION ChildExtension;
|
|
|
|
|
|
|
|
INFO_(VIDEOPRT, "Starting child device probe\n");
|
2022-01-02 20:31:29 +00:00
|
|
|
DeviceExtension = DeviceObject->DeviceExtension;
|
2013-11-13 21:32:16 +00:00
|
|
|
if (DeviceExtension->DriverExtension->InitializationData.HwGetVideoChildDescriptor == NULL)
|
|
|
|
{
|
|
|
|
WARN_(VIDEOPRT, "Miniport's HwGetVideoChildDescriptor is NULL!\n");
|
2022-01-02 20:31:29 +00:00
|
|
|
return STATUS_SUCCESS;
|
2013-11-13 21:32:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!IsListEmpty(&DeviceExtension->ChildDeviceList))
|
|
|
|
{
|
|
|
|
ERR_(VIDEOPRT, "FIXME: Support calling VideoPortEnumerateChildren again!\n");
|
2022-01-02 20:31:29 +00:00
|
|
|
return STATUS_SUCCESS;
|
2013-11-13 21:32:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Enumerate the children */
|
|
|
|
for (i = 1; ; i++)
|
|
|
|
{
|
|
|
|
Status = IoCreateDevice(DeviceExtension->DriverObject,
|
|
|
|
sizeof(VIDEO_PORT_CHILD_EXTENSION) +
|
|
|
|
DeviceExtension->DriverExtension->InitializationData.HwChildDeviceExtensionSize,
|
|
|
|
NULL,
|
|
|
|
FILE_DEVICE_CONTROLLER,
|
|
|
|
FILE_DEVICE_SECURE_OPEN,
|
|
|
|
FALSE,
|
|
|
|
&ChildDeviceObject);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
return Status;
|
|
|
|
|
|
|
|
ChildExtension = ChildDeviceObject->DeviceExtension;
|
|
|
|
|
|
|
|
RtlZeroMemory(ChildExtension,
|
|
|
|
sizeof(VIDEO_PORT_CHILD_EXTENSION) +
|
|
|
|
DeviceExtension->DriverExtension->InitializationData.HwChildDeviceExtensionSize);
|
|
|
|
|
|
|
|
ChildExtension->Common.Fdo = FALSE;
|
|
|
|
ChildExtension->ChildId = i;
|
|
|
|
ChildExtension->PhysicalDeviceObject = ChildDeviceObject;
|
|
|
|
ChildExtension->DriverObject = DeviceExtension->DriverObject;
|
|
|
|
|
|
|
|
/* Setup the ChildEnumInfo */
|
|
|
|
ChildEnumInfo.Size = sizeof(ChildEnumInfo);
|
|
|
|
ChildEnumInfo.ChildDescriptorSize = sizeof(ChildExtension->ChildDescriptor);
|
|
|
|
ChildEnumInfo.ACPIHwId = 0;
|
|
|
|
|
|
|
|
if (DeviceExtension->DriverExtension->InitializationData.HwChildDeviceExtensionSize)
|
|
|
|
ChildEnumInfo.ChildHwDeviceExtension = VIDEO_PORT_GET_CHILD_EXTENSION(ChildExtension);
|
|
|
|
else
|
|
|
|
ChildEnumInfo.ChildHwDeviceExtension = NULL;
|
|
|
|
|
|
|
|
ChildEnumInfo.ChildIndex = ChildExtension->ChildId;
|
|
|
|
|
|
|
|
INFO_(VIDEOPRT, "Probing child: %d\n", ChildEnumInfo.ChildIndex);
|
|
|
|
Status = DeviceExtension->DriverExtension->InitializationData.HwGetVideoChildDescriptor(
|
2022-01-02 20:31:29 +00:00
|
|
|
DeviceExtension->MiniPortDeviceExtension,
|
2013-11-13 21:32:16 +00:00
|
|
|
&ChildEnumInfo,
|
|
|
|
&ChildExtension->ChildType,
|
|
|
|
ChildExtension->ChildDescriptor,
|
|
|
|
&ChildExtension->ChildId,
|
|
|
|
&Unused);
|
|
|
|
if (Status == VIDEO_ENUM_MORE_DEVICES)
|
|
|
|
{
|
|
|
|
if (ChildExtension->ChildType == Monitor)
|
2007-08-03 12:10:43 +00:00
|
|
|
{
|
2013-11-13 21:32:16 +00:00
|
|
|
// Check if the EDID is valid
|
|
|
|
if (ChildExtension->ChildDescriptor[0] == 0x00 &&
|
|
|
|
ChildExtension->ChildDescriptor[1] == 0xFF &&
|
|
|
|
ChildExtension->ChildDescriptor[2] == 0xFF &&
|
|
|
|
ChildExtension->ChildDescriptor[3] == 0xFF &&
|
|
|
|
ChildExtension->ChildDescriptor[4] == 0xFF &&
|
|
|
|
ChildExtension->ChildDescriptor[5] == 0xFF &&
|
|
|
|
ChildExtension->ChildDescriptor[6] == 0xFF &&
|
|
|
|
ChildExtension->ChildDescriptor[7] == 0x00)
|
|
|
|
{
|
|
|
|
if (bHaveLastMonitorID)
|
|
|
|
{
|
|
|
|
// Compare the previous monitor ID with the current one, break the loop if they are identical
|
|
|
|
if (RtlCompareMemory(LastMonitorID, &ChildExtension->ChildDescriptor[8], sizeof(LastMonitorID)) == sizeof(LastMonitorID))
|
|
|
|
{
|
|
|
|
INFO_(VIDEOPRT, "Found identical Monitor ID two times, stopping enumeration\n");
|
|
|
|
IoDeleteDevice(ChildDeviceObject);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Copy 10 bytes from the EDID, which can be used to uniquely identify the monitor
|
|
|
|
RtlCopyMemory(LastMonitorID, &ChildExtension->ChildDescriptor[8], sizeof(LastMonitorID));
|
|
|
|
bHaveLastMonitorID = TRUE;
|
|
|
|
|
|
|
|
/* Mark it valid */
|
|
|
|
ChildExtension->EdidValid = TRUE;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Mark it invalid */
|
|
|
|
ChildExtension->EdidValid = FALSE;
|
|
|
|
}
|
2012-03-12 03:29:36 +00:00
|
|
|
}
|
2013-11-13 21:32:16 +00:00
|
|
|
}
|
|
|
|
else if (Status == VIDEO_ENUM_INVALID_DEVICE)
|
|
|
|
{
|
|
|
|
WARN_(VIDEOPRT, "Child device %d is invalid!\n", ChildEnumInfo.ChildIndex);
|
|
|
|
IoDeleteDevice(ChildDeviceObject);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
else if (Status == VIDEO_ENUM_NO_MORE_DEVICES)
|
|
|
|
{
|
|
|
|
INFO_(VIDEOPRT, "End of child enumeration! (%d children enumerated)\n", i - 1);
|
|
|
|
IoDeleteDevice(ChildDeviceObject);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
WARN_(VIDEOPRT, "HwGetVideoChildDescriptor returned unknown status code 0x%x!\n", Status);
|
|
|
|
IoDeleteDevice(ChildDeviceObject);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ChildExtension->ChildType == Monitor)
|
|
|
|
{
|
|
|
|
UINT j;
|
|
|
|
PUCHAR p = ChildExtension->ChildDescriptor;
|
|
|
|
INFO_(VIDEOPRT, "Monitor device enumerated! (ChildId = 0x%x)\n", ChildExtension->ChildId);
|
|
|
|
for (j = 0; j < sizeof (ChildExtension->ChildDescriptor); j += 8)
|
2012-03-12 03:29:36 +00:00
|
|
|
{
|
2013-11-13 21:32:16 +00:00
|
|
|
INFO_(VIDEOPRT, "%02x %02x %02x %02x %02x %02x %02x %02x\n",
|
|
|
|
p[j + 0], p[j + 1], p[j + 2], p[j + 3],
|
|
|
|
p[j + 4], p[j + 5], p[j + 6], p[j + 7]);
|
2007-08-03 12:10:43 +00:00
|
|
|
}
|
2013-11-13 21:32:16 +00:00
|
|
|
}
|
|
|
|
else if (ChildExtension->ChildType == Other)
|
|
|
|
{
|
|
|
|
INFO_(VIDEOPRT, "\"Other\" device enumerated: DeviceId = %S\n", (PWSTR)ChildExtension->ChildDescriptor);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
ERR_(VIDEOPRT, "HwGetVideoChildDescriptor returned unsupported type: %d\n", ChildExtension->ChildType);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Clear the init flag */
|
|
|
|
ChildDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
|
|
|
|
|
|
|
|
InsertTailList(&DeviceExtension->ChildDeviceList,
|
|
|
|
&ChildExtension->ListEntry);
|
|
|
|
}
|
|
|
|
|
2022-01-02 20:31:29 +00:00
|
|
|
return STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
VP_STATUS
|
|
|
|
NTAPI
|
|
|
|
VideoPortEnumerateChildren(
|
|
|
|
IN PVOID HwDeviceExtension,
|
|
|
|
IN PVOID Reserved)
|
|
|
|
{
|
|
|
|
PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension;
|
|
|
|
|
|
|
|
DeviceExtension = VIDEO_PORT_GET_DEVICE_EXTENSION(HwDeviceExtension);
|
|
|
|
ASSERT(DeviceExtension);
|
|
|
|
|
|
|
|
if (DeviceExtension->PhysicalDeviceObject)
|
|
|
|
{
|
|
|
|
/* Trigger reenumeration by the PnP manager */
|
|
|
|
IoInvalidateDeviceRelations(DeviceExtension->PhysicalDeviceObject, BusRelations);
|
|
|
|
}
|
2013-11-13 21:32:16 +00:00
|
|
|
|
|
|
|
return NO_ERROR;
|
2004-03-06 08:39:06 +00:00
|
|
|
}
|
|
|
|
|
2004-03-08 04:09:02 +00:00
|
|
|
/*
|
2004-03-19 20:58:32 +00:00
|
|
|
* @unimplemented
|
2004-03-08 04:09:02 +00:00
|
|
|
*/
|
2013-11-13 21:32:16 +00:00
|
|
|
VP_STATUS
|
|
|
|
NTAPI
|
2004-03-19 20:58:32 +00:00
|
|
|
VideoPortCreateSecondaryDisplay(
|
2013-11-13 21:32:16 +00:00
|
|
|
IN PVOID HwDeviceExtension,
|
|
|
|
IN OUT PVOID *SecondaryDeviceExtension,
|
|
|
|
IN ULONG Flag)
|
2004-03-06 22:25:22 +00:00
|
|
|
{
|
2021-06-23 06:54:27 +00:00
|
|
|
PDEVICE_OBJECT DeviceObject;
|
|
|
|
PVIDEO_PORT_DEVICE_EXTENSION FirstDeviceExtension, DeviceExtension;
|
|
|
|
NTSTATUS Status;
|
|
|
|
|
|
|
|
ASSERT(SecondaryDeviceExtension);
|
|
|
|
|
|
|
|
if (Flag != 0)
|
|
|
|
{
|
|
|
|
UNIMPLEMENTED;
|
|
|
|
}
|
|
|
|
|
|
|
|
FirstDeviceExtension = VIDEO_PORT_GET_DEVICE_EXTENSION(HwDeviceExtension);
|
|
|
|
|
|
|
|
if (FirstDeviceExtension->DisplayNumber != 0)
|
|
|
|
{
|
|
|
|
DPRINT1("Calling VideoPortCreateSecondaryDisplay for InstanceId %lu\n",
|
|
|
|
FirstDeviceExtension->DisplayNumber);
|
|
|
|
}
|
|
|
|
|
|
|
|
Status = IntVideoPortCreateAdapterDeviceObject(FirstDeviceExtension->DriverObject,
|
|
|
|
FirstDeviceExtension->DriverExtension,
|
|
|
|
FirstDeviceExtension->PhysicalDeviceObject,
|
|
|
|
FirstDeviceExtension->AdapterNumber,
|
|
|
|
FirstDeviceExtension->NumberOfSecondaryDisplays + 1,
|
|
|
|
&DeviceObject);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
DPRINT1("IntVideoPortCreateAdapterDeviceObject() failed with status 0x%08x\n", Status);
|
|
|
|
return ERROR_DEV_NOT_EXIST;
|
|
|
|
}
|
|
|
|
|
|
|
|
DeviceExtension = DeviceObject->DeviceExtension;
|
|
|
|
|
|
|
|
/* Increment secondary display count */
|
|
|
|
FirstDeviceExtension->NumberOfSecondaryDisplays++;
|
|
|
|
|
|
|
|
*SecondaryDeviceExtension = DeviceExtension->MiniPortDeviceExtension;
|
|
|
|
return NO_ERROR;
|
2004-03-06 22:25:22 +00:00
|
|
|
}
|
|
|
|
|
2004-03-19 20:58:32 +00:00
|
|
|
/*
|
|
|
|
* @implemented
|
|
|
|
*/
|
2013-11-13 21:32:16 +00:00
|
|
|
BOOLEAN
|
|
|
|
NTAPI
|
2004-03-19 20:58:32 +00:00
|
|
|
VideoPortQueueDpc(
|
2013-11-13 21:32:16 +00:00
|
|
|
IN PVOID HwDeviceExtension,
|
|
|
|
IN PMINIPORT_DPC_ROUTINE CallbackRoutine,
|
|
|
|
IN PVOID Context)
|
2004-03-06 22:25:22 +00:00
|
|
|
{
|
2013-11-13 21:32:16 +00:00
|
|
|
return KeInsertQueueDpc(
|
|
|
|
&VIDEO_PORT_GET_DEVICE_EXTENSION(HwDeviceExtension)->DpcObject,
|
|
|
|
(PVOID)CallbackRoutine,
|
|
|
|
(PVOID)Context);
|
2004-03-06 22:25:22 +00:00
|
|
|
}
|
|
|
|
|
2004-03-19 20:58:32 +00:00
|
|
|
/*
|
2005-12-31 16:01:02 +00:00
|
|
|
* @implemented
|
2004-03-19 20:58:32 +00:00
|
|
|
*/
|
2013-11-13 21:32:16 +00:00
|
|
|
PVOID
|
|
|
|
NTAPI
|
|
|
|
VideoPortGetAssociatedDeviceExtension(
|
|
|
|
IN PVOID DeviceObject)
|
2004-03-06 22:25:22 +00:00
|
|
|
{
|
2013-11-13 21:32:16 +00:00
|
|
|
PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension;
|
2005-12-31 16:01:02 +00:00
|
|
|
|
2013-11-13 21:32:16 +00:00
|
|
|
TRACE_(VIDEOPRT, "VideoPortGetAssociatedDeviceExtension\n");
|
|
|
|
DeviceExtension = ((PDEVICE_OBJECT)DeviceObject)->DeviceExtension;
|
|
|
|
if (!DeviceExtension)
|
|
|
|
return NULL;
|
|
|
|
return DeviceExtension->MiniPortDeviceExtension;
|
2004-03-06 22:25:22 +00:00
|
|
|
}
|
|
|
|
|
2004-03-08 04:09:02 +00:00
|
|
|
/*
|
|
|
|
* @implemented
|
|
|
|
*/
|
2013-11-13 21:32:16 +00:00
|
|
|
VP_STATUS
|
|
|
|
NTAPI
|
2004-03-19 20:58:32 +00:00
|
|
|
VideoPortGetVersion(
|
2013-11-13 21:32:16 +00:00
|
|
|
IN PVOID HwDeviceExtension,
|
|
|
|
IN OUT PVPOSVERSIONINFO VpOsVersionInfo)
|
2004-03-06 22:25:22 +00:00
|
|
|
{
|
2013-11-13 21:32:16 +00:00
|
|
|
RTL_OSVERSIONINFOEXW Version;
|
2004-03-08 08:05:27 +00:00
|
|
|
|
2013-11-13 21:32:16 +00:00
|
|
|
Version.dwOSVersionInfoSize = sizeof(RTL_OSVERSIONINFOEXW);
|
|
|
|
if (VpOsVersionInfo->Size >= sizeof(VPOSVERSIONINFO))
|
|
|
|
{
|
2004-03-08 20:27:33 +00:00
|
|
|
#if 1
|
2013-11-13 21:32:16 +00:00
|
|
|
if (NT_SUCCESS(RtlGetVersion((PRTL_OSVERSIONINFOW)&Version)))
|
|
|
|
{
|
|
|
|
VpOsVersionInfo->MajorVersion = Version.dwMajorVersion;
|
|
|
|
VpOsVersionInfo->MinorVersion = Version.dwMinorVersion;
|
|
|
|
VpOsVersionInfo->BuildNumber = Version.dwBuildNumber;
|
|
|
|
VpOsVersionInfo->ServicePackMajor = Version.wServicePackMajor;
|
|
|
|
VpOsVersionInfo->ServicePackMinor = Version.wServicePackMinor;
|
|
|
|
return NO_ERROR;
|
|
|
|
}
|
|
|
|
return ERROR_INVALID_PARAMETER;
|
2004-03-08 20:27:33 +00:00
|
|
|
#else
|
2013-11-13 21:32:16 +00:00
|
|
|
VpOsVersionInfo->MajorVersion = 5;
|
|
|
|
VpOsVersionInfo->MinorVersion = 0;
|
|
|
|
VpOsVersionInfo->BuildNumber = 2195;
|
|
|
|
VpOsVersionInfo->ServicePackMajor = 4;
|
|
|
|
VpOsVersionInfo->ServicePackMinor = 0;
|
|
|
|
return NO_ERROR;
|
2004-03-08 20:27:33 +00:00
|
|
|
#endif
|
2013-11-13 21:32:16 +00:00
|
|
|
}
|
2004-03-08 08:05:27 +00:00
|
|
|
|
2013-11-13 21:32:16 +00:00
|
|
|
return ERROR_INVALID_PARAMETER;
|
2004-03-06 22:25:22 +00:00
|
|
|
}
|
|
|
|
|
2004-03-19 20:58:32 +00:00
|
|
|
/*
|
2005-12-31 16:01:02 +00:00
|
|
|
* @implemented
|
2004-03-19 20:58:32 +00:00
|
|
|
*/
|
2013-11-13 21:32:16 +00:00
|
|
|
BOOLEAN
|
|
|
|
NTAPI
|
2004-03-19 20:58:32 +00:00
|
|
|
VideoPortCheckForDeviceExistence(
|
2013-11-13 21:32:16 +00:00
|
|
|
IN PVOID HwDeviceExtension,
|
|
|
|
IN USHORT VendorId,
|
|
|
|
IN USHORT DeviceId,
|
|
|
|
IN UCHAR RevisionId,
|
|
|
|
IN USHORT SubVendorId,
|
|
|
|
IN USHORT SubSystemId,
|
|
|
|
IN ULONG Flags)
|
2004-03-06 22:25:22 +00:00
|
|
|
{
|
2013-11-13 21:32:16 +00:00
|
|
|
PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension;
|
|
|
|
PCI_DEVICE_PRESENT_INTERFACE PciDevicePresentInterface;
|
|
|
|
IO_STATUS_BLOCK IoStatusBlock;
|
|
|
|
IO_STACK_LOCATION IoStack;
|
|
|
|
ULONG PciFlags = 0;
|
|
|
|
NTSTATUS Status;
|
|
|
|
BOOL DevicePresent;
|
|
|
|
|
|
|
|
TRACE_(VIDEOPRT, "VideoPortCheckForDeviceExistence\n");
|
|
|
|
|
|
|
|
if (Flags & ~(CDE_USE_REVISION | CDE_USE_SUBSYSTEM_IDS))
|
|
|
|
{
|
|
|
|
WARN_(VIDEOPRT, "VideoPortCheckForDeviceExistence: Unknown flags 0x%lx\n", Flags & ~(CDE_USE_REVISION | CDE_USE_SUBSYSTEM_IDS));
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
DeviceExtension = VIDEO_PORT_GET_DEVICE_EXTENSION(HwDeviceExtension);
|
|
|
|
|
|
|
|
PciDevicePresentInterface.Size = sizeof(PCI_DEVICE_PRESENT_INTERFACE);
|
|
|
|
PciDevicePresentInterface.Version = 1;
|
|
|
|
IoStack.Parameters.QueryInterface.Size = PciDevicePresentInterface.Size;
|
|
|
|
IoStack.Parameters.QueryInterface.Version = PciDevicePresentInterface.Version;
|
|
|
|
IoStack.Parameters.QueryInterface.Interface = (PINTERFACE)&PciDevicePresentInterface;
|
|
|
|
IoStack.Parameters.QueryInterface.InterfaceType =
|
|
|
|
&GUID_PCI_DEVICE_PRESENT_INTERFACE;
|
|
|
|
Status = IopInitiatePnpIrp(DeviceExtension->NextDeviceObject,
|
|
|
|
&IoStatusBlock, IRP_MN_QUERY_INTERFACE, &IoStack);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
WARN_(VIDEOPRT, "IopInitiatePnpIrp() failed! (Status 0x%lx)\n", Status);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Flags & CDE_USE_REVISION)
|
|
|
|
PciFlags |= PCI_USE_REVISION;
|
|
|
|
if (Flags & CDE_USE_SUBSYSTEM_IDS)
|
|
|
|
PciFlags |= PCI_USE_SUBSYSTEM_IDS;
|
|
|
|
|
|
|
|
DevicePresent = PciDevicePresentInterface.IsDevicePresent(
|
|
|
|
VendorId, DeviceId, RevisionId,
|
|
|
|
SubVendorId, SubSystemId, PciFlags);
|
|
|
|
|
|
|
|
PciDevicePresentInterface.InterfaceDereference(PciDevicePresentInterface.Context);
|
|
|
|
|
|
|
|
return DevicePresent;
|
2004-03-06 22:25:22 +00:00
|
|
|
}
|
|
|
|
|
2004-03-19 20:58:32 +00:00
|
|
|
/*
|
|
|
|
* @unimplemented
|
|
|
|
*/
|
2013-11-13 21:32:16 +00:00
|
|
|
VP_STATUS
|
|
|
|
NTAPI
|
2004-03-19 20:58:32 +00:00
|
|
|
VideoPortRegisterBugcheckCallback(
|
2013-11-13 21:32:16 +00:00
|
|
|
IN PVOID HwDeviceExtension,
|
|
|
|
IN ULONG BugcheckCode,
|
|
|
|
IN PVIDEO_BUGCHECK_CALLBACK Callback,
|
|
|
|
IN ULONG BugcheckDataSize)
|
2004-03-07 04:43:55 +00:00
|
|
|
{
|
2007-12-28 14:47:03 +00:00
|
|
|
UNIMPLEMENTED;
|
|
|
|
return NO_ERROR;
|
2004-03-07 04:43:55 +00:00
|
|
|
}
|
|
|
|
|
2004-03-19 20:58:32 +00:00
|
|
|
/*
|
|
|
|
* @implemented
|
|
|
|
*/
|
2013-11-13 21:32:16 +00:00
|
|
|
LONGLONG
|
|
|
|
NTAPI
|
2004-03-09 17:28:49 +00:00
|
|
|
VideoPortQueryPerformanceCounter(
|
2013-11-13 21:32:16 +00:00
|
|
|
IN PVOID HwDeviceExtension,
|
|
|
|
OUT PLONGLONG PerformanceFrequency OPTIONAL)
|
2004-03-09 17:28:49 +00:00
|
|
|
{
|
2013-11-13 21:32:16 +00:00
|
|
|
LARGE_INTEGER Result;
|
2004-03-09 17:28:49 +00:00
|
|
|
|
2013-11-13 21:32:16 +00:00
|
|
|
TRACE_(VIDEOPRT, "VideoPortQueryPerformanceCounter\n");
|
|
|
|
Result = KeQueryPerformanceCounter((PLARGE_INTEGER)PerformanceFrequency);
|
|
|
|
return Result.QuadPart;
|
2004-03-09 17:28:49 +00:00
|
|
|
}
|
2005-01-07 01:03:34 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* @implemented
|
|
|
|
*/
|
2013-11-13 21:32:16 +00:00
|
|
|
VOID
|
|
|
|
NTAPI
|
2005-01-07 01:03:34 +00:00
|
|
|
VideoPortAcquireDeviceLock(
|
2013-11-13 21:32:16 +00:00
|
|
|
IN PVOID HwDeviceExtension)
|
2005-01-07 01:03:34 +00:00
|
|
|
{
|
2013-11-13 21:32:16 +00:00
|
|
|
PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension;
|
|
|
|
|
|
|
|
TRACE_(VIDEOPRT, "VideoPortAcquireDeviceLock\n");
|
|
|
|
DeviceExtension = VIDEO_PORT_GET_DEVICE_EXTENSION(HwDeviceExtension);
|
2021-01-18 21:15:02 +00:00
|
|
|
KeWaitForMutexObject(&DeviceExtension->DeviceLock, Executive, KernelMode, FALSE, NULL);
|
2013-11-13 21:32:16 +00:00
|
|
|
// ASSERT(Status == STATUS_SUCCESS);
|
2005-01-07 01:03:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* @implemented
|
|
|
|
*/
|
2013-11-13 21:32:16 +00:00
|
|
|
VOID
|
|
|
|
NTAPI
|
2005-01-07 01:03:34 +00:00
|
|
|
VideoPortReleaseDeviceLock(
|
2013-11-13 21:32:16 +00:00
|
|
|
IN PVOID HwDeviceExtension)
|
2005-01-07 01:03:34 +00:00
|
|
|
{
|
2013-11-13 21:32:16 +00:00
|
|
|
PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension;
|
|
|
|
|
|
|
|
TRACE_(VIDEOPRT, "VideoPortReleaseDeviceLock\n");
|
|
|
|
DeviceExtension = VIDEO_PORT_GET_DEVICE_EXTENSION(HwDeviceExtension);
|
2021-01-18 21:15:02 +00:00
|
|
|
KeReleaseMutex(&DeviceExtension->DeviceLock, FALSE);
|
2013-11-13 21:32:16 +00:00
|
|
|
//ASSERT(Status == STATUS_SUCCESS);
|
2005-01-07 01:03:34 +00:00
|
|
|
}
|
|
|
|
|
2005-08-03 07:50:16 +00:00
|
|
|
/*
|
|
|
|
* @unimplemented
|
|
|
|
*/
|
2013-11-13 21:32:16 +00:00
|
|
|
VOID
|
|
|
|
NTAPI
|
2005-08-03 07:50:16 +00:00
|
|
|
VpNotifyEaData(
|
2013-11-13 21:32:16 +00:00
|
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
|
|
IN PVOID Data)
|
2005-08-03 07:50:16 +00:00
|
|
|
{
|
2007-12-28 14:47:03 +00:00
|
|
|
UNIMPLEMENTED;
|
2005-08-03 07:50:16 +00:00
|
|
|
}
|
2007-06-05 22:51:44 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* @implemented
|
|
|
|
*/
|
2013-11-13 21:32:16 +00:00
|
|
|
PVOID
|
|
|
|
NTAPI
|
2007-06-05 22:51:44 +00:00
|
|
|
VideoPortAllocateContiguousMemory(
|
2013-11-13 21:32:16 +00:00
|
|
|
IN PVOID HwDeviceExtension,
|
|
|
|
IN ULONG NumberOfBytes,
|
|
|
|
IN PHYSICAL_ADDRESS HighestAcceptableAddress
|
|
|
|
)
|
2007-06-05 22:51:44 +00:00
|
|
|
{
|
|
|
|
return MmAllocateContiguousMemory(NumberOfBytes, HighestAcceptableAddress);
|
|
|
|
}
|
2010-03-04 21:53:12 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* @implemented
|
|
|
|
*/
|
2013-11-13 21:32:16 +00:00
|
|
|
BOOLEAN
|
|
|
|
NTAPI
|
2010-03-04 21:53:12 +00:00
|
|
|
VideoPortIsNoVesa(VOID)
|
|
|
|
{
|
2019-12-24 12:51:20 +00:00
|
|
|
return VpNoVesa;
|
2010-03-04 21:53:12 +00:00
|
|
|
}
|