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