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