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