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