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