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