[HNETCFG] Sync with Wine 3.0. CORE-14225
[reactos.git] / win32ss / drivers / videoprt / videoprt.c
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 ULONG 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 }