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