Inform HAL about the switch to graphics mode as late as possible. Fixes bug 880.
[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->MajorFunction[IRP_MJ_WRITE] = IntVideoPortDispatchWrite;
650 DriverObject->DriverUnload = IntVideoPortUnload;
651
652 /*
653 * Plug & Play drivers registers the device in AddDevice routine. For
654 * legacy drivers we must do it now.
655 */
656
657 if (LegacyDetection)
658 {
659 PDEVICE_OBJECT DeviceObject;
660 Status = IntVideoPortCreateAdapterDeviceObject(DriverObject, DriverExtension,
661 NULL, &DeviceObject);
662 DPRINT("IntVideoPortCreateAdapterDeviceObject returned 0x%x\n", Status);
663 if (!NT_SUCCESS(Status))
664 return Status;
665 Status = IntVideoPortFindAdapter(DriverObject, DriverExtension, DeviceObject);
666 DPRINT("IntVideoPortFindAdapter returned 0x%x\n", Status);
667 return Status;
668 }
669 else
670 {
671 DriverObject->DriverExtension->AddDevice = IntVideoPortAddDevice;
672 DriverObject->MajorFunction[IRP_MJ_PNP] = IntVideoPortDispatchPnp;
673 DriverObject->MajorFunction[IRP_MJ_POWER] = IntVideoPortDispatchPower;
674
675 return STATUS_SUCCESS;
676 }
677 }
678
679 /*
680 * @implemented
681 */
682
683 VOID
684 VideoPortDebugPrint(
685 IN VIDEO_DEBUG_LEVEL DebugPrintLevel,
686 IN PCHAR DebugMessage, ...)
687 {
688 char Buffer[256];
689 va_list ap;
690
691 va_start(ap, DebugMessage);
692 vsprintf(Buffer, DebugMessage, ap);
693 va_end(ap);
694
695 DbgPrint(Buffer);
696 }
697
698 /*
699 * @unimplemented
700 */
701
702 VOID NTAPI
703 VideoPortLogError(
704 IN PVOID HwDeviceExtension,
705 IN PVIDEO_REQUEST_PACKET Vrp OPTIONAL,
706 IN VP_STATUS ErrorCode,
707 IN ULONG UniqueId)
708 {
709 DPRINT1("VideoPortLogError ErrorCode %d (0x%x) UniqueId %lu (0x%lx)\n",
710 ErrorCode, ErrorCode, UniqueId, UniqueId);
711 if (NULL != Vrp)
712 {
713 DPRINT1("Vrp->IoControlCode %lu (0x%lx)\n", Vrp->IoControlCode, Vrp->IoControlCode);
714 }
715 }
716
717 /*
718 * @implemented
719 */
720
721 UCHAR NTAPI
722 VideoPortGetCurrentIrql(VOID)
723 {
724 return KeGetCurrentIrql();
725 }
726
727 typedef struct QueryRegistryCallbackContext
728 {
729 PVOID HwDeviceExtension;
730 PVOID HwContext;
731 PMINIPORT_GET_REGISTRY_ROUTINE HwGetRegistryRoutine;
732 } QUERY_REGISTRY_CALLBACK_CONTEXT, *PQUERY_REGISTRY_CALLBACK_CONTEXT;
733
734 static NTSTATUS NTAPI
735 QueryRegistryCallback(
736 IN PWSTR ValueName,
737 IN ULONG ValueType,
738 IN PVOID ValueData,
739 IN ULONG ValueLength,
740 IN PVOID Context,
741 IN PVOID EntryContext)
742 {
743 PQUERY_REGISTRY_CALLBACK_CONTEXT CallbackContext = (PQUERY_REGISTRY_CALLBACK_CONTEXT) Context;
744
745 DPRINT("Found registry value for name %S: type %d, length %d\n",
746 ValueName, ValueType, ValueLength);
747 return (*(CallbackContext->HwGetRegistryRoutine))(
748 CallbackContext->HwDeviceExtension,
749 CallbackContext->HwContext,
750 ValueName,
751 ValueData,
752 ValueLength);
753 }
754
755 /*
756 * @unimplemented
757 */
758
759 VP_STATUS NTAPI
760 VideoPortGetRegistryParameters(
761 IN PVOID HwDeviceExtension,
762 IN PWSTR ParameterName,
763 IN UCHAR IsParameterFileName,
764 IN PMINIPORT_GET_REGISTRY_ROUTINE GetRegistryRoutine,
765 IN PVOID HwContext)
766 {
767 RTL_QUERY_REGISTRY_TABLE QueryTable[2];
768 QUERY_REGISTRY_CALLBACK_CONTEXT Context;
769 PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension;
770
771 DPRINT("VideoPortGetRegistryParameters ParameterName %S\n", ParameterName);
772
773 DeviceExtension = VIDEO_PORT_GET_DEVICE_EXTENSION(HwDeviceExtension);
774
775 if (IsParameterFileName)
776 {
777 UNIMPLEMENTED;
778 }
779
780 Context.HwDeviceExtension = HwDeviceExtension;
781 Context.HwContext = HwContext;
782 Context.HwGetRegistryRoutine = GetRegistryRoutine;
783
784 QueryTable[0].QueryRoutine = QueryRegistryCallback;
785 QueryTable[0].Flags = RTL_QUERY_REGISTRY_REQUIRED;
786 QueryTable[0].Name = ParameterName;
787 QueryTable[0].EntryContext = NULL;
788 QueryTable[0].DefaultType = REG_NONE;
789 QueryTable[0].DefaultData = NULL;
790 QueryTable[0].DefaultLength = 0;
791
792 QueryTable[1].QueryRoutine = NULL;
793 QueryTable[1].Name = NULL;
794
795 return NT_SUCCESS(RtlQueryRegistryValues(
796 RTL_REGISTRY_ABSOLUTE,
797 DeviceExtension->RegistryPath.Buffer,
798 QueryTable,
799 &Context,
800 NULL)) ? ERROR_SUCCESS : ERROR_INVALID_PARAMETER;
801 }
802
803 /*
804 * @implemented
805 */
806
807 VP_STATUS NTAPI
808 VideoPortSetRegistryParameters(
809 IN PVOID HwDeviceExtension,
810 IN PWSTR ValueName,
811 IN PVOID ValueData,
812 IN ULONG ValueLength)
813 {
814 DPRINT("VideoPortSetRegistryParameters\n");
815 ASSERT_IRQL(PASSIVE_LEVEL);
816 return RtlWriteRegistryValue(
817 RTL_REGISTRY_ABSOLUTE,
818 VIDEO_PORT_GET_DEVICE_EXTENSION(HwDeviceExtension)->RegistryPath.Buffer,
819 ValueName,
820 REG_BINARY,
821 ValueData,
822 ValueLength);
823 }
824
825 /*
826 * @implemented
827 */
828
829 VP_STATUS NTAPI
830 VideoPortGetVgaStatus(
831 IN PVOID HwDeviceExtension,
832 OUT PULONG VgaStatus)
833 {
834 PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension;
835
836 DPRINT("VideoPortGetVgaStatus\n");
837
838 DeviceExtension = VIDEO_PORT_GET_DEVICE_EXTENSION(HwDeviceExtension);
839 if (KeGetCurrentIrql() == PASSIVE_LEVEL)
840 {
841 if (DeviceExtension->AdapterInterfaceType == PCIBus)
842 {
843 /* VgaStatus: 0 == VGA not enabled, 1 == VGA enabled. */
844 /* Assumed for now */
845 *VgaStatus = 1;
846 return NO_ERROR;
847 }
848 }
849
850 return ERROR_INVALID_FUNCTION;
851 }
852
853 /*
854 * @implemented
855 */
856
857 PVOID NTAPI
858 VideoPortGetRomImage(
859 IN PVOID HwDeviceExtension,
860 IN PVOID Unused1,
861 IN ULONG Unused2,
862 IN ULONG Length)
863 {
864 static PVOID RomImageBuffer = NULL;
865 PKPROCESS CallingProcess;
866 KAPC_STATE ApcState;
867
868 DPRINT("VideoPortGetRomImage(HwDeviceExtension 0x%X Length 0x%X)\n",
869 HwDeviceExtension, Length);
870
871 /* If the length is zero then free the existing buffer. */
872 if (Length == 0)
873 {
874 if (RomImageBuffer != NULL)
875 {
876 ExFreePool(RomImageBuffer);
877 RomImageBuffer = NULL;
878 }
879 return NULL;
880 }
881 else
882 {
883 /*
884 * The DDK says we shouldn't use the legacy C0000 method but get the
885 * rom base address from the corresponding pci or acpi register but
886 * lets ignore that and use C0000 anyway. We have already mapped the
887 * bios area into memory so we'll copy from there.
888 */
889
890 /* Copy the bios. */
891 Length = min(Length, 0x10000);
892 if (RomImageBuffer != NULL)
893 {
894 ExFreePool(RomImageBuffer);
895 }
896
897 RomImageBuffer = ExAllocatePool(PagedPool, Length);
898 if (RomImageBuffer == NULL)
899 {
900 return NULL;
901 }
902
903 IntAttachToCSRSS(&CallingProcess, &ApcState);
904 RtlCopyMemory(RomImageBuffer, (PUCHAR)0xC0000, Length);
905 IntDetachFromCSRSS(&CallingProcess, &ApcState);
906
907 return RomImageBuffer;
908 }
909 }
910
911 /*
912 * @implemented
913 */
914
915 BOOLEAN NTAPI
916 VideoPortScanRom(
917 IN PVOID HwDeviceExtension,
918 IN PUCHAR RomBase,
919 IN ULONG RomLength,
920 IN PUCHAR String)
921 {
922 ULONG StringLength;
923 BOOLEAN Found;
924 PUCHAR SearchLocation;
925
926 DPRINT("VideoPortScanRom RomBase %p RomLength 0x%x String %s\n", RomBase, RomLength, String);
927
928 StringLength = strlen((PCHAR)String);
929 Found = FALSE;
930 SearchLocation = RomBase;
931 for (SearchLocation = RomBase;
932 !Found && SearchLocation < RomBase + RomLength - StringLength;
933 SearchLocation++)
934 {
935 Found = (RtlCompareMemory(SearchLocation, String, StringLength) == StringLength);
936 if (Found)
937 {
938 DPRINT("Match found at %p\n", SearchLocation);
939 }
940 }
941
942 return Found;
943 }
944
945 /*
946 * @implemented
947 */
948
949 BOOLEAN NTAPI
950 VideoPortSynchronizeExecution(
951 IN PVOID HwDeviceExtension,
952 IN VIDEO_SYNCHRONIZE_PRIORITY Priority,
953 IN PMINIPORT_SYNCHRONIZE_ROUTINE SynchronizeRoutine,
954 OUT PVOID Context)
955 {
956 BOOLEAN Ret;
957 PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension;
958 KIRQL OldIrql;
959
960 switch (Priority)
961 {
962 case VpLowPriority:
963 Ret = (*SynchronizeRoutine)(Context);
964 break;
965
966 case VpMediumPriority:
967 DeviceExtension = VIDEO_PORT_GET_DEVICE_EXTENSION(HwDeviceExtension);
968 if (DeviceExtension->InterruptObject == NULL)
969 Ret = (*SynchronizeRoutine)(Context);
970 else
971 Ret = KeSynchronizeExecution(
972 DeviceExtension->InterruptObject,
973 SynchronizeRoutine,
974 Context);
975 break;
976
977 case VpHighPriority:
978 OldIrql = KeGetCurrentIrql();
979 if (OldIrql < SYNCH_LEVEL)
980 OldIrql = KfRaiseIrql(SYNCH_LEVEL);
981
982 Ret = (*SynchronizeRoutine)(Context);
983
984 if (OldIrql < SYNCH_LEVEL)
985 KfLowerIrql(OldIrql);
986 break;
987
988 default:
989 Ret = FALSE;
990 }
991
992 return Ret;
993 }
994
995 /*
996 * @implemented
997 */
998
999 VP_STATUS NTAPI
1000 VideoPortEnumerateChildren(
1001 IN PVOID HwDeviceExtension,
1002 IN PVOID Reserved)
1003 {
1004 PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension;
1005 ULONG Status;
1006 VIDEO_CHILD_ENUM_INFO ChildEnumInfo;
1007 VIDEO_CHILD_TYPE ChildType;
1008 UCHAR ChildDescriptor[256];
1009 ULONG ChildId;
1010 ULONG Unused;
1011 INT i;
1012
1013 DeviceExtension = VIDEO_PORT_GET_DEVICE_EXTENSION(HwDeviceExtension);
1014 if (DeviceExtension->DriverExtension->InitializationData.HwGetVideoChildDescriptor == NULL)
1015 {
1016 DPRINT("Miniport's HwGetVideoChildDescriptor is NULL!\n");
1017 return NO_ERROR;
1018 }
1019
1020 /* Setup the ChildEnumInfo */
1021 ChildEnumInfo.Size = sizeof (ChildEnumInfo);
1022 ChildEnumInfo.ChildDescriptorSize = sizeof (ChildDescriptor);
1023 ChildEnumInfo.ACPIHwId = 0;
1024 ChildEnumInfo.ChildHwDeviceExtension = NULL; /* FIXME: must be set to
1025 ChildHwDeviceExtension... */
1026
1027 /* Enumerate the children */
1028 for (i = 1; ; i++)
1029 {
1030 ChildEnumInfo.ChildIndex = i;
1031 RtlZeroMemory(ChildDescriptor, sizeof(ChildDescriptor));
1032 Status = DeviceExtension->DriverExtension->InitializationData.HwGetVideoChildDescriptor(
1033 HwDeviceExtension,
1034 &ChildEnumInfo,
1035 &ChildType,
1036 ChildDescriptor,
1037 &ChildId,
1038 &Unused);
1039 if (Status == VIDEO_ENUM_INVALID_DEVICE)
1040 {
1041 DPRINT("Child device %d is invalid!\n", ChildEnumInfo.ChildIndex);
1042 continue;
1043 }
1044 else if (Status == VIDEO_ENUM_NO_MORE_DEVICES)
1045 {
1046 DPRINT("End of child enumeration! (%d children enumerated)\n", i - 1);
1047 break;
1048 }
1049 else if (Status != VIDEO_ENUM_MORE_DEVICES)
1050 {
1051 DPRINT("HwGetVideoChildDescriptor returned unknown status code 0x%x!\n", Status);
1052 break;
1053 }
1054
1055 #ifndef NDEBUG
1056 if (ChildType == Monitor)
1057 {
1058 INT j;
1059 PUCHAR p = ChildDescriptor;
1060 DPRINT("Monitor device enumerated! (ChildId = 0x%x)\n", ChildId);
1061 for (j = 0; j < sizeof (ChildDescriptor); j += 8)
1062 {
1063 DPRINT("%02x %02x %02x %02x %02x %02x %02x %02x\n",
1064 p[j+0], p[j+1], p[j+2], p[j+3],
1065 p[j+4], p[j+5], p[j+6], p[j+7]);
1066 }
1067 }
1068 else if (ChildType == Other)
1069 {
1070 DPRINT("\"Other\" device enumerated: DeviceId = %S\n", (PWSTR)ChildDescriptor);
1071 }
1072 else
1073 {
1074 DPRINT("HwGetVideoChildDescriptor returned unsupported type: %d\n", ChildType);
1075 }
1076 #endif /* NDEBUG */
1077
1078 }
1079
1080 return NO_ERROR;
1081 }
1082
1083 /*
1084 * @unimplemented
1085 */
1086
1087 VP_STATUS NTAPI
1088 VideoPortCreateSecondaryDisplay(
1089 IN PVOID HwDeviceExtension,
1090 IN OUT PVOID *SecondaryDeviceExtension,
1091 IN ULONG Flag)
1092 {
1093 DPRINT1("VideoPortCreateSecondaryDisplay: Unimplemented.\n");
1094 return NO_ERROR;
1095 }
1096
1097 /*
1098 * @implemented
1099 */
1100
1101 BOOLEAN NTAPI
1102 VideoPortQueueDpc(
1103 IN PVOID HwDeviceExtension,
1104 IN PMINIPORT_DPC_ROUTINE CallbackRoutine,
1105 IN PVOID Context)
1106 {
1107 return KeInsertQueueDpc(
1108 &VIDEO_PORT_GET_DEVICE_EXTENSION(HwDeviceExtension)->DpcObject,
1109 (PVOID)CallbackRoutine,
1110 (PVOID)Context);
1111 }
1112
1113 /*
1114 * @unimplemented
1115 */
1116
1117 PVOID NTAPI
1118 VideoPortGetAssociatedDeviceExtension(IN PVOID DeviceObject)
1119 {
1120 DPRINT1("VideoPortGetAssociatedDeviceExtension: Unimplemented.\n");
1121 return NULL;
1122 }
1123
1124 /*
1125 * @implemented
1126 */
1127
1128 VP_STATUS NTAPI
1129 VideoPortGetVersion(
1130 IN PVOID HwDeviceExtension,
1131 IN OUT PVPOSVERSIONINFO VpOsVersionInfo)
1132 {
1133 RTL_OSVERSIONINFOEXW Version;
1134
1135 Version.dwOSVersionInfoSize = sizeof(RTL_OSVERSIONINFOEXW);
1136 if (VpOsVersionInfo->Size >= sizeof(VPOSVERSIONINFO))
1137 {
1138 #if 1
1139 if (NT_SUCCESS(RtlGetVersion((PRTL_OSVERSIONINFOW)&Version)))
1140 {
1141 VpOsVersionInfo->MajorVersion = Version.dwMajorVersion;
1142 VpOsVersionInfo->MinorVersion = Version.dwMinorVersion;
1143 VpOsVersionInfo->BuildNumber = Version.dwBuildNumber;
1144 VpOsVersionInfo->ServicePackMajor = Version.wServicePackMajor;
1145 VpOsVersionInfo->ServicePackMinor = Version.wServicePackMinor;
1146 return NO_ERROR;
1147 }
1148 return ERROR_INVALID_PARAMETER;
1149 #else
1150 VpOsVersionInfo->MajorVersion = 5;
1151 VpOsVersionInfo->MinorVersion = 0;
1152 VpOsVersionInfo->BuildNumber = 2195;
1153 VpOsVersionInfo->ServicePackMajor = 4;
1154 VpOsVersionInfo->ServicePackMinor = 0;
1155 return NO_ERROR;
1156 #endif
1157 }
1158
1159 return ERROR_INVALID_PARAMETER;
1160 }
1161
1162 /*
1163 * @unimplemented
1164 */
1165
1166 BOOLEAN NTAPI
1167 VideoPortCheckForDeviceExistence(
1168 IN PVOID HwDeviceExtension,
1169 IN USHORT VendorId,
1170 IN USHORT DeviceId,
1171 IN UCHAR RevisionId,
1172 IN USHORT SubVendorId,
1173 IN USHORT SubSystemId,
1174 IN ULONG Flags)
1175 {
1176 DPRINT1("VideoPortCheckForDeviceExistence: Unimplemented.\n");
1177 return TRUE;
1178 }
1179
1180 /*
1181 * @unimplemented
1182 */
1183
1184 VP_STATUS NTAPI
1185 VideoPortRegisterBugcheckCallback(
1186 IN PVOID HwDeviceExtension,
1187 IN ULONG BugcheckCode,
1188 IN PVOID Callback,
1189 IN ULONG BugcheckDataSize)
1190 {
1191 DPRINT1("VideoPortRegisterBugcheckCallback(): Unimplemented.\n");
1192 return NO_ERROR;
1193 }
1194
1195 /*
1196 * @implemented
1197 */
1198
1199 LONGLONG NTAPI
1200 VideoPortQueryPerformanceCounter(
1201 IN PVOID HwDeviceExtension,
1202 OUT PLONGLONG PerformanceFrequency OPTIONAL)
1203 {
1204 LARGE_INTEGER Result;
1205
1206 DPRINT("VideoPortQueryPerformanceCounter\n");
1207 Result = KeQueryPerformanceCounter((PLARGE_INTEGER)PerformanceFrequency);
1208 return Result.QuadPart;
1209 }
1210
1211 /*
1212 * @implemented
1213 */
1214
1215 VOID NTAPI
1216 VideoPortAcquireDeviceLock(
1217 IN PVOID HwDeviceExtension)
1218 {
1219 PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension;
1220 NTSTATUS Status;
1221 (void)Status;
1222
1223 DPRINT("VideoPortAcquireDeviceLock\n");
1224 DeviceExtension = VIDEO_PORT_GET_DEVICE_EXTENSION(HwDeviceExtension);
1225 Status = KeWaitForMutexObject(&DeviceExtension->DeviceLock, Executive,
1226 KernelMode, FALSE, NULL);
1227 ASSERT(Status == STATUS_SUCCESS);
1228 }
1229
1230 /*
1231 * @implemented
1232 */
1233
1234 VOID NTAPI
1235 VideoPortReleaseDeviceLock(
1236 IN PVOID HwDeviceExtension)
1237 {
1238 PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension;
1239 LONG Status;
1240 (void)Status;
1241
1242 DPRINT("VideoPortReleaseDeviceLock\n");
1243 DeviceExtension = VIDEO_PORT_GET_DEVICE_EXTENSION(HwDeviceExtension);
1244 Status = KeReleaseMutex(&DeviceExtension->DeviceLock, FALSE);
1245 ASSERT(Status == 0);
1246 }
1247
1248 /*
1249 * @unimplemented
1250 */
1251
1252 VOID NTAPI
1253 VpNotifyEaData(
1254 IN PDEVICE_OBJECT DeviceObject,
1255 IN PVOID Data)
1256 {
1257 }