Link video miniports to videoprt library only
[reactos.git] / reactos / drivers / video / videoprt / videoprt.c
1 /*
2 * VideoPort driver
3 *
4 * Copyright (C) 2002, 2003, 2004 ReactOS Team
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Library General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 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 * Library General Public License for more details.
15 *
16 * You should have received a copy of the GNU Library General Public
17 * License along with this library; see the file COPYING.LIB.
18 * If not, write to the Free Software Foundation,
19 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 *
21 * $Id$
22 */
23
24 #include "videoprt.h"
25
26 /* GLOBAL VARIABLES ***********************************************************/
27
28 ULONG CsrssInitialized = FALSE;
29 PKPROCESS Csrss = NULL;
30 ULONG VideoPortDeviceNumber = 0;
31
32 /* PRIVATE FUNCTIONS **********************************************************/
33
34 NTSTATUS NTAPI
35 DriverEntry(
36 IN PDRIVER_OBJECT DriverObject,
37 IN PUNICODE_STRING RegistryPath)
38 {
39 return STATUS_SUCCESS;
40 }
41
42 PVOID NTAPI
43 IntVideoPortImageDirectoryEntryToData(
44 PVOID BaseAddress,
45 ULONG Directory)
46 {
47 PIMAGE_NT_HEADERS NtHeader;
48 ULONG Va;
49
50 NtHeader = RtlImageNtHeader(BaseAddress);
51 if (NtHeader == NULL)
52 return NULL;
53
54 if (Directory >= NtHeader->OptionalHeader.NumberOfRvaAndSizes)
55 return NULL;
56
57 Va = NtHeader->OptionalHeader.DataDirectory[Directory].VirtualAddress;
58 if (Va == 0)
59 return NULL;
60
61 return (PVOID)((ULONG_PTR)BaseAddress + Va);
62 }
63
64 PVOID NTAPI
65 IntVideoPortGetProcAddress(
66 IN PVOID HwDeviceExtension,
67 IN PUCHAR FunctionName)
68 {
69 SYSTEM_GDI_DRIVER_INFORMATION GdiDriverInfo;
70 PVOID BaseAddress;
71 PIMAGE_EXPORT_DIRECTORY ExportDir;
72 PUSHORT OrdinalPtr;
73 PULONG NamePtr;
74 PULONG AddressPtr;
75 ULONG i = 0;
76 NTSTATUS Status;
77
78 DPRINT("VideoPortGetProcAddress(%s)\n", FunctionName);
79
80 RtlInitUnicodeString(&GdiDriverInfo.DriverName, L"videoprt");
81 Status = ZwSetSystemInformation(
82 SystemLoadGdiDriverInformation,
83 &GdiDriverInfo,
84 sizeof(SYSTEM_GDI_DRIVER_INFORMATION));
85 if (!NT_SUCCESS(Status))
86 {
87 DPRINT("Couldn't get our own module handle?\n");
88 return NULL;
89 }
90
91 BaseAddress = GdiDriverInfo.ImageAddress;
92
93 /* Get the pointer to the export directory */
94 ExportDir = (PIMAGE_EXPORT_DIRECTORY)IntVideoPortImageDirectoryEntryToData(
95 BaseAddress,
96 IMAGE_DIRECTORY_ENTRY_EXPORT);
97
98 /* Search by name */
99 AddressPtr = (PULONG)
100 ((ULONG_PTR)BaseAddress + (ULONG_PTR)ExportDir->AddressOfFunctions);
101 OrdinalPtr = (PUSHORT)
102 ((ULONG_PTR)BaseAddress + (ULONG_PTR)ExportDir->AddressOfNameOrdinals);
103 NamePtr = (PULONG)
104 ((ULONG_PTR)BaseAddress + (ULONG_PTR)ExportDir->AddressOfNames);
105 for (i = 0; i < ExportDir->NumberOfNames; i++, NamePtr++, OrdinalPtr++)
106 {
107 if (!_strnicmp((PCHAR)FunctionName, (PCHAR)((ULONG_PTR)BaseAddress + *NamePtr),
108 strlen((PCHAR)FunctionName)))
109 {
110 return (PVOID)((ULONG_PTR)BaseAddress +
111 (ULONG_PTR)AddressPtr[*OrdinalPtr]);
112 }
113 }
114
115 DPRINT("VideoPortGetProcAddress: Can't resolve symbol %s\n", FunctionName);
116
117 return NULL;
118 }
119
120 VOID NTAPI
121 IntVideoPortDeferredRoutine(
122 IN PKDPC Dpc,
123 IN PVOID DeferredContext,
124 IN PVOID SystemArgument1,
125 IN PVOID SystemArgument2)
126 {
127 PVOID HwDeviceExtension =
128 &((PVIDEO_PORT_DEVICE_EXTENSION)DeferredContext)->MiniPortDeviceExtension;
129 ((PMINIPORT_DPC_ROUTINE)SystemArgument1)(HwDeviceExtension, SystemArgument2);
130 }
131
132 NTSTATUS NTAPI
133 IntVideoPortCreateAdapterDeviceObject(
134 IN PDRIVER_OBJECT DriverObject,
135 IN PVIDEO_PORT_DRIVER_EXTENSION DriverExtension,
136 IN PDEVICE_OBJECT PhysicalDeviceObject,
137 OUT PDEVICE_OBJECT *DeviceObject OPTIONAL)
138 {
139 PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension;
140 ULONG DeviceNumber;
141 ULONG Size;
142 NTSTATUS Status;
143 WCHAR DeviceBuffer[20];
144 UNICODE_STRING DeviceName;
145 PDEVICE_OBJECT DeviceObject_;
146
147 if (DeviceObject == NULL)
148 DeviceObject = &DeviceObject_;
149
150 /*
151 * Find the first free device number that can be used for video device
152 * object names and symlinks.
153 */
154
155 DeviceNumber = VideoPortDeviceNumber++;
156 if (DeviceNumber == 0xFFFFFFFF)
157 {
158 DPRINT("Can't find free device number\n");
159 return STATUS_UNSUCCESSFUL;
160 }
161
162 /*
163 * Create the device object.
164 */
165
166 /* Create a unicode device name. */
167 swprintf(DeviceBuffer, L"\\Device\\Video%lu", DeviceNumber);
168 RtlInitUnicodeString(&DeviceName, DeviceBuffer);
169
170 /* Create the device object. */
171 Status = IoCreateDevice(
172 DriverObject,
173 sizeof(VIDEO_PORT_DEVICE_EXTENSION) +
174 DriverExtension->InitializationData.HwDeviceExtensionSize,
175 &DeviceName,
176 FILE_DEVICE_VIDEO,
177 0,
178 TRUE,
179 DeviceObject);
180
181 if (!NT_SUCCESS(Status))
182 {
183 DPRINT("IoCreateDevice call failed with status 0x%08x\n", Status);
184 return Status;
185 }
186
187 /*
188 * Set the buffering strategy here. If you change this, remember
189 * to change VidDispatchDeviceControl too.
190 */
191
192 (*DeviceObject)->Flags |= DO_BUFFERED_IO;
193
194 /*
195 * Initialize device extension.
196 */
197
198 DeviceExtension = (PVIDEO_PORT_DEVICE_EXTENSION)((*DeviceObject)->DeviceExtension);
199 DeviceExtension->DeviceNumber = DeviceNumber;
200 DeviceExtension->DriverObject = DriverObject;
201 DeviceExtension->PhysicalDeviceObject = PhysicalDeviceObject;
202 DeviceExtension->FunctionalDeviceObject = *DeviceObject;
203 DeviceExtension->DriverExtension = DriverExtension;
204
205 DeviceExtension->RegistryPath.Length =
206 DeviceExtension->RegistryPath.MaximumLength =
207 DriverExtension->RegistryPath.Length + (9 * sizeof(WCHAR));
208 DeviceExtension->RegistryPath.Length -= sizeof(WCHAR);
209 DeviceExtension->RegistryPath.Buffer = ExAllocatePoolWithTag(
210 NonPagedPool,
211 DeviceExtension->RegistryPath.MaximumLength,
212 TAG_VIDEO_PORT);
213 swprintf(DeviceExtension->RegistryPath.Buffer, L"%s\\Device0",
214 DriverExtension->RegistryPath.Buffer);
215
216 if (PhysicalDeviceObject != NULL)
217 {
218 /* Get bus number from the upper level bus driver. */
219 Size = sizeof(ULONG);
220 Status = IoGetDeviceProperty(
221 PhysicalDeviceObject,
222 DevicePropertyBusNumber,
223 Size,
224 &DeviceExtension->SystemIoBusNumber,
225 &Size);
226 if (!NT_SUCCESS(Status))
227 {
228 DPRINT("Couldn't get an information from bus driver. We will try to\n"
229 "use legacy detection method, but even that doesn't mean that\n"
230 "it will work.\n");
231 DeviceExtension->PhysicalDeviceObject = NULL;
232 }
233 }
234
235 DeviceExtension->AdapterInterfaceType =
236 DriverExtension->InitializationData.AdapterInterfaceType;
237
238 if (PhysicalDeviceObject != NULL)
239 {
240 /* Get bus type from the upper level bus driver. */
241 Size = sizeof(ULONG);
242 IoGetDeviceProperty(
243 PhysicalDeviceObject,
244 DevicePropertyLegacyBusType,
245 Size,
246 &DeviceExtension->AdapterInterfaceType,
247 &Size);
248
249 /* Get bus device address from the upper level bus driver. */
250 Size = sizeof(ULONG);
251 IoGetDeviceProperty(
252 PhysicalDeviceObject,
253 DevicePropertyAddress,
254 Size,
255 &DeviceExtension->SystemIoSlotNumber,
256 &Size);
257 }
258
259 InitializeListHead(&DeviceExtension->AddressMappingListHead);
260 KeInitializeDpc(
261 &DeviceExtension->DpcObject,
262 IntVideoPortDeferredRoutine,
263 DeviceExtension);
264
265 KeInitializeMutex(&DeviceExtension->DeviceLock, 0);
266
267 /* Attach the device. */
268 if (PhysicalDeviceObject != NULL)
269 DeviceExtension->NextDeviceObject = IoAttachDeviceToDeviceStack(
270 *DeviceObject, PhysicalDeviceObject);
271
272 return STATUS_SUCCESS;
273 }
274
275
276 /* FIXME: we have to detach the device object in IntVideoPortFindAdapter if it fails */
277 NTSTATUS NTAPI
278 IntVideoPortFindAdapter(
279 IN PDRIVER_OBJECT DriverObject,
280 IN PVIDEO_PORT_DRIVER_EXTENSION DriverExtension,
281 IN PDEVICE_OBJECT DeviceObject)
282 {
283 WCHAR DeviceVideoBuffer[20];
284 PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension;
285 ULONG Size;
286 NTSTATUS Status;
287 VIDEO_PORT_CONFIG_INFO ConfigInfo;
288 SYSTEM_BASIC_INFORMATION SystemBasicInfo;
289 UCHAR Again = FALSE;
290 WCHAR DeviceBuffer[20];
291 UNICODE_STRING DeviceName;
292 WCHAR SymlinkBuffer[20];
293 UNICODE_STRING SymlinkName;
294 BOOL LegacyDetection = FALSE;
295 ULONG DeviceNumber;
296
297 DeviceExtension = (PVIDEO_PORT_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
298 DeviceNumber = DeviceExtension->DeviceNumber;
299
300 /*
301 * Setup a ConfigInfo structure that we will pass to HwFindAdapter.
302 */
303
304 RtlZeroMemory(&ConfigInfo, sizeof(VIDEO_PORT_CONFIG_INFO));
305 ConfigInfo.Length = sizeof(VIDEO_PORT_CONFIG_INFO);
306 ConfigInfo.AdapterInterfaceType = DeviceExtension->AdapterInterfaceType;
307 if (ConfigInfo.AdapterInterfaceType == PCIBus)
308 ConfigInfo.InterruptMode = LevelSensitive;
309 else
310 ConfigInfo.InterruptMode = Latched;
311 ConfigInfo.DriverRegistryPath = DriverExtension->RegistryPath.Buffer;
312 ConfigInfo.VideoPortGetProcAddress = IntVideoPortGetProcAddress;
313 ConfigInfo.SystemIoBusNumber = DeviceExtension->SystemIoBusNumber;
314 ConfigInfo.BusInterruptLevel = DeviceExtension->InterruptLevel;
315 ConfigInfo.BusInterruptVector = DeviceExtension->InterruptVector;
316
317 Size = sizeof(SystemBasicInfo);
318 Status = ZwQuerySystemInformation(
319 SystemBasicInformation,
320 &SystemBasicInfo,
321 Size,
322 &Size);
323
324 if (NT_SUCCESS(Status))
325 {
326 ConfigInfo.SystemMemorySize =
327 SystemBasicInfo.NumberOfPhysicalPages *
328 SystemBasicInfo.PageSize;
329 }
330
331 /*
332 * Call miniport HwVidFindAdapter entry point to detect if
333 * particular device is present. There are two possible code
334 * paths. The first one is for Legacy drivers (NT4) and cases
335 * when we don't have information about what bus we're on. The
336 * second case is the standard one for Plug & Play drivers.
337 */
338 if (DeviceExtension->PhysicalDeviceObject == NULL)
339 {
340 LegacyDetection = TRUE;
341 }
342
343 if (LegacyDetection)
344 {
345 ULONG BusNumber, MaxBuses;
346
347 MaxBuses = DeviceExtension->AdapterInterfaceType == PCIBus ? 8 : 1;
348
349 for (BusNumber = 0; BusNumber < MaxBuses; BusNumber++)
350 {
351 DeviceExtension->SystemIoBusNumber =
352 ConfigInfo.SystemIoBusNumber = BusNumber;
353
354 RtlZeroMemory(&DeviceExtension->MiniPortDeviceExtension,
355 DriverExtension->InitializationData.HwDeviceExtensionSize);
356
357 /* FIXME: Need to figure out what string to pass as param 3. */
358 Status = DriverExtension->InitializationData.HwFindAdapter(
359 &DeviceExtension->MiniPortDeviceExtension,
360 DriverExtension->HwContext,
361 NULL,
362 &ConfigInfo,
363 &Again);
364
365 if (Status == ERROR_DEV_NOT_EXIST)
366 {
367 continue;
368 }
369 else if (Status == NO_ERROR)
370 {
371 break;
372 }
373 else
374 {
375 DPRINT("HwFindAdapter call failed with error 0x%X\n", Status);
376 RtlFreeUnicodeString(&DeviceExtension->RegistryPath);
377 IoDeleteDevice(DeviceObject);
378
379 return Status;
380 }
381 }
382 }
383 else
384 {
385 /* FIXME: Need to figure out what string to pass as param 3. */
386 Status = DriverExtension->InitializationData.HwFindAdapter(
387 &DeviceExtension->MiniPortDeviceExtension,
388 DriverExtension->HwContext,
389 NULL,
390 &ConfigInfo,
391 &Again);
392 }
393
394 if (Status != NO_ERROR)
395 {
396 DPRINT("HwFindAdapter call failed with error 0x%X\n", Status);
397 RtlFreeUnicodeString(&DeviceExtension->RegistryPath);
398 IoDeleteDevice(DeviceObject);
399 return Status;
400 }
401
402 /*
403 * Now we know the device is present, so let's do all additional tasks
404 * such as creating symlinks or setting up interrupts and timer.
405 */
406
407 /* Create a unicode device name. */
408 swprintf(DeviceBuffer, L"\\Device\\Video%lu", DeviceNumber);
409 RtlInitUnicodeString(&DeviceName, DeviceBuffer);
410
411 /* Create symbolic link "\??\DISPLAYx" */
412 swprintf(SymlinkBuffer, L"\\??\\DISPLAY%lu", DeviceNumber + 1);
413 RtlInitUnicodeString(&SymlinkName, SymlinkBuffer);
414 IoCreateSymbolicLink(&SymlinkName, &DeviceName);
415
416 /* Add entry to DEVICEMAP\VIDEO key in registry. */
417 swprintf(DeviceVideoBuffer, L"\\Device\\Video%d", DeviceNumber);
418 RtlWriteRegistryValue(
419 RTL_REGISTRY_DEVICEMAP,
420 L"VIDEO",
421 DeviceVideoBuffer,
422 REG_SZ,
423 DeviceExtension->RegistryPath.Buffer,
424 DeviceExtension->RegistryPath.MaximumLength);
425
426 /* FIXME: Allocate hardware resources for device. */
427
428 /*
429 * Allocate interrupt for device.
430 */
431
432 if (!IntVideoPortSetupInterrupt(DeviceObject, DriverExtension, &ConfigInfo))
433 {
434 RtlFreeUnicodeString(&DeviceExtension->RegistryPath);
435 IoDeleteDevice(DeviceObject);
436 return STATUS_INSUFFICIENT_RESOURCES;
437 }
438
439 /*
440 * Allocate timer for device.
441 */
442
443 if (!IntVideoPortSetupTimer(DeviceObject, DriverExtension))
444 {
445 if (DeviceExtension->InterruptObject != NULL)
446 IoDisconnectInterrupt(DeviceExtension->InterruptObject);
447 RtlFreeUnicodeString(&DeviceExtension->RegistryPath);
448 IoDeleteDevice(DeviceObject);
449 DPRINT("STATUS_INSUFFICIENT_RESOURCES\n");
450 return STATUS_INSUFFICIENT_RESOURCES;
451 }
452
453 /*
454 * Query children of the device.
455 */
456 VideoPortEnumerateChildren(&DeviceExtension->MiniPortDeviceExtension, NULL);
457
458 DPRINT("STATUS_SUCCESS\n");
459 return STATUS_SUCCESS;
460 }
461
462 VOID FASTCALL
463 IntAttachToCSRSS(PKPROCESS *CallingProcess, PKAPC_STATE ApcState)
464 {
465 *CallingProcess = (PKPROCESS)PsGetCurrentProcess();
466 if (*CallingProcess != Csrss)
467 {
468 KeStackAttachProcess(Csrss, ApcState);
469 }
470 }
471
472 VOID FASTCALL
473 IntDetachFromCSRSS(PKPROCESS *CallingProcess, PKAPC_STATE ApcState)
474 {
475 if (*CallingProcess != Csrss)
476 {
477 KeUnstackDetachProcess(ApcState);
478 }
479 }
480
481 /* PUBLIC FUNCTIONS ***********************************************************/
482
483 /*
484 * @implemented
485 */
486
487 ULONG NTAPI
488 VideoPortInitialize(
489 IN PVOID Context1,
490 IN PVOID Context2,
491 IN PVIDEO_HW_INITIALIZATION_DATA HwInitializationData,
492 IN PVOID HwContext)
493 {
494 PDRIVER_OBJECT DriverObject = Context1;
495 PUNICODE_STRING RegistryPath = Context2;
496 NTSTATUS Status;
497 PVIDEO_PORT_DRIVER_EXTENSION DriverExtension;
498 BOOL LegacyDetection = FALSE;
499
500 DPRINT("VideoPortInitialize\n");
501
502 /*
503 * As a first thing do parameter checks.
504 */
505
506 if (HwInitializationData->HwInitDataSize > sizeof(VIDEO_HW_INITIALIZATION_DATA))
507 {
508 return STATUS_REVISION_MISMATCH;
509 }
510
511 if (HwInitializationData->HwFindAdapter == NULL ||
512 HwInitializationData->HwInitialize == NULL ||
513 HwInitializationData->HwStartIO == NULL)
514 {
515 return STATUS_INVALID_PARAMETER;
516 }
517
518 /*
519 * NOTE:
520 * The driver extension can be already allocated in case that we were
521 * called by legacy driver and failed detecting device. Some miniport
522 * drivers in that case adjust parameters and call VideoPortInitialize
523 * again.
524 */
525
526 DriverExtension = IoGetDriverObjectExtension(DriverObject, DriverObject);
527 if (DriverExtension == NULL)
528 {
529 Status = IoAllocateDriverObjectExtension(
530 DriverObject,
531 DriverObject,
532 sizeof(VIDEO_PORT_DRIVER_EXTENSION),
533 (PVOID *)&DriverExtension);
534
535 if (!NT_SUCCESS(Status))
536 {
537 return Status;
538 }
539
540 /*
541 * Save the registry path. This should be done only once even if
542 * VideoPortInitialize is called multiple times.
543 */
544
545 if (RegistryPath->Length != 0)
546 {
547 DriverExtension->RegistryPath.Length = 0;
548 DriverExtension->RegistryPath.MaximumLength =
549 RegistryPath->Length + sizeof(UNICODE_NULL);
550 DriverExtension->RegistryPath.Buffer =
551 ExAllocatePoolWithTag(
552 PagedPool,
553 DriverExtension->RegistryPath.MaximumLength,
554 TAG('U', 'S', 'T', 'R'));
555 if (DriverExtension->RegistryPath.Buffer == NULL)
556 {
557 RtlInitUnicodeString(&DriverExtension->RegistryPath, NULL);
558 return STATUS_INSUFFICIENT_RESOURCES;
559 }
560
561 RtlCopyUnicodeString(&DriverExtension->RegistryPath, RegistryPath);
562 }
563 else
564 {
565 RtlInitUnicodeString(&DriverExtension->RegistryPath, NULL);
566 }
567 }
568
569 /*
570 * Copy the correct miniport initializtation data to the device extension.
571 */
572
573 RtlCopyMemory(
574 &DriverExtension->InitializationData,
575 HwInitializationData,
576 HwInitializationData->HwInitDataSize);
577 if (HwInitializationData->HwInitDataSize <
578 sizeof(VIDEO_HW_INITIALIZATION_DATA))
579 {
580 RtlZeroMemory((PVOID)((ULONG_PTR)&DriverExtension->InitializationData +
581 HwInitializationData->HwInitDataSize),
582 sizeof(VIDEO_HW_INITIALIZATION_DATA) -
583 HwInitializationData->HwInitDataSize);
584 }
585 DriverExtension->HwContext = HwContext;
586
587 switch (HwInitializationData->HwInitDataSize)
588 {
589 /*
590 * NT4 drivers are special case, because we must use legacy method
591 * of detection instead of the Plug & Play one.
592 */
593
594 case SIZE_OF_NT4_VIDEO_HW_INITIALIZATION_DATA:
595 DPRINT("We were loaded by a Windows NT miniport driver.\n");
596 LegacyDetection = TRUE;
597 break;
598
599 case SIZE_OF_W2K_VIDEO_HW_INITIALIZATION_DATA:
600 DPRINT("We were loaded by a Windows 2000 miniport driver.\n");
601 break;
602
603 case sizeof(VIDEO_HW_INITIALIZATION_DATA):
604 DPRINT("We were loaded by a Windows XP or later miniport driver.\n");
605 break;
606
607 default:
608 DPRINT("Invalid HwInitializationData size.\n");
609 return STATUS_UNSUCCESSFUL;
610 }
611
612 DriverObject->MajorFunction[IRP_MJ_CREATE] = IntVideoPortDispatchOpen;
613 DriverObject->MajorFunction[IRP_MJ_CLOSE] = IntVideoPortDispatchClose;
614 DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = IntVideoPortDispatchDeviceControl;
615 DriverObject->MajorFunction[IRP_MJ_WRITE] = IntVideoPortDispatchWrite;
616 DriverObject->DriverUnload = IntVideoPortUnload;
617
618 /*
619 * Plug & Play drivers registers the device in AddDevice routine. For
620 * legacy drivers we must do it now.
621 */
622
623 if (LegacyDetection)
624 {
625 PDEVICE_OBJECT DeviceObject;
626 Status = IntVideoPortCreateAdapterDeviceObject(DriverObject, DriverExtension,
627 NULL, &DeviceObject);
628 DPRINT("IntVideoPortCreateAdapterDeviceObject returned 0x%x\n", Status);
629 if (!NT_SUCCESS(Status))
630 return Status;
631 Status = IntVideoPortFindAdapter(DriverObject, DriverExtension, DeviceObject);
632 DPRINT("IntVideoPortFindAdapter returned 0x%x\n", Status);
633 return Status;
634 }
635 else
636 {
637 DriverObject->DriverExtension->AddDevice = IntVideoPortAddDevice;
638 DriverObject->MajorFunction[IRP_MJ_PNP] = IntVideoPortDispatchPnp;
639 DriverObject->MajorFunction[IRP_MJ_POWER] = IntVideoPortDispatchPower;
640
641 return STATUS_SUCCESS;
642 }
643 }
644
645 /*
646 * @implemented
647 */
648
649 VOID
650 VideoPortDebugPrint(
651 IN VIDEO_DEBUG_LEVEL DebugPrintLevel,
652 IN PCHAR DebugMessage, ...)
653 {
654 char Buffer[256];
655 va_list ap;
656
657 va_start(ap, DebugMessage);
658 vsprintf(Buffer, DebugMessage, ap);
659 va_end(ap);
660
661 DbgPrintEx(DPFLTR_IHVVIDEO_ID, DebugPrintLevel, Buffer);
662 }
663
664 /*
665 * @unimplemented
666 */
667
668 VOID NTAPI
669 VideoPortLogError(
670 IN PVOID HwDeviceExtension,
671 IN PVIDEO_REQUEST_PACKET Vrp OPTIONAL,
672 IN VP_STATUS ErrorCode,
673 IN ULONG UniqueId)
674 {
675 DPRINT1("VideoPortLogError ErrorCode %d (0x%x) UniqueId %lu (0x%lx)\n",
676 ErrorCode, ErrorCode, UniqueId, UniqueId);
677 if (NULL != Vrp)
678 {
679 DPRINT1("Vrp->IoControlCode %lu (0x%lx)\n", Vrp->IoControlCode, Vrp->IoControlCode);
680 }
681 }
682
683 /*
684 * @implemented
685 */
686
687 UCHAR NTAPI
688 VideoPortGetCurrentIrql(VOID)
689 {
690 return KeGetCurrentIrql();
691 }
692
693 typedef struct QueryRegistryCallbackContext
694 {
695 PVOID HwDeviceExtension;
696 PVOID HwContext;
697 PMINIPORT_GET_REGISTRY_ROUTINE HwGetRegistryRoutine;
698 } QUERY_REGISTRY_CALLBACK_CONTEXT, *PQUERY_REGISTRY_CALLBACK_CONTEXT;
699
700 static NTSTATUS NTAPI
701 QueryRegistryCallback(
702 IN PWSTR ValueName,
703 IN ULONG ValueType,
704 IN PVOID ValueData,
705 IN ULONG ValueLength,
706 IN PVOID Context,
707 IN PVOID EntryContext)
708 {
709 PQUERY_REGISTRY_CALLBACK_CONTEXT CallbackContext = (PQUERY_REGISTRY_CALLBACK_CONTEXT) Context;
710
711 DPRINT("Found registry value for name %S: type %d, length %d\n",
712 ValueName, ValueType, ValueLength);
713 return (*(CallbackContext->HwGetRegistryRoutine))(
714 CallbackContext->HwDeviceExtension,
715 CallbackContext->HwContext,
716 ValueName,
717 ValueData,
718 ValueLength);
719 }
720
721 /*
722 * @unimplemented
723 */
724
725 VP_STATUS NTAPI
726 VideoPortGetRegistryParameters(
727 IN PVOID HwDeviceExtension,
728 IN PWSTR ParameterName,
729 IN UCHAR IsParameterFileName,
730 IN PMINIPORT_GET_REGISTRY_ROUTINE GetRegistryRoutine,
731 IN PVOID HwContext)
732 {
733 RTL_QUERY_REGISTRY_TABLE QueryTable[2];
734 QUERY_REGISTRY_CALLBACK_CONTEXT Context;
735 PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension;
736
737 DPRINT("VideoPortGetRegistryParameters ParameterName %S\n", ParameterName);
738
739 DeviceExtension = VIDEO_PORT_GET_DEVICE_EXTENSION(HwDeviceExtension);
740
741 if (IsParameterFileName)
742 {
743 UNIMPLEMENTED;
744 }
745
746 Context.HwDeviceExtension = HwDeviceExtension;
747 Context.HwContext = HwContext;
748 Context.HwGetRegistryRoutine = GetRegistryRoutine;
749
750 QueryTable[0].QueryRoutine = QueryRegistryCallback;
751 QueryTable[0].Flags = RTL_QUERY_REGISTRY_REQUIRED;
752 QueryTable[0].Name = ParameterName;
753 QueryTable[0].EntryContext = NULL;
754 QueryTable[0].DefaultType = REG_NONE;
755 QueryTable[0].DefaultData = NULL;
756 QueryTable[0].DefaultLength = 0;
757
758 QueryTable[1].QueryRoutine = NULL;
759 QueryTable[1].Name = NULL;
760
761 return NT_SUCCESS(RtlQueryRegistryValues(
762 RTL_REGISTRY_ABSOLUTE,
763 DeviceExtension->RegistryPath.Buffer,
764 QueryTable,
765 &Context,
766 NULL)) ? ERROR_SUCCESS : ERROR_INVALID_PARAMETER;
767 }
768
769 /*
770 * @implemented
771 */
772
773 VP_STATUS NTAPI
774 VideoPortSetRegistryParameters(
775 IN PVOID HwDeviceExtension,
776 IN PWSTR ValueName,
777 IN PVOID ValueData,
778 IN ULONG ValueLength)
779 {
780 DPRINT("VideoPortSetRegistryParameters\n");
781 ASSERT_IRQL(PASSIVE_LEVEL);
782 return RtlWriteRegistryValue(
783 RTL_REGISTRY_ABSOLUTE,
784 VIDEO_PORT_GET_DEVICE_EXTENSION(HwDeviceExtension)->RegistryPath.Buffer,
785 ValueName,
786 REG_BINARY,
787 ValueData,
788 ValueLength);
789 }
790
791 /*
792 * @implemented
793 */
794
795 VP_STATUS NTAPI
796 VideoPortGetVgaStatus(
797 IN PVOID HwDeviceExtension,
798 OUT PULONG VgaStatus)
799 {
800 PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension;
801
802 DPRINT("VideoPortGetVgaStatus\n");
803
804 DeviceExtension = VIDEO_PORT_GET_DEVICE_EXTENSION(HwDeviceExtension);
805 if (KeGetCurrentIrql() == PASSIVE_LEVEL)
806 {
807 if (DeviceExtension->AdapterInterfaceType == PCIBus)
808 {
809 /* VgaStatus: 0 == VGA not enabled, 1 == VGA enabled. */
810 /* Assumed for now */
811 *VgaStatus = 1;
812 return NO_ERROR;
813 }
814 }
815
816 return ERROR_INVALID_FUNCTION;
817 }
818
819 /*
820 * @implemented
821 */
822
823 PVOID NTAPI
824 VideoPortGetRomImage(
825 IN PVOID HwDeviceExtension,
826 IN PVOID Unused1,
827 IN ULONG Unused2,
828 IN ULONG Length)
829 {
830 static PVOID RomImageBuffer = NULL;
831 PKPROCESS CallingProcess;
832 KAPC_STATE ApcState;
833
834 DPRINT("VideoPortGetRomImage(HwDeviceExtension 0x%X Length 0x%X)\n",
835 HwDeviceExtension, Length);
836
837 /* If the length is zero then free the existing buffer. */
838 if (Length == 0)
839 {
840 if (RomImageBuffer != NULL)
841 {
842 ExFreePool(RomImageBuffer);
843 RomImageBuffer = NULL;
844 }
845 return NULL;
846 }
847 else
848 {
849 /*
850 * The DDK says we shouldn't use the legacy C0000 method but get the
851 * rom base address from the corresponding pci or acpi register but
852 * lets ignore that and use C0000 anyway. We have already mapped the
853 * bios area into memory so we'll copy from there.
854 */
855
856 /* Copy the bios. */
857 Length = min(Length, 0x10000);
858 if (RomImageBuffer != NULL)
859 {
860 ExFreePool(RomImageBuffer);
861 }
862
863 RomImageBuffer = ExAllocatePool(PagedPool, Length);
864 if (RomImageBuffer == NULL)
865 {
866 return NULL;
867 }
868
869 IntAttachToCSRSS(&CallingProcess, &ApcState);
870 RtlCopyMemory(RomImageBuffer, (PUCHAR)0xC0000, Length);
871 IntDetachFromCSRSS(&CallingProcess, &ApcState);
872
873 return RomImageBuffer;
874 }
875 }
876
877 /*
878 * @implemented
879 */
880
881 BOOLEAN NTAPI
882 VideoPortScanRom(
883 IN PVOID HwDeviceExtension,
884 IN PUCHAR RomBase,
885 IN ULONG RomLength,
886 IN PUCHAR String)
887 {
888 ULONG StringLength;
889 BOOLEAN Found;
890 PUCHAR SearchLocation;
891
892 DPRINT("VideoPortScanRom RomBase %p RomLength 0x%x String %s\n", RomBase, RomLength, String);
893
894 StringLength = strlen((PCHAR)String);
895 Found = FALSE;
896 SearchLocation = RomBase;
897 for (SearchLocation = RomBase;
898 !Found && SearchLocation < RomBase + RomLength - StringLength;
899 SearchLocation++)
900 {
901 Found = (RtlCompareMemory(SearchLocation, String, StringLength) == StringLength);
902 if (Found)
903 {
904 DPRINT("Match found at %p\n", SearchLocation);
905 }
906 }
907
908 return Found;
909 }
910
911 /*
912 * @implemented
913 */
914
915 BOOLEAN NTAPI
916 VideoPortSynchronizeExecution(
917 IN PVOID HwDeviceExtension,
918 IN VIDEO_SYNCHRONIZE_PRIORITY Priority,
919 IN PMINIPORT_SYNCHRONIZE_ROUTINE SynchronizeRoutine,
920 OUT PVOID Context)
921 {
922 BOOLEAN Ret;
923 PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension;
924 KIRQL OldIrql;
925
926 switch (Priority)
927 {
928 case VpLowPriority:
929 Ret = (*SynchronizeRoutine)(Context);
930 break;
931
932 case VpMediumPriority:
933 DeviceExtension = VIDEO_PORT_GET_DEVICE_EXTENSION(HwDeviceExtension);
934 if (DeviceExtension->InterruptObject == NULL)
935 Ret = (*SynchronizeRoutine)(Context);
936 else
937 Ret = KeSynchronizeExecution(
938 DeviceExtension->InterruptObject,
939 SynchronizeRoutine,
940 Context);
941 break;
942
943 case VpHighPriority:
944 OldIrql = KeGetCurrentIrql();
945 if (OldIrql < SYNCH_LEVEL)
946 OldIrql = KfRaiseIrql(SYNCH_LEVEL);
947
948 Ret = (*SynchronizeRoutine)(Context);
949
950 if (OldIrql < SYNCH_LEVEL)
951 KfLowerIrql(OldIrql);
952 break;
953
954 default:
955 Ret = FALSE;
956 }
957
958 return Ret;
959 }
960
961 /*
962 * @implemented
963 */
964
965 VP_STATUS NTAPI
966 VideoPortEnumerateChildren(
967 IN PVOID HwDeviceExtension,
968 IN PVOID Reserved)
969 {
970 PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension;
971 ULONG Status;
972 VIDEO_CHILD_ENUM_INFO ChildEnumInfo;
973 VIDEO_CHILD_TYPE ChildType;
974 UCHAR ChildDescriptor[256];
975 ULONG ChildId;
976 ULONG Unused;
977 INT i;
978
979 DeviceExtension = VIDEO_PORT_GET_DEVICE_EXTENSION(HwDeviceExtension);
980 if (DeviceExtension->DriverExtension->InitializationData.HwGetVideoChildDescriptor == NULL)
981 {
982 DPRINT("Miniport's HwGetVideoChildDescriptor is NULL!\n");
983 return NO_ERROR;
984 }
985
986 /* Setup the ChildEnumInfo */
987 ChildEnumInfo.Size = sizeof (ChildEnumInfo);
988 ChildEnumInfo.ChildDescriptorSize = sizeof (ChildDescriptor);
989 ChildEnumInfo.ACPIHwId = 0;
990 ChildEnumInfo.ChildHwDeviceExtension = NULL; /* FIXME: must be set to
991 ChildHwDeviceExtension... */
992
993 /* Enumerate the children */
994 for (i = 1; ; i++)
995 {
996 ChildEnumInfo.ChildIndex = i;
997 RtlZeroMemory(ChildDescriptor, sizeof(ChildDescriptor));
998 Status = DeviceExtension->DriverExtension->InitializationData.HwGetVideoChildDescriptor(
999 HwDeviceExtension,
1000 &ChildEnumInfo,
1001 &ChildType,
1002 ChildDescriptor,
1003 &ChildId,
1004 &Unused);
1005 if (Status == VIDEO_ENUM_INVALID_DEVICE)
1006 {
1007 DPRINT("Child device %d is invalid!\n", ChildEnumInfo.ChildIndex);
1008 continue;
1009 }
1010 else if (Status == VIDEO_ENUM_NO_MORE_DEVICES)
1011 {
1012 DPRINT("End of child enumeration! (%d children enumerated)\n", i - 1);
1013 break;
1014 }
1015 else if (Status != VIDEO_ENUM_MORE_DEVICES)
1016 {
1017 DPRINT("HwGetVideoChildDescriptor returned unknown status code 0x%x!\n", Status);
1018 break;
1019 }
1020
1021 #ifndef NDEBUG
1022 if (ChildType == Monitor)
1023 {
1024 INT j;
1025 PUCHAR p = ChildDescriptor;
1026 DPRINT("Monitor device enumerated! (ChildId = 0x%x)\n", ChildId);
1027 for (j = 0; j < sizeof (ChildDescriptor); j += 8)
1028 {
1029 DPRINT("%02x %02x %02x %02x %02x %02x %02x %02x\n",
1030 p[j+0], p[j+1], p[j+2], p[j+3],
1031 p[j+4], p[j+5], p[j+6], p[j+7]);
1032 }
1033 }
1034 else if (ChildType == Other)
1035 {
1036 DPRINT("\"Other\" device enumerated: DeviceId = %S\n", (PWSTR)ChildDescriptor);
1037 }
1038 else
1039 {
1040 DPRINT("HwGetVideoChildDescriptor returned unsupported type: %d\n", ChildType);
1041 }
1042 #endif /* NDEBUG */
1043
1044 }
1045
1046 return NO_ERROR;
1047 }
1048
1049 /*
1050 * @unimplemented
1051 */
1052
1053 VP_STATUS NTAPI
1054 VideoPortCreateSecondaryDisplay(
1055 IN PVOID HwDeviceExtension,
1056 IN OUT PVOID *SecondaryDeviceExtension,
1057 IN ULONG Flag)
1058 {
1059 DPRINT1("VideoPortCreateSecondaryDisplay: Unimplemented.\n");
1060 return NO_ERROR;
1061 }
1062
1063 /*
1064 * @implemented
1065 */
1066
1067 BOOLEAN NTAPI
1068 VideoPortQueueDpc(
1069 IN PVOID HwDeviceExtension,
1070 IN PMINIPORT_DPC_ROUTINE CallbackRoutine,
1071 IN PVOID Context)
1072 {
1073 return KeInsertQueueDpc(
1074 &VIDEO_PORT_GET_DEVICE_EXTENSION(HwDeviceExtension)->DpcObject,
1075 (PVOID)CallbackRoutine,
1076 (PVOID)Context);
1077 }
1078
1079 /*
1080 * @unimplemented
1081 */
1082
1083 PVOID NTAPI
1084 VideoPortGetAssociatedDeviceExtension(IN PVOID DeviceObject)
1085 {
1086 DPRINT1("VideoPortGetAssociatedDeviceExtension: Unimplemented.\n");
1087 return NULL;
1088 }
1089
1090 /*
1091 * @implemented
1092 */
1093
1094 VP_STATUS NTAPI
1095 VideoPortGetVersion(
1096 IN PVOID HwDeviceExtension,
1097 IN OUT PVPOSVERSIONINFO VpOsVersionInfo)
1098 {
1099 RTL_OSVERSIONINFOEXW Version;
1100
1101 Version.dwOSVersionInfoSize = sizeof(RTL_OSVERSIONINFOEXW);
1102 if (VpOsVersionInfo->Size >= sizeof(VPOSVERSIONINFO))
1103 {
1104 #if 1
1105 if (NT_SUCCESS(RtlGetVersion((PRTL_OSVERSIONINFOW)&Version)))
1106 {
1107 VpOsVersionInfo->MajorVersion = Version.dwMajorVersion;
1108 VpOsVersionInfo->MinorVersion = Version.dwMinorVersion;
1109 VpOsVersionInfo->BuildNumber = Version.dwBuildNumber;
1110 VpOsVersionInfo->ServicePackMajor = Version.wServicePackMajor;
1111 VpOsVersionInfo->ServicePackMinor = Version.wServicePackMinor;
1112 return NO_ERROR;
1113 }
1114 return ERROR_INVALID_PARAMETER;
1115 #else
1116 VpOsVersionInfo->MajorVersion = 5;
1117 VpOsVersionInfo->MinorVersion = 0;
1118 VpOsVersionInfo->BuildNumber = 2195;
1119 VpOsVersionInfo->ServicePackMajor = 4;
1120 VpOsVersionInfo->ServicePackMinor = 0;
1121 return NO_ERROR;
1122 #endif
1123 }
1124
1125 return ERROR_INVALID_PARAMETER;
1126 }
1127
1128 /*
1129 * @unimplemented
1130 */
1131
1132 BOOLEAN NTAPI
1133 VideoPortCheckForDeviceExistence(
1134 IN PVOID HwDeviceExtension,
1135 IN USHORT VendorId,
1136 IN USHORT DeviceId,
1137 IN UCHAR RevisionId,
1138 IN USHORT SubVendorId,
1139 IN USHORT SubSystemId,
1140 IN ULONG Flags)
1141 {
1142 DPRINT1("VideoPortCheckForDeviceExistence: Unimplemented.\n");
1143 return TRUE;
1144 }
1145
1146 /*
1147 * @unimplemented
1148 */
1149
1150 VP_STATUS NTAPI
1151 VideoPortRegisterBugcheckCallback(
1152 IN PVOID HwDeviceExtension,
1153 IN ULONG BugcheckCode,
1154 IN PVOID Callback,
1155 IN ULONG BugcheckDataSize)
1156 {
1157 DPRINT1("VideoPortRegisterBugcheckCallback(): Unimplemented.\n");
1158 return NO_ERROR;
1159 }
1160
1161 /*
1162 * @implemented
1163 */
1164
1165 LONGLONG NTAPI
1166 VideoPortQueryPerformanceCounter(
1167 IN PVOID HwDeviceExtension,
1168 OUT PLONGLONG PerformanceFrequency OPTIONAL)
1169 {
1170 LARGE_INTEGER Result;
1171
1172 DPRINT("VideoPortQueryPerformanceCounter\n");
1173 Result = KeQueryPerformanceCounter((PLARGE_INTEGER)PerformanceFrequency);
1174 return Result.QuadPart;
1175 }
1176
1177 /*
1178 * @implemented
1179 */
1180
1181 VOID NTAPI
1182 VideoPortAcquireDeviceLock(
1183 IN PVOID HwDeviceExtension)
1184 {
1185 PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension;
1186 NTSTATUS Status;
1187 (void)Status;
1188
1189 DPRINT("VideoPortAcquireDeviceLock\n");
1190 DeviceExtension = VIDEO_PORT_GET_DEVICE_EXTENSION(HwDeviceExtension);
1191 Status = KeWaitForMutexObject(&DeviceExtension->DeviceLock, Executive,
1192 KernelMode, FALSE, NULL);
1193 ASSERT(Status == STATUS_SUCCESS);
1194 }
1195
1196 /*
1197 * @implemented
1198 */
1199
1200 VOID NTAPI
1201 VideoPortReleaseDeviceLock(
1202 IN PVOID HwDeviceExtension)
1203 {
1204 PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension;
1205 LONG Status;
1206 (void)Status;
1207
1208 DPRINT("VideoPortReleaseDeviceLock\n");
1209 DeviceExtension = VIDEO_PORT_GET_DEVICE_EXTENSION(HwDeviceExtension);
1210 Status = KeReleaseMutex(&DeviceExtension->DeviceLock, FALSE);
1211 ASSERT(Status == 0);
1212 }
1213
1214 /*
1215 * @unimplemented
1216 */
1217
1218 VOID NTAPI
1219 VpNotifyEaData(
1220 IN PDEVICE_OBJECT DeviceObject,
1221 IN PVOID Data)
1222 {
1223 }