diff --git a/qxldod Package/qxldod Package.vcxproj b/qxldod Package/qxldod Package.vcxproj new file mode 100755 index 0000000..d783186 --- /dev/null +++ b/qxldod Package/qxldod Package.vcxproj @@ -0,0 +1,155 @@ + + + + + Win8 Debug + Win32 + + + Win8 Release + Win32 + + + Win7 Debug + Win32 + + + Win7 Release + Win32 + + + Vista Debug + Win32 + + + Vista Release + Win32 + + + Win8 Debug + x64 + + + Win8 Release + x64 + + + Win7 Debug + x64 + + + Win7 Release + x64 + + + Vista Debug + x64 + + + Vista Release + x64 + + + + {B8C04B51-4207-491D-A7DD-C54861E8B528} + {4605da2c-74a5-4865-98e1-152ef136825f} + v4.5 + 11.0 + Win8 Debug + Win32 + + + qxldod_Package + $(VCTargetsPath11) + + + WindowsKernelModeDriver8.0 + Utility + Package + true + + + + Windows8 + true + + + Windows8 + false + + + Windows7 + true + + + Windows7 + false + + + Vista + true + + + Vista + false + + + Windows8 + true + + + Windows8 + false + + + Windows7 + true + + + Windows7 + false + + + Vista + true + + + Vista + false + + + + + + + + + + + DbgengKernelDebugger + False + True + + + + False + False + True + + 133563 + $(OutDir)qxldod Package + + + + + + + + + {a6f48fc7-97e9-48ec-bcdf-1e4f9b43aadd} + + + + + + \ No newline at end of file diff --git a/qxldod Package/qxldod Package.vcxproj.filters b/qxldod Package/qxldod Package.vcxproj.filters new file mode 100755 index 0000000..73af436 --- /dev/null +++ b/qxldod Package/qxldod Package.vcxproj.filters @@ -0,0 +1,9 @@ + + + + + {8E41214B-6785-4CFE-B992-037D68949A14} + inf;inv;inx;mof;mc; + + + \ No newline at end of file diff --git a/qxldod.sln b/qxldod.sln new file mode 100755 index 0000000..2b74fb7 --- /dev/null +++ b/qxldod.sln @@ -0,0 +1,47 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2012 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "qxldod", "qxldod\qxldod.vcxproj", "{A6F48FC7-97E9-48EC-BCDF-1E4F9B43AADD}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "qxldod Package", "qxldod Package\qxldod Package.vcxproj", "{B8C04B51-4207-491D-A7DD-C54861E8B528}" + ProjectSection(ProjectDependencies) = postProject + {A6F48FC7-97E9-48EC-BCDF-1E4F9B43AADD} = {A6F48FC7-97E9-48EC-BCDF-1E4F9B43AADD} + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Win8 Debug|Win32 = Win8 Debug|Win32 + Win8 Debug|x64 = Win8 Debug|x64 + Win8 Release|Win32 = Win8 Release|Win32 + Win8 Release|x64 = Win8 Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {A6F48FC7-97E9-48EC-BCDF-1E4F9B43AADD}.Win8 Debug|Win32.ActiveCfg = Win8 Debug|Win32 + {A6F48FC7-97E9-48EC-BCDF-1E4F9B43AADD}.Win8 Debug|Win32.Build.0 = Win8 Debug|Win32 + {A6F48FC7-97E9-48EC-BCDF-1E4F9B43AADD}.Win8 Debug|Win32.Deploy.0 = Win8 Debug|Win32 + {A6F48FC7-97E9-48EC-BCDF-1E4F9B43AADD}.Win8 Debug|x64.ActiveCfg = Win8 Debug|x64 + {A6F48FC7-97E9-48EC-BCDF-1E4F9B43AADD}.Win8 Debug|x64.Build.0 = Win8 Debug|x64 + {A6F48FC7-97E9-48EC-BCDF-1E4F9B43AADD}.Win8 Debug|x64.Deploy.0 = Win8 Debug|x64 + {A6F48FC7-97E9-48EC-BCDF-1E4F9B43AADD}.Win8 Release|Win32.ActiveCfg = Win8 Release|Win32 + {A6F48FC7-97E9-48EC-BCDF-1E4F9B43AADD}.Win8 Release|Win32.Build.0 = Win8 Release|Win32 + {A6F48FC7-97E9-48EC-BCDF-1E4F9B43AADD}.Win8 Release|Win32.Deploy.0 = Win8 Release|Win32 + {A6F48FC7-97E9-48EC-BCDF-1E4F9B43AADD}.Win8 Release|x64.ActiveCfg = Win8 Release|x64 + {A6F48FC7-97E9-48EC-BCDF-1E4F9B43AADD}.Win8 Release|x64.Build.0 = Win8 Release|x64 + {A6F48FC7-97E9-48EC-BCDF-1E4F9B43AADD}.Win8 Release|x64.Deploy.0 = Win8 Release|x64 + {B8C04B51-4207-491D-A7DD-C54861E8B528}.Win8 Debug|Win32.ActiveCfg = Win8 Debug|Win32 + {B8C04B51-4207-491D-A7DD-C54861E8B528}.Win8 Debug|Win32.Build.0 = Win8 Debug|Win32 + {B8C04B51-4207-491D-A7DD-C54861E8B528}.Win8 Debug|Win32.Deploy.0 = Win8 Debug|Win32 + {B8C04B51-4207-491D-A7DD-C54861E8B528}.Win8 Debug|x64.ActiveCfg = Win8 Debug|x64 + {B8C04B51-4207-491D-A7DD-C54861E8B528}.Win8 Debug|x64.Build.0 = Win8 Debug|x64 + {B8C04B51-4207-491D-A7DD-C54861E8B528}.Win8 Debug|x64.Deploy.0 = Win8 Debug|x64 + {B8C04B51-4207-491D-A7DD-C54861E8B528}.Win8 Release|Win32.ActiveCfg = Win8 Release|Win32 + {B8C04B51-4207-491D-A7DD-C54861E8B528}.Win8 Release|Win32.Build.0 = Win8 Release|Win32 + {B8C04B51-4207-491D-A7DD-C54861E8B528}.Win8 Release|Win32.Deploy.0 = Win8 Release|Win32 + {B8C04B51-4207-491D-A7DD-C54861E8B528}.Win8 Release|x64.ActiveCfg = Win8 Release|x64 + {B8C04B51-4207-491D-A7DD-C54861E8B528}.Win8 Release|x64.Build.0 = Win8 Release|x64 + {B8C04B51-4207-491D-A7DD-C54861E8B528}.Win8 Release|x64.Deploy.0 = Win8 Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/qxldod/BaseObject.cpp b/qxldod/BaseObject.cpp new file mode 100755 index 0000000..0405541 --- /dev/null +++ b/qxldod/BaseObject.cpp @@ -0,0 +1,80 @@ +#include "BaseObject.h" + +#pragma code_seg("PAGE") + +#define QXLTAG 'LXQd' + +// +// New and delete operators +// +_When_((PoolType & NonPagedPoolMustSucceed) != 0, + __drv_reportError("Must succeed pool allocations are forbidden. " + "Allocation failures cause a system crash")) +void* __cdecl operator new(size_t Size, POOL_TYPE PoolType) +{ + PAGED_CODE(); + + Size = (Size != 0) ? Size : 1; + + void* pObject = ExAllocatePoolWithTag(PoolType, Size, QXLTAG); + +#if DBG + if (pObject != NULL) + { + RtlFillMemory(pObject, Size, 0xCD); + } +#endif // DBG + + return pObject; +} + +_When_((PoolType & NonPagedPoolMustSucceed) != 0, + __drv_reportError("Must succeed pool allocations are forbidden. " + "Allocation failures cause a system crash")) +void* __cdecl operator new[](size_t Size, POOL_TYPE PoolType) +{ + PAGED_CODE(); + + Size = (Size != 0) ? Size : 1; + + void* pObject = ExAllocatePoolWithTag(PoolType, Size, QXLTAG); + +#if DBG + if (pObject != NULL) + { + RtlFillMemory(pObject, Size, 0xCD); + } +#endif // DBG + + return pObject; +} + +void __cdecl operator delete(void* pObject) +{ + PAGED_CODE(); + + if (pObject != NULL) + { + ExFreePool(pObject); + } +} + +void __cdecl operator delete[](void* pObject) +{ + PAGED_CODE(); + + if (pObject != NULL) + { + ExFreePool(pObject); + } +} + + +BaseObject::BaseObject(void) +{ +} + + +BaseObject::~BaseObject(void) +{ +} diff --git a/qxldod/BaseObject.h b/qxldod/BaseObject.h new file mode 100755 index 0000000..fc4ca59 --- /dev/null +++ b/qxldod/BaseObject.h @@ -0,0 +1,70 @@ +#pragma once +extern "C" +{ + #define __CPLUSPLUS + + // Standard C-runtime headers + #include + #include + #include + #include + #include + + #include + + // NTOS headers + #include + + #ifndef FAR + #define FAR + #endif + + // Windows headers + #include + #include + + // Windows GDI headers + #include + + // Windows DDI headers + #include + #include + + #include + #include + + #include + #include + + #include +}; + +// +// Memory handling +// + +// Defaulting the value of PoolType means that any call to new Foo() +// will raise a compiler error for being ambiguous. This is to help keep +// any calls to allocate memory from accidentally NOT going through +// these functions. +_When_((PoolType & NonPagedPoolMustSucceed) != 0, + __drv_reportError("Must succeed pool allocations are forbidden. " + "Allocation failures cause a system crash")) +void* __cdecl operator new(size_t Size, POOL_TYPE PoolType = PagedPool); +_When_((PoolType & NonPagedPoolMustSucceed) != 0, + __drv_reportError("Must succeed pool allocations are forbidden. " + "Allocation failures cause a system crash")) +void* __cdecl operator new[](size_t Size, POOL_TYPE PoolType = PagedPool); +void __cdecl operator delete(void* pObject); +void __cdecl operator delete[](void* pObject); + +// Pool allocation tag for the Sample Display Driver. All allocations use this tag. + + +class BaseObject +{ +public: + BaseObject(void); + ~BaseObject(void); +}; + diff --git a/qxldod/QxlDod.cpp b/qxldod/QxlDod.cpp new file mode 100755 index 0000000..9717c7d --- /dev/null +++ b/qxldod/QxlDod.cpp @@ -0,0 +1,1074 @@ +#include "driver.h" +#include "qxldod.h" + +QxlDod::QxlDod(_In_ DEVICE_OBJECT* pPhysicalDeviceObject) : m_pPhysicalDevice(pPhysicalDeviceObject), + m_MonitorPowerState(PowerDeviceD0), + m_AdapterPowerState(PowerDeviceD0) +{ + DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__)); + *((UINT*)&m_Flags) = 0; + RtlZeroMemory(&m_DxgkInterface, sizeof(m_DxgkInterface)); + RtlZeroMemory(&m_DeviceInfo, sizeof(m_DeviceInfo)); + + DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__)); +} + + +QxlDod::~QxlDod(void) +{ + PAGED_CODE(); + DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__)); + +// CleanUp(); + DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__)); +} + + +NTSTATUS QxlDod::StartDevice(_In_ DXGK_START_INFO* pDxgkStartInfo, + _In_ DXGKRNL_INTERFACE* pDxgkInterface, + _Out_ ULONG* pNumberOfViews, + _Out_ ULONG* pNumberOfChildren) +{ + PAGED_CODE(); + DbgPrint(TRACE_LEVEL_INFORMATION, ("---> %s\n", __FUNCTION__)); + QXL_ASSERT(pDxgkStartInfo != NULL); + QXL_ASSERT(pDxgkInterface != NULL); + QXL_ASSERT(pNumberOfViews != NULL); + QXL_ASSERT(pNumberOfChildren != NULL); + DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__)); + + DXGK_DISPLAY_INFORMATION DisplayInfo; + RtlCopyMemory(&m_DxgkInterface, pDxgkInterface, sizeof(m_DxgkInterface)); + // Get device information from OS. + NTSTATUS Status = m_DxgkInterface.DxgkCbGetDeviceInformation(m_DxgkInterface.DeviceHandle, &m_DeviceInfo); + if (!NT_SUCCESS(Status)) + { + QXL_LOG_ASSERTION1("DxgkCbGetDeviceInformation failed with status 0x%X\n", + Status); + return Status; + } + + Status = RegisterHWInfo(); + if (!NT_SUCCESS(Status)) + { + QXL_LOG_ASSERTION1("RegisterHWInfo failed with status 0x%X\n", + Status); + return Status; + } + +// TODO: Uncomment the line below after updating the TODOs in the function CheckHardware +// Status = CheckHardware(); +// if (!NT_SUCCESS(Status)) +// { +// return Status; +// } + + + Status = VbeGetModeList(); + if (!NT_SUCCESS(Status)) + { + QXL_LOG_ASSERTION1("RegisterHWInfo failed with status 0x%X\n", + Status); + return Status; + } + + + // This sample driver only uses the frame buffer of the POST device. DxgkCbAcquirePostDisplayOwnership + // gives you the frame buffer address and ensures that no one else is drawing to it. Be sure to give it back! + Status = m_DxgkInterface.DxgkCbAcquirePostDisplayOwnership(m_DxgkInterface.DeviceHandle, &DisplayInfo); + if (!NT_SUCCESS(Status) || DisplayInfo.Width == 0) + { + // The most likely cause of failure is that the driver is simply not running on a POST device, or we are running + // after a pre-WDDM 1.2 driver. Since we can't draw anything, we should fail to start. + return STATUS_UNSUCCESSFUL; + } + *pNumberOfViews = MAX_VIEWS; + *pNumberOfChildren = MAX_CHILDREN; + m_Flags.DriverStarted = TRUE; + return STATUS_SUCCESS; +} + +NTSTATUS QxlDod::StopDevice(VOID) +{ + PAGED_CODE(); + DbgPrint(TRACE_LEVEL_INFORMATION, ("---> %s\n", __FUNCTION__)); + + DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__)); + m_Flags.DriverStarted = FALSE; + return STATUS_SUCCESS; +} + +VOID QxlDod::CleanUp(VOID) +{ + PAGED_CODE(); + DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__)); + DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__)); +} + + +NTSTATUS QxlDod::DispatchIoRequest(_In_ ULONG VidPnSourceId, + _In_ VIDEO_REQUEST_PACKET* pVideoRequestPacket) +{ + PAGED_CODE(); + UNREFERENCED_PARAMETER(VidPnSourceId); + UNREFERENCED_PARAMETER(pVideoRequestPacket); + + DbgPrint(TRACE_LEVEL_INFORMATION, ("---> %s\n", __FUNCTION__)); + return STATUS_SUCCESS; +} + +NTSTATUS QxlDod::SetPowerState(_In_ ULONG HardwareUid, + _In_ DEVICE_POWER_STATE DevicePowerState, + _In_ POWER_ACTION ActionType) +{ + NTSTATUS Status = STATUS_SUCCESS; + PAGED_CODE(); + DbgPrint(TRACE_LEVEL_INFORMATION, ("---> %s\n", __FUNCTION__)); + + if (HardwareUid == DISPLAY_ADAPTER_HW_ID) + { + + if (DevicePowerState == PowerDeviceD0) + { + + // When returning from D3 the device visibility defined to be off for all targets + if (m_AdapterPowerState == PowerDeviceD3) + { + DXGKARG_SETVIDPNSOURCEVISIBILITY Visibility; + Visibility.VidPnSourceId = D3DDDI_ID_ALL; + Visibility.Visible = FALSE; + SetVidPnSourceVisibility(&Visibility); + } + } + + + // Store new adapter power state + m_AdapterPowerState = DevicePowerState; + } + + if ((ActionType == PowerActionHibernate) && + (DevicePowerState > PowerDeviceD0)) + { + ActionType = PowerActionHibernate; + } + else if ((ActionType >= PowerActionShutdown) && + (ActionType < PowerActionWarmEject) && + (DevicePowerState > PowerDeviceD0)) + { + ActionType = PowerActionShutdown; + } + + Status = VbeSetPowerState(ActionType); + DbgPrint(TRACE_LEVEL_INFORMATION, ("<--- %s\n", __FUNCTION__)); + + return Status; +} + + +NTSTATUS QxlDod::QueryChildRelations(_Out_writes_bytes_(ChildRelationsSize) DXGK_CHILD_DESCRIPTOR* pChildRelations, + _In_ ULONG ChildRelationsSize) +{ + PAGED_CODE(); + + DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__)); + QXL_ASSERT(pChildRelations != NULL); + + // The last DXGK_CHILD_DESCRIPTOR in the array of pChildRelations must remain zeroed out, so we subtract this from the count + ULONG ChildRelationsCount = (ChildRelationsSize / sizeof(DXGK_CHILD_DESCRIPTOR)) - 1; + QXL_ASSERT(ChildRelationsCount <= MAX_CHILDREN); + + for (UINT ChildIndex = 0; ChildIndex < ChildRelationsCount; ++ChildIndex) + { + pChildRelations[ChildIndex].ChildDeviceType = TypeVideoOutput; + pChildRelations[ChildIndex].ChildCapabilities.HpdAwareness = HpdAwarenessAlwaysConnected; + pChildRelations[ChildIndex].ChildCapabilities.Type.VideoOutput.InterfaceTechnology = D3DKMDT_VOT_INTERNAL; + pChildRelations[ChildIndex].ChildCapabilities.Type.VideoOutput.MonitorOrientationAwareness = D3DKMDT_MOA_NONE; + pChildRelations[ChildIndex].ChildCapabilities.Type.VideoOutput.SupportsSdtvModes = FALSE; + // TODO: Replace 0 with the actual ACPI ID of the child device, if available + pChildRelations[ChildIndex].AcpiUid = 0; + pChildRelations[ChildIndex].ChildUid = ChildIndex; + } + + DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__)); + return STATUS_SUCCESS; +} + +NTSTATUS QxlDod::QueryChildStatus(_Inout_ DXGK_CHILD_STATUS* pChildStatus, + _In_ BOOLEAN NonDestructiveOnly) +{ + PAGED_CODE(); + DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__)); + UNREFERENCED_PARAMETER(NonDestructiveOnly); + QXL_ASSERT(pChildStatus != NULL); + QXL_ASSERT(pChildStatus->ChildUid < MAX_CHILDREN); + + switch (pChildStatus->Type) + { + case StatusConnection: + { + // HpdAwarenessInterruptible was reported since HpdAwarenessNone is deprecated. + // However, BDD has no knowledge of HotPlug events, so just always return connected. + pChildStatus->HotPlug.Connected = IsDriverActive(); + return STATUS_SUCCESS; + } + + case StatusRotation: + { + // D3DKMDT_MOA_NONE was reported, so this should never be called + DbgPrint(TRACE_LEVEL_ERROR, ("Child status being queried for StatusRotation even though D3DKMDT_MOA_NONE was reported")); + return STATUS_INVALID_PARAMETER; + } + + default: + { + DbgPrint(TRACE_LEVEL_WARNING, ("Unknown pChildStatus->Type (0x%I64x) requested.", pChildStatus->Type)); + return STATUS_NOT_SUPPORTED; + } + } +} + +// EDID retrieval +NTSTATUS QxlDod::QueryDeviceDescriptor(_In_ ULONG ChildUid, + _Inout_ DXGK_DEVICE_DESCRIPTOR* pDeviceDescriptor) +{ + PAGED_CODE(); + DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__)); + QXL_ASSERT(pDeviceDescriptor != NULL); + QXL_ASSERT(ChildUid < MAX_CHILDREN); + + DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__)); + return STATUS_MONITOR_NO_MORE_DESCRIPTOR_DATA; +} + +NTSTATUS QxlDod::QueryAdapterInfo(_In_ CONST DXGKARG_QUERYADAPTERINFO* pQueryAdapterInfo) +{ + PAGED_CODE(); + + QXL_ASSERT(pQueryAdapterInfo != NULL); + DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__)); + + switch (pQueryAdapterInfo->Type) + { + case DXGKQAITYPE_DRIVERCAPS: + { + if (pQueryAdapterInfo->OutputDataSize < sizeof(DXGK_DRIVERCAPS)) + { + DbgPrint(TRACE_LEVEL_ERROR, ("pQueryAdapterInfo->OutputDataSize (0x%I64x) is smaller than sizeof(DXGK_DRIVERCAPS) (0x%I64x)", pQueryAdapterInfo->OutputDataSize, sizeof(DXGK_DRIVERCAPS))); + return STATUS_BUFFER_TOO_SMALL; + } + + DXGK_DRIVERCAPS* pDriverCaps = (DXGK_DRIVERCAPS*)pQueryAdapterInfo->pOutputData; + + RtlZeroMemory(pDriverCaps, sizeof(DXGK_DRIVERCAPS)); + + pDriverCaps->WDDMVersion = DXGKDDI_WDDMv1_2; + pDriverCaps->HighestAcceptableAddress.QuadPart = -1; + DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s 1\n", __FUNCTION__)); + return STATUS_SUCCESS; + } + + default: + { + // BDD does not need to support any other adapter information types + DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__)); + return STATUS_NOT_SUPPORTED; + } + } +} + +NTSTATUS QxlDod::SetPointerPosition(_In_ CONST DXGKARG_SETPOINTERPOSITION* pSetPointerPosition) +{ + PAGED_CODE(); + DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__)); + + QXL_ASSERT(pSetPointerPosition != NULL); + QXL_ASSERT(pSetPointerPosition->VidPnSourceId < MAX_VIEWS); + + if (!(pSetPointerPosition->Flags.Visible)) + { + DbgPrint(TRACE_LEVEL_INFORMATION, ("<--- %s Cursor is not visible\n", __FUNCTION__)); + return STATUS_SUCCESS; + } + DbgPrint(TRACE_LEVEL_INFORMATION, ("<--- %s cursor position X = %d, Y = %d\n", __FUNCTION__, pSetPointerPosition->X, pSetPointerPosition->Y)); + return STATUS_UNSUCCESSFUL; +} + +// Basic Sample Display Driver does not support hardware cursors, and reports such +// in QueryAdapterInfo. Therefore this function should never be called. +NTSTATUS QxlDod::SetPointerShape(_In_ CONST DXGKARG_SETPOINTERSHAPE* pSetPointerShape) +{ + PAGED_CODE(); + QXL_ASSERT(pSetPointerShape != NULL); + + DbgPrint(TRACE_LEVEL_VERBOSE, ("<---> %s Height = %d, Width = %d, XHot= %d, YHot = %d\n", __FUNCTION__, pSetPointerShape->Height, pSetPointerShape->Width, pSetPointerShape->XHot, pSetPointerShape->YHot)); + + if (pSetPointerShape->Flags.Color) + { + } + else if (pSetPointerShape->Flags.Monochrome) + { + } + else + { + return STATUS_UNSUCCESSFUL; + } + + return STATUS_NOT_IMPLEMENTED; +} + +NTSTATUS QxlDod::Escape(_In_ CONST DXGKARG_ESCAPE* pEscape) +{ + PAGED_CODE(); + QXL_ASSERT(pEscape != NULL); + + DbgPrint(TRACE_LEVEL_VERBOSE, ("<---> %s Flags = %d\n", __FUNCTION__, pEscape->Flags)); + + return STATUS_NOT_IMPLEMENTED; +} + + +NTSTATUS QxlDod::PresentDisplayOnly(_In_ CONST DXGKARG_PRESENT_DISPLAYONLY* pPresentDisplayOnly) +{ + PAGED_CODE(); + + DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__)); + QXL_ASSERT(pPresentDisplayOnly != NULL); + QXL_ASSERT(pPresentDisplayOnly->VidPnSourceId < MAX_VIEWS); + + DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__)); + return STATUS_SUCCESS; +} + +NTSTATUS QxlDod::QueryInterface(_In_ CONST PQUERY_INTERFACE pQueryInterface) +{ + PAGED_CODE(); + QXL_ASSERT(pQueryInterface != NULL); + + DbgPrint(TRACE_LEVEL_VERBOSE, ("<---> %s Version = %d\n", __FUNCTION__, pQueryInterface->Version)); + + return STATUS_NOT_IMPLEMENTED; +} + +NTSTATUS QxlDod::StopDeviceAndReleasePostDisplayOwnership(_In_ D3DDDI_VIDEO_PRESENT_TARGET_ID TargetId, + _Out_ DXGK_DISPLAY_INFORMATION* pDisplayInfo) +{ + PAGED_CODE(); + + UNREFERENCED_PARAMETER(pDisplayInfo); + QXL_ASSERT(TargetId < MAX_CHILDREN); + + DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__)); + return StopDevice(); +} + +NTSTATUS QxlDod::QueryVidPnHWCapability(_Inout_ DXGKARG_QUERYVIDPNHWCAPABILITY* pVidPnHWCaps) +{ + PAGED_CODE(); + DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__)); + + QXL_ASSERT(pVidPnHWCaps != NULL); + QXL_ASSERT(pVidPnHWCaps->SourceId < MAX_VIEWS); + QXL_ASSERT(pVidPnHWCaps->TargetId < MAX_CHILDREN); + + pVidPnHWCaps->VidPnHWCaps.DriverRotation = 1; // BDD does rotation in software + pVidPnHWCaps->VidPnHWCaps.DriverScaling = 0; // BDD does not support scaling + pVidPnHWCaps->VidPnHWCaps.DriverCloning = 0; // BDD does not support clone + pVidPnHWCaps->VidPnHWCaps.DriverColorConvert = 1; // BDD does color conversions in software + pVidPnHWCaps->VidPnHWCaps.DriverLinkedAdapaterOutput = 0; // BDD does not support linked adapters + pVidPnHWCaps->VidPnHWCaps.DriverRemoteDisplay = 0; // BDD does not support remote displays + + DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__)); + return STATUS_SUCCESS; +} + + +// TODO: Need to also check pinned modes and the path parameters, not just topology +NTSTATUS QxlDod::IsSupportedVidPn(_Inout_ DXGKARG_ISSUPPORTEDVIDPN* pIsSupportedVidPn) +{ + PAGED_CODE(); + DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__)); + + QXL_ASSERT(pIsSupportedVidPn != NULL); + + if (pIsSupportedVidPn->hDesiredVidPn == 0) + { + // A null desired VidPn is supported + pIsSupportedVidPn->IsVidPnSupported = TRUE; + return STATUS_SUCCESS; + } + + // Default to not supported, until shown it is supported + pIsSupportedVidPn->IsVidPnSupported = FALSE; + + CONST DXGK_VIDPN_INTERFACE* pVidPnInterface; + NTSTATUS Status = m_DxgkInterface.DxgkCbQueryVidPnInterface(pIsSupportedVidPn->hDesiredVidPn, DXGK_VIDPN_INTERFACE_VERSION_V1, &pVidPnInterface); + if (!NT_SUCCESS(Status)) + { + DbgPrint(TRACE_LEVEL_ERROR, ("DxgkCbQueryVidPnInterface failed with Status = 0x%X, hDesiredVidPn = 0x%I64x\n", Status, pIsSupportedVidPn->hDesiredVidPn)); + return Status; + } + + D3DKMDT_HVIDPNTOPOLOGY hVidPnTopology; + CONST DXGK_VIDPNTOPOLOGY_INTERFACE* pVidPnTopologyInterface; + Status = pVidPnInterface->pfnGetTopology(pIsSupportedVidPn->hDesiredVidPn, &hVidPnTopology, &pVidPnTopologyInterface); + if (!NT_SUCCESS(Status)) + { + DbgPrint(TRACE_LEVEL_ERROR, ("pfnGetTopology failed with Status = 0x%X, hDesiredVidPn = 0x%I64x\n", Status, pIsSupportedVidPn->hDesiredVidPn)); + return Status; + } + + // For every source in this topology, make sure they don't have more paths than there are targets + for (D3DDDI_VIDEO_PRESENT_SOURCE_ID SourceId = 0; SourceId < MAX_VIEWS; ++SourceId) + { + SIZE_T NumPathsFromSource = 0; + Status = pVidPnTopologyInterface->pfnGetNumPathsFromSource(hVidPnTopology, SourceId, &NumPathsFromSource); + if (Status == STATUS_GRAPHICS_SOURCE_NOT_IN_TOPOLOGY) + { + continue; + } + else if (!NT_SUCCESS(Status)) + { + DbgPrint(TRACE_LEVEL_ERROR, ("pfnGetNumPathsFromSource failed with Status = 0x%X hVidPnTopology = 0x%I64x, SourceId = 0x%I64x", + Status, hVidPnTopology, SourceId)); + return Status; + } + else if (NumPathsFromSource > MAX_CHILDREN) + { + // This VidPn is not supported, which has already been set as the default + return STATUS_SUCCESS; + } + } + + // All sources succeeded so this VidPn is supported + pIsSupportedVidPn->IsVidPnSupported = TRUE; + DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__)); + return STATUS_SUCCESS; +} + +NTSTATUS QxlDod::RecommendFunctionalVidPn(_In_ CONST DXGKARG_RECOMMENDFUNCTIONALVIDPN* CONST pRecommendFunctionalVidPn) +{ + PAGED_CODE(); + DbgPrint(TRACE_LEVEL_VERBOSE, ("<---> %s\n", __FUNCTION__)); + + QXL_ASSERT(pRecommendFunctionalVidPn == NULL); + + return STATUS_GRAPHICS_NO_RECOMMENDED_FUNCTIONAL_VIDPN; +} + +NTSTATUS QxlDod::RecommendVidPnTopology(_In_ CONST DXGKARG_RECOMMENDVIDPNTOPOLOGY* CONST pRecommendVidPnTopology) +{ + PAGED_CODE(); + DbgPrint(TRACE_LEVEL_VERBOSE, ("<---> %s\n", __FUNCTION__)); + + QXL_ASSERT(pRecommendVidPnTopology == NULL); + + return STATUS_GRAPHICS_NO_RECOMMENDED_FUNCTIONAL_VIDPN; +} + +NTSTATUS QxlDod::RecommendMonitorModes(_In_ CONST DXGKARG_RECOMMENDMONITORMODES* CONST pRecommendMonitorModes) +{ + PAGED_CODE(); + NTSTATUS Status = STATUS_SUCCESS; + D3DKMDT_MONITOR_SOURCE_MODE* pMonitorSourceMode = NULL; + PVBE_MODEINFO pVbeModeInfo = NULL; + DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__)); + + Status = pRecommendMonitorModes->pMonitorSourceModeSetInterface->pfnCreateNewModeInfo(pRecommendMonitorModes->hMonitorSourceModeSet, &pMonitorSourceMode); + if (!NT_SUCCESS(Status)) + { + // If failed to create a new mode info, mode doesn't need to be released since it was never created + DbgPrint(TRACE_LEVEL_ERROR, ("pfnCreateNewModeInfo failed with Status = 0x%I64x, hMonitorSourceModeSet = 0x%I64x", Status, pRecommendMonitorModes->hMonitorSourceModeSet)); + return Status; + } + + pVbeModeInfo = &m_ModeInfo[m_CurrentMode]; + pMonitorSourceMode->VideoSignalInfo.VideoStandard = D3DKMDT_VSS_OTHER; + pMonitorSourceMode->VideoSignalInfo.TotalSize.cx = pVbeModeInfo->XResolution;//m_CurrentModes[CorrespondingSourceId].DispInfo.Width; + pMonitorSourceMode->VideoSignalInfo.TotalSize.cy = pVbeModeInfo->YResolution;//m_CurrentModes[CorrespondingSourceId].DispInfo.Height; + pMonitorSourceMode->VideoSignalInfo.ActiveSize = pMonitorSourceMode->VideoSignalInfo.TotalSize; + pMonitorSourceMode->VideoSignalInfo.VSyncFreq.Numerator = D3DKMDT_FREQUENCY_NOTSPECIFIED; + pMonitorSourceMode->VideoSignalInfo.VSyncFreq.Denominator = D3DKMDT_FREQUENCY_NOTSPECIFIED; + pMonitorSourceMode->VideoSignalInfo.HSyncFreq.Numerator = D3DKMDT_FREQUENCY_NOTSPECIFIED; + pMonitorSourceMode->VideoSignalInfo.HSyncFreq.Denominator = D3DKMDT_FREQUENCY_NOTSPECIFIED; + pMonitorSourceMode->VideoSignalInfo.PixelRate = D3DKMDT_FREQUENCY_NOTSPECIFIED; + pMonitorSourceMode->VideoSignalInfo.ScanLineOrdering = D3DDDI_VSSLO_PROGRESSIVE; + + // We set the preference to PREFERRED since this is the only supported mode + pMonitorSourceMode->Origin = D3DKMDT_MCO_DRIVER; + pMonitorSourceMode->Preference = D3DKMDT_MP_PREFERRED; + pMonitorSourceMode->ColorBasis = D3DKMDT_CB_SRGB; + pMonitorSourceMode->ColorCoeffDynamicRanges.FirstChannel = 8; + pMonitorSourceMode->ColorCoeffDynamicRanges.SecondChannel = 8; + pMonitorSourceMode->ColorCoeffDynamicRanges.ThirdChannel = 8; + pMonitorSourceMode->ColorCoeffDynamicRanges.FourthChannel = 8; + + Status = pRecommendMonitorModes->pMonitorSourceModeSetInterface->pfnAddMode(pRecommendMonitorModes->hMonitorSourceModeSet, pMonitorSourceMode); + if (!NT_SUCCESS(Status)) + { + if (Status != STATUS_GRAPHICS_MODE_ALREADY_IN_MODESET) + { + DbgPrint(TRACE_LEVEL_ERROR, ("pfnAddMode failed with Status = 0x%I64x, hMonitorSourceModeSet = 0x%I64x, pMonitorSourceMode = 0x%I64x", + Status, pRecommendMonitorModes->hMonitorSourceModeSet, pMonitorSourceMode)); + } + else + { + Status = STATUS_SUCCESS; + } + + // If adding the mode failed, release the mode, if this doesn't work there is nothing that can be done, some memory will get leaked + NTSTATUS TempStatus = pRecommendMonitorModes->pMonitorSourceModeSetInterface->pfnReleaseModeInfo(pRecommendMonitorModes->hMonitorSourceModeSet, pMonitorSourceMode); + UNREFERENCED_PARAMETER(TempStatus); + NT_ASSERT(NT_SUCCESS(TempStatus)); + return Status; + } + // If AddMode succeeded with something other than STATUS_SUCCESS treat it as such anyway when propagating up + return STATUS_SUCCESS; +} + +// Tell DMM about all the modes, etc. that are supported +NTSTATUS QxlDod::EnumVidPnCofuncModality(_In_ CONST DXGKARG_ENUMVIDPNCOFUNCMODALITY* CONST pEnumCofuncModality) +{ + PAGED_CODE(); + + QXL_ASSERT(pEnumCofuncModality != NULL); + DbgPrint(TRACE_LEVEL_FATAL, ("---> %s\n", __FUNCTION__)); + + D3DKMDT_HVIDPNTOPOLOGY hVidPnTopology = 0; + D3DKMDT_HVIDPNSOURCEMODESET hVidPnSourceModeSet = 0; + D3DKMDT_HVIDPNTARGETMODESET hVidPnTargetModeSet = 0; + CONST DXGK_VIDPN_INTERFACE* pVidPnInterface = NULL; + CONST DXGK_VIDPNTOPOLOGY_INTERFACE* pVidPnTopologyInterface = NULL; + CONST DXGK_VIDPNSOURCEMODESET_INTERFACE* pVidPnSourceModeSetInterface = NULL; + CONST DXGK_VIDPNTARGETMODESET_INTERFACE* pVidPnTargetModeSetInterface = NULL; + CONST D3DKMDT_VIDPN_PRESENT_PATH* pVidPnPresentPath = NULL; + CONST D3DKMDT_VIDPN_PRESENT_PATH* pVidPnPresentPathTemp = NULL; // Used for AcquireNextPathInfo + CONST D3DKMDT_VIDPN_SOURCE_MODE* pVidPnPinnedSourceModeInfo = NULL; + CONST D3DKMDT_VIDPN_TARGET_MODE* pVidPnPinnedTargetModeInfo = NULL; + + // Get the VidPn Interface so we can get the 'Source Mode Set', 'Target Mode Set' and 'VidPn Topology' interfaces + NTSTATUS Status = m_DxgkInterface.DxgkCbQueryVidPnInterface(pEnumCofuncModality->hConstrainingVidPn, DXGK_VIDPN_INTERFACE_VERSION_V1, &pVidPnInterface); + if (!NT_SUCCESS(Status)) + { + DbgPrint(TRACE_LEVEL_ERROR, ("DxgkCbQueryVidPnInterface failed with Status = 0x%X, hFunctionalVidPn = 0x%I64x", Status, pEnumCofuncModality->hConstrainingVidPn)); + return Status; + } + + // Get the VidPn Topology interface so we can enumerate all paths + Status = pVidPnInterface->pfnGetTopology(pEnumCofuncModality->hConstrainingVidPn, &hVidPnTopology, &pVidPnTopologyInterface); + if (!NT_SUCCESS(Status)) + { + DbgPrint(TRACE_LEVEL_ERROR, ("pfnGetTopology failed with Status = 0x%X, hFunctionalVidPn = 0x%I64x", Status, pEnumCofuncModality->hConstrainingVidPn)); + return Status; + } + + // Get the first path before we start looping through them + Status = pVidPnTopologyInterface->pfnAcquireFirstPathInfo(hVidPnTopology, &pVidPnPresentPath); + if (!NT_SUCCESS(Status)) + { + DbgPrint(TRACE_LEVEL_ERROR, ("pfnAcquireFirstPathInfo failed with Status =0x%X, hVidPnTopology = 0x%I64x", Status, hVidPnTopology)); + return Status; + } + + // Loop through all available paths. + while (Status != STATUS_GRAPHICS_NO_MORE_ELEMENTS_IN_DATASET) + { + +//FIXME + + pVidPnPresentPathTemp = NULL; // Successfully released it + }// End: while loop for paths in topology + + // If quit the while loop normally, set the return value to success + if (Status == STATUS_GRAPHICS_NO_MORE_ELEMENTS_IN_DATASET) + { + Status = STATUS_SUCCESS; + } + + // Release any resources hanging around because the loop was quit early. + // Since in normal execution everything should be released by this point, TempStatus is initialized to a bogus error to be used as an + // assertion that if anything had to be released now (TempStatus changing) Status isn't successful. + NTSTATUS TempStatus = STATUS_NOT_FOUND; + + if ((pVidPnSourceModeSetInterface != NULL) && + (pVidPnPinnedSourceModeInfo != NULL)) + { + TempStatus = pVidPnSourceModeSetInterface->pfnReleaseModeInfo(hVidPnSourceModeSet, pVidPnPinnedSourceModeInfo); + QXL_ASSERT_CHK(NT_SUCCESS(TempStatus)); + } + + if ((pVidPnTargetModeSetInterface != NULL) && + (pVidPnPinnedTargetModeInfo != NULL)) + { + TempStatus = pVidPnTargetModeSetInterface->pfnReleaseModeInfo(hVidPnTargetModeSet, pVidPnPinnedTargetModeInfo); + QXL_ASSERT_CHK(NT_SUCCESS(TempStatus)); + } + + if (pVidPnPresentPath != NULL) + { + TempStatus = pVidPnTopologyInterface->pfnReleasePathInfo(hVidPnTopology, pVidPnPresentPath); + QXL_ASSERT_CHK(NT_SUCCESS(TempStatus)); + } + + if (pVidPnPresentPathTemp != NULL) + { + TempStatus = pVidPnTopologyInterface->pfnReleasePathInfo(hVidPnTopology, pVidPnPresentPathTemp); + QXL_ASSERT_CHK(NT_SUCCESS(TempStatus)); + } + + if (hVidPnSourceModeSet != 0) + { + TempStatus = pVidPnInterface->pfnReleaseSourceModeSet(pEnumCofuncModality->hConstrainingVidPn, hVidPnSourceModeSet); + QXL_ASSERT_CHK(NT_SUCCESS(TempStatus)); + } + + if (hVidPnTargetModeSet != 0) + { + TempStatus = pVidPnInterface->pfnReleaseTargetModeSet(pEnumCofuncModality->hConstrainingVidPn, hVidPnTargetModeSet); + QXL_ASSERT_CHK(NT_SUCCESS(TempStatus)); + } + + QXL_ASSERT_CHK(TempStatus == STATUS_NOT_FOUND || Status != STATUS_SUCCESS); + + DbgPrint(TRACE_LEVEL_FATAL, ("<--- %s\n", __FUNCTION__)); + return Status; +} + +NTSTATUS QxlDod::SetVidPnSourceVisibility(_In_ CONST DXGKARG_SETVIDPNSOURCEVISIBILITY* pSetVidPnSourceVisibility) +{ + PAGED_CODE(); + DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__)); + QXL_ASSERT(pSetVidPnSourceVisibility != NULL); + QXL_ASSERT((pSetVidPnSourceVisibility->VidPnSourceId < MAX_VIEWS) || + (pSetVidPnSourceVisibility->VidPnSourceId == D3DDDI_ID_ALL)); + + UINT StartVidPnSourceId = (pSetVidPnSourceVisibility->VidPnSourceId == D3DDDI_ID_ALL) ? 0 : pSetVidPnSourceVisibility->VidPnSourceId; + UINT MaxVidPnSourceId = (pSetVidPnSourceVisibility->VidPnSourceId == D3DDDI_ID_ALL) ? MAX_VIEWS : pSetVidPnSourceVisibility->VidPnSourceId + 1; + + for (UINT SourceId = StartVidPnSourceId; SourceId < MaxVidPnSourceId; ++SourceId) + { + if (pSetVidPnSourceVisibility->Visible) + { +// m_CurrentModes[SourceId].Flags.FullscreenPresent = TRUE; + } + else + { +// BlackOutScreen(SourceId); + } + + // Store current visibility so it can be dealt with during Present call +// m_CurrentModes[SourceId].Flags.SourceNotVisible = !(pSetVidPnSourceVisibility->Visible); + } + + DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__)); + return STATUS_SUCCESS; +} + +// NOTE: The value of pCommitVidPn->MonitorConnectivityChecks is ignored, since BDD is unable to recognize whether a monitor is connected or not +// The value of pCommitVidPn->hPrimaryAllocation is also ignored, since BDD is a display only driver and does not deal with allocations +NTSTATUS QxlDod::CommitVidPn(_In_ CONST DXGKARG_COMMITVIDPN* CONST pCommitVidPn) +{ + PAGED_CODE(); + DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__)); + QXL_ASSERT(pCommitVidPn != NULL); + QXL_ASSERT(pCommitVidPn->AffectedVidPnSourceId < MAX_VIEWS); + + NTSTATUS Status = STATUS_SUCCESS; + + +//FIXME + + + DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__)); + return Status; +} + +NTSTATUS QxlDod::UpdateActiveVidPnPresentPath(_In_ CONST DXGKARG_UPDATEACTIVEVIDPNPRESENTPATH* CONST pUpdateActiveVidPnPresentPath) +{ + PAGED_CODE(); + DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__)); + QXL_ASSERT(pUpdateActiveVidPnPresentPath != NULL); + + DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__)); + return STATUS_SUCCESS; +} + + + +// +// Non-Paged Code +// +#pragma code_seg(push) +#pragma code_seg() + +VOID QxlDod::DpcRoutine(VOID) +{ + DbgPrint(TRACE_LEVEL_INFORMATION, ("---> %s\n", __FUNCTION__)); + m_DxgkInterface.DxgkCbNotifyDpc((HANDLE)m_DxgkInterface.DeviceHandle); + DbgPrint(TRACE_LEVEL_INFORMATION, ("<--- %s\n", __FUNCTION__)); +} + +BOOLEAN QxlDod::InterruptRoutine(_In_ ULONG MessageNumber) +{ + UNREFERENCED_PARAMETER(MessageNumber); + + DbgPrint(TRACE_LEVEL_INFORMATION, ("---> 0 %s\n", __FUNCTION__)); + DbgPrint(TRACE_LEVEL_INFORMATION, ("<--- %s\n", __FUNCTION__)); + return TRUE; +} + +VOID QxlDod::ResetDevice(VOID) +{ + DbgPrint(TRACE_LEVEL_VERBOSE, ("<---> %s\n", __FUNCTION__)); +} + +// Must be Non-Paged, as it sets up the display for a bugcheck +NTSTATUS QxlDod::SystemDisplayEnable(_In_ D3DDDI_VIDEO_PRESENT_TARGET_ID TargetId, + _In_ PDXGKARG_SYSTEM_DISPLAY_ENABLE_FLAGS Flags, + _Out_ UINT* pWidth, + _Out_ UINT* pHeight, + _Out_ D3DDDIFORMAT* pColorFormat) +{ + UNREFERENCED_PARAMETER(Flags); + UNREFERENCED_PARAMETER(pColorFormat); + UNREFERENCED_PARAMETER(pWidth); + UNREFERENCED_PARAMETER(pHeight); + QXL_ASSERT((TargetId < MAX_CHILDREN) || (TargetId == D3DDDI_ID_UNINITIALIZED)); + + return STATUS_SUCCESS; +} + +// Must be Non-Paged, as it is called to display the bugcheck screen +VOID QxlDod::SystemDisplayWrite(_In_reads_bytes_(SourceHeight * SourceStride) VOID* pSource, + _In_ UINT SourceWidth, + _In_ UINT SourceHeight, + _In_ UINT SourceStride, + _In_ INT PositionX, + _In_ INT PositionY) +{ + UNREFERENCED_PARAMETER(pSource); + UNREFERENCED_PARAMETER(SourceStride); + // Rect will be Offset by PositionX/Y in the src to reset it back to 0 + RECT Rect; + Rect.left = PositionX; + Rect.top = PositionY; + Rect.right = Rect.left + SourceWidth; + Rect.bottom = Rect.top + SourceHeight; + +} + +#pragma code_seg(pop) // End Non-Paged Code + + + +NTSTATUS QxlDod::WriteHWInfoStr(_In_ HANDLE DevInstRegKeyHandle, _In_ PCWSTR pszwValueName, _In_ PCSTR pszValue) +{ + PAGED_CODE(); + + NTSTATUS Status; + ANSI_STRING AnsiStrValue; + UNICODE_STRING UnicodeStrValue; + UNICODE_STRING UnicodeStrValueName; + DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__)); + + // ZwSetValueKey wants the ValueName as a UNICODE_STRING + RtlInitUnicodeString(&UnicodeStrValueName, pszwValueName); + + // REG_SZ is for WCHARs, there is no equivalent for CHARs + // Use the ansi/unicode conversion functions to get from PSTR to PWSTR + RtlInitAnsiString(&AnsiStrValue, pszValue); + Status = RtlAnsiStringToUnicodeString(&UnicodeStrValue, &AnsiStrValue, TRUE); + if (!NT_SUCCESS(Status)) + { + DbgPrint(TRACE_LEVEL_ERROR, ("RtlAnsiStringToUnicodeString failed with Status: 0x%X\n", Status)); + return Status; + } + + // Write the value to the registry + Status = ZwSetValueKey(DevInstRegKeyHandle, + &UnicodeStrValueName, + 0, + REG_SZ, + UnicodeStrValue.Buffer, + UnicodeStrValue.MaximumLength); + + // Free the earlier allocated unicode string + RtlFreeUnicodeString(&UnicodeStrValue); + + if (!NT_SUCCESS(Status)) + { + DbgPrint(TRACE_LEVEL_ERROR, ("ZwSetValueKey failed with Status: 0x%X\n", Status)); + } + + DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__)); + return Status; +} + +NTSTATUS QxlDod::RegisterHWInfo() +{ + PAGED_CODE(); + + NTSTATUS Status; + DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__)); + + // TODO: Replace these strings with proper information + PCSTR StrHWInfoChipType = "QEMU QXL"; + PCSTR StrHWInfoDacType = "QXL 1B36"; + PCSTR StrHWInfoAdapterString = "QXL"; + PCSTR StrHWInfoBiosString = "SEABIOS QXL"; + + HANDLE DevInstRegKeyHandle; + Status = IoOpenDeviceRegistryKey(m_pPhysicalDevice, PLUGPLAY_REGKEY_DRIVER, KEY_SET_VALUE, &DevInstRegKeyHandle); + if (!NT_SUCCESS(Status)) + { + DbgPrint(TRACE_LEVEL_ERROR, ("IoOpenDeviceRegistryKey failed for PDO: 0x%I64x, Status: 0x%I64x", m_pPhysicalDevice, Status)); + return Status; + } + + Status = WriteHWInfoStr(DevInstRegKeyHandle, L"HardwareInformation.ChipType", StrHWInfoChipType); + if (!NT_SUCCESS(Status)) + { + return Status; + } + + Status = WriteHWInfoStr(DevInstRegKeyHandle, L"HardwareInformation.DacType", StrHWInfoDacType); + if (!NT_SUCCESS(Status)) + { + return Status; + } + + Status = WriteHWInfoStr(DevInstRegKeyHandle, L"HardwareInformation.AdapterString", StrHWInfoAdapterString); + if (!NT_SUCCESS(Status)) + { + return Status; + } + + Status = WriteHWInfoStr(DevInstRegKeyHandle, L"HardwareInformation.BiosString", StrHWInfoBiosString); + if (!NT_SUCCESS(Status)) + { + return Status; + } + + // MemorySize is a ULONG, unlike the others which are all strings + UNICODE_STRING ValueNameMemorySize; + RtlInitUnicodeString(&ValueNameMemorySize, L"HardwareInformation.MemorySize"); + DWORD MemorySize = 0; // BDD has no access to video memory + Status = ZwSetValueKey(DevInstRegKeyHandle, + &ValueNameMemorySize, + 0, + REG_DWORD, + &MemorySize, + sizeof(MemorySize)); + if (!NT_SUCCESS(Status)) + { + DbgPrint(TRACE_LEVEL_ERROR, ("ZwSetValueKey for MemorySize failed with Status: 0x%X\n", Status)); + return Status; + } + + DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__)); + return Status; +} + +NTSTATUS QxlDod::VbeGetModeList() +{ + PAGED_CODE(); + USHORT m_Segment; + USHORT m_Offset; + USHORT ModeCount; + ULONG SuitableModeCount; + USHORT ModeTemp; + USHORT CurrentMode; + PVBE_MODEINFO VbeModeInfo; + VBE_INFO VbeInfo = {0}; + ULONG Length; + + NTSTATUS Status = STATUS_SUCCESS; + DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__)); +//Get VBE Mode List + Length = 0x400; + Status = x86BiosAllocateBuffer (&Length, &m_Segment, &m_Offset); + if (!NT_SUCCESS (Status)) + { + DbgPrint(TRACE_LEVEL_ERROR, ("x86BiosAllocateBuffer failed with Status: 0x%X\n", Status)); + return Status; + } + DbgPrint(TRACE_LEVEL_ERROR, ("x86BiosAllocateBuffer 0x%x (%x.%x)\n", VbeInfo.VideoModePtr, m_Segment, m_Offset)); + + Status = x86BiosWriteMemory (m_Segment, m_Offset, "VBE2", 4); + + if (!NT_SUCCESS (Status)) + { + DbgPrint(TRACE_LEVEL_ERROR, ("x86BiosWriteMemory failed with Status: 0x%X\n", Status)); + return Status; + } + + X86BIOS_REGISTERS regs = {0}; + regs.SegEs = m_Segment; + regs.Edi = m_Offset; + regs.Eax = 0x4F00; + if (!x86BiosCall (0x10, ®s) /* || (regs.Eax & 0xFF00) != 0x4F00 */) + { + DbgPrint(TRACE_LEVEL_ERROR, ("x86BiosCall failed\n")); + return STATUS_UNSUCCESSFUL; + } + + Status = x86BiosReadMemory (m_Segment, m_Offset, &VbeInfo, sizeof (VbeInfo)); + if (!NT_SUCCESS (Status)) + { + DbgPrint(TRACE_LEVEL_ERROR, ("x86BiosReadMemory failed with Status: 0x%X\n", Status)); + return Status; + } + + if (!RtlEqualMemory(VbeInfo.Signature, "VESA", 4)) + { + DbgPrint(TRACE_LEVEL_ERROR, ("No VBE BIOS present\n")); + return STATUS_UNSUCCESSFUL; + } + + DbgPrint(TRACE_LEVEL_ERROR, ("VBE BIOS Present (%d.%d, %8ld Kb)\n", VbeInfo.Version / 0x100, VbeInfo.Version & 0xFF, VbeInfo.TotalMemory * 64)); + DbgPrint(TRACE_LEVEL_ERROR, ("Capabilities = 0x%x\n", VbeInfo.Capabilities)); + DbgPrint(TRACE_LEVEL_ERROR, ("VideoModePtr = 0x%x (0x%x.0x%x)\n", VbeInfo.VideoModePtr, HIWORD( VbeInfo.VideoModePtr), LOWORD( VbeInfo.VideoModePtr))); + + for (ModeCount = 0; ; ModeCount++) + { + /* Read the VBE mode number. */ + Status = x86BiosReadMemory ( + HIWORD(VbeInfo.VideoModePtr), + LOWORD(VbeInfo.VideoModePtr) + (ModeCount << 1), + &ModeTemp, + sizeof(ModeTemp)); + + if (!NT_SUCCESS (Status)) + { + DbgPrint(TRACE_LEVEL_ERROR, ("x86BiosReadMemory failed with Status: 0x%X\n", Status)); + break; + } + /* End of list? */ + if (ModeTemp == 0xFFFF || ModeTemp == 0) + { + break; + } + } + + DbgPrint(TRACE_LEVEL_ERROR, ("ModeCount %d\n", ModeCount)); + + m_ModeInfo = reinterpret_cast (new (PagedPool) BYTE[sizeof (VBE_MODEINFO) * ModeCount]); + m_ModeNumbers = reinterpret_cast (new (PagedPool) BYTE [sizeof (USHORT) * ModeCount]); + m_CurrentMode = 0; + DbgPrint(TRACE_LEVEL_ERROR, ("m_ModeInfo = 0x%p, m_ModeNumbers = 0x%p\n", m_ModeInfo, m_ModeNumbers)); + for (CurrentMode = 0, SuitableModeCount = 0; + CurrentMode < ModeCount; + CurrentMode++) + { + Status = x86BiosReadMemory ( + HIWORD(VbeInfo.VideoModePtr), + LOWORD(VbeInfo.VideoModePtr) + (CurrentMode << 1), + &ModeTemp, + sizeof(ModeTemp)); + + if (!NT_SUCCESS (Status)) + { + DbgPrint(TRACE_LEVEL_ERROR, ("x86BiosReadMemory failed with Status: 0x%X\n", Status)); + break; + } + + DbgPrint(TRACE_LEVEL_ERROR, ("ModeTemp = 0x%X\n", ModeTemp)); + RtlZeroMemory(®s, sizeof(regs)); + regs.Eax = 0x4F01; + regs.Ecx = ModeTemp; + regs.Edi = m_Offset + sizeof (VbeInfo); + regs.SegEs = m_Segment; + if (!x86BiosCall (0x10, ®s)) + { + DbgPrint(TRACE_LEVEL_ERROR, ("x86BiosCall failed\n")); + return STATUS_UNSUCCESSFUL; + } + Status = x86BiosReadMemory ( + m_Segment, + m_Offset + sizeof (VbeInfo), + m_ModeInfo + SuitableModeCount, + sizeof(VBE_MODEINFO)); + + VbeModeInfo = m_ModeInfo + SuitableModeCount; + + if (VbeModeInfo->XResolution >= 1024 && + VbeModeInfo->YResolution >= 768 && + VbeModeInfo->BitsPerPixel == 32 && + VbeModeInfo->PhysBasePtr != 0) + { + m_ModeNumbers[SuitableModeCount] = ModeTemp; + if (VbeModeInfo->XResolution == 1024 && + VbeModeInfo->YResolution == 768) + { + m_CurrentMode = (USHORT)SuitableModeCount; + } + SuitableModeCount++; + } + } + + if (SuitableModeCount == 0) + { + DbgPrint(TRACE_LEVEL_ERROR, ("No video modes supported\n")); + Status = STATUS_UNSUCCESSFUL; + } + + m_ModeCount = SuitableModeCount; + DbgPrint(TRACE_LEVEL_ERROR, ("ModeCount filtered %d\n", m_ModeCount)); + + if (m_Segment != 0) + { + x86BiosFreeBuffer (m_Segment, m_Offset); + } + DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__)); + return Status; +} + +NTSTATUS QxlDod::VbeQueryCurrentMode(PVIDEO_MODE RequestedMode) +{ + DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__)); + NTSTATUS Status = STATUS_SUCCESS; + PVBE_MODEINFO VBEMode = &m_ModeInfo[m_CurrentMode]; + + return Status; +} + +NTSTATUS QxlDod::VbeSetCurrentMode(PVIDEO_MODE RequestedMode) +{ + NTSTATUS Status = STATUS_SUCCESS; + DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__)); + X86BIOS_REGISTERS regs = {0}; + regs.Eax = 0x4F02; + regs.Edx = m_ModeNumbers[RequestedMode->RequestedMode]; + if (!x86BiosCall (0x10, ®s)) + { + DbgPrint(TRACE_LEVEL_ERROR, ("x86BiosCall failed\n")); + return STATUS_UNSUCCESSFUL; + } + m_CurrentMode = (USHORT)RequestedMode->RequestedMode; + DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__)); + return Status; +} + +NTSTATUS QxlDod::VbeSetPowerState(POWER_ACTION ActionType) +{ + NTSTATUS Status = STATUS_SUCCESS; + DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__)); + + X86BIOS_REGISTERS regs = {0}; + regs.Eax = 0x4F10; + regs.Ebx = 1; + switch (ActionType) + { + case PowerActionSleep: regs.Ebx |= 0x100; break; + case PowerActionHibernate: regs.Ebx |= 0x200; break; + case PowerActionShutdown: + case PowerActionShutdownReset: + case PowerActionShutdownOff: regs.Ebx |= 0x400; break; + } + if (!x86BiosCall (0x10, ®s)) + { + DbgPrint(TRACE_LEVEL_ERROR, ("x86BiosCall failed\n")); + return STATUS_UNSUCCESSFUL; + } + DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__)); + return Status; +} diff --git a/qxldod/QxlDod.h b/qxldod/QxlDod.h new file mode 100755 index 0000000..18ec7b1 --- /dev/null +++ b/qxldod/QxlDod.h @@ -0,0 +1,236 @@ +#pragma once +#include "baseobject.h" + +typedef struct _QXL_FLAGS +{ + UINT DriverStarted : 1; // ( 1) 1 after StartDevice and 0 after StopDevice + UINT Unused : 31; +} QXL_FLAGS; + +#define MAX_CHILDREN 1 +#define MAX_VIEWS 1 + +#pragma pack(push) +#pragma pack(1) + +typedef struct +{ + CHAR Signature[4]; + USHORT Version; + ULONG OemStringPtr; + LONG Capabilities; + ULONG VideoModePtr; + USHORT TotalMemory; + USHORT OemSoftwareRevision; + ULONG OemVendorNamePtr; + ULONG OemProductNamePtr; + ULONG OemProductRevPtr; + CHAR Reserved[222]; +// CHAR OemData[256]; +} VBE_INFO, *PVBE_INFO; + +typedef struct +{ +/* Mandatory information for all VBE revisions */ + USHORT ModeAttributes; + UCHAR WinAAttributes; + UCHAR WinBAttributes; + USHORT WinGranularity; + USHORT WinSize; + USHORT WinASegment; + USHORT WinBSegment; + ULONG WinFuncPtr; + USHORT BytesPerScanLine; +/* Mandatory information for VBE 1.2 and above */ + USHORT XResolution; + USHORT YResolution; + UCHAR XCharSize; + UCHAR YCharSize; + UCHAR NumberOfPlanes; + UCHAR BitsPerPixel; + UCHAR NumberOfBanks; + UCHAR MemoryModel; + UCHAR BankSize; + UCHAR NumberOfImagePages; + UCHAR Reserved1; +/* Direct Color fields (required for Direct/6 and YUV/7 memory models) */ + UCHAR RedMaskSize; + UCHAR RedFieldPosition; + UCHAR GreenMaskSize; + UCHAR GreenFieldPosition; + UCHAR BlueMaskSize; + UCHAR BlueFieldPosition; + UCHAR ReservedMaskSize; + UCHAR ReservedFieldPosition; + UCHAR DirectColorModeInfo; +/* Mandatory information for VBE 2.0 and above */ + ULONG PhysBasePtr; + ULONG Reserved2; + USHORT Reserved3; + /* Mandatory information for VBE 3.0 and above */ + USHORT LinBytesPerScanLine; + UCHAR BnkNumberOfImagePages; + UCHAR LinNumberOfImagePages; + UCHAR LinRedMaskSize; + UCHAR LinRedFieldPosition; + UCHAR LinGreenMaskSize; + UCHAR LinGreenFieldPosition; + UCHAR LinBlueMaskSize; + UCHAR LinBlueFieldPosition; + UCHAR LinReservedMaskSize; + UCHAR LinReservedFieldPosition; + ULONG MaxPixelClock; + CHAR Reserved4[189]; +} VBE_MODEINFO, *PVBE_MODEINFO; + +#pragma pack(pop) + +typedef struct _X86BIOS_REGISTERS // invented names +{ + ULONG Eax; + ULONG Ecx; + ULONG Edx; + ULONG Ebx; + ULONG Ebp; + ULONG Esi; + ULONG Edi; + USHORT SegDs; + USHORT SegEs; +} X86BIOS_REGISTERS, *PX86BIOS_REGISTERS; + +/* Undocumented imports from the HAL */ + +#ifdef __cplusplus +extern "C" { +#endif + +NTHALAPI BOOLEAN x86BiosCall (ULONG, PX86BIOS_REGISTERS); + +NTHALAPI NTSTATUS x86BiosAllocateBuffer (ULONG *, USHORT *, USHORT *); +NTHALAPI NTSTATUS x86BiosFreeBuffer (USHORT, USHORT); + +NTHALAPI NTSTATUS x86BiosReadMemory (USHORT, USHORT, PVOID, ULONG); +NTHALAPI NTSTATUS x86BiosWriteMemory (USHORT, USHORT, PVOID, ULONG); + +#ifdef __cplusplus +} +#endif + + +class QxlDod : + public BaseObject +{ +private: + DEVICE_OBJECT* m_pPhysicalDevice; + DXGKRNL_INTERFACE m_DxgkInterface; + DXGK_DEVICE_INFO m_DeviceInfo; + + DEVICE_POWER_STATE m_MonitorPowerState; + DEVICE_POWER_STATE m_AdapterPowerState; + QXL_FLAGS m_Flags; + PVBE_MODEINFO m_ModeInfo; + ULONG m_ModeCount; + PUSHORT m_ModeNumbers; + USHORT m_CurrentMode; +public: + QxlDod(_In_ DEVICE_OBJECT* pPhysicalDeviceObject); + ~QxlDod(void); +#pragma code_seg(push) +#pragma code_seg() + BOOLEAN IsDriverActive() const + { + return m_Flags.DriverStarted; + } +#pragma code_seg(pop) + + NTSTATUS StartDevice(_In_ DXGK_START_INFO* pDxgkStartInfo, + _In_ DXGKRNL_INTERFACE* pDxgkInterface, + _Out_ ULONG* pNumberOfViews, + _Out_ ULONG* pNumberOfChildren); + NTSTATUS StopDevice(VOID); + // Must be Non-Paged + VOID ResetDevice(VOID); + + NTSTATUS DispatchIoRequest(_In_ ULONG VidPnSourceId, + _In_ VIDEO_REQUEST_PACKET* pVideoRequestPacket); + NTSTATUS SetPowerState(_In_ ULONG HardwareUid, + _In_ DEVICE_POWER_STATE DevicePowerState, + _In_ POWER_ACTION ActionType); + // Report back child capabilities + NTSTATUS QueryChildRelations(_Out_writes_bytes_(ChildRelationsSize) DXGK_CHILD_DESCRIPTOR* pChildRelations, + _In_ ULONG ChildRelationsSize); + + NTSTATUS QueryChildStatus(_Inout_ DXGK_CHILD_STATUS* pChildStatus, + _In_ BOOLEAN NonDestructiveOnly); + + // Return EDID if previously retrieved + NTSTATUS QueryDeviceDescriptor(_In_ ULONG ChildUid, + _Inout_ DXGK_DEVICE_DESCRIPTOR* pDeviceDescriptor); + + // Must be Non-Paged + // BDD doesn't have interrupts, so just returns false + BOOLEAN InterruptRoutine(_In_ ULONG MessageNumber); + + VOID DpcRoutine(VOID); + + // Return DriverCaps, doesn't support other queries though + NTSTATUS QueryAdapterInfo(_In_ CONST DXGKARG_QUERYADAPTERINFO* pQueryAdapterInfo); + + NTSTATUS SetPointerPosition(_In_ CONST DXGKARG_SETPOINTERPOSITION* pSetPointerPosition); + + NTSTATUS SetPointerShape(_In_ CONST DXGKARG_SETPOINTERSHAPE* pSetPointerShape); + + NTSTATUS Escape(_In_ CONST DXGKARG_ESCAPE* pEscape); + + NTSTATUS PresentDisplayOnly(_In_ CONST DXGKARG_PRESENT_DISPLAYONLY* pPresentDisplayOnly); + + NTSTATUS QueryInterface(_In_ CONST PQUERY_INTERFACE QueryInterface); + + NTSTATUS IsSupportedVidPn(_Inout_ DXGKARG_ISSUPPORTEDVIDPN* pIsSupportedVidPn); + + NTSTATUS RecommendFunctionalVidPn(_In_ CONST DXGKARG_RECOMMENDFUNCTIONALVIDPN* CONST pRecommendFunctionalVidPn); + + NTSTATUS RecommendVidPnTopology(_In_ CONST DXGKARG_RECOMMENDVIDPNTOPOLOGY* CONST pRecommendVidPnTopology); + + NTSTATUS RecommendMonitorModes(_In_ CONST DXGKARG_RECOMMENDMONITORMODES* CONST pRecommendMonitorModes); + + NTSTATUS EnumVidPnCofuncModality(_In_ CONST DXGKARG_ENUMVIDPNCOFUNCMODALITY* CONST pEnumCofuncModality); + + NTSTATUS SetVidPnSourceVisibility(_In_ CONST DXGKARG_SETVIDPNSOURCEVISIBILITY* pSetVidPnSourceVisibility); + + NTSTATUS CommitVidPn(_In_ CONST DXGKARG_COMMITVIDPN* CONST pCommitVidPn); + + NTSTATUS UpdateActiveVidPnPresentPath(_In_ CONST DXGKARG_UPDATEACTIVEVIDPNPRESENTPATH* CONST pUpdateActiveVidPnPresentPath); + + NTSTATUS QueryVidPnHWCapability(_Inout_ DXGKARG_QUERYVIDPNHWCAPABILITY* pVidPnHWCaps); + + // Part of PnPStop (PnP instance only), returns current mode information (which will be passed to fallback instance by dxgkrnl) + NTSTATUS StopDeviceAndReleasePostDisplayOwnership(_In_ D3DDDI_VIDEO_PRESENT_TARGET_ID TargetId, + _Out_ DXGK_DISPLAY_INFORMATION* pDisplayInfo); + + // Must be Non-Paged + // Call to initialize as part of bugcheck + NTSTATUS SystemDisplayEnable(_In_ D3DDDI_VIDEO_PRESENT_TARGET_ID TargetId, + _In_ PDXGKARG_SYSTEM_DISPLAY_ENABLE_FLAGS Flags, + _Out_ UINT* pWidth, + _Out_ UINT* pHeight, + _Out_ D3DDDIFORMAT* pColorFormat); + + // Must be Non-Paged + // Write out pixels as part of bugcheck + VOID SystemDisplayWrite(_In_reads_bytes_(SourceHeight * SourceStride) VOID* pSource, + _In_ UINT SourceWidth, + _In_ UINT SourceHeight, + _In_ UINT SourceStride, + _In_ INT PositionX, + _In_ INT PositionY); +private: + VOID CleanUp(VOID); + NTSTATUS WriteHWInfoStr(_In_ HANDLE DevInstRegKeyHandle, _In_ PCWSTR pszwValueName, _In_ PCSTR pszValue); + NTSTATUS RegisterHWInfo(); + NTSTATUS VbeGetModeList(); + NTSTATUS VbeQueryCurrentMode(PVIDEO_MODE RequestedMode); + NTSTATUS VbeSetCurrentMode(PVIDEO_MODE RequestedMode); + NTSTATUS VbeSetPowerState(POWER_ACTION ActionType); +}; + diff --git a/qxldod/driver.cpp b/qxldod/driver.cpp new file mode 100755 index 0000000..546fc88 --- /dev/null +++ b/qxldod/driver.cpp @@ -0,0 +1,676 @@ +#include "driver.h" +#include "QxlDod.h" + +#pragma code_seg(push) +#pragma code_seg("INIT") +// BEGIN: Init Code + +// +// Driver Entry point +// + +int nDebugLevel = TRACE_LEVEL_VERBOSE; + + +extern "C" +NTSTATUS +DriverEntry( + _In_ DRIVER_OBJECT* pDriverObject, + _In_ UNICODE_STRING* pRegistryPath) +{ + PAGED_CODE(); + + DbgPrint(TRACE_LEVEL_INFORMATION, ("---> KMDOD build on on %s %s\n", __DATE__, __TIME__)); + +#ifdef DBG +// KdBreakPoint(); +#endif + // Initialize DDI function pointers and dxgkrnl + KMDDOD_INITIALIZATION_DATA InitialData = {0}; + + InitialData.Version = DXGKDDI_INTERFACE_VERSION_WIN8; + + InitialData.DxgkDdiAddDevice = DodAddDevice; + InitialData.DxgkDdiStartDevice = DodStartDevice; + InitialData.DxgkDdiStopDevice = DodStopDevice; + InitialData.DxgkDdiResetDevice = DodResetDevice; + InitialData.DxgkDdiRemoveDevice = DodRemoveDevice; + InitialData.DxgkDdiDispatchIoRequest = DodDispatchIoRequest; + InitialData.DxgkDdiInterruptRoutine = DodInterruptRoutine; + InitialData.DxgkDdiDpcRoutine = DodDpcRoutine; + InitialData.DxgkDdiQueryChildRelations = DodQueryChildRelations; + InitialData.DxgkDdiQueryChildStatus = DodQueryChildStatus; + InitialData.DxgkDdiQueryDeviceDescriptor = DodQueryDeviceDescriptor; + InitialData.DxgkDdiSetPowerState = DodSetPowerState; + InitialData.DxgkDdiUnload = DodUnload; + InitialData.DxgkDdiQueryInterface = DodQueryInterface; + InitialData.DxgkDdiQueryAdapterInfo = DodQueryAdapterInfo; + InitialData.DxgkDdiSetPointerPosition = DodSetPointerPosition; + InitialData.DxgkDdiSetPointerShape = DodSetPointerShape; + InitialData.DxgkDdiEscape = DodEscape; + InitialData.DxgkDdiIsSupportedVidPn = DodIsSupportedVidPn; + InitialData.DxgkDdiRecommendFunctionalVidPn = DodRecommendFunctionalVidPn; + InitialData.DxgkDdiEnumVidPnCofuncModality = DodEnumVidPnCofuncModality; + InitialData.DxgkDdiSetVidPnSourceVisibility = DodSetVidPnSourceVisibility; + InitialData.DxgkDdiCommitVidPn = DodCommitVidPn; + InitialData.DxgkDdiUpdateActiveVidPnPresentPath = DodUpdateActiveVidPnPresentPath; + InitialData.DxgkDdiRecommendMonitorModes = DodRecommendMonitorModes; + InitialData.DxgkDdiQueryVidPnHWCapability = DodQueryVidPnHWCapability; + InitialData.DxgkDdiPresentDisplayOnly = DodPresentDisplayOnly; + InitialData.DxgkDdiStopDeviceAndReleasePostDisplayOwnership = DodStopDeviceAndReleasePostDisplayOwnership; + InitialData.DxgkDdiSystemDisplayEnable = DodSystemDisplayEnable; + InitialData.DxgkDdiSystemDisplayWrite = DodSystemDisplayWrite; + + NTSTATUS Status = DxgkInitializeDisplayOnlyDriver(pDriverObject, pRegistryPath, &InitialData); + if (!NT_SUCCESS(Status)) + { + DbgPrint(TRACE_LEVEL_ERROR, ("DxgkInitializeDisplayOnlyDriver failed with Status: 0x%X\n", Status)); + } + + DbgPrint(TRACE_LEVEL_INFORMATION, ("<--- %s\n", __FUNCTION__)); + return Status; +} +// END: Init Code +#pragma code_seg(pop) + +#pragma code_seg(push) +#pragma code_seg("PAGE") + +// +// PnP DDIs +// + +VOID +DodUnload(VOID) +{ + PAGED_CODE(); + DbgPrint(TRACE_LEVEL_INFORMATION, ("<--> %s\n", __FUNCTION__)); +} + +NTSTATUS +DodAddDevice( + _In_ DEVICE_OBJECT* pPhysicalDeviceObject, + _Outptr_ PVOID* ppDeviceContext) +{ + PAGED_CODE(); + DbgPrint(TRACE_LEVEL_INFORMATION, ("---> %s\n", __FUNCTION__)); + + if ((pPhysicalDeviceObject == NULL) || + (ppDeviceContext == NULL)) + { + DbgPrint(TRACE_LEVEL_ERROR, ("One of pPhysicalDeviceObject (0x%I64x), ppDeviceContext (0x%I64x) is NULL", + pPhysicalDeviceObject, ppDeviceContext)); + return STATUS_INVALID_PARAMETER; + } + *ppDeviceContext = NULL; + + QxlDod* pQxl = new(NonPagedPoolNx) QxlDod(pPhysicalDeviceObject); + if (pQxl == NULL) + { + DbgPrint(TRACE_LEVEL_ERROR, ("pQxl failed to be allocated")); + return STATUS_NO_MEMORY; + } + + *ppDeviceContext = pQxl; + + DbgPrint(TRACE_LEVEL_INFORMATION, ("<--- %s\n", __FUNCTION__)); + return STATUS_SUCCESS; +} + +NTSTATUS +DodRemoveDevice( + _In_ VOID* pDeviceContext) +{ + PAGED_CODE(); + DbgPrint(TRACE_LEVEL_INFORMATION, ("---> %s\n", __FUNCTION__)); + + QxlDod* pQxl = reinterpret_cast(pDeviceContext); + + if (pQxl) + { + delete pQxl; + pQxl = NULL; + } + + DbgPrint(TRACE_LEVEL_INFORMATION, ("<--- %s\n", __FUNCTION__)); + return STATUS_SUCCESS; +} + +NTSTATUS +DodStartDevice( + _In_ VOID* pDeviceContext, + _In_ DXGK_START_INFO* pDxgkStartInfo, + _In_ DXGKRNL_INTERFACE* pDxgkInterface, + _Out_ ULONG* pNumberOfViews, + _Out_ ULONG* pNumberOfChildren) +{ + PAGED_CODE(); + QXL_ASSERT_CHK(pDeviceContext != NULL); + DbgPrint(TRACE_LEVEL_INFORMATION, ("<---> %s\n", __FUNCTION__)); + + QxlDod* pQxl = reinterpret_cast(pDeviceContext); + return pQxl->StartDevice(pDxgkStartInfo, pDxgkInterface, pNumberOfViews, pNumberOfChildren); +} + +NTSTATUS +DodStopDevice( + _In_ VOID* pDeviceContext) +{ + PAGED_CODE(); + QXL_ASSERT_CHK(pDeviceContext != NULL); + DbgPrint(TRACE_LEVEL_INFORMATION, ("<---> %s\n", __FUNCTION__)); + + QxlDod* pQxl = reinterpret_cast(pDeviceContext); + return pQxl->StopDevice(); +} + + +NTSTATUS +DodDispatchIoRequest( + _In_ VOID* pDeviceContext, + _In_ ULONG VidPnSourceId, + _In_ VIDEO_REQUEST_PACKET* pVideoRequestPacket) +{ + PAGED_CODE(); + QXL_ASSERT_CHK(pDeviceContext != NULL); + DbgPrint(TRACE_LEVEL_INFORMATION, ("<---> %s\n", __FUNCTION__)); + + QxlDod* pQxl = reinterpret_cast(pDeviceContext); + if (!pQxl->IsDriverActive()) + { + QXL_LOG_ASSERTION1("QXL (0x%I64x) is being called when not active!", pQxl); + return STATUS_UNSUCCESSFUL; + } + return pQxl->DispatchIoRequest(VidPnSourceId, pVideoRequestPacket); +} + +NTSTATUS +DodSetPowerState( + _In_ VOID* pDeviceContext, + _In_ ULONG HardwareUid, + _In_ DEVICE_POWER_STATE DevicePowerState, + _In_ POWER_ACTION ActionType) +{ + PAGED_CODE(); + QXL_ASSERT_CHK(pDeviceContext != NULL); + DbgPrint(TRACE_LEVEL_INFORMATION, ("<---> %s\n", __FUNCTION__)); + + QxlDod* pQxl = reinterpret_cast(pDeviceContext); + if (!pQxl->IsDriverActive()) + { + // If the driver isn't active, SetPowerState can still be called, however in QXL's case + // this shouldn't do anything, as it could for instance be called on QXL Fallback after + // Fallback has been stopped and QXL PnP is being started. Fallback doesn't have control + // of the hardware in this case. + return STATUS_SUCCESS; + } + return pQxl->SetPowerState(HardwareUid, DevicePowerState, ActionType); +} + +NTSTATUS +DodQueryChildRelations( + _In_ VOID* pDeviceContext, + _Out_writes_bytes_(ChildRelationsSize) DXGK_CHILD_DESCRIPTOR* pChildRelations, + _In_ ULONG ChildRelationsSize) +{ + PAGED_CODE(); + QXL_ASSERT_CHK(pDeviceContext != NULL); + DbgPrint(TRACE_LEVEL_INFORMATION, ("<---> %s\n", __FUNCTION__)); + + QxlDod* pQxl = reinterpret_cast(pDeviceContext); + return pQxl->QueryChildRelations(pChildRelations, ChildRelationsSize); +} + +NTSTATUS +DodQueryChildStatus( + _In_ VOID* pDeviceContext, + _Inout_ DXGK_CHILD_STATUS* pChildStatus, + _In_ BOOLEAN NonDestructiveOnly) +{ + PAGED_CODE(); + QXL_ASSERT_CHK(pDeviceContext != NULL); + DbgPrint(TRACE_LEVEL_INFORMATION, ("<---> %s\n", __FUNCTION__)); + + QxlDod* pQxl = reinterpret_cast(pDeviceContext); + return pQxl->QueryChildStatus(pChildStatus, NonDestructiveOnly); +} + +NTSTATUS +DodQueryDeviceDescriptor( + _In_ VOID* pDeviceContext, + _In_ ULONG ChildUid, + _Inout_ DXGK_DEVICE_DESCRIPTOR* pDeviceDescriptor) +{ + PAGED_CODE(); + QXL_ASSERT_CHK(pDeviceContext != NULL); + DbgPrint(TRACE_LEVEL_INFORMATION, ("<---> %s\n", __FUNCTION__)); + + QxlDod* pQxl = reinterpret_cast(pDeviceContext); + if (!pQxl->IsDriverActive()) + { + // During stress testing of PnPStop, it is possible for QXL Fallback to get called to start then stop in quick succession. + // The first call queues a worker thread item indicating that it now has a child device, the second queues a worker thread + // item that it no longer has any child device. This function gets called based on the first worker thread item, but after + // the driver has been stopped. Therefore instead of asserting like other functions, we only warn. + DbgPrint(TRACE_LEVEL_WARNING, ("QXL (0x%I64x) is being called when not active!", pQxl)); + return STATUS_UNSUCCESSFUL; + } + return pQxl->QueryDeviceDescriptor(ChildUid, pDeviceDescriptor); +} + + +// +// WDDM Display Only Driver DDIs +// + +NTSTATUS +APIENTRY +DodQueryAdapterInfo( + _In_ CONST HANDLE hAdapter, + _In_ CONST DXGKARG_QUERYADAPTERINFO* pQueryAdapterInfo) +{ + PAGED_CODE(); + QXL_ASSERT_CHK(hAdapter != NULL); + DbgPrint(TRACE_LEVEL_INFORMATION, ("<---> %s\n", __FUNCTION__)); + + QxlDod* pQxl = reinterpret_cast(hAdapter); + return pQxl->QueryAdapterInfo(pQueryAdapterInfo); +} + +NTSTATUS +APIENTRY +DodSetPointerPosition( + _In_ CONST HANDLE hAdapter, + _In_ CONST DXGKARG_SETPOINTERPOSITION* pSetPointerPosition) +{ + PAGED_CODE(); + QXL_ASSERT_CHK(hAdapter != NULL); + DbgPrint(TRACE_LEVEL_INFORMATION, ("<---> %s\n", __FUNCTION__)); + + QxlDod* pQxl = reinterpret_cast(hAdapter); + if (!pQxl->IsDriverActive()) + { + QXL_LOG_ASSERTION1("QXL (0x%I64x) is being called when not active!", pQxl); + return STATUS_UNSUCCESSFUL; + } + return pQxl->SetPointerPosition(pSetPointerPosition); +} + +NTSTATUS +APIENTRY +DodSetPointerShape( + _In_ CONST HANDLE hAdapter, + _In_ CONST DXGKARG_SETPOINTERSHAPE* pSetPointerShape) +{ + PAGED_CODE(); + QXL_ASSERT_CHK(hAdapter != NULL); + DbgPrint(TRACE_LEVEL_INFORMATION, ("<---> %s\n", __FUNCTION__)); + + QxlDod* pQxl = reinterpret_cast(hAdapter); + if (!pQxl->IsDriverActive()) + { + QXL_LOG_ASSERTION1("QXL (0x%I64x) is being called when not active!", pQxl); + return STATUS_UNSUCCESSFUL; + } + return pQxl->SetPointerShape(pSetPointerShape); +} + +NTSTATUS +APIENTRY +DodEscape( + _In_ CONST HANDLE hAdapter, + _In_ CONST DXGKARG_ESCAPE* pEscape + ) +{ + PAGED_CODE(); + QXL_ASSERT_CHK(hAdapter != NULL); + DbgPrint(TRACE_LEVEL_INFORMATION, ("<---> %s\n", __FUNCTION__)); + + QxlDod* pQxl = reinterpret_cast(hAdapter); + return pQxl->Escape(pEscape); +} + +NTSTATUS +DodQueryInterface( + _In_ CONST PVOID pDeviceContext, + _In_ CONST PQUERY_INTERFACE QueryInterface + ) +{ + PAGED_CODE(); + QXL_ASSERT_CHK(pDeviceContext != NULL); + DbgPrint(TRACE_LEVEL_INFORMATION, ("<---> %s\n", __FUNCTION__)); + + QxlDod* pQxl = reinterpret_cast(pDeviceContext); + return pQxl->QueryInterface(QueryInterface); +} + +NTSTATUS +APIENTRY +DodPresentDisplayOnly( + _In_ CONST HANDLE hAdapter, + _In_ CONST DXGKARG_PRESENT_DISPLAYONLY* pPresentDisplayOnly) +{ + PAGED_CODE(); + QXL_ASSERT_CHK(hAdapter != NULL); +// DbgPrint(TRACE_LEVEL_INFORMATION, ("<---> %s\n", __FUNCTION__)); + + QxlDod* pQxl = reinterpret_cast(hAdapter); + if (!pQxl->IsDriverActive()) + { + QXL_LOG_ASSERTION1("QXL (0x%I64x) is being called when not active!", pQxl); + return STATUS_UNSUCCESSFUL; + } + return pQxl->PresentDisplayOnly(pPresentDisplayOnly); +} + +NTSTATUS +APIENTRY +DodStopDeviceAndReleasePostDisplayOwnership( + _In_ VOID* pDeviceContext, + _In_ D3DDDI_VIDEO_PRESENT_TARGET_ID TargetId, + _Out_ DXGK_DISPLAY_INFORMATION* DisplayInfo) +{ + PAGED_CODE(); + QXL_ASSERT_CHK(pDeviceContext != NULL); + DbgPrint(TRACE_LEVEL_INFORMATION, ("<---> %s\n", __FUNCTION__)); + + QxlDod* pQxl = reinterpret_cast(pDeviceContext); + return pQxl->StopDeviceAndReleasePostDisplayOwnership(TargetId, DisplayInfo); +} + +NTSTATUS +APIENTRY +DodIsSupportedVidPn( + _In_ CONST HANDLE hAdapter, + _Inout_ DXGKARG_ISSUPPORTEDVIDPN* pIsSupportedVidPn) +{ + PAGED_CODE(); + QXL_ASSERT_CHK(hAdapter != NULL); + DbgPrint(TRACE_LEVEL_INFORMATION, ("<---> %s\n", __FUNCTION__)); + + QxlDod* pQxl = reinterpret_cast(hAdapter); + if (!pQxl->IsDriverActive()) + { + // This path might hit because win32k/dxgport doesn't check that an adapter is active when taking the adapter lock. + // The adapter lock is the main thing QXL Fallback relies on to not be called while it's inactive. It is still a rare + // timing issue around PnpStart/Stop and isn't expected to have any effect on the stability of the system. + DbgPrint(TRACE_LEVEL_WARNING, ("QXL (0x%I64x) is being called when not active!", pQxl)); + return STATUS_UNSUCCESSFUL; + } + return pQxl->IsSupportedVidPn(pIsSupportedVidPn); +} + +NTSTATUS +APIENTRY +DodRecommendFunctionalVidPn( + _In_ CONST HANDLE hAdapter, + _In_ CONST DXGKARG_RECOMMENDFUNCTIONALVIDPN* CONST pRecommendFunctionalVidPn) +{ + PAGED_CODE(); + QXL_ASSERT_CHK(hAdapter != NULL); + DbgPrint(TRACE_LEVEL_INFORMATION, ("<---> %s\n", __FUNCTION__)); + + QxlDod* pQxl = reinterpret_cast(hAdapter); + if (!pQxl->IsDriverActive()) + { + QXL_LOG_ASSERTION1("QXL (0x%I64x) is being called when not active!", pQxl); + return STATUS_UNSUCCESSFUL; + } + return pQxl->RecommendFunctionalVidPn(pRecommendFunctionalVidPn); +} + +NTSTATUS +APIENTRY +DodRecommendVidPnTopology( + _In_ CONST HANDLE hAdapter, + _In_ CONST DXGKARG_RECOMMENDVIDPNTOPOLOGY* CONST pRecommendVidPnTopology) +{ + PAGED_CODE(); + QXL_ASSERT_CHK(hAdapter != NULL); + DbgPrint(TRACE_LEVEL_INFORMATION, ("<---> %s\n", __FUNCTION__)); + + QxlDod* pQxl = reinterpret_cast(hAdapter); + if (!pQxl->IsDriverActive()) + { + QXL_LOG_ASSERTION1("QXL (0x%I64x) is being called when not active!", pQxl); + return STATUS_UNSUCCESSFUL; + } + return pQxl->RecommendVidPnTopology(pRecommendVidPnTopology); +} + +NTSTATUS +APIENTRY +DodRecommendMonitorModes( + _In_ CONST HANDLE hAdapter, + _In_ CONST DXGKARG_RECOMMENDMONITORMODES* CONST pRecommendMonitorModes) +{ + PAGED_CODE(); + QXL_ASSERT_CHK(hAdapter != NULL); + DbgPrint(TRACE_LEVEL_INFORMATION, ("<---> %s\n", __FUNCTION__)); + + QxlDod* pQxl = reinterpret_cast(hAdapter); + if (!pQxl->IsDriverActive()) + { + QXL_LOG_ASSERTION1("QXL (0x%I64x) is being called when not active!", pQxl); + return STATUS_UNSUCCESSFUL; + } + return pQxl->RecommendMonitorModes(pRecommendMonitorModes); +} + +NTSTATUS +APIENTRY +DodEnumVidPnCofuncModality( + _In_ CONST HANDLE hAdapter, + _In_ CONST DXGKARG_ENUMVIDPNCOFUNCMODALITY* CONST pEnumCofuncModality) +{ + PAGED_CODE(); + QXL_ASSERT_CHK(hAdapter != NULL); + DbgPrint(TRACE_LEVEL_INFORMATION, ("<---> %s\n", __FUNCTION__)); + + QxlDod* pQxl = reinterpret_cast(hAdapter); + if (!pQxl->IsDriverActive()) + { + QXL_LOG_ASSERTION1("QXL (0x%I64x) is being called when not active!", pQxl); + return STATUS_UNSUCCESSFUL; + } + return pQxl->EnumVidPnCofuncModality(pEnumCofuncModality); +} + +NTSTATUS +APIENTRY +DodSetVidPnSourceVisibility( + _In_ CONST HANDLE hAdapter, + _In_ CONST DXGKARG_SETVIDPNSOURCEVISIBILITY* pSetVidPnSourceVisibility) +{ + PAGED_CODE(); + QXL_ASSERT_CHK(hAdapter != NULL); + DbgPrint(TRACE_LEVEL_INFORMATION, ("<---> %s\n", __FUNCTION__)); + + QxlDod* pQxl = reinterpret_cast(hAdapter); + if (!pQxl->IsDriverActive()) + { + QXL_LOG_ASSERTION1("QXL (0x%I64x) is being called when not active!", pQxl); + return STATUS_UNSUCCESSFUL; + } + return pQxl->SetVidPnSourceVisibility(pSetVidPnSourceVisibility); +} + +NTSTATUS +APIENTRY +DodCommitVidPn( + _In_ CONST HANDLE hAdapter, + _In_ CONST DXGKARG_COMMITVIDPN* CONST pCommitVidPn) +{ + PAGED_CODE(); + QXL_ASSERT_CHK(hAdapter != NULL); + DbgPrint(TRACE_LEVEL_INFORMATION, ("<---> %s\n", __FUNCTION__)); + + QxlDod* pQxl = reinterpret_cast(hAdapter); + if (!pQxl->IsDriverActive()) + { + QXL_LOG_ASSERTION1("QXL (0x%I64x) is being called when not active!", pQxl); + return STATUS_UNSUCCESSFUL; + } + return pQxl->CommitVidPn(pCommitVidPn); +} + +NTSTATUS +APIENTRY +DodUpdateActiveVidPnPresentPath( + _In_ CONST HANDLE hAdapter, + _In_ CONST DXGKARG_UPDATEACTIVEVIDPNPRESENTPATH* CONST pUpdateActiveVidPnPresentPath) +{ + PAGED_CODE(); + QXL_ASSERT_CHK(hAdapter != NULL); + DbgPrint(TRACE_LEVEL_INFORMATION, ("<---> %s\n", __FUNCTION__)); + + QxlDod* pQxl = reinterpret_cast(hAdapter); + if (!pQxl->IsDriverActive()) + { + QXL_LOG_ASSERTION1("QXL (0x%I64x) is being called when not active!", pQxl); + return STATUS_UNSUCCESSFUL; + } + return pQxl->UpdateActiveVidPnPresentPath(pUpdateActiveVidPnPresentPath); +} + +NTSTATUS +APIENTRY +DodQueryVidPnHWCapability( + _In_ CONST HANDLE hAdapter, + _Inout_ DXGKARG_QUERYVIDPNHWCAPABILITY* pVidPnHWCaps) +{ + PAGED_CODE(); + QXL_ASSERT_CHK(hAdapter != NULL); + DbgPrint(TRACE_LEVEL_INFORMATION, ("<---> %s\n", __FUNCTION__)); + + QxlDod* pQxl = reinterpret_cast(hAdapter); + if (!pQxl->IsDriverActive()) + { + QXL_LOG_ASSERTION1("QXL (0x%I64x) is being called when not active!", pQxl); + return STATUS_UNSUCCESSFUL; + } + return pQxl->QueryVidPnHWCapability(pVidPnHWCaps); +} + +//END: Paged Code +#pragma code_seg(pop) + +#pragma code_seg(push) +#pragma code_seg() +// BEGIN: Non-Paged Code + +VOID +DodDpcRoutine( + _In_ VOID* pDeviceContext) +{ + QXL_ASSERT_CHK(pDeviceContext != NULL); + DbgPrint(TRACE_LEVEL_INFORMATION, ("---> %s\n", __FUNCTION__)); + + QxlDod* pQxl = reinterpret_cast(pDeviceContext); + if (!pQxl->IsDriverActive()) + { + QXL_LOG_ASSERTION1("QXL (0x%I64x) is being called when not active!", pQxl); + return; + } + pQxl->DpcRoutine(); + DbgPrint(TRACE_LEVEL_INFORMATION, ("<--- %s\n", __FUNCTION__)); +} + +BOOLEAN +DodInterruptRoutine( + _In_ VOID* pDeviceContext, + _In_ ULONG MessageNumber) +{ + QXL_ASSERT_CHK(pDeviceContext != NULL); + DbgPrint(TRACE_LEVEL_INFORMATION, ("<---> %s\n", __FUNCTION__)); + + QxlDod* pQxl = reinterpret_cast(pDeviceContext); + return pQxl->InterruptRoutine(MessageNumber); +} + +VOID +DodResetDevice( + _In_ VOID* pDeviceContext) +{ + QXL_ASSERT_CHK(pDeviceContext != NULL); + DbgPrint(TRACE_LEVEL_INFORMATION, ("<---> %s\n", __FUNCTION__)); + + QxlDod* pQxl = reinterpret_cast(pDeviceContext); + pQxl->ResetDevice(); +} + +NTSTATUS +APIENTRY +DodSystemDisplayEnable( + _In_ VOID* pDeviceContext, + _In_ D3DDDI_VIDEO_PRESENT_TARGET_ID TargetId, + _In_ PDXGKARG_SYSTEM_DISPLAY_ENABLE_FLAGS Flags, + _Out_ UINT* Width, + _Out_ UINT* Height, + _Out_ D3DDDIFORMAT* ColorFormat) +{ + QXL_ASSERT_CHK(pDeviceContext != NULL); + DbgPrint(TRACE_LEVEL_INFORMATION, ("<---> %s\n", __FUNCTION__)); + + QxlDod* pQxl = reinterpret_cast(pDeviceContext); + return pQxl->SystemDisplayEnable(TargetId, Flags, Width, Height, ColorFormat); +} + +VOID +APIENTRY +DodSystemDisplayWrite( + _In_ VOID* pDeviceContext, + _In_ VOID* Source, + _In_ UINT SourceWidth, + _In_ UINT SourceHeight, + _In_ UINT SourceStride, + _In_ UINT PositionX, + _In_ UINT PositionY) +{ + QXL_ASSERT_CHK(pDeviceContext != NULL); + DbgPrint(TRACE_LEVEL_INFORMATION, ("<---> %s\n", __FUNCTION__)); + + QxlDod* pQxl = reinterpret_cast(pDeviceContext); + pQxl->SystemDisplayWrite(Source, SourceWidth, SourceHeight, SourceStride, PositionX, PositionY); +} + +#if defined(DBG) + +#define RHEL_DEBUG_PORT ((PUCHAR)0x3F8) +#define TEMP_BUFFER_SIZE 256 + +void DebugPrintFuncSerial(const char *format, ...) +{ + char buf[TEMP_BUFFER_SIZE]; + NTSTATUS status; + size_t len; + va_list list; + va_start(list, format); + status = RtlStringCbVPrintfA(buf, sizeof(buf), format, list); + if (status == STATUS_SUCCESS) + { + len = strlen(buf); + } + else + { + len = 2; + buf[0] = 'O'; + buf[1] = '\n'; + } + if (len) + { + WRITE_PORT_BUFFER_UCHAR(RHEL_DEBUG_PORT, (PUCHAR)buf, len); + WRITE_PORT_UCHAR(RHEL_DEBUG_PORT, '\r'); + } +} + +void DebugPrintFunc(const char *format, ...) +{ + va_list list; + va_start(list, format); + vDbgPrintEx(DPFLTR_DEFAULT_ID, 9 | DPFLTR_MASK, format, list); +} +#endif + +#pragma code_seg(pop) // End Non-Paged Code + diff --git a/qxldod/driver.h b/qxldod/driver.h new file mode 100755 index 0000000..72a8b46 --- /dev/null +++ b/qxldod/driver.h @@ -0,0 +1,255 @@ +#pragma once +#include "BaseObject.h" + + +extern "C" +DRIVER_INITIALIZE DriverEntry; + +// +// PnP DDIs +// + +VOID +DodUnload(VOID); + +// If uncommenting ENABLE_DXGK_SAL in the sources file, all the below function prototypes should be updated to use +// the function typedef's from the header files. Additionally, annotations on the function definitions can be removed +// as they are inherited from the prototype definition here. As an example the entire 4-line prototype for BddDdiAddDevice +// is replaced by the single commented line below: +// DXGKDDI_ADD_DEVICE BddDdiAddDevice; +NTSTATUS +DodAddDevice( + _In_ DEVICE_OBJECT* pPhysicalDeviceObject, + _Outptr_ PVOID* ppDeviceContext); + +NTSTATUS +DodRemoveDevice( + _In_ VOID* pDeviceContext); + +NTSTATUS +DodStartDevice( + _In_ VOID* pDeviceContext, + _In_ DXGK_START_INFO* pDxgkStartInfo, + _In_ DXGKRNL_INTERFACE* pDxgkInterface, + _Out_ ULONG* pNumberOfViews, + _Out_ ULONG* pNumberOfChildren); + +NTSTATUS +DodStopDevice( + _In_ VOID* pDeviceContext); + +VOID +DodResetDevice( + _In_ VOID* pDeviceContext); + + +NTSTATUS +DodDispatchIoRequest( + _In_ VOID* pDeviceContext, + _In_ ULONG VidPnSourceId, + _In_ VIDEO_REQUEST_PACKET* pVideoRequestPacket); + +NTSTATUS +DodSetPowerState( + _In_ VOID* pDeviceContext, + _In_ ULONG HardwareUid, + _In_ DEVICE_POWER_STATE DevicePowerState, + _In_ POWER_ACTION ActionType); + +NTSTATUS +DodQueryChildRelations( + _In_ VOID* pDeviceContext, + _Out_writes_bytes_(ChildRelationsSize) DXGK_CHILD_DESCRIPTOR* pChildRelations, + _In_ ULONG ChildRelationsSize); + +NTSTATUS +DodQueryChildStatus( + _In_ VOID* pDeviceContext, + _Inout_ DXGK_CHILD_STATUS* pChildStatus, + _In_ BOOLEAN NonDestructiveOnly); + +NTSTATUS +DodQueryDeviceDescriptor( + _In_ VOID* pDeviceContext, + _In_ ULONG ChildUid, + _Inout_ DXGK_DEVICE_DESCRIPTOR* pDeviceDescriptor); + +// Must be Non-Paged +BOOLEAN +DodInterruptRoutine( + _In_ VOID* pDeviceContext, + _In_ ULONG MessageNumber); + +VOID +DodDpcRoutine( + _In_ VOID* pDeviceContext); + +// +// WDDM Display Only Driver DDIs +// + +NTSTATUS +APIENTRY +DodQueryAdapterInfo( + _In_ CONST HANDLE hAdapter, + _In_ CONST DXGKARG_QUERYADAPTERINFO* pQueryAdapterInfo); + +NTSTATUS +APIENTRY +DodSetPointerPosition( + _In_ CONST HANDLE hAdapter, + _In_ CONST DXGKARG_SETPOINTERPOSITION* pSetPointerPosition); + +NTSTATUS +APIENTRY +DodSetPointerShape( + _In_ CONST HANDLE hAdapter, + _In_ CONST DXGKARG_SETPOINTERSHAPE* pSetPointerShape); + +NTSTATUS +APIENTRY +DodEscape( + _In_ CONST HANDLE hAdapter, + _In_ CONST DXGKARG_ESCAPE* pEscape); + +NTSTATUS +DodQueryInterface( + _In_ CONST PVOID pDeviceContext, + _In_ CONST PQUERY_INTERFACE pQueryInterface); + +NTSTATUS +APIENTRY +DodPresentDisplayOnly( + _In_ CONST HANDLE hAdapter, + _In_ CONST DXGKARG_PRESENT_DISPLAYONLY* pPresentDisplayOnly); + +NTSTATUS +APIENTRY +DodIsSupportedVidPn( + _In_ CONST HANDLE hAdapter, + _Inout_ DXGKARG_ISSUPPORTEDVIDPN* pIsSupportedVidPn); + +NTSTATUS +APIENTRY +DodRecommendFunctionalVidPn( + _In_ CONST HANDLE hAdapter, + _In_ CONST DXGKARG_RECOMMENDFUNCTIONALVIDPN* CONST pRecommendFunctionalVidPn); + +NTSTATUS +APIENTRY +DodRecommendVidPnTopology( + _In_ CONST HANDLE hAdapter, + _In_ CONST DXGKARG_RECOMMENDVIDPNTOPOLOGY* CONST pRecommendVidPnTopology); + +NTSTATUS +APIENTRY +DodRecommendMonitorModes( + _In_ CONST HANDLE hAdapter, + _In_ CONST DXGKARG_RECOMMENDMONITORMODES* CONST pRecommendMonitorModes); + +NTSTATUS +APIENTRY +DodEnumVidPnCofuncModality( + _In_ CONST HANDLE hAdapter, + _In_ CONST DXGKARG_ENUMVIDPNCOFUNCMODALITY* CONST pEnumCofuncModality); + +NTSTATUS +APIENTRY +DodSetVidPnSourceVisibility( + _In_ CONST HANDLE hAdapter, + _In_ CONST DXGKARG_SETVIDPNSOURCEVISIBILITY* pSetVidPnSourceVisibility); + +NTSTATUS +APIENTRY +DodCommitVidPn( + _In_ CONST HANDLE hAdapter, + _In_ CONST DXGKARG_COMMITVIDPN* CONST pCommitVidPn); + +NTSTATUS +APIENTRY +DodUpdateActiveVidPnPresentPath( + _In_ CONST HANDLE hAdapter, + _In_ CONST DXGKARG_UPDATEACTIVEVIDPNPRESENTPATH* CONST pUpdateActiveVidPnPresentPath); + +NTSTATUS +APIENTRY +DodQueryVidPnHWCapability( + _In_ CONST HANDLE hAdapter, + _Inout_ DXGKARG_QUERYVIDPNHWCAPABILITY* pVidPnHWCaps); + +NTSTATUS +APIENTRY +DodStopDeviceAndReleasePostDisplayOwnership( + _In_ VOID* pDeviceContext, + _In_ D3DDDI_VIDEO_PRESENT_TARGET_ID TargetId, + _Out_ DXGK_DISPLAY_INFORMATION* DisplayInfo); + +// Must be Non-Paged +NTSTATUS +APIENTRY +DodSystemDisplayEnable( + _In_ VOID* pDeviceContext, + _In_ D3DDDI_VIDEO_PRESENT_TARGET_ID TargetId, + _In_ PDXGKARG_SYSTEM_DISPLAY_ENABLE_FLAGS Flags, + _Out_ UINT* Width, + _Out_ UINT* Height, + _Out_ D3DDDIFORMAT* ColorFormat); + +// Must be Non-Paged +VOID +APIENTRY +DodSystemDisplayWrite( + _In_ VOID* pDeviceContext, + _In_ VOID* Source, + _In_ UINT SourceWidth, + _In_ UINT SourceHeight, + _In_ UINT SourceStride, + _In_ UINT PositionX, + _In_ UINT PositionY); + + + +#if DBG + +extern int nDebugLevel; +void DebugPrintFuncSerial(const char *format, ...); + +void DebugPrintFunc(const char *format, ...); + +#define DbgPrint(level, line) \ + if (level > nDebugLevel) {} \ + else DebugPrintFuncSerial line +#else +#define DbgPrint(level, line) +#endif + +// else if (0) DebugPrintFuncSerial line \ + + +#ifndef TRACE_LEVEL_INFORMATION +#define TRACE_LEVEL_NONE 0 // Tracing is not on +#define TRACE_LEVEL_FATAL 1 // Abnormal exit or termination +#define TRACE_LEVEL_ERROR 2 // Severe errors that need logging +#define TRACE_LEVEL_WARNING 3 // Warnings such as allocation failure +#define TRACE_LEVEL_INFORMATION 4 // Includes non-error cases(e.g.,Entry-Exit) +#define TRACE_LEVEL_VERBOSE 5 // Detailed traces from intermediate steps +#define TRACE_LEVEL_RESERVED6 6 +#define TRACE_LEVEL_RESERVED7 7 +#define TRACE_LEVEL_RESERVED8 8 +#define TRACE_LEVEL_RESERVED9 9 +#endif // TRACE_LEVEL_INFORMATION + +#define QXL_LOG_ASSERTION0(Msg) NT_ASSERT(FALSE) +#define QXL_LOG_ASSERTION1(Msg,Param1) NT_ASSERT(FALSE) +#define QXL_LOG_ASSERTION2(Msg,Param1,Param2) NT_ASSERT(FALSE) +#define QXL_LOG_ASSERTION3(Msg,Param1,Param2,Param3) NT_ASSERT(FALSE) +#define QXL_LOG_ASSERTION4(Msg,Param1,Param2,Param3,Param4) NT_ASSERT(FALSE) +#define QXL_LOG_ASSERTION5(Msg,Param1,Param2,Param3,Param4,Param5) NT_ASSERT(FALSE) +#define QXL_ASSERT(exp) {if (!(exp)) {QXL_LOG_ASSERTION0(#exp);}} + + +#if DBG +#define QXL_ASSERT_CHK(exp) QXL_ASSERT(exp) +#else +#define QXL_ASSERT_CHK(exp) {} +#endif diff --git a/qxldod/qxldod.inf b/qxldod/qxldod.inf new file mode 100755 index 0000000..28080d4 Binary files /dev/null and b/qxldod/qxldod.inf differ diff --git a/qxldod/qxldod.rc b/qxldod/qxldod.rc new file mode 100755 index 0000000..ba45879 Binary files /dev/null and b/qxldod/qxldod.rc differ diff --git a/qxldod/qxldod.vcxproj b/qxldod/qxldod.vcxproj new file mode 100755 index 0000000..38cd91a --- /dev/null +++ b/qxldod/qxldod.vcxproj @@ -0,0 +1,288 @@ + + + + + Win8 Debug + Win32 + + + Win8 Release + Win32 + + + Win7 Debug + Win32 + + + Win7 Release + Win32 + + + Vista Debug + Win32 + + + Vista Release + Win32 + + + Win8 Debug + x64 + + + Win8 Release + x64 + + + Win7 Debug + x64 + + + Win7 Release + x64 + + + Vista Debug + x64 + + + Vista Release + x64 + + + + {A6F48FC7-97E9-48EC-BCDF-1E4F9B43AADD} + {dd38f7fc-d7bd-488b-9242-7d8754cde80d} + v4.5 + 11.0 + Win8 Debug + Win32 + + + qxldod + $(VCTargetsPath11) + + + WindowsKernelModeDriver8.0 + Driver + WDM + + + + Windows8 + true + + + Windows8 + false + + + Windows7 + true + + + Windows7 + false + + + Vista + true + + + Vista + false + + + Windows8 + true + + + Windows8 + false + + + Windows7 + true + + + Windows7 + false + + + Vista + true + + + Vista + false + + + + + + + + + + + DbgengKernelDebugger + + + + ;$(DDK_LIB_PATH)\displib.lib;$(DDK_LIB_PATH)\ntoskrnl.lib;$(DDK_LIB_PATH)\hal.lib + + + %(AdditionalIncludeDirectories);$(DDK_INC_PATH);$(SDK_INC_PATH) + + + %(AdditionalIncludeDirectories);$(DDK_INC_PATH);$(SDK_INC_PATH) + + + + + %(AdditionalDependencies);$(DDK_LIB_PATH)\displib.lib;$(DDK_LIB_PATH)\ntoskrnl.lib;$(DDK_LIB_PATH)\hal.lib + + + %(AdditionalIncludeDirectories);$(DDK_INC_PATH);$(SDK_INC_PATH) + + + %(AdditionalIncludeDirectories);$(DDK_INC_PATH);$(SDK_INC_PATH) + Level3 + + + + + + ;$(DDK_LIB_PATH)\displib.lib;$(DDK_LIB_PATH)\ntoskrnl.lib;$(DDK_LIB_PATH)\hal.lib + + + %(AdditionalIncludeDirectories);$(DDK_INC_PATH);$(SDK_INC_PATH) + + + %(AdditionalIncludeDirectories);$(DDK_INC_PATH);$(SDK_INC_PATH) + + + + + ;$(DDK_LIB_PATH)\displib.lib;$(DDK_LIB_PATH)\ntoskrnl.lib;$(DDK_LIB_PATH)\hal.lib + + + %(AdditionalIncludeDirectories);$(DDK_INC_PATH);$(SDK_INC_PATH) + + + %(AdditionalIncludeDirectories);$(DDK_INC_PATH);$(SDK_INC_PATH) + + + + + ;$(DDK_LIB_PATH)\displib.lib;$(DDK_LIB_PATH)\ntoskrnl.lib;$(DDK_LIB_PATH)\hal.lib + + + %(AdditionalIncludeDirectories);$(DDK_INC_PATH);$(SDK_INC_PATH) + + + %(AdditionalIncludeDirectories);$(DDK_INC_PATH);$(SDK_INC_PATH) + + + + + ;$(DDK_LIB_PATH)\displib.lib;$(DDK_LIB_PATH)\ntoskrnl.lib;$(DDK_LIB_PATH)\hal.lib + + + %(AdditionalIncludeDirectories);$(DDK_INC_PATH);$(SDK_INC_PATH) + + + %(AdditionalIncludeDirectories);$(DDK_INC_PATH);$(SDK_INC_PATH) + + + + + ;$(DDK_LIB_PATH)\displib.lib;$(DDK_LIB_PATH)\ntoskrnl.lib;$(DDK_LIB_PATH)\hal.lib + + + %(AdditionalIncludeDirectories);$(DDK_INC_PATH);$(SDK_INC_PATH) + + + %(AdditionalIncludeDirectories);$(DDK_INC_PATH);$(SDK_INC_PATH) + + + + + ;$(DDK_LIB_PATH)\displib.lib;$(DDK_LIB_PATH)\ntoskrnl.lib;$(DDK_LIB_PATH)\hal.lib + + + %(AdditionalIncludeDirectories);$(DDK_INC_PATH);$(SDK_INC_PATH) + + + %(AdditionalIncludeDirectories);$(DDK_INC_PATH);$(SDK_INC_PATH) + + + + + ;$(DDK_LIB_PATH)\displib.lib;$(DDK_LIB_PATH)\ntoskrnl.lib;$(DDK_LIB_PATH)\hal.lib + + + %(AdditionalIncludeDirectories);$(DDK_INC_PATH);$(SDK_INC_PATH) + + + %(AdditionalIncludeDirectories);$(DDK_INC_PATH);$(SDK_INC_PATH) + + + + + ;$(DDK_LIB_PATH)\displib.lib;$(DDK_LIB_PATH)\ntoskrnl.lib;$(DDK_LIB_PATH)\hal.lib + + + %(AdditionalIncludeDirectories);$(DDK_INC_PATH);$(SDK_INC_PATH) + + + %(AdditionalIncludeDirectories);$(DDK_INC_PATH);$(SDK_INC_PATH) + + + + + ;$(DDK_LIB_PATH)\displib.lib;$(DDK_LIB_PATH)\ntoskrnl.lib;$(DDK_LIB_PATH)\hal.lib + + + %(AdditionalIncludeDirectories);$(DDK_INC_PATH);$(SDK_INC_PATH) + + + %(AdditionalIncludeDirectories);$(DDK_INC_PATH);$(SDK_INC_PATH) + + + + + ;$(DDK_LIB_PATH)\displib.lib;$(DDK_LIB_PATH)\ntoskrnl.lib;$(DDK_LIB_PATH)\hal.lib + + + %(AdditionalIncludeDirectories);$(DDK_INC_PATH);$(SDK_INC_PATH) + + + %(AdditionalIncludeDirectories);$(DDK_INC_PATH);$(SDK_INC_PATH) + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/qxldod/qxldod.vcxproj.filters b/qxldod/qxldod.vcxproj.filters new file mode 100755 index 0000000..db5df31 --- /dev/null +++ b/qxldod/qxldod.vcxproj.filters @@ -0,0 +1,56 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + {8E41214B-6785-4CFE-B992-037D68949A14} + inf;inv;inx;mof;mc; + + + + + Driver Files + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + + + Source Files + + + Source Files + + + Source Files + + + + + Resource Files + + + \ No newline at end of file diff --git a/qxldod/resource.h b/qxldod/resource.h new file mode 100755 index 0000000..4c0462f --- /dev/null +++ b/qxldod/resource.h @@ -0,0 +1,14 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by qxldod.rc + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 101 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1001 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif