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