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
26 /* GLOBAL VARIABLES ***********************************************************/
28 ULONG CsrssInitialized
= FALSE
;
29 PKPROCESS Csrss
= NULL
;
30 ULONG VideoPortDeviceNumber
= 0;
32 /* PRIVATE FUNCTIONS **********************************************************/
39 return STATUS_SUCCESS
;
43 IntVideoPortImageDirectoryEntryToData(
47 PIMAGE_NT_HEADERS NtHeader
;
50 NtHeader
= RtlImageNtHeader(BaseAddress
);
54 if (Directory
>= NtHeader
->OptionalHeader
.NumberOfRvaAndSizes
)
57 Va
= NtHeader
->OptionalHeader
.DataDirectory
[Directory
].VirtualAddress
;
61 return (PVOID
)((ULONG_PTR
)BaseAddress
+ Va
);
65 IntVideoPortDeferredRoutine(
67 IN PVOID DeferredContext
,
68 IN PVOID SystemArgument1
,
69 IN PVOID SystemArgument2
)
71 PVOID HwDeviceExtension
=
72 &((PVIDEO_PORT_DEVICE_EXTENSION
)DeferredContext
)->MiniPortDeviceExtension
;
73 ((PMINIPORT_DPC_ROUTINE
)SystemArgument1
)(HwDeviceExtension
, SystemArgument2
);
77 IntCreateRegistryPath(
78 IN PCUNICODE_STRING DriverRegistryPath
,
79 OUT PUNICODE_STRING DeviceRegistryPath
)
81 static WCHAR RegistryMachineSystem
[] = L
"\\REGISTRY\\MACHINE\\SYSTEM\\";
82 static WCHAR CurrentControlSet
[] = L
"CURRENTCONTROLSET\\";
83 static WCHAR ControlSet
[] = L
"CONTROLSET";
84 static WCHAR Insert1
[] = L
"Hardware Profiles\\Current\\System\\CurrentControlSet\\";
85 static WCHAR Insert2
[] = L
"\\Device0";
86 LPWSTR ProfilePath
= NULL
;
88 PWCHAR AfterControlSet
;
90 Valid
= (0 == _wcsnicmp(DriverRegistryPath
->Buffer
, RegistryMachineSystem
,
91 wcslen(RegistryMachineSystem
)));
93 AfterControlSet
= DriverRegistryPath
->Buffer
+ wcslen(RegistryMachineSystem
);
94 if (0 == _wcsnicmp(AfterControlSet
, CurrentControlSet
, wcslen(CurrentControlSet
)))
96 AfterControlSet
+= wcslen(CurrentControlSet
);
98 else if (0 == _wcsnicmp(AfterControlSet
, ControlSet
, wcslen(ControlSet
)))
100 AfterControlSet
+= wcslen(ControlSet
);
101 while (L
'0' <= *AfterControlSet
&& L
'9' <= *AfterControlSet
)
105 Valid
= (L
'\\' == *AfterControlSet
);
116 ProfilePath
= ExAllocatePoolWithTag(PagedPool
,
117 (wcslen(DriverRegistryPath
->Buffer
) +
118 wcslen(Insert1
) + wcslen(Insert2
) + 1) * sizeof(WCHAR
),
120 if (NULL
!= ProfilePath
)
122 wcsncpy(ProfilePath
, DriverRegistryPath
->Buffer
, AfterControlSet
- DriverRegistryPath
->Buffer
);
123 wcscpy(ProfilePath
+ (AfterControlSet
- DriverRegistryPath
->Buffer
), Insert1
);
124 wcscat(ProfilePath
, AfterControlSet
);
125 wcscat(ProfilePath
, Insert2
);
127 Valid
= NT_SUCCESS(RtlCheckRegistryKey(RTL_REGISTRY_ABSOLUTE
, ProfilePath
));
136 WARN_(VIDEOPRT
, "Unparsable registry path %wZ", DriverRegistryPath
);
141 RtlInitUnicodeString(DeviceRegistryPath
, ProfilePath
);
146 ExFreePoolWithTag(ProfilePath
, TAG_VIDEO_PORT
);
148 DeviceRegistryPath
->Length
=
149 DeviceRegistryPath
->MaximumLength
=
150 DriverRegistryPath
->Length
+ (9 * sizeof(WCHAR
));
151 DeviceRegistryPath
->Length
-= sizeof(WCHAR
);
152 DeviceRegistryPath
->Buffer
= ExAllocatePoolWithTag(
154 DeviceRegistryPath
->MaximumLength
,
156 if (!DeviceRegistryPath
->Buffer
)
157 return STATUS_NO_MEMORY
;
158 swprintf(DeviceRegistryPath
->Buffer
, L
"%s\\Device0",
159 DriverRegistryPath
->Buffer
);
161 return STATUS_SUCCESS
;
165 IntVideoPortCreateAdapterDeviceObject(
166 IN PDRIVER_OBJECT DriverObject
,
167 IN PVIDEO_PORT_DRIVER_EXTENSION DriverExtension
,
168 IN PDEVICE_OBJECT PhysicalDeviceObject
,
169 OUT PDEVICE_OBJECT
*DeviceObject OPTIONAL
)
171 PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension
;
174 PCI_SLOT_NUMBER SlotNumber
;
177 WCHAR DeviceBuffer
[20];
178 UNICODE_STRING DeviceName
;
179 PDEVICE_OBJECT DeviceObject_
;
181 if (DeviceObject
== NULL
)
182 DeviceObject
= &DeviceObject_
;
185 * Find the first free device number that can be used for video device
186 * object names and symlinks.
189 DeviceNumber
= VideoPortDeviceNumber
;
190 if (DeviceNumber
== 0xFFFFFFFF)
192 WARN_(VIDEOPRT
, "Can't find free device number\n");
193 return STATUS_UNSUCCESSFUL
;
197 * Create the device object.
200 /* Create a unicode device name. */
201 swprintf(DeviceBuffer
, L
"\\Device\\Video%lu", DeviceNumber
);
202 RtlInitUnicodeString(&DeviceName
, DeviceBuffer
);
204 INFO_(VIDEOPRT
, "HwDeviceExtension size is: 0x%x\n",
205 DriverExtension
->InitializationData
.HwDeviceExtensionSize
);
207 /* Create the device object. */
208 Status
= IoCreateDevice(
210 sizeof(VIDEO_PORT_DEVICE_EXTENSION
) +
211 DriverExtension
->InitializationData
.HwDeviceExtensionSize
,
218 if (!NT_SUCCESS(Status
))
220 WARN_(VIDEOPRT
, "IoCreateDevice call failed with status 0x%08x\n", Status
);
225 * Set the buffering strategy here. If you change this, remember
226 * to change VidDispatchDeviceControl too.
229 (*DeviceObject
)->Flags
|= DO_BUFFERED_IO
;
232 * Initialize device extension.
235 DeviceExtension
= (PVIDEO_PORT_DEVICE_EXTENSION
)((*DeviceObject
)->DeviceExtension
);
236 DeviceExtension
->DeviceNumber
= DeviceNumber
;
237 DeviceExtension
->DriverObject
= DriverObject
;
238 DeviceExtension
->PhysicalDeviceObject
= PhysicalDeviceObject
;
239 DeviceExtension
->FunctionalDeviceObject
= *DeviceObject
;
240 DeviceExtension
->DriverExtension
= DriverExtension
;
243 * Get the registry path associated with this driver.
246 Status
= IntCreateRegistryPath(
247 &DriverExtension
->RegistryPath
,
248 &DeviceExtension
->RegistryPath
);
249 if (!NT_SUCCESS(Status
))
251 WARN_(VIDEOPRT
, "IntCreateRegistryPath() call failed with status 0x%08x\n", Status
);
252 IoDeleteDevice(*DeviceObject
);
253 *DeviceObject
= NULL
;
257 if (PhysicalDeviceObject
!= NULL
)
259 /* Get bus number from the upper level bus driver. */
260 Size
= sizeof(ULONG
);
261 Status
= IoGetDeviceProperty(
262 PhysicalDeviceObject
,
263 DevicePropertyBusNumber
,
265 &DeviceExtension
->SystemIoBusNumber
,
267 if (!NT_SUCCESS(Status
))
269 WARN_(VIDEOPRT
, "Couldn't get an information from bus driver. We will try to\n"
270 "use legacy detection method, but even that doesn't mean that\n"
272 DeviceExtension
->PhysicalDeviceObject
= NULL
;
276 DeviceExtension
->AdapterInterfaceType
=
277 DriverExtension
->InitializationData
.AdapterInterfaceType
;
279 if (PhysicalDeviceObject
!= NULL
)
281 /* Get bus type from the upper level bus driver. */
282 Size
= sizeof(ULONG
);
284 PhysicalDeviceObject
,
285 DevicePropertyLegacyBusType
,
287 &DeviceExtension
->AdapterInterfaceType
,
290 /* Get bus device address from the upper level bus driver. */
291 Size
= sizeof(ULONG
);
293 PhysicalDeviceObject
,
294 DevicePropertyAddress
,
299 /* Convert slotnumber to PCI_SLOT_NUMBER */
300 SlotNumber
.u
.AsULONG
= 0;
301 SlotNumber
.u
.bits
.DeviceNumber
= (PciSlotNumber
>> 16) & 0xFFFF;
302 SlotNumber
.u
.bits
.FunctionNumber
= PciSlotNumber
& 0xFFFF;
303 DeviceExtension
->SystemIoSlotNumber
= SlotNumber
.u
.AsULONG
;
306 InitializeListHead(&DeviceExtension
->AddressMappingListHead
);
307 InitializeListHead(&DeviceExtension
->DmaAdapterList
);
310 &DeviceExtension
->DpcObject
,
311 IntVideoPortDeferredRoutine
,
314 KeInitializeMutex(&DeviceExtension
->DeviceLock
, 0);
316 /* Attach the device. */
317 if (PhysicalDeviceObject
!= NULL
)
318 DeviceExtension
->NextDeviceObject
= IoAttachDeviceToDeviceStack(
319 *DeviceObject
, PhysicalDeviceObject
);
321 /* Remove the initailizing flag */
322 (*DeviceObject
)->Flags
&= ~DO_DEVICE_INITIALIZING
;
323 return STATUS_SUCCESS
;
328 IntVideoPortFindAdapter(
329 IN PDRIVER_OBJECT DriverObject
,
330 IN PVIDEO_PORT_DRIVER_EXTENSION DriverExtension
,
331 IN PDEVICE_OBJECT DeviceObject
)
333 WCHAR DeviceVideoBuffer
[20];
334 PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension
;
337 VIDEO_PORT_CONFIG_INFO ConfigInfo
;
338 SYSTEM_BASIC_INFORMATION SystemBasicInfo
;
340 WCHAR DeviceBuffer
[20];
341 UNICODE_STRING DeviceName
;
342 WCHAR SymlinkBuffer
[20];
343 UNICODE_STRING SymlinkName
;
344 BOOL LegacyDetection
= FALSE
;
345 ULONG DeviceNumber
, DisplayNumber
;
347 DeviceExtension
= (PVIDEO_PORT_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
348 DeviceNumber
= DeviceExtension
->DeviceNumber
;
351 * Setup a ConfigInfo structure that we will pass to HwFindAdapter.
354 RtlZeroMemory(&ConfigInfo
, sizeof(VIDEO_PORT_CONFIG_INFO
));
355 ConfigInfo
.Length
= sizeof(VIDEO_PORT_CONFIG_INFO
);
356 ConfigInfo
.AdapterInterfaceType
= DeviceExtension
->AdapterInterfaceType
;
357 if (ConfigInfo
.AdapterInterfaceType
== PCIBus
)
358 ConfigInfo
.InterruptMode
= LevelSensitive
;
360 ConfigInfo
.InterruptMode
= Latched
;
361 ConfigInfo
.DriverRegistryPath
= DriverExtension
->RegistryPath
.Buffer
;
362 ConfigInfo
.VideoPortGetProcAddress
= IntVideoPortGetProcAddress
;
363 ConfigInfo
.SystemIoBusNumber
= DeviceExtension
->SystemIoBusNumber
;
364 ConfigInfo
.BusInterruptLevel
= DeviceExtension
->InterruptLevel
;
365 ConfigInfo
.BusInterruptVector
= DeviceExtension
->InterruptVector
;
367 Size
= sizeof(SystemBasicInfo
);
368 Status
= ZwQuerySystemInformation(
369 SystemBasicInformation
,
374 if (NT_SUCCESS(Status
))
376 ConfigInfo
.SystemMemorySize
=
377 SystemBasicInfo
.NumberOfPhysicalPages
*
378 SystemBasicInfo
.PageSize
;
382 * Call miniport HwVidFindAdapter entry point to detect if
383 * particular device is present. There are two possible code
384 * paths. The first one is for Legacy drivers (NT4) and cases
385 * when we don't have information about what bus we're on. The
386 * second case is the standard one for Plug & Play drivers.
388 if (DeviceExtension
->PhysicalDeviceObject
== NULL
)
390 LegacyDetection
= TRUE
;
395 ULONG BusNumber
, MaxBuses
;
397 MaxBuses
= DeviceExtension
->AdapterInterfaceType
== PCIBus
? 8 : 1;
399 for (BusNumber
= 0; BusNumber
< MaxBuses
; BusNumber
++)
401 DeviceExtension
->SystemIoBusNumber
=
402 ConfigInfo
.SystemIoBusNumber
= BusNumber
;
404 RtlZeroMemory(&DeviceExtension
->MiniPortDeviceExtension
,
405 DriverExtension
->InitializationData
.HwDeviceExtensionSize
);
407 /* FIXME: Need to figure out what string to pass as param 3. */
408 Status
= DriverExtension
->InitializationData
.HwFindAdapter(
409 &DeviceExtension
->MiniPortDeviceExtension
,
410 DriverExtension
->HwContext
,
415 if (Status
== ERROR_DEV_NOT_EXIST
)
419 else if (Status
== NO_ERROR
)
425 WARN_(VIDEOPRT
, "HwFindAdapter call failed with error 0x%X\n", Status
);
426 RtlFreeUnicodeString(&DeviceExtension
->RegistryPath
);
427 if (DeviceExtension
->NextDeviceObject
)
428 IoDetachDevice(DeviceExtension
->NextDeviceObject
);
429 IoDeleteDevice(DeviceObject
);
437 /* FIXME: Need to figure out what string to pass as param 3. */
438 Status
= DriverExtension
->InitializationData
.HwFindAdapter(
439 &DeviceExtension
->MiniPortDeviceExtension
,
440 DriverExtension
->HwContext
,
446 if (Status
!= NO_ERROR
)
448 WARN_(VIDEOPRT
, "HwFindAdapter call failed with error 0x%X\n", Status
);
449 RtlFreeUnicodeString(&DeviceExtension
->RegistryPath
);
450 if (DeviceExtension
->NextDeviceObject
)
451 IoDetachDevice(DeviceExtension
->NextDeviceObject
);
452 IoDeleteDevice(DeviceObject
);
457 * Now we know the device is present, so let's do all additional tasks
458 * such as creating symlinks or setting up interrupts and timer.
461 /* Create a unicode device name. */
462 swprintf(DeviceBuffer
, L
"\\Device\\Video%lu", DeviceNumber
);
463 RtlInitUnicodeString(&DeviceName
, DeviceBuffer
);
465 /* Create symbolic link "\??\DISPLAYx" */
467 /* HACK: We need this to find the first available display to
468 * use. We can't use the device number because then we could
469 * end up with \Device\Video0 being non-functional because
470 * HwFindAdapter returned an error. \Device\Video1 would be
471 * the correct primary display but it would be set to DISPLAY2
472 * so it would never be used and ROS would bugcheck on boot.
473 * By doing it this way, we ensure that DISPLAY1 is always
474 * functional. Another idea would be letting the IO manager
475 * give our video devices names then getting those names
476 * somehow and creating symbolic links to \Device\VideoX
477 * and \??\DISPLAYX once we know that HwFindAdapter has succeeded.
483 swprintf(SymlinkBuffer
, L
"\\??\\DISPLAY%lu", DisplayNumber
);
484 RtlInitUnicodeString(&SymlinkName
, SymlinkBuffer
);
486 while (IoCreateSymbolicLink(&SymlinkName
, &DeviceName
) != STATUS_SUCCESS
);
488 /* Add entry to DEVICEMAP\VIDEO key in registry. */
489 swprintf(DeviceVideoBuffer
, L
"\\Device\\Video%d", DisplayNumber
- 1);
490 RtlWriteRegistryValue(
491 RTL_REGISTRY_DEVICEMAP
,
495 DeviceExtension
->RegistryPath
.Buffer
,
496 DeviceExtension
->RegistryPath
.MaximumLength
);
498 RtlWriteRegistryValue(
499 RTL_REGISTRY_DEVICEMAP
,
504 sizeof(DeviceNumber
));
506 /* FIXME: Allocate hardware resources for device. */
509 * Allocate interrupt for device.
512 if (!IntVideoPortSetupInterrupt(DeviceObject
, DriverExtension
, &ConfigInfo
))
514 RtlFreeUnicodeString(&DeviceExtension
->RegistryPath
);
515 if (DeviceExtension
->NextDeviceObject
)
516 IoDetachDevice(DeviceExtension
->NextDeviceObject
);
517 IoDeleteDevice(DeviceObject
);
518 return STATUS_INSUFFICIENT_RESOURCES
;
522 * Allocate timer for device.
525 if (!IntVideoPortSetupTimer(DeviceObject
, DriverExtension
))
527 if (DeviceExtension
->InterruptObject
!= NULL
)
528 IoDisconnectInterrupt(DeviceExtension
->InterruptObject
);
529 if (DeviceExtension
->NextDeviceObject
)
530 IoDetachDevice(DeviceExtension
->NextDeviceObject
);
531 RtlFreeUnicodeString(&DeviceExtension
->RegistryPath
);
532 IoDeleteDevice(DeviceObject
);
533 WARN_(VIDEOPRT
, "STATUS_INSUFFICIENT_RESOURCES\n");
534 return STATUS_INSUFFICIENT_RESOURCES
;
538 * Query children of the device.
540 VideoPortEnumerateChildren(&DeviceExtension
->MiniPortDeviceExtension
, NULL
);
542 INFO_(VIDEOPRT
, "STATUS_SUCCESS\n");
543 return STATUS_SUCCESS
;
547 IntAttachToCSRSS(PKPROCESS
*CallingProcess
, PKAPC_STATE ApcState
)
549 *CallingProcess
= (PKPROCESS
)PsGetCurrentProcess();
550 if (*CallingProcess
!= Csrss
)
552 KeStackAttachProcess(Csrss
, ApcState
);
557 IntDetachFromCSRSS(PKPROCESS
*CallingProcess
, PKAPC_STATE ApcState
)
559 if (*CallingProcess
!= Csrss
)
561 KeUnstackDetachProcess(ApcState
);
565 /* PUBLIC FUNCTIONS ***********************************************************/
575 IN PVIDEO_HW_INITIALIZATION_DATA HwInitializationData
,
578 PDRIVER_OBJECT DriverObject
= Context1
;
579 PUNICODE_STRING RegistryPath
= Context2
;
581 PVIDEO_PORT_DRIVER_EXTENSION DriverExtension
;
582 BOOLEAN PnpDriver
= FALSE
, LegacyDetection
= FALSE
;
584 TRACE_(VIDEOPRT
, "VideoPortInitialize\n");
587 * As a first thing do parameter checks.
590 if (HwInitializationData
->HwInitDataSize
> sizeof(VIDEO_HW_INITIALIZATION_DATA
))
592 return STATUS_REVISION_MISMATCH
;
595 if (HwInitializationData
->HwFindAdapter
== NULL
||
596 HwInitializationData
->HwInitialize
== NULL
||
597 HwInitializationData
->HwStartIO
== NULL
)
599 return STATUS_INVALID_PARAMETER
;
602 switch (HwInitializationData
->HwInitDataSize
)
605 * NT4 drivers are special case, because we must use legacy method
606 * of detection instead of the Plug & Play one.
609 case SIZE_OF_NT4_VIDEO_HW_INITIALIZATION_DATA
:
610 INFO_(VIDEOPRT
, "We were loaded by a Windows NT miniport driver.\n");
613 case SIZE_OF_W2K_VIDEO_HW_INITIALIZATION_DATA
:
614 INFO_(VIDEOPRT
, "We were loaded by a Windows 2000 miniport driver.\n");
617 case sizeof(VIDEO_HW_INITIALIZATION_DATA
):
618 INFO_(VIDEOPRT
, "We were loaded by a Windows XP or later miniport driver.\n");
622 WARN_(VIDEOPRT
, "Invalid HwInitializationData size.\n");
623 return STATUS_UNSUCCESSFUL
;
626 /* Set dispatching routines */
627 DriverObject
->MajorFunction
[IRP_MJ_CREATE
] = IntVideoPortDispatchOpen
;
628 DriverObject
->MajorFunction
[IRP_MJ_CLOSE
] = IntVideoPortDispatchClose
;
629 DriverObject
->MajorFunction
[IRP_MJ_DEVICE_CONTROL
] =
630 IntVideoPortDispatchDeviceControl
;
631 DriverObject
->MajorFunction
[IRP_MJ_INTERNAL_DEVICE_CONTROL
] =
632 IntVideoPortDispatchDeviceControl
;
633 DriverObject
->MajorFunction
[IRP_MJ_WRITE
] =
634 IntVideoPortDispatchWrite
; // ReactOS-specific hack
635 DriverObject
->DriverUnload
= IntVideoPortUnload
;
637 /* Determine type of the miniport driver */
638 if ((HwInitializationData
->HwInitDataSize
>=
639 FIELD_OFFSET(VIDEO_HW_INITIALIZATION_DATA
, HwQueryInterface
))
640 && HwInitializationData
->HwSetPowerState
641 && HwInitializationData
->HwGetPowerState
642 && HwInitializationData
->HwGetVideoChildDescriptor
)
644 INFO_(VIDEOPRT
, "The miniport is a PnP miniport driver\n");
648 /* Check if legacy detection should be applied */
649 if (!PnpDriver
|| HwContext
)
651 INFO_(VIDEOPRT
, "Legacy detection for adapter interface %d\n",
652 HwInitializationData
->AdapterInterfaceType
);
654 /* FIXME: Move the code for legacy detection
655 to another function and call it here */
656 LegacyDetection
= TRUE
;
661 * The driver extension can be already allocated in case that we were
662 * called by legacy driver and failed detecting device. Some miniport
663 * drivers in that case adjust parameters and call VideoPortInitialize
667 DriverExtension
= IoGetDriverObjectExtension(DriverObject
, DriverObject
);
668 if (DriverExtension
== NULL
)
670 Status
= IoAllocateDriverObjectExtension(
673 sizeof(VIDEO_PORT_DRIVER_EXTENSION
),
674 (PVOID
*)&DriverExtension
);
676 if (!NT_SUCCESS(Status
))
682 * Save the registry path. This should be done only once even if
683 * VideoPortInitialize is called multiple times.
686 if (RegistryPath
->Length
!= 0)
688 DriverExtension
->RegistryPath
.Length
= 0;
689 DriverExtension
->RegistryPath
.MaximumLength
=
690 RegistryPath
->Length
+ sizeof(UNICODE_NULL
);
691 DriverExtension
->RegistryPath
.Buffer
=
692 ExAllocatePoolWithTag(
694 DriverExtension
->RegistryPath
.MaximumLength
,
696 if (DriverExtension
->RegistryPath
.Buffer
== NULL
)
698 RtlInitUnicodeString(&DriverExtension
->RegistryPath
, NULL
);
699 return STATUS_INSUFFICIENT_RESOURCES
;
702 RtlCopyUnicodeString(&DriverExtension
->RegistryPath
, RegistryPath
);
703 INFO_(VIDEOPRT
, "RegistryPath: %wZ\n", &DriverExtension
->RegistryPath
);
707 RtlInitUnicodeString(&DriverExtension
->RegistryPath
, NULL
);
712 * Copy the correct miniport initialization data to the device extension.
716 &DriverExtension
->InitializationData
,
717 HwInitializationData
,
718 HwInitializationData
->HwInitDataSize
);
719 if (HwInitializationData
->HwInitDataSize
<
720 sizeof(VIDEO_HW_INITIALIZATION_DATA
))
722 RtlZeroMemory((PVOID
)((ULONG_PTR
)&DriverExtension
->InitializationData
+
723 HwInitializationData
->HwInitDataSize
),
724 sizeof(VIDEO_HW_INITIALIZATION_DATA
) -
725 HwInitializationData
->HwInitDataSize
);
727 DriverExtension
->HwContext
= HwContext
;
730 * Plug & Play drivers registers the device in AddDevice routine. For
731 * legacy drivers we must do it now.
736 PDEVICE_OBJECT DeviceObject
;
738 if (HwInitializationData
->HwInitDataSize
!= SIZE_OF_NT4_VIDEO_HW_INITIALIZATION_DATA
)
740 /* power management */
741 DriverObject
->MajorFunction
[IRP_MJ_POWER
] = IntVideoPortDispatchPower
;
743 Status
= IntVideoPortCreateAdapterDeviceObject(DriverObject
, DriverExtension
,
744 NULL
, &DeviceObject
);
745 INFO_(VIDEOPRT
, "IntVideoPortCreateAdapterDeviceObject returned 0x%x\n", Status
);
746 if (!NT_SUCCESS(Status
))
748 Status
= IntVideoPortFindAdapter(DriverObject
, DriverExtension
, DeviceObject
);
749 INFO_(VIDEOPRT
, "IntVideoPortFindAdapter returned 0x%x\n", Status
);
750 if (NT_SUCCESS(Status
))
751 VideoPortDeviceNumber
++;
756 DriverObject
->DriverExtension
->AddDevice
= IntVideoPortAddDevice
;
757 DriverObject
->MajorFunction
[IRP_MJ_PNP
] = IntVideoPortDispatchPnp
;
758 DriverObject
->MajorFunction
[IRP_MJ_POWER
] = IntVideoPortDispatchPower
;
759 DriverObject
->MajorFunction
[IRP_MJ_SYSTEM_CONTROL
] = IntVideoPortDispatchSystemControl
;
761 return STATUS_SUCCESS
;
771 IN VIDEO_DEBUG_LEVEL DebugPrintLevel
,
772 IN PCHAR DebugMessage
, ...)
776 va_start(ap
, DebugMessage
);
777 vDbgPrintEx(DPFLTR_IHVVIDEO_ID
, DebugPrintLevel
, DebugMessage
, ap
);
787 IN PVOID HwDeviceExtension
,
788 IN PVIDEO_REQUEST_PACKET Vrp OPTIONAL
,
789 IN VP_STATUS ErrorCode
,
794 INFO_(VIDEOPRT
, "VideoPortLogError ErrorCode %d (0x%x) UniqueId %lu (0x%lx)\n",
795 ErrorCode
, ErrorCode
, UniqueId
, UniqueId
);
797 INFO_(VIDEOPRT
, "Vrp->IoControlCode %lu (0x%lx)\n", Vrp
->IoControlCode
, Vrp
->IoControlCode
);
805 VideoPortGetCurrentIrql(VOID
)
807 return KeGetCurrentIrql();
810 typedef struct QueryRegistryCallbackContext
812 PVOID HwDeviceExtension
;
814 PMINIPORT_GET_REGISTRY_ROUTINE HwGetRegistryRoutine
;
815 } QUERY_REGISTRY_CALLBACK_CONTEXT
, *PQUERY_REGISTRY_CALLBACK_CONTEXT
;
817 static NTSTATUS NTAPI
818 QueryRegistryCallback(
822 IN ULONG ValueLength
,
824 IN PVOID EntryContext
)
826 PQUERY_REGISTRY_CALLBACK_CONTEXT CallbackContext
= (PQUERY_REGISTRY_CALLBACK_CONTEXT
) Context
;
828 INFO_(VIDEOPRT
, "Found registry value for name %S: type %d, length %d\n",
829 ValueName
, ValueType
, ValueLength
);
830 return (*(CallbackContext
->HwGetRegistryRoutine
))(
831 CallbackContext
->HwDeviceExtension
,
832 CallbackContext
->HwContext
,
843 VideoPortGetRegistryParameters(
844 IN PVOID HwDeviceExtension
,
845 IN PWSTR ParameterName
,
846 IN UCHAR IsParameterFileName
,
847 IN PMINIPORT_GET_REGISTRY_ROUTINE GetRegistryRoutine
,
850 RTL_QUERY_REGISTRY_TABLE QueryTable
[2] = {{0}};
851 QUERY_REGISTRY_CALLBACK_CONTEXT Context
;
852 PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension
;
854 DeviceExtension
= VIDEO_PORT_GET_DEVICE_EXTENSION(HwDeviceExtension
);
856 TRACE_(VIDEOPRT
, "VideoPortGetRegistryParameters ParameterName %S, RegPath: %wZ\n",
857 ParameterName
, &DeviceExtension
->RegistryPath
);
859 Context
.HwDeviceExtension
= HwDeviceExtension
;
860 Context
.HwContext
= HwContext
;
861 Context
.HwGetRegistryRoutine
= GetRegistryRoutine
;
863 QueryTable
[0].QueryRoutine
= QueryRegistryCallback
;
864 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_REQUIRED
;
865 QueryTable
[0].Name
= ParameterName
;
867 if (!NT_SUCCESS(RtlQueryRegistryValues(
868 RTL_REGISTRY_ABSOLUTE
,
869 DeviceExtension
->RegistryPath
.Buffer
,
874 WARN_(VIDEOPRT
, "VideoPortGetRegistryParameters could not find the "
875 "requested parameter\n");
876 return ERROR_INVALID_PARAMETER
;
879 if (IsParameterFileName
)
881 /* FIXME: need to read the contents of the file */
893 VideoPortSetRegistryParameters(
894 IN PVOID HwDeviceExtension
,
897 IN ULONG ValueLength
)
901 TRACE_(VIDEOPRT
, "VideoPortSetRegistryParameters ParameterName %S, RegPath: %wZ\n",
903 &VIDEO_PORT_GET_DEVICE_EXTENSION(HwDeviceExtension
)->RegistryPath
);
904 ASSERT_IRQL_LESS_OR_EQUAL(PASSIVE_LEVEL
);
905 Status
= RtlWriteRegistryValue(
906 RTL_REGISTRY_ABSOLUTE
,
907 VIDEO_PORT_GET_DEVICE_EXTENSION(HwDeviceExtension
)->RegistryPath
.Buffer
,
913 if (Status
!= NO_ERROR
)
914 WARN_(VIDEOPRT
, "VideoPortSetRegistryParameters error 0x%x\n", Status
);
924 VideoPortGetVgaStatus(
925 IN PVOID HwDeviceExtension
,
926 OUT PULONG VgaStatus
)
928 PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension
;
930 TRACE_(VIDEOPRT
, "VideoPortGetVgaStatus\n");
932 DeviceExtension
= VIDEO_PORT_GET_DEVICE_EXTENSION(HwDeviceExtension
);
933 if (KeGetCurrentIrql() == PASSIVE_LEVEL
)
935 if (DeviceExtension
->AdapterInterfaceType
== PCIBus
)
937 /* VgaStatus: 0 == VGA not enabled, 1 == VGA enabled. */
938 /* Assumed for now */
944 return ERROR_INVALID_FUNCTION
;
952 VideoPortGetRomImage(
953 IN PVOID HwDeviceExtension
,
958 static PVOID RomImageBuffer
= NULL
;
959 PKPROCESS CallingProcess
;
962 TRACE_(VIDEOPRT
, "VideoPortGetRomImage(HwDeviceExtension 0x%X Length 0x%X)\n",
963 HwDeviceExtension
, Length
);
965 /* If the length is zero then free the existing buffer. */
968 if (RomImageBuffer
!= NULL
)
970 ExFreePool(RomImageBuffer
);
971 RomImageBuffer
= NULL
;
978 * The DDK says we shouldn't use the legacy C0000 method but get the
979 * rom base address from the corresponding pci or acpi register but
980 * lets ignore that and use C0000 anyway. We have already mapped the
981 * bios area into memory so we'll copy from there.
985 Length
= min(Length
, 0x10000);
986 if (RomImageBuffer
!= NULL
)
988 ExFreePool(RomImageBuffer
);
991 RomImageBuffer
= ExAllocatePool(PagedPool
, Length
);
992 if (RomImageBuffer
== NULL
)
997 IntAttachToCSRSS(&CallingProcess
, &ApcState
);
998 RtlCopyMemory(RomImageBuffer
, (PUCHAR
)0xC0000, Length
);
999 IntDetachFromCSRSS(&CallingProcess
, &ApcState
);
1001 return RomImageBuffer
;
1011 IN PVOID HwDeviceExtension
,
1018 PUCHAR SearchLocation
;
1020 TRACE_(VIDEOPRT
, "VideoPortScanRom RomBase %p RomLength 0x%x String %s\n", RomBase
, RomLength
, String
);
1022 StringLength
= strlen((PCHAR
)String
);
1024 SearchLocation
= RomBase
;
1025 for (SearchLocation
= RomBase
;
1026 !Found
&& SearchLocation
< RomBase
+ RomLength
- StringLength
;
1029 Found
= (RtlCompareMemory(SearchLocation
, String
, StringLength
) == StringLength
);
1032 INFO_(VIDEOPRT
, "Match found at %p\n", SearchLocation
);
1044 VideoPortSynchronizeExecution(
1045 IN PVOID HwDeviceExtension
,
1046 IN VIDEO_SYNCHRONIZE_PRIORITY Priority
,
1047 IN PMINIPORT_SYNCHRONIZE_ROUTINE SynchronizeRoutine
,
1051 PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension
;
1057 Ret
= (*SynchronizeRoutine
)(Context
);
1060 case VpMediumPriority
:
1061 DeviceExtension
= VIDEO_PORT_GET_DEVICE_EXTENSION(HwDeviceExtension
);
1062 if (DeviceExtension
->InterruptObject
== NULL
)
1063 Ret
= (*SynchronizeRoutine
)(Context
);
1065 Ret
= KeSynchronizeExecution(
1066 DeviceExtension
->InterruptObject
,
1071 case VpHighPriority
:
1072 OldIrql
= KeGetCurrentIrql();
1073 if (OldIrql
< SYNCH_LEVEL
)
1074 KeRaiseIrql(SYNCH_LEVEL
, &OldIrql
);
1076 Ret
= (*SynchronizeRoutine
)(Context
);
1078 if (OldIrql
< SYNCH_LEVEL
)
1079 KeLowerIrql(OldIrql
);
1094 VideoPortEnumerateChildren(
1095 IN PVOID HwDeviceExtension
,
1098 PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension
;
1100 VIDEO_CHILD_ENUM_INFO ChildEnumInfo
;
1101 VIDEO_CHILD_TYPE ChildType
;
1102 BOOLEAN bHaveLastMonitorID
= FALSE
;
1103 UCHAR LastMonitorID
[10];
1104 UCHAR ChildDescriptor
[256];
1109 DeviceExtension
= VIDEO_PORT_GET_DEVICE_EXTENSION(HwDeviceExtension
);
1110 if (DeviceExtension
->DriverExtension
->InitializationData
.HwGetVideoChildDescriptor
== NULL
)
1112 WARN_(VIDEOPRT
, "Miniport's HwGetVideoChildDescriptor is NULL!\n");
1116 /* Setup the ChildEnumInfo */
1117 ChildEnumInfo
.Size
= sizeof (ChildEnumInfo
);
1118 ChildEnumInfo
.ChildDescriptorSize
= sizeof (ChildDescriptor
);
1119 ChildEnumInfo
.ACPIHwId
= 0;
1120 ChildEnumInfo
.ChildHwDeviceExtension
= NULL
; /* FIXME: must be set to
1121 ChildHwDeviceExtension... */
1123 /* Enumerate the children */
1126 ChildEnumInfo
.ChildIndex
= i
;
1127 RtlZeroMemory(ChildDescriptor
, sizeof(ChildDescriptor
));
1128 Status
= DeviceExtension
->DriverExtension
->InitializationData
.HwGetVideoChildDescriptor(
1135 if (Status
== VIDEO_ENUM_MORE_DEVICES
)
1137 if (ChildType
== Monitor
)
1139 // Check if the EDID is valid
1140 if (ChildDescriptor
[0] == 0x00 &&
1141 ChildDescriptor
[1] == 0xFF &&
1142 ChildDescriptor
[2] == 0xFF &&
1143 ChildDescriptor
[3] == 0xFF &&
1144 ChildDescriptor
[4] == 0xFF &&
1145 ChildDescriptor
[5] == 0xFF &&
1146 ChildDescriptor
[6] == 0xFF &&
1147 ChildDescriptor
[7] == 0x00)
1149 if (bHaveLastMonitorID
)
1151 // Compare the previous monitor ID with the current one, break the loop if they are identical
1152 if (RtlCompareMemory(LastMonitorID
, &ChildDescriptor
[8], sizeof(LastMonitorID
)) == sizeof(LastMonitorID
))
1154 INFO_(VIDEOPRT
, "Found identical Monitor ID two times, stopping enumeration\n");
1159 // Copy 10 bytes from the EDID, which can be used to uniquely identify the monitor
1160 RtlCopyMemory(LastMonitorID
, &ChildDescriptor
[8], sizeof(LastMonitorID
));
1161 bHaveLastMonitorID
= TRUE
;
1165 else if (Status
== VIDEO_ENUM_INVALID_DEVICE
)
1167 WARN_(VIDEOPRT
, "Child device %d is invalid!\n", ChildEnumInfo
.ChildIndex
);
1170 else if (Status
== VIDEO_ENUM_NO_MORE_DEVICES
)
1172 INFO_(VIDEOPRT
, "End of child enumeration! (%d children enumerated)\n", i
- 1);
1177 WARN_(VIDEOPRT
, "HwGetVideoChildDescriptor returned unknown status code 0x%x!\n", Status
);
1182 if (ChildType
== Monitor
)
1185 PUCHAR p
= ChildDescriptor
;
1186 INFO_(VIDEOPRT
, "Monitor device enumerated! (ChildId = 0x%x)\n", ChildId
);
1187 for (j
= 0; j
< sizeof (ChildDescriptor
); j
+= 8)
1189 INFO_(VIDEOPRT
, "%02x %02x %02x %02x %02x %02x %02x %02x\n",
1190 p
[j
+0], p
[j
+1], p
[j
+2], p
[j
+3],
1191 p
[j
+4], p
[j
+5], p
[j
+6], p
[j
+7]);
1194 else if (ChildType
== Other
)
1196 INFO_(VIDEOPRT
, "\"Other\" device enumerated: DeviceId = %S\n", (PWSTR
)ChildDescriptor
);
1200 WARN_(VIDEOPRT
, "HwGetVideoChildDescriptor returned unsupported type: %d\n", ChildType
);
1214 VideoPortCreateSecondaryDisplay(
1215 IN PVOID HwDeviceExtension
,
1216 IN OUT PVOID
*SecondaryDeviceExtension
,
1220 return ERROR_DEV_NOT_EXIST
;
1229 IN PVOID HwDeviceExtension
,
1230 IN PMINIPORT_DPC_ROUTINE CallbackRoutine
,
1233 return KeInsertQueueDpc(
1234 &VIDEO_PORT_GET_DEVICE_EXTENSION(HwDeviceExtension
)->DpcObject
,
1235 (PVOID
)CallbackRoutine
,
1244 VideoPortGetAssociatedDeviceExtension(IN PVOID DeviceObject
)
1246 PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension
;
1248 TRACE_(VIDEOPRT
, "VideoPortGetAssociatedDeviceExtension\n");
1249 DeviceExtension
= ((PDEVICE_OBJECT
)DeviceObject
)->DeviceExtension
;
1250 if (!DeviceExtension
)
1252 return DeviceExtension
->MiniPortDeviceExtension
;
1260 VideoPortGetVersion(
1261 IN PVOID HwDeviceExtension
,
1262 IN OUT PVPOSVERSIONINFO VpOsVersionInfo
)
1264 RTL_OSVERSIONINFOEXW Version
;
1266 Version
.dwOSVersionInfoSize
= sizeof(RTL_OSVERSIONINFOEXW
);
1267 if (VpOsVersionInfo
->Size
>= sizeof(VPOSVERSIONINFO
))
1270 if (NT_SUCCESS(RtlGetVersion((PRTL_OSVERSIONINFOW
)&Version
)))
1272 VpOsVersionInfo
->MajorVersion
= Version
.dwMajorVersion
;
1273 VpOsVersionInfo
->MinorVersion
= Version
.dwMinorVersion
;
1274 VpOsVersionInfo
->BuildNumber
= Version
.dwBuildNumber
;
1275 VpOsVersionInfo
->ServicePackMajor
= Version
.wServicePackMajor
;
1276 VpOsVersionInfo
->ServicePackMinor
= Version
.wServicePackMinor
;
1279 return ERROR_INVALID_PARAMETER
;
1281 VpOsVersionInfo
->MajorVersion
= 5;
1282 VpOsVersionInfo
->MinorVersion
= 0;
1283 VpOsVersionInfo
->BuildNumber
= 2195;
1284 VpOsVersionInfo
->ServicePackMajor
= 4;
1285 VpOsVersionInfo
->ServicePackMinor
= 0;
1290 return ERROR_INVALID_PARAMETER
;
1298 VideoPortCheckForDeviceExistence(
1299 IN PVOID HwDeviceExtension
,
1302 IN UCHAR RevisionId
,
1303 IN USHORT SubVendorId
,
1304 IN USHORT SubSystemId
,
1307 PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension
;
1308 PCI_DEVICE_PRESENT_INTERFACE PciDevicePresentInterface
;
1309 IO_STATUS_BLOCK IoStatusBlock
;
1310 IO_STACK_LOCATION IoStack
;
1315 TRACE_(VIDEOPRT
, "VideoPortCheckForDeviceExistence\n");
1317 if (Flags
& ~(CDE_USE_REVISION
| CDE_USE_SUBSYSTEM_IDS
))
1319 WARN_(VIDEOPRT
, "VideoPortCheckForDeviceExistence: Unknown flags 0x%lx\n", Flags
& ~(CDE_USE_REVISION
| CDE_USE_SUBSYSTEM_IDS
));
1323 DeviceExtension
= VIDEO_PORT_GET_DEVICE_EXTENSION(HwDeviceExtension
);
1325 PciDevicePresentInterface
.Size
= sizeof(PCI_DEVICE_PRESENT_INTERFACE
);
1326 PciDevicePresentInterface
.Version
= 1;
1327 IoStack
.Parameters
.QueryInterface
.Size
= PciDevicePresentInterface
.Size
;
1328 IoStack
.Parameters
.QueryInterface
.Version
= PciDevicePresentInterface
.Version
;
1329 IoStack
.Parameters
.QueryInterface
.Interface
= (PINTERFACE
)&PciDevicePresentInterface
;
1330 IoStack
.Parameters
.QueryInterface
.InterfaceType
=
1331 &GUID_PCI_DEVICE_PRESENT_INTERFACE
;
1332 Status
= IopInitiatePnpIrp(DeviceExtension
->NextDeviceObject
,
1333 &IoStatusBlock
, IRP_MN_QUERY_INTERFACE
, &IoStack
);
1334 if (!NT_SUCCESS(Status
))
1336 WARN_(VIDEOPRT
, "IopInitiatePnpIrp() failed! (Status 0x%lx)\n", Status
);
1340 if (Flags
& CDE_USE_REVISION
)
1341 PciFlags
|= PCI_USE_REVISION
;
1342 if (Flags
& CDE_USE_SUBSYSTEM_IDS
)
1343 PciFlags
|= PCI_USE_SUBSYSTEM_IDS
;
1345 DevicePresent
= PciDevicePresentInterface
.IsDevicePresent(
1346 VendorId
, DeviceId
, RevisionId
,
1347 SubVendorId
, SubSystemId
, PciFlags
);
1349 PciDevicePresentInterface
.InterfaceDereference(PciDevicePresentInterface
.Context
);
1351 return DevicePresent
;
1359 VideoPortRegisterBugcheckCallback(
1360 IN PVOID HwDeviceExtension
,
1361 IN ULONG BugcheckCode
,
1362 IN PVIDEO_BUGCHECK_CALLBACK Callback
,
1363 IN ULONG BugcheckDataSize
)
1374 VideoPortQueryPerformanceCounter(
1375 IN PVOID HwDeviceExtension
,
1376 OUT PLONGLONG PerformanceFrequency OPTIONAL
)
1378 LARGE_INTEGER Result
;
1380 TRACE_(VIDEOPRT
, "VideoPortQueryPerformanceCounter\n");
1381 Result
= KeQueryPerformanceCounter((PLARGE_INTEGER
)PerformanceFrequency
);
1382 return Result
.QuadPart
;
1390 VideoPortAcquireDeviceLock(
1391 IN PVOID HwDeviceExtension
)
1393 PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension
;
1397 TRACE_(VIDEOPRT
, "VideoPortAcquireDeviceLock\n");
1398 DeviceExtension
= VIDEO_PORT_GET_DEVICE_EXTENSION(HwDeviceExtension
);
1399 Status
= KeWaitForMutexObject(&DeviceExtension
->DeviceLock
, Executive
,
1400 KernelMode
, FALSE
, NULL
);
1401 // ASSERT(Status == STATUS_SUCCESS);
1409 VideoPortReleaseDeviceLock(
1410 IN PVOID HwDeviceExtension
)
1412 PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension
;
1416 TRACE_(VIDEOPRT
, "VideoPortReleaseDeviceLock\n");
1417 DeviceExtension
= VIDEO_PORT_GET_DEVICE_EXTENSION(HwDeviceExtension
);
1418 Status
= KeReleaseMutex(&DeviceExtension
->DeviceLock
, FALSE
);
1419 //ASSERT(Status == STATUS_SUCCESS);
1428 IN PDEVICE_OBJECT DeviceObject
,
1438 VideoPortAllocateContiguousMemory(
1439 IN PVOID HwDeviceExtension
,
1440 IN ULONG NumberOfBytes
,
1441 IN PHYSICAL_ADDRESS HighestAcceptableAddress
1445 return MmAllocateContiguousMemory(NumberOfBytes
, HighestAcceptableAddress
);
1452 VideoPortIsNoVesa(VOID
)
1456 UNICODE_STRING Path
= RTL_CONSTANT_STRING(L
"\\REGISTRY\\MACHINE\\SYSTEM\\CurrentControlSet\\Control");
1457 UNICODE_STRING ValueName
= RTL_CONSTANT_STRING(L
"SystemStartOptions");
1458 OBJECT_ATTRIBUTES ObjectAttributes
;
1459 PKEY_VALUE_PARTIAL_INFORMATION KeyInfo
;
1460 ULONG Length
, NewLength
;
1462 /* Initialize object attributes with the path we want */
1463 InitializeObjectAttributes(&ObjectAttributes
,
1465 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
1470 Status
= ZwOpenKey(&KeyHandle
,
1474 if (!NT_SUCCESS(Status
))
1476 VideoPortDebugPrint(Error
, "ZwOpenKey failed (0x%x)\n", Status
);
1480 /* Find out how large our buffer should be */
1481 Status
= ZwQueryValueKey(KeyHandle
,
1483 KeyValuePartialInformation
,
1487 if (Status
!= STATUS_BUFFER_OVERFLOW
&& Status
!= STATUS_BUFFER_TOO_SMALL
)
1489 VideoPortDebugPrint(Error
, "ZwQueryValueKey failed (0x%x)\n", Status
);
1495 KeyInfo
= ExAllocatePool(PagedPool
, Length
);
1498 VideoPortDebugPrint(Error
, "Out of memory\n");
1503 /* Now for real this time */
1504 Status
= ZwQueryValueKey(KeyHandle
,
1506 KeyValuePartialInformation
,
1513 if (!NT_SUCCESS(Status
))
1515 VideoPortDebugPrint(Error
, "ZwQueryValueKey failed (0x%x)\n", Status
);
1516 ExFreePool(KeyInfo
);
1521 if (KeyInfo
->Type
!= REG_SZ
)
1523 VideoPortDebugPrint(Error
, "Invalid type for SystemStartOptions\n");
1524 ExFreePool(KeyInfo
);
1528 /* Check if NOVESA or BASEVIDEO is present in the start options */
1529 if (wcsstr((PWCHAR
)KeyInfo
->Data
, L
"NOVESA") ||
1530 wcsstr((PWCHAR
)KeyInfo
->Data
, L
"BASEVIDEO"))
1532 VideoPortDebugPrint(Info
, "VESA mode disabled\n");
1533 ExFreePool(KeyInfo
);
1537 ExFreePool(KeyInfo
);
1539 VideoPortDebugPrint(Info
, "VESA mode enabled\n");