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