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