windows-nt/Source/XPSP1/NT/drivers/video/ms/port/videoprt.c

9649 lines
274 KiB
C
Raw Normal View History

2020-09-26 03:20:57 -05:00
/*++
Copyright (c) 1990-2000 Microsoft Corporation
Module Name:
videoprt.c
Abstract:
This is the NT Video port driver.
Author:
Andre Vachon (andreva) 18-Dec-1991
Environment:
kernel mode only
Notes:
This module is a driver which implements OS dependant functions on the
behalf of the video drivers
Revision History:
--*/
#define INITGUID
#include "videoprt.h"
NTSTATUS
DriverEntry(
IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPath
);
#ifdef ALLOC_PRAGMA
#pragma alloc_text(INIT,DriverEntry)
#pragma alloc_text(PAGE,pVideoPortCreateDeviceName)
#pragma alloc_text(PAGE,pVideoPortDispatch)
#pragma alloc_text(PAGE,VideoPortFreeDeviceBase)
#pragma alloc_text(PAGE,pVideoPortFreeDeviceBase)
#pragma alloc_text(PAGE,pVideoPortGetDeviceBase)
#pragma alloc_text(PAGE,VideoPortGetDeviceBase)
#pragma alloc_text(PAGE,pVideoPortGetDeviceDataRegistry)
#pragma alloc_text(PAGE,VideoPortGetDeviceData)
#pragma alloc_text(PAGE,pVideoPortGetRegistryCallback)
#pragma alloc_text(PAGE,VideoPortGetRegistryParameters)
#pragma alloc_text(PAGE,pVPInit)
#pragma alloc_text(PAGE,VpInitializeBusCallback)
#pragma alloc_text(PAGE,VpDriverUnload)
#pragma alloc_text(PAGE,VpAddDevice)
#pragma alloc_text(PAGE,VpCreateDevice)
#pragma alloc_text(PAGE,VideoPortInitialize)
#pragma alloc_text(PAGE,UpdateRegValue)
#pragma alloc_text(PAGE,VideoPortLegacyFindAdapter)
#pragma alloc_text(PAGE,VideoPortFindAdapter2)
#pragma alloc_text(PAGE,VideoPortFindAdapter)
#pragma alloc_text(PAGE,pVideoPortMapToNtStatus)
#pragma alloc_text(PAGE,pVideoPortMapUserPhysicalMem)
#pragma alloc_text(PAGE,VideoPortMapMemory)
#pragma alloc_text(PAGE,VideoPortMapBankedMemory)
#pragma alloc_text(PAGE,VideoPortAllocateBuffer)
#pragma alloc_text(PAGE,VideoPortReleaseBuffer)
#pragma alloc_text(PAGE,VideoPortScanRom)
#pragma alloc_text(PAGE,VideoPortSetRegistryParameters)
#pragma alloc_text(PAGE,VideoPortUnmapMemory)
#pragma alloc_text(PAGE,VpEnableDisplay)
#pragma alloc_text(PAGE,VpWin32kCallout)
#pragma alloc_text(PAGE,VpAllowFindAdapter)
#pragma alloc_text(PAGE,VpTranslateBusAddress)
#if DBG
#pragma alloc_text(PAGE,BuildRequirements)
#pragma alloc_text(PAGE,DumpRequirements)
#pragma alloc_text(PAGE,DumpResourceList)
#pragma alloc_text(PAGE,DumpUnicodeString)
#endif
#pragma alloc_text(PAGE,VideoPortCreateSecondaryDisplay)
#pragma alloc_text(PAGE,VideoPortQueryServices)
#pragma alloc_text(PAGE,VpInterfaceDefaultReference)
#pragma alloc_text(PAGE,VpInterfaceDefaultDereference)
#pragma alloc_text(PAGE,VpEnableAdapterInterface)
#pragma alloc_text(PAGE,VpDisableAdapterInterface)
//
// VideoPortQueryPerformanceCounter() cannot be pageable.
//
#endif
NTSTATUS
DriverEntry(
IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPath
)
/*++
Routine Description:
Temporary entry point needed to initialize the video port driver.
Arguments:
DriverObject - Pointer to the driver object created by the system.
Return Value:
STATUS_SUCCESS
--*/
{
UNREFERENCED_PARAMETER(DriverObject);
ASSERT(0);
//
//
//
// WARNING !!!
//
// This function is never called because we are loaded as a DLL by other video drivers !
//
//
//
//
//
//
// We always return STATUS_SUCCESS because otherwise no video miniport
// driver will be able to call us.
//
return STATUS_SUCCESS;
} // end DriverEntry()
NTSTATUS
pVideoPortCreateDeviceName(
PWSTR DeviceString,
ULONG DeviceNumber,
PUNICODE_STRING UnicodeString,
PWCHAR UnicodeBuffer
)
/*++
Routine Description:
Helper function that does string manipulation to create a device name
--*/
{
WCHAR ntNumberBuffer[STRING_LENGTH];
UNICODE_STRING ntNumberUnicodeString;
//
// Create the name buffer
//
UnicodeString->Buffer = UnicodeBuffer;
UnicodeString->Length = 0;
UnicodeString->MaximumLength = STRING_LENGTH;
//
// Create the miniport driver object name.
//
ntNumberUnicodeString.Buffer = ntNumberBuffer;
ntNumberUnicodeString.Length = 0;
ntNumberUnicodeString.MaximumLength = STRING_LENGTH;
if (NT_SUCCESS(RtlIntegerToUnicodeString(DeviceNumber,
10,
&ntNumberUnicodeString))) {
if (NT_SUCCESS(RtlAppendUnicodeToString(UnicodeString,
DeviceString))) {
if (NT_SUCCESS(RtlAppendUnicodeStringToString(UnicodeString,
&ntNumberUnicodeString))) {
UnicodeString->MaximumLength = (USHORT)
(UnicodeString->Length + sizeof(UNICODE_NULL));
return STATUS_SUCCESS;
}
}
}
return STATUS_INSUFFICIENT_RESOURCES;
} // pVideoPortCreateDeviceName()
VOID
VideoPortDebugPrint(
VIDEO_DEBUG_LEVEL DebugPrintLevel,
PCHAR DebugMessage,
...
)
/*++
Routine Description:
This routine allows the miniport drivers (as well as the port driver) to
display error messages to the debug port when running in the debug
environment.
When running a non-debugged system, all references to this call are
eliminated by the compiler.
Arguments:
DebugPrintLevel - Debug print level being:
0 = Error Level (always prints no matter what on a checked build)
1 = Warning Level (prints only when VIDEO filter is on for this level or higher)
2 = Trace Level (see above)
3 = Info Level (see above)
Return Value:
None.
--*/
{
va_list ap;
va_start(ap, DebugMessage);
if (VideoDebugLevel && (VideoDebugLevel >= (ULONG)DebugPrintLevel)) {
vDbgPrintEx(DPFLTR_VIDEO_ID, 0, DebugMessage, ap);
} else {
vDbgPrintEx(DPFLTR_VIDEO_ID, DebugPrintLevel, DebugMessage, ap);
}
va_end(ap);
} // VideoPortDebugPrint()
VOID
VpEnableDisplay(
PFDO_EXTENSION fdoExtension,
BOOLEAN bState
)
/*++
Routine Description:
This routine enables/disables the current display so that we can execut
the drivers FindAdapter code.
Arugments:
bState - Should the display be enabled or disabled
Returns:
none
Notes:
The device lock for the passed in fdoExtension must be held
before this routine is called!
--*/
{
if (!InbvCheckDisplayOwnership()) {
VIDEO_WIN32K_CALLBACKS_PARAMS calloutParams;
//
// The system is up and running. Notify GDI to enable/disable
// the current display.
//
calloutParams.CalloutType = VideoFindAdapterCallout;
calloutParams.Param = bState;
RELEASE_DEVICE_LOCK(fdoExtension);
VpWin32kCallout(&calloutParams);
ACQUIRE_DEVICE_LOCK(fdoExtension);
} else {
//
// The boot driver is still in control. Modify the state of the
// boot driver.
//
InbvEnableBootDriver(bState);
}
}
VOID
VpWin32kCallout(
PVIDEO_WIN32K_CALLBACKS_PARAMS calloutParams
)
/*++
Routine Description:
This routine makes a callout into win32k. It attaches to csrss
to guarantee that win32k is in the address space on hydra machines.
Arguments:
calloutParams - a pointer to the callout struture.
Returns:
none.
--*/
{
if (Win32kCallout && CsrProcess) {
KeAttachProcess(PEProcessToPKProcess(CsrProcess));
(*Win32kCallout)(calloutParams);
KeDetachProcess();
}
}
BOOLEAN
VpAllowFindAdapter(
PFDO_EXTENSION fdoExtension
)
/*++
Routine Description:
Determine if we allow this device to be used if part of a multi-function
board.
Arguments;
fdoExtension - The device extenstion for the object in question.
Returns:
TRUE if the device is allowed as part of a multi-function board.
FALSE otherwise.
--*/
{
BOOLEAN bRet = TRUE;
if ((fdoExtension->AdapterInterfaceType == PCIBus) &&
((fdoExtension->Flags & PNP_ENABLED) == PNP_ENABLED)) {
PCI_COMMON_CONFIG ConfigSpace;
if (PCI_COMMON_HDR_LENGTH ==
VideoPortGetBusData(fdoExtension->HwDeviceExtension,
PCIConfiguration,
0,
&ConfigSpace,
0,
PCI_COMMON_HDR_LENGTH)) {
if (PCI_MULTIFUNCTION_DEVICE(&ConfigSpace)) {
ULONG MultiFunc = 0;
//
// This is a multi-function device. So only allow
// HwInitialize if the INF indicated we'd be multi-function.
//
VideoPortGetRegistryParameters(fdoExtension->HwDeviceExtension,
L"MultiFunctionSupported",
FALSE,
VpRegistryCallback,
&MultiFunc);
if (MultiFunc == 0) {
pVideoDebugPrint((Warn, "VIDEOPRT: Multifunction board not allowed to start\n"));
bRet = FALSE;
}
}
}
}
return bRet;
}
NTSTATUS
pVideoPortDispatch(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
/*++
Routine Description:
This routine is the main dispatch routine for the video port driver.
It accepts an I/O Request Packet, transforms it to a video Request
Packet, and forwards it to the appropriate miniport dispatch routine.
Upon returning, it completes the request and return the appropriate
status value.
Arguments:
DeviceObject - Pointer to the device object of the miniport driver to
which the request must be sent.
Irp - Pointer to the request packet representing the I/O request.
Return Value:
The function value os the status of the operation.
--*/
{
PFDO_EXTENSION combinedExtension;
PFDO_EXTENSION fdoExtension;
PVOID HwDeviceExtension;
PDEVICE_SPECIFIC_EXTENSION DoSpecificExtension;
PCHILD_PDO_EXTENSION pdoExtension = NULL;
PIO_STACK_LOCATION irpStack;
PVOID ioBuffer;
ULONG inputBufferLength;
ULONG outputBufferLength;
PSTATUS_BLOCK statusBlock;
NTSTATUS finalStatus = -1;
ULONG ioControlCode;
VIDEO_REQUEST_PACKET vrp;
NTSTATUS status;
PBACKLIGHT_STATUS pVpBacklightStatus = &VpBacklightStatus;
ULONG ulACPIMethodParam1;
ULONG ulACPIMethodParam2;
HANDLE hkRegistry;
UNICODE_STRING UnicodeString;
OBJECT_ATTRIBUTES ObjectAttributes;
#if _X86_
PUCHAR BiosDataBuffer;
#define BIOS_DATA_SIZE 256
#endif
//
// Get pointer to the port driver's device extension.
//
combinedExtension = DeviceObject->DeviceExtension;
HwDeviceExtension = combinedExtension->HwDeviceExtension;
//
// Get pointer to the port driver's device extension.
//
if (IS_PDO(DeviceObject->DeviceExtension)) {
pdoExtension = DeviceObject->DeviceExtension;
fdoExtension = pdoExtension->pFdoExtension;
DoSpecificExtension = (PDEVICE_SPECIFIC_EXTENSION)(fdoExtension + 1);
} else if (IS_FDO(DeviceObject->DeviceExtension)) {
fdoExtension = DeviceObject->DeviceExtension;
DoSpecificExtension = (PDEVICE_SPECIFIC_EXTENSION)(fdoExtension + 1);
} else {
DoSpecificExtension = DeviceObject->DeviceExtension;
fdoExtension = DoSpecificExtension->pFdoExtension;
combinedExtension = fdoExtension;
}
//
// Get a pointer to the current location in the Irp. This is where
// the function codes and parameters are located.
//
irpStack = IoGetCurrentIrpStackLocation(Irp);
//
// Get the pointer to the status buffer.
// Assume SUCCESS for now.
//
statusBlock = (PSTATUS_BLOCK) &Irp->IoStatus;
//
// Synchronize execution of the dispatch routine by acquiring the device
// event object. This ensures all request are serialized.
// The synchronization must be done explicitly because the functions
// executed in the dispatch routine use system services that cannot
// be executed in the start I/O routine.
//
// The synchronization is done on the miniport's event so as not to
// block commands coming in for another device.
//
#if REMOVE_LOCK_ENABLED
status = IoAcquireRemoveLock(&combinedExtension->RemoveLock, Irp);
if (NT_SUCCESS(status) == FALSE) {
ASSERT(FALSE);
Irp->IoStatus.Information = 0;
Irp->IoStatus.Status = status;
IoCompleteRequest(Irp, IO_VIDEO_INCREMENT);
return status;
}
#endif
ACQUIRE_DEVICE_LOCK(combinedExtension);
//
// Get the requestor mode.
//
combinedExtension->CurrentIrpRequestorMode = Irp->RequestorMode;
ASSERT(irpStack->MajorFunction != IRP_MJ_PNP);
ASSERT(irpStack->MajorFunction != IRP_MJ_POWER);
//
// Case on the function being requested.
// If the function is operating specific, intercept the operation and
// perform directly. Otherwise, pass it on to the appropriate miniport.
//
switch (irpStack->MajorFunction) {
//
// Called by the display driver *or a user-mode application*
// to get exclusive access to the device.
// This access is given by the I/O system (based on a bit set during the
// IoCreateDevice() call).
//
case IRP_MJ_CREATE:
pVideoDebugPrint((Trace, "VIDEOPRT: IRP_MJ_CREATE\n"));
if (Irp->RequestorMode == UserMode)
{
statusBlock->Status = STATUS_SUCCESS;
break;
}
//
// Don't let an old driver start during the upgrade
//
if (fdoExtension->Flags & UPGRADE_FAIL_START)
{
statusBlock->Status = STATUS_ACCESS_DENIED;
break;
}
//
// Don't allow create's on children, unless they are a monitor
// which will receive calls from the display driver
//
if (IS_PDO(pdoExtension)) {
pVideoDebugPrint((Error, "VIDEOPRT: Create's on children devices not allowed.\n"));
statusBlock->Status = STATUS_ACCESS_DENIED;
break;
}
//
// Special hack to succeed on Attach, but do nothing ...
// If the device is already opened, do nothing.
//
if ((irpStack->Parameters.Create.SecurityContext->DesiredAccess ==
FILE_READ_ATTRIBUTES) ||
(DoSpecificExtension->DeviceOpened)) {
statusBlock->Information = FILE_OPEN;
statusBlock->Status = STATUS_SUCCESS;
break;
}
//
// If we haven't already done so, create our watchdog recovery event
//
if (VpThreadStuckEvent == NULL) {
UNICODE_STRING strName;
RtlInitUnicodeString(&strName, L"\\BaseNamedObjects\\StuckThreadEvent");
VpThreadStuckEvent = IoCreateNotificationEvent(&strName, &VpThreadStuckEventHandle);
if (VpThreadStuckEvent) {
KeClearEvent(VpThreadStuckEvent);
}
}
//
// Get out of the special setup mode that we may be in
//
VpSetupType = 0;
//
// If hwInitialize has been called then the system is done
// initializing and we are transitioning into gui mode.
//
VpSystemInitialized = TRUE;
//
// Now perform basic initialization to allow the Windows display
// driver to set up the device appropriately.
//
statusBlock->Information = FILE_OPEN;
//
// If the address space has not been set up in the server yet, do it now.
// NOTE: no need to map in IO ports since the server has IOPL
//
if (CsrProcess == NULL)
{
CsrProcess = PsGetCurrentProcess();
ObReferenceObject(CsrProcess);
}
pVideoPortInitializeInt10(fdoExtension);
if (!IsMirrorDriver(fdoExtension)) {
//
// Tell the kernel we are now taking ownership the display, but
// only do so if this is not a mirroring driver.
//
InbvNotifyDisplayOwnershipLost(pVideoPortResetDisplay);
}
if ((fdoExtension->Flags & FINDADAPTER_SUCCEEDED) == 0) {
statusBlock->Status = STATUS_DEVICE_CONFIGURATION_ERROR;
} else if ((fdoExtension->HwInitStatus == HwInitNotCalled) &&
(fdoExtension->HwInitialize(fdoExtension->HwDeviceExtension) == FALSE))
{
statusBlock->Status = STATUS_DEVICE_CONFIGURATION_ERROR;
fdoExtension->HwInitStatus = HwInitFailed;
} else if (fdoExtension->HwInitStatus == HwInitFailed) {
statusBlock->Status = STATUS_DEVICE_CONFIGURATION_ERROR;
} else {
fdoExtension->HwInitStatus = HwInitSucceeded;
statusBlock->Status = STATUS_SUCCESS;
}
//
// Mark the device as opened so we will fail future opens.
//
DoSpecificExtension->DeviceOpened = TRUE;
//
// We don't want GDI to use any drivers other than display
// or boot drivers during upgrade setup.
//
if (fdoExtension->Flags & UPGRADE_FAIL_HWINIT) {
statusBlock->Status = STATUS_ACCESS_DENIED;
}
break;
//
// Called when the display driver wishes to give up it's handle to the
// device.
//
case IRP_MJ_CLOSE:
pVideoDebugPrint((Trace, "VIDEOPRT: IRP_MJ_CLOSE\n"));
statusBlock->Status = STATUS_SUCCESS;
break;
//
// Device Controls are specific functions for the driver.
// First check for calls that must be intercepted and hidden from the
// miniport driver. These calls are hidden for simplicity.
// The other control functions are passed down to the miniport after
// the request structure has been filled out properly.
//
case IRP_MJ_DEVICE_CONTROL:
//
// Get the pointer to the input/output buffer and it's length
//
ioBuffer = Irp->AssociatedIrp.SystemBuffer;
inputBufferLength = irpStack->Parameters.DeviceIoControl.InputBufferLength;
outputBufferLength = irpStack->Parameters.DeviceIoControl.OutputBufferLength;
ioControlCode = irpStack->Parameters.DeviceIoControl.IoControlCode;
if (Irp->RequestorMode == UserMode)
{
statusBlock->Information = 0;
if ((ioControlCode != IOCTL_VIDEO_QUERY_SUPPORTED_BRIGHTNESS) &&
(ioControlCode != IOCTL_VIDEO_QUERY_DISPLAY_BRIGHTNESS) &&
(ioControlCode != IOCTL_VIDEO_SET_DISPLAY_BRIGHTNESS))
{
statusBlock->Status = STATUS_ACCESS_DENIED;
break;
}
}
#ifdef IOCTL_VIDEO_USE_DEVICE_IN_SESSION
//
// Validate session usage
//
// Note: Some IOCTLs are acceptable to call from non-console sessions
// These include all private IOCTLs which is completely under
// the drivers' control and may happen even when the device is
// disabled. IOCTL_VIDEO_REGISTER_VDM is also allowed since
// it doesn't access any hardware.
//
if ((ioControlCode & CTL_CODE(0x8000, 0x800, METHOD_BUFFERED, FILE_ANY_ACCESS)) == 0 &&
ioControlCode != IOCTL_VIDEO_REGISTER_VDM)
{
if (DoSpecificExtension->SessionId != VIDEO_DEVICE_INVALID_SESSION &&
PsGetCurrentProcessSessionId() != DoSpecificExtension->SessionId)
{
DbgPrint("VIDEOPRT: Trying to use display device in sessions %lu and %lu.\n",
DoSpecificExtension->SessionId,
PsGetCurrentProcessSessionId());
//
// We will also allow several other IOCTLs to be called from
// a non-console session.
// For simplicity we allow all IOCTLs for which the driver
// provides support with the exception of
// IOCTL_VIDEO_ENABLE_VDM.
//
if ((ioControlCode &
CTL_CODE(0x7fff, 0x7ff, METHOD_BUFFERED, FILE_ANY_ACCESS)) <=
IOCTL_VIDEO_USE_DEVICE_IN_SESSION)
{
ASSERT(FALSE);
}
else
{
DbgPrint("VIDEOPRT: Cross session use is acceptable in this case.\n");
}
}
}
#endif IOCTL_VIDEO_USE_DEVICE_IN_SESSION
//
// Enabling or disabling the VDM is done only by the port driver.
//
if (ioControlCode == IOCTL_VIDEO_REGISTER_VDM) {
pVideoDebugPrint((Trace, "VIDEOPRT: IOCTL_VIDEO_REGISTER_VDM\n"));
ASSERT(IS_PDO(pdoExtension) == FALSE);
statusBlock->Status = pVideoPortRegisterVDM(fdoExtension,
(PVIDEO_VDM) ioBuffer,
inputBufferLength,
(PVIDEO_REGISTER_VDM) ioBuffer,
outputBufferLength,
&statusBlock->Information);
} else if (ioControlCode == IOCTL_VIDEO_DISABLE_VDM) {
pVideoDebugPrint((Trace, "VIDEOPRT: IOCTL_VIDEO_DISABLE_VDM"));
ASSERT(IS_PDO(pdoExtension) == FALSE);
statusBlock->Status = pVideoPortEnableVDM(fdoExtension,
FALSE,
(PVIDEO_VDM) ioBuffer,
inputBufferLength);
} else if ((ioControlCode == IOCTL_VIDEO_SET_OUTPUT_DEVICE_POWER_STATE) ||
(ioControlCode == IOCTL_VIDEO_GET_OUTPUT_DEVICE_POWER_STATE)) {
//
// This handles the case where ntuser has signalled that it wants
// to change or detect the power state.
//
PCHILD_PDO_EXTENSION pChild;
PPOWER_BLOCK powerCtx = NULL;
ULONG count = 0;
UCHAR mFnc =
(ioControlCode == IOCTL_VIDEO_SET_OUTPUT_DEVICE_POWER_STATE) ?
IRP_MN_SET_POWER : IRP_MN_QUERY_POWER ;
pVideoDebugPrint((Trace, "VIDEOPRT: IOCTL_%s_OUTPUT_DEVICE_POWER_STATE\n",
ioControlCode == IOCTL_VIDEO_SET_OUTPUT_DEVICE_POWER_STATE ? "SET" : "GET"));
//
// USER wants to set the power on the monitor, not the card.
// So let's find our child monitor and send it the power management
// function.
// If there is no power manageable monitor, then we can just fail
// the request right here.
//
ASSERT(IS_PDO(pdoExtension) == FALSE);
if (fdoExtension->ChildPdoList)
{
//
// Count the number of monitor devices so that the IRP will
// be completed properly after a power IRP has been requested
// for each.
//
for (pChild = fdoExtension->ChildPdoList;
pChild;
pChild = pChild->NextChild) {
if (pChild->VideoChildDescriptor->Type == Monitor)
count++;
}
for (pChild = fdoExtension->ChildPdoList;
pChild;
pChild = pChild->NextChild)
{
if (pChild->VideoChildDescriptor->Type == Monitor)
{
count--;
//
// Allocate memory for the IRP context.
//
powerCtx = ExAllocatePoolWithTag(NonPagedPool,
sizeof(POWER_BLOCK),
VP_TAG);
if (!powerCtx) {
pVideoDebugPrint ((Error, "VIDEOPRT: No memory for power context.\n"));
finalStatus = statusBlock->Status = STATUS_INSUFFICIENT_RESOURCES;
break;
}
powerCtx->Irp = Irp;
powerCtx->FinalFlag = FALSE;
//
// Since there is a least one monitor that a power IRP
// will be requested for, mark this IRP as pending as
// it will undoubtedly be returned with STATUS_PENDING.
//
IoMarkIrpPending(Irp);
if (count == 0) {
powerCtx->FinalFlag = TRUE;
}
//
// Since PoRequestPowerIrp always returns STATUS_PENDING
// if the IRP was sent, a double completion here is
// impossible as at the bottom of this function
// IoCompleteRequest will not be called if status is
// STATUS_PENDING
//
finalStatus =
PoRequestPowerIrp(pChild->ChildDeviceObject,
mFnc,
*(PPOWER_STATE)(ioBuffer),
pVideoPortPowerCompletionIoctl,
powerCtx,
NULL);
if (finalStatus != STATUS_PENDING) {
break;
}
}
}
}
} else if ((ioControlCode == IOCTL_VIDEO_SET_POWER_MANAGEMENT) ||
(ioControlCode == IOCTL_VIDEO_GET_POWER_MANAGEMENT)) {
statusBlock->Status = STATUS_SUCCESS;
} else if (ioControlCode == IOCTL_VIDEO_ENUM_MONITOR_PDO) {
ULONG szMonitorDevices;
PVIDEO_MONITOR_DEVICE pMonitorDevices = NULL, pMD;
PCHILD_PDO_EXTENSION pChildDeviceExtension;
PDEVICE_OBJECT pdo;
pVideoDebugPrint((Trace, "VIDEOPRT: IOCTL_VIDEO_ENUM_MONITOR_PDO\n"));
szMonitorDevices = (fdoExtension->ChildPdoNumber+1)*sizeof(VIDEO_MONITOR_DEVICE);
pMonitorDevices = ExAllocatePoolWithTag(PagedPool | POOL_COLD_ALLOCATION,
szMonitorDevices,
VP_TAG);
if (pMonitorDevices == NULL) {
statusBlock->Status = STATUS_INSUFFICIENT_RESOURCES;
} else {
RtlZeroMemory(pMonitorDevices, szMonitorDevices);
//
// Walk our chain of children, and store them in the relations array.
//
pChildDeviceExtension = fdoExtension->ChildPdoList;
pMD = pMonitorDevices;
while (pChildDeviceExtension) {
if (pChildDeviceExtension->bIsEnumerated &&
pChildDeviceExtension->VideoChildDescriptor->Type == Monitor
)
{
ULONG UId, flag = VIDEO_CHILD_ACTIVE;
//
// Refcount the ChildDeviceObject.
//
ObReferenceObject(pChildDeviceExtension->ChildDeviceObject);
UId = pChildDeviceExtension->VideoChildDescriptor->UId;
if (!NT_SUCCESS
(pVideoMiniDeviceIoControl(DeviceObject,
IOCTL_VIDEO_GET_CHILD_STATE,
&UId,
sizeof(ULONG),
&flag,
sizeof(ULONG) ) )
)
{
//
// If driver driver doesn't handle IOCTL_VIDEO_GET_CHILD_STATE, set to default value
//
flag = pCheckActiveMonitor(pChildDeviceExtension) ? VIDEO_CHILD_ACTIVE : 0;
}
pMD->flag = flag;
pMD->pdo = pChildDeviceExtension->ChildDeviceObject;
pMD->HwID = pChildDeviceExtension->VideoChildDescriptor->UId;
pMD++;
}
pChildDeviceExtension = pChildDeviceExtension->NextChild;
}
//
// Return the information to GDI. The array terminated by a zero unit.
//
*((PVOID *)ioBuffer) = pMonitorDevices;
statusBlock->Status = STATUS_SUCCESS;
statusBlock->Information = sizeof(PVOID);
}
} else if (ioControlCode == IOCTL_VIDEO_INIT_WIN32K_CALLBACKS) {
pVideoDebugPrint((Trace, "VIDEOPRT: IOCTL_VIDEO_INIT_WIN32K_CALLBACKS\n"));
if (DoSpecificExtension->PhysDisp == NULL)
{
DoSpecificExtension->PhysDisp = ((PVIDEO_WIN32K_CALLBACKS)(ioBuffer))->PhysDisp;
}
if (Win32kCallout == NULL)
{
Win32kCallout = ((PVIDEO_WIN32K_CALLBACKS)(ioBuffer))->Callout;
}
((PVIDEO_WIN32K_CALLBACKS)ioBuffer)->bACPI = DoSpecificExtension->bACPI;
((PVIDEO_WIN32K_CALLBACKS)ioBuffer)->pPhysDeviceObject = fdoExtension->PhysicalDeviceObject;
((PVIDEO_WIN32K_CALLBACKS)ioBuffer)->DualviewFlags = DoSpecificExtension->DualviewFlags;
statusBlock->Status = STATUS_SUCCESS;
statusBlock->Information = sizeof(VIDEO_WIN32K_CALLBACKS);
} else if (ioControlCode == IOCTL_VIDEO_IS_VGA_DEVICE) {
pVideoDebugPrint((Trace, "VIDEOPRT: IOCTL_VIDEO_IS_VGA_DEVICE\n"));
*((PBOOLEAN)(ioBuffer)) = (BOOLEAN)(DeviceObject == DeviceOwningVga);
statusBlock->Status = STATUS_SUCCESS;
statusBlock->Information = sizeof(BOOLEAN);
} else if (ioControlCode == IOCTL_VIDEO_PREPARE_FOR_EARECOVERY) {
KBUGCHECK_SECONDARY_DUMP_DATA DumpData;
ULONG ulDumpSize = 0;
pVideoDebugPrint((Trace, "VIDEOPRT: IOCTL_VIDEO_PREPARE_FOR_EARECOVERY\n"));
//
// Save basic minidump on the disk (if we have any problem later
// during recovery we still will have something to work with)
//
if (VpDump) {
ulDumpSize = min((ULONG)((PMEMORY_DUMP)VpDump)->Header.RequiredDumpSpace.QuadPart,
TRIAGE_DUMP_SIZE);
pVpWriteFile(L"\\SystemRoot\\MEMORY.DMP",
VpDump,
ulDumpSize);
}
//
// As all the display devices to go into a mode where VGA works.
//
pVpGeneralBugcheckHandler(&DumpData);
if (VpDump) {
ULONG ulSize;
ULONG BugcheckDataSize = (VpBugcheckDeviceObject) ?
((PFDO_EXTENSION)VpBugcheckDeviceObject->DeviceExtension)->BugcheckDataSize :
0;
//
// Dump file created already so just add driver specific data
//
ulSize = pVpAppendSecondaryMinidumpData(VpBugcheckData,
BugcheckDataSize,
VpDump);
if (ulSize > ulDumpSize) {
//
// Write the data to disk
//
pVpWriteFile(L"\\SystemRoot\\MEMORY.DMP",
VpDump,
ulSize);
}
if (VpDump) {
ExFreePool(VpDump);
VpDump = NULL;
}
}
pVideoPortResetDisplay(80,25);
statusBlock->Status = STATUS_SUCCESS;
statusBlock->Information = 0;
#ifdef IOCTL_VIDEO_USE_DEVICE_IN_SESSION
} else if (ioControlCode == IOCTL_VIDEO_USE_DEVICE_IN_SESSION) {
pVideoDebugPrint((Trace, "VIDEOPRT: IOCTL_VIDEO_USE_DEVICE_IN_SESSION\n"));
if (((PVIDEO_DEVICE_SESSION_STATUS)ioBuffer)->bEnable)
{
if (DoSpecificExtension->SessionId == VIDEO_DEVICE_INVALID_SESSION)
{
DoSpecificExtension->SessionId = PsGetCurrentProcessSessionId();
((PVIDEO_DEVICE_SESSION_STATUS)ioBuffer)->bSuccess = TRUE;
}
else
{
((PVIDEO_DEVICE_SESSION_STATUS)ioBuffer)->bSuccess = FALSE;
}
}
else
{
if (DoSpecificExtension->SessionId == PsGetCurrentProcessSessionId())
{
DoSpecificExtension->SessionId = VIDEO_DEVICE_INVALID_SESSION;
((PVIDEO_DEVICE_SESSION_STATUS)ioBuffer)->bSuccess = TRUE;
}
else
{
((PVIDEO_DEVICE_SESSION_STATUS)ioBuffer)->bSuccess = FALSE;
}
}
statusBlock->Status = STATUS_SUCCESS;
statusBlock->Information = sizeof(VIDEO_DEVICE_SESSION_STATUS);
#endif IOCTL_VIDEO_USE_DEVICE_IN_SESSION
//
// The following three IOCTLs support LCD backlight control.
//
} else if (ioControlCode == IOCTL_VIDEO_QUERY_SUPPORTED_BRIGHTNESS) {
//
// Note: this IOCTL must be called before:
// IOCTL_VIDEO_SET_DISPLAY_BRIGHTNESS
//
// This IOCTL will query the brightness capabilities
// of the BIOS.
//
//
// We expect a buffer size of 256 bytes.
//
ULONG ulNumReturnedLevels = 0;
PDEVICE_OBJECT AttachedDevice = NULL;
if (outputBufferLength < 256)
{
statusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
break;
}
//
// Call VpQueryBacklightLevels to obtain the list of supported levels.
//
if (LCDPanelDevice) {
AttachedDevice = IoGetAttachedDeviceReference(LCDPanelDevice);
}
if (AttachedDevice) {
statusBlock->Status = VpQueryBacklightLevels(
AttachedDevice,
(PUCHAR) ioBuffer,
&ulNumReturnedLevels);
ObDereferenceObject(AttachedDevice);
}
else {
statusBlock->Status = ERROR_INVALID_PARAMETER;
}
if (!NT_SUCCESS(statusBlock->Status)) {
break;
}
//
// The new API is being used. If we haven't already read the applicable
// levels from the registry (per pVpInit) then write the keys to the
// registry and update pVpBacklightStatus as necessary.
//
if ((pVpBacklightStatus->bNewAPISupported == FALSE) ||
(pVpBacklightStatus->bACBrightnessInRegistry == FALSE) ||
(pVpBacklightStatus->bDCBrightnessInRegistry == FALSE)) {
// ZwCreateKey
RtlInitUnicodeString(&UnicodeString,
L"\\Registry\\Machine\\System\\CurrentControlSet\\"
L"Control\\Backlight");
InitializeObjectAttributes(&ObjectAttributes,
&UnicodeString,
OBJ_CASE_INSENSITIVE,
NULL,
NULL);
statusBlock->Status = ZwCreateKey(&hkRegistry,
GENERIC_READ | GENERIC_WRITE,
&ObjectAttributes,
0L,
NULL,
REG_OPTION_NON_VOLATILE,
NULL);
if (NT_SUCCESS(statusBlock->Status)) {
ULONG ulRegData = 1;
PVOID pvData;
// NewAPISupported
RtlInitUnicodeString(
&UnicodeString,
L"NewAPISupported"
);
pvData = &ulRegData;
statusBlock->Status = ZwSetValueKey(
hkRegistry,
&UnicodeString,
0,
REG_DWORD,
pvData,
4
);
if (NT_SUCCESS(statusBlock->Status)) {
pVpBacklightStatus->bNewAPISupported = TRUE;
}
// ACBacklightLevel, use BIOS default value
RtlInitUnicodeString(
&UnicodeString,
L"ACBacklightLevel"
);
pVpBacklightStatus->ucACBrightness = pVpBacklightStatus->ucBIOSDefaultAC;
ulRegData = (UCHAR) pVpBacklightStatus->ucACBrightness;
pvData = &ulRegData;
statusBlock->Status = ZwSetValueKey(
hkRegistry,
&UnicodeString,
0,
REG_DWORD,
pvData,
4
);
if (NT_SUCCESS(statusBlock->Status)) {
pVpBacklightStatus->bACBrightnessInRegistry = TRUE;
}
// DCBacklightLevel, use BIOS default value
RtlInitUnicodeString(
&UnicodeString,
L"DCBacklightLevel"
);
pVpBacklightStatus->ucDCBrightness = pVpBacklightStatus->ucBIOSDefaultDC;
ulRegData = (UCHAR) pVpBacklightStatus->ucDCBrightness;
pvData = &ulRegData;
statusBlock->Status = ZwSetValueKey(
hkRegistry,
&UnicodeString,
0,
REG_DWORD,
pvData,
4
);
if (NT_SUCCESS(statusBlock->Status)) {
pVpBacklightStatus->bDCBrightnessInRegistry = TRUE;
}
ZwClose(hkRegistry);
pVpBacklightStatus->bACBrightnessKnown = TRUE;
pVpBacklightStatus->bDCBrightnessKnown = TRUE;
}
}
pVpBacklightStatus->bQuerySupportedBrightnessCalled = TRUE;
statusBlock->Status = STATUS_SUCCESS;
statusBlock->Information = ulNumReturnedLevels;
} else if (ioControlCode == IOCTL_VIDEO_QUERY_DISPLAY_BRIGHTNESS) {
//
// If the backlight level is known for the display policy queried,
// it will be reported.
//
// No ACPI methods are used here. _BCL will be used in
// IOCTL_VIDEO_QUERY_SUPPORTED_BRIGHTNESS and _BCM will
// be used in IOCTL_VIDEO_SET_DISPLAY_BRIGHTNESS.
//
PDISPLAY_BRIGHTNESS pDisplayBrightness;
if (outputBufferLength < sizeof(DISPLAY_BRIGHTNESS))
{
statusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
break;
}
pDisplayBrightness = (PDISPLAY_BRIGHTNESS) ioBuffer;
//
// Report AC value if available.
//
// Note: Value ~should~ be known, even if we need to use
// AC default.
//
if ((pVpBacklightStatus->bACBrightnessKnown == FALSE) &&
(pVpBacklightStatus->bBIOSDefaultACKnown == FALSE))
{
statusBlock->Status = ERROR_INVALID_PARAMETER;
break;
}
if (pVpBacklightStatus->bACBrightnessKnown == TRUE)
{
pDisplayBrightness->ucACBrightness = pVpBacklightStatus->ucACBrightness;
}
else
{
pDisplayBrightness->ucACBrightness = pVpBacklightStatus->ucBIOSDefaultAC;
}
//
// Report DC value if available.
//
// Note: Value ~should~ be known, even if we need to use
// DC default.
//
if ((pVpBacklightStatus->bDCBrightnessKnown == FALSE) &&
(pVpBacklightStatus->bBIOSDefaultDCKnown == FALSE))
{
statusBlock->Status = ERROR_INVALID_PARAMETER;
break;
}
if (pVpBacklightStatus->bDCBrightnessKnown == TRUE)
{
pDisplayBrightness->ucDCBrightness = pVpBacklightStatus->ucDCBrightness;
}
else
{
pDisplayBrightness->ucDCBrightness = pVpBacklightStatus->ucBIOSDefaultDC;
}
//
// Report the current power policy.
//
if (VpRunningOnAC == TRUE)
{
pDisplayBrightness->ucDisplayPolicy = DISPLAYPOLICY_AC;
}
else
{
pDisplayBrightness->ucDisplayPolicy = DISPLAYPOLICY_DC;
}
//
// No errors are expected here.
//
statusBlock->Status = STATUS_SUCCESS;
statusBlock->Information = sizeof(DISPLAY_BRIGHTNESS);
} else if (ioControlCode == IOCTL_VIDEO_SET_DISPLAY_BRIGHTNESS) {
//
// This IOCTL will set the current brightness level of
// the backlight.
//
// The _BCM ACPI method will be used.
//
PDISPLAY_BRIGHTNESS pDisplayBrightness;
PDEVICE_OBJECT AttachedDevice = NULL;
BOOLEAN bSetPanelBrightness = FALSE;
//
// Check buffer size and that Brightness capabilities
// have been queried.
//
if (inputBufferLength < sizeof(DISPLAY_BRIGHTNESS))
{
statusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
break;
}
//
// Videoprt insists that IOCTL_VIDEO_QUERY_SUPPORTED_BRIGHTNESS
// be called first.
//
if (pVpBacklightStatus->bQuerySupportedBrightnessCalled == FALSE)
{
statusBlock->Status = ERROR_INVALID_FUNCTION;
break;
}
//
// Videoprt will ensure no crashes, but caller should ensure
// they are setting a valid value.
//
pDisplayBrightness = (PDISPLAY_BRIGHTNESS) ioBuffer;
//
// Set the AC/DC brightness level, if appropriate.
// The caller could conceivably ask us to set a value
// for a power policy that is not currenlty active.
//
ulACPIMethodParam2 = 0;
if ((VpRunningOnAC == TRUE) &&
((pDisplayBrightness->ucDisplayPolicy) & DISPLAYPOLICY_AC))
{
bSetPanelBrightness = TRUE;
ulACPIMethodParam1 = (ULONG) pDisplayBrightness->ucACBrightness;
}
else if ((VpRunningOnAC == FALSE) &&
((pDisplayBrightness->ucDisplayPolicy) & DISPLAYPOLICY_DC))
{
bSetPanelBrightness = TRUE;
ulACPIMethodParam1 = (ULONG) pDisplayBrightness->ucDCBrightness;
}
statusBlock->Status = STATUS_SUCCESS;
if (bSetPanelBrightness == TRUE)
{
if (LCDPanelDevice) {
AttachedDevice = IoGetAttachedDeviceReference(LCDPanelDevice);
}
if (AttachedDevice) {
statusBlock->Status = pVideoPortACPIIoctl(
AttachedDevice,
(ULONG) ('MCB_'),
&ulACPIMethodParam1,
NULL,
0,
NULL);
ObDereferenceObject(AttachedDevice);
}
else {
statusBlock->Status = ERROR_INVALID_PARAMETER;
}
}
if (!NT_SUCCESS(statusBlock->Status))
{
statusBlock->Status = ERROR_INVALID_PARAMETER;
break;
}
//
// Save the new brightness levels.
//
if ((pDisplayBrightness->ucDisplayPolicy) & DISPLAYPOLICY_DC)
{
pVpBacklightStatus->ucDCBrightness = pDisplayBrightness->ucDCBrightness;
pVpBacklightStatus->bDCBrightnessKnown = TRUE;
}
if ((pDisplayBrightness->ucDisplayPolicy) & DISPLAYPOLICY_AC)
{
pVpBacklightStatus->ucACBrightness = pDisplayBrightness->ucACBrightness;
pVpBacklightStatus->bACBrightnessKnown = TRUE;
}
//
// Save the new AC / DC values in the Registry.
//
// ZwCreateKey
RtlInitUnicodeString(&UnicodeString,
L"\\Registry\\Machine\\System\\CurrentControlSet\\"
L"Control\\Backlight");
InitializeObjectAttributes(&ObjectAttributes,
&UnicodeString,
OBJ_CASE_INSENSITIVE,
NULL,
NULL);
statusBlock->Status = ZwCreateKey(&hkRegistry,
GENERIC_READ | GENERIC_WRITE,
&ObjectAttributes,
0L,
NULL,
REG_OPTION_NON_VOLATILE,
NULL);
if (NT_SUCCESS(statusBlock->Status)) {
ULONG ulRegData = 0;
PVOID pvData;
// ACBacklightLevel
RtlInitUnicodeString(
&UnicodeString,
L"ACBacklightLevel"
);
ulRegData = (UCHAR) pVpBacklightStatus->ucACBrightness;
pvData = &ulRegData;
statusBlock->Status = ZwSetValueKey(
hkRegistry,
&UnicodeString,
0,
REG_DWORD,
pvData,
4
);
if (NT_SUCCESS(statusBlock->Status)) {
pVpBacklightStatus->bACBrightnessInRegistry = TRUE;
}
// DCBacklightLevel
RtlInitUnicodeString(
&UnicodeString,
L"DCBacklightLevel"
);
ulRegData = (UCHAR) pVpBacklightStatus->ucDCBrightness;
pvData = &ulRegData;
statusBlock->Status = ZwSetValueKey(
hkRegistry,
&UnicodeString,
0,
REG_DWORD,
pvData,
4
);
if (NT_SUCCESS(statusBlock->Status)) {
pVpBacklightStatus->bDCBrightnessInRegistry = TRUE;
}
ZwClose(hkRegistry);
}
//
// No errors are expected here unless the caller asked us to set a
// level that is not available.
//
statusBlock->Status = STATUS_SUCCESS;
statusBlock->Information = 0;
} else {
//
// All other request need to be passed to the miniport driver.
//
statusBlock->Status = STATUS_SUCCESS;
switch (ioControlCode) {
case IOCTL_VIDEO_ENABLE_VDM:
pVideoDebugPrint((Trace, "VIDEOPRT: IOCTL_VIDEO_ENABLE_VDM\n"));
ASSERT(IS_PDO(pdoExtension) == FALSE);
statusBlock->Status = pVideoPortEnableVDM(fdoExtension,
TRUE,
(PVIDEO_VDM) ioBuffer,
inputBufferLength);
#if DBG
if (statusBlock->Status == STATUS_CONFLICTING_ADDRESSES) {
pVideoDebugPrint((Trace, "VIDEOPRT: pVideoPortEnableVDM failed\n"));
}
#endif
break;
#if _X86_
case IOCTL_VIDEO_SAVE_HARDWARE_STATE:
pVideoDebugPrint((Trace, "VIDEOPRT: IOCTL_VIDEO_SAVE_HARDWARE_STATE\n"));
//
// allocate the memory required by the miniport driver so it can
// save its state to be returned to the caller.
//
ASSERT(IS_PDO(pdoExtension) == FALSE);
if (fdoExtension->HardwareStateSize == 0) {
statusBlock->Status = STATUS_NOT_IMPLEMENTED;
break;
}
//
// Must make sure the caller is a trusted subsystem with the
// appropriate privilege level before executing this call.
// If the calls returns FALSE we must return an error code.
//
if (!SeSinglePrivilegeCheck(RtlConvertLongToLuid(
SE_TCB_PRIVILEGE),
fdoExtension->CurrentIrpRequestorMode)) {
statusBlock->Status = STATUS_PRIVILEGE_NOT_HELD;
break;
}
((PVIDEO_HARDWARE_STATE)(ioBuffer))->StateLength =
fdoExtension->HardwareStateSize;
statusBlock->Status =
ZwAllocateVirtualMemory(NtCurrentProcess(),
(PVOID *) &(((PVIDEO_HARDWARE_STATE)(ioBuffer))->StateHeader),
0L,
&((PVIDEO_HARDWARE_STATE)(ioBuffer))->StateLength,
MEM_COMMIT,
PAGE_READWRITE);
if(!NT_SUCCESS(statusBlock->Status))
break;
BiosDataBuffer = ExAllocatePoolWithTag(PagedPool,
BIOS_DATA_SIZE,
VP_TAG);
if (BiosDataBuffer == NULL) {
statusBlock->Status = STATUS_INSUFFICIENT_RESOURCES;
} else {
statusBlock->Status =
pVideoPortGetVDMBiosData(fdoExtension,
BiosDataBuffer,
BIOS_DATA_SIZE);
if(!NT_SUCCESS(statusBlock->Status)) {
ExFreePool(BiosDataBuffer);
}
}
break;
#endif
case IOCTL_VIDEO_QUERY_PUBLIC_ACCESS_RANGES:
pVideoDebugPrint((Trace, "VIDEOPRT: IOCTL_VIDEO_QUERY_PUBLIC_ACCESS_RANGES\n"));
//
// Must make sure the caller is a trusted subsystem with the
// appropriate privilege level before executing this call.
// If the calls returns FALSE we must return an error code.
//
if (!SeSinglePrivilegeCheck(RtlConvertLongToLuid(
SE_TCB_PRIVILEGE),
fdoExtension->CurrentIrpRequestorMode)) {
statusBlock->Status = STATUS_PRIVILEGE_NOT_HELD;
}
break;
case IOCTL_VIDEO_GET_CHILD_STATE:
pVideoDebugPrint((Trace, "VIDEOPRT: IOCTL_VIDEO_GET_CHILD_STATE\n"));
//
// If it's PDO, set the ID of the child device before letting it go
// to the miniports StartIo routine.
//
if (IS_PDO(pdoExtension)) {
if (outputBufferLength < sizeof (ULONG)) {
statusBlock->Status = STATUS_BUFFER_TOO_SMALL ;
break ;
}
*((PULONG)(ioBuffer)) = pdoExtension->ChildUId ;
}
break;
//
// The default case is when the port driver does not handle the
// request. We must then call the miniport driver.
//
default:
break;
} // switch (ioControlCode)
//
// All above cases call the miniport driver.
//
// only process it if no errors happened in the port driver
// processing.
//
if (NT_SUCCESS(statusBlock->Status)) {
pVideoDebugPrint((Trace, "VIDEOPRT: IOCTL fallthrough\n"));
vrp.IoControlCode = ioControlCode;
vrp.StatusBlock = statusBlock;
vrp.InputBuffer = ioBuffer;
vrp.InputBufferLength = inputBufferLength;
vrp.OutputBuffer = ioBuffer;
vrp.OutputBufferLength = outputBufferLength;
//
// Send the request to the miniport.
//
fdoExtension->HwStartIO(HwDeviceExtension, &vrp);
#if _X86_
if(ioControlCode == IOCTL_VIDEO_SAVE_HARDWARE_STATE) {
pVideoPortPutVDMBiosData(fdoExtension,
BiosDataBuffer,
BIOS_DATA_SIZE);
ExFreePool(BiosDataBuffer);
}
#endif
if (statusBlock->Status != NO_ERROR) {
//
// Make sure we don't tell the IO system to copy data
// on a real error.
//
if (statusBlock->Status != ERROR_MORE_DATA) {
statusBlock->Information = 0;
}
pVideoPortMapToNtStatus(statusBlock);
//
// !!! Compatibility:
// Do not require a miniport to support the REGISTER_VDM
// IOCTL, so if we get an error in that case, just
// return success.
//
// Do put up a message so people fix this.
//
if (ioControlCode == IOCTL_VIDEO_ENABLE_VDM) {
statusBlock->Status = STATUS_SUCCESS;
pVideoDebugPrint((Warn, "VIDEOPRT: The miniport driver does not support IOCTL_VIDEO_ENABLE_VDM. The video miniport driver *should* be fixed.\n"));
}
}
}
} // if (ioControlCode == ...
break;
case IRP_MJ_SHUTDOWN:
{
PEPROCESS csr;
//
// This little dance is just to make sure we never overdereference csr.
//
csr = InterlockedExchangePointer(&CsrProcess, NULL);
if (csr != NULL) {
ObDereferenceObject(csr);
}
//
// TODO: This is a temporary hack only till we get Nt/ZwQueryLastShutdownType()
// API implemented. On the next boot we need to know if the last shutdown was
// successful, and if not and if we have a watchdog event registered from that
// session we can assume the driver got stuck so we can notify user and
// optionally send a problem report to MS.
//
// N.B. This doesn't work for non-PnP devices (e.g. VGA) but it's still good
// enough, we're losing once piece of info but we'll still check for watchdog
// events from the last session.
//
{
#define VP_KEY_WATCHDOG L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Watchdog"
#define VP_KEY_WATCHDOG_DISPLAY L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Watchdog\\Display"
static BOOLEAN shutdownRegistered = FALSE;
if (FALSE == shutdownRegistered)
{
NTSTATUS ntStatus;
shutdownRegistered = TRUE;
//
// Is Watchdog\Display key already there?
//
ntStatus = RtlCheckRegistryKey(RTL_REGISTRY_ABSOLUTE, VP_KEY_WATCHDOG_DISPLAY);
if (!NT_SUCCESS(ntStatus)) {
//
// Is Watchdog key already there?
//
ntStatus = RtlCheckRegistryKey(RTL_REGISTRY_ABSOLUTE, VP_KEY_WATCHDOG);
if (!NT_SUCCESS(ntStatus)) {
//
// Create a new key.
//
ntStatus = RtlCreateRegistryKey(RTL_REGISTRY_ABSOLUTE, VP_KEY_WATCHDOG);
}
if (NT_SUCCESS(ntStatus)) {
//
// Create a new key.
//
ntStatus = RtlCreateRegistryKey(RTL_REGISTRY_ABSOLUTE, VP_KEY_WATCHDOG_DISPLAY);
}
}
if (NT_SUCCESS(ntStatus)) {
ULONG shutdownFlag = 1;
ULONG shutdownCount;
ULONG defaultShutdownCount = 0;
RTL_QUERY_REGISTRY_TABLE queryTable[] =
{
{NULL, RTL_QUERY_REGISTRY_DIRECT, L"ShutdownCount", &shutdownCount, REG_DWORD, &defaultShutdownCount, 4},
{NULL, 0, NULL}
};
//
// Get accumulated statistics from registry.
//
RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
VP_KEY_WATCHDOG_DISPLAY,
queryTable,
NULL,
NULL);
shutdownCount++;
//
// Update registry values.
//
RtlWriteRegistryValue(RTL_REGISTRY_ABSOLUTE,
VP_KEY_WATCHDOG_DISPLAY,
L"ShutdownCount",
REG_DWORD,
&shutdownCount,
sizeof (ULONG));
RtlWriteRegistryValue(RTL_REGISTRY_ABSOLUTE,
VP_KEY_WATCHDOG_DISPLAY,
L"Shutdown",
REG_DWORD,
&shutdownFlag,
sizeof (ULONG));
}
}
}
break;
}
//
// Other major entry points in the dispatch routine are not supported.
//
default:
statusBlock->Status = STATUS_SUCCESS;
break;
} // switch (irpStack->MajorFunction)
//
// save the final status so we can return it after the IRP is completed.
//
if (finalStatus == -1) {
finalStatus = statusBlock->Status;
}
RELEASE_DEVICE_LOCK(combinedExtension);
#if REMOVE_LOCK_ENABLED
IoReleaseRemoveLock(&combinedExtension->RemoveLock, Irp);
#endif
if (finalStatus == STATUS_PENDING) {
pVideoDebugPrint((Trace, "VIDEOPRT: Returned pending in pVideoPortDispatch.\n")) ;
return STATUS_PENDING ;
}
pVideoDebugPrint((Trace, "VIDEOPRT: IoCompleteRequest with Irp %x\n", Irp));
IoCompleteRequest(Irp,
IO_VIDEO_INCREMENT);
//
// We never have pending operation so always return the status code.
//
pVideoDebugPrint((Trace, "VIDEOPRT: final IOCTL status: %08lx\n",
finalStatus));
return finalStatus;
} // pVideoPortDispatch()
VOID
VideoPortFreeDeviceBase(
IN PVOID HwDeviceExtension,
IN PVOID MappedAddress
)
/*++
Routine Description:
VideoPortFreeDeviceBase frees a block of I/O addresses or memory space
previously mapped into the system address space by calling
VideoPortGetDeviceBase.
Arguments:
HwDeviceExtension - Points to the miniport driver's device extension.
MappedAddress - Specifies the base address of the block to be freed. This
value must be the same as the value returned by VideoPortGetDeviceBase.
Return Value:
None.
Environment:
This routine cannot be called from a miniport routine synchronized with
VideoPortSynchronizeRoutine or from an ISR.
--*/
{
pVideoPortFreeDeviceBase(HwDeviceExtension, MappedAddress);
return;
}
PVOID
pVideoPortFreeDeviceBase(
IN PVOID HwDeviceExtension,
IN PVOID MappedAddress
)
{
PMAPPED_ADDRESS nextMappedAddress;
PMAPPED_ADDRESS lastMappedAddress;
PFDO_EXTENSION fdoExtension = GET_FDO_EXT(HwDeviceExtension);
pVideoDebugPrint((Info, "VPFreeDeviceBase at mapped address is %08lx\n",
MappedAddress));
lastMappedAddress = NULL;
nextMappedAddress = fdoExtension->MappedAddressList;
while (nextMappedAddress) {
if (nextMappedAddress->MappedAddress == MappedAddress) {
//
// Count up how much memory a miniport driver is really taking
//
if (nextMappedAddress->bNeedsUnmapping) {
fdoExtension->MemoryPTEUsage -=
ADDRESS_AND_SIZE_TO_SPAN_PAGES(nextMappedAddress->MappedAddress,
nextMappedAddress->NumberOfUchars);
}
if (!(--nextMappedAddress->RefCount)) {
//
// Unmap address, if necessary.
//
if (nextMappedAddress->bNeedsUnmapping) {
if (nextMappedAddress->bLargePageRequest) {
MmUnmapVideoDisplay(nextMappedAddress->MappedAddress,
nextMappedAddress->NumberOfUchars);
} else {
MmUnmapIoSpace(nextMappedAddress->MappedAddress,
nextMappedAddress->NumberOfUchars);
}
}
//
// Remove mapped address from list.
//
if (lastMappedAddress == NULL) {
fdoExtension->MappedAddressList =
nextMappedAddress->NextMappedAddress;
} else {
lastMappedAddress->NextMappedAddress =
nextMappedAddress->NextMappedAddress;
}
ExFreePool(nextMappedAddress);
}
//
// We just return the value to show that the call succeeded.
//
return (nextMappedAddress);
} else {
lastMappedAddress = nextMappedAddress;
nextMappedAddress = nextMappedAddress->NextMappedAddress;
}
}
return NULL;
} // end VideoPortFreeDeviceBase()
PVOID
VideoPortGetDeviceBase(
IN PVOID HwDeviceExtension,
IN PHYSICAL_ADDRESS IoAddress,
IN ULONG NumberOfUchars,
IN UCHAR InIoSpace
)
/*++
Routine Description:
VideoPortGetDeviceBase maps a memory or I/O address range into the
system (kernel) address space. Access to this mapped address space
must follow these rules:
If the input value for InIoSpace is 1 (the address IS in I/O space),
the returned logical address should be used in conjunction with
VideoPort[Read/Write]Port[Uchar/Ushort/Ulong] functions.
^^^^
If the input value for InIoSpace is 0 (the address IS NOT in I/O
space), the returned logical address should be used in conjunction
with VideoPort[Read/Write]Register[Uchar/Ushort/Ulong] functions.
^^^^^^^^
Note that VideoPortFreeDeviceBase is used to unmap a previously mapped
range from the system address space.
Arguments:
HwDeviceExtension - Points to the miniport driver's device extension.
IoAddress - Specifies the base physical address of the range to be
mapped in the system address space.
NumberOfUchars - Specifies the number of bytes, starting at the base
address, to map in system space. The driver must not access
addresses outside this range.
InIoSpace - Specifies that the address is in the I/O space if 1.
Otherwise, the address is assumed to be in memory space.
Return Value:
This function returns a base address suitable for use by the hardware
access functions. VideoPortGetDeviceBase may be called several times
by the miniport driver.
Environment:
This routine cannot be called from a miniport routine synchronized with
VideoPortSynchronizeRoutine or from an ISR.
--*/
{
//
// We specify large page as FALSE for the default since the miniport could
// be using the address at raise IRQL in an ISR.
//
return pVideoPortGetDeviceBase(HwDeviceExtension,
IoAddress,
NumberOfUchars,
InIoSpace,
FALSE);
}
BOOLEAN
VpTranslateBusAddress(
IN PFDO_EXTENSION fdoExtension,
IN PPHYSICAL_ADDRESS IoAddress,
IN OUT PULONG addressSpace,
IN OUT PPHYSICAL_ADDRESS TranslatedAddress
)
/*++
Routine Description:
This routine finds the cpu relative address that matches the given
bus relative address.
Arguments:
fdoExtension - The device extension for the device in question.
IoAddress - The address which we mean to translate.
addressSpace - pointer to resource type (IO, memory, etc).
TranslatedAddress - a pointer to the location in which to store the
translated address.
Returns:
TRUE if successful,
FALSE otherwise.
--*/
{
BOOLEAN bStatus;
//
// We need to find a way to translate dense space before we can
// do this.
//
#if 0
if ((fdoExtension->Flags & LEGACY_DRIVER) != LEGACY_DRIVER) {
bStatus = VpTranslateResource(
fdoExtension,
addressSpace,
IoAddress,
TranslatedAddress);
} else {
#endif
bStatus = HalTranslateBusAddress(
fdoExtension->AdapterInterfaceType,
fdoExtension->SystemIoBusNumber,
*IoAddress,
addressSpace,
TranslatedAddress);
#if 0
}
#endif
return bStatus;
}
PVOID
pVideoPortGetDeviceBase(
IN PVOID HwDeviceExtension,
IN PHYSICAL_ADDRESS IoAddress,
IN ULONG NumberOfUchars,
IN UCHAR InIoSpace,
IN BOOLEAN bLargePage
)
{
PFDO_EXTENSION fdoExtension = GET_FDO_EXT(HwDeviceExtension);
PHYSICAL_ADDRESS cardAddress = IoAddress;
PVOID mappedAddress = NULL;
PMAPPED_ADDRESS newMappedAddress;
BOOLEAN bMapped;
ULONG addressSpace;
ULONG p6Caching = FALSE;
pVideoDebugPrint((Info, "VPGetDeviceBase reqested %08lx mem type. address is %08lx %08lx, length of %08lx\n",
InIoSpace, IoAddress.HighPart, IoAddress.LowPart, NumberOfUchars));
//
// Properly configure the flags for translation
//
addressSpace = InIoSpace & 0xFF;
p6Caching = addressSpace & VIDEO_MEMORY_SPACE_P6CACHE;
addressSpace &= ~VIDEO_MEMORY_SPACE_P6CACHE;
addressSpace &= ~VIDEO_MEMORY_SPACE_DENSE;
if (addressSpace & VIDEO_MEMORY_SPACE_USER_MODE) {
ASSERT(FALSE);
return NULL;
}
if ((((cardAddress.QuadPart >= 0x000C0000) && (cardAddress.QuadPart < 0x000C8000)) &&
(InIoSpace == 0) &&
(VpC0000Compatible == 2)) ||
VpTranslateBusAddress(fdoExtension,
&IoAddress,
&addressSpace,
&cardAddress)) {
//
// Use reference counting for addresses to support broken ATI !
// Return the previously mapped address if we find the same physical
// address.
//
PMAPPED_ADDRESS nextMappedAddress;
pVideoDebugPrint((Info, "VPGetDeviceBase requested %08lx mem type. physical address is %08lx %08lx, length of %08lx\n",
addressSpace, cardAddress.HighPart, cardAddress.LowPart, NumberOfUchars));
nextMappedAddress = fdoExtension->MappedAddressList;
while (nextMappedAddress) {
if ((nextMappedAddress->InIoSpace == InIoSpace) &&
(nextMappedAddress->NumberOfUchars == NumberOfUchars) &&
(nextMappedAddress->PhysicalAddress.QuadPart == cardAddress.QuadPart)) {
pVideoDebugPrint((Info, "VPGetDeviceBase : refCount hit on address %08lx \n",
nextMappedAddress->PhysicalAddress.LowPart));
nextMappedAddress->RefCount++;
//
// Count up how much memory a miniport driver is really taking
//
if (nextMappedAddress->bNeedsUnmapping) {
fdoExtension->MemoryPTEUsage +=
ADDRESS_AND_SIZE_TO_SPAN_PAGES(nextMappedAddress->MappedAddress,
nextMappedAddress->NumberOfUchars);
}
return (nextMappedAddress->MappedAddress);
} else {
nextMappedAddress = nextMappedAddress->NextMappedAddress;
}
}
//
// Allocate memory to store mapped address for unmap.
//
newMappedAddress = ExAllocatePoolWithTag(NonPagedPool,
sizeof(MAPPED_ADDRESS),
'trpV');
if (!newMappedAddress) {
pVideoDebugPrint((Error, "VIDEOPRT: Not enough memory to cache mapped address! \n"));
return NULL;
}
//
// If the address is in IO space, don't do anything.
// If the address is in memory space, map it and save the information.
//
if (addressSpace & VIDEO_MEMORY_SPACE_IO) {
mappedAddress = (PVOID) cardAddress.QuadPart;
bMapped = FALSE;
} else {
//
// Map the device base address into the virtual address space
//
// NOTE: This routine is order dependant, and changing flags like
// bLargePage will affect the caching of address we do earlier
// on in this routine.
//
if (p6Caching && EnableUSWC) {
mappedAddress = MmMapIoSpace(cardAddress,
NumberOfUchars,
MmFrameBufferCached);
if (mappedAddress == NULL) {
mappedAddress = MmMapIoSpace(cardAddress,
NumberOfUchars,
FALSE);
}
} else if (bLargePage) {
mappedAddress = MmMapVideoDisplay(cardAddress,
NumberOfUchars,
0);
} else {
mappedAddress = MmMapIoSpace(cardAddress,
NumberOfUchars,
FALSE);
}
if (mappedAddress == NULL) {
ExFreePool(newMappedAddress);
pVideoDebugPrint((Error, "VIDEOPRT: MmMapIoSpace FAILED\n"));
return NULL;
}
bMapped = TRUE;
fdoExtension->MemoryPTEUsage +=
ADDRESS_AND_SIZE_TO_SPAN_PAGES(mappedAddress,
NumberOfUchars);
}
//
// Save the reference
//
newMappedAddress->PhysicalAddress = cardAddress;
newMappedAddress->RefCount = 1;
newMappedAddress->MappedAddress = mappedAddress;
newMappedAddress->NumberOfUchars = NumberOfUchars;
newMappedAddress->InIoSpace = InIoSpace;
newMappedAddress->bNeedsUnmapping = bMapped;
newMappedAddress->bLargePageRequest = bLargePage;
//
// Link current list to new entry.
//
newMappedAddress->NextMappedAddress = fdoExtension->MappedAddressList;
//
// Point anchor at new list.
//
fdoExtension->MappedAddressList = newMappedAddress;
} else {
pVideoDebugPrint((Error, "VIDEOPRT: VpTranslateBusAddress failed\n"));
}
pVideoDebugPrint((Info, "VIDEOPRT: VideoPortGetDeviceBase mapped virtual address is %08lx\n",
mappedAddress));
return mappedAddress;
} // end VideoPortGetDeviceBase()
NTSTATUS
pVideoPortGetDeviceDataRegistry(
IN PVOID Context,
IN PUNICODE_STRING PathName,
IN INTERFACE_TYPE BusType,
IN ULONG BusNumber,
IN PKEY_VALUE_FULL_INFORMATION *BusInformation,
IN CONFIGURATION_TYPE ControllerType,
IN ULONG ControllerNumber,
IN PKEY_VALUE_FULL_INFORMATION *ControllerInformation,
IN CONFIGURATION_TYPE PeripheralType,
IN ULONG PeripheralNumber,
IN PKEY_VALUE_FULL_INFORMATION *PeripheralInformation
)
/*++
Routine Description:
Arguments:
Return Value:
Environment:
This routine cannot be called from a miniport routine synchronized with
VideoPortSynchronizeRoutine or from an ISR.
--*/
{
//
// This macro should be in the io system header file.
//
#define GetIoQueryDeviceInfo(DeviceInfo, InfoType) \
((PVOID) ( ((PUCHAR) (*(DeviceInfo + InfoType))) + \
((ULONG_PTR) (*(DeviceInfo + InfoType))->DataOffset) ))
#define GetIoQueryDeviceInfoLength(DeviceInfo, InfoType) \
((*(DeviceInfo + InfoType))->DataLength)
PVP_QUERY_DEVICE queryDevice = Context;
PKEY_VALUE_FULL_INFORMATION *deviceInformation;
PCM_FULL_RESOURCE_DESCRIPTOR configurationData;
switch (queryDevice->DeviceDataType) {
case VpBusData:
pVideoDebugPrint((Trace, "VIDEOPRT: VPGetDeviceDataCallback: BusData\n"));
configurationData = (PCM_FULL_RESOURCE_DESCRIPTOR)
GetIoQueryDeviceInfo(BusInformation,
IoQueryDeviceConfigurationData);
if (NO_ERROR == ((PMINIPORT_QUERY_DEVICE_ROUTINE)
queryDevice->CallbackRoutine)(
queryDevice->MiniportHwDeviceExtension,
queryDevice->MiniportContext,
queryDevice->DeviceDataType,
GetIoQueryDeviceInfo(BusInformation,
IoQueryDeviceIdentifier),
GetIoQueryDeviceInfoLength(BusInformation,
IoQueryDeviceIdentifier),
(PVOID) &(configurationData->PartialResourceList.PartialDescriptors[1]),
configurationData->PartialResourceList.PartialDescriptors[0].u.DeviceSpecificData.DataSize,
GetIoQueryDeviceInfo(BusInformation,
IoQueryDeviceComponentInformation),
GetIoQueryDeviceInfoLength(BusInformation,
IoQueryDeviceComponentInformation)
)) {
return STATUS_SUCCESS;
} else {
return STATUS_DEVICE_DOES_NOT_EXIST;
}
break;
case VpControllerData:
deviceInformation = ControllerInformation;
pVideoDebugPrint((Trace, "VIDEOPRT: VPGetDeviceDataCallback: ControllerData\n"));
//
// This data we are getting is actually a CM_FULL_RESOURCE_DESCRIPTOR.
//
if (NO_ERROR == ((PMINIPORT_QUERY_DEVICE_ROUTINE)
queryDevice->CallbackRoutine)(
queryDevice->MiniportHwDeviceExtension,
queryDevice->MiniportContext,
queryDevice->DeviceDataType,
GetIoQueryDeviceInfo(deviceInformation,
IoQueryDeviceIdentifier),
GetIoQueryDeviceInfoLength(deviceInformation,
IoQueryDeviceIdentifier),
GetIoQueryDeviceInfo(deviceInformation,
IoQueryDeviceConfigurationData),
GetIoQueryDeviceInfoLength(deviceInformation,
IoQueryDeviceConfigurationData),
GetIoQueryDeviceInfo(deviceInformation,
IoQueryDeviceComponentInformation),
GetIoQueryDeviceInfoLength(deviceInformation,
IoQueryDeviceComponentInformation)
)) {
return STATUS_SUCCESS;
} else {
return STATUS_DEVICE_DOES_NOT_EXIST;
}
break;
case VpMonitorData:
deviceInformation = PeripheralInformation;
pVideoDebugPrint((Trace, "VIDEOPRT: VPGetDeviceDataCallback: MonitorData\n"));
//
// This data we are getting is actually a CM_FULL_RESOURCE_DESCRIPTOR.
//
if (NO_ERROR == ((PMINIPORT_QUERY_DEVICE_ROUTINE)
queryDevice->CallbackRoutine)(
queryDevice->MiniportHwDeviceExtension,
queryDevice->MiniportContext,
queryDevice->DeviceDataType,
GetIoQueryDeviceInfo(deviceInformation,
IoQueryDeviceIdentifier),
GetIoQueryDeviceInfoLength(deviceInformation,
IoQueryDeviceIdentifier),
GetIoQueryDeviceInfo(deviceInformation,
IoQueryDeviceConfigurationData),
GetIoQueryDeviceInfoLength(deviceInformation,
IoQueryDeviceConfigurationData),
GetIoQueryDeviceInfo(deviceInformation,
IoQueryDeviceComponentInformation),
GetIoQueryDeviceInfoLength(deviceInformation,
IoQueryDeviceComponentInformation)
)) {
return STATUS_SUCCESS;
} else {
return STATUS_DEVICE_DOES_NOT_EXIST;
}
break;
default:
ASSERT(FALSE);
return STATUS_UNSUCCESSFUL;
}
} // end pVideoPortGetDeviceDataRegistry()
VP_STATUS
VideoPortGetDeviceData(
PVOID HwDeviceExtension,
VIDEO_DEVICE_DATA_TYPE DeviceDataType,
PMINIPORT_QUERY_DEVICE_ROUTINE CallbackRoutine,
PVOID Context
)
/*++
Routine Description:
VideoPortGetDeviceData retrieves information from the hardware hive in
the registry. The information retrieved from the registry is
bus-specific or hardware-specific.
Arguments:
HwDeviceExtension - Points to the miniport driver's device extension.
DeviceDataType - Specifies the type of data being requested (as indicated
in VIDEO_DEVICE_DATA_TYPE).
CallbackRoutine - Points to a function that should be called back with
the requested information.
Context - Specifies a context parameter passed to the callback function.
Return Value:
This function returns the final status of the operation.
Environment:
This routine cannot be called from a miniport routine synchronized with
VideoPortSynchronizeRoutine or from an ISR.
--*/
{
#define CMOS_MAX_DATA_SIZE 66000
NTSTATUS ntStatus;
VP_STATUS vpStatus;
PFDO_EXTENSION fdoExtension = GET_FDO_EXT(HwDeviceExtension);
VP_QUERY_DEVICE queryDevice;
PUCHAR cmosData = NULL;
ULONG cmosDataSize;
ULONG exCmosDataSize;
UNICODE_STRING Identifier;
PULONG pConfiguration = NULL;
PULONG pComponent = NULL;
queryDevice.MiniportHwDeviceExtension = HwDeviceExtension;
queryDevice.DeviceDataType = DeviceDataType;
queryDevice.CallbackRoutine = CallbackRoutine;
queryDevice.MiniportStatus = NO_ERROR;
queryDevice.MiniportContext = Context;
switch (DeviceDataType) {
case VpMachineData:
pVideoDebugPrint((Trace, "VIDEOPRT: VPGetDeviceData: MachineData\n"));
ntStatus = STATUS_UNSUCCESSFUL;
pConfiguration = ExAllocatePoolWithTag(PagedPool,
0x1000,
VP_TAG);
pComponent = ExAllocatePoolWithTag(PagedPool,
0x1000,
VP_TAG);
if (pConfiguration && pComponent)
{
RTL_QUERY_REGISTRY_TABLE QueryTable[] = {
{ NULL,
RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED,
L"Identifier",
&Identifier,
REG_NONE,
NULL,
0
},
{ NULL,
RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED,
L"Configuration Data",
pConfiguration,
REG_NONE,
NULL,
0
},
{ NULL,
RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED,
L"Component Information",
pComponent,
REG_NONE,
NULL,
0
},
// Null entry to mark the end
{ 0, 0, 0, 0, 0, 0, 0 }
};
//
// The first DWORD of the buffer contains the size of the buffer.
// Upon return, the first return contains the size of the data in the buffer.
//
// A NULL bufferint he UNICODE_STRING means the unicode string will be set up automatically
//
*pConfiguration = 0x1000 - 4;
*pComponent = 0x1000 - 4;
Identifier.Buffer = NULL;
if (NT_SUCCESS(RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
L"\\Registry\\Machine\\Hardware\\Description\\System",
QueryTable,
NULL,
NULL)))
{
vpStatus = ((PMINIPORT_QUERY_DEVICE_ROUTINE) CallbackRoutine)(
HwDeviceExtension,
Context,
DeviceDataType,
Identifier.Buffer,
Identifier.Length,
pConfiguration + 1,
*pConfiguration,
pComponent + 1,
*pComponent);
if (vpStatus == NO_ERROR)
{
ntStatus = STATUS_SUCCESS;
}
}
if (Identifier.Buffer)
{
ExFreePool(Identifier.Buffer);
}
}
//
// Free up the resources
//
if (pConfiguration)
{
ExFreePool(pConfiguration);
}
if (pComponent)
{
ExFreePool(pComponent);
}
break;
case VpCmosData:
pVideoDebugPrint((Trace, "VIDEOPRT: VPGetDeviceData: CmosData - not implemented\n"));
#if !defined(NO_LEGACY_DRIVERS)
cmosData = ExAllocatePoolWithTag(PagedPool,
CMOS_MAX_DATA_SIZE,
VP_TAG);
//
// Allocate enough pool to store all the CMOS data.
//
if (!cmosData) {
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
break;
}
cmosDataSize = HalGetBusData(Cmos,
0, // bus 0 returns standard Cmos info
0, // no slot number
cmosData,
CMOS_MAX_DATA_SIZE);
exCmosDataSize = HalGetBusData(Cmos,
1, // bus 1 returns extended Cmos info
0, // no slot number
cmosData + cmosDataSize,
CMOS_MAX_DATA_SIZE - cmosDataSize);
//
// Call the miniport driver callback routine
//
if (NO_ERROR == CallbackRoutine(HwDeviceExtension,
Context,
DeviceDataType,
NULL,
0,
cmosData,
cmosDataSize + exCmosDataSize,
NULL,
0)) {
ntStatus = STATUS_SUCCESS;
} else {
ntStatus = STATUS_DEVICE_DOES_NOT_EXIST;
}
#endif // NO_LEGACY_DRIVERS
break;
break;
case VpBusData:
pVideoDebugPrint((Trace, "VIDEOPRT: VPGetDeviceData: BusData\n"));
ntStatus = IoQueryDeviceDescription(&fdoExtension->AdapterInterfaceType,
&fdoExtension->SystemIoBusNumber,
NULL,
NULL,
NULL,
NULL,
&pVideoPortGetDeviceDataRegistry,
(PVOID)(&queryDevice));
break;
case VpControllerData:
pVideoDebugPrint((Trace, "VIDEOPRT: VPGetDeviceData: ControllerData\n"));
//
// Increment the controller number since we want to get info on the
// new controller.
// We do a pre-increment since the number must remain the same for
// monitor queries.
//
VpQueryDeviceControllerNumber++;
ntStatus = IoQueryDeviceDescription(&fdoExtension->AdapterInterfaceType,
&fdoExtension->SystemIoBusNumber,
&VpQueryDeviceControllerType,
&VpQueryDeviceControllerNumber,
NULL,
NULL,
&pVideoPortGetDeviceDataRegistry,
(PVOID)(&queryDevice));
//
// Reset the Peripheral number to zero since we are working on a new
// Controller.
//
VpQueryDevicePeripheralNumber = 0;
break;
case VpMonitorData:
pVideoDebugPrint((Trace, "VIDEOPRT: VPGetDeviceData: MonitorData\n"));
ntStatus = IoQueryDeviceDescription(&fdoExtension->AdapterInterfaceType,
&fdoExtension->SystemIoBusNumber,
&VpQueryDeviceControllerType,
&VpQueryDeviceControllerNumber,
&VpQueryDevicePeripheralType,
&VpQueryDevicePeripheralNumber,
&pVideoPortGetDeviceDataRegistry,
(PVOID)(&queryDevice));
//
// Increment the peripheral number since we have the info on this
// monitor already.
//
VpQueryDevicePeripheralNumber++;
break;
default:
pVideoDebugPrint((Warn, "VIDEOPRT: VPGetDeviceData: invalid Data type\n"));
ASSERT(FALSE);
ntStatus = STATUS_UNSUCCESSFUL;
}
//
// Free the pool we may have allocated
//
if (cmosData) {
ExFreePool(cmosData);
}
if (NT_SUCCESS(ntStatus)) {
return NO_ERROR;
} else {
pVideoDebugPrint((Warn, "VPGetDeviceData failed: return status is %08lx\n", ntStatus));
return ERROR_INVALID_PARAMETER;
}
} // end VideoPortGetDeviceData()
NTSTATUS
pVideoPortGetRegistryCallback(
IN PWSTR ValueName,
IN ULONG ValueType,
IN PVOID ValueData,
IN ULONG ValueLength,
IN PVOID Context,
IN PVOID EntryContext
)
/*++
Routine Description:
This routine gets information from the system hive, user-specified
registry (as opposed to the information gathered by ntdetect.
Arguments:
ValueName - Pointer to a unicode String containing the name of the data
value being searched for.
ValueType - Type of the data value.
ValueData - Pointer to a buffer containing the information to be written
out to the registry.
ValueLength - Size of the data being written to the registry.
Context - Specifies a context parameter passed to the callback routine.
EntryContext - Specifies a second context parameter passed with the
request.
Return Value:
STATUS_SUCCESS
Environment:
This routine cannot be called from a miniport routine synchronized with
VideoPortSynchronizeRoutine or from an ISR.
--*/
{
PVP_QUERY_DEVICE queryDevice = Context;
UNICODE_STRING unicodeString;
OBJECT_ATTRIBUTES objectAttributes;
NTSTATUS ntStatus = STATUS_SUCCESS;
HANDLE fileHandle = NULL;
IO_STATUS_BLOCK ioStatusBlock;
FILE_STANDARD_INFORMATION fileStandardInfo;
PVOID fileBuffer = NULL;
LARGE_INTEGER byteOffset;
//
// If the parameter was a file to be opened, perform the operation
// here. Otherwise just return the data.
//
if (queryDevice->DeviceDataType == VP_GET_REGISTRY_FILE) {
//
// For the name of the file to be valid, we must first append
// \DosDevices in front of it.
//
RtlInitUnicodeString(&unicodeString,
ValueData);
InitializeObjectAttributes(&objectAttributes,
&unicodeString,
OBJ_CASE_INSENSITIVE,
(HANDLE) NULL,
(PSECURITY_DESCRIPTOR) NULL);
ntStatus = ZwOpenFile(&fileHandle,
FILE_GENERIC_READ | SYNCHRONIZE,
&objectAttributes,
&ioStatusBlock,
0,
FILE_SYNCHRONOUS_IO_ALERT);
if (!NT_SUCCESS(ntStatus)) {
pVideoDebugPrint((Error, "VIDEOPRT: VideoPortGetRegistryParameters: Could not open file\n"));
goto EndRegistryCallback;
}
ntStatus = ZwQueryInformationFile(fileHandle,
&ioStatusBlock,
&fileStandardInfo,
sizeof(FILE_STANDARD_INFORMATION),
FileStandardInformation);
if (!NT_SUCCESS(ntStatus)) {
pVideoDebugPrint((Error, "VIDEOPRT: VideoPortGetRegistryParameters: Could not get size of file\n"));
goto EndRegistryCallback;
}
if (fileStandardInfo.EndOfFile.HighPart) {
//
// If file is too big, do not try to go further.
//
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
goto EndRegistryCallback;
}
ValueLength = fileStandardInfo.EndOfFile.LowPart;
fileBuffer = ExAllocatePoolWithTag(PagedPool,
ValueLength,
VP_TAG);
if (!fileBuffer) {
pVideoDebugPrint((Error, "VideoPortGetRegistryParameters: Could not allocate buffer to read file\n"));
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
goto EndRegistryCallback;
}
ValueData = fileBuffer;
//
// Read the entire file for the beginning.
//
byteOffset.QuadPart = 0;
ntStatus = ZwReadFile(fileHandle,
NULL,
NULL,
NULL,
&ioStatusBlock,
ValueData,
ValueLength,
&byteOffset,
NULL);
if (!NT_SUCCESS(ntStatus)) {
pVideoDebugPrint((Error, "VIDEOPRT: VideoPortGetRegistryParameters: Could not read file\n"));
goto EndRegistryCallback;
}
}
//
// Call the miniport with the appropriate information.
//
queryDevice->MiniportStatus = ((PMINIPORT_GET_REGISTRY_ROUTINE)
queryDevice->CallbackRoutine) (queryDevice->MiniportHwDeviceExtension,
queryDevice->MiniportContext,
ValueName,
ValueData,
ValueLength);
EndRegistryCallback:
if (fileHandle) {
ZwClose(fileHandle);
}
if (fileBuffer) {
ExFreePool(fileBuffer);
}
return ntStatus;
} // end pVideoPortGetRegistryCallback()
VP_STATUS
VideoPortGetRegistryParameters(
PVOID HwDeviceExtension,
PWSTR ParameterName,
UCHAR IsParameterFileName,
PMINIPORT_GET_REGISTRY_ROUTINE CallbackRoutine,
PVOID Context
)
/*++
Routine Description:
VideoPortGetRegistryParameters retrieves information from the
CurrentControlSet in the registry. The function automatically searches
for the specified parameter name under the \Devicexxx key for the
current driver.
Arguments:
HwDeviceExtension - Points to the miniport driver's device extension.
ParameterName - Points to a Unicode string that contains the name of the
data value being searched for in the registry.
IsParameterFileName - If 1, the data retrieved from the requested
parameter name is treated as a file name. The contents of the file are
returned, instead of the parameter itself.
CallbackRoutine - Points to a function that should be called back with
the requested information.
Context - Specifies a context parameter passed to the callback routine.
Return Value:
This function returns the final status of the operation.
Environment:
This routine cannot be called from a miniport routine synchronized with
VideoPortSynchronizeRoutine or from an ISR.
--*/
{
VP_STATUS vpStatus = ERROR_INVALID_PARAMETER;
PDEVICE_SPECIFIC_EXTENSION DoSpecificExtension = GET_DSP_EXT(HwDeviceExtension);
if (DoSpecificExtension->DriverNewRegistryPath != NULL) {
vpStatus = VPGetRegistryParameters(HwDeviceExtension,
ParameterName,
IsParameterFileName,
CallbackRoutine,
Context,
DoSpecificExtension->DriverNewRegistryPath,
DoSpecificExtension->DriverNewRegistryPathLength);
} else {
vpStatus = VPGetRegistryParameters(HwDeviceExtension,
ParameterName,
IsParameterFileName,
CallbackRoutine,
Context,
DoSpecificExtension->DriverOldRegistryPath,
DoSpecificExtension->DriverOldRegistryPathLength);
}
return vpStatus;
}
VP_STATUS
VPGetRegistryParameters(
PVOID HwDeviceExtension,
PWSTR ParameterName,
UCHAR IsParameterFileName,
PMINIPORT_GET_REGISTRY_ROUTINE CallbackRoutine,
PVOID Context,
PWSTR RegistryPath,
ULONG RegistryPathLength
)
{
RTL_QUERY_REGISTRY_TABLE queryTable[2];
NTSTATUS ntStatus;
VP_QUERY_DEVICE queryDevice;
LPWSTR RegPath;
LPWSTR lpstrStart, lpstrEnd;
ASSERT (ParameterName != NULL);
//
// Check if there are subkeys to be entered
//
RegPath = (LPWSTR) ExAllocatePoolWithTag(PagedPool | POOL_COLD_ALLOCATION,
RegistryPathLength +
2 * (wcslen(ParameterName) + sizeof(WCHAR)),
VP_TAG);
if (RegPath == NULL) {
return ERROR_NOT_ENOUGH_MEMORY;
}
wcscpy(RegPath, RegistryPath);
if (!IsParameterFileName)
{
lpstrStart = RegPath + (RegistryPathLength / 2);
while (lpstrEnd = wcschr(ParameterName, L'\\'))
{
//
// Concat the string
//
*(lpstrStart++) = L'\\';
while (ParameterName != lpstrEnd) {
*(lpstrStart++) = *(ParameterName++);
}
*lpstrStart = UNICODE_NULL;
ParameterName++;
}
}
queryDevice.MiniportHwDeviceExtension = HwDeviceExtension;
queryDevice.DeviceDataType = IsParameterFileName ? VP_GET_REGISTRY_FILE : VP_GET_REGISTRY_DATA;
queryDevice.CallbackRoutine = CallbackRoutine;
queryDevice.MiniportStatus = NO_ERROR;
queryDevice.MiniportContext = Context;
//
// Can be simplified now since we don't have to go down a directory.
// It can be just one call.
//
queryTable[0].QueryRoutine = pVideoPortGetRegistryCallback;
queryTable[0].Flags = RTL_QUERY_REGISTRY_REQUIRED;
queryTable[0].Name = ParameterName;
queryTable[0].EntryContext = NULL;
queryTable[0].DefaultType = REG_NONE;
queryTable[0].DefaultData = 0;
queryTable[0].DefaultLength = 0;
queryTable[1].QueryRoutine = NULL;
queryTable[1].Flags = 0;
queryTable[1].Name = NULL;
queryTable[1].EntryContext = NULL;
queryTable[1].DefaultType = REG_NONE;
queryTable[1].DefaultData = 0;
queryTable[1].DefaultLength = 0;
ntStatus = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
RegPath,
queryTable,
&queryDevice,
NULL);
if (!NT_SUCCESS(ntStatus)) {
queryDevice.MiniportStatus = ERROR_INVALID_PARAMETER;
}
ExFreePool(RegPath);
return queryDevice.MiniportStatus;
} // end VideoPortGetRegistryParameters()
VOID
pVPInit(
VOID
)
/*++
Routine Description:
First time initialization of the video port.
Normally, this is the stuff we should put in the DriverEntry routine.
However, the video port is being loaded as a DLL, and the DriverEntry
is never called. It would just be too much work to add it back to the hive
and setup.
This little routine works just as well.
--*/
{
UNICODE_STRING UnicodeString;
OBJECT_ATTRIBUTES ObjectAttributes;
NTSTATUS ntStatus;
HANDLE hkRegistry;
UCHAR OptionsData[512];
HANDLE physicalMemoryHandle = NULL;
PBACKLIGHT_STATUS pVpBacklightStatus = &VpBacklightStatus;
PKEY_VALUE_PARTIAL_INFORMATION pKeyValueInfo = NULL;
HAL_DISPLAY_BIOS_INFORMATION HalBiosInfo;
ULONG HalBiosInfoLen = sizeof(ULONG);
SYSTEM_BASIC_INFORMATION basicInfo;
//
// Check for USWC disabling
//
RtlInitUnicodeString(&UnicodeString,
L"\\Registry\\Machine\\System\\CurrentControlSet"
L"\\Control\\GraphicsDrivers\\DisableUSWC");
InitializeObjectAttributes(&ObjectAttributes,
&UnicodeString,
OBJ_CASE_INSENSITIVE,
NULL,
NULL);
ntStatus = ZwOpenKey(&hkRegistry,
GENERIC_READ | GENERIC_WRITE,
&ObjectAttributes);
if (NT_SUCCESS(ntStatus)) {
EnableUSWC = FALSE;
ZwClose(hkRegistry);
}
//
// Check for setup running
//
{
ULONG defaultValue = 0;
ULONG UpgradeInProgress = 0, SystemSetupInProgress = 0, MiniSetupInProgress = 0;
RTL_QUERY_REGISTRY_TABLE QueryTable[] = {
{NULL, RTL_QUERY_REGISTRY_DIRECT, L"SystemSetupInProgress",
&SystemSetupInProgress, REG_DWORD, &defaultValue, 4},
{NULL, RTL_QUERY_REGISTRY_DIRECT, L"UpgradeInProgress",
&UpgradeInProgress, REG_DWORD, &defaultValue, 4},
{NULL, RTL_QUERY_REGISTRY_DIRECT, L"MiniSetupInProgress",
&MiniSetupInProgress, REG_DWORD, &defaultValue, 4},
{NULL, 0, NULL}
};
RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
L"\\Registry\\Machine\\System\\Setup",
&QueryTable[0],
NULL,
NULL);
// System is doing an upgrade.
if (UpgradeInProgress)
{
ASSERT(SystemSetupInProgress);
VpSetupType = SETUPTYPE_UPGRADE;
}
// System is doing a clean install.
else if (SystemSetupInProgress && !MiniSetupInProgress)
{
VpSetupType = SETUPTYPE_FULL;
}
else
{
VpSetupType = SETUPTYPE_NONE;
}
VpSetupTypeAtBoot = VpSetupType;
}
//
// Check for basevideo from the start options
//
RtlInitUnicodeString(&UnicodeString,
L"\\Registry\\Machine\\System\\CurrentControlSet"
L"\\Control");
InitializeObjectAttributes(&ObjectAttributes,
&UnicodeString,
OBJ_CASE_INSENSITIVE,
NULL,
NULL);
ntStatus = ZwOpenKey(&hkRegistry,
GENERIC_READ | GENERIC_WRITE,
&ObjectAttributes);
if (NT_SUCCESS(ntStatus)) {
PVOID pwszOptions;
ULONG returnSize;
RtlInitUnicodeString(&UnicodeString,
L"SystemStartOptions");
ntStatus = ZwQueryValueKey(hkRegistry,
&UnicodeString,
KeyValueFullInformation,
OptionsData,
sizeof(OptionsData),
&returnSize);
if ((NT_SUCCESS(ntStatus)) &&
(((PKEY_VALUE_FULL_INFORMATION)OptionsData)->DataLength) &&
(((PKEY_VALUE_FULL_INFORMATION)OptionsData)->DataOffset)) {
pwszOptions = ((PUCHAR)OptionsData) +
((PKEY_VALUE_FULL_INFORMATION)OptionsData)->DataOffset;
if (wcsstr(pwszOptions, L"BASEVIDEO")) {
VpBaseVideo = TRUE;
}
}
ZwClose(hkRegistry);
}
if (VpBaseVideo == TRUE)
{
//
// If we are in Basevideo mode, then create a key and value in the
// currentcontrolset part of the hardware profile that USER will
// read to determine if the vga driver should be used or not.
//
RtlInitUnicodeString(&UnicodeString,
L"\\Registry\\Machine\\System\\CurrentControlSet\\"
L"Control\\GraphicsDrivers\\BaseVideo");
InitializeObjectAttributes(&ObjectAttributes,
&UnicodeString,
OBJ_CASE_INSENSITIVE,
NULL,
NULL);
ntStatus = ZwCreateKey(&hkRegistry,
GENERIC_READ | GENERIC_WRITE,
&ObjectAttributes,
0L,
NULL,
REG_OPTION_VOLATILE,
NULL);
if (NT_SUCCESS(ntStatus)) {
ZwClose(hkRegistry);
} else {
ASSERT(FALSE);
}
}
//
// Determine if we have a VGA compatible machine
//
ntStatus = HalQuerySystemInformation(HalDisplayBiosInformation,
HalBiosInfoLen,
&HalBiosInfo,
&HalBiosInfoLen);
if (NT_SUCCESS(ntStatus)) {
if (HalBiosInfo == HalDisplayInt10Bios) {
VpC0000Compatible = 2;
} else {
// == HalDisplayEmulatedBios,
// == HalDisplayNoBios
VpC0000Compatible = 0;
}
} else {
//
// In case of an error in the API call, we just assume it's an old HAL
// and use the old behaviour of the video port which is to assume
// there is a BIOS at C000
//
VpC0000Compatible = 1;
}
//
// Lets open the physical memory section just once, for all drivers.
//
//
// Get a pointer to physical memory so we can map the
// video frame buffer (and possibly video registers) into
// the caller's address space whenever he needs it.
//
// - Create the name
// - Initialize the data to find the object
// - Open a handle to the oject and check the status
// - Get a pointer to the object
// - Free the handle
//
RtlInitUnicodeString(&UnicodeString,
L"\\Device\\PhysicalMemory");
InitializeObjectAttributes(&ObjectAttributes,
&UnicodeString,
OBJ_CASE_INSENSITIVE,
(HANDLE) NULL,
(PSECURITY_DESCRIPTOR) NULL);
ntStatus = ZwOpenSection(&physicalMemoryHandle,
SECTION_ALL_ACCESS,
&ObjectAttributes);
if (NT_SUCCESS(ntStatus)) {
ntStatus = ObReferenceObjectByHandle(physicalMemoryHandle,
SECTION_ALL_ACCESS,
(POBJECT_TYPE) NULL,
KernelMode,
&PhysicalMemorySection,
(POBJECT_HANDLE_INFORMATION) NULL);
if (!NT_SUCCESS(ntStatus)) {
pVideoDebugPrint((Warn, "VIDEOPRT: VPInit: Could not reference physical memory\n"));
ASSERT(PhysicalMemorySection == NULL);
}
ZwClose(physicalMemoryHandle);
}
VpSystemMemorySize = 0;
ntStatus = ZwQuerySystemInformation(SystemBasicInformation,
&basicInfo,
sizeof(basicInfo),
NULL);
if (NT_SUCCESS(ntStatus)) {
VpSystemMemorySize
= (ULONGLONG)basicInfo.NumberOfPhysicalPages * (ULONGLONG)basicInfo.PageSize;
}
//
// Initialize the fast mutex to protect the LCD Panel information
// Initialize the fast mutex to protect INT10
//
KeInitializeMutex (&LCDPanelMutex, 0);
KeInitializeMutex (&VpInt10Mutex, 0);
//
// Check if we should use the new way of generating the registry path
//
RtlInitUnicodeString(&UnicodeString,
SZ_USE_NEW_KEY);
InitializeObjectAttributes(&ObjectAttributes,
&UnicodeString,
OBJ_CASE_INSENSITIVE,
NULL,
NULL);
ntStatus = ZwOpenKey(&hkRegistry,
GENERIC_READ | GENERIC_WRITE,
&ObjectAttributes);
if (NT_SUCCESS(ntStatus)) {
EnableNewRegistryKey = TRUE;
ZwClose(hkRegistry);
}
//
// Initialize our structure which tracks the state of
// a backlight for the LCD (when present)
//
pVpBacklightStatus->bQuerySupportedBrightnessCalled = FALSE;
pVpBacklightStatus->bACBrightnessKnown = FALSE;
pVpBacklightStatus->bDCBrightnessKnown = FALSE;
pVpBacklightStatus->bBIOSDefaultACKnown = FALSE;
pVpBacklightStatus->bBIOSDefaultDCKnown = FALSE;
pVpBacklightStatus->bNewAPISupported = FALSE;
pVpBacklightStatus->bACBrightnessInRegistry = FALSE;
pVpBacklightStatus->bACBrightnessInRegistry = FALSE;
//
// Read the registry to find out if the new API is supported.
// If so, retreive the AC/DC brightness values and set the
// brightness as applicable (depending upon VpRunningOnAC).
//
// Note: We will store the Backlight info in the following
// location in the registry:
//
// HKLM\System\CurrentControlSet\Control\Backlight
//
// The values there will be:
//
// NewAPISupported REG_DWORD 0 Not Supported
// 1 Supported
//
//
// ACBacklightLevel REG_DWORD 0-255
//
// DCBacklightLevel REG_DWORD 0-255
//
pKeyValueInfo = ExAllocatePoolWithTag(PagedPool,
sizeof(KEY_VALUE_PARTIAL_INFORMATION) + 3,
VP_TAG);
if (pKeyValueInfo == NULL) {
return;
}
RtlInitUnicodeString(&UnicodeString,
L"\\Registry\\Machine\\System\\CurrentControlSet"
L"\\Control\\Backlight");
InitializeObjectAttributes(&ObjectAttributes,
&UnicodeString,
OBJ_CASE_INSENSITIVE,
NULL,
NULL);
ntStatus = ZwOpenKey(&hkRegistry,
GENERIC_READ | GENERIC_WRITE,
&ObjectAttributes);
if (NT_SUCCESS(ntStatus)) {
//
// The key is there, read the 3 values listed above
//
ULONG ulReturnSize;
// NewAPISupported
RtlInitUnicodeString(&UnicodeString,
L"NewAPISupported");
ntStatus = ZwQueryValueKey(hkRegistry,
&UnicodeString,
KeyValuePartialInformation,
(PVOID) pKeyValueInfo,
sizeof(KEY_VALUE_PARTIAL_INFORMATION) + 3,
&ulReturnSize);
if (NT_SUCCESS(ntStatus)) {
if ((UCHAR) *pKeyValueInfo->Data) {
pVpBacklightStatus->bNewAPISupported = TRUE;
}
// ACBacklightLevel
RtlInitUnicodeString(&UnicodeString,
L"ACBacklightLevel");
ntStatus = ZwQueryValueKey(hkRegistry,
&UnicodeString,
KeyValuePartialInformation,
(PVOID) pKeyValueInfo,
sizeof(KEY_VALUE_PARTIAL_INFORMATION) + 3,
&ulReturnSize);
if (NT_SUCCESS(ntStatus)) {
pVpBacklightStatus->bACBrightnessInRegistry = TRUE;
pVpBacklightStatus->bACBrightnessKnown = TRUE;
pVpBacklightStatus->ucACBrightness = (UCHAR) *pKeyValueInfo->Data;
}
// DCBacklightLevel
RtlInitUnicodeString(&UnicodeString,
L"DCBacklightLevel");
ntStatus = ZwQueryValueKey(hkRegistry,
&UnicodeString,
KeyValuePartialInformation,
(PVOID) pKeyValueInfo,
sizeof(KEY_VALUE_PARTIAL_INFORMATION) + 3,
&ulReturnSize);
if (NT_SUCCESS(ntStatus)) {
pVpBacklightStatus->bDCBrightnessInRegistry = TRUE;
pVpBacklightStatus->bDCBrightnessKnown = TRUE;
pVpBacklightStatus->ucDCBrightness = (UCHAR) *pKeyValueInfo->Data;
}
}
ZwClose(hkRegistry);
}
if (pKeyValueInfo) {
ExFreePool(pKeyValueInfo);
}
//
// Most laptops respond incorrectly to HwSetPowerState calls
// on lid close. By default, we will support the XP behavior
// and not notify the miniport on lid close.
//
// The driver will be called if the following registry key
// is present:
//
// HKLM\System\CurrentControlSet\Control\GraphicsDrivers\LidCloseSetPower"
//
RtlInitUnicodeString(&UnicodeString,
SZ_LIDCLOSE);
InitializeObjectAttributes(&ObjectAttributes,
&UnicodeString,
OBJ_CASE_INSENSITIVE,
NULL,
NULL);
ntStatus = ZwOpenKey(&hkRegistry,
GENERIC_READ | GENERIC_WRITE,
&ObjectAttributes);
if (NT_SUCCESS(ntStatus)) {
VpLidCloseSetPower = TRUE;
ZwClose(hkRegistry);
}
//
// Initialize the bugcheck callback record
//
KeInitializeCallbackRecord(&VpCallbackRecord);
//
// Regiter for bugcheck callbacks.
//
KeRegisterBugCheckReasonCallback(&VpCallbackRecord,
pVpBugcheckCallback,
KbCallbackSecondaryDumpData,
"Videoprt");
//
// Initialize the global video port mutex.
//
KeInitializeMutex(&VpGlobalLock, 0);
}
VOID
VpDriverUnload(
IN PDRIVER_OBJECT DriverObject
)
{
ULONG_PTR emptyList = 0;
BOOLEAN conflict;
//ULONG iReset;
//PDEVICE_OBJECT DeviceObject = DriverObject->DeviceObject;
//
// Release the resource we put in the resourcemap (if any).
//
IoReportResourceUsage(&VideoClassName,
DriverObject,
NULL,
0L,
NULL,
(PCM_RESOURCE_LIST) &emptyList,
sizeof(ULONG_PTR),
FALSE,
&conflict);
//
// Unregister LCD callbacks.
//
VpUnregisterLCDCallbacks();
//
// Unregister Dock/Undock callbacks.
//
if (DockCallbackHandle)
{
IoUnregisterPlugPlayNotification(DockCallbackHandle);
}
//
// Make absolutely certain there are no HwResetHw routines left
// for this devices controlled by this DriverObject.
//
//while (DeviceObject) {
//
// for (iReset=0; iReset<6; iReset++) {
//
// if (HwResetHw[iReset].HwDeviceExtension ==
// ((PDEVICE_EXTENSION)
// DeviceObject->DeviceExtension)->HwDeviceExtension) {
//
// HwResetHw[iReset].ResetFunction = NULL;
// break;
// }
// }
//
// DeviceObject = DeviceObject->NextDevice;
//}
// This is causing us to lose video on a number of systems
// during setup. This code can be used when the necessary
// additional checks are determined.
//
//if (CsrProcess) {
// ObDereferenceObject(CsrProcess);
// CsrProcess = NULL;
//}
//
// Unregister bugcheck callbacks
//
KeDeregisterBugCheckReasonCallback(&VpCallbackRecord);
return;
}
NTSTATUS
VpInitializeBusCallback(
IN PVOID Context,
IN PUNICODE_STRING PathName,
IN INTERFACE_TYPE BusType,
IN ULONG BusNumber,
IN PKEY_VALUE_FULL_INFORMATION *BusInformation,
IN CONFIGURATION_TYPE ControllerType,
IN ULONG ControllerNumber,
IN PKEY_VALUE_FULL_INFORMATION *ControllerInformation,
IN CONFIGURATION_TYPE PeripheralType,
IN ULONG PeripheralNumber,
IN PKEY_VALUE_FULL_INFORMATION *PeripheralInformation
)
{
return STATUS_SUCCESS;
} // end VpInitializeBusCallback()
VP_STATUS
VpRegistryCallback(
PVOID HwDeviceExtension,
PVOID Context,
PWSTR ValueName,
PVOID ValueData,
ULONG ValueLength
)
{
if (ValueLength && ValueData) {
*((PULONG)Context) = *((PULONG)ValueData);
return NO_ERROR;
} else {
return ERROR_INVALID_PARAMETER;
}
}
NTSTATUS
VpAddDevice(
IN PDRIVER_OBJECT DriverObject,
IN PDEVICE_OBJECT PhysicalDeviceObject
)
{
NTSTATUS ntStatus;
PDEVICE_OBJECT functionalDeviceObject;
PDEVICE_OBJECT attachedTo;
PFDO_EXTENSION fdoExtension;
ULONG extensionAllocationSize;
PVIDEO_PORT_DRIVER_EXTENSION DriverObjectExtension;
PVIDEO_HW_INITIALIZATION_DATA HwInitializationData;
pVideoDebugPrint((Trace, "VIDEOPRT: VpAddDevice\n"));
DriverObjectExtension = (PVIDEO_PORT_DRIVER_EXTENSION)
IoGetDriverObjectExtension(DriverObject,
DriverObject);
HwInitializationData = &DriverObjectExtension->HwInitData;
extensionAllocationSize = HwInitializationData->HwDeviceExtensionSize +
sizeof(FDO_EXTENSION) +
sizeof(DEVICE_SPECIFIC_EXTENSION);
ntStatus = VpCreateDevice(DriverObject,
extensionAllocationSize,
&functionalDeviceObject);
if (NT_SUCCESS(ntStatus)) {
PCHILD_PDO_EXTENSION PdoExtension = PhysicalDeviceObject->DeviceExtension;
VideoDeviceNumber++;
fdoExtension = (PFDO_EXTENSION)functionalDeviceObject->DeviceExtension;
//
// Set any deviceExtension fields here that are PnP specific
//
fdoExtension->ChildPdoNumber = 0;
fdoExtension->ChildPdoList = NULL;
fdoExtension->PhysicalDeviceObject = PhysicalDeviceObject;
//
// Since the pnp system is notifying us of our device, this is
// not a legacy device.
//
fdoExtension->Flags = PNP_ENABLED;
//
// Now attach to the PDO we were given.
//
attachedTo = IoAttachDeviceToDeviceStack(functionalDeviceObject,
PhysicalDeviceObject);
if (attachedTo == NULL) {
pVideoDebugPrint((Error, "VIDEOPRT: Could not attach in AddDevice.\n"));
ASSERT(attachedTo != NULL);
//
// Couldn't attach. Delete the FDO, and tear down anything that has
// been allocated so far.
//
VideoDeviceNumber--;
IoDeleteDevice (functionalDeviceObject);
return STATUS_NO_SUCH_DEVICE;
}
//
// Initialize the remove lock.
//
IoInitializeRemoveLock(&fdoExtension->RemoveLock, 0, 0, 256);
fdoExtension->AttachedDeviceObject = attachedTo;
fdoExtension->VpDmaAdapterHead = NULL ;
//
// Set the power management flag indicating that device mapping
// has not been done yet.
//
fdoExtension->IsMappingReady = FALSE ;
//
// Clear DO_DEVICE_INITIALIZING flag.
//
functionalDeviceObject->Flags |= DO_BUFFERED_IO | DO_POWER_PAGABLE;
functionalDeviceObject->Flags &= ~(DO_DEVICE_INITIALIZING | DO_POWER_INRUSH);
//
// Save the function pointers to the new 5.0 miniport driver callbacks.
//
if (HwInitializationData->HwInitDataSize >
FIELD_OFFSET(VIDEO_HW_INITIALIZATION_DATA, HwQueryInterface)) {
fdoExtension->HwSetPowerState = HwInitializationData->HwSetPowerState;
fdoExtension->HwGetPowerState = HwInitializationData->HwGetPowerState;
fdoExtension->HwQueryInterface = HwInitializationData->HwQueryInterface;
fdoExtension->HwGetVideoChildDescriptor = HwInitializationData->HwGetVideoChildDescriptor;
}
}
pVideoDebugPrint((Trace, "VIDEOPRT: VpAddDevice returned: 0x%x\n", ntStatus));
return ntStatus;
}
NTSTATUS
VpCreateDevice(
IN PDRIVER_OBJECT DriverObject,
IN ULONG DeviceExtensionSize,
OUT PDEVICE_OBJECT *FunctionalDeviceObject
)
{
WCHAR deviceNameBuffer[STRING_LENGTH];
UNICODE_STRING deviceNameUnicodeString;
NTSTATUS ntStatus;
PFDO_EXTENSION fdoExtension;
PDEVICE_SPECIFIC_EXTENSION DoSpecificExtension;
ntStatus = pVideoPortCreateDeviceName(L"\\Device\\Video",
VideoDeviceNumber,
&deviceNameUnicodeString,
deviceNameBuffer);
//
// Create a device object to represent the Video Adapter.
//
if (NT_SUCCESS(ntStatus)) {
ntStatus = IoCreateDevice(DriverObject,
DeviceExtensionSize,
&deviceNameUnicodeString,
FILE_DEVICE_VIDEO,
0,
TRUE,
FunctionalDeviceObject);
if (NT_SUCCESS(ntStatus)) {
ntStatus = IoRegisterShutdownNotification(*FunctionalDeviceObject);
if (!NT_SUCCESS(ntStatus)) {
IoDeleteDevice(*FunctionalDeviceObject);
*FunctionalDeviceObject = NULL;
} else {
(*FunctionalDeviceObject)->DeviceType = FILE_DEVICE_VIDEO;
fdoExtension = (*FunctionalDeviceObject)->DeviceExtension;
//
// Set any deviceExtension fields here
//
DoSpecificExtension = (PVOID)(fdoExtension + 1);
DoSpecificExtension->DeviceNumber = VideoDeviceNumber;
DoSpecificExtension->pFdoExtension = fdoExtension;
DoSpecificExtension->Signature = VP_TAG;
DoSpecificExtension->ExtensionType = TypeDeviceSpecificExtension;
DoSpecificExtension->HwDeviceExtension = (PVOID)(DoSpecificExtension + 1);
DoSpecificExtension->DualviewFlags = 0;
#ifdef IOCTL_VIDEO_USE_DEVICE_IN_SESSION
DoSpecificExtension->SessionId = VIDEO_DEVICE_INVALID_SESSION;
#endif IOCTL_VIDEO_USE_DEVICE_IN_SESSION
fdoExtension->pFdoExtension = fdoExtension;
fdoExtension->Signature = VP_TAG;
fdoExtension->ExtensionType = TypeFdoExtension;
fdoExtension->FunctionalDeviceObject = *FunctionalDeviceObject;
fdoExtension->DriverObject = DriverObject;
KeInitializeMutex(&fdoExtension->SyncMutex,
0);
}
}
}
return ntStatus;
}
ULONG
VideoPortInitialize(
IN PVOID Argument1, // DriverObject
IN PVOID Argument2, // RegistryPath
IN PVIDEO_HW_INITIALIZATION_DATA HwInitializationData,
IN PVOID HwContext
)
{
PDRIVER_OBJECT driverObject = Argument1;
NTSTATUS ntStatus;
PUNICODE_STRING registryPath = (PUNICODE_STRING) Argument2;
ULONG PnpFlags;
if (VPFirstTime)
{
VPFirstTime = FALSE;
pVPInit();
}
//
// Check if the size of the pointer, or the size of the data passed in
// are OK.
//
ASSERT(HwInitializationData != NULL);
if (HwInitializationData->HwInitDataSize >
sizeof(VIDEO_HW_INITIALIZATION_DATA) ) {
pVideoDebugPrint((Error, "VIDEOPRT: Invalid initialization data size\n"));
return ((ULONG) STATUS_REVISION_MISMATCH);
}
//
// Check that each required entry is not NULL.
//
if ((!HwInitializationData->HwFindAdapter) ||
(!HwInitializationData->HwInitialize) ||
(!HwInitializationData->HwStartIO)) {
pVideoDebugPrint((Error, "VIDEOPRT: Miniport missing required entry\n"));
return ((ULONG)STATUS_REVISION_MISMATCH);
}
//
// Check the registry for PnP Flags. Currently we recongnize the
// following values:
//
// PnPEnabled - If this value is set with a non-zero value, we
// will treat behave like a PnP driver.
//
// LegacyDetect - If this value is non-zero, we will report
// a non-pci device to the system via
// IoReportDetectedDevice.
//
// If we don't get the flags, we don't know how to run this driver.
// return failure
//
if (!(NT_SUCCESS(VpGetFlags(registryPath,
HwInitializationData,
&PnpFlags))))
{
return STATUS_UNSUCCESSFUL;
}
//
// During an upgrade don't allow a driver to start unless it was written
// for this version of Windows.
//
if ((VpSetupTypeAtBoot == SETUPTYPE_UPGRADE) &&
(HwInitializationData->HwInitDataSize < sizeof(VIDEO_HW_INITIALIZATION_DATA)))
{
pVideoDebugPrint((0, "We don't allow pre WinXP drivers to start during upgrade.\n"));
return STATUS_UNSUCCESSFUL;
}
//
// Set up the device driver entry points.
//
driverObject->DriverUnload = VpDriverUnload;
driverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = pVideoPortDispatch;
driverObject->MajorFunction[IRP_MJ_CREATE] = pVideoPortDispatch;
driverObject->MajorFunction[IRP_MJ_CLOSE] = pVideoPortDispatch;
driverObject->MajorFunction[IRP_MJ_SHUTDOWN] = pVideoPortDispatch;
//
// Check that the device extension size is reasonable.
//
#if DBG
if (HwInitializationData->HwDeviceExtensionSize > 0x4000) {
pVideoDebugPrint((Warn, "VIDEOPRT: VideoPortInitialize:\n"
"Warning: Device Extension is stored in non-paged pool\n"
" Do you need a 0x%x byte device extension?\n",
HwInitializationData->HwDeviceExtensionSize));
}
#endif
//
// PnP drivers have new rules.
//
if (PnpFlags & PNP_ENABLED)
{
pVideoDebugPrint((Trace, "VIDEOPRT: VideoPortInitialize with PNP_ENABLED\n"));
//
// We also can't be plug and play compatible if the driver passes
// info in HwContext. This is because we can't store this.
//
if ((PnpFlags & VGA_DRIVER) ||
(HwContext != NULL))
{
pVideoDebugPrint((Error, "VIDEOPRT: This video driver can not be "
"PNP due to passing info in HwContext.\n"));
ASSERT(FALSE);
return STATUS_INVALID_PARAMETER;
}
} else {
//
// Don't allow a non PnP driver to start after the system is up and
// running. Instead require a reboot first.
//
if (VpSystemInitialized) {
#if defined STATUS_REBOOT_REQUIRED
return STATUS_REBOOT_REQUIRED;
#else
return STATUS_INVALID_PARAMETER;
#endif
}
}
//
// Never do legacy detection of PnP drivers on the PCI Bus.
//
if (HwInitializationData->AdapterInterfaceType == PCIBus) {
pVideoDebugPrint((Trace, "VIDEOPRT: VideoPortInitialize on PCI Bus\n"));
if ( (PnpFlags & PNP_ENABLED) &&
((PnpFlags & LEGACY_DETECT) ||
(PnpFlags & REPORT_DEVICE)) ) {
pVideoDebugPrint((Error, "VIDEOPRT: Trying to detect PnP driver on PCI - fail\n"));
return STATUS_INVALID_PARAMETER;
}
}
//
// Set this information for all PnP Drivers
//
// Special !!! - we cannot do this in the LEGACY_DETECT because the system
// will think we failed to load and return a failure code.
//
if ( (PnpFlags & PNP_ENABLED) &&
(!(PnpFlags & LEGACY_DETECT)) )
{
PVIDEO_PORT_DRIVER_EXTENSION DriverObjectExtension;
pVideoDebugPrint((Info, "VIDEOPRT: We have a PnP Device.\n"));
//
// Fill in the new PnP entry points.
//
driverObject->DriverExtension->AddDevice = VpAddDevice;
driverObject->MajorFunction[IRP_MJ_PNP] = pVideoPortPnpDispatch;
driverObject->MajorFunction[IRP_MJ_POWER] = pVideoPortPowerDispatch;
driverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = pVideoPortSystemControl;
//
// we'll do findadapter during the START_DEVICE irp
//
// Store away arguments, so we can retrieve them when we need them.
//
// Try to create a DriverObjectExtension
//
if (DriverObjectExtension = (PVIDEO_PORT_DRIVER_EXTENSION)
IoGetDriverObjectExtension(driverObject,
driverObject))
{
DriverObjectExtension->HwInitData = *HwInitializationData;
ntStatus = STATUS_SUCCESS;
}
else if (NT_SUCCESS(IoAllocateDriverObjectExtension(
driverObject,
driverObject,
sizeof(VIDEO_PORT_DRIVER_EXTENSION),
&DriverObjectExtension)))
{
DriverObjectExtension->RegistryPath = *registryPath;
DriverObjectExtension->RegistryPath.MaximumLength += sizeof(WCHAR);
DriverObjectExtension->RegistryPath.Buffer =
ExAllocatePoolWithTag(PagedPool | POOL_COLD_ALLOCATION,
DriverObjectExtension->RegistryPath.MaximumLength,
'trpV');
ASSERT(DriverObjectExtension->RegistryPath.Buffer);
RtlCopyUnicodeString(&(DriverObjectExtension->RegistryPath),
registryPath);
DriverObjectExtension->HwInitData = *HwInitializationData;
ntStatus = STATUS_SUCCESS;
}
else
{
//
// Something went wrong. We should have a
// DriverObjectExtension by now.
//
pVideoDebugPrint((Error, "VIDEOPRT: IoAllocateDriverExtensionObject failed!\n"));
ASSERT(FALSE);
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
}
}
//
// If we are doing legacy detection or reporting, create the FDO
// right now ...
//
if ((!(PnpFlags & PNP_ENABLED)) ||
(PnpFlags & LEGACY_DETECT) ||
(PnpFlags & VGA_DRIVER) ||
(PnpFlags & REPORT_DEVICE) ||
(HwContext != NULL)) {
pVideoDebugPrint((Trace, "VIDEOPRT: VideoPortInitialize on PCI Bus\n"));
pVideoDebugPrint((Info, "Legacy FindAdapter Interface %s\n",
BusType[HwInitializationData->AdapterInterfaceType]));
ntStatus = VideoPortLegacyFindAdapter(Argument1,
Argument2,
HwInitializationData,
HwContext,
PnpFlags);
}
return ntStatus;
}
VOID
UpdateRegValue(
IN PUNICODE_STRING RegistryPath,
IN PWCHAR RegValue,
IN ULONG Value
)
{
PWSTR Path;
Path = ExAllocatePoolWithTag(PagedPool,
RegistryPath->Length + sizeof(UNICODE_NULL),
VP_TAG);
if (Path) {
RtlCopyMemory(Path,
RegistryPath->Buffer,
RegistryPath->Length);
*(Path + (RegistryPath->Length / sizeof(UNICODE_NULL))) = UNICODE_NULL;
RtlWriteRegistryValue(
RTL_REGISTRY_ABSOLUTE,
Path,
RegValue,
REG_DWORD,
&Value,
sizeof(ULONG));
ExFreePool(Path);
}
}
ULONG
VideoPortLegacyFindAdapter(
IN PDRIVER_OBJECT DriverObject,
IN PVOID Argument2,
IN PVIDEO_HW_INITIALIZATION_DATA HwInitializationData,
IN PVOID HwContext,
IN ULONG PnpFlags
)
{
ULONG busNumber = 0;
ULONG extensionAllocationSize;
NTSTATUS ntStatus;
UCHAR nextMiniport;
ULONG registryIndex = 0;
//
// Reset the controller number used in IoQueryDeviceDescription to zero
// since we are restarting on a new type of bus.
// Note: PeripheralNumber is reset only when we find a new controller.
//
VpQueryDeviceControllerNumber = 0xFFFFFFFF;
//
// Determine size of the device extension to allocate.
//
extensionAllocationSize = sizeof(FDO_EXTENSION) +
sizeof(DEVICE_SPECIFIC_EXTENSION) +
HwInitializationData->HwDeviceExtensionSize;
//
// Check if we are on the right Bus Adapter type.
// If we are not, then return immediately.
//
ASSERT (HwInitializationData->AdapterInterfaceType < MaximumInterfaceType);
//
// Assume we are going to fail this the IoQueryDeviceDescription call
// and that no device is found.
//
ntStatus = STATUS_NO_SUCH_DEVICE;
pVideoDebugPrint((Trace, "Legacy FindAdapter Interface %s, Bus %d\n",
BusType[HwInitializationData->AdapterInterfaceType],
busNumber));
while (NT_SUCCESS(IoQueryDeviceDescription(
&HwInitializationData->AdapterInterfaceType,
&busNumber,
NULL,
NULL,
NULL,
NULL,
&VpInitializeBusCallback,
NULL))) {
//
// This is to support the multiple initialization as described by the
// again paramter in HwFindAdapter.
// We must repeat almost everything in this function until FALSE is
// returned by the miniport. This is why we test for the condition at
// the end. Freeing of data structure has to be done also since we want
// to delete a device object for a device that did not load properly.
//
do {
PDEVICE_OBJECT deviceObject = NULL;
PDEVICE_OBJECT PnPDeviceObject = NULL;
PFDO_EXTENSION fdoExtension;
UNICODE_STRING tmpString;
nextMiniport = FALSE;
//
// Allocate the buffer in which the miniport driver will store all the
// configuration information.
//
ntStatus = VpCreateDevice(DriverObject,
extensionAllocationSize,
&deviceObject);
if (!NT_SUCCESS(ntStatus)) {
pVideoDebugPrint((Error, "VIDEOPRT: VideoPortLegacyFindAdapter: Could not create device object\n"));
return (ULONG)ntStatus;
}
fdoExtension = deviceObject->DeviceExtension;
fdoExtension->SystemIoBusNumber = busNumber;
fdoExtension->AdapterInterfaceType =
HwInitializationData->AdapterInterfaceType;
fdoExtension->RegistryIndex = registryIndex;
//
// Initialize the remove lock.
//
IoInitializeRemoveLock(&fdoExtension->RemoveLock, 0, 0, 256);
//
// If we came through this code path, we are a legacy device
//
fdoExtension->Flags = PnpFlags | LEGACY_DRIVER;
fdoExtension->VpDmaAdapterHead = NULL ;
//
// Make the VGA driver report resources "for detection" during
// FindAdapter. Later we'll remove the "LEGACY_DETECT" flag and
// try to claim the resources for real.
//
if (fdoExtension->Flags & VGA_DRIVER) {
fdoExtension->Flags |= VGA_DETECT;
}
ntStatus = VideoPortFindAdapter(DriverObject,
Argument2,
HwInitializationData,
HwContext,
deviceObject,
&nextMiniport);
if (fdoExtension->Flags & VGA_DRIVER) {
fdoExtension->Flags &= ~VGA_DETECT;
}
pVideoDebugPrint((Info, "VIDEOPRT: Legacy VideoPortFindAdapter status = %08lx\n", ntStatus));
pVideoDebugPrint((Info, "VIDEOPRT: Legacy VideoPortFindAdapter nextMiniport = %d\n", nextMiniport));
if ((NT_SUCCESS(ntStatus) == FALSE) || (PnpFlags & LEGACY_DETECT))
{
pVideoDebugPrint((1, "Deleting Device Object.\n"));
IoDeleteDevice(deviceObject);
}
if (NT_SUCCESS(ntStatus))
{
//
// We use this variable to know if at least one of the tries at
// loading the device succeded.
//
registryIndex++;
}
else
{
continue;
}
//
// If this is the VGA driver, store this device extension for
// us to play around with the resources later on (so we can release
// the resources if we install a driver on the fly).
//
// Otherwise, determine if we want to report it to the IO system
// so it can be used as a PNP device later on.
// ... Never report a device found on the PCI bus.
//
if (PnpFlags & VGA_DRIVER)
{
VgaHwDeviceExtension = fdoExtension->HwDeviceExtension;
if (NT_SUCCESS(ntStatus)) {
//
// Claim the VGA resources again without the
// VGA_DETECT flag.
//
VideoPortVerifyAccessRanges(VgaHwDeviceExtension,
NumVgaAccessRanges,
VgaAccessRanges);
}
}
else if (PnpFlags & REPORT_DEVICE)
{
ULONG_PTR emptyList = 0;
BOOLEAN conflict;
PDEVICE_OBJECT attachedTo;
ASSERT (HwInitializationData->AdapterInterfaceType != PCIBus);
//
// Release the resource we put in the resourcemap (if any).
//
IoReportResourceUsage(&VideoClassName,
DriverObject,
NULL,
0L,
deviceObject,
(PCM_RESOURCE_LIST) &emptyList,
sizeof(ULONG_PTR),
FALSE,
&conflict);
pVideoDebugPrint((Info, "VIDEOPRT: Reporting new device to the system.\n"));
pVideoDebugPrint((Info, "VIDEOPRT: ResourceList...\n"));
if (fdoExtension->ResourceList) {
#if DBG
DumpResourceList(fdoExtension->ResourceList);
#endif
} else {
pVideoDebugPrint((Info, "\tnone.\n"));
}
ntStatus = IoReportDetectedDevice(
DriverObject,
InterfaceTypeUndefined,
-1,
-1,
fdoExtension->ResourceList,
NULL,
FALSE,
&PnPDeviceObject);
pVideoDebugPrint((Info, "VIDEOPRT: New device reported ntStatus %08lx\n", ntStatus));
ASSERT(NT_SUCCESS(ntStatus));
//
// Now we can release the memory used to hold
// the resources pointed to by ResourceList.
//
if (fdoExtension->ResourceList) {
ExFreePool(fdoExtension->ResourceList);
fdoExtension->ResourceList = NULL;
}
attachedTo = IoAttachDeviceToDeviceStack(deviceObject,
PnPDeviceObject);
ASSERT(attachedTo != NULL);
fdoExtension->AttachedDeviceObject = attachedTo;
fdoExtension->PhysicalDeviceObject = PnPDeviceObject;
//
// Clear the ReportDevice value in the registry so
// that we don't try to report the device again in
// the future.
//
UpdateRegValue(Argument2, L"ReportDevice", FALSE);
}
} while (nextMiniport);
//
// We finished finding all the device on the current bus
// Go on to the next bus.
//
busNumber++;
}
//
// If at least one device loaded, then return success, otherwise return
// the last available error message.
//
if (registryIndex > 0) {
return STATUS_SUCCESS;
} else {
return ((ULONG)ntStatus);
}
}
NTSTATUS
VideoPortFindAdapter(
IN PDRIVER_OBJECT DriverObject,
IN PVOID Argument2,
IN PVIDEO_HW_INITIALIZATION_DATA HwInitializationData,
IN PVOID HwContext,
PDEVICE_OBJECT DeviceObject,
PUCHAR nextMiniport
)
{
NTSTATUS status;
PVOID vgaDE = VgaHwDeviceExtension;
PFDO_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
POWER_STATE state;
//
// During boot of upgrade install, only let VGA,
// boot video drivers start. Other types of drivers don't get
// a chance to start until after the vga or a boot driver tries'
// to start.
//
// The logic relies on the fact that today PNP drivers try to
// start before legacy drivers (including our system vga driver).a3844
//
// All other drivers are disabled so we have a chance of
// 1) booting the machine
// 2) installing the PnP drivers
//
if ((VpSetupType == SETUPTYPE_UPGRADE) &&
((fdoExtension->Flags & (BOOT_DRIVER | VGA_DRIVER)) == 0) &&
(VpSetupAllowDriversToStart == FALSE))
{
status = STATUS_NO_SUCH_DEVICE;
}
else
{
//
// If we get here during setup we may be trying to start the
// vga driver. As soon as it is started we will allow othere
// devices to start.
//
VpSetupAllowDriversToStart = TRUE;
//
// Allow PNP adapters to start so that we can enumerate their
// children. But don't let IRP_MJ_CREATE succeed, so GDI
// won't try to use the device during gui mode setup.
//
if ((VpSetupType == SETUPTYPE_UPGRADE) &&
(fdoExtension->Flags & PNP_ENABLED)) {
fdoExtension->Flags |= UPGRADE_FAIL_HWINIT;
}
//
// If the VGA driver has the VGA resources, unclaim them temporarily
//
if (vgaDE) {
pVideoDebugPrint((Info, "VIDEOPRT: Freeing VGA resources\n"));
VpReleaseResources(GET_FDO_EXT(vgaDE));
}
status = VideoPortFindAdapter2(DriverObject,
Argument2,
HwInitializationData,
HwContext,
DeviceObject,
nextMiniport);
//
// Try to reclaim the vga ports. FYI, may not get them
// back if the new driver claimed them.
//
if (vgaDE) {
pVideoDebugPrint((Info, "VIDEOPRT: Try to allocate back vga resources.\n"));
if (((DeviceObject == DeviceOwningVga) && NT_SUCCESS(status)) ||
VideoPortVerifyAccessRanges(vgaDE,
NumVgaAccessRanges,
VgaAccessRanges) != NO_ERROR) {
//
// We couldn't reclaim the vga resources, so another driver
// must have claimed them. Lets release our resources.
//
if (VgaAccessRanges) {
ExFreePool(VgaAccessRanges);
}
VgaHwDeviceExtension = NULL;
VgaAccessRanges = NULL;
NumVgaAccessRanges = 0;
pVideoDebugPrint((Warn, "VIDEOPRT: Resource re-allocation failed.\n"));
}
}
}
if (NT_SUCCESS(status))
{
//
// Initialize Power stuff.
// Set the devices current power state.
// NOTE - we assume the device is on at this point in time ...
//
fdoExtension->DevicePowerState = PowerDeviceD0;
state.DeviceState = fdoExtension->DevicePowerState;
state = PoSetPowerState(DeviceObject,
DevicePowerState,
state);
//
// Register and enable the interface
//
VpEnableAdapterInterface((PDEVICE_SPECIFIC_EXTENSION)
(fdoExtension + 1));
//
// Mark this object as supporting buffered I/O so that the I/O system
// will only supply simple buffers in IRPs.
//
// Set and clear the two power fields to ensure we only get called
// as passive level to do power management operations.
//
// Finally, tell the system we are done with Device Initialization
//
DeviceObject->Flags |= DO_BUFFERED_IO | DO_POWER_PAGABLE;
DeviceObject->Flags &= ~(DO_DEVICE_INITIALIZING | DO_POWER_INRUSH);
fdoExtension->Flags |= FINDADAPTER_SUCCEEDED;
//
// Track the number of started devices (don't count mirroring drivers)
//
if (!IsMirrorDriver(fdoExtension)) {
NumDevicesStarted++;
}
}
return status;
}
NTSTATUS
VideoPortFindAdapter2(
IN PDRIVER_OBJECT DriverObject,
IN PVOID Argument2,
IN PVIDEO_HW_INITIALIZATION_DATA HwInitializationData,
IN PVOID HwContext,
PDEVICE_OBJECT DeviceObject,
PUCHAR nextMiniport
)
{
WCHAR deviceNameBuffer[STRING_LENGTH];
POBJECT_NAME_INFORMATION deviceName;
ULONG strLength;
NTSTATUS ntStatus;
WCHAR deviceSubpathBuffer[STRING_LENGTH];
UNICODE_STRING deviceSubpathUnicodeString;
WCHAR deviceLinkBuffer[STRING_LENGTH];
UNICODE_STRING deviceLinkUnicodeString;
KAFFINITY affinity;
PVIDEO_PORT_CONFIG_INFO miniportConfigInfo = NULL;
PDEVICE_OBJECT deviceObject;
PFDO_EXTENSION fdoExtension;
VP_STATUS findAdapterStatus = ERROR_DEV_NOT_EXIST;
ULONG driverKeySize;
PWSTR driverKeyName = NULL;
BOOLEAN symbolicLinkCreated = FALSE;
ULONG MaxObjectNumber;
PDEVICE_OBJECT pdo;
BOOLEAN ChildObject=FALSE;
PDEVICE_SPECIFIC_EXTENSION DoSpecificExtension;
ntStatus = STATUS_NO_SUCH_DEVICE;
deviceObject = DeviceObject;
fdoExtension = deviceObject->DeviceExtension;
DoSpecificExtension = (PVOID)(fdoExtension + 1);
pdo = fdoExtension->PhysicalDeviceObject;
deviceName = (POBJECT_NAME_INFORMATION) deviceNameBuffer;
ObQueryNameString(deviceObject,
deviceName,
STRING_LENGTH * sizeof(WCHAR),
&strLength);
//
// Allocate the buffer in which the miniport driver will store all the
// configuration information.
//
miniportConfigInfo = (PVIDEO_PORT_CONFIG_INFO)
ExAllocatePoolWithTag(PagedPool | POOL_COLD_ALLOCATION,
sizeof(VIDEO_PORT_CONFIG_INFO),
VP_TAG);
if (miniportConfigInfo == NULL) {
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
goto EndOfInitialization;
}
RtlZeroMemory((PVOID) miniportConfigInfo,
sizeof(VIDEO_PORT_CONFIG_INFO));
miniportConfigInfo->Length = sizeof(VIDEO_PORT_CONFIG_INFO);
//
// Put in the BusType specified within the HW_INITIALIZATION_DATA
// structure by the miniport and the bus number inthe miniport config info.
//
miniportConfigInfo->SystemIoBusNumber = fdoExtension->SystemIoBusNumber;
miniportConfigInfo->AdapterInterfaceType = fdoExtension->AdapterInterfaceType;
//
// Initialize the pointer to VpGetProcAddress.
//
miniportConfigInfo->VideoPortGetProcAddress = VpGetProcAddress;
//
// Initialize the type of interrupt based on the bus type.
//
switch (miniportConfigInfo->AdapterInterfaceType) {
case Internal:
case MicroChannel:
case PCIBus:
miniportConfigInfo->InterruptMode = LevelSensitive;
break;
default:
miniportConfigInfo->InterruptMode = Latched;
break;
}
//
// Set up device extension pointers and sizes
//
fdoExtension->HwDeviceExtension = (PVOID)((ULONG_PTR)(fdoExtension) +
sizeof(FDO_EXTENSION) + sizeof(DEVICE_SPECIFIC_EXTENSION));
fdoExtension->HwDeviceExtensionSize =
HwInitializationData->HwDeviceExtensionSize;
fdoExtension->MiniportConfigInfo = miniportConfigInfo;
//
// Save the dependent driver routines in the device extension.
//
fdoExtension->HwFindAdapter = HwInitializationData->HwFindAdapter;
fdoExtension->HwInitialize = HwInitializationData->HwInitialize;
fdoExtension->HwInterrupt = HwInitializationData->HwInterrupt;
fdoExtension->HwStartIO = HwInitializationData->HwStartIO;
if (HwInitializationData->HwInitDataSize >
FIELD_OFFSET(VIDEO_HW_INITIALIZATION_DATA, HwLegacyResourceCount)) {
fdoExtension->HwLegacyResourceList = HwInitializationData->HwLegacyResourceList;
fdoExtension->HwLegacyResourceCount = HwInitializationData->HwLegacyResourceCount;
}
if (HwInitializationData->HwInitDataSize >
FIELD_OFFSET(VIDEO_HW_INITIALIZATION_DATA, AllowEarlyEnumeration)) {
fdoExtension->AllowEarlyEnumeration = HwInitializationData->AllowEarlyEnumeration;
}
//
// Create the name we will be storing in the \DeviceMap.
// This name is a PWSTR, not a unicode string
// This is the name of the driver with an appended device number
//
if (!NT_SUCCESS(pVideoPortCreateDeviceName(L"\\Device",
HwInitializationData->StartingDeviceNumber,
&deviceSubpathUnicodeString,
deviceSubpathBuffer))) {
pVideoDebugPrint((Error, "VIDEOPRT: VideoPortFindAdapter: Could not create device subpath number\n"));
goto EndOfInitialization;
}
DoSpecificExtension->DriverOldRegistryPathLength =
((PUNICODE_STRING)Argument2)->Length +
deviceSubpathUnicodeString.Length;
driverKeySize =
DoSpecificExtension->DriverOldRegistryPathLength +
2 * sizeof(UNICODE_NULL);
if ( (driverKeyName = (PWSTR) ExAllocatePoolWithTag(PagedPool,
driverKeySize,
VP_TAG) ) == NULL) {
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
goto EndOfInitialization;
}
RtlMoveMemory(driverKeyName,
((PUNICODE_STRING)Argument2)->Buffer,
((PUNICODE_STRING)Argument2)->Length);
RtlMoveMemory((PWSTR)( (ULONG_PTR)driverKeyName +
((PUNICODE_STRING)Argument2)->Length ),
deviceSubpathBuffer,
deviceSubpathUnicodeString.Length);
//
// Put two NULLs at the end so we can play around with the string later.
//
*((PWSTR) ((ULONG_PTR)driverKeyName +
DoSpecificExtension->DriverOldRegistryPathLength))
= UNICODE_NULL;
*((PWSTR) ((ULONG_PTR)driverKeyName +
DoSpecificExtension->DriverOldRegistryPathLength
+ sizeof(UNICODE_NULL))) = UNICODE_NULL;
//
// There is a bug in Lotus Screen Cam where it will only work if our
// reg path is \REGISTRY\Machine\System not \REGISTRY\MACHINE\SYSTEM.
// so replace the appropriate strings.
//
if (wcsstr(driverKeyName, L"MACHINE")) {
wcsncpy(wcsstr(driverKeyName, L"MACHINE"), L"Machine", sizeof("Machine")-1);
}
if (wcsstr(driverKeyName, L"SYSTEM")) {
wcsncpy(wcsstr(driverKeyName, L"SYSTEM"), L"System", sizeof("System")-1);
}
//
// Store the old key
//
DoSpecificExtension->DriverOldRegistryPath = driverKeyName;
//
// Store the new key
// If this is not a Whistler driver, then use the old key.
//
if (EnableNewRegistryKey) {
#if _X86_
if (HwInitializationData->HwInitDataSize > SIZE_OF_W2K_VIDEO_HW_INITIALIZATION_DATA)
#endif // _X86_
VpEnableNewRegistryKey(fdoExtension,
DoSpecificExtension,
(PUNICODE_STRING)Argument2,
fdoExtension->RegistryIndex);
}
//
// Store the path name of the location of the driver in the registry.
//
if (DoSpecificExtension->DriverNewRegistryPath != NULL) {
DoSpecificExtension->DriverRegistryPath =
DoSpecificExtension->DriverNewRegistryPath;
DoSpecificExtension->DriverRegistryPathLength =
DoSpecificExtension->DriverNewRegistryPathLength;
} else {
DoSpecificExtension->DriverRegistryPath =
DoSpecificExtension->DriverOldRegistryPath;
DoSpecificExtension->DriverRegistryPathLength =
DoSpecificExtension->DriverOldRegistryPathLength;
}
miniportConfigInfo->DriverRegistryPath = DoSpecificExtension->DriverRegistryPath;
//
// Let the driver know how much system memory is present.
//
miniportConfigInfo->SystemMemorySize = VpSystemMemorySize;
//
// Initialize the DPC object used for error logging.
//
KeInitializeDpc(&fdoExtension->ErrorLogDpc,
pVideoPortLogErrorEntryDPC,
deviceObject);
//
// If the machine is using a Intel 450NX PCIset with a
// 82451NX Memory & I/O Controller (MIOC) then we must
// disable write combining to work around a bug in the
// chipset.
//
// We also want to disable USWC on the Compaq fiat
// chipset.
//
if (EnableUSWC) {
if ((VideoPortCheckForDeviceExistence(fdoExtension->HwDeviceExtension, 0x8086, 0x84CA, 0, 0, 0, 0)) ||
(VideoPortCheckForDeviceExistence(fdoExtension->HwDeviceExtension, 0x0E11, 0x6010, 0, 0, 0, 0)) ||
(VideoPortCheckForDeviceExistence(fdoExtension->HwDeviceExtension, 0x1166, 0x0009, 0, 0, 0, 0))) {
pVideoDebugPrint((Warn, "VIDEOPRT: USWC disabled due to to MIOC bug.\n"));
EnableUSWC = FALSE;
}
//
// Disable USWC on HPs 6 way box.
//
if (VideoPortCheckForDeviceExistence(fdoExtension->HwDeviceExtension, 0x1166, 0x0008, 0, 0, 0, 0) &&
(VideoPortCheckForDeviceExistence(fdoExtension->HwDeviceExtension, 0x103C, 0x1219, 0, 0, 0, 0) ||
VideoPortCheckForDeviceExistence(fdoExtension->HwDeviceExtension, 0x103C, 0x121A, 0, 0, 0, 0))) {
pVideoDebugPrint((Warn, "USWC disabled due to to RCC USWC bug on HP 6-way system.\n"));
EnableUSWC = FALSE;
}
}
//
// Turn on the debug level based on the miniport driver entry
//
VideoPortGetRegistryParameters(fdoExtension->HwDeviceExtension,
L"VideoDebugLevel",
FALSE,
VpRegistryCallback,
&VideoDebugLevel);
if (VpAllowFindAdapter(fdoExtension)) {
ACQUIRE_DEVICE_LOCK(fdoExtension);
//
// Notify the boot driver that we will be accessing the display
// hardware.
//
VpEnableDisplay(fdoExtension, FALSE);
findAdapterStatus =
fdoExtension->HwFindAdapter(fdoExtension->HwDeviceExtension,
HwContext,
NULL,
miniportConfigInfo,
nextMiniport);
VpEnableDisplay(fdoExtension, TRUE);
RELEASE_DEVICE_LOCK(fdoExtension);
}
//
// If the adapter is not found, display an error.
//
if (findAdapterStatus != NO_ERROR) {
pVideoDebugPrint((Warn, "VIDEOPRT: VideoPortFindAdapter: Find adapter failed\n"));
ntStatus = STATUS_UNSUCCESSFUL;
goto EndOfInitialization;
}
//
// Store the emulator data in the device extension so we can use it
// later.
//
fdoExtension->NumEmulatorAccessEntries =
miniportConfigInfo->NumEmulatorAccessEntries;
fdoExtension->EmulatorAccessEntries =
miniportConfigInfo->EmulatorAccessEntries;
fdoExtension->EmulatorAccessEntriesContext =
miniportConfigInfo->EmulatorAccessEntriesContext;
fdoExtension->VdmPhysicalVideoMemoryAddress =
miniportConfigInfo->VdmPhysicalVideoMemoryAddress;
fdoExtension->VdmPhysicalVideoMemoryLength =
miniportConfigInfo->VdmPhysicalVideoMemoryLength;
//
// Store the required information in the device extension for later use.
//
fdoExtension->HardwareStateSize =
miniportConfigInfo->HardwareStateSize;
//
// If the device supplies an interrupt service routine, we must
// set up all the structures to support interrupts. Otherwise,
// they can be ignored.
//
if (fdoExtension->HwInterrupt) {
if ((miniportConfigInfo->BusInterruptLevel != 0) ||
(miniportConfigInfo->BusInterruptVector != 0)) {
#if defined(NO_LEGACY_DRIVERS)
affinity = fdoExtension->InterruptAffinity;
#else
if (fdoExtension->Flags & LEGACY_DRIVER) {
//
// Note: the spinlock for the interrupt object is created
// internally by the IoConnectInterrupt() call. It is also
// used internally by KeSynchronizeExecution.
//
fdoExtension->InterruptVector =
HalGetInterruptVector(fdoExtension->AdapterInterfaceType,
fdoExtension->SystemIoBusNumber,
miniportConfigInfo->BusInterruptLevel,
miniportConfigInfo->BusInterruptVector,
&fdoExtension->InterruptIrql,
&affinity);
} else {
affinity = fdoExtension->InterruptAffinity;
}
#endif
fdoExtension->InterruptMode = miniportConfigInfo->InterruptMode;
fdoExtension->InterruptsEnabled = TRUE;
ntStatus = IoConnectInterrupt(&fdoExtension->InterruptObject,
(PKSERVICE_ROUTINE) pVideoPortInterrupt,
deviceObject,
NULL,
fdoExtension->InterruptVector,
fdoExtension->InterruptIrql,
fdoExtension->InterruptIrql,
fdoExtension->InterruptMode,
(BOOLEAN) ((miniportConfigInfo->InterruptMode ==
LevelSensitive) ? TRUE : FALSE),
affinity,
FALSE);
if (!NT_SUCCESS(ntStatus)) {
pVideoDebugPrint((Error, "VIDEOPRT: VideoPortFindAdapter: Can't connect interrupt\n"));
goto EndOfInitialization;
}
} else {
pVideoDebugPrint((Warn, "VIDEOPRT: Warning: No interrupt resources assigned to this device.\n"));
}
} else {
fdoExtension->HwInterrupt = NULL;
}
//
// Initialize DPC Support
//
KeInitializeDpc(&fdoExtension->Dpc,
pVideoPortDpcDispatcher,
fdoExtension->HwDeviceExtension);
//
// DMA support
//
if (HwInitializationData->HwInitDataSize >
FIELD_OFFSET(VIDEO_HW_INITIALIZATION_DATA, HwStartDma)) {
fdoExtension->HwStartDma = HwInitializationData->HwStartDma;
//
// Determine if a Dma Adapter must be allocated.
//
if (fdoExtension->DmaAdapterObject == NULL &&
(miniportConfigInfo->Master ||
miniportConfigInfo->DmaChannel != 0)) {
DEVICE_DESCRIPTION deviceDescription;
ULONG numberOfMapRegisters;
//
// Get the adapter object for this card.
//
RtlZeroMemory(&deviceDescription, sizeof(deviceDescription));
deviceDescription.Version = DEVICE_DESCRIPTION_VERSION;
deviceDescription.DmaChannel = miniportConfigInfo->DmaChannel;
deviceDescription.BusNumber = miniportConfigInfo->SystemIoBusNumber;
deviceDescription.DmaWidth = miniportConfigInfo->DmaWidth;
deviceDescription.DmaSpeed = miniportConfigInfo->DmaSpeed;
deviceDescription.ScatterGather = miniportConfigInfo->ScatterGather;
deviceDescription.Master = miniportConfigInfo->Master;
deviceDescription.DmaPort = miniportConfigInfo->DmaPort;
deviceDescription.AutoInitialize = FALSE;
deviceDescription.DemandMode = miniportConfigInfo->DemandMode;
deviceDescription.MaximumLength = miniportConfigInfo->MaximumTransferLength;
deviceDescription.InterfaceType = fdoExtension->AdapterInterfaceType;
fdoExtension->DmaAdapterObject =
IoGetDmaAdapter(fdoExtension->PhysicalDeviceObject,
&deviceDescription,
&numberOfMapRegisters);
ASSERT(fdoExtension->DmaAdapterObject);
}
} // end if HW_DATA_SIZE > ... HWStartDma
//
// New, Optional.
// Setup the timer if it is specified by a driver.
//
if (HwInitializationData->HwInitDataSize >
FIELD_OFFSET(VIDEO_HW_INITIALIZATION_DATA, HwTimer)){
fdoExtension->HwTimer = HwInitializationData->HwTimer;
if (fdoExtension->HwTimer) {
ntStatus = IoInitializeTimer(deviceObject,
pVideoPortHwTimer,
NULL);
//
// If we fail forget about the timer !
//
if (!NT_SUCCESS(ntStatus)) {
ASSERT(FALSE);
fdoExtension->HwTimer = NULL;
}
}
}
//
// New, Optional.
// Reset Hw function.
//
if (HwInitializationData->HwInitDataSize >
FIELD_OFFSET(VIDEO_HW_INITIALIZATION_DATA, HwResetHw)) {
ULONG iReset;
for (iReset=0; iReset<6; iReset++) {
if (HwResetHw[iReset].ResetFunction == NULL) {
HwResetHw[iReset].ResetFunction = HwInitializationData->HwResetHw;
HwResetHw[iReset].HwDeviceExtension = fdoExtension->HwDeviceExtension;
break;
}
}
}
//
// The FdoList is for debugging purpose
//
{
ULONG i;
for(i = 0; i < 8; i++) {
if(FdoList[i] == NULL) {
FdoList[i] = fdoExtension;
break;
}
}
}
fdoExtension->NextFdoExtension = FdoHead;
FdoHead = fdoExtension;
//
// NOTE:
//
// We only want to reinitialize the device once the Boot sequence has
// been completed and the HAL does not need to access the device again.
// So the initialization entry point will be called when the device is
// opened.
//
if (!NT_SUCCESS(pVideoPortCreateDeviceName(L"\\DosDevices\\DISPLAY",
DoSpecificExtension->DeviceNumber + 1,
&deviceLinkUnicodeString,
deviceLinkBuffer))) {
pVideoDebugPrint((Error, "VIDEOPRT: VideoPortFindAdapter: Could not create device subpath number\n"));
goto EndOfInitialization;
}
ntStatus = IoCreateSymbolicLink(&deviceLinkUnicodeString,
&deviceName->Name);
if (!NT_SUCCESS(ntStatus)) {
pVideoDebugPrint((Error, "VIDEOPRT: VideoPortFindAdapter: SymbolicLink Creation failed\n"));
goto EndOfInitialization;
}
symbolicLinkCreated = TRUE;
//
// Once initialization is finished, load the required information in the
// registry so that the appropriate display drivers can be loaded.
//
ntStatus = RtlWriteRegistryValue(RTL_REGISTRY_DEVICEMAP,
VideoClassString,
deviceName->Name.Buffer,
REG_SZ,
DoSpecificExtension->DriverRegistryPath,
DoSpecificExtension->DriverRegistryPathLength +
sizeof(UNICODE_NULL));
if (!NT_SUCCESS(ntStatus)) {
pVideoDebugPrint((Error, "VIDEOPRT: VideoPortFindAdapter: Could not store name in DeviceMap\n"));
}
if (fdoExtension->Flags & LEGACY_DRIVER) {
//
// If we successfully found a legacy driver, increment the
// global device number.
//
VideoDeviceNumber++;
}
//
// Tell win32k how many objects to try to open
//
MaxObjectNumber = VideoDeviceNumber - 1;
ntStatus = RtlWriteRegistryValue(RTL_REGISTRY_DEVICEMAP,
VideoClassString,
L"MaxObjectNumber",
REG_DWORD,
&MaxObjectNumber,
sizeof(ULONG));
if (!NT_SUCCESS(ntStatus)) {
pVideoDebugPrint((Error, "VIDEOPRT: VideoPortFindAdapter: Could not store name in DeviceMap\n"));
} else {
pVideoDebugPrint((Info, "VIDEOPRT: VideoPortFindAdapter: %d is stored in MaxObjectNumber of DeviceMap\n",
MaxObjectNumber));
}
//
// Save the function pointers to the new 5.0 miniport driver callbacks.
//
if (HwInitializationData->HwInitDataSize >
FIELD_OFFSET(VIDEO_HW_INITIALIZATION_DATA, HwQueryInterface)) {
fdoExtension->HwSetPowerState = HwInitializationData->HwSetPowerState;
fdoExtension->HwGetPowerState = HwInitializationData->HwGetPowerState;
fdoExtension->HwQueryInterface = HwInitializationData->HwQueryInterface;
if (!ChildObject)
{
fdoExtension->HwGetVideoChildDescriptor = HwInitializationData->HwGetVideoChildDescriptor;
}
}
//
// Check if the minitor should always be D0 or D3
//
{
ULONG OverrideMonitorPower = 0;
VideoPortGetRegistryParameters(fdoExtension->HwDeviceExtension,
L"OverrideMonitorPower",
FALSE,
VpRegistryCallback,
&OverrideMonitorPower);
fdoExtension->OverrideMonitorPower = (OverrideMonitorPower != 0);
}
EndOfInitialization:
//
// If we are doing detection, then don't save all of these objects.
// We just want to see if the driver would load or not
//
if ( (fdoExtension->Flags & LEGACY_DETECT) ||
(!NT_SUCCESS(ntStatus)) )
{
//
// Free the miniport config info buffer.
//
if (miniportConfigInfo) {
ExFreePool(miniportConfigInfo);
}
//
// Free the rom image if we grabbed one.
//
if (fdoExtension->RomImage) {
ExFreePool(fdoExtension->RomImage);
fdoExtension->RomImage = NULL;
}
//
// Release the resource we put in the resourcemap (if any).
//
if ((fdoExtension->Flags & LEGACY_DETECT) ||
(findAdapterStatus != NO_ERROR)) {
ULONG_PTR emptyList = 0;
BOOLEAN conflict;
IoReportResourceUsage(&VideoClassName,
DriverObject,
NULL,
0L,
deviceObject,
(PCM_RESOURCE_LIST) &emptyList, // an empty resource list
sizeof(ULONG_PTR),
FALSE,
&conflict);
}
//
// These are the things we want to delete if they were created and
// the initialization *FAILED* at a later time.
//
if (fdoExtension->InterruptObject) {
IoDisconnectInterrupt(fdoExtension->InterruptObject);
}
if (driverKeyName) {
ExFreePool(driverKeyName);
DoSpecificExtension->DriverOldRegistryPath = NULL;
}
if (DoSpecificExtension->DriverNewRegistryPath) {
ExFreePool(DoSpecificExtension->DriverNewRegistryPath);
DoSpecificExtension->DriverNewRegistryPath = NULL;
}
DoSpecificExtension->DriverRegistryPath = NULL;
if (symbolicLinkCreated) {
IoDeleteSymbolicLink(&deviceLinkUnicodeString);
}
//
// Free up any memory mapped in by the miniport using
// VideoPort GetDeviceBase.
//
while (fdoExtension->MappedAddressList != NULL)
{
pVideoDebugPrint((Warn, "VIDEOPRT: VideoPortFindAdapter: unfreed address %08lx, physical %08lx, size %08lx\n",
fdoExtension->MappedAddressList->MappedAddress,
fdoExtension->MappedAddressList->PhysicalAddress.LowPart,
fdoExtension->MappedAddressList->NumberOfUchars));
pVideoDebugPrint((Warn, "VIDEOPRT: VideoPortFindAdapter: unfreed refcount %d, unmapping %d\n\n",
fdoExtension->MappedAddressList->RefCount,
fdoExtension->MappedAddressList->bNeedsUnmapping));
VideoPortFreeDeviceBase(fdoExtension->HwDeviceExtension,
fdoExtension->MappedAddressList->MappedAddress);
}
//
// Remove any HwResetHw function we may have added for this device.
//
if (HwInitializationData->HwInitDataSize >
FIELD_OFFSET(VIDEO_HW_INITIALIZATION_DATA, HwResetHw)) {
ULONG iReset;
for (iReset=0; iReset<6; iReset++) {
if (HwResetHw[iReset].HwDeviceExtension ==
fdoExtension->HwDeviceExtension) {
HwResetHw[iReset].ResetFunction = NULL;
break;
}
}
}
} else {
HwInitializationData->StartingDeviceNumber++;
}
return ntStatus;
}
BOOLEAN
pVideoPortInterrupt(
IN PKINTERRUPT Interrupt,
IN PDEVICE_OBJECT DeviceObject
)
/*++
Routine Description:
This function is the main interrupt service routine. If finds which
miniport driver the interrupt was for and forwards it.
Arguments:
Interrupt -
DeviceObject -
Return Value:
Returns TRUE if the interrupt was expected.
--*/
{
PFDO_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
BOOLEAN bRet;
UNREFERENCED_PARAMETER(Interrupt);
//
// If there is no interrupt routine, fail the assertion
//
ASSERT (fdoExtension->HwInterrupt);
if (fdoExtension->InterruptsEnabled) {
bRet = fdoExtension->HwInterrupt(fdoExtension->HwDeviceExtension);
} else {
bRet = FALSE; // this device did not handle the interrupt
}
return bRet;
} // pVideoPortInterrupt()
VOID
VideoPortLogError(
IN PVOID HwDeviceExtension,
IN PVIDEO_REQUEST_PACKET Vrp OPTIONAL,
IN VP_STATUS ErrorCode,
IN ULONG UniqueId
)
/*++
Routine Description:
This routine saves the error log information so it can be processed at
any IRQL.
Arguments:
HwDeviceExtension - Supplies the HBA miniport driver's adapter data storage.
Vrp - Supplies an optional pointer to a video request packet if there is
one.
ErrorCode - Supplies an error code indicating the type of error.
UniqueId - Supplies a unique identifier for the error.
Return Value:
None.
--*/
{
VP_ERROR_LOG_ENTRY errorLogEntry;
//
// Save the information in a local errorLogEntry structure.
//
errorLogEntry.DeviceExtension = GET_FDO_EXT(HwDeviceExtension);
if (Vrp != NULL) {
errorLogEntry.IoControlCode = Vrp->IoControlCode;
} else {
errorLogEntry.IoControlCode = 0;
}
errorLogEntry.ErrorCode = ErrorCode;
errorLogEntry.UniqueId = UniqueId;
//
// Call the sync routine so we are synchronized when writting in
// the device extension.
//
pVideoPortSynchronizeExecution(HwDeviceExtension,
VpMediumPriority,
pVideoPortLogErrorEntry,
&errorLogEntry);
return;
} // end VideoPortLogError()
BOOLEAN
pVideoPortLogErrorEntry(
IN PVOID Context
)
/*++
Routine Description:
This function is the synchronized LogError functions.
Arguments:
Context - Context value used here as the VP_ERROR_LOG_ENTRY for this
particular error
Return Value:
None.
--*/
{
PVP_ERROR_LOG_ENTRY logEntry = Context;
PFDO_EXTENSION fdoExtension = logEntry->DeviceExtension;
//
// If the error log entry is already full, then dump the error.
//
if (fdoExtension->InterruptFlags & VP_ERROR_LOGGED) {
pVideoDebugPrint((Trace, "VIDEOPRT: VideoPortLogError: Dumping video error log packet.\n"));
pVideoDebugPrint((Info, "\tControlCode = %x, ErrorCode = %x, UniqueId = %x.\n",
logEntry->IoControlCode, logEntry->ErrorCode,
logEntry->UniqueId));
return TRUE;
}
//
// Indicate that the error log entry is in use.
//
fdoExtension->InterruptFlags |= VP_ERROR_LOGGED;
fdoExtension->ErrorLogEntry = *logEntry;
//
// Now queue a DPC so we can process the error.
//
KeInsertQueueDpc(&fdoExtension->ErrorLogDpc,
NULL,
NULL);
return TRUE;
} // end pVideoPortLogErrorEntry();
VOID
pVideoPortLogErrorEntryDPC(
IN PKDPC Dpc,
IN PVOID DeferredContext,
IN PVOID SystemArgument1,
IN PVOID SystemArgument2
)
/*++
Routine Description:
This function allocates an I/O error log record, fills it in and writes it
to the I/O error log.
Arguments:
Dpc - Pointer to the DPC object.
DeferredContext - Context parameter that was passed to the DPC
initialization routine. It contains a pointer to the deviceObject.
SystemArgument1 - Unused.
SystemArgument2 - Unused.
Return Value:
None.
--*/
{
PDEVICE_OBJECT DeviceObject = DeferredContext;
PFDO_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
PIO_ERROR_LOG_PACKET errorLogPacket;
errorLogPacket = (PIO_ERROR_LOG_PACKET)
IoAllocateErrorLogEntry(DeviceObject,
sizeof(IO_ERROR_LOG_PACKET) + sizeof(ULONG));
if (errorLogPacket != NULL) {
errorLogPacket->MajorFunctionCode = IRP_MJ_DEVICE_CONTROL;
errorLogPacket->RetryCount = 0;
errorLogPacket->NumberOfStrings = 0;
errorLogPacket->StringOffset = 0;
errorLogPacket->EventCategory = 0;
//
// Translate the miniport error code into the NT I\O driver.
//
switch (fdoExtension->ErrorLogEntry.ErrorCode) {
case ERROR_INVALID_FUNCTION:
case ERROR_INVALID_PARAMETER:
errorLogPacket->ErrorCode = IO_ERR_INVALID_REQUEST;
break;
case ERROR_NOT_ENOUGH_MEMORY:
case ERROR_INSUFFICIENT_BUFFER:
errorLogPacket->ErrorCode = IO_ERR_INSUFFICIENT_RESOURCES;
break;
case ERROR_DEV_NOT_EXIST:
errorLogPacket->ErrorCode = IO_ERR_CONFIGURATION_ERROR;
break;
case ERROR_IO_PENDING:
ASSERT(FALSE);
case ERROR_MORE_DATA:
case NO_ERROR:
errorLogPacket->ErrorCode = 0;
break;
//
// If it is another error code, than assume it is private to the
// driver and just pass as-is.
//
default:
errorLogPacket->ErrorCode =
fdoExtension->ErrorLogEntry.ErrorCode;
break;
}
errorLogPacket->UniqueErrorValue =
fdoExtension->ErrorLogEntry.UniqueId;
errorLogPacket->FinalStatus = STATUS_SUCCESS;
errorLogPacket->SequenceNumber = 0;
errorLogPacket->IoControlCode =
fdoExtension->ErrorLogEntry.IoControlCode;
errorLogPacket->DumpDataSize = sizeof(ULONG);
errorLogPacket->DumpData[0] =
fdoExtension->ErrorLogEntry.ErrorCode;
IoWriteErrorLogEntry(errorLogPacket);
}
fdoExtension->InterruptFlags &= ~VP_ERROR_LOGGED;
} // end pVideoPortLogErrorEntry();
VOID
pVideoPortMapToNtStatus(
IN PSTATUS_BLOCK StatusBlock
)
/*++
Routine Description:
This function maps a Win32 error code to an NT error code, making sure
the inverse translation will map back to the original status code.
Arguments:
StatusBlock - Pointer to the status block
Return Value:
None.
--*/
{
PNTSTATUS status = &StatusBlock->Status;
switch (*status) {
case ERROR_INVALID_FUNCTION:
*status = STATUS_NOT_IMPLEMENTED;
break;
case ERROR_NOT_ENOUGH_MEMORY:
*status = STATUS_INSUFFICIENT_RESOURCES;
break;
case ERROR_INVALID_PARAMETER:
*status = STATUS_INVALID_PARAMETER;
break;
case ERROR_INSUFFICIENT_BUFFER:
*status = STATUS_BUFFER_TOO_SMALL;
//
// Make sure we zero out the information block if we get an
// insufficient buffer.
//
StatusBlock->Information = 0;
break;
case ERROR_MORE_DATA:
*status = STATUS_BUFFER_OVERFLOW;
break;
case ERROR_DEV_NOT_EXIST:
*status = STATUS_DEVICE_DOES_NOT_EXIST;
break;
case ERROR_IO_PENDING:
ASSERT(FALSE);
// Fall through.
case NO_ERROR:
*status = STATUS_SUCCESS;
break;
default:
pVideoDebugPrint((Error, "VIDEOPRT: Invalid return value from HwStartIo!\n"));
ASSERT(FALSE);
//
// Since the driver did not see fit to follow the
// rules about returning correct error codes. Videoprt will do it for
// them.
//
*status = STATUS_UNSUCCESSFUL;
break;
}
return;
} // end pVideoPortMapToNtStatus()
NTSTATUS
pVideoPortMapUserPhysicalMem(
IN PFDO_EXTENSION FdoExtension,
IN HANDLE ProcessHandle OPTIONAL,
IN PHYSICAL_ADDRESS PhysicalAddress,
IN OUT PULONG Length,
IN OUT PULONG InIoSpace,
IN OUT PVOID *VirtualAddress
)
/*++
Routine Description:
This function maps a view of a block of physical memory into a process'
virtual address space.
Arguments:
HwDeviceExtension - Pointer to the miniport driver's device extension.
ProcessHandle - Optional handle to the process into which the memory must
be mapped.
PhysicalAddress - Offset from the beginning of physical memory, in bytes.
Length - Pointer to a variable that will receive that actual size in
bytes of the view. The length is rounded to a page boundary. THe
length may not be zero.
InIoSpace - Specifies if the address is in the IO space if TRUE; otherwise,
the address is assumed to be in memory space.
VirtualAddress - Pointer to a variable that will receive the base
address of the view. If the initial value is not NULL, then the view
will be allocated starting at teh specified virtual address rounded
down to the next 64kb addess boundary.
Return Value:
STATUS_UNSUCCESSFUL if the length was zero.
STATUS_SUCCESS otherwise.
Environment:
This routine cannot be called from a miniport routine synchronized with
VideoPortSynchronizeRoutine or from an ISR.
--*/
{
NTSTATUS ntStatus;
HANDLE physicalMemoryHandle;
PHYSICAL_ADDRESS physicalAddressBase;
PHYSICAL_ADDRESS physicalAddressEnd;
PHYSICAL_ADDRESS viewBase;
PHYSICAL_ADDRESS mappedLength;
HANDLE processHandle;
BOOLEAN translateBaseAddress;
BOOLEAN translateEndAddress;
ULONG inIoSpace2;
ULONG inIoSpace1;
ULONG MapViewFlags;
//
// Check for a length of zero. If it is, the entire physical memory
// would be mapped into the process' address space. An error is returned
// in this case.
//
if (!*Length) {
return STATUS_INVALID_PARAMETER_4;
}
if (!(*InIoSpace & VIDEO_MEMORY_SPACE_USER_MODE)) {
return STATUS_INVALID_PARAMETER_5;
}
//
// Get a handle to the physical memory section using our pointer.
// If this fails, return.
//
ntStatus = ObOpenObjectByPointer(PhysicalMemorySection,
0L,
(PACCESS_STATE) NULL,
SECTION_ALL_ACCESS,
(POBJECT_TYPE) NULL,
KernelMode,
&physicalMemoryHandle);
if (!NT_SUCCESS(ntStatus)) {
return ntStatus;
}
//
// No flags are used in translation
//
inIoSpace1 = *InIoSpace & VIDEO_MEMORY_SPACE_IO;
inIoSpace2 = *InIoSpace & VIDEO_MEMORY_SPACE_IO;
//
// Initialize the physical addresses that will be translated
//
physicalAddressEnd.QuadPart = PhysicalAddress.QuadPart + (*Length - 1);
//
// Translate the physical addresses.
//
translateBaseAddress =
VpTranslateBusAddress(FdoExtension,
&PhysicalAddress,
&inIoSpace1,
&physicalAddressBase);
translateEndAddress =
VpTranslateBusAddress(FdoExtension,
&physicalAddressEnd,
&inIoSpace2,
&physicalAddressEnd);
if ( !(translateBaseAddress && translateEndAddress) ) {
ZwClose(physicalMemoryHandle);
return STATUS_DEVICE_CONFIGURATION_ERROR;
}
ASSERT(inIoSpace1 == inIoSpace2);
//
// Calcualte the length of the memory to be mapped
//
mappedLength.QuadPart = physicalAddressEnd.QuadPart -
physicalAddressBase.QuadPart + 1;
//
// If the mappedlength is zero, somthing very weird happened in the HAL
// since the Length was checked against zero.
//
ASSERT (mappedLength.QuadPart != 0);
//
// If the address is in io space, just return the address, otherwise
// go through the mapping mechanism
//
if ( (*InIoSpace) & (ULONG)0x01 ) {
(ULONG_PTR) *VirtualAddress = (ULONG_PTR) physicalAddressBase.QuadPart;
} else {
//
// If no process handle was passed, get the handle to the current
// process.
//
if (ProcessHandle) {
processHandle = ProcessHandle;
} else {
processHandle = NtCurrentProcess();
}
//
// initialize view base that will receive the physical mapped
// address after the MapViewOfSection call.
//
viewBase = physicalAddressBase;
//
// Map the section
//
if ((*InIoSpace) & VIDEO_MEMORY_SPACE_P6CACHE) {
MapViewFlags = PAGE_READWRITE | PAGE_WRITECOMBINE;
} else {
MapViewFlags = PAGE_READWRITE | PAGE_NOCACHE;
}
ntStatus = ZwMapViewOfSection(physicalMemoryHandle,
processHandle,
VirtualAddress,
0L,
(ULONG_PTR) mappedLength.QuadPart,
&viewBase,
(PULONG_PTR) (&(mappedLength.QuadPart)),
ViewUnmap,
0,
MapViewFlags);
//
// Close the handle since we only keep the pointer reference to the
// section.
//
ZwClose(physicalMemoryHandle);
//
// Mapping the section above rounded the physical address down to the
// nearest 64 K boundary. Now return a virtual address that sits where
// we wnat by adding in the offset from the beginning of the section.
//
(ULONG_PTR) *VirtualAddress += (ULONG_PTR) (physicalAddressBase.QuadPart -
viewBase.QuadPart);
}
//
// Restore all the other FLAGS
//
*InIoSpace = inIoSpace1 | *InIoSpace & ~VIDEO_MEMORY_SPACE_IO;
*Length = mappedLength.LowPart;
return ntStatus;
} // end pVideoPortMapUserPhysicalMem()
PVOID
VideoPortAllocatePool(
IN PVOID HwDeviceExtension,
IN VP_POOL_TYPE PoolType,
IN SIZE_T NumberOfBytes,
IN ULONG Tag)
/*++
Routine Description:
Allocates Memory
Arguments:
HwDeviceExtension - pointer to the miniports device extension
VpPoolType - The type of pool to allocate:
VpNonPagedPool
VpPagedPool
VpNonPagedPoolCacheAligned
VpPagedPoolCacheAligned
NumberOfBytes - Supplies the number of bytes to allocate.
Tag - Supplies the caller's identifying tag.
Return Value:
NULL - The memory allocation failed.
NON-NULL - Returns a pointer to the allocated pool.
--*/
{
ASSERT(HwDeviceExtension != NULL);
return ExAllocatePoolWithTag(PoolType, NumberOfBytes, Tag);
}
VOID
VideoPortFreePool(
IN PVOID HwDeviceExtension,
IN PVOID Ptr
)
/*++
Routine Description:
Free's allocated memory
Arguments:
HwDeviceExtension - pointer to the miniports device extension
Ptr - pointer to the memory to free
Return Value:
none
--*/
{
ASSERT(HwDeviceExtension != NULL);
ASSERT(Ptr != NULL);
ExFreePool(Ptr);
}
VP_STATUS
VideoPortAllocateBuffer(
IN PVOID HwDeviceExtension,
IN ULONG Size,
OUT PVOID *Buffer
)
{
pVideoDebugPrint((1, "Obsolete function: Please use VideoPortAllocatePool instead\n"));
*Buffer = VideoPortAllocatePool(HwDeviceExtension, VpPagedPool, Size, ' pmV');
if (*Buffer) {
return NO_ERROR;
} else {
return ERROR_NOT_ENOUGH_MEMORY;
}
}
VOID
VideoPortReleaseBuffer(
IN PVOID HwDeviceExtension,
IN PVOID Buffer
)
{
pVideoDebugPrint((1, "Obsolete function: Please use VideoPortFreePool instead\n"));
VideoPortFreePool(HwDeviceExtension, Buffer);
}
VP_STATUS
VideoPortMapBankedMemory(
PVOID HwDeviceExtension,
PHYSICAL_ADDRESS PhysicalAddress,
PULONG Length,
PULONG InIoSpace,
PVOID *VirtualAddress,
ULONG BankLength,
UCHAR ReadWriteBank,
PBANKED_SECTION_ROUTINE BankRoutine,
PVOID Context
)
/*++
Routine Description:
VideoPortMapMemory allows the miniport driver to map a section of
physical memory (either memory or registers) into the calling process'
address space (eventhough we are in kernel mode, this function is
executed within the same context as the user-mode process that initiated
the call).
Arguments:
HwDeviceExtension - Points to the miniport driver's device extension.
PhysicalAddress - Specifies the physical address to be mapped.
Length - Points to the number of bytes of physical memory to be mapped.
This argument returns the actual amount of memory mapped.
InIoSpace - Points to a variable that is 1 if the address is in I/O
space. Otherwise, the address is assumed to be in memory space.
VirtualAddress - A pointer to a location containing:
on input: An optional handle to the process in which the memory must
be mapped. 0 must be used to map the memory for the display
driver (in the context of the windows server process).
on output: The return value is the virtual address at which the
physical address has been mapped.
BankLength - Size of the bank on the device.
ReadWriteBank - TRUE is the bank is READ\WRITE, FALSE if there are
two independent READ and WRITE banks.
BankRoutine - Pointer to the banking routine.
Context - Context parameter passed in by the miniport supplied on
each callback to the miniport.
Return Value:
VideoPortMapBankedMemory returns the status of the operation.
Environment:
This routine cannot be called from a miniport routine synchronized with
VideoPortSynchronizeRoutine or from an ISR.
--*/
{
VP_STATUS status;
HANDLE processHandle;
//
// Save the process ID, but don't change it since MapMemory relies
// on it also
//
if (*VirtualAddress == NULL) {
processHandle = NtCurrentProcess();
} else {
processHandle = (HANDLE) *VirtualAddress;
}
status = VideoPortMapMemory(HwDeviceExtension,
PhysicalAddress,
Length,
InIoSpace,
VirtualAddress);
if (status == NO_ERROR) {
NTSTATUS ntstatus;
ntstatus = MmSetBankedSection(processHandle,
*VirtualAddress,
BankLength,
ReadWriteBank,
BankRoutine,
Context);
if (!NT_SUCCESS(ntstatus)) {
ASSERT (FALSE);
status = ERROR_INVALID_PARAMETER;
}
}
return status;
} // end VideoPortMapBankedMemory()
VP_STATUS
VideoPortMapMemory(
PVOID HwDeviceExtension,
PHYSICAL_ADDRESS PhysicalAddress,
PULONG Length,
PULONG InIoSpace,
PVOID *VirtualAddress
)
/*++
Routine Description:
VideoPortMapMemory allows the miniport driver to map a section of
physical memory (either memory or registers) into the calling process'
address space (eventhough we are in kernel mode, this function is
executed within the same context as the user-mode process that initiated
the call).
Arguments:
HwDeviceExtension - Points to the miniport driver's device extension.
PhysicalAddress - Specifies the physical address to be mapped.
Length - Points to the number of bytes of physical memory to be mapped.
This argument returns the actual amount of memory mapped.
InIoSpace - Points to a variable that is 1 if the address is in I/O
space. Otherwise, the address is assumed to be in memory space.
VirtualAddress - A pointer to a location containing:
on input: An optional handle to the process in which the memory must
be mapped. 0 must be used to map the memory for the display
driver (in the context of the windows server process).
on output: The return value is the virtual address at which the
physical address has been mapped.
Return Value:
VideoPortMapMemory returns the status of the operation.
Environment:
This routine cannot be called from a miniport routine synchronized with
VideoPortSynchronizeRoutine or from an ISR.
--*/
{
NTSTATUS ntStatus;
PFDO_EXTENSION fdoExtension = GET_FDO_EXT(HwDeviceExtension);
HANDLE processHandle;
//
// Check for valid pointers.
//
if (!(ARGUMENT_PRESENT(Length)) ||
!(ARGUMENT_PRESENT(InIoSpace)) ||
!(ARGUMENT_PRESENT(VirtualAddress)) ) {
ASSERT(FALSE);
return ERROR_INVALID_PARAMETER;
}
//
// Let's handle the special memory types here.
//
// NOTE
// Large pages is automatic - the caller need not specify this attribute
// since it does not affect the device.
//
// Save the process handle and zero out the Virtual address field
//
if (*VirtualAddress == NULL) {
if (*InIoSpace & VIDEO_MEMORY_SPACE_USER_MODE)
{
ASSERT(FALSE);
return ERROR_INVALID_PARAMETER;
}
ntStatus = STATUS_SUCCESS;
//
// We specify TRUE for large pages since we know the addrses will only
// be used in the context of the display driver, at normal IRQL.
//
*VirtualAddress = pVideoPortGetDeviceBase(HwDeviceExtension,
PhysicalAddress,
*Length,
(UCHAR) (*InIoSpace),
TRUE);
//
// Zero can only be success if the driver is calling to MAP
// address 0. Otherwise, it is an error.
//
if (*VirtualAddress == NULL) {
//
// Only on X86 can the logical address also be 0.
//
#if defined (_X86_) || defined(_IA64_)
if (PhysicalAddress.QuadPart != 0)
#endif
ntStatus = STATUS_INVALID_PARAMETER;
}
} else {
if (!(*InIoSpace & VIDEO_MEMORY_SPACE_USER_MODE))
{
//
// We can not assert since this is an existing path and old
// drivers will not have this flag set.
//
// ASSERT(FALSE);
// return ERROR_INVALID_PARAMETER;
//
*InIoSpace |= VIDEO_MEMORY_SPACE_USER_MODE;
}
processHandle = (HANDLE) *VirtualAddress;
*VirtualAddress = NULL;
ntStatus = pVideoPortMapUserPhysicalMem(fdoExtension,
processHandle,
PhysicalAddress,
Length,
InIoSpace,
VirtualAddress);
}
if (!NT_SUCCESS(ntStatus)) {
pVideoDebugPrint((Error,
"VIDEOPRT: VideoPortMapMemory failed with NtStatus = %08lx\n",
ntStatus));
pVideoDebugPrint((Error, "*VirtualAddress = 0x%x\n", *VirtualAddress));
pVideoDebugPrint((Error, "Length = 0x%x\n", *Length));
pVideoDebugPrint((Error,
"PhysicalAddress.LowPart = 0x%08lx, PhysicalAddress.HighPart = 0x%08lx\n",
PhysicalAddress.LowPart, PhysicalAddress.HighPart));
*VirtualAddress = NULL;
return ERROR_INVALID_PARAMETER;
} else {
return NO_ERROR;
}
} // end VideoPortMapMemory()
VOID
pVideoPortPowerCompletionIoctl(
IN PDEVICE_OBJECT DeviceObject,
IN UCHAR MinorFunction,
IN POWER_STATE PowerState,
IN PVOID Context,
IN PIO_STATUS_BLOCK IoStatus
)
/*++
Routine Description:
Completion routine that is called when one of our power irps has been
comeplted. This allows us to fill out the status code for the request.
Arguments:
DeviceObject - Pointer to the device object
MinorFunction - Minor function of the IRP
PowerState - Power state that was set
Context - Context paramter
IoStatus - Status block for that IRP
Return Value:
VOID
Environment:
--*/
{
PPOWER_BLOCK powerContext = (PPOWER_BLOCK) Context;
if (powerContext->FinalFlag == TRUE) {
powerContext->Irp->IoStatus.Status = IoStatus->Status;
IoCompleteRequest (powerContext->Irp, IO_VIDEO_INCREMENT);
}
ExFreePool(Context);
return;
}
BOOLEAN
pVideoPortResetDisplay(
IN ULONG Columns,
IN ULONG Rows
)
/*++
Routine Description:
Callback for the HAL that calls the miniport driver.
Arguments:
Columns - The number of columns of the video mode.
Rows - The number of rows for the video mode.
Return Value:
We always return FALSE so the HAL will always reste the mode afterwards.
Environment:
Non-paged only.
Used in BugCheck and soft-reset calls.
--*/
{
ULONG iReset;
BOOLEAN bRetVal = FALSE;
for (iReset=0;
(iReset < 6) && (HwResetHw[iReset].HwDeviceExtension);
iReset++) {
PFDO_EXTENSION fdoExtension =
GET_FDO_EXT(HwResetHw[iReset].HwDeviceExtension);
//
// We can only reset devices which are on the hibernation path, otherwise
// we are running into the risk that IO / MMIO decode has been disabled
// by PCI.SYS for that device during power management cycle.
//
if (HwResetHw[iReset].ResetFunction &&
(fdoExtension->HwInitStatus == HwInitSucceeded) &&
(fdoExtension->OnHibernationPath == TRUE)) {
bRetVal &= HwResetHw[iReset].ResetFunction(HwResetHw[iReset].HwDeviceExtension,
Columns,
Rows);
}
}
return bRetVal;
} // end pVideoPortResetDisplay()
BOOLEAN
VideoPortScanRom(
PVOID HwDeviceExtension,
PUCHAR RomBase,
ULONG RomLength,
PUCHAR String
)
/*++
Routine Description:
Does a case *SENSITIVE* search for a string in the ROM.
Arguments:
HwDeviceExtension - Points to the miniport driver's device extension.
RomBase - Base address at which the search should start.
RomLength - Size, in bytes, of the ROM area in which to perform the
search.
String - String to search for
Return Value:
Returns TRUE if the string was found.
Returns FALSE if it was not found.
Environment:
This routine cannot be called from a miniport routine synchronized with
VideoPortSynchronizeRoutine or from an ISR.
--*/
{
ULONG stringLength, length;
ULONG_PTR startOffset;
PUCHAR string1, string2;
BOOLEAN match;
UNREFERENCED_PARAMETER(HwDeviceExtension);
stringLength = strlen(String);
for (startOffset = 0;
startOffset < RomLength - stringLength + 1;
startOffset++) {
length = stringLength;
string1 = RomBase + startOffset;
string2 = String;
match = TRUE;
while (length--) {
if (READ_REGISTER_UCHAR(string1++) - (*string2++)) {
match = FALSE;
break;
}
}
if (match) {
return TRUE;
}
}
return FALSE;
} // end VideoPortScanRom()
VP_STATUS
VideoPortSetRegistryParameters(
PVOID HwDeviceExtension,
PWSTR ValueName,
PVOID ValueData,
ULONG ValueLength
)
/*++
Routine Description:
VideoPortSetRegistryParameters writes information to the CurrentControlSet
in the registry. The function automatically searches for or creates the
specified parameter name under the parameter key of the current driver.
Arguments:
HwDeviceExtension - Points to the miniport driver's device extension.
ValueName - Points to a Unicode string that contains the name of the
data value being written in the registry.
ValueData - Points to a buffer containing the information to be written
to the registry.
ValueLength - Specifies the size of the data being written to the registry.
Return Value:
This function returns the final status of the operation.
Environment:
This routine cannot be called from a miniport routine synchronized with
VideoPortSynchronizeRoutine or from an ISR.
--*/
{
PDEVICE_SPECIFIC_EXTENSION DoSpecificExtension;
VP_STATUS vpStatus;
ASSERT (ValueName != NULL);
DoSpecificExtension = GET_DSP_EXT(HwDeviceExtension);
if (DoSpecificExtension->DriverNewRegistryPath != NULL) {
vpStatus = VPSetRegistryParameters(HwDeviceExtension,
ValueName,
ValueData,
ValueLength,
DoSpecificExtension->DriverNewRegistryPath,
DoSpecificExtension->DriverNewRegistryPathLength);
} else {
vpStatus = VPSetRegistryParameters(HwDeviceExtension,
ValueName,
ValueData,
ValueLength,
DoSpecificExtension->DriverOldRegistryPath,
DoSpecificExtension->DriverOldRegistryPathLength);
}
return vpStatus;
}
VP_STATUS
VPSetRegistryParameters(
PVOID HwDeviceExtension,
PWSTR ValueName,
PVOID ValueData,
ULONG ValueLength,
PWSTR RegistryPath,
ULONG RegistryPathLength
)
{
NTSTATUS ntStatus;
LPWSTR RegPath;
LPWSTR lpstrStart, lpstrEnd;
//
// Check if there are subkeys need to be created
//
RegPath = (LPWSTR) ExAllocatePoolWithTag(PagedPool | POOL_COLD_ALLOCATION,
RegistryPathLength +
2 * (wcslen(ValueName) + sizeof(WCHAR)),
VP_TAG);
if (RegPath == NULL) {
return ERROR_NOT_ENOUGH_MEMORY;
}
wcscpy(RegPath, RegistryPath);
lpstrStart = RegPath + (RegistryPathLength / 2);
while (lpstrEnd = wcschr(ValueName, L'\\'))
{
//
// Concat the string
//
*(lpstrStart++) = L'\\';
while (ValueName != lpstrEnd) {
*(lpstrStart++) = *(ValueName++);
}
*lpstrStart = UNICODE_NULL;
//
// Create the Key.
//
ntStatus = RtlCreateRegistryKey(RTL_REGISTRY_ABSOLUTE, RegPath);
if (!NT_SUCCESS(ntStatus)) {
ExFreePool(RegPath);
return ERROR_INVALID_PARAMETER;
}
ValueName++;
}
//
// Don't let people store as DefaultSettings anymore ...
// Must still work for older drivers through.
//
if (wcsncmp(ValueName,
L"DefaultSettings.",
sizeof(L"DefaultSettings.")) == 0) {
ASSERT(FALSE);
//
// check for NT 5.0
//
if (GET_FDO_EXT(HwDeviceExtension)->Flags & PNP_ENABLED) {
ExFreePool(RegPath);
return ERROR_INVALID_PARAMETER;
}
}
ntStatus = RtlWriteRegistryValue(RTL_REGISTRY_ABSOLUTE,
RegPath,
ValueName,
REG_BINARY,
ValueData,
ValueLength);
ExFreePool(RegPath);
if (!NT_SUCCESS(ntStatus)) {
return ERROR_INVALID_PARAMETER;
}
return NO_ERROR;
} // end VideoPortSetRegistryParamaters()
VP_STATUS
VideoPortFlushRegistry(
PVOID HwDeviceExtension
)
/*++
Routine Description:
This routine will flush the registry keys and values associated with
the given miniport driver.
Arguments:
HwDeviceExtension - Pointer to the miniport device extension.
Return Value:
Status Code.
--*/
{
OBJECT_ATTRIBUTES ObjectAttributes;
UNICODE_STRING KeyName;
HANDLE RegKey;
NTSTATUS Status;
PDEVICE_SPECIFIC_EXTENSION DoSpecificExtension;
DoSpecificExtension = GET_DSP_EXT(HwDeviceExtension);
if (DoSpecificExtension->DriverNewRegistryPath != NULL) {
KeyName.Length = (USHORT)DoSpecificExtension->DriverNewRegistryPathLength;
KeyName.MaximumLength = (USHORT)DoSpecificExtension->DriverNewRegistryPathLength;
KeyName.Buffer = DoSpecificExtension->DriverNewRegistryPath;
} else {
KeyName.Length = (USHORT)DoSpecificExtension->DriverOldRegistryPathLength;
KeyName.MaximumLength = (USHORT)DoSpecificExtension->DriverOldRegistryPathLength;
KeyName.Buffer = DoSpecificExtension->DriverOldRegistryPath;
}
//
// Flush the registry key
//
InitializeObjectAttributes(&ObjectAttributes,
&KeyName,
OBJ_CASE_INSENSITIVE,
NULL,
NULL);
Status = ZwOpenKey(&RegKey,
KEY_READ | KEY_WRITE,
&ObjectAttributes);
if (NT_SUCCESS(Status)) {
ZwFlushKey(RegKey);
ZwClose(RegKey);
}
return NO_ERROR;
}
VOID
pVideoPortHwTimer(
IN PDEVICE_OBJECT DeviceObject,
PVOID Context
)
/*++
Routine Description:
This function is the main entry point for the timer routine that we then
forward to the miniport driver.
Arguments:
DeviceObject -
Context - Not needed
Return Value:
None.
--*/
{
PFDO_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
UNREFERENCED_PARAMETER(Context);
fdoExtension->HwTimer(fdoExtension->HwDeviceExtension);
return;
} // pVideoPortInterrupt()
VOID
VideoPortStartTimer(
PVOID HwDeviceExtension
)
/*++
Routine Description:
Enables the timer specified in the HW_INITIALIZATION_DATA structure
passed to the video port driver at init time.
Arguments:
HwDeviceExtension - Points to the miniport driver's device extension.
Return Value:
None
--*/
{
PFDO_EXTENSION fdoExtension = GET_FDO_EXT(HwDeviceExtension);
if (fdoExtension->HwTimer == NULL) {
ASSERT(fdoExtension->HwTimer != NULL);
} else {
IoStartTimer(fdoExtension->FunctionalDeviceObject);
}
return;
}
VOID
VideoPortStopTimer(
PVOID HwDeviceExtension
)
/*++
Routine Description:
Disables the timer specified in the HW_INITIALIZATION_DATA structure
passed to the video port driver at init time.
Arguments:
HwDeviceExtension - Points to the miniport driver's device extension.
Return Value:
None
--*/
{
PFDO_EXTENSION fdoExtension = GET_FDO_EXT(HwDeviceExtension);
if (fdoExtension->HwTimer == NULL) {
ASSERT(fdoExtension->HwTimer != NULL);
} else {
IoStopTimer(fdoExtension->FunctionalDeviceObject);
}
return;
}
BOOLEAN
VideoPortSynchronizeExecution(
PVOID HwDeviceExtension,
VIDEO_SYNCHRONIZE_PRIORITY Priority,
PMINIPORT_SYNCHRONIZE_ROUTINE SynchronizeRoutine,
PVOID Context
)
/*++
Stub so we can allow the miniports to link directly
--*/
{
return pVideoPortSynchronizeExecution(HwDeviceExtension,
Priority,
SynchronizeRoutine,
Context);
} // end VideoPortSynchronizeExecution()
BOOLEAN
pVideoPortSynchronizeExecution(
PVOID HwDeviceExtension,
VIDEO_SYNCHRONIZE_PRIORITY Priority,
PMINIPORT_SYNCHRONIZE_ROUTINE SynchronizeRoutine,
PVOID Context
)
/*++
Routine Description:
VideoPortSynchronizeExecution synchronizes the execution of a miniport
driver function in the following manner:
- If Priority is equal to VpLowPriority, the current thread is
raised to the highest non-interrupt-masking priority. In
other words, the current thread can only be pre-empted by an ISR.
- If Priority is equal to VpMediumPriority and there is an
ISR associated with the video device, then the function specified
by SynchronizeRoutine is synchronized with the ISR.
If no ISR is connected, synchronization is made at VpHighPriority
level.
- If Priority is equal to VpHighPriority, the current IRQL is
raised to HIGH_LEVEL, which effectively masks out ALL interrupts
in the system. This should be done sparingly and for very short
periods -- it will completely freeze up the entire system.
Arguments:
HwDeviceExtension - Points to the miniport driver's device extension.
Priority - Specifies the type of priority at which the SynchronizeRoutine
must be executed (found in VIDEO_SYNCHRONIZE_PRIORITY).
SynchronizeRoutine - Points to the miniport driver function to be
synchronized.
Context - Specifies a context parameter to be passed to the miniport's
SynchronizeRoutine.
Return Value:
This function returns TRUE if the operation is successful. Otherwise, it
returns FALSE.
--*/
{
BOOLEAN status;
PFDO_EXTENSION fdoExtension = GET_FDO_EXT(HwDeviceExtension);
KIRQL oldIrql;
//
// Switch on which type of priority.
//
switch (Priority) {
case VpMediumPriority:
case VpHighPriority:
//
// This is synchronized with the interrupt object
//
if (fdoExtension->InterruptObject) {
status = KeSynchronizeExecution(fdoExtension->InterruptObject,
(PKSYNCHRONIZE_ROUTINE)
SynchronizeRoutine,
Context);
return status;
}
//
// Fall through for Medium Priority
//
case VpLowPriority:
//
// Just normal level
//
status = SynchronizeRoutine(Context);
return status;
default:
return FALSE;
}
}
VP_STATUS
VideoPortUnmapMemory(
PVOID HwDeviceExtension,
PVOID VirtualAddress,
HANDLE ProcessHandle
)
/*++
Routine Description:
VideoPortUnmapMemory allows the miniport driver to unmap a physical
address range previously mapped into the calling process' address space
using the VideoPortMapMemory function.
Arguments:
HwDeviceExtension - Points to the miniport driver's device extension.
VirtualAddress - Points to the virtual address to unmap from the
address space of the caller.
// InIoSpace - Specifies whether the address is in I/O space (1) or memory
// space (0).
ProcessHandle - Handle to the process from which memory must be unmapped.
Return Value:
This function returns a status code of NO_ERROR if the operation succeeds.
It returns ERROR_INVALID_PARAMETER if an error occurs.
Environment:
This routine cannot be called from a miniport routine synchronized with
VideoPortSynchronizeRoutine or from an ISR.
--*/
{
NTSTATUS ntstatus;
VP_STATUS vpStatus = NO_ERROR;
PFDO_EXTENSION fdoExtension = GET_FDO_EXT(HwDeviceExtension);
//
// Backwards compatibility to when the ProcessHandle was actually
// ULONG InIoSpace.
//
if (((ULONG_PTR)(ProcessHandle)) == 1) {
pVideoDebugPrint((Warn,"VIDEOPRT: VideoPortUnmapMemory - interface change, must pass in process handle\n\n"));
ASSERT(FALSE);
return NO_ERROR;
}
if (((ULONG_PTR)(ProcessHandle)) == 0) {
//
// If the process handle is zero, it means it was mapped by the display
// driver and is therefore in kernel mode address space.
//
if (!pVideoPortFreeDeviceBase(HwDeviceExtension, VirtualAddress)) {
ASSERT(FALSE);
vpStatus = ERROR_INVALID_PARAMETER;
}
} else {
//
// A process handle is passed in.
// This ms it was mapped for use by an application (DCI \ DirectDraw).
//
ntstatus = ZwUnmapViewOfSection ( ProcessHandle,
(PVOID) ( ((ULONG_PTR)VirtualAddress) & (~(PAGE_SIZE - 1)) ) );
if ( (!NT_SUCCESS(ntstatus)) &&
(ntstatus != STATUS_PROCESS_IS_TERMINATING) ) {
ASSERT(FALSE);
vpStatus = ERROR_INVALID_PARAMETER;
}
}
return NO_ERROR;
} // end VideoPortUnmapMemory()
BOOLEAN
VideoPortSignalDmaComplete(
IN PVOID HwDeviceExtension,
IN PDMA pDmaHandle
)
/*++
Routine Description:
This function is obsolete.
--*/
{
return FALSE;
}
VP_STATUS
VideoPortCreateSecondaryDisplay(
IN PVOID HwDeviceExtension,
IN OUT PVOID *SecondaryDeviceExtension,
IN ULONG ulFlag
)
/*++
Routine Description:
This routine creates a secondary device object for the given device. This
will allow for dual-view support.
Arguments:
HwDeviceExtension - The HwDeviceExtension for the device which wants to
create additional output devices.
SecondaryDeviceExtension - The location in which to store the
HwDeviceExtension for the secondary display.
Returns:
VP_STATUS
--*/
{
WCHAR deviceNameBuffer[STRING_LENGTH];
POBJECT_NAME_INFORMATION deviceName;
ULONG strLength;
UNICODE_STRING deviceNameUnicodeString;
PDEVICE_OBJECT DeviceObject;
NTSTATUS ntStatus;
PDEVICE_SPECIFIC_EXTENSION DoSpecificExtension;
PFDO_EXTENSION FdoExtension = GET_FDO_EXT(HwDeviceExtension);
PVIDEO_PORT_DRIVER_EXTENSION DriverObjectExtension;
PUNICODE_STRING RegistryPath;
WCHAR deviceSubpathBuffer[STRING_LENGTH];
UNICODE_STRING deviceSubpathUnicodeString;
WCHAR deviceLinkBuffer[STRING_LENGTH];
UNICODE_STRING deviceLinkUnicodeString;
ULONG driverKeySize;
PWSTR driverKeyName = NULL;
ULONG MaxObjectNumber;
//
// Retrieve the data we cached away during VideoPortInitialize.
//
DriverObjectExtension = (PVIDEO_PORT_DRIVER_EXTENSION)
IoGetDriverObjectExtension(
FdoExtension->DriverObject,
FdoExtension->DriverObject);
ASSERT(DriverObjectExtension);
ASSERT(SecondaryDeviceExtension != NULL);
RegistryPath = &DriverObjectExtension->RegistryPath;
ntStatus = pVideoPortCreateDeviceName(L"\\Device\\Video",
VideoDeviceNumber,
&deviceNameUnicodeString,
deviceNameBuffer);
//
// Create a device object to represent the Video Adapter.
//
if (NT_SUCCESS(ntStatus)) {
ntStatus = IoCreateDevice(FdoExtension->DriverObject,
sizeof(DEVICE_SPECIFIC_EXTENSION) +
FdoExtension->HwDeviceExtensionSize,
&deviceNameUnicodeString,
FILE_DEVICE_VIDEO,
0,
TRUE,
&DeviceObject);
if (NT_SUCCESS(ntStatus)) {
DeviceObject->DeviceType = FILE_DEVICE_VIDEO;
DoSpecificExtension = DeviceObject->DeviceExtension;
//
// Initialize DeviceSpecificExtension
//
DoSpecificExtension->DeviceNumber = VideoDeviceNumber;
DoSpecificExtension->pFdoExtension = FdoExtension;
DoSpecificExtension->Signature = VP_TAG;
DoSpecificExtension->ExtensionType = TypeDeviceSpecificExtension;
DoSpecificExtension->HwDeviceExtension = (PVOID)(DoSpecificExtension + 1);
DoSpecificExtension->DualviewFlags = ulFlag | VIDEO_DUALVIEW_SECONDARY;
#ifdef IOCTL_VIDEO_USE_DEVICE_IN_SESSION
DoSpecificExtension->SessionId = VIDEO_DEVICE_INVALID_SESSION;
#endif IOCTL_VIDEO_USE_DEVICE_IN_SESSION
deviceName = (POBJECT_NAME_INFORMATION) deviceNameBuffer;
ObQueryNameString(DeviceObject,
deviceName,
STRING_LENGTH * sizeof(WCHAR),
&strLength);
//
// Create the name we will be storing in the \DeviceMap.
// This name is a PWSTR, not a unicode string
// This is the name of the driver with an appended device number
//
if (!NT_SUCCESS(pVideoPortCreateDeviceName(
L"\\Device",
DriverObjectExtension->HwInitData.StartingDeviceNumber + 1,
&deviceSubpathUnicodeString,
deviceSubpathBuffer)))
{
pVideoDebugPrint((Error, "VIDEOPRT: VideoPortCreateSecondaryDisplay: Could not create device subpath number\n"));
IoDeleteDevice(DeviceObject);
return STATUS_INSUFFICIENT_RESOURCES;
}
DoSpecificExtension->DriverOldRegistryPathLength =
RegistryPath->Length +
deviceSubpathUnicodeString.Length;
driverKeySize =
DoSpecificExtension->DriverOldRegistryPathLength +
2 * sizeof(UNICODE_NULL);
if ( (driverKeyName = (PWSTR) ExAllocatePoolWithTag(PagedPool,
driverKeySize,
VP_TAG) ) == NULL)
{
pVideoDebugPrint((Error, "VIDEOPRT: VideoPortCreateSecondaryDisplay: Fail to allocate driverKeyName\n"));
IoDeleteDevice(DeviceObject);
return STATUS_INSUFFICIENT_RESOURCES;
}
RtlMoveMemory(driverKeyName,
RegistryPath->Buffer,
RegistryPath->Length);
RtlMoveMemory((PWSTR)((ULONG_PTR)driverKeyName +
RegistryPath->Length),
deviceSubpathBuffer,
deviceSubpathUnicodeString.Length);
//
// Put two NULLs at the end so we can play around with the string later.
//
*((PWSTR) ((ULONG_PTR)driverKeyName +
DoSpecificExtension->DriverOldRegistryPathLength))
= UNICODE_NULL;
*((PWSTR) ((ULONG_PTR)driverKeyName +
(DoSpecificExtension->DriverOldRegistryPathLength
+ sizeof(UNICODE_NULL)))) = UNICODE_NULL;
//
// There is a bug in Lotus Screen Cam where it will only work if our
// reg path is \REGISTRY\Machine\System not \REGISTRY\MACHINE\SYSTEM.
// so replace the appropriate strings.
//
if (wcsstr(driverKeyName, L"MACHINE")) {
wcsncpy(wcsstr(driverKeyName, L"MACHINE"), L"Machine", sizeof("Machine")-1);
}
if (wcsstr(driverKeyName, L"SYSTEM")) {
wcsncpy(wcsstr(driverKeyName, L"SYSTEM"), L"System", sizeof("System")-1);
}
//
// Store the old key
//
DoSpecificExtension->DriverOldRegistryPath = driverKeyName;
//
// Store the new key
// If this is not a Whistler driver, then use the old key.
//
if (EnableNewRegistryKey) {
#if _X86_
if (DriverObjectExtension->HwInitData.HwInitDataSize > SIZE_OF_W2K_VIDEO_HW_INITIALIZATION_DATA)
#endif // _X86_
VpEnableNewRegistryKey(FdoExtension,
DoSpecificExtension,
RegistryPath,
FdoExtension->RegistryIndex + 1);
}
//
// Store the path name of the location of the driver in the registry.
//
if (DoSpecificExtension->DriverNewRegistryPath != NULL) {
DoSpecificExtension->DriverRegistryPath =
DoSpecificExtension->DriverNewRegistryPath;
DoSpecificExtension->DriverRegistryPathLength =
DoSpecificExtension->DriverNewRegistryPathLength;
} else {
DoSpecificExtension->DriverRegistryPath =
DoSpecificExtension->DriverOldRegistryPath;
DoSpecificExtension->DriverRegistryPathLength =
DoSpecificExtension->DriverOldRegistryPathLength;
}
//
// NOTE:
//
// We only want to reinitialize the device once the Boot sequence has
// been completed and the HAL does not need to access the device again.
// So the initialization entry point will be called when the device is
// opened.
//
if (!NT_SUCCESS(pVideoPortCreateDeviceName(L"\\DosDevices\\DISPLAY",
DoSpecificExtension->DeviceNumber + 1,
&deviceLinkUnicodeString,
deviceLinkBuffer)))
{
pVideoDebugPrint((Error, "VIDEOPRT: VideoPortCreateSecondaryDisplay: Could not create device subpath number\n"));
ExFreePool(driverKeyName);
IoDeleteDevice(DeviceObject);
return STATUS_INSUFFICIENT_RESOURCES;
}
ntStatus = IoCreateSymbolicLink(&deviceLinkUnicodeString,
&deviceName->Name);
if (!NT_SUCCESS(ntStatus)) {
pVideoDebugPrint((Error, "VIDEOPRT: VideoPortCreateSecondaryDisplay: SymbolicLink Creation failed\n"));
ExFreePool(driverKeyName);
IoDeleteDevice(DeviceObject);
return STATUS_INSUFFICIENT_RESOURCES;
}
//
// Once initialization is finished, load the required information in the
// registry so that the appropriate display drivers can be loaded.
//
ntStatus = RtlWriteRegistryValue(RTL_REGISTRY_DEVICEMAP,
VideoClassString,
deviceName->Name.Buffer,
REG_SZ,
DoSpecificExtension->DriverRegistryPath,
DoSpecificExtension->DriverRegistryPathLength +
sizeof(UNICODE_NULL));
if (!NT_SUCCESS(ntStatus)) {
pVideoDebugPrint((Error, "VIDEOPRT: VideoPortCreateSecondaryDisplay: Could not store name in DeviceMap\n"));
}
//
// Tell win32k how many objects to try to open
//
MaxObjectNumber = VideoDeviceNumber - 1;
ntStatus = RtlWriteRegistryValue(RTL_REGISTRY_DEVICEMAP,
VideoClassString,
L"MaxObjectNumber",
REG_DWORD,
&MaxObjectNumber,
sizeof(ULONG));
if (!NT_SUCCESS(ntStatus)) {
pVideoDebugPrint((Error, "VIDEOPRT: VideoPortCreateSecondaryDisplay: Could not store name in DeviceMap\n"));
}
//
// Register and enable the interface
//
VpEnableAdapterInterface(DoSpecificExtension);
//
// Finally, tell the system we are done with Device Initialization
//
DeviceObject->Flags |= DO_BUFFERED_IO | DO_POWER_PAGABLE;
DeviceObject->Flags &= ~(DO_DEVICE_INITIALIZING | DO_POWER_INRUSH);
VideoDeviceNumber++;
FdoExtension->RegistryIndex++;
}
}
if (NT_SUCCESS(ntStatus)) {
*SecondaryDeviceExtension = (PVOID)(DoSpecificExtension + 1);
DriverObjectExtension->HwInitData.StartingDeviceNumber++;
//
// Mark the primary view
//
((PDEVICE_SPECIFIC_EXTENSION)(FdoExtension + 1))->DualviewFlags = VIDEO_DUALVIEW_PRIMARY;
}
return ntStatus;
}
#if DBG
PIO_RESOURCE_REQUIREMENTS_LIST
BuildRequirements(
PCM_RESOURCE_LIST pcmResourceList
)
{
ULONG i;
PCM_PARTIAL_RESOURCE_DESCRIPTOR pcmDescript;
PIO_RESOURCE_REQUIREMENTS_LIST Requirements;
PIO_RESOURCE_DESCRIPTOR pioDescript;
ULONG RequirementsListSize;
ULONG RequirementCount;
pVideoDebugPrint((Trace, "VIDEOPRT: BuildRequirements()\n"));
RequirementCount = pcmResourceList->List[0].PartialResourceList.Count;
RequirementsListSize = sizeof(IO_RESOURCE_REQUIREMENTS_LIST) +
((RequirementCount - 1) *
sizeof(IO_RESOURCE_DESCRIPTOR));
Requirements = (PIO_RESOURCE_REQUIREMENTS_LIST) ExAllocatePool(
PagedPool,
RequirementsListSize);
Requirements->ListSize = RequirementsListSize;
Requirements->InterfaceType = pcmResourceList->List[0].InterfaceType;
Requirements->BusNumber = pcmResourceList->List[0].BusNumber;
Requirements->SlotNumber = -1; // ???
Requirements->AlternativeLists = 0; // ???
Requirements->List[0].Version = pcmResourceList->List[0].PartialResourceList.Version;
Requirements->List[0].Revision = pcmResourceList->List[0].PartialResourceList.Revision;
Requirements->List[0].Count = RequirementCount;
pcmDescript = &(pcmResourceList->List[0].PartialResourceList.PartialDescriptors[0]);
pioDescript = &(Requirements->List[0].Descriptors[0]);
for (i=0; i<RequirementCount; i++) {
pioDescript->Option = IO_RESOURCE_PREFERRED;
pioDescript->Type = pcmDescript->Type;
pioDescript->ShareDisposition = pcmDescript->ShareDisposition;
pioDescript->Flags = pcmDescript->Flags;
switch (pcmDescript->Type) {
case CmResourceTypePort:
pioDescript->u.Port.Length = pcmDescript->u.Port.Length;
pioDescript->u.Port.Alignment = 1;
pioDescript->u.Port.MinimumAddress =
pioDescript->u.Port.MaximumAddress = pcmDescript->u.Port.Start;
break;
case CmResourceTypeMemory:
pioDescript->u.Memory.Length = pcmDescript->u.Memory.Length;
pioDescript->u.Memory.Alignment = 1;
pioDescript->u.Memory.MinimumAddress =
pioDescript->u.Memory.MaximumAddress = pcmDescript->u.Memory.Start;
break;
default:
//
// We don't have to handle the other stuff, because we only
// want to report Ports and Memory to the system.
//
break;
}
pioDescript++;
pcmDescript++;
}
return Requirements;
}
VOID
DumpRequirements(
PIO_RESOURCE_REQUIREMENTS_LIST Requirements
)
{
ULONG i;
PIO_RESOURCE_DESCRIPTOR pioDescript;
ULONG RequirementsListSize;
ULONG RequirementCount = Requirements->List[0].Count;
char *Table[] = { "Internal",
"Isa",
"Eisa",
"MicroChannel",
"TurboChannel",
"PCIBus",
"VMEBus",
"NuBus",
"PCMCIABus",
"CBus",
"MPIBus",
"MPSABus",
"ProcessorInternal",
"InternalPowerBus",
"PNPISABus",
"MaximumInterfaceType"
};
pVideoDebugPrint((Info, "VIDEOPRT: Beginning dump of requirements list:\n"));
pVideoDebugPrint((Info, "ListSize: 0x%x\n"
"InterfaceType: %s\n"
"BusNumber: 0x%x\n"
"SlotNumber: 0x%x\n"
"AlternativeLists: 0x%x\n",
Requirements->ListSize,
Table[Requirements->InterfaceType],
Requirements->BusNumber,
Requirements->SlotNumber,
Requirements->AlternativeLists));
pVideoDebugPrint((Info, "List[0].Version: 0x%x\n"
"List[0].Revision: 0x%x\n"
"List[0].Count: 0x%x\n",
Requirements->List[0].Version,
Requirements->List[0].Revision,
Requirements->List[0].Count));
pioDescript = &(Requirements->List[0].Descriptors[0]);
for (i=0; i<RequirementCount; i++) {
pVideoDebugPrint((Info, "\n"
"Option: 0x%x\n"
"Type: 0x%x\n"
"ShareDisposition: 0x%x\n"
"Flags: 0x%x\n",
pioDescript->Option,
pioDescript->Type,
pioDescript->ShareDisposition,
pioDescript->Flags));
switch (pioDescript->Type) {
case CmResourceTypePort:
pVideoDebugPrint((Info, "\nPort...\n"
"\tLength: 0x%x\n"
"\tAlignment: 0x%x\n"
"\tMinimumAddress: 0x%x\n"
"\tMaximumAddress: 0x%x\n",
pioDescript->u.Port.Length,
pioDescript->u.Port.Alignment,
pioDescript->u.Port.MinimumAddress,
pioDescript->u.Port.MaximumAddress));
break;
case CmResourceTypeMemory:
pVideoDebugPrint((Info, "\nMemory...\n"
"\tLength: 0x%x\n"
"\tAlignment: 0x%x\n"
"\tMinimumAddress: 0x%x\n"
"\tMaximumAddress: 0x%x\n",
pioDescript->u.Memory.Length,
pioDescript->u.Memory.Alignment,
pioDescript->u.Memory.MinimumAddress,
pioDescript->u.Memory.MaximumAddress));
break;
case CmResourceTypeInterrupt:
pVideoDebugPrint((Info, "\nInterrupt...\n"
"\tMinimum Vector: 0x%x\n"
"\tMaximum Vector: 0x%x\n",
pioDescript->u.Interrupt.MinimumVector,
pioDescript->u.Interrupt.MaximumVector));
break;
default:
//
// We don't have to handle the other stuff, because we only
// want to report Ports and Memory to the system.
//
break;
}
pioDescript++;
}
return;
}
VOID
DumpResourceList(
PCM_RESOURCE_LIST pcmResourceList)
{
ULONG i, j;
PCM_FULL_RESOURCE_DESCRIPTOR pcmFull;
PCM_PARTIAL_RESOURCE_LIST pcmPartial;
PCM_PARTIAL_RESOURCE_DESCRIPTOR pcmDescript;
pVideoDebugPrint((Trace, "VIDEOPRT: Beginning dump of resource list:\n"));
pcmFull = &(pcmResourceList->List[0]);
for (i=0; i<pcmResourceList->Count; i++) {
pVideoDebugPrint((Info, "List[%d]\n", i));
pVideoDebugPrint((Info, "InterfaceType = 0x%x\n", pcmFull->InterfaceType));
pVideoDebugPrint((Info, "BusNumber = 0x%x\n", pcmFull->BusNumber));
pcmPartial = &(pcmFull->PartialResourceList);
pVideoDebugPrint((Info, "Version = 0x%x\n", pcmPartial->Version));
pVideoDebugPrint((Info, "Revision = 0x%x\n", pcmPartial->Revision));
pcmDescript = &(pcmPartial->PartialDescriptors[0]);
for (j=0; j<pcmPartial->Count; j++) {
switch (pcmDescript->Type) {
case CmResourceTypePort:
pVideoDebugPrint((Info, "Port: 0x%x Length: 0x%x\n",
pcmDescript->u.Port.Start.LowPart,
pcmDescript->u.Port.Length));
break;
case CmResourceTypeInterrupt:
pVideoDebugPrint((Info, "Interrupt: 0x%x Level: 0x%x\n",
pcmDescript->u.Interrupt.Vector,
pcmDescript->u.Interrupt.Level));
break;
case CmResourceTypeMemory:
pVideoDebugPrint((Info, "Start: 0x%x Length: 0x%x\n",
pcmDescript->u.Memory.Start.LowPart,
pcmDescript->u.Memory.Length));
break;
case CmResourceTypeDma:
pVideoDebugPrint((Info, "Dma Channel: 0x%x Port: 0x%x\n",
pcmDescript->u.Dma.Channel,
pcmDescript->u.Dma.Port));
break;
}
pcmDescript++;
}
pcmFull = (PCM_FULL_RESOURCE_DESCRIPTOR) pcmDescript;
}
pVideoDebugPrint((Info, "VIDEOPRT: EndResourceList\n"));
}
VOID
DumpUnicodeString(
IN PUNICODE_STRING p
)
{
PUSHORT pus = p->Buffer;
UCHAR buffer[256]; // the string better not be longer than 255 chars!
PUCHAR puc = buffer;
ULONG i;
for (i = 0; i < p->Length; i++) {
*puc++ = (UCHAR) *pus++;
}
*puc = 0; // null terminate the string
pVideoDebugPrint((Info, "VIDEOPRT: UNICODE STRING: %s\n", buffer));
}
#endif
VP_STATUS
VideoPortEnumerateChildren(
IN PVOID HwDeviceExtension,
IN PVOID Reserved
)
/*++
Routine Description:
Allows a miniport to force a re-enumeration of it's children.
Arguments:
HwDeviceExtension - The miniports device extension
Reserved - Not currently used, should be NULL.
Returns:
Status
--*/
{
PFDO_EXTENSION fdoExtension = GET_FDO_EXT (HwDeviceExtension);
PDEVICE_OBJECT pFDO = fdoExtension->FunctionalDeviceObject;
PDEVICE_OBJECT pPDO = fdoExtension->PhysicalDeviceObject;
ASSERT(Reserved == NULL);
IoInvalidateDeviceRelations(pPDO, BusRelations);
return NO_ERROR;
}
VIDEOPORT_API
VP_STATUS
VideoPortQueryServices(
IN PVOID pHwDeviceExtension,
IN VIDEO_PORT_SERVICES servicesType,
IN OUT PINTERFACE pInterface
)
/*++
Routine Description:
This routine exposes interfaces to services supported by the videoprt.
Arguments:
pHwDeviceExtension - Points to per-adapter device extension.
servicesType - Requested services type.
pInterface - Points to services interface structure.
Returns:
NO_ERROR - Valid interface in the pInterface.
Error code - Unsupported / unavailable services.
--*/
{
VP_STATUS vpStatus;
PAGED_CODE();
ASSERT(NULL != pHwDeviceExtension);
ASSERT(NULL != pInterface);
ASSERT(IS_HW_DEVICE_EXTENSION(pHwDeviceExtension) == TRUE);
if (VideoPortServicesAGP == servicesType)
{
if ((pInterface->Version == VIDEO_PORT_AGP_INTERFACE_VERSION_2) &&
(pInterface->Size == sizeof (VIDEO_PORT_AGP_INTERFACE_2)))
{
PVIDEO_PORT_AGP_INTERFACE_2 pAgpInterface = (PVIDEO_PORT_AGP_INTERFACE_2)pInterface;
vpStatus = VpGetAgpServices2(pHwDeviceExtension, pAgpInterface);
}
else if ((pInterface->Version == VIDEO_PORT_AGP_INTERFACE_VERSION_1) &&
(pInterface->Size == sizeof (VIDEO_PORT_AGP_INTERFACE)))
{
PVIDEO_PORT_AGP_INTERFACE pAgpInterface = (PVIDEO_PORT_AGP_INTERFACE)pInterface;
pAgpInterface->Context = pHwDeviceExtension;
pAgpInterface->InterfaceReference = VpInterfaceDefaultReference;
pAgpInterface->InterfaceDereference = VpInterfaceDefaultDereference;
if (VideoPortGetAgpServices(pHwDeviceExtension,
(PVIDEO_PORT_AGP_SERVICES)&(pAgpInterface->AgpReservePhysical)) == TRUE)
{
//
// Reference the interface before handing it out.
//
pAgpInterface->InterfaceReference(pAgpInterface->Context);
vpStatus = NO_ERROR;
}
else
{
vpStatus = ERROR_DEV_NOT_EXIST;
}
}
else
{
pVideoDebugPrint((Warn, "VIDEOPRT: VideoPortQueryServices: Unsupported interface version\n"));
vpStatus = ERROR_INVALID_PARAMETER;
}
}
else if (VideoPortServicesI2C == servicesType)
{
if ((pInterface->Version == VIDEO_PORT_I2C_INTERFACE_VERSION_2) &&
(pInterface->Size == sizeof (VIDEO_PORT_I2C_INTERFACE_2)))
{
PVIDEO_PORT_I2C_INTERFACE_2 pI2CInterface = (PVIDEO_PORT_I2C_INTERFACE_2)pInterface;
pI2CInterface->Context = pHwDeviceExtension;
pI2CInterface->InterfaceReference = VpInterfaceDefaultReference;
pI2CInterface->InterfaceDereference = VpInterfaceDefaultDereference;
pI2CInterface->I2CStart = I2CStart2;
pI2CInterface->I2CStop = I2CStop2;
pI2CInterface->I2CWrite = I2CWrite2;
pI2CInterface->I2CRead = I2CRead2;
//
// Reference the interface before handing it out.
//
pI2CInterface->InterfaceReference(pI2CInterface->Context);
vpStatus = NO_ERROR;
}
else if ((pInterface->Version == VIDEO_PORT_I2C_INTERFACE_VERSION_1) &&
(pInterface->Size == sizeof (VIDEO_PORT_I2C_INTERFACE)))
{
PVIDEO_PORT_I2C_INTERFACE pI2CInterface = (PVIDEO_PORT_I2C_INTERFACE)pInterface;
pI2CInterface->Context = pHwDeviceExtension;
pI2CInterface->InterfaceReference = VpInterfaceDefaultReference;
pI2CInterface->InterfaceDereference = VpInterfaceDefaultDereference;
pI2CInterface->I2CStart = I2CStart;
pI2CInterface->I2CStop = I2CStop;
pI2CInterface->I2CWrite = I2CWrite;
pI2CInterface->I2CRead = I2CRead;
//
// Reference the interface before handing it out.
//
pI2CInterface->InterfaceReference(pI2CInterface->Context);
vpStatus = NO_ERROR;
}
else
{
pVideoDebugPrint((Warn, "VIDEOPRT: VideoPortQueryServices: Unsupported interface version\n"));
vpStatus = ERROR_INVALID_PARAMETER;
}
}
else if (VideoPortServicesInt10 == servicesType)
{
if ((pInterface->Version == VIDEO_PORT_INT10_INTERFACE_VERSION_1) &&
(pInterface->Size == sizeof(VIDEO_PORT_INT10_INTERFACE)))
{
PVIDEO_PORT_INT10_INTERFACE pInt10 = (PVIDEO_PORT_INT10_INTERFACE)pInterface;
pInt10->Context = pHwDeviceExtension;
pInt10->InterfaceReference = VpInterfaceDefaultReference;
pInt10->InterfaceDereference = VpInterfaceDefaultDereference;
pInt10->Int10AllocateBuffer = VpInt10AllocateBuffer;
pInt10->Int10FreeBuffer = VpInt10FreeBuffer;
pInt10->Int10ReadMemory = VpInt10ReadMemory;
pInt10->Int10WriteMemory = VpInt10WriteMemory;
pInt10->Int10CallBios = VpInt10CallBios;
//
// Reference the interface before handing it out.
//
pInt10->InterfaceReference(pInt10->Context);
vpStatus = NO_ERROR;
}
else
{
pVideoDebugPrint((Warn, "VIDEOPRT: VideoPortQueryServices: Unsupported interface version\n"));
vpStatus = ERROR_INVALID_PARAMETER;
}
}
else
{
pVideoDebugPrint((Warn, "VIDEOPRT: VideoPortQueryServices: Unsupported service type\n"));
vpStatus = ERROR_INVALID_PARAMETER;
}
return vpStatus;
} // VideoPortQueryServices()
VIDEOPORT_API
LONGLONG
VideoPortQueryPerformanceCounter(
IN PVOID pHwDeviceExtension,
OUT PLONGLONG pllPerformanceFrequency OPTIONAL
)
/*++
Routine Description:
This routine provides the finest grained running count available in the system.
Use this routine as infrequently as possible. Depending on the platform,
VideoPortQueryPerformanceCounter can disable system-wide interrupts for a minimal interval.
Consequently, calling this routine frequently or repeatedly, as in an iteration, defeats its
purpose of returning very fine-grained, running time-stamp information. Calling this routine
too frequently can degrade I/O performance for the calling driver and for the system as a whole.
Arguments:
pHwDeviceExtension - Points to per-adapter device extension.
pllPerformanceFrequency - Specifies an optional pointer to a variable that is to receive the
performance counter frequency.
Returns:
The performance counter value in units of ticks.
--*/
{
LARGE_INTEGER li;
//
// No ASSERT() allowed - nonpagable code.
//
li = KeQueryPerformanceCounter((PLARGE_INTEGER)pllPerformanceFrequency);
return *((PLONGLONG) &li);
} // VideoPortQueryPerformanceCounter()
VOID
VpInterfaceDefaultReference(
IN PVOID pContext
)
/*++
Routine Description:
This routine is default callback for interfaces exposed from the videoprt.
Should be called by the client before it starts using an interface.
Arguments:
pContext - Context returned by the VideoPortQueryServices() in the
pInterface->Context field.
--*/
{
UNREFERENCED_PARAMETER(pContext);
PAGED_CODE();
} // VpInterfaceDefaultReference()
VOID
VpInterfaceDefaultDereference(
IN PVOID pContext
)
/*++
Routine Description:
This routine is default callback for interfaces exposed from the videoprt.
Should be called by the client when it stops using an interface.
Arguments:
pContext - Context returned by the VideoPortQueryServices() in the
pInterface->Context field.
--*/
{
UNREFERENCED_PARAMETER(pContext);
PAGED_CODE();
} // VpInterfaceDefaultDereference()
BOOLEAN
VpEnableAdapterInterface(
PDEVICE_SPECIFIC_EXTENSION DoSpecificExtension
)
/*++
Routine Description:
This routine registers and enables a display adapter interface.
It also writes the interface name to the registry.
Arguments:
DoSpecificExtension - Pointer to the functional device object
specific extension.
--*/
{
PFDO_EXTENSION fdoExtension = NULL;
UNICODE_STRING SymbolicLinkName;
BOOLEAN Success = FALSE;
UNICODE_STRING VolatileSettingsString;
OBJECT_ATTRIBUTES VolatileSettingsAttributes;
HANDLE VolatileSettingsKey;
PAGED_CODE();
ASSERT ((DoSpecificExtension != NULL) &&
(DoSpecificExtension->ExtensionType == TypeDeviceSpecificExtension));
VolatileSettingsString.Buffer = NULL;
fdoExtension = DoSpecificExtension->pFdoExtension;
ASSERT (IS_FDO(fdoExtension));
if (fdoExtension->PhysicalDeviceObject == NULL) {
//
// This fdo doesn't have a physical device object (e.g. vga).
// In this case, we can't create an interface.
//
goto Fallout;
}
//
// Register the interface
//
if (IoRegisterDeviceInterface(fdoExtension->PhysicalDeviceObject,
&GUID_DISPLAY_ADAPTER_INTERFACE,
NULL,
&SymbolicLinkName) != STATUS_SUCCESS) {
goto Fallout;
}
//
// Enable the interface
//
if (IoSetDeviceInterfaceState(&SymbolicLinkName, TRUE) != STATUS_SUCCESS) {
goto Cleanup;
}
//
// Write the interface name to registry
//
ASSERT (DoSpecificExtension->DriverRegistryPath != NULL);
VolatileSettingsString.Length = 0;
VolatileSettingsString.MaximumLength =
(USHORT)DoSpecificExtension->DriverRegistryPathLength + 40;
VolatileSettingsString.Buffer = ExAllocatePoolWithTag(
PagedPool | POOL_COLD_ALLOCATION,
VolatileSettingsString.MaximumLength,
VP_TAG);
if (VolatileSettingsString.Buffer == NULL) {
goto Cleanup;
}
if (RtlAppendUnicodeToString(&VolatileSettingsString,
DoSpecificExtension->DriverRegistryPath) != STATUS_SUCCESS) {
goto Cleanup;
}
if (RtlAppendUnicodeToString(&VolatileSettingsString,
L"\\VolatileSettings") != STATUS_SUCCESS) {
goto Cleanup;
}
InitializeObjectAttributes(&VolatileSettingsAttributes,
&VolatileSettingsString,
OBJ_CASE_INSENSITIVE,
NULL,
NULL);
if (ZwCreateKey(&VolatileSettingsKey,
GENERIC_READ | GENERIC_WRITE,
&VolatileSettingsAttributes,
0L,
NULL,
REG_OPTION_VOLATILE,
NULL) != STATUS_SUCCESS) {
goto Cleanup;
}
if (RtlWriteRegistryValue(
RTL_REGISTRY_ABSOLUTE,
VolatileSettingsString.Buffer,
L"{5b45201d-f2f2-4f3b-85bb-30ff1f953599}",
REG_BINARY,
(PVOID)SymbolicLinkName.Buffer,
SymbolicLinkName.Length) == STATUS_SUCCESS) {
Success = TRUE;
}
Cleanup:
if (VolatileSettingsString.Buffer != NULL) {
ExFreePool(VolatileSettingsString.Buffer);
}
RtlFreeUnicodeString(&SymbolicLinkName);
Fallout:
if (Success) {
pVideoDebugPrint((Trace, "VideoPort - Device interface ok.\n"));
} else {
pVideoDebugPrint((Warn,
"VideoPort - Couldn't register, enable or save the device interface.\n"));
}
return Success;
} // VpEnableAdapterInterface
VOID
VpDisableAdapterInterface(
PFDO_EXTENSION fdoExtension
)
/*++
Routine Description:
This routine disables the display adapter interface.
Arguments:
fdoExtension - Pointer to the functional device object extension.
--*/
{
PWSTR SymbolicLinkList = NULL;
UNICODE_STRING SymbolicLinkName;
PAGED_CODE();
ASSERT ((fdoExtension != NULL) && IS_FDO(fdoExtension));
if (fdoExtension->PhysicalDeviceObject == NULL) {
//
// This fdo doesn't have a physical device object (e.g. vga ...).
// In this case, we didn't create any interface so there is
// nothing to disable.
//
return;
}
//
// There is no need to remove the InterfaceName from the registry
// as the parent key is volatile.
//
//
// Disable the interface
//
if (IoGetDeviceInterfaces(&GUID_DISPLAY_ADAPTER_INTERFACE,
fdoExtension->PhysicalDeviceObject,
0,
&SymbolicLinkList) != STATUS_SUCCESS) {
pVideoDebugPrint((Warn,
"VideoPort - Could not find any enabled device interfaces.\n"));
return;
}
RtlInitUnicodeString(&SymbolicLinkName, SymbolicLinkList);
if (SymbolicLinkName.Length > 0) {
if (IoSetDeviceInterfaceState(&SymbolicLinkName,
FALSE) != STATUS_SUCCESS) {
pVideoDebugPrint((Warn,
"VideoPort - Could not disable the device interface.\n"));
}
}
ExFreePool((PVOID)SymbolicLinkList);
} // VpDisableAdapterInterface
VOID
VpEnableNewRegistryKey(
PFDO_EXTENSION FdoExtension,
PDEVICE_SPECIFIC_EXTENSION DoSpecificExtension,
PUNICODE_STRING RegistryPath,
ULONG RegistryIndex
)
{
PKEY_VALUE_PARTIAL_INFORMATION GUIDBuffer = NULL;
ULONG GUIDLength = 0;
LPWSTR Buffer = NULL;
HANDLE GuidKey = NULL;
HANDLE NewDeviceKey = NULL;
HANDLE ServiceSubKey = NULL;
UNICODE_STRING UnicodeString, newGuidStr;
OBJECT_ATTRIBUTES ObjectAttributes;
ULONG Len;
GUID newGuid;
BOOLEAN IsLegacy = FALSE;
NTSTATUS ntStatus = STATUS_UNSUCCESSFUL;
BOOLEAN IsNewKey = FALSE;
PWSTR pService = NULL;
ULONG ServiceLen = 0;
ASSERT((DoSpecificExtension->DriverNewRegistryPath == NULL) &&
(DoSpecificExtension->DriverNewRegistryPathLength == 0));
ASSERT(DoSpecificExtension->DriverOldRegistryPath != NULL);
ASSERT(EnableNewRegistryKey);
newGuidStr.Buffer = NULL;
//
// Get the service name
//
pService = RegistryPath->Buffer +
(RegistryPath->Length / sizeof(WCHAR)) - 1;
while ((pService > RegistryPath->Buffer) &&
(*pService != L'\\')) {
pService--;
ServiceLen++;
}
ASSERT (*pService == L'\\');
pService++;
Buffer = (LPWSTR)ExAllocatePoolWithTag(PagedPool | POOL_COLD_ALLOCATION,
(ServiceLen + 1) * sizeof(WCHAR),
VP_TAG);
if (Buffer == NULL) {
pVideoDebugPrint((Error,
"VIDEOPRT: VpEnableNewRegistryKey: failed to allocate memory.\n"));
goto Fallout;
}
RtlZeroMemory(Buffer, (ServiceLen + 1) * sizeof(WCHAR));
wcsncpy(Buffer, pService, ServiceLen);
pService = Buffer;
Buffer = NULL;
//
// Try to open the PnP device key
//
if ((FdoExtension->PhysicalDeviceObject == NULL) ||
(IoOpenDeviceRegistryKey(FdoExtension->PhysicalDeviceObject,
PLUGPLAY_REGKEY_DEVICE,
KEY_READ | KEY_WRITE,
&GuidKey) != STATUS_SUCCESS)) {
//
// We failed to open the PnP device key.
// Try to open the service subkey instead.
//
if (!VpGetServiceSubkey(RegistryPath,
&GuidKey)) {
GuidKey = NULL;
goto Fallout;
}
IsLegacy = TRUE;
}
//
// Is the GUID there?
//
RtlInitUnicodeString(&UnicodeString, SZ_GUID);
ntStatus = ZwQueryValueKey(GuidKey,
&UnicodeString,
KeyValuePartialInformation,
(PVOID)NULL,
0,
&GUIDLength);
if ((ntStatus == STATUS_BUFFER_OVERFLOW) ||
(ntStatus == STATUS_BUFFER_TOO_SMALL)) {
//
// The GUID is there.
// Allocate a buffer large enough to contain the entire key data value.
//
GUIDBuffer = ExAllocatePoolWithTag(PagedPool | POOL_COLD_ALLOCATION,
GUIDLength,
VP_TAG);
if (GUIDBuffer == NULL) {
pVideoDebugPrint((Error,
"VIDEOPRT: VpEnableNewRegistryKey: failed to allocate memory.\n"));
goto Fallout;
}
//
// Get the GUID from the registry
//
ntStatus = ZwQueryValueKey(GuidKey,
&UnicodeString,
KeyValuePartialInformation,
GUIDBuffer,
GUIDLength,
&GUIDLength);
if (!NT_SUCCESS(ntStatus)) {
pVideoDebugPrint((Error,
"VIDEOPRT: VpEnableNewRegistryKey: failed to get the GUID from the registry.\n"));
goto Fallout;
}
//
// Build the new registry path
//
Len = (wcslen(SZ_VIDEO_DEVICES) + 8) * sizeof(WCHAR) + GUIDBuffer->DataLength;
Buffer = (LPWSTR)ExAllocatePoolWithTag(PagedPool | POOL_COLD_ALLOCATION,
Len,
VP_TAG);
if (Buffer == NULL) {
pVideoDebugPrint((Error,
"VIDEOPRT: VpEnableNewRegistryKey: failed to allocate memory.\n"));
goto Fallout;
}
RtlZeroMemory(Buffer, Len);
wcscpy(Buffer, SZ_VIDEO_DEVICES);
wcscat(Buffer, L"\\");
wcsncpy(Buffer + wcslen(Buffer),
(LPWSTR)GUIDBuffer->Data,
GUIDBuffer->DataLength / sizeof(WCHAR));
ASSERT (RegistryIndex <= 9999);
swprintf(Buffer + wcslen(Buffer), L"\\%04d", RegistryIndex);
//
// Is the key already there?
//
if (RtlCheckRegistryKey(RTL_REGISTRY_ABSOLUTE,
Buffer) != STATUS_SUCCESS) {
//
// Create the new key
//
if (RtlCreateRegistryKey(RTL_REGISTRY_ABSOLUTE,
Buffer) != STATUS_SUCCESS) {
pVideoDebugPrint((Error,
"VIDEOPRT: VpEnableNewRegistryKey: failed to create the new key.\n"));
goto Fallout;
}
//
// Initialize the key
//
if (IsLegacy) {
VpInitializeLegacyKey(DoSpecificExtension->DriverOldRegistryPath,
Buffer);
} else {
VpInitializeKey(FdoExtension->PhysicalDeviceObject,
Buffer);
}
}
} else {
//
// The GUID is not there so allocate a new one
//
// !!! Add special case for VGA, MNMDD & RDPCDD
//
ntStatus = ExUuidCreate(&newGuid);
if ((ntStatus != STATUS_SUCCESS) &&
(ntStatus != RPC_NT_UUID_LOCAL_ONLY)) {
pVideoDebugPrint((Error,
"VIDEOPRT: VpEnableNewRegistryKey: failed to create a new GUID.\n"));
goto Fallout;
}
if (RtlStringFromGUID(&newGuid, &newGuidStr) != STATUS_SUCCESS) {
pVideoDebugPrint((Error,
"VIDEOPRT: VpEnableNewRegistryKey: failed to convert the GUID to a string.\n"));
newGuidStr.Buffer = NULL;
goto Fallout;
}
//
// Upcase the string
//
RtlUpcaseUnicodeString(&newGuidStr, &newGuidStr, FALSE);
//
// Build the new registry path
//
Len = (wcslen(SZ_VIDEO_DEVICES) +
wcslen(newGuidStr.Buffer) +
wcslen(SZ_COMMON_SUBKEY) + 8) * sizeof(WCHAR);
Buffer = (LPWSTR)ExAllocatePoolWithTag(PagedPool | POOL_COLD_ALLOCATION,
Len,
VP_TAG);
if (Buffer == NULL) {
pVideoDebugPrint((Error,
"VIDEOPRT: VpEnableNewRegistryKey: failed to allocate memory.\n"));
goto Fallout;
}
RtlZeroMemory(Buffer, Len);
wcscpy(Buffer, SZ_VIDEO_DEVICES);
if (RtlCreateRegistryKey(RTL_REGISTRY_ABSOLUTE,
Buffer) != STATUS_SUCCESS) {
pVideoDebugPrint((Error,
"VIDEOPRT: VpEnableNewRegistryKey: failed to create the new key.\n"));
goto Fallout;
}
wcscat(Buffer, L"\\");
wcscat(Buffer, newGuidStr.Buffer);
if (RtlCreateRegistryKey(RTL_REGISTRY_ABSOLUTE,
Buffer) != STATUS_SUCCESS) {
pVideoDebugPrint((Error,
"VIDEOPRT: VpEnableNewRegistryKey: failed to create the new key.\n"));
goto Fallout;
}
//
// Save the service name
//
Len = wcslen(Buffer);
wcscat(Buffer, L"\\");
wcscat(Buffer, SZ_COMMON_SUBKEY);
if (RtlCreateRegistryKey(RTL_REGISTRY_ABSOLUTE,
Buffer) != STATUS_SUCCESS) {
pVideoDebugPrint((Error,
"VIDEOPRT: VpEnableNewRegistryKey: failed to create the new key.\n"));
goto Fallout;
}
if (RtlWriteRegistryValue(
RTL_REGISTRY_ABSOLUTE,
Buffer,
SZ_SERVICE,
REG_SZ,
(PVOID)pService,
(ServiceLen + 1) * sizeof(WCHAR)) != STATUS_SUCCESS) {
pVideoDebugPrint((Error,
"VIDEOPRT: VpEnableNewRegistryKey: failed to save the service name.\n"));
goto Fallout;
}
if (IsLegacy) {
ServiceSubKey = GuidKey;
} else {
if (!VpGetServiceSubkey(RegistryPath,
&ServiceSubKey)) {
ServiceSubKey = NULL;
}
}
if (ServiceSubKey != NULL) {
if (RtlWriteRegistryValue(RTL_REGISTRY_HANDLE,
ServiceSubKey,
SZ_SERVICE,
REG_SZ,
(PVOID)pService,
(ServiceLen + 1) * sizeof(WCHAR)) != STATUS_SUCCESS) {
pVideoDebugPrint((Error,
"VIDEOPRT: VpEnableNewRegistryKey: failed to save the service name.\n"));
goto Fallout;
}
}
//
// Create the 000X subkey
//
Buffer[Len] = 0;
ASSERT (RegistryIndex == 0);
wcscat(Buffer, L"\\0000");
if (RtlCreateRegistryKey(RTL_REGISTRY_ABSOLUTE,
Buffer) != STATUS_SUCCESS) {
pVideoDebugPrint((Error,
"VIDEOPRT: VpEnableNewRegistryKey: failed to create the new key.\n"));
goto Fallout;
}
//
// Save the new key under the PnP device key or the service subkey
//
if (RtlWriteRegistryValue(RTL_REGISTRY_HANDLE,
GuidKey,
SZ_GUID,
REG_SZ,
(PVOID)newGuidStr.Buffer,
(wcslen(newGuidStr.Buffer) + 1) * sizeof(WCHAR)) != STATUS_SUCCESS) {
pVideoDebugPrint((Error,
"VIDEOPRT: VpEnableNewRegistryKey: failed to write the new GUID to the registry.\n"));
goto Fallout;
}
//
// The key was not there, so initialize it.
//
if (IsLegacy) {
VpInitializeLegacyKey(DoSpecificExtension->DriverOldRegistryPath,
Buffer);
} else {
VpInitializeKey(FdoExtension->PhysicalDeviceObject,
Buffer);
}
}
pVideoDebugPrint((Info, "VIDEOPRT: VpEnableNewRegistryKey: %ws\n", Buffer));
//
// Initialize the new registry path fields
//
DoSpecificExtension->DriverNewRegistryPath = Buffer;
DoSpecificExtension->DriverNewRegistryPathLength = wcslen(Buffer) * sizeof(WCHAR);
Fallout:
//
// Cleanup
//
if (GUIDBuffer != NULL) {
ExFreePool(GUIDBuffer);
}
if (newGuidStr.Buffer != NULL) {
RtlFreeUnicodeString(&newGuidStr);
}
if ((DoSpecificExtension->DriverNewRegistryPath == NULL) &&
(Buffer != NULL)) {
ExFreePool(Buffer);
}
if (GuidKey != NULL) {
ZwClose(GuidKey);
}
if (!IsLegacy && (ServiceSubKey != NULL)) {
ZwClose(ServiceSubKey);
}
if (pService != NULL) {
ExFreePool(pService);
}
return;
} // VpEnableNewRegistryKey
VOID
VpInitializeKey(
PDEVICE_OBJECT PhysicalDeviceObject,
PWSTR NewRegistryPath
)
{
HANDLE NewDeviceKey = NULL;
HANDLE DriverKey = NULL;
HANDLE DriverSettingsKey = NULL;
UNICODE_STRING UnicodeString;
OBJECT_ATTRIBUTES ObjectAttributes;
ASSERT (PhysicalDeviceObject != NULL);
ASSERT (NewRegistryPath != NULL);
//
// Open the new key
//
RtlInitUnicodeString(&UnicodeString, NewRegistryPath);
InitializeObjectAttributes(&ObjectAttributes,
&UnicodeString,
OBJ_CASE_INSENSITIVE,
NULL,
NULL);
if (ZwOpenKey(&NewDeviceKey,
KEY_ALL_ACCESS,
&ObjectAttributes) != STATUS_SUCCESS) {
pVideoDebugPrint((Error,
"VIDEOPRT: VpInitializeKey: failed to open the new key.\n"));
NewDeviceKey = NULL;
goto Fallout;
}
//
// Open the PnP driver key
//
if (IoOpenDeviceRegistryKey(PhysicalDeviceObject,
PLUGPLAY_REGKEY_DRIVER,
KEY_READ | KEY_WRITE,
&DriverKey) != STATUS_SUCCESS) {
pVideoDebugPrint((Error,
"VIDEOPRT: VpInitializeKey: could not open the driver key.\n"));
DriverKey = NULL;
goto Fallout;
}
RtlInitUnicodeString(&UnicodeString, SZ_INITIAL_SETTINGS);
InitializeObjectAttributes(&ObjectAttributes,
&UnicodeString,
OBJ_CASE_INSENSITIVE,
DriverKey,
NULL);
//
// Open the "Settings" key.
// The class installer saved the initial settings there.
//
if (ZwOpenKey(&DriverSettingsKey,
GENERIC_READ | GENERIC_WRITE,
&ObjectAttributes) != STATUS_SUCCESS) {
pVideoDebugPrint((Error,
"VIDEOPRT: VpInitializeKey: failed to open the driver settings key.\n"));
DriverSettingsKey = NULL;
goto Fallout;
}
//
// Copy the settings
//
VpCopyRegistry(DriverSettingsKey,
NewDeviceKey,
NULL,
NULL);
Fallout:
if (DriverSettingsKey != NULL) {
ZwClose(DriverSettingsKey);
}
if (DriverKey != NULL) {
ZwClose(DriverKey);
}
if (NewDeviceKey != NULL) {
ZwClose(NewDeviceKey);
}
} // VpInitializeKey
VOID
VpInitializeLegacyKey(
PWSTR OldRegistryPath,
PWSTR NewRegistryPath
)
{
HANDLE NewDeviceKey = NULL;
HANDLE OldDeviceKey = NULL;
UNICODE_STRING UnicodeString;
OBJECT_ATTRIBUTES ObjectAttributes;
ASSERT (NewRegistryPath != NULL);
//
// Open the new key
//
RtlInitUnicodeString(&UnicodeString, NewRegistryPath);
InitializeObjectAttributes(&ObjectAttributes,
&UnicodeString,
OBJ_CASE_INSENSITIVE,
NULL,
NULL);
if (ZwOpenKey(&NewDeviceKey,
KEY_ALL_ACCESS,
&ObjectAttributes) != STATUS_SUCCESS) {
pVideoDebugPrint((Error,
"VIDEOPRT: VpInitializeLegacyKey: failed to open the new key.\n"));
NewDeviceKey = NULL;
goto Fallout;
}
//
// Open the old key
//
RtlInitUnicodeString(&UnicodeString,
OldRegistryPath);
InitializeObjectAttributes(&ObjectAttributes,
&UnicodeString,
OBJ_CASE_INSENSITIVE,
NULL,
NULL);
if (ZwOpenKey(&OldDeviceKey,
GENERIC_READ | GENERIC_WRITE,
&ObjectAttributes) != STATUS_SUCCESS) {
pVideoDebugPrint((Error,
"VIDEOPRT: VpInitializeLegacyKey: failed to open the old key.\n"));
OldDeviceKey = NULL;
goto Fallout;
}
//
// Copy the settings
//
VpCopyRegistry(OldDeviceKey,
NewDeviceKey,
NULL,
NULL);
Fallout:
if (NewDeviceKey != NULL) {
ZwClose(NewDeviceKey);
}
if (OldDeviceKey != NULL) {
ZwClose(OldDeviceKey);
}
} // VpInitializeLegacyKey
NTSTATUS
VpCopyRegistry(
HANDLE hKeyRootSrc,
HANDLE hKeyRootDst,
PWSTR SrcKeyPath,
PWSTR DstKeyPath
)
/*++
Routine Description:
This routine recursively copies a src key to a destination key.
Arguments:
hKeyRootSrc: Handle to root src key
hKeyRootDst: Handle to root dst key
SrcKeyPath: src root key relative path to the subkey which needs to be
recursively copied. if this is null SourceKey is the key
from which the recursive copy is to be done.
DstKeyPath: dst root key relative path to the subkey which needs to be
recursively copied. if this is null DestinationKey is the key
from which the recursive copy is to be done.
Return Value:
Status is returned.
--*/
{
NTSTATUS Status = STATUS_SUCCESS;
OBJECT_ATTRIBUTES ObjectAttributes;
UNICODE_STRING UnicodeString;
HANDLE hKeySrc = NULL, hKeyDst = NULL;
ULONG ResultLength, Index;
PKEY_BASIC_INFORMATION KeyInfo;
PKEY_VALUE_FULL_INFORMATION ValueInfo;
PWSTR ValueName;
ULONG BufferSize = 512;
PVOID Buffer = NULL;
//
// Get a handle to the source key
//
if(SrcKeyPath == NULL) {
hKeySrc = hKeyRootSrc;
} else {
//
// Open the Src key
//
RtlInitUnicodeString(&UnicodeString, SrcKeyPath);
InitializeObjectAttributes(&ObjectAttributes,
&UnicodeString,
OBJ_CASE_INSENSITIVE,
hKeyRootSrc,
NULL);
Status = ZwOpenKey(&hKeySrc,
KEY_READ,
&ObjectAttributes);
if(!NT_SUCCESS(Status)) {
pVideoDebugPrint((Error,
"VIDEOPRT: VpCopyRegistry: failed to open the source key.\n"));
hKeySrc = NULL;
goto Fallout;
}
}
//
// Get a handle to the destination key
//
if(DstKeyPath == NULL) {
hKeyDst = hKeyRootDst;
} else {
//
// Create the destination key.
//
RtlInitUnicodeString(&UnicodeString, DstKeyPath);
InitializeObjectAttributes(&ObjectAttributes,
&UnicodeString,
OBJ_CASE_INSENSITIVE,
hKeyRootDst,
NULL);
Status = ZwCreateKey(&hKeyDst,
GENERIC_READ | GENERIC_WRITE,
&ObjectAttributes,
0,
NULL,
REG_OPTION_NON_VOLATILE,
NULL);
if (!NT_SUCCESS(Status)) {
pVideoDebugPrint((Error,
"VIDEOPRT: VpCopyRegistry: failed to create the destination key.\n"));
hKeyDst = NULL;
goto Fallout;
}
}
//
// Enumerate all keys in the source key and recursively
// create all subkeys
//
for (Index = 0; ;Index++) {
do {
if (Buffer == NULL) {
Buffer = ExAllocatePoolWithTag(PagedPool,
BufferSize,
VP_TAG);
if (Buffer == NULL) {
pVideoDebugPrint((Error,
"VIDEOPRT: VpCopyRegistry: failed to allocate memory.\n"));
goto Fallout;
}
}
Status = ZwEnumerateKey(hKeySrc,
Index,
KeyBasicInformation,
Buffer,
BufferSize - sizeof(WCHAR),
&ResultLength);
if (Status == STATUS_BUFFER_TOO_SMALL) {
ExFreePool(Buffer);
Buffer = NULL;
BufferSize = ResultLength + sizeof(WCHAR);
}
} while (Status == STATUS_BUFFER_TOO_SMALL);
KeyInfo = (PKEY_BASIC_INFORMATION)Buffer;
if (!NT_SUCCESS(Status)) {
if(Status == STATUS_NO_MORE_ENTRIES) {
Status = STATUS_SUCCESS;
} else {
pVideoDebugPrint((Error,
"VIDEOPRT: VpCopyRegistry: failed to enumerate the subkeys.\n"));
}
break;
}
//
// Zero-terminate the subkey name
//
KeyInfo->Name[KeyInfo->NameLength / sizeof(WCHAR)] = 0;
//
// Copy the subkey
//
Status = VpCopyRegistry(hKeySrc,
hKeyDst,
KeyInfo->Name,
KeyInfo->Name);
}
//
// Enumerate all values in the source key and create all the values
// in the destination key
//
for(Index = 0; ;Index++) {
do {
if (Buffer == NULL) {
Buffer = ExAllocatePoolWithTag(PagedPool,
BufferSize,
VP_TAG);
if (Buffer == NULL) {
pVideoDebugPrint((Error,
"VIDEOPRT: VpCopyRegistry: failed to allocate memory.\n"));
goto Fallout;
}
}
Status = ZwEnumerateValueKey(hKeySrc,
Index,
KeyValueFullInformation,
Buffer,
BufferSize,
&ResultLength);
if (Status == STATUS_BUFFER_TOO_SMALL) {
ExFreePool(Buffer);
Buffer = NULL;
BufferSize = ResultLength;
}
} while (Status == STATUS_BUFFER_TOO_SMALL);
ValueInfo = (PKEY_VALUE_FULL_INFORMATION)Buffer;
if(!NT_SUCCESS(Status)) {
if(Status == STATUS_NO_MORE_ENTRIES) {
Status = STATUS_SUCCESS;
} else {
pVideoDebugPrint((Error,
"VIDEOPRT: VpCopyRegistry: failed to enumerate the values.\n"));
}
break;
}
//
// Process the value found and create the value in the destination key
//
ValueName = (PWSTR)
ExAllocatePoolWithTag(PagedPool,
ValueInfo->NameLength + sizeof(WCHAR),
VP_TAG);
if (ValueName == NULL) {
pVideoDebugPrint((Error,
"VIDEOPRT: VpCopyRegistry: failed to allocate memory.\n"));
goto Fallout;
}
wcsncpy(ValueName,
ValueInfo->Name,
(ValueInfo->NameLength)/sizeof(WCHAR));
ValueName[(ValueInfo->NameLength)/sizeof(WCHAR)] = 0;
RtlInitUnicodeString(&UnicodeString, ValueName);
Status = ZwSetValueKey(hKeyDst,
&UnicodeString,
ValueInfo->TitleIndex,
ValueInfo->Type,
(PVOID)((PUCHAR)ValueInfo + ValueInfo->DataOffset),
ValueInfo->DataLength);
if(!NT_SUCCESS(Status)) {
pVideoDebugPrint((Error,
"VIDEOPRT: VpCopyRegistry: failed to set the value.\n"));
}
ExFreePool(ValueName);
}
Fallout:
//
// Cleanup
//
if (Buffer != NULL) {
ExFreePool(Buffer);
}
if ((hKeySrc != NULL) && (hKeySrc != hKeyRootSrc)) {
ZwClose(hKeySrc);
}
if ((hKeyDst != NULL) && (hKeyDst != hKeyRootDst)) {
ZwClose(hKeyDst);
}
return(Status);
} // VpCopyRegistry
BOOLEAN
VpGetServiceSubkey(
PUNICODE_STRING RegistryPath,
HANDLE* pServiceSubKey
)
{
LPWSTR Buffer = NULL;
USHORT Len = 0;
OBJECT_ATTRIBUTES ObjectAttributes;
UNICODE_STRING UnicodeString;
BOOLEAN bSuccess = FALSE;
Len = RegistryPath->Length + (wcslen(SZ_COMMON_SUBKEY) + 2) * sizeof(WCHAR);
Buffer = (LPWSTR)ExAllocatePoolWithTag(PagedPool | POOL_COLD_ALLOCATION, Len, VP_TAG);
if (Buffer == NULL) {
pVideoDebugPrint((Error,
"VIDEOPRT: VpGetServiceSubkey: failed to allocate memory.\n"));
goto Fallout;
}
RtlZeroMemory(Buffer, Len);
wcsncpy(Buffer,
RegistryPath->Buffer,
RegistryPath->Length / sizeof(WCHAR));
wcscat(Buffer, L"\\");
wcscat(Buffer, SZ_COMMON_SUBKEY);
RtlInitUnicodeString(&UnicodeString, Buffer);
InitializeObjectAttributes(&ObjectAttributes,
&UnicodeString,
OBJ_CASE_INSENSITIVE,
NULL,
NULL);
if (ZwCreateKey(pServiceSubKey,
GENERIC_READ | GENERIC_WRITE,
&ObjectAttributes,
0,
NULL,
REG_OPTION_NON_VOLATILE,
NULL) != STATUS_SUCCESS) {
pVideoDebugPrint((Error,
"VIDEOPRT: VpGetServiceSubkey: could not create the service subkey.\n"));
goto Fallout;
}
bSuccess = TRUE;
Fallout:
if (Buffer != NULL) {
ExFreePool(Buffer);
}
return bSuccess;
} // VpGetServiceSubkey
VP_STATUS
VideoPortGetVersion(
PVOID HwDeviceExtension,
PVPOSVERSIONINFO pVpOsVersionInfo
)
{
RTL_OSVERSIONINFOEXW VersionInformation;
UNREFERENCED_PARAMETER(HwDeviceExtension);
if(pVpOsVersionInfo->Size < sizeof(VPOSVERSIONINFO)) {
return ERROR_INVALID_PARAMETER;
}
RtlZeroMemory ((PVOID)(&VersionInformation), sizeof(RTL_OSVERSIONINFOEXW));
VersionInformation.dwOSVersionInfoSize = sizeof(RTL_OSVERSIONINFOEXW);
if ( STATUS_SUCCESS !=
RtlGetVersion( (PRTL_OSVERSIONINFOW) (&VersionInformation)) ) {
return ERROR_INVALID_PARAMETER;
}
pVpOsVersionInfo->MajorVersion = VersionInformation.dwMajorVersion;
pVpOsVersionInfo->MinorVersion = VersionInformation.dwMinorVersion;
pVpOsVersionInfo->BuildNumber = VersionInformation.dwBuildNumber;
pVpOsVersionInfo->ServicePackMajor = VersionInformation.wServicePackMajor;
pVpOsVersionInfo->ServicePackMinor = VersionInformation.wServicePackMinor;
return NO_ERROR;
}