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 ULONG CsrssInitialized
= FALSE
;
34 PKPROCESS Csrss
= NULL
;
35 ULONG VideoPortDeviceNumber
= 0;
36 KMUTEX VideoPortInt10Mutex
;
38 /* PRIVATE FUNCTIONS **********************************************************/
46 return STATUS_SUCCESS
;
51 IntVideoPortImageDirectoryEntryToData(
55 PIMAGE_NT_HEADERS NtHeader
;
58 NtHeader
= RtlImageNtHeader(BaseAddress
);
62 if (Directory
>= NtHeader
->OptionalHeader
.NumberOfRvaAndSizes
)
65 Va
= NtHeader
->OptionalHeader
.DataDirectory
[Directory
].VirtualAddress
;
69 return (PVOID
)((ULONG_PTR
)BaseAddress
+ Va
);
74 IntVideoPortDeferredRoutine(
76 IN PVOID DeferredContext
,
77 IN PVOID SystemArgument1
,
78 IN PVOID SystemArgument2
)
80 PVOID HwDeviceExtension
=
81 &((PVIDEO_PORT_DEVICE_EXTENSION
)DeferredContext
)->MiniPortDeviceExtension
;
82 ((PMINIPORT_DPC_ROUTINE
)SystemArgument1
)(HwDeviceExtension
, SystemArgument2
);
87 IntVideoPortCreateAdapterDeviceObject(
88 IN PDRIVER_OBJECT DriverObject
,
89 IN PVIDEO_PORT_DRIVER_EXTENSION DriverExtension
,
90 IN PDEVICE_OBJECT PhysicalDeviceObject
,
91 OUT PDEVICE_OBJECT
*DeviceObject OPTIONAL
)
93 PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension
;
96 PCI_SLOT_NUMBER SlotNumber
;
99 WCHAR DeviceBuffer
[20];
100 UNICODE_STRING DeviceName
;
101 PDEVICE_OBJECT DeviceObject_
;
103 if (DeviceObject
== NULL
)
104 DeviceObject
= &DeviceObject_
;
107 * Find the first free device number that can be used for video device
108 * object names and symlinks.
110 DeviceNumber
= VideoPortDeviceNumber
;
111 if (DeviceNumber
== 0xFFFFFFFF)
113 WARN_(VIDEOPRT
, "Can't find free device number\n");
114 return STATUS_UNSUCCESSFUL
;
118 * Create the device object.
121 /* Create a unicode device name. */
122 swprintf(DeviceBuffer
, L
"\\Device\\Video%lu", DeviceNumber
);
123 RtlInitUnicodeString(&DeviceName
, DeviceBuffer
);
125 INFO_(VIDEOPRT
, "HwDeviceExtension size is: 0x%x\n",
126 DriverExtension
->InitializationData
.HwDeviceExtensionSize
);
128 /* Create the device object. */
129 Size
= sizeof(VIDEO_PORT_DEVICE_EXTENSION
) +
130 DriverExtension
->InitializationData
.HwDeviceExtensionSize
;
131 Status
= IoCreateDevice(DriverObject
,
139 if (!NT_SUCCESS(Status
))
141 WARN_(VIDEOPRT
, "IoCreateDevice call failed with status 0x%08x\n", Status
);
146 * Set the buffering strategy here. If you change this, remember
147 * to change VidDispatchDeviceControl too.
150 (*DeviceObject
)->Flags
|= DO_BUFFERED_IO
;
152 /* Initialize device extension. */
153 DeviceExtension
= (PVIDEO_PORT_DEVICE_EXTENSION
)((*DeviceObject
)->DeviceExtension
);
154 DeviceExtension
->Common
.Fdo
= TRUE
;
155 DeviceExtension
->DeviceNumber
= DeviceNumber
;
156 DeviceExtension
->DriverObject
= DriverObject
;
157 DeviceExtension
->PhysicalDeviceObject
= PhysicalDeviceObject
;
158 DeviceExtension
->FunctionalDeviceObject
= *DeviceObject
;
159 DeviceExtension
->DriverExtension
= DriverExtension
;
160 DeviceExtension
->SessionId
= -1;
162 InitializeListHead(&DeviceExtension
->ChildDeviceList
);
164 /* Get the registry path associated with this device. */
165 Status
= IntCreateRegistryPath(&DriverExtension
->RegistryPath
,
166 &DeviceExtension
->RegistryPath
);
167 if (!NT_SUCCESS(Status
))
169 WARN_(VIDEOPRT
, "IntCreateRegistryPath() call failed with status 0x%08x\n", Status
);
170 IoDeleteDevice(*DeviceObject
);
171 *DeviceObject
= NULL
;
175 if (PhysicalDeviceObject
!= NULL
)
177 /* Get bus number from the upper level bus driver. */
178 Size
= sizeof(ULONG
);
179 Status
= IoGetDeviceProperty(PhysicalDeviceObject
,
180 DevicePropertyBusNumber
,
182 &DeviceExtension
->SystemIoBusNumber
,
184 if (!NT_SUCCESS(Status
))
186 WARN_(VIDEOPRT
, "Couldn't get an information from bus driver. We will try to\n"
187 "use legacy detection method, but even that doesn't mean that\n"
189 DeviceExtension
->PhysicalDeviceObject
= NULL
;
193 DeviceExtension
->AdapterInterfaceType
=
194 DriverExtension
->InitializationData
.AdapterInterfaceType
;
196 if (PhysicalDeviceObject
!= NULL
)
198 /* Get bus type from the upper level bus driver. */
199 Size
= sizeof(ULONG
);
200 IoGetDeviceProperty(PhysicalDeviceObject
,
201 DevicePropertyLegacyBusType
,
203 &DeviceExtension
->AdapterInterfaceType
,
206 /* Get bus device address from the upper level bus driver. */
207 Size
= sizeof(ULONG
);
208 IoGetDeviceProperty(PhysicalDeviceObject
,
209 DevicePropertyAddress
,
214 /* Convert slotnumber to PCI_SLOT_NUMBER */
215 SlotNumber
.u
.AsULONG
= 0;
216 SlotNumber
.u
.bits
.DeviceNumber
= (PciSlotNumber
>> 16) & 0xFFFF;
217 SlotNumber
.u
.bits
.FunctionNumber
= PciSlotNumber
& 0xFFFF;
218 DeviceExtension
->SystemIoSlotNumber
= SlotNumber
.u
.AsULONG
;
221 InitializeListHead(&DeviceExtension
->AddressMappingListHead
);
222 InitializeListHead(&DeviceExtension
->DmaAdapterList
);
224 KeInitializeDpc(&DeviceExtension
->DpcObject
,
225 IntVideoPortDeferredRoutine
,
228 KeInitializeMutex(&DeviceExtension
->DeviceLock
, 0);
230 /* Attach the device. */
231 if (PhysicalDeviceObject
!= NULL
)
232 DeviceExtension
->NextDeviceObject
= IoAttachDeviceToDeviceStack(
234 PhysicalDeviceObject
);
236 IntCreateNewRegistryPath(DeviceExtension
);
237 IntSetupDeviceSettingsKey(DeviceExtension
);
239 /* Remove the initailizing flag */
240 (*DeviceObject
)->Flags
&= ~DO_DEVICE_INITIALIZING
;
241 return STATUS_SUCCESS
;
247 IntVideoPortFindAdapter(
248 IN PDRIVER_OBJECT DriverObject
,
249 IN PVIDEO_PORT_DRIVER_EXTENSION DriverExtension
,
250 IN PDEVICE_OBJECT DeviceObject
)
252 WCHAR DeviceVideoBuffer
[20];
253 PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension
;
255 VIDEO_PORT_CONFIG_INFO ConfigInfo
;
256 SYSTEM_BASIC_INFORMATION SystemBasicInfo
;
258 WCHAR DeviceBuffer
[20];
259 UNICODE_STRING DeviceName
;
260 WCHAR SymlinkBuffer
[20];
261 UNICODE_STRING SymlinkName
;
262 BOOL LegacyDetection
= FALSE
;
265 DeviceExtension
= (PVIDEO_PORT_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
266 DeviceNumber
= DeviceExtension
->DeviceNumber
;
268 /* Setup a ConfigInfo structure that we will pass to HwFindAdapter. */
269 RtlZeroMemory(&ConfigInfo
, sizeof(VIDEO_PORT_CONFIG_INFO
));
270 ConfigInfo
.Length
= sizeof(VIDEO_PORT_CONFIG_INFO
);
271 ConfigInfo
.AdapterInterfaceType
= DeviceExtension
->AdapterInterfaceType
;
272 if (ConfigInfo
.AdapterInterfaceType
== PCIBus
)
273 ConfigInfo
.InterruptMode
= LevelSensitive
;
275 ConfigInfo
.InterruptMode
= Latched
;
276 ConfigInfo
.DriverRegistryPath
= DriverExtension
->RegistryPath
.Buffer
;
277 ConfigInfo
.VideoPortGetProcAddress
= IntVideoPortGetProcAddress
;
278 ConfigInfo
.SystemIoBusNumber
= DeviceExtension
->SystemIoBusNumber
;
279 ConfigInfo
.BusInterruptLevel
= DeviceExtension
->InterruptLevel
;
280 ConfigInfo
.BusInterruptVector
= DeviceExtension
->InterruptVector
;
282 Status
= ZwQuerySystemInformation(SystemBasicInformation
,
284 sizeof(SystemBasicInfo
),
286 if (NT_SUCCESS(Status
))
288 ConfigInfo
.SystemMemorySize
= SystemBasicInfo
.NumberOfPhysicalPages
*
289 SystemBasicInfo
.PageSize
;
293 * Call miniport HwVidFindAdapter entry point to detect if
294 * particular device is present. There are two possible code
295 * paths. The first one is for Legacy drivers (NT4) and cases
296 * when we don't have information about what bus we're on. The
297 * second case is the standard one for Plug & Play drivers.
299 if (DeviceExtension
->PhysicalDeviceObject
== NULL
)
301 LegacyDetection
= TRUE
;
306 ULONG BusNumber
, MaxBuses
;
308 MaxBuses
= DeviceExtension
->AdapterInterfaceType
== PCIBus
? PCI_MAX_BRIDGE_NUMBER
: 1;
310 for (BusNumber
= 0; BusNumber
< MaxBuses
; BusNumber
++)
312 DeviceExtension
->SystemIoBusNumber
=
313 ConfigInfo
.SystemIoBusNumber
= BusNumber
;
315 RtlZeroMemory(&DeviceExtension
->MiniPortDeviceExtension
,
316 DriverExtension
->InitializationData
.HwDeviceExtensionSize
);
318 /* FIXME: Need to figure out what string to pass as param 3. */
319 Status
= DriverExtension
->InitializationData
.HwFindAdapter(
320 &DeviceExtension
->MiniPortDeviceExtension
,
321 DriverExtension
->HwContext
,
326 if (Status
== ERROR_DEV_NOT_EXIST
)
330 else if (Status
== NO_ERROR
)
336 ERR_(VIDEOPRT
, "HwFindAdapter call failed with error 0x%X\n", Status
);
343 /* FIXME: Need to figure out what string to pass as param 3. */
344 Status
= DriverExtension
->InitializationData
.HwFindAdapter(
345 &DeviceExtension
->MiniPortDeviceExtension
,
346 DriverExtension
->HwContext
,
352 if (Status
!= NO_ERROR
)
354 ERR_(VIDEOPRT
, "HwFindAdapter call failed with error 0x%X\n", Status
);
359 * Now we know the device is present, so let's do all additional tasks
360 * such as creating symlinks or setting up interrupts and timer.
363 /* Create a unicode device name. */
364 swprintf(DeviceBuffer
, L
"\\Device\\Video%lu", DeviceNumber
);
365 RtlInitUnicodeString(&DeviceName
, DeviceBuffer
);
367 /* Create symbolic link "\??\DISPLAYx" */
368 swprintf(SymlinkBuffer
, L
"\\??\\DISPLAY%lu", DeviceNumber
+ 1);
369 RtlInitUnicodeString(&SymlinkName
, SymlinkBuffer
);
370 IoCreateSymbolicLink(&SymlinkName
, &DeviceName
);
372 /* Add entry to DEVICEMAP\VIDEO key in registry. */
373 swprintf(DeviceVideoBuffer
, L
"\\Device\\Video%d", DeviceNumber
);
374 RtlWriteRegistryValue(
375 RTL_REGISTRY_DEVICEMAP
,
379 DeviceExtension
->RegistryPath
.Buffer
,
380 DeviceExtension
->RegistryPath
.Length
+ sizeof(UNICODE_NULL
));
382 RtlWriteRegistryValue(
383 RTL_REGISTRY_DEVICEMAP
,
388 sizeof(DeviceNumber
));
390 /* FIXME: Allocate hardware resources for device. */
392 /* Allocate interrupt for device. */
393 if (!IntVideoPortSetupInterrupt(DeviceObject
, DriverExtension
, &ConfigInfo
))
395 Status
= STATUS_INSUFFICIENT_RESOURCES
;
399 /* Allocate timer for device. */
400 if (!IntVideoPortSetupTimer(DeviceObject
, DriverExtension
))
402 if (DeviceExtension
->InterruptObject
!= NULL
)
403 IoDisconnectInterrupt(DeviceExtension
->InterruptObject
);
404 ERR_(VIDEOPRT
, "IntVideoPortSetupTimer failed\n");
405 Status
= STATUS_INSUFFICIENT_RESOURCES
;
409 /* Query children of the device. */
410 VideoPortEnumerateChildren(&DeviceExtension
->MiniPortDeviceExtension
, NULL
);
412 INFO_(VIDEOPRT
, "STATUS_SUCCESS\n");
413 return STATUS_SUCCESS
;
416 RtlFreeUnicodeString(&DeviceExtension
->RegistryPath
);
417 if (DeviceExtension
->NextDeviceObject
)
418 IoDetachDevice(DeviceExtension
->NextDeviceObject
);
419 IoDeleteDevice(DeviceObject
);
426 PKPROCESS
*CallingProcess
,
427 PKAPC_STATE ApcState
)
429 *CallingProcess
= (PKPROCESS
)PsGetCurrentProcess();
430 if (*CallingProcess
!= Csrss
)
432 KeStackAttachProcess(Csrss
, ApcState
);
439 PKPROCESS
*CallingProcess
,
440 PKAPC_STATE ApcState
)
442 if (*CallingProcess
!= Csrss
)
444 KeUnstackDetachProcess(ApcState
);
448 /* PUBLIC FUNCTIONS ***********************************************************/
458 IN PVIDEO_HW_INITIALIZATION_DATA HwInitializationData
,
461 PDRIVER_OBJECT DriverObject
= Context1
;
462 PUNICODE_STRING RegistryPath
= Context2
;
464 PVIDEO_PORT_DRIVER_EXTENSION DriverExtension
;
465 BOOLEAN PnpDriver
= FALSE
, LegacyDetection
= FALSE
;
466 static BOOLEAN Int10MutexInitialized
;
468 TRACE_(VIDEOPRT
, "VideoPortInitialize\n");
470 if (!Int10MutexInitialized
)
472 KeInitializeMutex(&VideoPortInt10Mutex
, 0);
473 Int10MutexInitialized
= TRUE
;
476 /* As a first thing do parameter checks. */
477 if (HwInitializationData
->HwInitDataSize
> sizeof(VIDEO_HW_INITIALIZATION_DATA
))
479 ERR_(VIDEOPRT
, "Invalid HwInitializationData\n");
480 return STATUS_REVISION_MISMATCH
;
483 if ((HwInitializationData
->HwFindAdapter
== NULL
) ||
484 (HwInitializationData
->HwInitialize
== NULL
) ||
485 (HwInitializationData
->HwStartIO
== NULL
))
487 ERR_(VIDEOPRT
, "Invalid HwInitializationData\n");
488 return STATUS_INVALID_PARAMETER
;
491 switch (HwInitializationData
->HwInitDataSize
)
494 * NT4 drivers are special case, because we must use legacy method
495 * of detection instead of the Plug & Play one.
497 case SIZE_OF_NT4_VIDEO_HW_INITIALIZATION_DATA
:
498 INFO_(VIDEOPRT
, "We were loaded by a Windows NT miniport driver.\n");
501 case SIZE_OF_W2K_VIDEO_HW_INITIALIZATION_DATA
:
502 INFO_(VIDEOPRT
, "We were loaded by a Windows 2000 miniport driver.\n");
505 case sizeof(VIDEO_HW_INITIALIZATION_DATA
):
506 INFO_(VIDEOPRT
, "We were loaded by a Windows XP or later miniport driver.\n");
510 ERR_(VIDEOPRT
, "Invalid HwInitializationData size.\n");
511 return STATUS_UNSUCCESSFUL
;
514 /* Set dispatching routines */
515 DriverObject
->MajorFunction
[IRP_MJ_CREATE
] = IntVideoPortDispatchOpen
;
516 DriverObject
->MajorFunction
[IRP_MJ_CLOSE
] = IntVideoPortDispatchClose
;
517 DriverObject
->MajorFunction
[IRP_MJ_DEVICE_CONTROL
] =
518 IntVideoPortDispatchDeviceControl
;
519 DriverObject
->MajorFunction
[IRP_MJ_INTERNAL_DEVICE_CONTROL
] =
520 IntVideoPortDispatchDeviceControl
;
521 DriverObject
->MajorFunction
[IRP_MJ_WRITE
] =
522 IntVideoPortDispatchWrite
; // ReactOS-specific hack
523 DriverObject
->DriverUnload
= IntVideoPortUnload
;
525 /* Determine type of the miniport driver */
526 if ((HwInitializationData
->HwInitDataSize
>=
527 FIELD_OFFSET(VIDEO_HW_INITIALIZATION_DATA
, HwQueryInterface
)) &&
528 (HwInitializationData
->HwSetPowerState
!= NULL
) &&
529 (HwInitializationData
->HwGetPowerState
!= NULL
) &&
530 (HwInitializationData
->HwGetVideoChildDescriptor
!= NULL
))
532 INFO_(VIDEOPRT
, "The miniport is a PnP miniport driver\n");
536 /* Check if legacy detection should be applied */
537 if (!PnpDriver
|| HwContext
)
539 INFO_(VIDEOPRT
, "Legacy detection for adapter interface %d\n",
540 HwInitializationData
->AdapterInterfaceType
);
542 /* FIXME: Move the code for legacy detection
543 to another function and call it here */
544 LegacyDetection
= TRUE
;
549 * The driver extension can be already allocated in case that we were
550 * called by legacy driver and failed detecting device. Some miniport
551 * drivers in that case adjust parameters and call VideoPortInitialize
554 DriverExtension
= IoGetDriverObjectExtension(DriverObject
, DriverObject
);
555 if (DriverExtension
== NULL
)
557 Status
= IoAllocateDriverObjectExtension(DriverObject
,
559 sizeof(VIDEO_PORT_DRIVER_EXTENSION
),
560 (PVOID
*)&DriverExtension
);
561 if (!NT_SUCCESS(Status
))
563 ERR_(VIDEOPRT
, "IoAllocateDriverObjectExtension failed 0x%x\n", Status
);
568 * Save the registry path. This should be done only once even if
569 * VideoPortInitialize is called multiple times.
571 if (RegistryPath
->Length
!= 0)
573 DriverExtension
->RegistryPath
.Length
= 0;
574 DriverExtension
->RegistryPath
.MaximumLength
=
575 RegistryPath
->Length
+ sizeof(UNICODE_NULL
);
576 DriverExtension
->RegistryPath
.Buffer
=
577 ExAllocatePoolWithTag(
579 DriverExtension
->RegistryPath
.MaximumLength
,
581 if (DriverExtension
->RegistryPath
.Buffer
== NULL
)
583 RtlInitUnicodeString(&DriverExtension
->RegistryPath
, NULL
);
584 return STATUS_INSUFFICIENT_RESOURCES
;
587 RtlCopyUnicodeString(&DriverExtension
->RegistryPath
, RegistryPath
);
588 INFO_(VIDEOPRT
, "RegistryPath: %wZ\n", &DriverExtension
->RegistryPath
);
592 RtlInitUnicodeString(&DriverExtension
->RegistryPath
, NULL
);
596 /* Copy the correct miniport initialization data to the device extension. */
597 RtlCopyMemory(&DriverExtension
->InitializationData
,
598 HwInitializationData
,
599 HwInitializationData
->HwInitDataSize
);
600 if (HwInitializationData
->HwInitDataSize
<
601 sizeof(VIDEO_HW_INITIALIZATION_DATA
))
603 RtlZeroMemory((PVOID
)((ULONG_PTR
)&DriverExtension
->InitializationData
+
604 HwInitializationData
->HwInitDataSize
),
605 sizeof(VIDEO_HW_INITIALIZATION_DATA
) -
606 HwInitializationData
->HwInitDataSize
);
608 DriverExtension
->HwContext
= HwContext
;
611 * Plug & Play drivers registers the device in AddDevice routine. For
612 * legacy drivers we must do it now.
616 PDEVICE_OBJECT DeviceObject
;
618 if (HwInitializationData
->HwInitDataSize
!= SIZE_OF_NT4_VIDEO_HW_INITIALIZATION_DATA
)
620 /* power management */
621 DriverObject
->MajorFunction
[IRP_MJ_POWER
] = IntVideoPortDispatchPower
;
624 Status
= IntVideoPortCreateAdapterDeviceObject(DriverObject
,
628 if (!NT_SUCCESS(Status
))
630 ERR_(VIDEOPRT
, "IntVideoPortCreateAdapterDeviceObject returned 0x%x\n", Status
);
634 Status
= IntVideoPortFindAdapter(DriverObject
, DriverExtension
, DeviceObject
);
635 if (NT_SUCCESS(Status
))
636 VideoPortDeviceNumber
++;
638 ERR_(VIDEOPRT
, "IntVideoPortFindAdapter returned 0x%x\n", Status
);
644 DriverObject
->DriverExtension
->AddDevice
= IntVideoPortAddDevice
;
645 DriverObject
->MajorFunction
[IRP_MJ_PNP
] = IntVideoPortDispatchPnp
;
646 DriverObject
->MajorFunction
[IRP_MJ_POWER
] = IntVideoPortDispatchPower
;
647 DriverObject
->MajorFunction
[IRP_MJ_SYSTEM_CONTROL
] = IntVideoPortDispatchSystemControl
;
649 return STATUS_SUCCESS
;
658 IN VIDEO_DEBUG_LEVEL DebugPrintLevel
,
659 IN PCHAR DebugMessage
,
664 va_start(ap
, DebugMessage
);
665 vDbgPrintEx(DPFLTR_IHVVIDEO_ID
, DebugPrintLevel
, DebugMessage
, ap
);
675 IN PVOID HwDeviceExtension
,
676 IN PVIDEO_REQUEST_PACKET Vrp OPTIONAL
,
677 IN VP_STATUS ErrorCode
,
682 INFO_(VIDEOPRT
, "VideoPortLogError ErrorCode %d (0x%x) UniqueId %lu (0x%lx)\n",
683 ErrorCode
, ErrorCode
, UniqueId
, UniqueId
);
685 INFO_(VIDEOPRT
, "Vrp->IoControlCode %lu (0x%lx)\n", Vrp
->IoControlCode
, Vrp
->IoControlCode
);
693 VideoPortGetCurrentIrql(VOID
)
695 return KeGetCurrentIrql();
698 typedef struct QueryRegistryCallbackContext
700 PVOID HwDeviceExtension
;
702 PMINIPORT_GET_REGISTRY_ROUTINE HwGetRegistryRoutine
;
703 } QUERY_REGISTRY_CALLBACK_CONTEXT
, *PQUERY_REGISTRY_CALLBACK_CONTEXT
;
708 QueryRegistryCallback(
712 IN ULONG ValueLength
,
714 IN PVOID EntryContext
)
716 PQUERY_REGISTRY_CALLBACK_CONTEXT CallbackContext
= (PQUERY_REGISTRY_CALLBACK_CONTEXT
) Context
;
718 INFO_(VIDEOPRT
, "Found registry value for name %S: type %d, length %d\n",
719 ValueName
, ValueType
, ValueLength
);
720 return (*(CallbackContext
->HwGetRegistryRoutine
))(
721 CallbackContext
->HwDeviceExtension
,
722 CallbackContext
->HwContext
,
734 VideoPortGetRegistryParameters(
735 IN PVOID HwDeviceExtension
,
736 IN PWSTR ParameterName
,
737 IN UCHAR IsParameterFileName
,
738 IN PMINIPORT_GET_REGISTRY_ROUTINE GetRegistryRoutine
,
741 RTL_QUERY_REGISTRY_TABLE QueryTable
[2] = {{0}};
742 QUERY_REGISTRY_CALLBACK_CONTEXT Context
;
743 PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension
;
746 DeviceExtension
= VIDEO_PORT_GET_DEVICE_EXTENSION(HwDeviceExtension
);
748 TRACE_(VIDEOPRT
, "VideoPortGetRegistryParameters ParameterName %S, RegPath: %wZ\n",
749 ParameterName
, &DeviceExtension
->RegistryPath
);
751 Context
.HwDeviceExtension
= HwDeviceExtension
;
752 Context
.HwContext
= HwContext
;
753 Context
.HwGetRegistryRoutine
= GetRegistryRoutine
;
755 QueryTable
[0].QueryRoutine
= QueryRegistryCallback
;
756 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_REQUIRED
;
757 QueryTable
[0].Name
= ParameterName
;
759 Status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
,
760 DeviceExtension
->RegistryPath
.Buffer
,
764 if (!NT_SUCCESS(Status
))
766 WARN_(VIDEOPRT
, "VideoPortGetRegistryParameters could not find the "
767 "requested parameter\n");
768 return ERROR_INVALID_PARAMETER
;
771 if (IsParameterFileName
)
773 /* FIXME: need to read the contents of the file */
785 VideoPortSetRegistryParameters(
786 IN PVOID HwDeviceExtension
,
789 IN ULONG ValueLength
)
791 PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension
;
794 DeviceExtension
= VIDEO_PORT_GET_DEVICE_EXTENSION(HwDeviceExtension
);
795 TRACE_(VIDEOPRT
, "VideoPortSetRegistryParameters ParameterName %S, RegPath: %wZ\n",
797 &DeviceExtension
->RegistryPath
);
798 ASSERT_IRQL_LESS_OR_EQUAL(PASSIVE_LEVEL
);
799 Status
= RtlWriteRegistryValue(RTL_REGISTRY_ABSOLUTE
,
800 DeviceExtension
->RegistryPath
.Buffer
,
805 if (Status
!= NO_ERROR
)
806 WARN_(VIDEOPRT
, "VideoPortSetRegistryParameters error 0x%x\n", Status
);
816 VideoPortGetVgaStatus(
817 IN PVOID HwDeviceExtension
,
818 OUT PULONG VgaStatus
)
820 PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension
;
822 TRACE_(VIDEOPRT
, "VideoPortGetVgaStatus\n");
824 DeviceExtension
= VIDEO_PORT_GET_DEVICE_EXTENSION(HwDeviceExtension
);
825 if (KeGetCurrentIrql() == PASSIVE_LEVEL
)
827 if (DeviceExtension
->AdapterInterfaceType
== PCIBus
)
829 /* VgaStatus: 0 == VGA not enabled, 1 == VGA enabled. */
830 /* Assumed for now */
836 return ERROR_INVALID_FUNCTION
;
844 VideoPortGetRomImage(
845 IN PVOID HwDeviceExtension
,
850 static PVOID RomImageBuffer
= NULL
;
851 PKPROCESS CallingProcess
;
854 TRACE_(VIDEOPRT
, "VideoPortGetRomImage(HwDeviceExtension 0x%X Length 0x%X)\n",
855 HwDeviceExtension
, Length
);
857 /* If the length is zero then free the existing buffer. */
860 if (RomImageBuffer
!= NULL
)
862 ExFreePool(RomImageBuffer
);
863 RomImageBuffer
= NULL
;
870 * The DDK says we shouldn't use the legacy C0000 method but get the
871 * rom base address from the corresponding pci or acpi register but
872 * lets ignore that and use C0000 anyway. We have already mapped the
873 * bios area into memory so we'll copy from there.
877 Length
= min(Length
, 0x10000);
878 if (RomImageBuffer
!= NULL
)
880 ExFreePool(RomImageBuffer
);
883 RomImageBuffer
= ExAllocatePool(PagedPool
, Length
);
884 if (RomImageBuffer
== NULL
)
889 IntAttachToCSRSS(&CallingProcess
, &ApcState
);
890 RtlCopyMemory(RomImageBuffer
, (PUCHAR
)0xC0000, Length
);
891 IntDetachFromCSRSS(&CallingProcess
, &ApcState
);
893 return RomImageBuffer
;
903 IN PVOID HwDeviceExtension
,
910 PUCHAR SearchLocation
;
912 TRACE_(VIDEOPRT
, "VideoPortScanRom RomBase %p RomLength 0x%x String %s\n", RomBase
, RomLength
, String
);
914 StringLength
= strlen((PCHAR
)String
);
916 SearchLocation
= RomBase
;
917 for (SearchLocation
= RomBase
;
918 !Found
&& SearchLocation
< RomBase
+ RomLength
- StringLength
;
921 Found
= (RtlCompareMemory(SearchLocation
, String
, StringLength
) == StringLength
);
924 INFO_(VIDEOPRT
, "Match found at %p\n", SearchLocation
);
936 VideoPortSynchronizeExecution(
937 IN PVOID HwDeviceExtension
,
938 IN VIDEO_SYNCHRONIZE_PRIORITY Priority
,
939 IN PMINIPORT_SYNCHRONIZE_ROUTINE SynchronizeRoutine
,
943 PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension
;
949 Ret
= (*SynchronizeRoutine
)(Context
);
952 case VpMediumPriority
:
953 DeviceExtension
= VIDEO_PORT_GET_DEVICE_EXTENSION(HwDeviceExtension
);
954 if (DeviceExtension
->InterruptObject
== NULL
)
955 Ret
= (*SynchronizeRoutine
)(Context
);
957 Ret
= KeSynchronizeExecution(
958 DeviceExtension
->InterruptObject
,
964 OldIrql
= KeGetCurrentIrql();
965 if (OldIrql
< SYNCH_LEVEL
)
966 KeRaiseIrql(SYNCH_LEVEL
, &OldIrql
);
968 Ret
= (*SynchronizeRoutine
)(Context
);
970 if (OldIrql
< SYNCH_LEVEL
)
971 KeLowerIrql(OldIrql
);
986 VideoPortEnumerateChildren(
987 IN PVOID HwDeviceExtension
,
990 PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension
;
992 VIDEO_CHILD_ENUM_INFO ChildEnumInfo
;
993 BOOLEAN bHaveLastMonitorID
= FALSE
;
994 UCHAR LastMonitorID
[10];
997 PDEVICE_OBJECT ChildDeviceObject
;
998 PVIDEO_PORT_CHILD_EXTENSION ChildExtension
;
1000 INFO_(VIDEOPRT
, "Starting child device probe\n");
1001 DeviceExtension
= VIDEO_PORT_GET_DEVICE_EXTENSION(HwDeviceExtension
);
1002 if (DeviceExtension
->DriverExtension
->InitializationData
.HwGetVideoChildDescriptor
== NULL
)
1004 WARN_(VIDEOPRT
, "Miniport's HwGetVideoChildDescriptor is NULL!\n");
1008 if (!IsListEmpty(&DeviceExtension
->ChildDeviceList
))
1010 ERR_(VIDEOPRT
, "FIXME: Support calling VideoPortEnumerateChildren again!\n");
1014 /* Enumerate the children */
1017 Status
= IoCreateDevice(DeviceExtension
->DriverObject
,
1018 sizeof(VIDEO_PORT_CHILD_EXTENSION
) +
1019 DeviceExtension
->DriverExtension
->InitializationData
.HwChildDeviceExtensionSize
,
1021 FILE_DEVICE_CONTROLLER
,
1022 FILE_DEVICE_SECURE_OPEN
,
1024 &ChildDeviceObject
);
1025 if (!NT_SUCCESS(Status
))
1028 ChildExtension
= ChildDeviceObject
->DeviceExtension
;
1030 RtlZeroMemory(ChildExtension
,
1031 sizeof(VIDEO_PORT_CHILD_EXTENSION
) +
1032 DeviceExtension
->DriverExtension
->InitializationData
.HwChildDeviceExtensionSize
);
1034 ChildExtension
->Common
.Fdo
= FALSE
;
1035 ChildExtension
->ChildId
= i
;
1036 ChildExtension
->PhysicalDeviceObject
= ChildDeviceObject
;
1037 ChildExtension
->DriverObject
= DeviceExtension
->DriverObject
;
1039 /* Setup the ChildEnumInfo */
1040 ChildEnumInfo
.Size
= sizeof(ChildEnumInfo
);
1041 ChildEnumInfo
.ChildDescriptorSize
= sizeof(ChildExtension
->ChildDescriptor
);
1042 ChildEnumInfo
.ACPIHwId
= 0;
1044 if (DeviceExtension
->DriverExtension
->InitializationData
.HwChildDeviceExtensionSize
)
1045 ChildEnumInfo
.ChildHwDeviceExtension
= VIDEO_PORT_GET_CHILD_EXTENSION(ChildExtension
);
1047 ChildEnumInfo
.ChildHwDeviceExtension
= NULL
;
1049 ChildEnumInfo
.ChildIndex
= ChildExtension
->ChildId
;
1051 INFO_(VIDEOPRT
, "Probing child: %d\n", ChildEnumInfo
.ChildIndex
);
1052 Status
= DeviceExtension
->DriverExtension
->InitializationData
.HwGetVideoChildDescriptor(
1055 &ChildExtension
->ChildType
,
1056 ChildExtension
->ChildDescriptor
,
1057 &ChildExtension
->ChildId
,
1059 if (Status
== VIDEO_ENUM_MORE_DEVICES
)
1061 if (ChildExtension
->ChildType
== Monitor
)
1063 // Check if the EDID is valid
1064 if (ChildExtension
->ChildDescriptor
[0] == 0x00 &&
1065 ChildExtension
->ChildDescriptor
[1] == 0xFF &&
1066 ChildExtension
->ChildDescriptor
[2] == 0xFF &&
1067 ChildExtension
->ChildDescriptor
[3] == 0xFF &&
1068 ChildExtension
->ChildDescriptor
[4] == 0xFF &&
1069 ChildExtension
->ChildDescriptor
[5] == 0xFF &&
1070 ChildExtension
->ChildDescriptor
[6] == 0xFF &&
1071 ChildExtension
->ChildDescriptor
[7] == 0x00)
1073 if (bHaveLastMonitorID
)
1075 // Compare the previous monitor ID with the current one, break the loop if they are identical
1076 if (RtlCompareMemory(LastMonitorID
, &ChildExtension
->ChildDescriptor
[8], sizeof(LastMonitorID
)) == sizeof(LastMonitorID
))
1078 INFO_(VIDEOPRT
, "Found identical Monitor ID two times, stopping enumeration\n");
1079 IoDeleteDevice(ChildDeviceObject
);
1084 // Copy 10 bytes from the EDID, which can be used to uniquely identify the monitor
1085 RtlCopyMemory(LastMonitorID
, &ChildExtension
->ChildDescriptor
[8], sizeof(LastMonitorID
));
1086 bHaveLastMonitorID
= TRUE
;
1089 ChildExtension
->EdidValid
= TRUE
;
1093 /* Mark it invalid */
1094 ChildExtension
->EdidValid
= FALSE
;
1098 else if (Status
== VIDEO_ENUM_INVALID_DEVICE
)
1100 WARN_(VIDEOPRT
, "Child device %d is invalid!\n", ChildEnumInfo
.ChildIndex
);
1101 IoDeleteDevice(ChildDeviceObject
);
1104 else if (Status
== VIDEO_ENUM_NO_MORE_DEVICES
)
1106 INFO_(VIDEOPRT
, "End of child enumeration! (%d children enumerated)\n", i
- 1);
1107 IoDeleteDevice(ChildDeviceObject
);
1112 WARN_(VIDEOPRT
, "HwGetVideoChildDescriptor returned unknown status code 0x%x!\n", Status
);
1113 IoDeleteDevice(ChildDeviceObject
);
1117 if (ChildExtension
->ChildType
== Monitor
)
1120 PUCHAR p
= ChildExtension
->ChildDescriptor
;
1121 INFO_(VIDEOPRT
, "Monitor device enumerated! (ChildId = 0x%x)\n", ChildExtension
->ChildId
);
1122 for (j
= 0; j
< sizeof (ChildExtension
->ChildDescriptor
); j
+= 8)
1124 INFO_(VIDEOPRT
, "%02x %02x %02x %02x %02x %02x %02x %02x\n",
1125 p
[j
+ 0], p
[j
+ 1], p
[j
+ 2], p
[j
+ 3],
1126 p
[j
+ 4], p
[j
+ 5], p
[j
+ 6], p
[j
+ 7]);
1129 else if (ChildExtension
->ChildType
== Other
)
1131 INFO_(VIDEOPRT
, "\"Other\" device enumerated: DeviceId = %S\n", (PWSTR
)ChildExtension
->ChildDescriptor
);
1135 ERR_(VIDEOPRT
, "HwGetVideoChildDescriptor returned unsupported type: %d\n", ChildExtension
->ChildType
);
1138 /* Clear the init flag */
1139 ChildDeviceObject
->Flags
&= ~DO_DEVICE_INITIALIZING
;
1141 InsertTailList(&DeviceExtension
->ChildDeviceList
,
1142 &ChildExtension
->ListEntry
);
1145 /* Trigger reenumeration by the PnP manager */
1146 IoInvalidateDeviceRelations(DeviceExtension
->PhysicalDeviceObject
, BusRelations
);
1156 VideoPortCreateSecondaryDisplay(
1157 IN PVOID HwDeviceExtension
,
1158 IN OUT PVOID
*SecondaryDeviceExtension
,
1162 return ERROR_DEV_NOT_EXIST
;
1171 IN PVOID HwDeviceExtension
,
1172 IN PMINIPORT_DPC_ROUTINE CallbackRoutine
,
1175 return KeInsertQueueDpc(
1176 &VIDEO_PORT_GET_DEVICE_EXTENSION(HwDeviceExtension
)->DpcObject
,
1177 (PVOID
)CallbackRoutine
,
1186 VideoPortGetAssociatedDeviceExtension(
1187 IN PVOID DeviceObject
)
1189 PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension
;
1191 TRACE_(VIDEOPRT
, "VideoPortGetAssociatedDeviceExtension\n");
1192 DeviceExtension
= ((PDEVICE_OBJECT
)DeviceObject
)->DeviceExtension
;
1193 if (!DeviceExtension
)
1195 return DeviceExtension
->MiniPortDeviceExtension
;
1203 VideoPortGetVersion(
1204 IN PVOID HwDeviceExtension
,
1205 IN OUT PVPOSVERSIONINFO VpOsVersionInfo
)
1207 RTL_OSVERSIONINFOEXW Version
;
1209 Version
.dwOSVersionInfoSize
= sizeof(RTL_OSVERSIONINFOEXW
);
1210 if (VpOsVersionInfo
->Size
>= sizeof(VPOSVERSIONINFO
))
1213 if (NT_SUCCESS(RtlGetVersion((PRTL_OSVERSIONINFOW
)&Version
)))
1215 VpOsVersionInfo
->MajorVersion
= Version
.dwMajorVersion
;
1216 VpOsVersionInfo
->MinorVersion
= Version
.dwMinorVersion
;
1217 VpOsVersionInfo
->BuildNumber
= Version
.dwBuildNumber
;
1218 VpOsVersionInfo
->ServicePackMajor
= Version
.wServicePackMajor
;
1219 VpOsVersionInfo
->ServicePackMinor
= Version
.wServicePackMinor
;
1222 return ERROR_INVALID_PARAMETER
;
1224 VpOsVersionInfo
->MajorVersion
= 5;
1225 VpOsVersionInfo
->MinorVersion
= 0;
1226 VpOsVersionInfo
->BuildNumber
= 2195;
1227 VpOsVersionInfo
->ServicePackMajor
= 4;
1228 VpOsVersionInfo
->ServicePackMinor
= 0;
1233 return ERROR_INVALID_PARAMETER
;
1241 VideoPortCheckForDeviceExistence(
1242 IN PVOID HwDeviceExtension
,
1245 IN UCHAR RevisionId
,
1246 IN USHORT SubVendorId
,
1247 IN USHORT SubSystemId
,
1250 PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension
;
1251 PCI_DEVICE_PRESENT_INTERFACE PciDevicePresentInterface
;
1252 IO_STATUS_BLOCK IoStatusBlock
;
1253 IO_STACK_LOCATION IoStack
;
1258 TRACE_(VIDEOPRT
, "VideoPortCheckForDeviceExistence\n");
1260 if (Flags
& ~(CDE_USE_REVISION
| CDE_USE_SUBSYSTEM_IDS
))
1262 WARN_(VIDEOPRT
, "VideoPortCheckForDeviceExistence: Unknown flags 0x%lx\n", Flags
& ~(CDE_USE_REVISION
| CDE_USE_SUBSYSTEM_IDS
));
1266 DeviceExtension
= VIDEO_PORT_GET_DEVICE_EXTENSION(HwDeviceExtension
);
1268 PciDevicePresentInterface
.Size
= sizeof(PCI_DEVICE_PRESENT_INTERFACE
);
1269 PciDevicePresentInterface
.Version
= 1;
1270 IoStack
.Parameters
.QueryInterface
.Size
= PciDevicePresentInterface
.Size
;
1271 IoStack
.Parameters
.QueryInterface
.Version
= PciDevicePresentInterface
.Version
;
1272 IoStack
.Parameters
.QueryInterface
.Interface
= (PINTERFACE
)&PciDevicePresentInterface
;
1273 IoStack
.Parameters
.QueryInterface
.InterfaceType
=
1274 &GUID_PCI_DEVICE_PRESENT_INTERFACE
;
1275 Status
= IopInitiatePnpIrp(DeviceExtension
->NextDeviceObject
,
1276 &IoStatusBlock
, IRP_MN_QUERY_INTERFACE
, &IoStack
);
1277 if (!NT_SUCCESS(Status
))
1279 WARN_(VIDEOPRT
, "IopInitiatePnpIrp() failed! (Status 0x%lx)\n", Status
);
1283 if (Flags
& CDE_USE_REVISION
)
1284 PciFlags
|= PCI_USE_REVISION
;
1285 if (Flags
& CDE_USE_SUBSYSTEM_IDS
)
1286 PciFlags
|= PCI_USE_SUBSYSTEM_IDS
;
1288 DevicePresent
= PciDevicePresentInterface
.IsDevicePresent(
1289 VendorId
, DeviceId
, RevisionId
,
1290 SubVendorId
, SubSystemId
, PciFlags
);
1292 PciDevicePresentInterface
.InterfaceDereference(PciDevicePresentInterface
.Context
);
1294 return DevicePresent
;
1302 VideoPortRegisterBugcheckCallback(
1303 IN PVOID HwDeviceExtension
,
1304 IN ULONG BugcheckCode
,
1305 IN PVIDEO_BUGCHECK_CALLBACK Callback
,
1306 IN ULONG BugcheckDataSize
)
1317 VideoPortQueryPerformanceCounter(
1318 IN PVOID HwDeviceExtension
,
1319 OUT PLONGLONG PerformanceFrequency OPTIONAL
)
1321 LARGE_INTEGER Result
;
1323 TRACE_(VIDEOPRT
, "VideoPortQueryPerformanceCounter\n");
1324 Result
= KeQueryPerformanceCounter((PLARGE_INTEGER
)PerformanceFrequency
);
1325 return Result
.QuadPart
;
1333 VideoPortAcquireDeviceLock(
1334 IN PVOID HwDeviceExtension
)
1336 PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension
;
1340 TRACE_(VIDEOPRT
, "VideoPortAcquireDeviceLock\n");
1341 DeviceExtension
= VIDEO_PORT_GET_DEVICE_EXTENSION(HwDeviceExtension
);
1342 Status
= KeWaitForMutexObject(&DeviceExtension
->DeviceLock
, Executive
,
1343 KernelMode
, FALSE
, NULL
);
1344 // ASSERT(Status == STATUS_SUCCESS);
1352 VideoPortReleaseDeviceLock(
1353 IN PVOID HwDeviceExtension
)
1355 PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension
;
1359 TRACE_(VIDEOPRT
, "VideoPortReleaseDeviceLock\n");
1360 DeviceExtension
= VIDEO_PORT_GET_DEVICE_EXTENSION(HwDeviceExtension
);
1361 Status
= KeReleaseMutex(&DeviceExtension
->DeviceLock
, FALSE
);
1362 //ASSERT(Status == STATUS_SUCCESS);
1371 IN PDEVICE_OBJECT DeviceObject
,
1382 VideoPortAllocateContiguousMemory(
1383 IN PVOID HwDeviceExtension
,
1384 IN ULONG NumberOfBytes
,
1385 IN PHYSICAL_ADDRESS HighestAcceptableAddress
1389 return MmAllocateContiguousMemory(NumberOfBytes
, HighestAcceptableAddress
);
1397 VideoPortIsNoVesa(VOID
)
1401 UNICODE_STRING Path
= RTL_CONSTANT_STRING(L
"\\REGISTRY\\MACHINE\\SYSTEM\\CurrentControlSet\\Control");
1402 UNICODE_STRING ValueName
= RTL_CONSTANT_STRING(L
"SystemStartOptions");
1403 OBJECT_ATTRIBUTES ObjectAttributes
;
1404 PKEY_VALUE_PARTIAL_INFORMATION KeyInfo
;
1405 ULONG Length
, NewLength
;
1407 /* Initialize object attributes with the path we want */
1408 InitializeObjectAttributes(&ObjectAttributes
,
1410 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
1415 Status
= ZwOpenKey(&KeyHandle
,
1419 if (!NT_SUCCESS(Status
))
1421 VideoPortDebugPrint(Error
, "ZwOpenKey failed (0x%x)\n", Status
);
1425 /* Find out how large our buffer should be */
1426 Status
= ZwQueryValueKey(KeyHandle
,
1428 KeyValuePartialInformation
,
1432 if (Status
!= STATUS_BUFFER_OVERFLOW
&& Status
!= STATUS_BUFFER_TOO_SMALL
)
1434 VideoPortDebugPrint(Error
, "ZwQueryValueKey failed (0x%x)\n", Status
);
1440 KeyInfo
= ExAllocatePool(PagedPool
, Length
);
1443 VideoPortDebugPrint(Error
, "Out of memory\n");
1448 /* Now for real this time */
1449 Status
= ZwQueryValueKey(KeyHandle
,
1451 KeyValuePartialInformation
,
1458 if (!NT_SUCCESS(Status
))
1460 VideoPortDebugPrint(Error
, "ZwQueryValueKey failed (0x%x)\n", Status
);
1461 ExFreePool(KeyInfo
);
1466 if (KeyInfo
->Type
!= REG_SZ
)
1468 VideoPortDebugPrint(Error
, "Invalid type for SystemStartOptions\n");
1469 ExFreePool(KeyInfo
);
1473 /* Check if NOVESA or BASEVIDEO is present in the start options */
1474 if (wcsstr((PWCHAR
)KeyInfo
->Data
, L
"NOVESA") ||
1475 wcsstr((PWCHAR
)KeyInfo
->Data
, L
"BASEVIDEO"))
1477 VideoPortDebugPrint(Info
, "VESA mode disabled\n");
1478 ExFreePool(KeyInfo
);
1482 ExFreePool(KeyInfo
);
1484 VideoPortDebugPrint(Info
, "VESA mode enabled\n");