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