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