reactos/win32ss/drivers/videoprt/videoprt.c

1742 lines
54 KiB
C
Raw Normal View History

/*
* VideoPort driver
*
* Copyright (C) 2002-2004, 2007 ReactOS Team
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* 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
* Lesser General Public License for more details.
*
* 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
*
*/
#include "videoprt.h"
#include <stdio.h>
#include <ndk/exfuncs.h>
#include <ndk/obfuncs.h>
#include <ndk/rtlfuncs.h>
#define NDEBUG
#include <debug.h>
/* GLOBAL VARIABLES ***********************************************************/
ULONG VideoDebugLevel = 0;
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;
static ULONG VideoPortMaxObjectNumber = -1;
BOOLEAN VideoPortUseNewKey = FALSE;
KMUTEX VideoPortInt10Mutex;
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);
/* PRIVATE FUNCTIONS **********************************************************/
ULONG
NTAPI
DriverEntry(
IN PVOID Context1,
IN PVOID Context2)
{
return STATUS_SUCCESS;
}
static
NTSTATUS
IntVideoPortAddDeviceMapLink(
PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension)
{
PUNICODE_STRING RegistryPath;
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);
if (VideoPortUseNewKey)
RegistryPath = &DeviceExtension->NewRegistryPath;
else
RegistryPath = &DeviceExtension->RegistryPath;
/* Add entry to DEVICEMAP\VIDEO key in registry. */
Status = RtlWriteRegistryValue(RTL_REGISTRY_DEVICEMAP,
L"VIDEO",
DeviceBuffer,
REG_SZ,
RegistryPath->Buffer,
RegistryPath->Length + sizeof(UNICODE_NULL));
if (!NT_SUCCESS(Status))
{
ERR_(VIDEOPRT, "Failed to create DEVICEMAP registry entry: 0x%X\n", Status);
return Status;
}
Status = RtlWriteRegistryValue(RTL_REGISTRY_DEVICEMAP,
L"VIDEO",
L"MaxObjectNumber",
REG_DWORD,
&DeviceNumber,
sizeof(DeviceNumber));
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))
{
ERR_(VIDEOPRT, "Failed to create symbolic link: 0x%X\n", Status);
return Status;
}
/* Update MaxObjectNumber */
VideoPortMaxObjectNumber = DeviceNumber;
return STATUS_SUCCESS;
}
PVOID
NTAPI
IntVideoPortImageDirectoryEntryToData(
PVOID BaseAddress,
ULONG Directory)
{
PIMAGE_NT_HEADERS NtHeader;
ULONG Va;
NtHeader = RtlImageNtHeader(BaseAddress);
if (NtHeader == NULL)
return NULL;
if (Directory >= NtHeader->OptionalHeader.NumberOfRvaAndSizes)
return NULL;
Va = NtHeader->OptionalHeader.DataDirectory[Directory].VirtualAddress;
if (Va == 0)
return NULL;
return (PVOID)((ULONG_PTR)BaseAddress + Va);
}
VOID
NTAPI
IntVideoPortDeferredRoutine(
IN PKDPC Dpc,
IN PVOID DeferredContext,
IN PVOID SystemArgument1,
IN PVOID SystemArgument2)
{
PVOID HwDeviceExtension =
&((PVIDEO_PORT_DEVICE_EXTENSION)DeferredContext)->MiniPortDeviceExtension;
((PMINIPORT_DPC_ROUTINE)SystemArgument1)(HwDeviceExtension, SystemArgument2);
}
NTSTATUS
NTAPI
IntVideoPortCreateAdapterDeviceObject(
_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,
_Out_opt_ PDEVICE_OBJECT *DeviceObject)
{
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.
*/
DeviceNumber = VideoPortMaxObjectNumber + 1;
if (DeviceNumber == (ULONG)-1)
{
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. */
Size = sizeof(VIDEO_PORT_DEVICE_EXTENSION) +
DriverExtension->InitializationData.HwDeviceExtensionSize;
Status = IoCreateDevice(DriverObject,
Size,
&DeviceName,
FILE_DEVICE_VIDEO,
0,
TRUE,
DeviceObject);
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;
DeviceExtension->SessionId = -1;
2021-07-03 20:59:30 +00:00
DeviceExtension->AdapterNumber = AdapterNumber;
DeviceExtension->DisplayNumber = DisplayNumber;
InitializeListHead(&DeviceExtension->ChildDeviceList);
/* Get the registry path associated with this device. */
Status = IntCreateRegistryPath(&DriverExtension->RegistryPath,
2021-07-03 20:59:30 +00:00
DeviceExtension->AdapterNumber,
&DeviceExtension->RegistryPath);
if (!NT_SUCCESS(Status))
{
WARN_(VIDEOPRT, "IntCreateRegistryPath() call failed with status 0x%08x\n", Status);
goto Failure;
}
if (PhysicalDeviceObject != NULL)
{
/* Get bus number from the upper level bus driver. */
Size = sizeof(ULONG);
Status = IoGetDeviceProperty(PhysicalDeviceObject,
DevicePropertyBusNumber,
Size,
&DeviceExtension->SystemIoBusNumber,
&Size);
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);
/* 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;
}
InitializeListHead(&DeviceExtension->AddressMappingListHead);
InitializeListHead(&DeviceExtension->DmaAdapterList);
KeInitializeDpc(&DeviceExtension->DpcObject,
IntVideoPortDeferredRoutine,
DeviceExtension);
KeInitializeMutex(&DeviceExtension->DeviceLock, 0);
/* Attach the device. */
if ((PhysicalDeviceObject != NULL) && (DisplayNumber == 0))
DeviceExtension->NextDeviceObject = IoAttachDeviceToDeviceStack(
*DeviceObject,
PhysicalDeviceObject);
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);
goto Failure;
2021-07-03 20:59:30 +00:00
}
IntSetupDeviceSettingsKey(DeviceExtension);
/* Remove the initializing flag */
(*DeviceObject)->Flags &= ~DO_DEVICE_INITIALIZING;
/* Set up the VIDEO/DEVICEMAP registry keys */
Status = IntVideoPortAddDeviceMapLink(DeviceExtension);
if (!NT_SUCCESS(Status))
{
ERR_(VIDEOPRT, "IntVideoPortAddDeviceMapLink() failed with status 0x%08x\n", Status);
goto Failure;
}
2021-07-03 20:59:30 +00:00
if (DisplayNumber == 0)
{
DriverExtension->InitializationData.StartingDeviceNumber++;
}
return STATUS_SUCCESS;
Failure:
if (DeviceExtension->NextDeviceObject)
IoDetachDevice(DeviceExtension->NextDeviceObject);
IoDeleteDevice(*DeviceObject);
*DeviceObject = NULL;
return Status;
}
/**
* @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);
}
NTSTATUS
NTAPI
IntVideoPortFindAdapter(
IN PDRIVER_OBJECT DriverObject,
IN PVIDEO_PORT_DRIVER_EXTENSION DriverExtension,
IN PDEVICE_OBJECT DeviceObject)
{
PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension;
NTSTATUS Status;
VP_STATUS vpStatus;
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,
sizeof(SystemBasicInfo),
NULL);
if (NT_SUCCESS(Status))
{
ConfigInfo.SystemMemorySize = SystemBasicInfo.NumberOfPhysicalPages *
SystemBasicInfo.PageSize;
}
// FIXME: Check the adapter key and update VideoDebugLevel variable.
/*
* 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)
{
ULONG BusNumber;
/* Suppose first we may not find any suitable device */
vpStatus = ERROR_DEV_NOT_EXIST; // ERROR_NO_MORE_DEVICES;
/* 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)
{
DPRINT("Bus Type %lu, Number %lu\n",
DeviceExtension->AdapterInterfaceType, BusNumber);
DeviceExtension->SystemIoBusNumber =
ConfigInfo.SystemIoBusNumber = BusNumber;
RtlZeroMemory(&DeviceExtension->MiniPortDeviceExtension,
DriverExtension->InitializationData.HwDeviceExtensionSize);
/* FIXME: Need to figure out what string to pass as param 3. */
// FIXME: Handle the 'Again' parameter for legacy detection.
vpStatus = DriverExtension->InitializationData.HwFindAdapter(
&DeviceExtension->MiniPortDeviceExtension,
DriverExtension->HwContext,
NULL,
&ConfigInfo,
&Again);
if (vpStatus == ERROR_DEV_NOT_EXIST)
{
continue;
}
else
{
break;
}
}
}
else
{
/* FIXME: Need to figure out what string to pass as param 3. */
vpStatus = DriverExtension->InitializationData.HwFindAdapter(
&DeviceExtension->MiniPortDeviceExtension,
DriverExtension->HwContext,
NULL,
&ConfigInfo,
&Again);
}
if (vpStatus != NO_ERROR)
{
ERR_(VIDEOPRT, "HwFindAdapter call failed with error 0x%X\n", vpStatus);
Status = STATUS_UNSUCCESSFUL;
goto Failure;
}
/*
* 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))
{
Status = STATUS_INSUFFICIENT_RESOURCES;
goto Failure;
}
/* Allocate timer for device. */
if (!IntVideoPortSetupTimer(DeviceObject, DriverExtension))
{
if (DeviceExtension->InterruptObject != NULL)
IoDisconnectInterrupt(DeviceExtension->InterruptObject);
ERR_(VIDEOPRT, "IntVideoPortSetupTimer failed\n");
Status = STATUS_INSUFFICIENT_RESOURCES;
goto Failure;
}
[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)
{
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
}
INFO_(VIDEOPRT, "STATUS_SUCCESS\n");
return STATUS_SUCCESS;
Failure:
RtlFreeUnicodeString(&DeviceExtension->RegistryPath);
if (DeviceExtension->NextDeviceObject)
IoDetachDevice(DeviceExtension->NextDeviceObject);
IoDeleteDevice(DeviceObject);
return Status;
}
VOID
FASTCALL
IntAttachToCSRSS(
PKPROCESS *CallingProcess,
PKAPC_STATE ApcState)
{
*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)
{
[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);
}
}
VOID
FASTCALL
IntDetachFromCSRSS(
PKPROCESS *CallingProcess,
PKAPC_STATE ApcState)
{
[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)
{
KeUnstackDetachProcess(ApcState);
}
}
VOID
FASTCALL
IntLoadRegistryParameters(VOID)
{
NTSTATUS Status;
HANDLE KeyHandle;
UNICODE_STRING UseNewKeyPath = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\GraphicsDrivers\\UseNewKey");
UNICODE_STRING Path = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\System\\CurrentControlSet\\Control");
UNICODE_STRING ValueName = RTL_CONSTANT_STRING(L"SystemStartOptions");
OBJECT_ATTRIBUTES ObjectAttributes;
PKEY_VALUE_PARTIAL_INFORMATION KeyInfo;
ULONG Length, NewLength;
/* 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);
}
/* 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,
READ_CONTROL, // Non-0 placeholder: no use for this handle.
&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;
}
/* PUBLIC FUNCTIONS ***********************************************************/
/*
* @implemented
*/
ULONG
NTAPI
VideoPortInitialize(
IN PVOID Context1,
IN PVOID Context2,
IN PVIDEO_HW_INITIALIZATION_DATA HwInitializationData,
IN PVOID HwContext)
{
PDRIVER_OBJECT DriverObject = Context1;
PUNICODE_STRING RegistryPath = Context2;
NTSTATUS Status;
PVIDEO_PORT_DRIVER_EXTENSION DriverExtension;
BOOLEAN PnpDriver = FALSE, LegacyDetection = FALSE;
static BOOLEAN FirstInitialization;
TRACE_(VIDEOPRT, "VideoPortInitialize\n");
if (!FirstInitialization)
{
FirstInitialization = TRUE;
KeInitializeMutex(&VideoPortInt10Mutex, 0);
KeInitializeSpinLock(&HwResetAdaptersLock);
IntLoadRegistryParameters();
}
/* As a first thing do parameter checks. */
if (HwInitializationData->HwInitDataSize > sizeof(VIDEO_HW_INITIALIZATION_DATA))
{
ERR_(VIDEOPRT, "Invalid HwInitializationData\n");
return STATUS_REVISION_MISMATCH;
}
if ((HwInitializationData->HwFindAdapter == NULL) ||
(HwInitializationData->HwInitialize == NULL) ||
(HwInitializationData->HwStartIO == NULL))
{
ERR_(VIDEOPRT, "Invalid HwInitializationData\n");
return STATUS_INVALID_PARAMETER;
}
switch (HwInitializationData->HwInitDataSize)
{
/*
* NT4 drivers are special case, because we must use legacy method
* of detection instead of the Plug & Play one.
*/
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] =
IntVideoPortDispatchDeviceControl;
DriverObject->DriverUnload = IntVideoPortUnload;
/* Determine type of the miniport driver */
if ((HwInitializationData->HwInitDataSize >=
FIELD_OFFSET(VIDEO_HW_INITIALIZATION_DATA, HwQueryInterface)) &&
(HwInitializationData->HwSetPowerState != NULL) &&
(HwInitializationData->HwGetPowerState != NULL) &&
(HwInitializationData->HwGetVideoChildDescriptor != NULL))
{
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)
{
Status = IoAllocateDriverObjectExtension(DriverObject,
DriverObject,
sizeof(VIDEO_PORT_DRIVER_EXTENSION),
(PVOID *)&DriverExtension);
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);
/* 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);
INFO_(VIDEOPRT, "RegistryPath: %wZ\n", &DriverExtension->RegistryPath);
}
else
{
RtlInitUnicodeString(&DriverExtension->RegistryPath, NULL);
}
}
/* Copy the correct miniport initialization data to the device extension. */
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.
*/
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 */
DriverObject->MajorFunction[IRP_MJ_POWER] = IntVideoPortDispatchPower;
}
Status = IntVideoPortCreateAdapterDeviceObject(DriverObject,
DriverExtension,
NULL,
2021-07-03 20:59:30 +00:00
DriverExtension->InitializationData.StartingDeviceNumber,
0,
&DeviceObject);
if (!NT_SUCCESS(Status))
{
ERR_(VIDEOPRT, "IntVideoPortCreateAdapterDeviceObject returned 0x%x\n", Status);
return Status;
}
Status = IntVideoPortFindAdapter(DriverObject, DriverExtension, DeviceObject);
if (!NT_SUCCESS(Status))
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;
}
}
/*
* @implemented
*/
VOID
VideoPortDebugPrint(
IN VIDEO_DEBUG_LEVEL DebugPrintLevel,
IN PCHAR DebugMessage,
...)
{
va_list ap;
if (VideoDebugLevel >= DebugPrintLevel)
DebugPrintLevel = Error;
va_start(ap, DebugMessage);
vDbgPrintEx(DPFLTR_IHVVIDEO_ID, DebugPrintLevel, DebugMessage, ap);
va_end(ap);
}
/*
* @unimplemented
*/
VOID
NTAPI
VideoPortLogError(
IN PVOID HwDeviceExtension,
IN PVIDEO_REQUEST_PACKET Vrp OPTIONAL,
IN VP_STATUS ErrorCode,
IN ULONG UniqueId)
{
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);
}
/*
* @implemented
*/
UCHAR
NTAPI
VideoPortGetCurrentIrql(VOID)
{
return KeGetCurrentIrql();
}
typedef struct QueryRegistryCallbackContext
{
PVOID HwDeviceExtension;
PVOID HwContext;
PMINIPORT_GET_REGISTRY_ROUTINE HwGetRegistryRoutine;
} QUERY_REGISTRY_CALLBACK_CONTEXT, *PQUERY_REGISTRY_CALLBACK_CONTEXT;
static
NTSTATUS
NTAPI
QueryRegistryCallback(
IN PWSTR ValueName,
IN ULONG ValueType,
IN PVOID ValueData,
IN ULONG ValueLength,
IN PVOID Context,
IN PVOID EntryContext)
{
PQUERY_REGISTRY_CALLBACK_CONTEXT CallbackContext = (PQUERY_REGISTRY_CALLBACK_CONTEXT) Context;
INFO_(VIDEOPRT, "Found registry value for name %S: type %d, length %d\n",
ValueName, ValueType, ValueLength);
return (*(CallbackContext->HwGetRegistryRoutine))(
CallbackContext->HwDeviceExtension,
CallbackContext->HwContext,
ValueName,
ValueData,
ValueLength);
}
/*
* @unimplemented
*/
VP_STATUS
NTAPI
VideoPortGetRegistryParameters(
IN PVOID HwDeviceExtension,
IN PWSTR ParameterName,
IN UCHAR IsParameterFileName,
IN PMINIPORT_GET_REGISTRY_ROUTINE GetRegistryRoutine,
IN PVOID HwContext)
{
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;
}
/*
* @implemented
*/
VP_STATUS
NTAPI
VideoPortSetRegistryParameters(
IN PVOID HwDeviceExtension,
IN PWSTR ValueName,
IN PVOID ValueData,
IN ULONG ValueLength)
{
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;
}
/*
* @implemented
*/
VP_STATUS
NTAPI
VideoPortGetVgaStatus(
IN PVOID HwDeviceExtension,
OUT PULONG VgaStatus)
{
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;
}
/*
* @implemented
*/
PVOID
NTAPI
VideoPortGetRomImage(
IN PVOID HwDeviceExtension,
IN PVOID Unused1,
IN ULONG Unused2,
IN ULONG Length)
{
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;
}
}
/*
* @implemented
*/
BOOLEAN
NTAPI
VideoPortScanRom(
IN PVOID HwDeviceExtension,
IN PUCHAR RomBase,
IN ULONG RomLength,
IN PUCHAR String)
{
2019-05-26 13:00:21 +00:00
SIZE_T StringLength;
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;
}
/*
* @implemented
*/
BOOLEAN
NTAPI
VideoPortSynchronizeExecution(
IN PVOID HwDeviceExtension,
IN VIDEO_SYNCHRONIZE_PRIORITY Priority,
IN PMINIPORT_SYNCHRONIZE_ROUTINE SynchronizeRoutine,
OUT PVOID Context)
{
BOOLEAN Ret;
PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension;
KIRQL OldIrql;
switch (Priority)
{
case VpLowPriority:
Ret = (*SynchronizeRoutine)(Context);
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;
case VpHighPriority:
OldIrql = KeGetCurrentIrql();
if (OldIrql < SYNCH_LEVEL)
KeRaiseIrql(SYNCH_LEVEL, &OldIrql);
Ret = (*SynchronizeRoutine)(Context);
if (OldIrql < SYNCH_LEVEL)
KeLowerIrql(OldIrql);
break;
default:
Ret = FALSE;
}
2004-03-06 Filip Navara <xnavara@volny.cz> * drivers/video/videoprt/int10.c (VideoPortInt10): Print more debug informations. * drivers/video/videoprt/videoprt.c (VideoPortInitialize): Prevent conflicts when more miniport drivers are loaded. (VideoPortGetDeviceBase, VideoPortMapMemory, InternalMapMemory): Change way of reporting error to prevent reporting error when the resources were successfully mapped. (VideoPortDDCMonitorHelper): Add stub. (VidDispatchDeviceControl): Allocate memory from NonPagedPool. Add debug messages. * drivers/video/videoprt/videoprt.def (VideoPortDDCMonitorHelper): Add export. * drivers/video/videoprt/videoprt.edf (VideoPortDDCMonitorHelper): Ditto. * include/ddk/winddi.h (ENG_SYSTEM_ATTRIBUTE): Declare. * include/win32k/driver.h (DRIVER_FindMPDriver): Change declaration. * subsys/win32k/eng/surface.c (EngModifySurface): Implement. * subsys/win32k/misc/driver.c (DRIVER_FindMPDriver): Modify to open specific miniport driver depending on parameter. * subsys/win32k/objects/dc.c (GetRegistryPath): Add parameter to specify display driver number. (FindDriverFileNames): Ditto. (SetupDevMode): Ditto. (IntCreateDC): Correct DPRINT. (IntCreatePrimarySurface): Change to try more miniport drivers before giving up. * subsys/win32k/stubs/stubs.c (HeapVidMemAllocAligned, VidMemFree, EngDitherColor, EngQuerySystemAttribute): Add stubs. * subsys/win32k/win32k.edf (EngDitherColor, EngQuerySystemAttribute, HeapVidMemAllocAligned, VidMemFree, EngModifySurface): Add exports. * subsys/win32k/win32k.def: Ditto. svn path=/trunk/; revision=8547
2004-03-06 01:22:04 +00:00
return Ret;
}
/*
* @implemented
*/
NTSTATUS NTAPI
IntVideoPortEnumerateChildren(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp)
{
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");
DeviceExtension = DeviceObject->DeviceExtension;
if (DeviceExtension->DriverExtension->InitializationData.HwGetVideoChildDescriptor == NULL)
{
WARN_(VIDEOPRT, "Miniport's HwGetVideoChildDescriptor is NULL!\n");
return STATUS_SUCCESS;
}
if (!IsListEmpty(&DeviceExtension->ChildDeviceList))
{
ERR_(VIDEOPRT, "FIXME: Support calling VideoPortEnumerateChildren again!\n");
return STATUS_SUCCESS;
}
/* 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(
DeviceExtension->MiniPortDeviceExtension,
&ChildEnumInfo,
&ChildExtension->ChildType,
ChildExtension->ChildDescriptor,
&ChildExtension->ChildId,
&Unused);
if (Status == VIDEO_ENUM_MORE_DEVICES)
{
if (ChildExtension->ChildType == Monitor)
{
// 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;
}
}
}
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)
{
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]);
}
}
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);
}
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);
}
return NO_ERROR;
}
/*
* @unimplemented
*/
VP_STATUS
NTAPI
VideoPortCreateSecondaryDisplay(
IN PVOID HwDeviceExtension,
IN OUT PVOID *SecondaryDeviceExtension,
IN ULONG Flag)
{
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;
}
/*
* @implemented
*/
BOOLEAN
NTAPI
VideoPortQueueDpc(
IN PVOID HwDeviceExtension,
IN PMINIPORT_DPC_ROUTINE CallbackRoutine,
IN PVOID Context)
{
return KeInsertQueueDpc(
&VIDEO_PORT_GET_DEVICE_EXTENSION(HwDeviceExtension)->DpcObject,
(PVOID)CallbackRoutine,
(PVOID)Context);
}
/*
* @implemented
*/
PVOID
NTAPI
VideoPortGetAssociatedDeviceExtension(
IN PVOID DeviceObject)
{
PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension;
TRACE_(VIDEOPRT, "VideoPortGetAssociatedDeviceExtension\n");
DeviceExtension = ((PDEVICE_OBJECT)DeviceObject)->DeviceExtension;
if (!DeviceExtension)
return NULL;
return DeviceExtension->MiniPortDeviceExtension;
}
/*
* @implemented
*/
VP_STATUS
NTAPI
VideoPortGetVersion(
IN PVOID HwDeviceExtension,
IN OUT PVPOSVERSIONINFO VpOsVersionInfo)
{
RTL_OSVERSIONINFOEXW Version;
Version.dwOSVersionInfoSize = sizeof(RTL_OSVERSIONINFOEXW);
if (VpOsVersionInfo->Size >= sizeof(VPOSVERSIONINFO))
{
#if 1
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;
#else
VpOsVersionInfo->MajorVersion = 5;
VpOsVersionInfo->MinorVersion = 0;
VpOsVersionInfo->BuildNumber = 2195;
VpOsVersionInfo->ServicePackMajor = 4;
VpOsVersionInfo->ServicePackMinor = 0;
return NO_ERROR;
#endif
}
return ERROR_INVALID_PARAMETER;
}
/*
* @implemented
*/
BOOLEAN
NTAPI
VideoPortCheckForDeviceExistence(
IN PVOID HwDeviceExtension,
IN USHORT VendorId,
IN USHORT DeviceId,
IN UCHAR RevisionId,
IN USHORT SubVendorId,
IN USHORT SubSystemId,
IN ULONG Flags)
{
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;
}
/*
* @unimplemented
*/
VP_STATUS
NTAPI
VideoPortRegisterBugcheckCallback(
IN PVOID HwDeviceExtension,
IN ULONG BugcheckCode,
IN PVIDEO_BUGCHECK_CALLBACK Callback,
IN ULONG BugcheckDataSize)
{
UNIMPLEMENTED;
return NO_ERROR;
}
/*
* @implemented
*/
LONGLONG
NTAPI
VideoPortQueryPerformanceCounter(
IN PVOID HwDeviceExtension,
OUT PLONGLONG PerformanceFrequency OPTIONAL)
{
LARGE_INTEGER Result;
TRACE_(VIDEOPRT, "VideoPortQueryPerformanceCounter\n");
Result = KeQueryPerformanceCounter((PLARGE_INTEGER)PerformanceFrequency);
return Result.QuadPart;
}
/*
* @implemented
*/
VOID
NTAPI
VideoPortAcquireDeviceLock(
IN PVOID HwDeviceExtension)
{
PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension;
TRACE_(VIDEOPRT, "VideoPortAcquireDeviceLock\n");
DeviceExtension = VIDEO_PORT_GET_DEVICE_EXTENSION(HwDeviceExtension);
KeWaitForMutexObject(&DeviceExtension->DeviceLock, Executive, KernelMode, FALSE, NULL);
// ASSERT(Status == STATUS_SUCCESS);
}
/*
* @implemented
*/
VOID
NTAPI
VideoPortReleaseDeviceLock(
IN PVOID HwDeviceExtension)
{
PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension;
TRACE_(VIDEOPRT, "VideoPortReleaseDeviceLock\n");
DeviceExtension = VIDEO_PORT_GET_DEVICE_EXTENSION(HwDeviceExtension);
KeReleaseMutex(&DeviceExtension->DeviceLock, FALSE);
//ASSERT(Status == STATUS_SUCCESS);
}
/*
* @unimplemented
*/
VOID
NTAPI
VpNotifyEaData(
IN PDEVICE_OBJECT DeviceObject,
IN PVOID Data)
{
UNIMPLEMENTED;
}
/*
* @implemented
*/
PVOID
NTAPI
VideoPortAllocateContiguousMemory(
IN PVOID HwDeviceExtension,
IN ULONG NumberOfBytes,
IN PHYSICAL_ADDRESS HighestAcceptableAddress
)
{
return MmAllocateContiguousMemory(NumberOfBytes, HighestAcceptableAddress);
}
/*
* @implemented
*/
BOOLEAN
NTAPI
VideoPortIsNoVesa(VOID)
{
return VpNoVesa;
}