4 * Copyright (C) 2002-2004, 2007 ReactOS Team
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
25 #include <ndk/exfuncs.h>
26 #include <ndk/rtlfuncs.h>
31 /* GLOBAL VARIABLES ***********************************************************/
33 PKPROCESS CsrProcess
= NULL
;
34 ULONG VideoPortDeviceNumber
= 0;
35 KMUTEX VideoPortInt10Mutex
;
36 KSPIN_LOCK HwResetAdaptersLock
;
37 RTL_STATIC_LIST_HEAD(HwResetAdaptersList
);
39 /* PRIVATE FUNCTIONS **********************************************************/
47 return STATUS_SUCCESS
;
52 IntVideoPortImageDirectoryEntryToData(
56 PIMAGE_NT_HEADERS NtHeader
;
59 NtHeader
= RtlImageNtHeader(BaseAddress
);
63 if (Directory
>= NtHeader
->OptionalHeader
.NumberOfRvaAndSizes
)
66 Va
= NtHeader
->OptionalHeader
.DataDirectory
[Directory
].VirtualAddress
;
70 return (PVOID
)((ULONG_PTR
)BaseAddress
+ Va
);
75 IntVideoPortDeferredRoutine(
77 IN PVOID DeferredContext
,
78 IN PVOID SystemArgument1
,
79 IN PVOID SystemArgument2
)
81 PVOID HwDeviceExtension
=
82 &((PVIDEO_PORT_DEVICE_EXTENSION
)DeferredContext
)->MiniPortDeviceExtension
;
83 ((PMINIPORT_DPC_ROUTINE
)SystemArgument1
)(HwDeviceExtension
, SystemArgument2
);
88 IntVideoPortCreateAdapterDeviceObject(
89 IN PDRIVER_OBJECT DriverObject
,
90 IN PVIDEO_PORT_DRIVER_EXTENSION DriverExtension
,
91 IN PDEVICE_OBJECT PhysicalDeviceObject
,
92 OUT PDEVICE_OBJECT
*DeviceObject OPTIONAL
)
94 PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension
;
97 PCI_SLOT_NUMBER SlotNumber
;
100 WCHAR DeviceBuffer
[20];
101 UNICODE_STRING DeviceName
;
102 PDEVICE_OBJECT DeviceObject_
;
104 if (DeviceObject
== NULL
)
105 DeviceObject
= &DeviceObject_
;
108 * Find the first free device number that can be used for video device
109 * object names and symlinks.
111 DeviceNumber
= VideoPortDeviceNumber
;
112 if (DeviceNumber
== 0xFFFFFFFF)
114 WARN_(VIDEOPRT
, "Can't find free device number\n");
115 return STATUS_UNSUCCESSFUL
;
119 * Create the device object.
122 /* Create a unicode device name. */
123 swprintf(DeviceBuffer
, L
"\\Device\\Video%lu", DeviceNumber
);
124 RtlInitUnicodeString(&DeviceName
, DeviceBuffer
);
126 INFO_(VIDEOPRT
, "HwDeviceExtension size is: 0x%x\n",
127 DriverExtension
->InitializationData
.HwDeviceExtensionSize
);
129 /* Create the device object. */
130 Size
= sizeof(VIDEO_PORT_DEVICE_EXTENSION
) +
131 DriverExtension
->InitializationData
.HwDeviceExtensionSize
;
132 Status
= IoCreateDevice(DriverObject
,
140 if (!NT_SUCCESS(Status
))
142 WARN_(VIDEOPRT
, "IoCreateDevice call failed with status 0x%08x\n", Status
);
147 * Set the buffering strategy here. If you change this, remember
148 * to change VidDispatchDeviceControl too.
151 (*DeviceObject
)->Flags
|= DO_BUFFERED_IO
;
153 /* Initialize device extension. */
154 DeviceExtension
= (PVIDEO_PORT_DEVICE_EXTENSION
)((*DeviceObject
)->DeviceExtension
);
155 DeviceExtension
->Common
.Fdo
= TRUE
;
156 DeviceExtension
->DeviceNumber
= DeviceNumber
;
157 DeviceExtension
->DriverObject
= DriverObject
;
158 DeviceExtension
->PhysicalDeviceObject
= PhysicalDeviceObject
;
159 DeviceExtension
->FunctionalDeviceObject
= *DeviceObject
;
160 DeviceExtension
->DriverExtension
= DriverExtension
;
161 DeviceExtension
->SessionId
= -1;
163 InitializeListHead(&DeviceExtension
->ChildDeviceList
);
165 /* Get the registry path associated with this device. */
166 Status
= IntCreateRegistryPath(&DriverExtension
->RegistryPath
,
167 &DeviceExtension
->RegistryPath
);
168 if (!NT_SUCCESS(Status
))
170 WARN_(VIDEOPRT
, "IntCreateRegistryPath() call failed with status 0x%08x\n", Status
);
171 IoDeleteDevice(*DeviceObject
);
172 *DeviceObject
= NULL
;
176 if (PhysicalDeviceObject
!= NULL
)
178 /* Get bus number from the upper level bus driver. */
179 Size
= sizeof(ULONG
);
180 Status
= IoGetDeviceProperty(PhysicalDeviceObject
,
181 DevicePropertyBusNumber
,
183 &DeviceExtension
->SystemIoBusNumber
,
185 if (!NT_SUCCESS(Status
))
187 WARN_(VIDEOPRT
, "Couldn't get an information from bus driver. We will try to\n"
188 "use legacy detection method, but even that doesn't mean that\n"
190 DeviceExtension
->PhysicalDeviceObject
= NULL
;
194 DeviceExtension
->AdapterInterfaceType
=
195 DriverExtension
->InitializationData
.AdapterInterfaceType
;
197 if (PhysicalDeviceObject
!= NULL
)
199 /* Get bus type from the upper level bus driver. */
200 Size
= sizeof(ULONG
);
201 IoGetDeviceProperty(PhysicalDeviceObject
,
202 DevicePropertyLegacyBusType
,
204 &DeviceExtension
->AdapterInterfaceType
,
207 /* Get bus device address from the upper level bus driver. */
208 Size
= sizeof(ULONG
);
209 IoGetDeviceProperty(PhysicalDeviceObject
,
210 DevicePropertyAddress
,
215 /* Convert slotnumber to PCI_SLOT_NUMBER */
216 SlotNumber
.u
.AsULONG
= 0;
217 SlotNumber
.u
.bits
.DeviceNumber
= (PciSlotNumber
>> 16) & 0xFFFF;
218 SlotNumber
.u
.bits
.FunctionNumber
= PciSlotNumber
& 0xFFFF;
219 DeviceExtension
->SystemIoSlotNumber
= SlotNumber
.u
.AsULONG
;
222 InitializeListHead(&DeviceExtension
->AddressMappingListHead
);
223 InitializeListHead(&DeviceExtension
->DmaAdapterList
);
225 KeInitializeDpc(&DeviceExtension
->DpcObject
,
226 IntVideoPortDeferredRoutine
,
229 KeInitializeMutex(&DeviceExtension
->DeviceLock
, 0);
231 /* Attach the device. */
232 if (PhysicalDeviceObject
!= NULL
)
233 DeviceExtension
->NextDeviceObject
= IoAttachDeviceToDeviceStack(
235 PhysicalDeviceObject
);
237 IntCreateNewRegistryPath(DeviceExtension
);
238 IntSetupDeviceSettingsKey(DeviceExtension
);
240 /* Remove the initailizing flag */
241 (*DeviceObject
)->Flags
&= ~DO_DEVICE_INITIALIZING
;
242 return STATUS_SUCCESS
;
248 IntVideoPortFindAdapter(
249 IN PDRIVER_OBJECT DriverObject
,
250 IN PVIDEO_PORT_DRIVER_EXTENSION DriverExtension
,
251 IN PDEVICE_OBJECT DeviceObject
)
253 WCHAR DeviceVideoBuffer
[20];
254 PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension
;
256 VIDEO_PORT_CONFIG_INFO ConfigInfo
;
257 SYSTEM_BASIC_INFORMATION SystemBasicInfo
;
259 WCHAR DeviceBuffer
[20];
260 UNICODE_STRING DeviceName
;
261 WCHAR SymlinkBuffer
[20];
262 UNICODE_STRING SymlinkName
;
263 BOOL LegacyDetection
= FALSE
;
266 DeviceExtension
= (PVIDEO_PORT_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
267 DeviceNumber
= DeviceExtension
->DeviceNumber
;
269 /* Setup a ConfigInfo structure that we will pass to HwFindAdapter. */
270 RtlZeroMemory(&ConfigInfo
, sizeof(VIDEO_PORT_CONFIG_INFO
));
271 ConfigInfo
.Length
= sizeof(VIDEO_PORT_CONFIG_INFO
);
272 ConfigInfo
.AdapterInterfaceType
= DeviceExtension
->AdapterInterfaceType
;
273 if (ConfigInfo
.AdapterInterfaceType
== PCIBus
)
274 ConfigInfo
.InterruptMode
= LevelSensitive
;
276 ConfigInfo
.InterruptMode
= Latched
;
277 ConfigInfo
.DriverRegistryPath
= DriverExtension
->RegistryPath
.Buffer
;
278 ConfigInfo
.VideoPortGetProcAddress
= IntVideoPortGetProcAddress
;
279 ConfigInfo
.SystemIoBusNumber
= DeviceExtension
->SystemIoBusNumber
;
280 ConfigInfo
.BusInterruptLevel
= DeviceExtension
->InterruptLevel
;
281 ConfigInfo
.BusInterruptVector
= DeviceExtension
->InterruptVector
;
283 Status
= ZwQuerySystemInformation(SystemBasicInformation
,
285 sizeof(SystemBasicInfo
),
287 if (NT_SUCCESS(Status
))
289 ConfigInfo
.SystemMemorySize
= SystemBasicInfo
.NumberOfPhysicalPages
*
290 SystemBasicInfo
.PageSize
;
294 * Call miniport HwVidFindAdapter entry point to detect if
295 * particular device is present. There are two possible code
296 * paths. The first one is for Legacy drivers (NT4) and cases
297 * when we don't have information about what bus we're on. The
298 * second case is the standard one for Plug & Play drivers.
300 if (DeviceExtension
->PhysicalDeviceObject
== NULL
)
302 LegacyDetection
= TRUE
;
307 ULONG BusNumber
, MaxBuses
;
309 MaxBuses
= DeviceExtension
->AdapterInterfaceType
== PCIBus
? PCI_MAX_BRIDGE_NUMBER
: 1;
311 for (BusNumber
= 0; BusNumber
< MaxBuses
; BusNumber
++)
313 DeviceExtension
->SystemIoBusNumber
=
314 ConfigInfo
.SystemIoBusNumber
= BusNumber
;
316 RtlZeroMemory(&DeviceExtension
->MiniPortDeviceExtension
,
317 DriverExtension
->InitializationData
.HwDeviceExtensionSize
);
319 /* FIXME: Need to figure out what string to pass as param 3. */
320 Status
= DriverExtension
->InitializationData
.HwFindAdapter(
321 &DeviceExtension
->MiniPortDeviceExtension
,
322 DriverExtension
->HwContext
,
327 if (Status
== ERROR_DEV_NOT_EXIST
)
331 else if (Status
== NO_ERROR
)
337 ERR_(VIDEOPRT
, "HwFindAdapter call failed with error 0x%X\n", Status
);
344 /* FIXME: Need to figure out what string to pass as param 3. */
345 Status
= DriverExtension
->InitializationData
.HwFindAdapter(
346 &DeviceExtension
->MiniPortDeviceExtension
,
347 DriverExtension
->HwContext
,
353 if (Status
!= NO_ERROR
)
355 ERR_(VIDEOPRT
, "HwFindAdapter call failed with error 0x%X\n", Status
);
360 * Now we know the device is present, so let's do all additional tasks
361 * such as creating symlinks or setting up interrupts and timer.
364 /* Create a unicode device name. */
365 swprintf(DeviceBuffer
, L
"\\Device\\Video%lu", DeviceNumber
);
366 RtlInitUnicodeString(&DeviceName
, DeviceBuffer
);
368 /* Create symbolic link "\??\DISPLAYx" */
369 swprintf(SymlinkBuffer
, L
"\\??\\DISPLAY%lu", DeviceNumber
+ 1);
370 RtlInitUnicodeString(&SymlinkName
, SymlinkBuffer
);
371 IoCreateSymbolicLink(&SymlinkName
, &DeviceName
);
373 /* Add entry to DEVICEMAP\VIDEO key in registry. */
374 swprintf(DeviceVideoBuffer
, L
"\\Device\\Video%d", DeviceNumber
);
375 RtlWriteRegistryValue(
376 RTL_REGISTRY_DEVICEMAP
,
380 DeviceExtension
->RegistryPath
.Buffer
,
381 DeviceExtension
->RegistryPath
.Length
+ sizeof(UNICODE_NULL
));
383 RtlWriteRegistryValue(
384 RTL_REGISTRY_DEVICEMAP
,
389 sizeof(DeviceNumber
));
391 /* FIXME: Allocate hardware resources for device. */
393 /* Allocate interrupt for device. */
394 if (!IntVideoPortSetupInterrupt(DeviceObject
, DriverExtension
, &ConfigInfo
))
396 Status
= STATUS_INSUFFICIENT_RESOURCES
;
400 /* Allocate timer for device. */
401 if (!IntVideoPortSetupTimer(DeviceObject
, DriverExtension
))
403 if (DeviceExtension
->InterruptObject
!= NULL
)
404 IoDisconnectInterrupt(DeviceExtension
->InterruptObject
);
405 ERR_(VIDEOPRT
, "IntVideoPortSetupTimer failed\n");
406 Status
= STATUS_INSUFFICIENT_RESOURCES
;
410 /* If the device can be reset, insert it in the list of resettable adapters */
411 InitializeListHead(&DeviceExtension
->HwResetListEntry
);
412 if (DriverExtension
->InitializationData
.HwResetHw
!= NULL
)
414 ExInterlockedInsertTailList(&HwResetAdaptersList
,
415 &DeviceExtension
->HwResetListEntry
,
416 &HwResetAdaptersLock
);
419 /* Query children of the device. */
420 VideoPortEnumerateChildren(&DeviceExtension
->MiniPortDeviceExtension
, NULL
);
422 INFO_(VIDEOPRT
, "STATUS_SUCCESS\n");
423 return STATUS_SUCCESS
;
426 RtlFreeUnicodeString(&DeviceExtension
->RegistryPath
);
427 if (DeviceExtension
->NextDeviceObject
)
428 IoDetachDevice(DeviceExtension
->NextDeviceObject
);
429 IoDeleteDevice(DeviceObject
);
436 PKPROCESS
*CallingProcess
,
437 PKAPC_STATE ApcState
)
439 *CallingProcess
= (PKPROCESS
)PsGetCurrentProcess();
440 if (*CallingProcess
!= CsrProcess
)
442 KeStackAttachProcess(CsrProcess
, ApcState
);
449 PKPROCESS
*CallingProcess
,
450 PKAPC_STATE ApcState
)
452 if (*CallingProcess
!= CsrProcess
)
454 KeUnstackDetachProcess(ApcState
);
458 /* PUBLIC FUNCTIONS ***********************************************************/
468 IN PVIDEO_HW_INITIALIZATION_DATA HwInitializationData
,
471 PDRIVER_OBJECT DriverObject
= Context1
;
472 PUNICODE_STRING RegistryPath
= Context2
;
474 PVIDEO_PORT_DRIVER_EXTENSION DriverExtension
;
475 BOOLEAN PnpDriver
= FALSE
, LegacyDetection
= FALSE
;
476 static BOOLEAN FirstInitialization
;
478 TRACE_(VIDEOPRT
, "VideoPortInitialize\n");
480 if (!FirstInitialization
)
482 KeInitializeMutex(&VideoPortInt10Mutex
, 0);
483 KeInitializeSpinLock(&HwResetAdaptersLock
);
484 FirstInitialization
= TRUE
;
487 /* As a first thing do parameter checks. */
488 if (HwInitializationData
->HwInitDataSize
> sizeof(VIDEO_HW_INITIALIZATION_DATA
))
490 ERR_(VIDEOPRT
, "Invalid HwInitializationData\n");
491 return STATUS_REVISION_MISMATCH
;
494 if ((HwInitializationData
->HwFindAdapter
== NULL
) ||
495 (HwInitializationData
->HwInitialize
== NULL
) ||
496 (HwInitializationData
->HwStartIO
== NULL
))
498 ERR_(VIDEOPRT
, "Invalid HwInitializationData\n");
499 return STATUS_INVALID_PARAMETER
;
502 switch (HwInitializationData
->HwInitDataSize
)
505 * NT4 drivers are special case, because we must use legacy method
506 * of detection instead of the Plug & Play one.
508 case SIZE_OF_NT4_VIDEO_HW_INITIALIZATION_DATA
:
509 INFO_(VIDEOPRT
, "We were loaded by a Windows NT miniport driver.\n");
512 case SIZE_OF_W2K_VIDEO_HW_INITIALIZATION_DATA
:
513 INFO_(VIDEOPRT
, "We were loaded by a Windows 2000 miniport driver.\n");
516 case sizeof(VIDEO_HW_INITIALIZATION_DATA
):
517 INFO_(VIDEOPRT
, "We were loaded by a Windows XP or later miniport driver.\n");
521 ERR_(VIDEOPRT
, "Invalid HwInitializationData size.\n");
522 return STATUS_UNSUCCESSFUL
;
525 /* Set dispatching routines */
526 DriverObject
->MajorFunction
[IRP_MJ_CREATE
] = IntVideoPortDispatchOpen
;
527 DriverObject
->MajorFunction
[IRP_MJ_CLOSE
] = IntVideoPortDispatchClose
;
528 DriverObject
->MajorFunction
[IRP_MJ_DEVICE_CONTROL
] =
529 IntVideoPortDispatchDeviceControl
;
530 DriverObject
->MajorFunction
[IRP_MJ_SHUTDOWN
] =
531 IntVideoPortDispatchDeviceControl
;
532 DriverObject
->DriverUnload
= IntVideoPortUnload
;
534 /* Determine type of the miniport driver */
535 if ((HwInitializationData
->HwInitDataSize
>=
536 FIELD_OFFSET(VIDEO_HW_INITIALIZATION_DATA
, HwQueryInterface
)) &&
537 (HwInitializationData
->HwSetPowerState
!= NULL
) &&
538 (HwInitializationData
->HwGetPowerState
!= NULL
) &&
539 (HwInitializationData
->HwGetVideoChildDescriptor
!= NULL
))
541 INFO_(VIDEOPRT
, "The miniport is a PnP miniport driver\n");
545 /* Check if legacy detection should be applied */
546 if (!PnpDriver
|| HwContext
)
548 INFO_(VIDEOPRT
, "Legacy detection for adapter interface %d\n",
549 HwInitializationData
->AdapterInterfaceType
);
551 /* FIXME: Move the code for legacy detection
552 to another function and call it here */
553 LegacyDetection
= TRUE
;
558 * The driver extension can be already allocated in case that we were
559 * called by legacy driver and failed detecting device. Some miniport
560 * drivers in that case adjust parameters and call VideoPortInitialize
563 DriverExtension
= IoGetDriverObjectExtension(DriverObject
, DriverObject
);
564 if (DriverExtension
== NULL
)
566 Status
= IoAllocateDriverObjectExtension(DriverObject
,
568 sizeof(VIDEO_PORT_DRIVER_EXTENSION
),
569 (PVOID
*)&DriverExtension
);
570 if (!NT_SUCCESS(Status
))
572 ERR_(VIDEOPRT
, "IoAllocateDriverObjectExtension failed 0x%x\n", Status
);
577 * Save the registry path. This should be done only once even if
578 * VideoPortInitialize is called multiple times.
580 if (RegistryPath
->Length
!= 0)
582 DriverExtension
->RegistryPath
.Length
= 0;
583 DriverExtension
->RegistryPath
.MaximumLength
=
584 RegistryPath
->Length
+ sizeof(UNICODE_NULL
);
585 DriverExtension
->RegistryPath
.Buffer
=
586 ExAllocatePoolWithTag(
588 DriverExtension
->RegistryPath
.MaximumLength
,
590 if (DriverExtension
->RegistryPath
.Buffer
== NULL
)
592 RtlInitUnicodeString(&DriverExtension
->RegistryPath
, NULL
);
593 return STATUS_INSUFFICIENT_RESOURCES
;
596 RtlCopyUnicodeString(&DriverExtension
->RegistryPath
, RegistryPath
);
597 INFO_(VIDEOPRT
, "RegistryPath: %wZ\n", &DriverExtension
->RegistryPath
);
601 RtlInitUnicodeString(&DriverExtension
->RegistryPath
, NULL
);
605 /* Copy the correct miniport initialization data to the device extension. */
606 RtlCopyMemory(&DriverExtension
->InitializationData
,
607 HwInitializationData
,
608 HwInitializationData
->HwInitDataSize
);
609 if (HwInitializationData
->HwInitDataSize
<
610 sizeof(VIDEO_HW_INITIALIZATION_DATA
))
612 RtlZeroMemory((PVOID
)((ULONG_PTR
)&DriverExtension
->InitializationData
+
613 HwInitializationData
->HwInitDataSize
),
614 sizeof(VIDEO_HW_INITIALIZATION_DATA
) -
615 HwInitializationData
->HwInitDataSize
);
617 DriverExtension
->HwContext
= HwContext
;
620 * Plug & Play drivers registers the device in AddDevice routine.
621 * For legacy drivers we must do it now.
625 PDEVICE_OBJECT DeviceObject
;
627 if (HwInitializationData
->HwInitDataSize
!= SIZE_OF_NT4_VIDEO_HW_INITIALIZATION_DATA
)
629 /* Power management */
630 DriverObject
->MajorFunction
[IRP_MJ_POWER
] = IntVideoPortDispatchPower
;
633 Status
= IntVideoPortCreateAdapterDeviceObject(DriverObject
,
637 if (!NT_SUCCESS(Status
))
639 ERR_(VIDEOPRT
, "IntVideoPortCreateAdapterDeviceObject returned 0x%x\n", Status
);
643 Status
= IntVideoPortFindAdapter(DriverObject
, DriverExtension
, DeviceObject
);
644 if (NT_SUCCESS(Status
))
645 VideoPortDeviceNumber
++;
647 ERR_(VIDEOPRT
, "IntVideoPortFindAdapter returned 0x%x\n", Status
);
653 DriverObject
->DriverExtension
->AddDevice
= IntVideoPortAddDevice
;
654 DriverObject
->MajorFunction
[IRP_MJ_PNP
] = IntVideoPortDispatchPnp
;
655 DriverObject
->MajorFunction
[IRP_MJ_POWER
] = IntVideoPortDispatchPower
;
656 DriverObject
->MajorFunction
[IRP_MJ_SYSTEM_CONTROL
] = IntVideoPortDispatchSystemControl
;
658 return STATUS_SUCCESS
;
667 IN VIDEO_DEBUG_LEVEL DebugPrintLevel
,
668 IN PCHAR DebugMessage
,
673 va_start(ap
, DebugMessage
);
674 vDbgPrintEx(DPFLTR_IHVVIDEO_ID
, DebugPrintLevel
, DebugMessage
, ap
);
684 IN PVOID HwDeviceExtension
,
685 IN PVIDEO_REQUEST_PACKET Vrp OPTIONAL
,
686 IN VP_STATUS ErrorCode
,
691 INFO_(VIDEOPRT
, "VideoPortLogError ErrorCode %d (0x%x) UniqueId %lu (0x%lx)\n",
692 ErrorCode
, ErrorCode
, UniqueId
, UniqueId
);
694 INFO_(VIDEOPRT
, "Vrp->IoControlCode %lu (0x%lx)\n", Vrp
->IoControlCode
, Vrp
->IoControlCode
);
702 VideoPortGetCurrentIrql(VOID
)
704 return KeGetCurrentIrql();
707 typedef struct QueryRegistryCallbackContext
709 PVOID HwDeviceExtension
;
711 PMINIPORT_GET_REGISTRY_ROUTINE HwGetRegistryRoutine
;
712 } QUERY_REGISTRY_CALLBACK_CONTEXT
, *PQUERY_REGISTRY_CALLBACK_CONTEXT
;
717 QueryRegistryCallback(
721 IN ULONG ValueLength
,
723 IN PVOID EntryContext
)
725 PQUERY_REGISTRY_CALLBACK_CONTEXT CallbackContext
= (PQUERY_REGISTRY_CALLBACK_CONTEXT
) Context
;
727 INFO_(VIDEOPRT
, "Found registry value for name %S: type %d, length %d\n",
728 ValueName
, ValueType
, ValueLength
);
729 return (*(CallbackContext
->HwGetRegistryRoutine
))(
730 CallbackContext
->HwDeviceExtension
,
731 CallbackContext
->HwContext
,
743 VideoPortGetRegistryParameters(
744 IN PVOID HwDeviceExtension
,
745 IN PWSTR ParameterName
,
746 IN UCHAR IsParameterFileName
,
747 IN PMINIPORT_GET_REGISTRY_ROUTINE GetRegistryRoutine
,
750 RTL_QUERY_REGISTRY_TABLE QueryTable
[2] = {{0}};
751 QUERY_REGISTRY_CALLBACK_CONTEXT Context
;
752 PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension
;
755 DeviceExtension
= VIDEO_PORT_GET_DEVICE_EXTENSION(HwDeviceExtension
);
757 TRACE_(VIDEOPRT
, "VideoPortGetRegistryParameters ParameterName %S, RegPath: %wZ\n",
758 ParameterName
, &DeviceExtension
->RegistryPath
);
760 Context
.HwDeviceExtension
= HwDeviceExtension
;
761 Context
.HwContext
= HwContext
;
762 Context
.HwGetRegistryRoutine
= GetRegistryRoutine
;
764 QueryTable
[0].QueryRoutine
= QueryRegistryCallback
;
765 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_REQUIRED
;
766 QueryTable
[0].Name
= ParameterName
;
768 Status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
,
769 DeviceExtension
->RegistryPath
.Buffer
,
773 if (!NT_SUCCESS(Status
))
775 WARN_(VIDEOPRT
, "VideoPortGetRegistryParameters could not find the "
776 "requested parameter\n");
777 return ERROR_INVALID_PARAMETER
;
780 if (IsParameterFileName
)
782 /* FIXME: need to read the contents of the file */
794 VideoPortSetRegistryParameters(
795 IN PVOID HwDeviceExtension
,
798 IN ULONG ValueLength
)
800 PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension
;
803 DeviceExtension
= VIDEO_PORT_GET_DEVICE_EXTENSION(HwDeviceExtension
);
804 TRACE_(VIDEOPRT
, "VideoPortSetRegistryParameters ParameterName %S, RegPath: %wZ\n",
806 &DeviceExtension
->RegistryPath
);
807 ASSERT_IRQL_LESS_OR_EQUAL(PASSIVE_LEVEL
);
808 Status
= RtlWriteRegistryValue(RTL_REGISTRY_ABSOLUTE
,
809 DeviceExtension
->RegistryPath
.Buffer
,
814 if (Status
!= NO_ERROR
)
815 WARN_(VIDEOPRT
, "VideoPortSetRegistryParameters error 0x%x\n", Status
);
825 VideoPortGetVgaStatus(
826 IN PVOID HwDeviceExtension
,
827 OUT PULONG VgaStatus
)
829 PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension
;
831 TRACE_(VIDEOPRT
, "VideoPortGetVgaStatus\n");
833 DeviceExtension
= VIDEO_PORT_GET_DEVICE_EXTENSION(HwDeviceExtension
);
834 if (KeGetCurrentIrql() == PASSIVE_LEVEL
)
836 if (DeviceExtension
->AdapterInterfaceType
== PCIBus
)
838 /* VgaStatus: 0 == VGA not enabled, 1 == VGA enabled. */
839 /* Assumed for now */
845 return ERROR_INVALID_FUNCTION
;
853 VideoPortGetRomImage(
854 IN PVOID HwDeviceExtension
,
859 static PVOID RomImageBuffer
= NULL
;
860 PKPROCESS CallingProcess
;
863 TRACE_(VIDEOPRT
, "VideoPortGetRomImage(HwDeviceExtension 0x%X Length 0x%X)\n",
864 HwDeviceExtension
, Length
);
866 /* If the length is zero then free the existing buffer. */
869 if (RomImageBuffer
!= NULL
)
871 ExFreePool(RomImageBuffer
);
872 RomImageBuffer
= NULL
;
879 * The DDK says we shouldn't use the legacy C0000 method but get the
880 * rom base address from the corresponding pci or acpi register but
881 * lets ignore that and use C0000 anyway. We have already mapped the
882 * bios area into memory so we'll copy from there.
886 Length
= min(Length
, 0x10000);
887 if (RomImageBuffer
!= NULL
)
889 ExFreePool(RomImageBuffer
);
892 RomImageBuffer
= ExAllocatePool(PagedPool
, Length
);
893 if (RomImageBuffer
== NULL
)
898 IntAttachToCSRSS(&CallingProcess
, &ApcState
);
899 RtlCopyMemory(RomImageBuffer
, (PUCHAR
)0xC0000, Length
);
900 IntDetachFromCSRSS(&CallingProcess
, &ApcState
);
902 return RomImageBuffer
;
912 IN PVOID HwDeviceExtension
,
919 PUCHAR SearchLocation
;
921 TRACE_(VIDEOPRT
, "VideoPortScanRom RomBase %p RomLength 0x%x String %s\n", RomBase
, RomLength
, String
);
923 StringLength
= strlen((PCHAR
)String
);
925 SearchLocation
= RomBase
;
926 for (SearchLocation
= RomBase
;
927 !Found
&& SearchLocation
< RomBase
+ RomLength
- StringLength
;
930 Found
= (RtlCompareMemory(SearchLocation
, String
, StringLength
) == StringLength
);
933 INFO_(VIDEOPRT
, "Match found at %p\n", SearchLocation
);
945 VideoPortSynchronizeExecution(
946 IN PVOID HwDeviceExtension
,
947 IN VIDEO_SYNCHRONIZE_PRIORITY Priority
,
948 IN PMINIPORT_SYNCHRONIZE_ROUTINE SynchronizeRoutine
,
952 PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension
;
958 Ret
= (*SynchronizeRoutine
)(Context
);
961 case VpMediumPriority
:
962 DeviceExtension
= VIDEO_PORT_GET_DEVICE_EXTENSION(HwDeviceExtension
);
963 if (DeviceExtension
->InterruptObject
== NULL
)
964 Ret
= (*SynchronizeRoutine
)(Context
);
966 Ret
= KeSynchronizeExecution(
967 DeviceExtension
->InterruptObject
,
973 OldIrql
= KeGetCurrentIrql();
974 if (OldIrql
< SYNCH_LEVEL
)
975 KeRaiseIrql(SYNCH_LEVEL
, &OldIrql
);
977 Ret
= (*SynchronizeRoutine
)(Context
);
979 if (OldIrql
< SYNCH_LEVEL
)
980 KeLowerIrql(OldIrql
);
995 VideoPortEnumerateChildren(
996 IN PVOID HwDeviceExtension
,
999 PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension
;
1001 VIDEO_CHILD_ENUM_INFO ChildEnumInfo
;
1002 BOOLEAN bHaveLastMonitorID
= FALSE
;
1003 UCHAR LastMonitorID
[10];
1006 PDEVICE_OBJECT ChildDeviceObject
;
1007 PVIDEO_PORT_CHILD_EXTENSION ChildExtension
;
1009 INFO_(VIDEOPRT
, "Starting child device probe\n");
1010 DeviceExtension
= VIDEO_PORT_GET_DEVICE_EXTENSION(HwDeviceExtension
);
1011 if (DeviceExtension
->DriverExtension
->InitializationData
.HwGetVideoChildDescriptor
== NULL
)
1013 WARN_(VIDEOPRT
, "Miniport's HwGetVideoChildDescriptor is NULL!\n");
1017 if (!IsListEmpty(&DeviceExtension
->ChildDeviceList
))
1019 ERR_(VIDEOPRT
, "FIXME: Support calling VideoPortEnumerateChildren again!\n");
1023 /* Enumerate the children */
1026 Status
= IoCreateDevice(DeviceExtension
->DriverObject
,
1027 sizeof(VIDEO_PORT_CHILD_EXTENSION
) +
1028 DeviceExtension
->DriverExtension
->InitializationData
.HwChildDeviceExtensionSize
,
1030 FILE_DEVICE_CONTROLLER
,
1031 FILE_DEVICE_SECURE_OPEN
,
1033 &ChildDeviceObject
);
1034 if (!NT_SUCCESS(Status
))
1037 ChildExtension
= ChildDeviceObject
->DeviceExtension
;
1039 RtlZeroMemory(ChildExtension
,
1040 sizeof(VIDEO_PORT_CHILD_EXTENSION
) +
1041 DeviceExtension
->DriverExtension
->InitializationData
.HwChildDeviceExtensionSize
);
1043 ChildExtension
->Common
.Fdo
= FALSE
;
1044 ChildExtension
->ChildId
= i
;
1045 ChildExtension
->PhysicalDeviceObject
= ChildDeviceObject
;
1046 ChildExtension
->DriverObject
= DeviceExtension
->DriverObject
;
1048 /* Setup the ChildEnumInfo */
1049 ChildEnumInfo
.Size
= sizeof(ChildEnumInfo
);
1050 ChildEnumInfo
.ChildDescriptorSize
= sizeof(ChildExtension
->ChildDescriptor
);
1051 ChildEnumInfo
.ACPIHwId
= 0;
1053 if (DeviceExtension
->DriverExtension
->InitializationData
.HwChildDeviceExtensionSize
)
1054 ChildEnumInfo
.ChildHwDeviceExtension
= VIDEO_PORT_GET_CHILD_EXTENSION(ChildExtension
);
1056 ChildEnumInfo
.ChildHwDeviceExtension
= NULL
;
1058 ChildEnumInfo
.ChildIndex
= ChildExtension
->ChildId
;
1060 INFO_(VIDEOPRT
, "Probing child: %d\n", ChildEnumInfo
.ChildIndex
);
1061 Status
= DeviceExtension
->DriverExtension
->InitializationData
.HwGetVideoChildDescriptor(
1064 &ChildExtension
->ChildType
,
1065 ChildExtension
->ChildDescriptor
,
1066 &ChildExtension
->ChildId
,
1068 if (Status
== VIDEO_ENUM_MORE_DEVICES
)
1070 if (ChildExtension
->ChildType
== Monitor
)
1072 // Check if the EDID is valid
1073 if (ChildExtension
->ChildDescriptor
[0] == 0x00 &&
1074 ChildExtension
->ChildDescriptor
[1] == 0xFF &&
1075 ChildExtension
->ChildDescriptor
[2] == 0xFF &&
1076 ChildExtension
->ChildDescriptor
[3] == 0xFF &&
1077 ChildExtension
->ChildDescriptor
[4] == 0xFF &&
1078 ChildExtension
->ChildDescriptor
[5] == 0xFF &&
1079 ChildExtension
->ChildDescriptor
[6] == 0xFF &&
1080 ChildExtension
->ChildDescriptor
[7] == 0x00)
1082 if (bHaveLastMonitorID
)
1084 // Compare the previous monitor ID with the current one, break the loop if they are identical
1085 if (RtlCompareMemory(LastMonitorID
, &ChildExtension
->ChildDescriptor
[8], sizeof(LastMonitorID
)) == sizeof(LastMonitorID
))
1087 INFO_(VIDEOPRT
, "Found identical Monitor ID two times, stopping enumeration\n");
1088 IoDeleteDevice(ChildDeviceObject
);
1093 // Copy 10 bytes from the EDID, which can be used to uniquely identify the monitor
1094 RtlCopyMemory(LastMonitorID
, &ChildExtension
->ChildDescriptor
[8], sizeof(LastMonitorID
));
1095 bHaveLastMonitorID
= TRUE
;
1098 ChildExtension
->EdidValid
= TRUE
;
1102 /* Mark it invalid */
1103 ChildExtension
->EdidValid
= FALSE
;
1107 else if (Status
== VIDEO_ENUM_INVALID_DEVICE
)
1109 WARN_(VIDEOPRT
, "Child device %d is invalid!\n", ChildEnumInfo
.ChildIndex
);
1110 IoDeleteDevice(ChildDeviceObject
);
1113 else if (Status
== VIDEO_ENUM_NO_MORE_DEVICES
)
1115 INFO_(VIDEOPRT
, "End of child enumeration! (%d children enumerated)\n", i
- 1);
1116 IoDeleteDevice(ChildDeviceObject
);
1121 WARN_(VIDEOPRT
, "HwGetVideoChildDescriptor returned unknown status code 0x%x!\n", Status
);
1122 IoDeleteDevice(ChildDeviceObject
);
1126 if (ChildExtension
->ChildType
== Monitor
)
1129 PUCHAR p
= ChildExtension
->ChildDescriptor
;
1130 INFO_(VIDEOPRT
, "Monitor device enumerated! (ChildId = 0x%x)\n", ChildExtension
->ChildId
);
1131 for (j
= 0; j
< sizeof (ChildExtension
->ChildDescriptor
); j
+= 8)
1133 INFO_(VIDEOPRT
, "%02x %02x %02x %02x %02x %02x %02x %02x\n",
1134 p
[j
+ 0], p
[j
+ 1], p
[j
+ 2], p
[j
+ 3],
1135 p
[j
+ 4], p
[j
+ 5], p
[j
+ 6], p
[j
+ 7]);
1138 else if (ChildExtension
->ChildType
== Other
)
1140 INFO_(VIDEOPRT
, "\"Other\" device enumerated: DeviceId = %S\n", (PWSTR
)ChildExtension
->ChildDescriptor
);
1144 ERR_(VIDEOPRT
, "HwGetVideoChildDescriptor returned unsupported type: %d\n", ChildExtension
->ChildType
);
1147 /* Clear the init flag */
1148 ChildDeviceObject
->Flags
&= ~DO_DEVICE_INITIALIZING
;
1150 InsertTailList(&DeviceExtension
->ChildDeviceList
,
1151 &ChildExtension
->ListEntry
);
1154 /* Trigger reenumeration by the PnP manager */
1155 IoInvalidateDeviceRelations(DeviceExtension
->PhysicalDeviceObject
, BusRelations
);
1165 VideoPortCreateSecondaryDisplay(
1166 IN PVOID HwDeviceExtension
,
1167 IN OUT PVOID
*SecondaryDeviceExtension
,
1171 return ERROR_DEV_NOT_EXIST
;
1180 IN PVOID HwDeviceExtension
,
1181 IN PMINIPORT_DPC_ROUTINE CallbackRoutine
,
1184 return KeInsertQueueDpc(
1185 &VIDEO_PORT_GET_DEVICE_EXTENSION(HwDeviceExtension
)->DpcObject
,
1186 (PVOID
)CallbackRoutine
,
1195 VideoPortGetAssociatedDeviceExtension(
1196 IN PVOID DeviceObject
)
1198 PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension
;
1200 TRACE_(VIDEOPRT
, "VideoPortGetAssociatedDeviceExtension\n");
1201 DeviceExtension
= ((PDEVICE_OBJECT
)DeviceObject
)->DeviceExtension
;
1202 if (!DeviceExtension
)
1204 return DeviceExtension
->MiniPortDeviceExtension
;
1212 VideoPortGetVersion(
1213 IN PVOID HwDeviceExtension
,
1214 IN OUT PVPOSVERSIONINFO VpOsVersionInfo
)
1216 RTL_OSVERSIONINFOEXW Version
;
1218 Version
.dwOSVersionInfoSize
= sizeof(RTL_OSVERSIONINFOEXW
);
1219 if (VpOsVersionInfo
->Size
>= sizeof(VPOSVERSIONINFO
))
1222 if (NT_SUCCESS(RtlGetVersion((PRTL_OSVERSIONINFOW
)&Version
)))
1224 VpOsVersionInfo
->MajorVersion
= Version
.dwMajorVersion
;
1225 VpOsVersionInfo
->MinorVersion
= Version
.dwMinorVersion
;
1226 VpOsVersionInfo
->BuildNumber
= Version
.dwBuildNumber
;
1227 VpOsVersionInfo
->ServicePackMajor
= Version
.wServicePackMajor
;
1228 VpOsVersionInfo
->ServicePackMinor
= Version
.wServicePackMinor
;
1231 return ERROR_INVALID_PARAMETER
;
1233 VpOsVersionInfo
->MajorVersion
= 5;
1234 VpOsVersionInfo
->MinorVersion
= 0;
1235 VpOsVersionInfo
->BuildNumber
= 2195;
1236 VpOsVersionInfo
->ServicePackMajor
= 4;
1237 VpOsVersionInfo
->ServicePackMinor
= 0;
1242 return ERROR_INVALID_PARAMETER
;
1250 VideoPortCheckForDeviceExistence(
1251 IN PVOID HwDeviceExtension
,
1254 IN UCHAR RevisionId
,
1255 IN USHORT SubVendorId
,
1256 IN USHORT SubSystemId
,
1259 PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension
;
1260 PCI_DEVICE_PRESENT_INTERFACE PciDevicePresentInterface
;
1261 IO_STATUS_BLOCK IoStatusBlock
;
1262 IO_STACK_LOCATION IoStack
;
1267 TRACE_(VIDEOPRT
, "VideoPortCheckForDeviceExistence\n");
1269 if (Flags
& ~(CDE_USE_REVISION
| CDE_USE_SUBSYSTEM_IDS
))
1271 WARN_(VIDEOPRT
, "VideoPortCheckForDeviceExistence: Unknown flags 0x%lx\n", Flags
& ~(CDE_USE_REVISION
| CDE_USE_SUBSYSTEM_IDS
));
1275 DeviceExtension
= VIDEO_PORT_GET_DEVICE_EXTENSION(HwDeviceExtension
);
1277 PciDevicePresentInterface
.Size
= sizeof(PCI_DEVICE_PRESENT_INTERFACE
);
1278 PciDevicePresentInterface
.Version
= 1;
1279 IoStack
.Parameters
.QueryInterface
.Size
= PciDevicePresentInterface
.Size
;
1280 IoStack
.Parameters
.QueryInterface
.Version
= PciDevicePresentInterface
.Version
;
1281 IoStack
.Parameters
.QueryInterface
.Interface
= (PINTERFACE
)&PciDevicePresentInterface
;
1282 IoStack
.Parameters
.QueryInterface
.InterfaceType
=
1283 &GUID_PCI_DEVICE_PRESENT_INTERFACE
;
1284 Status
= IopInitiatePnpIrp(DeviceExtension
->NextDeviceObject
,
1285 &IoStatusBlock
, IRP_MN_QUERY_INTERFACE
, &IoStack
);
1286 if (!NT_SUCCESS(Status
))
1288 WARN_(VIDEOPRT
, "IopInitiatePnpIrp() failed! (Status 0x%lx)\n", Status
);
1292 if (Flags
& CDE_USE_REVISION
)
1293 PciFlags
|= PCI_USE_REVISION
;
1294 if (Flags
& CDE_USE_SUBSYSTEM_IDS
)
1295 PciFlags
|= PCI_USE_SUBSYSTEM_IDS
;
1297 DevicePresent
= PciDevicePresentInterface
.IsDevicePresent(
1298 VendorId
, DeviceId
, RevisionId
,
1299 SubVendorId
, SubSystemId
, PciFlags
);
1301 PciDevicePresentInterface
.InterfaceDereference(PciDevicePresentInterface
.Context
);
1303 return DevicePresent
;
1311 VideoPortRegisterBugcheckCallback(
1312 IN PVOID HwDeviceExtension
,
1313 IN ULONG BugcheckCode
,
1314 IN PVIDEO_BUGCHECK_CALLBACK Callback
,
1315 IN ULONG BugcheckDataSize
)
1326 VideoPortQueryPerformanceCounter(
1327 IN PVOID HwDeviceExtension
,
1328 OUT PLONGLONG PerformanceFrequency OPTIONAL
)
1330 LARGE_INTEGER Result
;
1332 TRACE_(VIDEOPRT
, "VideoPortQueryPerformanceCounter\n");
1333 Result
= KeQueryPerformanceCounter((PLARGE_INTEGER
)PerformanceFrequency
);
1334 return Result
.QuadPart
;
1342 VideoPortAcquireDeviceLock(
1343 IN PVOID HwDeviceExtension
)
1345 PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension
;
1349 TRACE_(VIDEOPRT
, "VideoPortAcquireDeviceLock\n");
1350 DeviceExtension
= VIDEO_PORT_GET_DEVICE_EXTENSION(HwDeviceExtension
);
1351 Status
= KeWaitForMutexObject(&DeviceExtension
->DeviceLock
, Executive
,
1352 KernelMode
, FALSE
, NULL
);
1353 // ASSERT(Status == STATUS_SUCCESS);
1361 VideoPortReleaseDeviceLock(
1362 IN PVOID HwDeviceExtension
)
1364 PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension
;
1368 TRACE_(VIDEOPRT
, "VideoPortReleaseDeviceLock\n");
1369 DeviceExtension
= VIDEO_PORT_GET_DEVICE_EXTENSION(HwDeviceExtension
);
1370 Status
= KeReleaseMutex(&DeviceExtension
->DeviceLock
, FALSE
);
1371 //ASSERT(Status == STATUS_SUCCESS);
1380 IN PDEVICE_OBJECT DeviceObject
,
1391 VideoPortAllocateContiguousMemory(
1392 IN PVOID HwDeviceExtension
,
1393 IN ULONG NumberOfBytes
,
1394 IN PHYSICAL_ADDRESS HighestAcceptableAddress
1398 return MmAllocateContiguousMemory(NumberOfBytes
, HighestAcceptableAddress
);
1406 VideoPortIsNoVesa(VOID
)
1410 UNICODE_STRING Path
= RTL_CONSTANT_STRING(L
"\\REGISTRY\\MACHINE\\SYSTEM\\CurrentControlSet\\Control");
1411 UNICODE_STRING ValueName
= RTL_CONSTANT_STRING(L
"SystemStartOptions");
1412 OBJECT_ATTRIBUTES ObjectAttributes
;
1413 PKEY_VALUE_PARTIAL_INFORMATION KeyInfo
;
1414 ULONG Length
, NewLength
;
1416 /* Initialize object attributes with the path we want */
1417 InitializeObjectAttributes(&ObjectAttributes
,
1419 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
1424 Status
= ZwOpenKey(&KeyHandle
,
1428 if (!NT_SUCCESS(Status
))
1430 VideoPortDebugPrint(Error
, "ZwOpenKey failed (0x%x)\n", Status
);
1434 /* Find out how large our buffer should be */
1435 Status
= ZwQueryValueKey(KeyHandle
,
1437 KeyValuePartialInformation
,
1441 if (Status
!= STATUS_BUFFER_OVERFLOW
&& Status
!= STATUS_BUFFER_TOO_SMALL
)
1443 VideoPortDebugPrint(Error
, "ZwQueryValueKey failed (0x%x)\n", Status
);
1449 KeyInfo
= ExAllocatePool(PagedPool
, Length
);
1452 VideoPortDebugPrint(Error
, "Out of memory\n");
1457 /* Now for real this time */
1458 Status
= ZwQueryValueKey(KeyHandle
,
1460 KeyValuePartialInformation
,
1467 if (!NT_SUCCESS(Status
))
1469 VideoPortDebugPrint(Error
, "ZwQueryValueKey failed (0x%x)\n", Status
);
1470 ExFreePool(KeyInfo
);
1475 if (KeyInfo
->Type
!= REG_SZ
)
1477 VideoPortDebugPrint(Error
, "Invalid type for SystemStartOptions\n");
1478 ExFreePool(KeyInfo
);
1482 /* Check if NOVESA or BASEVIDEO is present in the start options */
1483 if (wcsstr((PWCHAR
)KeyInfo
->Data
, L
"NOVESA") ||
1484 wcsstr((PWCHAR
)KeyInfo
->Data
, L
"BASEVIDEO"))
1486 VideoPortDebugPrint(Info
, "VESA mode disabled\n");
1487 ExFreePool(KeyInfo
);
1491 ExFreePool(KeyInfo
);
1493 VideoPortDebugPrint(Info
, "VESA mode enabled\n");