7b0e93b0a95537c6a1265388c1954af190119972
[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 STDCALL
34 DriverEntry(
35 IN PDRIVER_OBJECT DriverObject,
36 IN PUNICODE_STRING RegistryPath)
37 {
38 return STATUS_SUCCESS;
39 }
40
41 PVOID STDCALL
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 STDCALL
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 STDCALL
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 STDCALL
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 STDCALL
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 STDCALL
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 STDCALL
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 * NOTE:
538 * The driver extension can be already allocated in case that we were
539 * called by legacy driver and failed detecting device. Some miniport
540 * drivers in that case adjust parameters and calls VideoPortInitialize
541 * again.
542 */
543
544 DriverExtension = IoGetDriverObjectExtension(DriverObject, DriverObject);
545 if (DriverExtension == NULL)
546 {
547 Status = IoAllocateDriverObjectExtension(
548 DriverObject,
549 DriverObject,
550 sizeof(VIDEO_PORT_DRIVER_EXTENSION),
551 (PVOID *)&DriverExtension);
552
553 if (!NT_SUCCESS(Status))
554 {
555 return Status;
556 }
557 }
558
559 /*
560 * Copy the correct miniport initializtation data to the device extension.
561 */
562
563 RtlCopyMemory(
564 &DriverExtension->InitializationData,
565 HwInitializationData,
566 min(sizeof(VIDEO_HW_INITIALIZATION_DATA),
567 HwInitializationData->HwInitDataSize));
568 if (sizeof(VIDEO_HW_INITIALIZATION_DATA) > HwInitializationData->HwInitDataSize)
569 {
570 RtlZeroMemory((PVOID)((ULONG_PTR)&DriverExtension->InitializationData +
571 HwInitializationData->HwInitDataSize),
572 sizeof(VIDEO_HW_INITIALIZATION_DATA) -
573 HwInitializationData->HwInitDataSize);
574 }
575 DriverExtension->HwContext = HwContext;
576
577 /* we can't use RtlDuplicateUnicodeString because only ntdll exposes it... */
578 if (RegistryPath->Length != 0)
579 {
580 DriverExtension->RegistryPath.Length = 0;
581 DriverExtension->RegistryPath.MaximumLength = RegistryPath->Length + sizeof(UNICODE_NULL);
582 DriverExtension->RegistryPath.Buffer = ExAllocatePoolWithTag(PagedPool,
583 DriverExtension->RegistryPath.MaximumLength,
584 TAG('U', 'S', 'T', 'R'));
585 if (DriverExtension->RegistryPath.Buffer == NULL)
586 {
587 RtlInitUnicodeString(&DriverExtension->RegistryPath, NULL);
588 return STATUS_INSUFFICIENT_RESOURCES;
589 }
590
591 RtlCopyUnicodeString(&DriverExtension->RegistryPath, RegistryPath);
592 }
593 else
594 {
595 RtlInitUnicodeString(&DriverExtension->RegistryPath, NULL);
596 }
597
598 switch (HwInitializationData->HwInitDataSize)
599 {
600 /*
601 * NT4 drivers are special case, because we must use legacy method
602 * of detection instead of the Plug & Play one.
603 */
604
605 case SIZE_OF_NT4_VIDEO_HW_INITIALIZATION_DATA:
606 DPRINT("We were loaded by a Windows NT miniport driver.\n");
607 LegacyDetection = TRUE;
608 break;
609
610 case SIZE_OF_W2K_VIDEO_HW_INITIALIZATION_DATA:
611 DPRINT("We were loaded by a Windows 2000 miniport driver.\n");
612 break;
613
614 case sizeof(VIDEO_HW_INITIALIZATION_DATA):
615 DPRINT("We were loaded by a Windows XP or later miniport driver.\n");
616 break;
617
618 default:
619 DPRINT("Invalid HwInitializationData size.\n");
620 return STATUS_UNSUCCESSFUL;
621 }
622
623 DriverObject->MajorFunction[IRP_MJ_CREATE] = IntVideoPortDispatchOpen;
624 DriverObject->MajorFunction[IRP_MJ_CLOSE] = IntVideoPortDispatchClose;
625 DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = IntVideoPortDispatchDeviceControl;
626 DriverObject->DriverUnload = IntVideoPortUnload;
627
628 /*
629 * Plug & Play drivers registers the device in AddDevice routine. For
630 * legacy drivers we must do it now.
631 */
632
633 if (LegacyDetection)
634 {
635 PDEVICE_OBJECT DeviceObject;
636 Status = IntVideoPortCreateAdapterDeviceObject(DriverObject, DriverExtension,
637 NULL, &DeviceObject);
638 DPRINT("IntVideoPortCreateAdapterDeviceObject returned 0x%x\n", Status);
639 if (!NT_SUCCESS(Status))
640 return Status;
641 Status = IntVideoPortFindAdapter(DriverObject, DriverExtension, DeviceObject);
642 DPRINT("IntVideoPortFindAdapter returned 0x%x\n", Status);
643 return Status;
644 }
645 else
646 {
647 DriverObject->DriverExtension->AddDevice = IntVideoPortAddDevice;
648 DriverObject->MajorFunction[IRP_MJ_PNP] = IntVideoPortDispatchPnp;
649 DriverObject->MajorFunction[IRP_MJ_POWER] = IntVideoPortDispatchPower;
650
651 return STATUS_SUCCESS;
652 }
653 }
654
655 /*
656 * @implemented
657 */
658
659 VOID
660 VideoPortDebugPrint(
661 IN VIDEO_DEBUG_LEVEL DebugPrintLevel,
662 IN PCHAR DebugMessage, ...)
663 {
664 char Buffer[256];
665 va_list ap;
666
667 va_start(ap, DebugMessage);
668 vsprintf(Buffer, DebugMessage, ap);
669 va_end(ap);
670
671 DbgPrint(Buffer);
672 }
673
674 /*
675 * @unimplemented
676 */
677
678 VOID STDCALL
679 VideoPortLogError(
680 IN PVOID HwDeviceExtension,
681 IN PVIDEO_REQUEST_PACKET Vrp OPTIONAL,
682 IN VP_STATUS ErrorCode,
683 IN ULONG UniqueId)
684 {
685 DPRINT1("VideoPortLogError ErrorCode %d (0x%x) UniqueId %lu (0x%lx)\n",
686 ErrorCode, ErrorCode, UniqueId, UniqueId);
687 if (NULL != Vrp)
688 {
689 DPRINT1("Vrp->IoControlCode %lu (0x%lx)\n", Vrp->IoControlCode, Vrp->IoControlCode);
690 }
691 }
692
693 /*
694 * @implemented
695 */
696
697 UCHAR STDCALL
698 VideoPortGetCurrentIrql(VOID)
699 {
700 return KeGetCurrentIrql();
701 }
702
703 typedef struct QueryRegistryCallbackContext
704 {
705 PVOID HwDeviceExtension;
706 PVOID HwContext;
707 PMINIPORT_GET_REGISTRY_ROUTINE HwGetRegistryRoutine;
708 } QUERY_REGISTRY_CALLBACK_CONTEXT, *PQUERY_REGISTRY_CALLBACK_CONTEXT;
709
710 static NTSTATUS STDCALL
711 QueryRegistryCallback(
712 IN PWSTR ValueName,
713 IN ULONG ValueType,
714 IN PVOID ValueData,
715 IN ULONG ValueLength,
716 IN PVOID Context,
717 IN PVOID EntryContext)
718 {
719 PQUERY_REGISTRY_CALLBACK_CONTEXT CallbackContext = (PQUERY_REGISTRY_CALLBACK_CONTEXT) Context;
720
721 DPRINT("Found registry value for name %S: type %d, length %d\n",
722 ValueName, ValueType, ValueLength);
723 return (*(CallbackContext->HwGetRegistryRoutine))(
724 CallbackContext->HwDeviceExtension,
725 CallbackContext->HwContext,
726 ValueName,
727 ValueData,
728 ValueLength);
729 }
730
731 /*
732 * @unimplemented
733 */
734
735 VP_STATUS STDCALL
736 VideoPortGetRegistryParameters(
737 IN PVOID HwDeviceExtension,
738 IN PWSTR ParameterName,
739 IN UCHAR IsParameterFileName,
740 IN PMINIPORT_GET_REGISTRY_ROUTINE GetRegistryRoutine,
741 IN PVOID HwContext)
742 {
743 RTL_QUERY_REGISTRY_TABLE QueryTable[2];
744 QUERY_REGISTRY_CALLBACK_CONTEXT Context;
745 PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension;
746
747 DPRINT("VideoPortGetRegistryParameters ParameterName %S\n", ParameterName);
748
749 DeviceExtension = VIDEO_PORT_GET_DEVICE_EXTENSION(HwDeviceExtension);
750
751 if (IsParameterFileName)
752 {
753 UNIMPLEMENTED;
754 }
755
756 Context.HwDeviceExtension = HwDeviceExtension;
757 Context.HwContext = HwContext;
758 Context.HwGetRegistryRoutine = GetRegistryRoutine;
759
760 QueryTable[0].QueryRoutine = QueryRegistryCallback;
761 QueryTable[0].Flags = RTL_QUERY_REGISTRY_REQUIRED;
762 QueryTable[0].Name = ParameterName;
763 QueryTable[0].EntryContext = NULL;
764 QueryTable[0].DefaultType = REG_NONE;
765 QueryTable[0].DefaultData = NULL;
766 QueryTable[0].DefaultLength = 0;
767
768 QueryTable[1].QueryRoutine = NULL;
769 QueryTable[1].Name = NULL;
770
771 return NT_SUCCESS(RtlQueryRegistryValues(
772 RTL_REGISTRY_ABSOLUTE,
773 DeviceExtension->RegistryPath.Buffer,
774 QueryTable,
775 &Context,
776 NULL)) ? ERROR_SUCCESS : ERROR_INVALID_PARAMETER;
777 }
778
779 /*
780 * @implemented
781 */
782
783 VP_STATUS STDCALL
784 VideoPortSetRegistryParameters(
785 IN PVOID HwDeviceExtension,
786 IN PWSTR ValueName,
787 IN PVOID ValueData,
788 IN ULONG ValueLength)
789 {
790 DPRINT("VideoPortSetRegistryParameters\n");
791 ASSERT_IRQL(PASSIVE_LEVEL);
792 return RtlWriteRegistryValue(
793 RTL_REGISTRY_ABSOLUTE,
794 VIDEO_PORT_GET_DEVICE_EXTENSION(HwDeviceExtension)->RegistryPath.Buffer,
795 ValueName,
796 REG_BINARY,
797 ValueData,
798 ValueLength);
799 }
800
801 /*
802 * @implemented
803 */
804
805 VP_STATUS STDCALL
806 VideoPortGetVgaStatus(
807 IN PVOID HwDeviceExtension,
808 OUT PULONG VgaStatus)
809 {
810 PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension;
811
812 DPRINT("VideoPortGetVgaStatus\n");
813
814 DeviceExtension = VIDEO_PORT_GET_DEVICE_EXTENSION(HwDeviceExtension);
815 if (KeGetCurrentIrql() == PASSIVE_LEVEL)
816 {
817 if (DeviceExtension->AdapterInterfaceType == PCIBus)
818 {
819 /* VgaStatus: 0 == VGA not enabled, 1 == VGA enabled. */
820 /* Assumed for now */
821 *VgaStatus = 1;
822 return NO_ERROR;
823 }
824 }
825
826 return ERROR_INVALID_FUNCTION;
827 }
828
829 /*
830 * @implemented
831 */
832
833 PVOID STDCALL
834 VideoPortGetRomImage(
835 IN PVOID HwDeviceExtension,
836 IN PVOID Unused1,
837 IN ULONG Unused2,
838 IN ULONG Length)
839 {
840 static PVOID RomImageBuffer = NULL;
841 PKPROCESS CallingProcess;
842 KAPC_STATE ApcState;
843
844 DPRINT("VideoPortGetRomImage(HwDeviceExtension 0x%X Length 0x%X)\n",
845 HwDeviceExtension, Length);
846
847 /* If the length is zero then free the existing buffer. */
848 if (Length == 0)
849 {
850 if (RomImageBuffer != NULL)
851 {
852 ExFreePool(RomImageBuffer);
853 RomImageBuffer = NULL;
854 }
855 return NULL;
856 }
857 else
858 {
859 /*
860 * The DDK says we shouldn't use the legacy C0000 method but get the
861 * rom base address from the corresponding pci or acpi register but
862 * lets ignore that and use C0000 anyway. We have already mapped the
863 * bios area into memory so we'll copy from there.
864 */
865
866 /* Copy the bios. */
867 Length = min(Length, 0x10000);
868 if (RomImageBuffer != NULL)
869 {
870 ExFreePool(RomImageBuffer);
871 }
872
873 RomImageBuffer = ExAllocatePool(PagedPool, Length);
874 if (RomImageBuffer == NULL)
875 {
876 return NULL;
877 }
878
879 IntAttachToCSRSS(&CallingProcess, &ApcState);
880 RtlCopyMemory(RomImageBuffer, (PUCHAR)0xC0000, Length);
881 IntDetachFromCSRSS(&CallingProcess, &ApcState);
882
883 return RomImageBuffer;
884 }
885 }
886
887 /*
888 * @implemented
889 */
890
891 BOOLEAN STDCALL
892 VideoPortScanRom(
893 IN PVOID HwDeviceExtension,
894 IN PUCHAR RomBase,
895 IN ULONG RomLength,
896 IN PUCHAR String)
897 {
898 ULONG StringLength;
899 BOOLEAN Found;
900 PUCHAR SearchLocation;
901
902 DPRINT("VideoPortScanRom RomBase %p RomLength 0x%x String %s\n", RomBase, RomLength, String);
903
904 StringLength = strlen((PCHAR)String);
905 Found = FALSE;
906 SearchLocation = RomBase;
907 for (SearchLocation = RomBase;
908 !Found && SearchLocation < RomBase + RomLength - StringLength;
909 SearchLocation++)
910 {
911 Found = (RtlCompareMemory(SearchLocation, String, StringLength) == StringLength);
912 if (Found)
913 {
914 DPRINT("Match found at %p\n", SearchLocation);
915 }
916 }
917
918 return Found;
919 }
920
921 /*
922 * @implemented
923 */
924
925 BOOLEAN STDCALL
926 VideoPortSynchronizeExecution(
927 IN PVOID HwDeviceExtension,
928 IN VIDEO_SYNCHRONIZE_PRIORITY Priority,
929 IN PMINIPORT_SYNCHRONIZE_ROUTINE SynchronizeRoutine,
930 OUT PVOID Context)
931 {
932 BOOLEAN Ret;
933 PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension;
934 KIRQL OldIrql;
935
936 switch (Priority)
937 {
938 case VpLowPriority:
939 Ret = (*SynchronizeRoutine)(Context);
940 break;
941
942 case VpMediumPriority:
943 DeviceExtension = VIDEO_PORT_GET_DEVICE_EXTENSION(HwDeviceExtension);
944 if (DeviceExtension->InterruptObject == NULL)
945 Ret = (*SynchronizeRoutine)(Context);
946 else
947 Ret = KeSynchronizeExecution(
948 DeviceExtension->InterruptObject,
949 SynchronizeRoutine,
950 Context);
951 break;
952
953 case VpHighPriority:
954 OldIrql = KeGetCurrentIrql();
955 if (OldIrql < SYNCH_LEVEL)
956 OldIrql = KfRaiseIrql(SYNCH_LEVEL);
957
958 Ret = (*SynchronizeRoutine)(Context);
959
960 if (OldIrql < SYNCH_LEVEL)
961 KfLowerIrql(OldIrql);
962 break;
963
964 default:
965 Ret = FALSE;
966 }
967
968 return Ret;
969 }
970
971 /*
972 * @implemented
973 */
974
975 VP_STATUS STDCALL
976 VideoPortEnumerateChildren(
977 IN PVOID HwDeviceExtension,
978 IN PVOID Reserved)
979 {
980 PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension;
981 ULONG Status;
982 VIDEO_CHILD_ENUM_INFO ChildEnumInfo;
983 VIDEO_CHILD_TYPE ChildType;
984 UCHAR ChildDescriptor[256];
985 ULONG ChildId;
986 ULONG Unused;
987 INT i;
988
989 DeviceExtension = VIDEO_PORT_GET_DEVICE_EXTENSION(HwDeviceExtension);
990 if (DeviceExtension->DriverExtension->InitializationData.HwGetVideoChildDescriptor == NULL)
991 {
992 DPRINT("Miniport's HwGetVideoChildDescriptor is NULL!\n");
993 return NO_ERROR;
994 }
995
996 /* Setup the ChildEnumInfo */
997 ChildEnumInfo.Size = sizeof (ChildEnumInfo);
998 ChildEnumInfo.ChildDescriptorSize = sizeof (ChildDescriptor);
999 ChildEnumInfo.ACPIHwId = 0;
1000 ChildEnumInfo.ChildHwDeviceExtension = NULL; /* FIXME: must be set to
1001 ChildHwDeviceExtension... */
1002
1003 /* Enumerate the children */
1004 for (i = 1; ; i++)
1005 {
1006 ChildEnumInfo.ChildIndex = i;
1007 RtlZeroMemory(ChildDescriptor, sizeof(ChildDescriptor));
1008 Status = DeviceExtension->DriverExtension->InitializationData.HwGetVideoChildDescriptor(
1009 HwDeviceExtension,
1010 &ChildEnumInfo,
1011 &ChildType,
1012 ChildDescriptor,
1013 &ChildId,
1014 &Unused);
1015 if (Status == VIDEO_ENUM_INVALID_DEVICE)
1016 {
1017 DPRINT("Child device %d is invalid!\n", ChildEnumInfo.ChildIndex);
1018 continue;
1019 }
1020 else if (Status == VIDEO_ENUM_NO_MORE_DEVICES)
1021 {
1022 DPRINT("End of child enumeration! (%d children enumerated)\n", i - 1);
1023 break;
1024 }
1025 else if (Status != VIDEO_ENUM_MORE_DEVICES)
1026 {
1027 DPRINT("HwGetVideoChildDescriptor returned unknown status code 0x%x!\n", Status);
1028 break;
1029 }
1030
1031 #ifndef NDEBUG
1032 if (ChildType == Monitor)
1033 {
1034 INT j;
1035 PUCHAR p = ChildDescriptor;
1036 DPRINT("Monitor device enumerated! (ChildId = 0x%x)\n", ChildId);
1037 for (j = 0; j < sizeof (ChildDescriptor); j += 8)
1038 {
1039 DPRINT("%02x %02x %02x %02x %02x %02x %02x %02x\n",
1040 p[j+0], p[j+1], p[j+2], p[j+3],
1041 p[j+4], p[j+5], p[j+6], p[j+7]);
1042 }
1043 }
1044 else if (ChildType == Other)
1045 {
1046 DPRINT("\"Other\" device enumerated: DeviceId = %S\n", (PWSTR)ChildDescriptor);
1047 }
1048 else
1049 {
1050 DPRINT("HwGetVideoChildDescriptor returned unsupported type: %d\n", ChildType);
1051 }
1052 #endif /* NDEBUG */
1053
1054 }
1055
1056 return NO_ERROR;
1057 }
1058
1059 /*
1060 * @unimplemented
1061 */
1062
1063 VP_STATUS STDCALL
1064 VideoPortCreateSecondaryDisplay(
1065 IN PVOID HwDeviceExtension,
1066 IN OUT PVOID *SecondaryDeviceExtension,
1067 IN ULONG Flag)
1068 {
1069 DPRINT1("VideoPortCreateSecondaryDisplay: Unimplemented.\n");
1070 return NO_ERROR;
1071 }
1072
1073 /*
1074 * @implemented
1075 */
1076
1077 BOOLEAN STDCALL
1078 VideoPortQueueDpc(
1079 IN PVOID HwDeviceExtension,
1080 IN PMINIPORT_DPC_ROUTINE CallbackRoutine,
1081 IN PVOID Context)
1082 {
1083 return KeInsertQueueDpc(
1084 &VIDEO_PORT_GET_DEVICE_EXTENSION(HwDeviceExtension)->DpcObject,
1085 (PVOID)CallbackRoutine,
1086 (PVOID)Context);
1087 }
1088
1089 /*
1090 * @unimplemented
1091 */
1092
1093 PVOID STDCALL
1094 VideoPortGetAssociatedDeviceExtension(IN PVOID DeviceObject)
1095 {
1096 DPRINT1("VideoPortGetAssociatedDeviceExtension: Unimplemented.\n");
1097 return NULL;
1098 }
1099
1100 /*
1101 * @implemented
1102 */
1103
1104 VP_STATUS STDCALL
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 * @unimplemented
1140 */
1141
1142 BOOLEAN STDCALL
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 DPRINT1("VideoPortCheckForDeviceExistence: Unimplemented.\n");
1153 return TRUE;
1154 }
1155
1156 /*
1157 * @unimplemented
1158 */
1159
1160 VP_STATUS STDCALL
1161 VideoPortRegisterBugcheckCallback(
1162 IN PVOID HwDeviceExtension,
1163 IN ULONG BugcheckCode,
1164 IN PVOID Callback,
1165 IN ULONG BugcheckDataSize)
1166 {
1167 DPRINT1("VideoPortRegisterBugcheckCallback(): Unimplemented.\n");
1168 return NO_ERROR;
1169 }
1170
1171 /*
1172 * @implemented
1173 */
1174
1175 LONGLONG STDCALL
1176 VideoPortQueryPerformanceCounter(
1177 IN PVOID HwDeviceExtension,
1178 OUT PLONGLONG PerformanceFrequency OPTIONAL)
1179 {
1180 LARGE_INTEGER Result;
1181
1182 DPRINT("VideoPortQueryPerformanceCounter\n");
1183 Result = KeQueryPerformanceCounter((PLARGE_INTEGER)PerformanceFrequency);
1184 return Result.QuadPart;
1185 }
1186
1187 /*
1188 * @implemented
1189 */
1190
1191 VOID STDCALL
1192 VideoPortAcquireDeviceLock(
1193 IN PVOID HwDeviceExtension)
1194 {
1195 PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension;
1196 NTSTATUS Status;
1197 (void)Status;
1198
1199 DPRINT("VideoPortAcquireDeviceLock\n");
1200 DeviceExtension = VIDEO_PORT_GET_DEVICE_EXTENSION(HwDeviceExtension);
1201 Status = KeWaitForMutexObject(&DeviceExtension->DeviceLock, Executive,
1202 KernelMode, FALSE, NULL);
1203 ASSERT(Status == STATUS_SUCCESS);
1204 }
1205
1206 /*
1207 * @implemented
1208 */
1209
1210 VOID STDCALL
1211 VideoPortReleaseDeviceLock(
1212 IN PVOID HwDeviceExtension)
1213 {
1214 PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension;
1215 LONG Status;
1216 (void)Status;
1217
1218 DPRINT("VideoPortReleaseDeviceLock\n");
1219 DeviceExtension = VIDEO_PORT_GET_DEVICE_EXTENSION(HwDeviceExtension);
1220 Status = KeReleaseMutex(&DeviceExtension->DeviceLock, FALSE);
1221 ASSERT(Status == 0);
1222 }
1223
1224 /*
1225 * @unimplemented
1226 */
1227
1228 VOID STDCALL
1229 VpNotifyEaData(
1230 IN PDEVICE_OBJECT DeviceObject,
1231 IN PVOID Data)
1232 {
1233 }