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