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