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