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