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