xref: /reactos/win32ss/drivers/videoprt/videoprt.c (revision b8dd046e)
1 /*
2  * VideoPort driver
3  *
4  * Copyright (C) 2002-2004, 2007 ReactOS Team
5  *
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.
10  *
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.
15  *
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
19  *
20  */
21 
22 #include "videoprt.h"
23 
24 #include <stdio.h>
25 #include <ndk/exfuncs.h>
26 #include <ndk/obfuncs.h>
27 #include <ndk/rtlfuncs.h>
28 
29 #define NDEBUG
30 #include <debug.h>
31 
32 /* GLOBAL VARIABLES ***********************************************************/
33 
34 BOOLEAN VpBaseVideo = FALSE;
35 BOOLEAN VpNoVesa = FALSE;
36 
37 PKPROCESS CsrProcess = NULL;
38 ULONG VideoPortDeviceNumber = 0;
39 KMUTEX VideoPortInt10Mutex;
40 KSPIN_LOCK HwResetAdaptersLock;
41 RTL_STATIC_LIST_HEAD(HwResetAdaptersList);
42 
43 /* PRIVATE FUNCTIONS **********************************************************/
44 
45 ULONG
46 NTAPI
47 DriverEntry(
48     IN PVOID Context1,
49     IN PVOID Context2)
50 {
51     return STATUS_SUCCESS;
52 }
53 
54 PVOID
55 NTAPI
56 IntVideoPortImageDirectoryEntryToData(
57     PVOID BaseAddress,
58     ULONG Directory)
59 {
60     PIMAGE_NT_HEADERS NtHeader;
61     ULONG Va;
62 
63     NtHeader = RtlImageNtHeader(BaseAddress);
64     if (NtHeader == NULL)
65         return NULL;
66 
67     if (Directory >= NtHeader->OptionalHeader.NumberOfRvaAndSizes)
68         return NULL;
69 
70     Va = NtHeader->OptionalHeader.DataDirectory[Directory].VirtualAddress;
71     if (Va == 0)
72         return NULL;
73 
74     return (PVOID)((ULONG_PTR)BaseAddress + Va);
75 }
76 
77 VOID
78 NTAPI
79 IntVideoPortDeferredRoutine(
80     IN PKDPC Dpc,
81     IN PVOID DeferredContext,
82     IN PVOID SystemArgument1,
83     IN PVOID SystemArgument2)
84 {
85     PVOID HwDeviceExtension =
86         &((PVIDEO_PORT_DEVICE_EXTENSION)DeferredContext)->MiniPortDeviceExtension;
87     ((PMINIPORT_DPC_ROUTINE)SystemArgument1)(HwDeviceExtension, SystemArgument2);
88 }
89 
90 NTSTATUS
91 NTAPI
92 IntVideoPortCreateAdapterDeviceObject(
93     IN PDRIVER_OBJECT DriverObject,
94     IN PVIDEO_PORT_DRIVER_EXTENSION DriverExtension,
95     IN PDEVICE_OBJECT PhysicalDeviceObject,
96     OUT PDEVICE_OBJECT *DeviceObject  OPTIONAL)
97 {
98     PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension;
99     ULONG DeviceNumber;
100     ULONG PciSlotNumber;
101     PCI_SLOT_NUMBER SlotNumber;
102     ULONG Size;
103     NTSTATUS Status;
104     WCHAR DeviceBuffer[20];
105     UNICODE_STRING DeviceName;
106     PDEVICE_OBJECT DeviceObject_;
107 
108     if (DeviceObject == NULL)
109         DeviceObject = &DeviceObject_;
110 
111     /*
112      * Find the first free device number that can be used for video device
113      * object names and symlinks.
114      */
115     DeviceNumber = VideoPortDeviceNumber;
116     if (DeviceNumber == 0xFFFFFFFF)
117     {
118         WARN_(VIDEOPRT, "Can't find free device number\n");
119         return STATUS_UNSUCCESSFUL;
120     }
121 
122     /*
123      * Create the device object.
124      */
125 
126     /* Create a unicode device name. */
127     swprintf(DeviceBuffer, L"\\Device\\Video%lu", DeviceNumber);
128     RtlInitUnicodeString(&DeviceName, DeviceBuffer);
129 
130     INFO_(VIDEOPRT, "HwDeviceExtension size is: 0x%x\n",
131           DriverExtension->InitializationData.HwDeviceExtensionSize);
132 
133     /* Create the device object. */
134     Size = sizeof(VIDEO_PORT_DEVICE_EXTENSION) +
135         DriverExtension->InitializationData.HwDeviceExtensionSize;
136     Status = IoCreateDevice(DriverObject,
137                             Size,
138                             &DeviceName,
139                             FILE_DEVICE_VIDEO,
140                             0,
141                             TRUE,
142                             DeviceObject);
143 
144     if (!NT_SUCCESS(Status))
145     {
146         WARN_(VIDEOPRT, "IoCreateDevice call failed with status 0x%08x\n", Status);
147         return Status;
148     }
149 
150     /*
151      * Set the buffering strategy here. If you change this, remember
152      * to change VidDispatchDeviceControl too.
153      */
154 
155     (*DeviceObject)->Flags |= DO_BUFFERED_IO;
156 
157     /* Initialize device extension. */
158     DeviceExtension = (PVIDEO_PORT_DEVICE_EXTENSION)((*DeviceObject)->DeviceExtension);
159     DeviceExtension->Common.Fdo = TRUE;
160     DeviceExtension->DeviceNumber = DeviceNumber;
161     DeviceExtension->DriverObject = DriverObject;
162     DeviceExtension->PhysicalDeviceObject = PhysicalDeviceObject;
163     DeviceExtension->FunctionalDeviceObject = *DeviceObject;
164     DeviceExtension->DriverExtension = DriverExtension;
165     DeviceExtension->SessionId = -1;
166 
167     InitializeListHead(&DeviceExtension->ChildDeviceList);
168 
169     /* Get the registry path associated with this device. */
170     Status = IntCreateRegistryPath(&DriverExtension->RegistryPath,
171                                    &DeviceExtension->RegistryPath);
172     if (!NT_SUCCESS(Status))
173     {
174         WARN_(VIDEOPRT, "IntCreateRegistryPath() call failed with status 0x%08x\n", Status);
175         IoDeleteDevice(*DeviceObject);
176         *DeviceObject = NULL;
177         return Status;
178     }
179 
180     if (PhysicalDeviceObject != NULL)
181     {
182         /* Get bus number from the upper level bus driver. */
183         Size = sizeof(ULONG);
184         Status = IoGetDeviceProperty(PhysicalDeviceObject,
185                                      DevicePropertyBusNumber,
186                                      Size,
187                                      &DeviceExtension->SystemIoBusNumber,
188                                      &Size);
189         if (!NT_SUCCESS(Status))
190         {
191             WARN_(VIDEOPRT, "Couldn't get an information from bus driver. We will try to\n"
192                   "use legacy detection method, but even that doesn't mean that\n"
193                   "it will work.\n");
194             DeviceExtension->PhysicalDeviceObject = NULL;
195         }
196     }
197 
198     DeviceExtension->AdapterInterfaceType =
199         DriverExtension->InitializationData.AdapterInterfaceType;
200 
201     if (PhysicalDeviceObject != NULL)
202     {
203         /* Get bus type from the upper level bus driver. */
204         Size = sizeof(ULONG);
205         IoGetDeviceProperty(PhysicalDeviceObject,
206                             DevicePropertyLegacyBusType,
207                             Size,
208                             &DeviceExtension->AdapterInterfaceType,
209                             &Size);
210 
211         /* Get bus device address from the upper level bus driver. */
212         Size = sizeof(ULONG);
213         IoGetDeviceProperty(PhysicalDeviceObject,
214                             DevicePropertyAddress,
215                             Size,
216                             &PciSlotNumber,
217                             &Size);
218 
219         /* Convert slotnumber to PCI_SLOT_NUMBER */
220         SlotNumber.u.AsULONG = 0;
221         SlotNumber.u.bits.DeviceNumber = (PciSlotNumber >> 16) & 0xFFFF;
222         SlotNumber.u.bits.FunctionNumber = PciSlotNumber & 0xFFFF;
223         DeviceExtension->SystemIoSlotNumber = SlotNumber.u.AsULONG;
224     }
225 
226     InitializeListHead(&DeviceExtension->AddressMappingListHead);
227     InitializeListHead(&DeviceExtension->DmaAdapterList);
228 
229     KeInitializeDpc(&DeviceExtension->DpcObject,
230                     IntVideoPortDeferredRoutine,
231                     DeviceExtension);
232 
233     KeInitializeMutex(&DeviceExtension->DeviceLock, 0);
234 
235     /* Attach the device. */
236     if (PhysicalDeviceObject != NULL)
237         DeviceExtension->NextDeviceObject = IoAttachDeviceToDeviceStack(
238                                                 *DeviceObject,
239                                                 PhysicalDeviceObject);
240 
241     IntCreateNewRegistryPath(DeviceExtension);
242     IntSetupDeviceSettingsKey(DeviceExtension);
243 
244     /* Remove the initailizing flag */
245     (*DeviceObject)->Flags &= ~DO_DEVICE_INITIALIZING;
246     return STATUS_SUCCESS;
247 }
248 
249 
250 NTSTATUS
251 NTAPI
252 IntVideoPortFindAdapter(
253     IN PDRIVER_OBJECT DriverObject,
254     IN PVIDEO_PORT_DRIVER_EXTENSION DriverExtension,
255     IN PDEVICE_OBJECT DeviceObject)
256 {
257     WCHAR DeviceVideoBuffer[20];
258     PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension;
259     NTSTATUS Status;
260     VIDEO_PORT_CONFIG_INFO ConfigInfo;
261     SYSTEM_BASIC_INFORMATION SystemBasicInfo;
262     UCHAR Again = FALSE;
263     WCHAR DeviceBuffer[20];
264     UNICODE_STRING DeviceName;
265     WCHAR SymlinkBuffer[20];
266     UNICODE_STRING SymlinkName;
267     BOOL LegacyDetection = FALSE;
268     ULONG DeviceNumber;
269 
270     DeviceExtension = (PVIDEO_PORT_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
271     DeviceNumber = DeviceExtension->DeviceNumber;
272 
273     /* Setup a ConfigInfo structure that we will pass to HwFindAdapter. */
274     RtlZeroMemory(&ConfigInfo, sizeof(VIDEO_PORT_CONFIG_INFO));
275     ConfigInfo.Length = sizeof(VIDEO_PORT_CONFIG_INFO);
276     ConfigInfo.AdapterInterfaceType = DeviceExtension->AdapterInterfaceType;
277     if (ConfigInfo.AdapterInterfaceType == PCIBus)
278         ConfigInfo.InterruptMode = LevelSensitive;
279     else
280         ConfigInfo.InterruptMode = Latched;
281     ConfigInfo.DriverRegistryPath = DriverExtension->RegistryPath.Buffer;
282     ConfigInfo.VideoPortGetProcAddress = IntVideoPortGetProcAddress;
283     ConfigInfo.SystemIoBusNumber = DeviceExtension->SystemIoBusNumber;
284     ConfigInfo.BusInterruptLevel = DeviceExtension->InterruptLevel;
285     ConfigInfo.BusInterruptVector = DeviceExtension->InterruptVector;
286 
287     Status = ZwQuerySystemInformation(SystemBasicInformation,
288                                       &SystemBasicInfo,
289                                       sizeof(SystemBasicInfo),
290                                       NULL);
291     if (NT_SUCCESS(Status))
292     {
293         ConfigInfo.SystemMemorySize = SystemBasicInfo.NumberOfPhysicalPages *
294                                       SystemBasicInfo.PageSize;
295     }
296 
297     /*
298      * Call miniport HwVidFindAdapter entry point to detect if
299      * particular device is present. There are two possible code
300      * paths. The first one is for Legacy drivers (NT4) and cases
301      * when we don't have information about what bus we're on. The
302      * second case is the standard one for Plug & Play drivers.
303      */
304     if (DeviceExtension->PhysicalDeviceObject == NULL)
305     {
306         LegacyDetection = TRUE;
307     }
308 
309     if (LegacyDetection)
310     {
311         ULONG BusNumber, MaxBuses;
312 
313         MaxBuses = DeviceExtension->AdapterInterfaceType == PCIBus ? PCI_MAX_BRIDGE_NUMBER : 1;
314 
315         for (BusNumber = 0; BusNumber < MaxBuses; BusNumber++)
316         {
317             DeviceExtension->SystemIoBusNumber =
318                 ConfigInfo.SystemIoBusNumber = BusNumber;
319 
320             RtlZeroMemory(&DeviceExtension->MiniPortDeviceExtension,
321                           DriverExtension->InitializationData.HwDeviceExtensionSize);
322 
323             /* FIXME: Need to figure out what string to pass as param 3. */
324             Status = DriverExtension->InitializationData.HwFindAdapter(
325                          &DeviceExtension->MiniPortDeviceExtension,
326                          DriverExtension->HwContext,
327                          NULL,
328                          &ConfigInfo,
329                          &Again);
330 
331             if (Status == ERROR_DEV_NOT_EXIST)
332             {
333                 continue;
334             }
335             else if (Status == NO_ERROR)
336             {
337                 break;
338             }
339             else
340             {
341                 ERR_(VIDEOPRT, "HwFindAdapter call failed with error 0x%X\n", Status);
342                 goto Failure;
343             }
344         }
345     }
346     else
347     {
348         /* FIXME: Need to figure out what string to pass as param 3. */
349         Status = DriverExtension->InitializationData.HwFindAdapter(
350                      &DeviceExtension->MiniPortDeviceExtension,
351                      DriverExtension->HwContext,
352                      NULL,
353                      &ConfigInfo,
354                      &Again);
355     }
356 
357     if (Status != NO_ERROR)
358     {
359         ERR_(VIDEOPRT, "HwFindAdapter call failed with error 0x%X\n", Status);
360         goto Failure;
361     }
362 
363     /*
364      * Now we know the device is present, so let's do all additional tasks
365      * such as creating symlinks or setting up interrupts and timer.
366      */
367 
368     /* Create a unicode device name. */
369     swprintf(DeviceBuffer, L"\\Device\\Video%lu", DeviceNumber);
370     RtlInitUnicodeString(&DeviceName, DeviceBuffer);
371 
372     /* Create symbolic link "\??\DISPLAYx" */
373     swprintf(SymlinkBuffer, L"\\??\\DISPLAY%lu", DeviceNumber + 1);
374     RtlInitUnicodeString(&SymlinkName, SymlinkBuffer);
375     IoCreateSymbolicLink(&SymlinkName, &DeviceName);
376 
377     /* Add entry to DEVICEMAP\VIDEO key in registry. */
378     swprintf(DeviceVideoBuffer, L"\\Device\\Video%d", DeviceNumber);
379     RtlWriteRegistryValue(
380         RTL_REGISTRY_DEVICEMAP,
381         L"VIDEO",
382         DeviceVideoBuffer,
383         REG_SZ,
384         DeviceExtension->RegistryPath.Buffer,
385         DeviceExtension->RegistryPath.Length + sizeof(UNICODE_NULL));
386 
387     RtlWriteRegistryValue(
388         RTL_REGISTRY_DEVICEMAP,
389         L"VIDEO",
390         L"MaxObjectNumber",
391         REG_DWORD,
392         &DeviceNumber,
393         sizeof(DeviceNumber));
394 
395     /* FIXME: Allocate hardware resources for device. */
396 
397     /* Allocate interrupt for device. */
398     if (!IntVideoPortSetupInterrupt(DeviceObject, DriverExtension, &ConfigInfo))
399     {
400         Status = STATUS_INSUFFICIENT_RESOURCES;
401         goto Failure;
402     }
403 
404     /* Allocate timer for device. */
405     if (!IntVideoPortSetupTimer(DeviceObject, DriverExtension))
406     {
407         if (DeviceExtension->InterruptObject != NULL)
408             IoDisconnectInterrupt(DeviceExtension->InterruptObject);
409         ERR_(VIDEOPRT, "IntVideoPortSetupTimer failed\n");
410         Status = STATUS_INSUFFICIENT_RESOURCES;
411         goto Failure;
412     }
413 
414     /* If the device can be reset, insert it in the list of resettable adapters */
415     InitializeListHead(&DeviceExtension->HwResetListEntry);
416     if (DriverExtension->InitializationData.HwResetHw != NULL)
417     {
418         ExInterlockedInsertTailList(&HwResetAdaptersList,
419                                     &DeviceExtension->HwResetListEntry,
420                                     &HwResetAdaptersLock);
421     }
422 
423     /* Query children of the device. */
424     VideoPortEnumerateChildren(&DeviceExtension->MiniPortDeviceExtension, NULL);
425 
426     INFO_(VIDEOPRT, "STATUS_SUCCESS\n");
427     return STATUS_SUCCESS;
428 
429 Failure:
430     RtlFreeUnicodeString(&DeviceExtension->RegistryPath);
431     if (DeviceExtension->NextDeviceObject)
432         IoDetachDevice(DeviceExtension->NextDeviceObject);
433     IoDeleteDevice(DeviceObject);
434     return Status;
435 }
436 
437 VOID
438 FASTCALL
439 IntAttachToCSRSS(
440     PKPROCESS *CallingProcess,
441     PKAPC_STATE ApcState)
442 {
443     *CallingProcess = (PKPROCESS)PsGetCurrentProcess();
444     if (*CallingProcess != CsrProcess)
445     {
446         KeStackAttachProcess(CsrProcess, ApcState);
447     }
448 }
449 
450 VOID
451 FASTCALL
452 IntDetachFromCSRSS(
453     PKPROCESS *CallingProcess,
454     PKAPC_STATE ApcState)
455 {
456     if (*CallingProcess != CsrProcess)
457     {
458         KeUnstackDetachProcess(ApcState);
459     }
460 }
461 
462 VOID
463 FASTCALL
464 IntLoadRegistryParameters(VOID)
465 {
466     NTSTATUS Status;
467     HANDLE KeyHandle;
468     UNICODE_STRING Path = RTL_CONSTANT_STRING(L"\\REGISTRY\\MACHINE\\SYSTEM\\CurrentControlSet\\Control");
469     UNICODE_STRING ValueName = RTL_CONSTANT_STRING(L"SystemStartOptions");
470     OBJECT_ATTRIBUTES ObjectAttributes;
471     PKEY_VALUE_PARTIAL_INFORMATION KeyInfo;
472     ULONG Length, NewLength;
473 
474     /* Initialize object attributes with the path we want */
475     InitializeObjectAttributes(&ObjectAttributes,
476                                &Path,
477                                OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
478                                NULL,
479                                NULL);
480 
481     /* Open the key */
482     Status = ZwOpenKey(&KeyHandle,
483                        KEY_QUERY_VALUE,
484                        &ObjectAttributes);
485     if (!NT_SUCCESS(Status))
486     {
487         VideoPortDebugPrint(Error, "ZwOpenKey failed (0x%x)\n", Status);
488         return;
489     }
490 
491     /* Find out how large our buffer should be */
492     Status = ZwQueryValueKey(KeyHandle,
493                              &ValueName,
494                              KeyValuePartialInformation,
495                              NULL,
496                              0,
497                              &Length);
498     if (Status != STATUS_BUFFER_OVERFLOW && Status != STATUS_BUFFER_TOO_SMALL)
499     {
500         VideoPortDebugPrint(Error, "ZwQueryValueKey failed (0x%x)\n", Status);
501         ObCloseHandle(KeyHandle, KernelMode);
502         return;
503     }
504 
505     /* Allocate it */
506     KeyInfo = ExAllocatePoolWithTag(PagedPool, Length, TAG_VIDEO_PORT);
507     if (!KeyInfo)
508     {
509         VideoPortDebugPrint(Error, "Out of memory\n");
510         ObCloseHandle(KeyHandle, KernelMode);
511         return;
512     }
513 
514     /* Now for real this time */
515     Status = ZwQueryValueKey(KeyHandle,
516                              &ValueName,
517                              KeyValuePartialInformation,
518                              KeyInfo,
519                              Length,
520                              &NewLength);
521     ObCloseHandle(KeyHandle, KernelMode);
522 
523     if (!NT_SUCCESS(Status))
524     {
525         VideoPortDebugPrint(Error, "ZwQueryValueKey failed (0x%x)\n", Status);
526         ExFreePoolWithTag(KeyInfo, TAG_VIDEO_PORT);
527         return;
528     }
529 
530     /* Sanity check */
531     if (KeyInfo->Type != REG_SZ)
532     {
533         VideoPortDebugPrint(Error, "Invalid type for SystemStartOptions\n");
534         ExFreePoolWithTag(KeyInfo, TAG_VIDEO_PORT);
535         return;
536     }
537 
538     /* Check if BASEVIDEO or NOVESA is present in the start options */
539     if (wcsstr((PWCHAR)KeyInfo->Data, L"BASEVIDEO"))
540         VpBaseVideo = TRUE;
541     if (wcsstr((PWCHAR)KeyInfo->Data, L"NOVESA"))
542         VpNoVesa = TRUE;
543 
544     ExFreePoolWithTag(KeyInfo, TAG_VIDEO_PORT);
545 
546     /* FIXME: Old ReactOS-compatibility... */
547     if (VpBaseVideo) VpNoVesa = TRUE;
548 
549     if (VpNoVesa)
550         VideoPortDebugPrint(Info, "VESA mode disabled\n");
551     else
552         VideoPortDebugPrint(Info, "VESA mode enabled\n");
553 
554     /* If we are in BASEVIDEO, create the volatile registry key for Win32k */
555     if (VpBaseVideo)
556     {
557         RtlInitUnicodeString(&Path, L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\GraphicsDrivers\\BaseVideo");
558 
559         InitializeObjectAttributes(&ObjectAttributes,
560                                    &Path,
561                                    OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
562                                    NULL,
563                                    NULL);
564 
565         Status = ZwCreateKey(&KeyHandle,
566                              KEY_WRITE,
567                              &ObjectAttributes,
568                              0,
569                              NULL,
570                              REG_OPTION_VOLATILE,
571                              NULL);
572         if (NT_SUCCESS(Status))
573             ObCloseHandle(KeyHandle, KernelMode);
574         else
575             ERR_(VIDEOPRT, "Failed to create the BaseVideo key (0x%x)\n", Status);
576     }
577 
578     return;
579 }
580 
581 /* PUBLIC FUNCTIONS ***********************************************************/
582 
583 /*
584  * @implemented
585  */
586 ULONG
587 NTAPI
588 VideoPortInitialize(
589     IN PVOID Context1,
590     IN PVOID Context2,
591     IN PVIDEO_HW_INITIALIZATION_DATA HwInitializationData,
592     IN PVOID HwContext)
593 {
594     PDRIVER_OBJECT DriverObject = Context1;
595     PUNICODE_STRING RegistryPath = Context2;
596     NTSTATUS Status;
597     PVIDEO_PORT_DRIVER_EXTENSION DriverExtension;
598     BOOLEAN PnpDriver = FALSE, LegacyDetection = FALSE;
599     static BOOLEAN FirstInitialization;
600 
601     TRACE_(VIDEOPRT, "VideoPortInitialize\n");
602 
603     if (!FirstInitialization)
604     {
605         FirstInitialization = TRUE;
606         KeInitializeMutex(&VideoPortInt10Mutex, 0);
607         KeInitializeSpinLock(&HwResetAdaptersLock);
608         IntLoadRegistryParameters();
609     }
610 
611     /* As a first thing do parameter checks. */
612     if (HwInitializationData->HwInitDataSize > sizeof(VIDEO_HW_INITIALIZATION_DATA))
613     {
614         ERR_(VIDEOPRT, "Invalid HwInitializationData\n");
615         return STATUS_REVISION_MISMATCH;
616     }
617 
618     if ((HwInitializationData->HwFindAdapter == NULL) ||
619         (HwInitializationData->HwInitialize == NULL) ||
620         (HwInitializationData->HwStartIO == NULL))
621     {
622         ERR_(VIDEOPRT, "Invalid HwInitializationData\n");
623         return STATUS_INVALID_PARAMETER;
624     }
625 
626     switch (HwInitializationData->HwInitDataSize)
627     {
628             /*
629              * NT4 drivers are special case, because we must use legacy method
630              * of detection instead of the Plug & Play one.
631              */
632         case SIZE_OF_NT4_VIDEO_HW_INITIALIZATION_DATA:
633             INFO_(VIDEOPRT, "We were loaded by a Windows NT miniport driver.\n");
634             break;
635 
636         case SIZE_OF_W2K_VIDEO_HW_INITIALIZATION_DATA:
637             INFO_(VIDEOPRT, "We were loaded by a Windows 2000 miniport driver.\n");
638             break;
639 
640         case sizeof(VIDEO_HW_INITIALIZATION_DATA):
641             INFO_(VIDEOPRT, "We were loaded by a Windows XP or later miniport driver.\n");
642             break;
643 
644         default:
645             ERR_(VIDEOPRT, "Invalid HwInitializationData size.\n");
646             return STATUS_UNSUCCESSFUL;
647     }
648 
649     /* Set dispatching routines */
650     DriverObject->MajorFunction[IRP_MJ_CREATE] = IntVideoPortDispatchOpen;
651     DriverObject->MajorFunction[IRP_MJ_CLOSE] = IntVideoPortDispatchClose;
652     DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] =
653         IntVideoPortDispatchDeviceControl;
654     DriverObject->MajorFunction[IRP_MJ_SHUTDOWN] =
655         IntVideoPortDispatchDeviceControl;
656     DriverObject->DriverUnload = IntVideoPortUnload;
657 
658     /* Determine type of the miniport driver */
659     if ((HwInitializationData->HwInitDataSize >=
660             FIELD_OFFSET(VIDEO_HW_INITIALIZATION_DATA, HwQueryInterface)) &&
661         (HwInitializationData->HwSetPowerState != NULL) &&
662         (HwInitializationData->HwGetPowerState != NULL) &&
663         (HwInitializationData->HwGetVideoChildDescriptor != NULL))
664     {
665         INFO_(VIDEOPRT, "The miniport is a PnP miniport driver\n");
666         PnpDriver = TRUE;
667     }
668 
669     /* Check if legacy detection should be applied */
670     if (!PnpDriver || HwContext)
671     {
672         INFO_(VIDEOPRT, "Legacy detection for adapter interface %d\n",
673               HwInitializationData->AdapterInterfaceType);
674 
675         /* FIXME: Move the code for legacy detection
676            to another function and call it here */
677         LegacyDetection = TRUE;
678     }
679 
680     /*
681      * NOTE:
682      * The driver extension can be already allocated in case that we were
683      * called by legacy driver and failed detecting device. Some miniport
684      * drivers in that case adjust parameters and call VideoPortInitialize
685      * again.
686      */
687     DriverExtension = IoGetDriverObjectExtension(DriverObject, DriverObject);
688     if (DriverExtension == NULL)
689     {
690         Status = IoAllocateDriverObjectExtension(DriverObject,
691                                                  DriverObject,
692                                                  sizeof(VIDEO_PORT_DRIVER_EXTENSION),
693                                                  (PVOID *)&DriverExtension);
694         if (!NT_SUCCESS(Status))
695         {
696             ERR_(VIDEOPRT, "IoAllocateDriverObjectExtension failed 0x%x\n", Status);
697             return Status;
698         }
699 
700         /*
701          * Save the registry path. This should be done only once even if
702          * VideoPortInitialize is called multiple times.
703          */
704         if (RegistryPath->Length != 0)
705         {
706             DriverExtension->RegistryPath.Length = 0;
707             DriverExtension->RegistryPath.MaximumLength =
708                 RegistryPath->Length + sizeof(UNICODE_NULL);
709             DriverExtension->RegistryPath.Buffer =
710                 ExAllocatePoolWithTag(
711                     PagedPool,
712                     DriverExtension->RegistryPath.MaximumLength,
713                     'RTSU');
714             if (DriverExtension->RegistryPath.Buffer == NULL)
715             {
716                 RtlInitUnicodeString(&DriverExtension->RegistryPath, NULL);
717                 return STATUS_INSUFFICIENT_RESOURCES;
718             }
719 
720             RtlCopyUnicodeString(&DriverExtension->RegistryPath, RegistryPath);
721             INFO_(VIDEOPRT, "RegistryPath: %wZ\n", &DriverExtension->RegistryPath);
722         }
723         else
724         {
725             RtlInitUnicodeString(&DriverExtension->RegistryPath, NULL);
726         }
727     }
728 
729     /* Copy the correct miniport initialization data to the device extension. */
730     RtlCopyMemory(&DriverExtension->InitializationData,
731                   HwInitializationData,
732                   HwInitializationData->HwInitDataSize);
733     if (HwInitializationData->HwInitDataSize <
734             sizeof(VIDEO_HW_INITIALIZATION_DATA))
735     {
736         RtlZeroMemory((PVOID)((ULONG_PTR)&DriverExtension->InitializationData +
737                               HwInitializationData->HwInitDataSize),
738                       sizeof(VIDEO_HW_INITIALIZATION_DATA) -
739                       HwInitializationData->HwInitDataSize);
740     }
741     DriverExtension->HwContext = HwContext;
742 
743     /*
744      * Plug & Play drivers registers the device in AddDevice routine.
745      * For legacy drivers we must do it now.
746      */
747     if (LegacyDetection)
748     {
749         PDEVICE_OBJECT DeviceObject;
750 
751         if (HwInitializationData->HwInitDataSize != SIZE_OF_NT4_VIDEO_HW_INITIALIZATION_DATA)
752         {
753             /* Power management */
754             DriverObject->MajorFunction[IRP_MJ_POWER] = IntVideoPortDispatchPower;
755         }
756 
757         Status = IntVideoPortCreateAdapterDeviceObject(DriverObject,
758                                                        DriverExtension,
759                                                        NULL,
760                                                        &DeviceObject);
761         if (!NT_SUCCESS(Status))
762         {
763             ERR_(VIDEOPRT, "IntVideoPortCreateAdapterDeviceObject returned 0x%x\n", Status);
764             return Status;
765         }
766 
767         Status = IntVideoPortFindAdapter(DriverObject, DriverExtension, DeviceObject);
768         if (NT_SUCCESS(Status))
769             VideoPortDeviceNumber++;
770         else
771             ERR_(VIDEOPRT, "IntVideoPortFindAdapter returned 0x%x\n", Status);
772 
773         return Status;
774     }
775     else
776     {
777         DriverObject->DriverExtension->AddDevice = IntVideoPortAddDevice;
778         DriverObject->MajorFunction[IRP_MJ_PNP] = IntVideoPortDispatchPnp;
779         DriverObject->MajorFunction[IRP_MJ_POWER] = IntVideoPortDispatchPower;
780         DriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = IntVideoPortDispatchSystemControl;
781 
782         return STATUS_SUCCESS;
783     }
784 }
785 
786 /*
787  * @implemented
788  */
789 VOID
790 VideoPortDebugPrint(
791     IN VIDEO_DEBUG_LEVEL DebugPrintLevel,
792     IN PCHAR DebugMessage,
793     ...)
794 {
795     va_list ap;
796 
797     va_start(ap, DebugMessage);
798     vDbgPrintEx(DPFLTR_IHVVIDEO_ID, DebugPrintLevel, DebugMessage, ap);
799     va_end(ap);
800 }
801 
802 /*
803  * @unimplemented
804  */
805 VOID
806 NTAPI
807 VideoPortLogError(
808     IN PVOID HwDeviceExtension,
809     IN PVIDEO_REQUEST_PACKET Vrp OPTIONAL,
810     IN VP_STATUS ErrorCode,
811     IN ULONG UniqueId)
812 {
813     UNIMPLEMENTED;
814 
815     INFO_(VIDEOPRT, "VideoPortLogError ErrorCode %d (0x%x) UniqueId %lu (0x%lx)\n",
816           ErrorCode, ErrorCode, UniqueId, UniqueId);
817     if (Vrp)
818         INFO_(VIDEOPRT, "Vrp->IoControlCode %lu (0x%lx)\n", Vrp->IoControlCode, Vrp->IoControlCode);
819 }
820 
821 /*
822  * @implemented
823  */
824 UCHAR
825 NTAPI
826 VideoPortGetCurrentIrql(VOID)
827 {
828     return KeGetCurrentIrql();
829 }
830 
831 typedef struct QueryRegistryCallbackContext
832 {
833     PVOID HwDeviceExtension;
834     PVOID HwContext;
835     PMINIPORT_GET_REGISTRY_ROUTINE HwGetRegistryRoutine;
836 } QUERY_REGISTRY_CALLBACK_CONTEXT, *PQUERY_REGISTRY_CALLBACK_CONTEXT;
837 
838 static
839 NTSTATUS
840 NTAPI
841 QueryRegistryCallback(
842     IN PWSTR ValueName,
843     IN ULONG ValueType,
844     IN PVOID ValueData,
845     IN ULONG ValueLength,
846     IN PVOID Context,
847     IN PVOID EntryContext)
848 {
849     PQUERY_REGISTRY_CALLBACK_CONTEXT CallbackContext = (PQUERY_REGISTRY_CALLBACK_CONTEXT) Context;
850 
851     INFO_(VIDEOPRT, "Found registry value for name %S: type %d, length %d\n",
852           ValueName, ValueType, ValueLength);
853     return (*(CallbackContext->HwGetRegistryRoutine))(
854                CallbackContext->HwDeviceExtension,
855                CallbackContext->HwContext,
856                ValueName,
857                ValueData,
858                ValueLength);
859 }
860 
861 /*
862  * @unimplemented
863  */
864 
865 VP_STATUS
866 NTAPI
867 VideoPortGetRegistryParameters(
868     IN PVOID HwDeviceExtension,
869     IN PWSTR ParameterName,
870     IN UCHAR IsParameterFileName,
871     IN PMINIPORT_GET_REGISTRY_ROUTINE GetRegistryRoutine,
872     IN PVOID HwContext)
873 {
874     RTL_QUERY_REGISTRY_TABLE QueryTable[2] = {{0}};
875     QUERY_REGISTRY_CALLBACK_CONTEXT Context;
876     PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension;
877     NTSTATUS Status;
878 
879     DeviceExtension = VIDEO_PORT_GET_DEVICE_EXTENSION(HwDeviceExtension);
880 
881     TRACE_(VIDEOPRT, "VideoPortGetRegistryParameters ParameterName %S, RegPath: %wZ\n",
882            ParameterName, &DeviceExtension->RegistryPath);
883 
884     Context.HwDeviceExtension = HwDeviceExtension;
885     Context.HwContext = HwContext;
886     Context.HwGetRegistryRoutine = GetRegistryRoutine;
887 
888     QueryTable[0].QueryRoutine = QueryRegistryCallback;
889     QueryTable[0].Flags = RTL_QUERY_REGISTRY_REQUIRED;
890     QueryTable[0].Name = ParameterName;
891 
892     Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
893                                     DeviceExtension->RegistryPath.Buffer,
894                                     QueryTable,
895                                     &Context,
896                                     NULL);
897     if (!NT_SUCCESS(Status))
898     {
899         WARN_(VIDEOPRT, "VideoPortGetRegistryParameters could not find the "
900               "requested parameter\n");
901         return ERROR_INVALID_PARAMETER;
902     }
903 
904     if (IsParameterFileName)
905     {
906         /* FIXME: need to read the contents of the file */
907         UNIMPLEMENTED;
908     }
909 
910     return NO_ERROR;
911 }
912 
913 /*
914  * @implemented
915  */
916 VP_STATUS
917 NTAPI
918 VideoPortSetRegistryParameters(
919     IN PVOID HwDeviceExtension,
920     IN PWSTR ValueName,
921     IN PVOID ValueData,
922     IN ULONG ValueLength)
923 {
924     PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension;
925     VP_STATUS Status;
926 
927     DeviceExtension = VIDEO_PORT_GET_DEVICE_EXTENSION(HwDeviceExtension);
928     TRACE_(VIDEOPRT, "VideoPortSetRegistryParameters ParameterName %S, RegPath: %wZ\n",
929            ValueName,
930            &DeviceExtension->RegistryPath);
931     ASSERT_IRQL_LESS_OR_EQUAL(PASSIVE_LEVEL);
932     Status = RtlWriteRegistryValue(RTL_REGISTRY_ABSOLUTE,
933                                    DeviceExtension->RegistryPath.Buffer,
934                                    ValueName,
935                                    REG_BINARY,
936                                    ValueData,
937                                    ValueLength);
938     if (Status != NO_ERROR)
939         WARN_(VIDEOPRT, "VideoPortSetRegistryParameters error 0x%x\n", Status);
940 
941     return Status;
942 }
943 
944 /*
945  * @implemented
946  */
947 VP_STATUS
948 NTAPI
949 VideoPortGetVgaStatus(
950     IN PVOID HwDeviceExtension,
951     OUT PULONG VgaStatus)
952 {
953     PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension;
954 
955     TRACE_(VIDEOPRT, "VideoPortGetVgaStatus\n");
956 
957     DeviceExtension = VIDEO_PORT_GET_DEVICE_EXTENSION(HwDeviceExtension);
958     if (KeGetCurrentIrql() == PASSIVE_LEVEL)
959     {
960         if (DeviceExtension->AdapterInterfaceType == PCIBus)
961         {
962             /* VgaStatus: 0 == VGA not enabled, 1 == VGA enabled. */
963             /* Assumed for now */
964             *VgaStatus = 1;
965             return NO_ERROR;
966         }
967     }
968 
969     return ERROR_INVALID_FUNCTION;
970 }
971 
972 /*
973  * @implemented
974  */
975 PVOID
976 NTAPI
977 VideoPortGetRomImage(
978     IN PVOID HwDeviceExtension,
979     IN PVOID Unused1,
980     IN ULONG Unused2,
981     IN ULONG Length)
982 {
983     static PVOID RomImageBuffer = NULL;
984     PKPROCESS CallingProcess;
985     KAPC_STATE ApcState;
986 
987     TRACE_(VIDEOPRT, "VideoPortGetRomImage(HwDeviceExtension 0x%X Length 0x%X)\n",
988            HwDeviceExtension, Length);
989 
990     /* If the length is zero then free the existing buffer. */
991     if (Length == 0)
992     {
993         if (RomImageBuffer != NULL)
994         {
995             ExFreePool(RomImageBuffer);
996             RomImageBuffer = NULL;
997         }
998         return NULL;
999     }
1000     else
1001     {
1002         /*
1003          * The DDK says we shouldn't use the legacy C0000 method but get the
1004          * rom base address from the corresponding pci or acpi register but
1005          * lets ignore that and use C0000 anyway. We have already mapped the
1006          * bios area into memory so we'll copy from there.
1007          */
1008 
1009         /* Copy the bios. */
1010         Length = min(Length, 0x10000);
1011         if (RomImageBuffer != NULL)
1012         {
1013             ExFreePool(RomImageBuffer);
1014         }
1015 
1016         RomImageBuffer = ExAllocatePool(PagedPool, Length);
1017         if (RomImageBuffer == NULL)
1018         {
1019             return NULL;
1020         }
1021 
1022         IntAttachToCSRSS(&CallingProcess, &ApcState);
1023         RtlCopyMemory(RomImageBuffer, (PUCHAR)0xC0000, Length);
1024         IntDetachFromCSRSS(&CallingProcess, &ApcState);
1025 
1026         return RomImageBuffer;
1027     }
1028 }
1029 
1030 /*
1031  * @implemented
1032  */
1033 BOOLEAN
1034 NTAPI
1035 VideoPortScanRom(
1036     IN PVOID HwDeviceExtension,
1037     IN PUCHAR RomBase,
1038     IN ULONG RomLength,
1039     IN PUCHAR String)
1040 {
1041     SIZE_T StringLength;
1042     BOOLEAN Found;
1043     PUCHAR SearchLocation;
1044 
1045     TRACE_(VIDEOPRT, "VideoPortScanRom RomBase %p RomLength 0x%x String %s\n", RomBase, RomLength, String);
1046 
1047     StringLength = strlen((PCHAR)String);
1048     Found = FALSE;
1049     SearchLocation = RomBase;
1050     for (SearchLocation = RomBase;
1051             !Found && SearchLocation < RomBase + RomLength - StringLength;
1052             SearchLocation++)
1053     {
1054         Found = (RtlCompareMemory(SearchLocation, String, StringLength) == StringLength);
1055         if (Found)
1056         {
1057             INFO_(VIDEOPRT, "Match found at %p\n", SearchLocation);
1058         }
1059     }
1060 
1061     return Found;
1062 }
1063 
1064 /*
1065  * @implemented
1066  */
1067 BOOLEAN
1068 NTAPI
1069 VideoPortSynchronizeExecution(
1070     IN PVOID HwDeviceExtension,
1071     IN VIDEO_SYNCHRONIZE_PRIORITY Priority,
1072     IN PMINIPORT_SYNCHRONIZE_ROUTINE SynchronizeRoutine,
1073     OUT PVOID Context)
1074 {
1075     BOOLEAN Ret;
1076     PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension;
1077     KIRQL OldIrql;
1078 
1079     switch (Priority)
1080     {
1081         case VpLowPriority:
1082             Ret = (*SynchronizeRoutine)(Context);
1083             break;
1084 
1085         case VpMediumPriority:
1086             DeviceExtension = VIDEO_PORT_GET_DEVICE_EXTENSION(HwDeviceExtension);
1087             if (DeviceExtension->InterruptObject == NULL)
1088                 Ret = (*SynchronizeRoutine)(Context);
1089             else
1090                 Ret = KeSynchronizeExecution(
1091                           DeviceExtension->InterruptObject,
1092                           SynchronizeRoutine,
1093                           Context);
1094             break;
1095 
1096         case VpHighPriority:
1097             OldIrql = KeGetCurrentIrql();
1098             if (OldIrql < SYNCH_LEVEL)
1099                 KeRaiseIrql(SYNCH_LEVEL, &OldIrql);
1100 
1101             Ret = (*SynchronizeRoutine)(Context);
1102 
1103             if (OldIrql < SYNCH_LEVEL)
1104                 KeLowerIrql(OldIrql);
1105             break;
1106 
1107         default:
1108             Ret = FALSE;
1109     }
1110 
1111     return Ret;
1112 }
1113 
1114 /*
1115  * @implemented
1116  */
1117 VP_STATUS
1118 NTAPI
1119 VideoPortEnumerateChildren(
1120     IN PVOID HwDeviceExtension,
1121     IN PVOID Reserved)
1122 {
1123     PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension;
1124     ULONG Status;
1125     VIDEO_CHILD_ENUM_INFO ChildEnumInfo;
1126     BOOLEAN bHaveLastMonitorID = FALSE;
1127     UCHAR LastMonitorID[10];
1128     ULONG Unused;
1129     UINT i;
1130     PDEVICE_OBJECT ChildDeviceObject;
1131     PVIDEO_PORT_CHILD_EXTENSION ChildExtension;
1132 
1133     INFO_(VIDEOPRT, "Starting child device probe\n");
1134     DeviceExtension = VIDEO_PORT_GET_DEVICE_EXTENSION(HwDeviceExtension);
1135     if (DeviceExtension->DriverExtension->InitializationData.HwGetVideoChildDescriptor == NULL)
1136     {
1137         WARN_(VIDEOPRT, "Miniport's HwGetVideoChildDescriptor is NULL!\n");
1138         return NO_ERROR;
1139     }
1140 
1141     if (!IsListEmpty(&DeviceExtension->ChildDeviceList))
1142     {
1143         ERR_(VIDEOPRT, "FIXME: Support calling VideoPortEnumerateChildren again!\n");
1144         return NO_ERROR;
1145     }
1146 
1147     /* Enumerate the children */
1148     for (i = 1; ; i++)
1149     {
1150         Status = IoCreateDevice(DeviceExtension->DriverObject,
1151                                 sizeof(VIDEO_PORT_CHILD_EXTENSION) +
1152                                 DeviceExtension->DriverExtension->InitializationData.HwChildDeviceExtensionSize,
1153                                 NULL,
1154                                 FILE_DEVICE_CONTROLLER,
1155                                 FILE_DEVICE_SECURE_OPEN,
1156                                 FALSE,
1157                                 &ChildDeviceObject);
1158         if (!NT_SUCCESS(Status))
1159             return Status;
1160 
1161         ChildExtension = ChildDeviceObject->DeviceExtension;
1162 
1163         RtlZeroMemory(ChildExtension,
1164                       sizeof(VIDEO_PORT_CHILD_EXTENSION) +
1165                         DeviceExtension->DriverExtension->InitializationData.HwChildDeviceExtensionSize);
1166 
1167         ChildExtension->Common.Fdo = FALSE;
1168         ChildExtension->ChildId = i;
1169         ChildExtension->PhysicalDeviceObject = ChildDeviceObject;
1170         ChildExtension->DriverObject = DeviceExtension->DriverObject;
1171 
1172         /* Setup the ChildEnumInfo */
1173         ChildEnumInfo.Size = sizeof(ChildEnumInfo);
1174         ChildEnumInfo.ChildDescriptorSize = sizeof(ChildExtension->ChildDescriptor);
1175         ChildEnumInfo.ACPIHwId = 0;
1176 
1177         if (DeviceExtension->DriverExtension->InitializationData.HwChildDeviceExtensionSize)
1178             ChildEnumInfo.ChildHwDeviceExtension = VIDEO_PORT_GET_CHILD_EXTENSION(ChildExtension);
1179         else
1180             ChildEnumInfo.ChildHwDeviceExtension = NULL;
1181 
1182         ChildEnumInfo.ChildIndex = ChildExtension->ChildId;
1183 
1184         INFO_(VIDEOPRT, "Probing child: %d\n", ChildEnumInfo.ChildIndex);
1185         Status = DeviceExtension->DriverExtension->InitializationData.HwGetVideoChildDescriptor(
1186                      HwDeviceExtension,
1187                      &ChildEnumInfo,
1188                      &ChildExtension->ChildType,
1189                      ChildExtension->ChildDescriptor,
1190                      &ChildExtension->ChildId,
1191                      &Unused);
1192         if (Status == VIDEO_ENUM_MORE_DEVICES)
1193         {
1194             if (ChildExtension->ChildType == Monitor)
1195             {
1196                 // Check if the EDID is valid
1197                 if (ChildExtension->ChildDescriptor[0] == 0x00 &&
1198                         ChildExtension->ChildDescriptor[1] == 0xFF &&
1199                         ChildExtension->ChildDescriptor[2] == 0xFF &&
1200                         ChildExtension->ChildDescriptor[3] == 0xFF &&
1201                         ChildExtension->ChildDescriptor[4] == 0xFF &&
1202                         ChildExtension->ChildDescriptor[5] == 0xFF &&
1203                         ChildExtension->ChildDescriptor[6] == 0xFF &&
1204                         ChildExtension->ChildDescriptor[7] == 0x00)
1205                 {
1206                     if (bHaveLastMonitorID)
1207                     {
1208                         // Compare the previous monitor ID with the current one, break the loop if they are identical
1209                         if (RtlCompareMemory(LastMonitorID, &ChildExtension->ChildDescriptor[8], sizeof(LastMonitorID)) == sizeof(LastMonitorID))
1210                         {
1211                             INFO_(VIDEOPRT, "Found identical Monitor ID two times, stopping enumeration\n");
1212                             IoDeleteDevice(ChildDeviceObject);
1213                             break;
1214                         }
1215                     }
1216 
1217                     // Copy 10 bytes from the EDID, which can be used to uniquely identify the monitor
1218                     RtlCopyMemory(LastMonitorID, &ChildExtension->ChildDescriptor[8], sizeof(LastMonitorID));
1219                     bHaveLastMonitorID = TRUE;
1220 
1221                     /* Mark it valid */
1222                     ChildExtension->EdidValid = TRUE;
1223                 }
1224                 else
1225                 {
1226                     /* Mark it invalid */
1227                     ChildExtension->EdidValid = FALSE;
1228                     // FIXME: the following break workarounds CORE-16695
1229                     // but prevents graphic cards to return an invalid
1230                     // EDID as first child, and a valid one as second child.
1231                     break;
1232                 }
1233             }
1234         }
1235         else if (Status == VIDEO_ENUM_INVALID_DEVICE)
1236         {
1237             WARN_(VIDEOPRT, "Child device %d is invalid!\n", ChildEnumInfo.ChildIndex);
1238             IoDeleteDevice(ChildDeviceObject);
1239             continue;
1240         }
1241         else if (Status == VIDEO_ENUM_NO_MORE_DEVICES)
1242         {
1243             INFO_(VIDEOPRT, "End of child enumeration! (%d children enumerated)\n", i - 1);
1244             IoDeleteDevice(ChildDeviceObject);
1245             break;
1246         }
1247         else
1248         {
1249             WARN_(VIDEOPRT, "HwGetVideoChildDescriptor returned unknown status code 0x%x!\n", Status);
1250             IoDeleteDevice(ChildDeviceObject);
1251             break;
1252         }
1253 
1254         if (ChildExtension->ChildType == Monitor)
1255         {
1256             UINT j;
1257             PUCHAR p = ChildExtension->ChildDescriptor;
1258             INFO_(VIDEOPRT, "Monitor device enumerated! (ChildId = 0x%x)\n", ChildExtension->ChildId);
1259             for (j = 0; j < sizeof (ChildExtension->ChildDescriptor); j += 8)
1260             {
1261                 INFO_(VIDEOPRT, "%02x %02x %02x %02x %02x %02x %02x %02x\n",
1262                       p[j + 0], p[j + 1], p[j + 2], p[j + 3],
1263                       p[j + 4], p[j + 5], p[j + 6], p[j + 7]);
1264             }
1265         }
1266         else if (ChildExtension->ChildType == Other)
1267         {
1268             INFO_(VIDEOPRT, "\"Other\" device enumerated: DeviceId = %S\n", (PWSTR)ChildExtension->ChildDescriptor);
1269         }
1270         else
1271         {
1272             ERR_(VIDEOPRT, "HwGetVideoChildDescriptor returned unsupported type: %d\n", ChildExtension->ChildType);
1273         }
1274 
1275         /* Clear the init flag */
1276         ChildDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
1277 
1278         InsertTailList(&DeviceExtension->ChildDeviceList,
1279                        &ChildExtension->ListEntry);
1280     }
1281 
1282     /* Trigger reenumeration by the PnP manager */
1283     IoInvalidateDeviceRelations(DeviceExtension->PhysicalDeviceObject, BusRelations);
1284 
1285     return NO_ERROR;
1286 }
1287 
1288 /*
1289  * @unimplemented
1290  */
1291 VP_STATUS
1292 NTAPI
1293 VideoPortCreateSecondaryDisplay(
1294     IN PVOID HwDeviceExtension,
1295     IN OUT PVOID *SecondaryDeviceExtension,
1296     IN ULONG Flag)
1297 {
1298     UNIMPLEMENTED;
1299     return ERROR_DEV_NOT_EXIST;
1300 }
1301 
1302 /*
1303  * @implemented
1304  */
1305 BOOLEAN
1306 NTAPI
1307 VideoPortQueueDpc(
1308     IN PVOID HwDeviceExtension,
1309     IN PMINIPORT_DPC_ROUTINE CallbackRoutine,
1310     IN PVOID Context)
1311 {
1312     return KeInsertQueueDpc(
1313                &VIDEO_PORT_GET_DEVICE_EXTENSION(HwDeviceExtension)->DpcObject,
1314                (PVOID)CallbackRoutine,
1315                (PVOID)Context);
1316 }
1317 
1318 /*
1319  * @implemented
1320  */
1321 PVOID
1322 NTAPI
1323 VideoPortGetAssociatedDeviceExtension(
1324     IN PVOID DeviceObject)
1325 {
1326     PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension;
1327 
1328     TRACE_(VIDEOPRT, "VideoPortGetAssociatedDeviceExtension\n");
1329     DeviceExtension = ((PDEVICE_OBJECT)DeviceObject)->DeviceExtension;
1330     if (!DeviceExtension)
1331         return NULL;
1332     return DeviceExtension->MiniPortDeviceExtension;
1333 }
1334 
1335 /*
1336  * @implemented
1337  */
1338 VP_STATUS
1339 NTAPI
1340 VideoPortGetVersion(
1341     IN PVOID HwDeviceExtension,
1342     IN OUT PVPOSVERSIONINFO VpOsVersionInfo)
1343 {
1344     RTL_OSVERSIONINFOEXW Version;
1345 
1346     Version.dwOSVersionInfoSize = sizeof(RTL_OSVERSIONINFOEXW);
1347     if (VpOsVersionInfo->Size >= sizeof(VPOSVERSIONINFO))
1348     {
1349 #if 1
1350         if (NT_SUCCESS(RtlGetVersion((PRTL_OSVERSIONINFOW)&Version)))
1351         {
1352             VpOsVersionInfo->MajorVersion = Version.dwMajorVersion;
1353             VpOsVersionInfo->MinorVersion = Version.dwMinorVersion;
1354             VpOsVersionInfo->BuildNumber = Version.dwBuildNumber;
1355             VpOsVersionInfo->ServicePackMajor = Version.wServicePackMajor;
1356             VpOsVersionInfo->ServicePackMinor = Version.wServicePackMinor;
1357             return NO_ERROR;
1358         }
1359         return ERROR_INVALID_PARAMETER;
1360 #else
1361         VpOsVersionInfo->MajorVersion = 5;
1362         VpOsVersionInfo->MinorVersion = 0;
1363         VpOsVersionInfo->BuildNumber = 2195;
1364         VpOsVersionInfo->ServicePackMajor = 4;
1365         VpOsVersionInfo->ServicePackMinor = 0;
1366         return NO_ERROR;
1367 #endif
1368     }
1369 
1370     return ERROR_INVALID_PARAMETER;
1371 }
1372 
1373 /*
1374  * @implemented
1375  */
1376 BOOLEAN
1377 NTAPI
1378 VideoPortCheckForDeviceExistence(
1379     IN PVOID HwDeviceExtension,
1380     IN USHORT VendorId,
1381     IN USHORT DeviceId,
1382     IN UCHAR RevisionId,
1383     IN USHORT SubVendorId,
1384     IN USHORT SubSystemId,
1385     IN ULONG Flags)
1386 {
1387     PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension;
1388     PCI_DEVICE_PRESENT_INTERFACE PciDevicePresentInterface;
1389     IO_STATUS_BLOCK IoStatusBlock;
1390     IO_STACK_LOCATION IoStack;
1391     ULONG PciFlags = 0;
1392     NTSTATUS Status;
1393     BOOL DevicePresent;
1394 
1395     TRACE_(VIDEOPRT, "VideoPortCheckForDeviceExistence\n");
1396 
1397     if (Flags & ~(CDE_USE_REVISION | CDE_USE_SUBSYSTEM_IDS))
1398     {
1399         WARN_(VIDEOPRT, "VideoPortCheckForDeviceExistence: Unknown flags 0x%lx\n", Flags & ~(CDE_USE_REVISION | CDE_USE_SUBSYSTEM_IDS));
1400         return FALSE;
1401     }
1402 
1403     DeviceExtension = VIDEO_PORT_GET_DEVICE_EXTENSION(HwDeviceExtension);
1404 
1405     PciDevicePresentInterface.Size = sizeof(PCI_DEVICE_PRESENT_INTERFACE);
1406     PciDevicePresentInterface.Version = 1;
1407     IoStack.Parameters.QueryInterface.Size = PciDevicePresentInterface.Size;
1408     IoStack.Parameters.QueryInterface.Version = PciDevicePresentInterface.Version;
1409     IoStack.Parameters.QueryInterface.Interface = (PINTERFACE)&PciDevicePresentInterface;
1410     IoStack.Parameters.QueryInterface.InterfaceType =
1411         &GUID_PCI_DEVICE_PRESENT_INTERFACE;
1412     Status = IopInitiatePnpIrp(DeviceExtension->NextDeviceObject,
1413                                &IoStatusBlock, IRP_MN_QUERY_INTERFACE, &IoStack);
1414     if (!NT_SUCCESS(Status))
1415     {
1416         WARN_(VIDEOPRT, "IopInitiatePnpIrp() failed! (Status 0x%lx)\n", Status);
1417         return FALSE;
1418     }
1419 
1420     if (Flags & CDE_USE_REVISION)
1421         PciFlags |= PCI_USE_REVISION;
1422     if (Flags & CDE_USE_SUBSYSTEM_IDS)
1423         PciFlags |= PCI_USE_SUBSYSTEM_IDS;
1424 
1425     DevicePresent = PciDevicePresentInterface.IsDevicePresent(
1426                         VendorId, DeviceId, RevisionId,
1427                         SubVendorId, SubSystemId, PciFlags);
1428 
1429     PciDevicePresentInterface.InterfaceDereference(PciDevicePresentInterface.Context);
1430 
1431     return DevicePresent;
1432 }
1433 
1434 /*
1435  * @unimplemented
1436  */
1437 VP_STATUS
1438 NTAPI
1439 VideoPortRegisterBugcheckCallback(
1440     IN PVOID HwDeviceExtension,
1441     IN ULONG BugcheckCode,
1442     IN PVIDEO_BUGCHECK_CALLBACK Callback,
1443     IN ULONG BugcheckDataSize)
1444 {
1445     UNIMPLEMENTED;
1446     return NO_ERROR;
1447 }
1448 
1449 /*
1450  * @implemented
1451  */
1452 LONGLONG
1453 NTAPI
1454 VideoPortQueryPerformanceCounter(
1455     IN PVOID HwDeviceExtension,
1456     OUT PLONGLONG PerformanceFrequency OPTIONAL)
1457 {
1458     LARGE_INTEGER Result;
1459 
1460     TRACE_(VIDEOPRT, "VideoPortQueryPerformanceCounter\n");
1461     Result = KeQueryPerformanceCounter((PLARGE_INTEGER)PerformanceFrequency);
1462     return Result.QuadPart;
1463 }
1464 
1465 /*
1466  * @implemented
1467  */
1468 VOID
1469 NTAPI
1470 VideoPortAcquireDeviceLock(
1471     IN PVOID  HwDeviceExtension)
1472 {
1473     PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension;
1474     NTSTATUS Status;
1475 
1476     UNREFERENCED_LOCAL_VARIABLE(Status);
1477 
1478     TRACE_(VIDEOPRT, "VideoPortAcquireDeviceLock\n");
1479     DeviceExtension = VIDEO_PORT_GET_DEVICE_EXTENSION(HwDeviceExtension);
1480     Status = KeWaitForMutexObject(&DeviceExtension->DeviceLock, Executive,
1481                                   KernelMode, FALSE, NULL);
1482     // ASSERT(Status == STATUS_SUCCESS);
1483 }
1484 
1485 /*
1486  * @implemented
1487  */
1488 VOID
1489 NTAPI
1490 VideoPortReleaseDeviceLock(
1491     IN PVOID HwDeviceExtension)
1492 {
1493     PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension;
1494     LONG Status;
1495 
1496     UNREFERENCED_LOCAL_VARIABLE(Status);
1497 
1498     TRACE_(VIDEOPRT, "VideoPortReleaseDeviceLock\n");
1499     DeviceExtension = VIDEO_PORT_GET_DEVICE_EXTENSION(HwDeviceExtension);
1500     Status = KeReleaseMutex(&DeviceExtension->DeviceLock, FALSE);
1501     //ASSERT(Status == STATUS_SUCCESS);
1502 }
1503 
1504 /*
1505  * @unimplemented
1506  */
1507 VOID
1508 NTAPI
1509 VpNotifyEaData(
1510     IN PDEVICE_OBJECT DeviceObject,
1511     IN PVOID Data)
1512 {
1513     UNIMPLEMENTED;
1514 }
1515 
1516 /*
1517  * @implemented
1518  */
1519 PVOID
1520 NTAPI
1521 VideoPortAllocateContiguousMemory(
1522     IN PVOID HwDeviceExtension,
1523     IN ULONG NumberOfBytes,
1524     IN PHYSICAL_ADDRESS HighestAcceptableAddress
1525 )
1526 {
1527     return MmAllocateContiguousMemory(NumberOfBytes, HighestAcceptableAddress);
1528 }
1529 
1530 /*
1531  * @implemented
1532  */
1533 BOOLEAN
1534 NTAPI
1535 VideoPortIsNoVesa(VOID)
1536 {
1537     return VpNoVesa;
1538 }
1539