qxl-wddm-dod/qxldod/driver.cpp
yuri.benditovich@daynix.com 454a66a25a qxl-wddm-dod: Support ETW for release version
Add ability to produce ETW (Event Tracing for Windows) to release
version of the driver to be able to record binary traces in case
of problem in customer environment for further analysis.
Logging of debug build is not changed.

Signed-off-by: Yuri Benditovich <yuri.benditovich@daynix.com>
Acked-by: Frediano Ziglio <fziglio@redhat.com>
2017-07-09 09:46:33 +01:00

794 lines
25 KiB
C++
Executable File

/*
* Copyright 2013-2016 Red Hat, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
*
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
*/
#include "driver.h"
#include "QxlDod.h"
#if !DBG
#include "driver.tmh"
#endif
#pragma code_seg(push)
#pragma code_seg("INIT")
// BEGIN: Init Code
//
// Driver Entry point
//
int nDebugLevel = TRACE_LEVEL_ERROR;
// registry-based configuration is intended to be manual only
// for VSync suppression during support and troubleshooting
// and not expected to be made default
static void QueryVSyncSetting(BOOLEAN& b, const UNICODE_STRING *path)
{
PAGED_CODE();
WCHAR buffer[MAX_PATH];
ULONG val = b;
RTL_QUERY_REGISTRY_TABLE QueryTable[3] = {};
if (path->Length >= sizeof(buffer))
return;
QueryTable[0].Flags = RTL_QUERY_REGISTRY_SUBKEY;
QueryTable[0].Name = L"Parameters";
QueryTable[1].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_TYPECHECK | RTL_QUERY_REGISTRY_REQUIRED;
QueryTable[1].Name = L"EnableVSync";
QueryTable[1].DefaultType = REG_DWORD << 24;
QueryTable[1].EntryContext = &val;
RtlCopyMemory(buffer, path->Buffer, path->Length);
buffer[path->Length/2] = 0;
NTSTATUS status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE, buffer, QueryTable, NULL, NULL);
if (NT_SUCCESS(status))
{
DbgPrint(TRACE_LEVEL_INFORMATION, ("%s: val = %d\n", __FUNCTION__, val));
b = !!val;
}
else
{
DbgPrint(TRACE_LEVEL_INFORMATION, ("%s: status = %X\n", __FUNCTION__, status));
}
}
extern "C"
NTSTATUS
DriverEntry(
_In_ DRIVER_OBJECT* pDriverObject,
_In_ UNICODE_STRING* pRegistryPath)
{
PAGED_CODE();
WPP_INIT_TRACING(NULL, NULL);
DbgPrint(TRACE_LEVEL_FATAL, ("---> KMDOD build on on %s %s\n", __DATE__, __TIME__));
RTL_OSVERSIONINFOW versionInfo;
versionInfo.dwOSVersionInfoSize = sizeof(versionInfo);
RtlGetVersion(&versionInfo);
// VSync control is NOT planned to be enabled on Win10 builds
// before RS1. Enabling it on DOD driver causes OS to stop the driver
// with error 43 when the system turns off display due to idle setting.
// On Windows 8.1 (9200 and 9600) till now no problem observed
// (OS does not send VSync enable command)
// On Windows 10RS1 (14393) enabling VSync control activates
// watchdog policy and creates high sensitivity to long (> 2 sec)
// processing in PresentDisplayOnly callback (stop with error 43)
if (versionInfo.dwBuildNumber >= 14393 || versionInfo.dwBuildNumber <= 9600)
{
// we will uncomment the line below after we address all the problems
// related to enabled VSync control in Win10RS1
//g_bSupportVSync = TRUE;
// for support/troubleshooting be able to disable VSync on specific machine
QueryVSyncSetting(g_bSupportVSync, pRegistryPath);
}
DbgPrint(TRACE_LEVEL_WARNING, ("VSync support %sabled for %d.%d.%d\n",
g_bSupportVSync ? "en" : "dis",
versionInfo.dwMajorVersion, versionInfo.dwMinorVersion, versionInfo.dwBuildNumber));
// Initialize DDI function pointers and dxgkrnl
KMDDOD_INITIALIZATION_DATA InitialData = {0};
InitialData.Version = DXGKDDI_INTERFACE_VERSION;
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;
if (g_bSupportVSync)
{
InitialData.DxgkDdiControlInterrupt = DodControlInterrupt;
InitialData.DxgkDdiGetScanLine = DodGetScanLine;
}
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__));
WPP_CLEANUP(NULL);
}
NTSTATUS
DodAddDevice(
_In_ DEVICE_OBJECT* pPhysicalDeviceObject,
_Outptr_ PVOID* ppDeviceContext)
{
PAGED_CODE();
DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__));
if ((pPhysicalDeviceObject == NULL) ||
(ppDeviceContext == NULL))
{
DbgPrint(TRACE_LEVEL_ERROR, ("One of pPhysicalDeviceObject (0x%p), ppDeviceContext (0x%p) 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_VERBOSE, ("<--- %s\n", __FUNCTION__));
return STATUS_SUCCESS;
}
NTSTATUS
DodRemoveDevice(
_In_ VOID* pDeviceContext)
{
PAGED_CODE();
DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__));
QxlDod* pQxl = reinterpret_cast<QxlDod*>(pDeviceContext);
delete pQxl;
DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %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_VERBOSE, ("<---> %s\n", __FUNCTION__));
QxlDod* pQxl = reinterpret_cast<QxlDod*>(pDeviceContext);
return pQxl->StartDevice(pDxgkStartInfo, pDxgkInterface, pNumberOfViews, pNumberOfChildren);
}
NTSTATUS
DodStopDevice(
_In_ VOID* pDeviceContext)
{
PAGED_CODE();
QXL_ASSERT_CHK(pDeviceContext != NULL);
DbgPrint(TRACE_LEVEL_VERBOSE, ("<---> %s\n", __FUNCTION__));
QxlDod* pQxl = reinterpret_cast<QxlDod*>(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_VERBOSE, ("<---> %s\n", __FUNCTION__));
QxlDod* pQxl = reinterpret_cast<QxlDod*>(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_VERBOSE, ("<---> %s\n", __FUNCTION__));
QxlDod* pQxl = reinterpret_cast<QxlDod*>(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_VERBOSE, ("<---> %s\n", __FUNCTION__));
QxlDod* pQxl = reinterpret_cast<QxlDod*>(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_VERBOSE, ("<---> %s\n", __FUNCTION__));
QxlDod* pQxl = reinterpret_cast<QxlDod*>(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_VERBOSE, ("<---> %s\n", __FUNCTION__));
QxlDod* pQxl = reinterpret_cast<QxlDod*>(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 (%p) 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_VERBOSE, ("<---> %s\n", __FUNCTION__));
QxlDod* pQxl = reinterpret_cast<QxlDod*>(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_VERBOSE, ("<---> %s\n", __FUNCTION__));
QxlDod* pQxl = reinterpret_cast<QxlDod*>(hAdapter);
if (!pQxl->IsDriverActive())
{
QXL_LOG_ASSERTION1("QXL (%p) 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_VERBOSE, ("<---> %s\n", __FUNCTION__));
QxlDod* pQxl = reinterpret_cast<QxlDod*>(hAdapter);
if (!pQxl->IsDriverActive())
{
QXL_LOG_ASSERTION1("QXL (%p) 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_VERBOSE, ("<---> %s\n", __FUNCTION__));
QxlDod* pQxl = reinterpret_cast<QxlDod*>(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_VERBOSE, ("<---> %s\n", __FUNCTION__));
QxlDod* pQxl = reinterpret_cast<QxlDod*>(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_VERBOSE, ("<---> %s\n", __FUNCTION__));
QxlDod* pQxl = reinterpret_cast<QxlDod*>(hAdapter);
if (!pQxl->IsDriverActive())
{
QXL_LOG_ASSERTION1("QXL (%p) 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_VERBOSE, ("<---> %s\n", __FUNCTION__));
QxlDod* pQxl = reinterpret_cast<QxlDod*>(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_VERBOSE, ("<---> %s\n", __FUNCTION__));
QxlDod* pQxl = reinterpret_cast<QxlDod*>(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 (%p) 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_VERBOSE, ("<---> %s\n", __FUNCTION__));
QxlDod* pQxl = reinterpret_cast<QxlDod*>(hAdapter);
if (!pQxl->IsDriverActive())
{
QXL_LOG_ASSERTION1("QXL (%p) 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_VERBOSE, ("<---> %s\n", __FUNCTION__));
QxlDod* pQxl = reinterpret_cast<QxlDod*>(hAdapter);
if (!pQxl->IsDriverActive())
{
QXL_LOG_ASSERTION1("QXL (%p) 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_VERBOSE, ("<---> %s\n", __FUNCTION__));
QxlDod* pQxl = reinterpret_cast<QxlDod*>(hAdapter);
if (!pQxl->IsDriverActive())
{
QXL_LOG_ASSERTION1("QXL (%p) 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_VERBOSE, ("<---> %s\n", __FUNCTION__));
QxlDod* pQxl = reinterpret_cast<QxlDod*>(hAdapter);
if (!pQxl->IsDriverActive())
{
QXL_LOG_ASSERTION1("QXL (%p) 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_VERBOSE, ("<---> %s\n", __FUNCTION__));
QxlDod* pQxl = reinterpret_cast<QxlDod*>(hAdapter);
if (!pQxl->IsDriverActive())
{
QXL_LOG_ASSERTION1("QXL (%p) 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_VERBOSE, ("<---> %s\n", __FUNCTION__));
QxlDod* pQxl = reinterpret_cast<QxlDod*>(hAdapter);
if (!pQxl->IsDriverActive())
{
QXL_LOG_ASSERTION1("QXL (%p) 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_VERBOSE, ("<---> %s\n", __FUNCTION__));
QxlDod* pQxl = reinterpret_cast<QxlDod*>(hAdapter);
if (!pQxl->IsDriverActive())
{
QXL_LOG_ASSERTION1("QXL (%p) 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_VERBOSE, ("<---> %s\n", __FUNCTION__));
QxlDod* pQxl = reinterpret_cast<QxlDod*>(hAdapter);
if (!pQxl->IsDriverActive())
{
QXL_LOG_ASSERTION1("QXL (%p) is being called when not active!", pQxl);
return STATUS_UNSUCCESSFUL;
}
return pQxl->QueryVidPnHWCapability(pVidPnHWCaps);
}
NTSTATUS
APIENTRY
DodControlInterrupt(
IN_CONST_HANDLE hAdapter,
IN_CONST_DXGK_INTERRUPT_TYPE InterruptType,
IN_BOOLEAN EnableInterrupt
)
{
PAGED_CODE();
QxlDod* pQxl = reinterpret_cast<QxlDod*>(hAdapter);
if (InterruptType == DXGK_INTERRUPT_DISPLAYONLY_VSYNC)
{
pQxl->EnableVsync(EnableInterrupt);
return STATUS_SUCCESS;
}
return STATUS_NOT_IMPLEMENTED;
}
NTSTATUS
APIENTRY
DodGetScanLine(
IN_CONST_HANDLE hAdapter,
INOUT_PDXGKARG_GETSCANLINE pGetScanLine
)
{
PAGED_CODE();
// Currently we do not see any practical use case when this procedure is called
// IDirectDraw has an interface for querying scan line
// Leave it not implemented like remote desktop does
// until we recognize use case for more intelligent implementation
DbgPrint(TRACE_LEVEL_ERROR, ("<---> %s\n", __FUNCTION__));
return STATUS_NOT_IMPLEMENTED;
}
//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_VERBOSE, ("---> %s\n", __FUNCTION__));
QxlDod* pQxl = reinterpret_cast<QxlDod*>(pDeviceContext);
if (!pQxl->IsDriverActive())
{
QXL_LOG_ASSERTION1("QXL (%p) is being called when not active!", pQxl);
return;
}
pQxl->DpcRoutine();
DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__));
}
BOOLEAN
DodInterruptRoutine(
_In_ VOID* pDeviceContext,
_In_ ULONG MessageNumber)
{
QXL_ASSERT_CHK(pDeviceContext != NULL);
DbgPrint(TRACE_LEVEL_VERBOSE, ("<---> %s\n", __FUNCTION__));
QxlDod* pQxl = reinterpret_cast<QxlDod*>(pDeviceContext);
return pQxl->InterruptRoutine(MessageNumber);
}
VOID
DodResetDevice(
_In_ VOID* pDeviceContext)
{
QXL_ASSERT_CHK(pDeviceContext != NULL);
DbgPrint(TRACE_LEVEL_VERBOSE, ("<---> %s\n", __FUNCTION__));
QxlDod* pQxl = reinterpret_cast<QxlDod*>(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_VERBOSE, ("<---> %s\n", __FUNCTION__));
QxlDod* pQxl = reinterpret_cast<QxlDod*>(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<QxlDod*>(pDeviceContext);
pQxl->SystemDisplayWrite(Source, SourceWidth, SourceHeight, SourceStride, PositionX, PositionY);
}
#if defined(DBG)
#define RHEL_DEBUG_PORT ((PUCHAR)0x3F8)
#define TEMP_BUFFER_SIZE 256
static void DebugPrintFuncSerial(const char *format, va_list list)
{
char buf[TEMP_BUFFER_SIZE];
NTSTATUS status;
size_t len;
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, (ULONG)len);
WRITE_PORT_UCHAR(RHEL_DEBUG_PORT, '\r');
}
}
void DebugPrint(int level, const char *fmt, ...)
{
va_list list;
if (level <= nDebugLevel) {
va_start(list, fmt);
DebugPrintFuncSerial(fmt, list);
va_end(list);
}
static const ULONG xlate[] = { 0, 0, 1, 2, 3 };
if (level <= 0 || level > 5)
return;
va_start(list, fmt);
vDbgPrintEx(DPFLTR_IHVVIDEO_ID, xlate[level - 1], fmt, list);
va_end(list);
}
#endif
#pragma code_seg(pop) // End Non-Paged Code