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