9aaae88e4a
Signed-off-by: Frediano Ziglio <fziglio@redhat.com> Acked-by: Yuri Benditovich <yuri.benditovich@daynix.com>
788 lines
25 KiB
C++
Executable File
788 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"
|
|
|
|
#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();
|
|
|
|
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__));
|
|
}
|
|
|
|
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%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_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
|