1 /* 2 * VideoPort driver 3 * 4 * Copyright (C) 2002-2004, 2007 ReactOS Team 5 * 6 * This library is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU Lesser General Public 8 * License as published by the Free Software Foundation; either 9 * version 2.1 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 * Lesser General Public License for more details. 15 * 16 * You should have received a copy of the GNU Lesser General Public 17 * License along with this library; if not, write to the Free Software 18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 19 * 20 */ 21 22 #include "videoprt.h" 23 24 #include <stdio.h> 25 #include <ndk/exfuncs.h> 26 #include <ndk/obfuncs.h> 27 #include <ndk/rtlfuncs.h> 28 29 #define NDEBUG 30 #include <debug.h> 31 32 /* GLOBAL VARIABLES ***********************************************************/ 33 34 ULONG VideoDebugLevel = 0; 35 36 BOOLEAN VpBaseVideo = FALSE; 37 BOOLEAN VpNoVesa = FALSE; 38 39 PKPROCESS CsrProcess = NULL; 40 static ULONG VideoPortMaxObjectNumber = -1; 41 BOOLEAN VideoPortUseNewKey = FALSE; 42 KMUTEX VideoPortInt10Mutex; 43 KSPIN_LOCK HwResetAdaptersLock; 44 RTL_STATIC_LIST_HEAD(HwResetAdaptersList); 45 46 /* PRIVATE FUNCTIONS **********************************************************/ 47 48 ULONG 49 NTAPI 50 DriverEntry( 51 IN PVOID Context1, 52 IN PVOID Context2) 53 { 54 return STATUS_SUCCESS; 55 } 56 57 static 58 NTSTATUS 59 IntVideoPortAddDeviceMapLink( 60 PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension) 61 { 62 PUNICODE_STRING RegistryPath; 63 WCHAR DeviceBuffer[20]; 64 UNICODE_STRING DeviceName; 65 WCHAR SymlinkBuffer[20]; 66 UNICODE_STRING SymlinkName; 67 ULONG DeviceNumber; 68 NTSTATUS Status; 69 70 /* Create a unicode device name. */ 71 DeviceNumber = DeviceExtension->DeviceNumber; 72 swprintf(DeviceBuffer, L"\\Device\\Video%lu", DeviceNumber); 73 74 if (VideoPortUseNewKey) 75 RegistryPath = &DeviceExtension->NewRegistryPath; 76 else 77 RegistryPath = &DeviceExtension->RegistryPath; 78 79 /* Add entry to DEVICEMAP\VIDEO key in registry. */ 80 Status = RtlWriteRegistryValue(RTL_REGISTRY_DEVICEMAP, 81 L"VIDEO", 82 DeviceBuffer, 83 REG_SZ, 84 RegistryPath->Buffer, 85 RegistryPath->Length + sizeof(UNICODE_NULL)); 86 if (!NT_SUCCESS(Status)) 87 { 88 ERR_(VIDEOPRT, "Failed to create DEVICEMAP registry entry: 0x%X\n", Status); 89 return Status; 90 } 91 92 Status = RtlWriteRegistryValue(RTL_REGISTRY_DEVICEMAP, 93 L"VIDEO", 94 L"MaxObjectNumber", 95 REG_DWORD, 96 &DeviceNumber, 97 sizeof(DeviceNumber)); 98 if (!NT_SUCCESS(Status)) 99 { 100 ERR_(VIDEOPRT, "Failed to write MaxObjectNumber: 0x%X\n", Status); 101 return Status; 102 } 103 104 /* Create symbolic link "\??\DISPLAYx" */ 105 swprintf(SymlinkBuffer, L"\\??\\DISPLAY%lu", DeviceNumber + 1); 106 RtlInitUnicodeString(&SymlinkName, SymlinkBuffer); 107 RtlInitUnicodeString(&DeviceName, DeviceBuffer); 108 Status = IoCreateSymbolicLink(&SymlinkName, &DeviceName); 109 if (!NT_SUCCESS(Status)) 110 { 111 ERR_(VIDEOPRT, "Failed to create symbolic link: 0x%X\n", Status); 112 return Status; 113 } 114 115 /* Update MaxObjectNumber */ 116 VideoPortMaxObjectNumber = DeviceNumber; 117 118 return STATUS_SUCCESS; 119 } 120 121 PVOID 122 NTAPI 123 IntVideoPortImageDirectoryEntryToData( 124 PVOID BaseAddress, 125 ULONG Directory) 126 { 127 PIMAGE_NT_HEADERS NtHeader; 128 ULONG Va; 129 130 NtHeader = RtlImageNtHeader(BaseAddress); 131 if (NtHeader == NULL) 132 return NULL; 133 134 if (Directory >= NtHeader->OptionalHeader.NumberOfRvaAndSizes) 135 return NULL; 136 137 Va = NtHeader->OptionalHeader.DataDirectory[Directory].VirtualAddress; 138 if (Va == 0) 139 return NULL; 140 141 return (PVOID)((ULONG_PTR)BaseAddress + Va); 142 } 143 144 VOID 145 NTAPI 146 IntVideoPortDeferredRoutine( 147 IN PKDPC Dpc, 148 IN PVOID DeferredContext, 149 IN PVOID SystemArgument1, 150 IN PVOID SystemArgument2) 151 { 152 PVOID HwDeviceExtension = 153 &((PVIDEO_PORT_DEVICE_EXTENSION)DeferredContext)->MiniPortDeviceExtension; 154 ((PMINIPORT_DPC_ROUTINE)SystemArgument1)(HwDeviceExtension, SystemArgument2); 155 } 156 157 NTSTATUS 158 NTAPI 159 IntVideoPortCreateAdapterDeviceObject( 160 _In_ PDRIVER_OBJECT DriverObject, 161 _In_ PVIDEO_PORT_DRIVER_EXTENSION DriverExtension, 162 _In_opt_ PDEVICE_OBJECT PhysicalDeviceObject, 163 _In_ USHORT AdapterNumber, 164 _In_ USHORT DisplayNumber, 165 _Out_opt_ PDEVICE_OBJECT *DeviceObject) 166 { 167 PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension; 168 ULONG DeviceNumber; 169 ULONG PciSlotNumber; 170 PCI_SLOT_NUMBER SlotNumber; 171 ULONG Size; 172 NTSTATUS Status; 173 WCHAR DeviceBuffer[20]; 174 UNICODE_STRING DeviceName; 175 PDEVICE_OBJECT DeviceObject_; 176 177 if (DeviceObject == NULL) 178 DeviceObject = &DeviceObject_; 179 180 /* 181 * Find the first free device number that can be used for video device 182 * object names and symlinks. 183 */ 184 DeviceNumber = VideoPortMaxObjectNumber + 1; 185 if (DeviceNumber == (ULONG)-1) 186 { 187 WARN_(VIDEOPRT, "Can't find free device number\n"); 188 return STATUS_UNSUCCESSFUL; 189 } 190 191 /* 192 * Create the device object. 193 */ 194 195 /* Create a unicode device name. */ 196 swprintf(DeviceBuffer, L"\\Device\\Video%lu", DeviceNumber); 197 RtlInitUnicodeString(&DeviceName, DeviceBuffer); 198 199 INFO_(VIDEOPRT, "HwDeviceExtension size is: 0x%x\n", 200 DriverExtension->InitializationData.HwDeviceExtensionSize); 201 202 /* Create the device object. */ 203 Size = sizeof(VIDEO_PORT_DEVICE_EXTENSION) + 204 DriverExtension->InitializationData.HwDeviceExtensionSize; 205 Status = IoCreateDevice(DriverObject, 206 Size, 207 &DeviceName, 208 FILE_DEVICE_VIDEO, 209 0, 210 TRUE, 211 DeviceObject); 212 213 if (!NT_SUCCESS(Status)) 214 { 215 WARN_(VIDEOPRT, "IoCreateDevice call failed with status 0x%08x\n", Status); 216 return Status; 217 } 218 219 /* 220 * Set the buffering strategy here. If you change this, remember 221 * to change VidDispatchDeviceControl too. 222 */ 223 224 (*DeviceObject)->Flags |= DO_BUFFERED_IO; 225 226 /* Initialize device extension. */ 227 DeviceExtension = (PVIDEO_PORT_DEVICE_EXTENSION)((*DeviceObject)->DeviceExtension); 228 DeviceExtension->Common.Fdo = TRUE; 229 DeviceExtension->DeviceNumber = DeviceNumber; 230 DeviceExtension->DriverObject = DriverObject; 231 DeviceExtension->PhysicalDeviceObject = PhysicalDeviceObject; 232 DeviceExtension->FunctionalDeviceObject = *DeviceObject; 233 DeviceExtension->DriverExtension = DriverExtension; 234 DeviceExtension->SessionId = -1; 235 DeviceExtension->AdapterNumber = AdapterNumber; 236 DeviceExtension->DisplayNumber = DisplayNumber; 237 238 InitializeListHead(&DeviceExtension->ChildDeviceList); 239 240 /* Get the registry path associated with this device. */ 241 Status = IntCreateRegistryPath(&DriverExtension->RegistryPath, 242 DeviceExtension->AdapterNumber, 243 &DeviceExtension->RegistryPath); 244 if (!NT_SUCCESS(Status)) 245 { 246 WARN_(VIDEOPRT, "IntCreateRegistryPath() call failed with status 0x%08x\n", Status); 247 IoDeleteDevice(*DeviceObject); 248 *DeviceObject = NULL; 249 return Status; 250 } 251 252 if (PhysicalDeviceObject != NULL) 253 { 254 /* Get bus number from the upper level bus driver. */ 255 Size = sizeof(ULONG); 256 Status = IoGetDeviceProperty(PhysicalDeviceObject, 257 DevicePropertyBusNumber, 258 Size, 259 &DeviceExtension->SystemIoBusNumber, 260 &Size); 261 if (!NT_SUCCESS(Status)) 262 { 263 WARN_(VIDEOPRT, "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(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(PhysicalDeviceObject, 286 DevicePropertyAddress, 287 Size, 288 &PciSlotNumber, 289 &Size); 290 291 /* Convert slotnumber to PCI_SLOT_NUMBER */ 292 SlotNumber.u.AsULONG = 0; 293 SlotNumber.u.bits.DeviceNumber = (PciSlotNumber >> 16) & 0xFFFF; 294 SlotNumber.u.bits.FunctionNumber = PciSlotNumber & 0xFFFF; 295 DeviceExtension->SystemIoSlotNumber = SlotNumber.u.AsULONG; 296 } 297 298 InitializeListHead(&DeviceExtension->AddressMappingListHead); 299 InitializeListHead(&DeviceExtension->DmaAdapterList); 300 301 KeInitializeDpc(&DeviceExtension->DpcObject, 302 IntVideoPortDeferredRoutine, 303 DeviceExtension); 304 305 KeInitializeMutex(&DeviceExtension->DeviceLock, 0); 306 307 /* Attach the device. */ 308 if ((PhysicalDeviceObject != NULL) && (DisplayNumber == 0)) 309 DeviceExtension->NextDeviceObject = IoAttachDeviceToDeviceStack( 310 *DeviceObject, 311 PhysicalDeviceObject); 312 313 Status = IntCreateNewRegistryPath(DeviceExtension); 314 if (!NT_SUCCESS(Status)) 315 { 316 ERR_(VIDEOPRT, "IntCreateNewRegistryPath() failed with status 0x%08x\n", Status); 317 IoDeleteDevice(*DeviceObject); 318 *DeviceObject = NULL; 319 return Status; 320 } 321 322 IntSetupDeviceSettingsKey(DeviceExtension); 323 324 /* Remove the initailizing flag */ 325 (*DeviceObject)->Flags &= ~DO_DEVICE_INITIALIZING; 326 327 /* Set up the VIDEO/DEVICEMAP registry keys */ 328 Status = IntVideoPortAddDeviceMapLink(DeviceExtension); 329 if (!NT_SUCCESS(Status)) 330 { 331 ERR_(VIDEOPRT, "IntVideoPortAddDeviceMapLink() failed with status 0x%08x\n", Status); 332 IoDeleteDevice(*DeviceObject); 333 *DeviceObject = NULL; 334 return Status; 335 } 336 337 if (DisplayNumber == 0) 338 { 339 DriverExtension->InitializationData.StartingDeviceNumber++; 340 } 341 342 return STATUS_SUCCESS; 343 } 344 345 346 NTSTATUS 347 NTAPI 348 IntVideoPortFindAdapter( 349 IN PDRIVER_OBJECT DriverObject, 350 IN PVIDEO_PORT_DRIVER_EXTENSION DriverExtension, 351 IN PDEVICE_OBJECT DeviceObject) 352 { 353 PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension; 354 NTSTATUS Status; 355 VP_STATUS vpStatus; 356 VIDEO_PORT_CONFIG_INFO ConfigInfo; 357 SYSTEM_BASIC_INFORMATION SystemBasicInfo; 358 UCHAR Again = FALSE; 359 BOOL LegacyDetection = FALSE; 360 361 DeviceExtension = (PVIDEO_PORT_DEVICE_EXTENSION)DeviceObject->DeviceExtension; 362 363 /* Setup a ConfigInfo structure that we will pass to HwFindAdapter. */ 364 RtlZeroMemory(&ConfigInfo, sizeof(VIDEO_PORT_CONFIG_INFO)); 365 ConfigInfo.Length = sizeof(VIDEO_PORT_CONFIG_INFO); 366 ConfigInfo.AdapterInterfaceType = DeviceExtension->AdapterInterfaceType; 367 if (ConfigInfo.AdapterInterfaceType == PCIBus) 368 ConfigInfo.InterruptMode = LevelSensitive; 369 else 370 ConfigInfo.InterruptMode = Latched; 371 ConfigInfo.DriverRegistryPath = DriverExtension->RegistryPath.Buffer; 372 ConfigInfo.VideoPortGetProcAddress = IntVideoPortGetProcAddress; 373 ConfigInfo.SystemIoBusNumber = DeviceExtension->SystemIoBusNumber; 374 ConfigInfo.BusInterruptLevel = DeviceExtension->InterruptLevel; 375 ConfigInfo.BusInterruptVector = DeviceExtension->InterruptVector; 376 377 Status = ZwQuerySystemInformation(SystemBasicInformation, 378 &SystemBasicInfo, 379 sizeof(SystemBasicInfo), 380 NULL); 381 if (NT_SUCCESS(Status)) 382 { 383 ConfigInfo.SystemMemorySize = SystemBasicInfo.NumberOfPhysicalPages * 384 SystemBasicInfo.PageSize; 385 } 386 387 // FIXME: Check the adapter key and update VideoDebugLevel variable. 388 389 /* 390 * Call miniport HwVidFindAdapter entry point to detect if 391 * particular device is present. There are two possible code 392 * paths. The first one is for Legacy drivers (NT4) and cases 393 * when we don't have information about what bus we're on. The 394 * second case is the standard one for Plug & Play drivers. 395 */ 396 if (DeviceExtension->PhysicalDeviceObject == NULL) 397 { 398 LegacyDetection = TRUE; 399 } 400 401 if (LegacyDetection) 402 { 403 ULONG BusNumber, MaxBuses; 404 405 MaxBuses = DeviceExtension->AdapterInterfaceType == PCIBus ? PCI_MAX_BRIDGE_NUMBER : 1; 406 407 for (BusNumber = 0; BusNumber < MaxBuses; BusNumber++) 408 { 409 DeviceExtension->SystemIoBusNumber = 410 ConfigInfo.SystemIoBusNumber = BusNumber; 411 412 RtlZeroMemory(&DeviceExtension->MiniPortDeviceExtension, 413 DriverExtension->InitializationData.HwDeviceExtensionSize); 414 415 /* FIXME: Need to figure out what string to pass as param 3. */ 416 vpStatus = DriverExtension->InitializationData.HwFindAdapter( 417 &DeviceExtension->MiniPortDeviceExtension, 418 DriverExtension->HwContext, 419 NULL, 420 &ConfigInfo, 421 &Again); 422 423 if (vpStatus == ERROR_DEV_NOT_EXIST) 424 { 425 continue; 426 } 427 else 428 { 429 break; 430 } 431 } 432 } 433 else 434 { 435 /* FIXME: Need to figure out what string to pass as param 3. */ 436 vpStatus = DriverExtension->InitializationData.HwFindAdapter( 437 &DeviceExtension->MiniPortDeviceExtension, 438 DriverExtension->HwContext, 439 NULL, 440 &ConfigInfo, 441 &Again); 442 } 443 444 if (vpStatus != NO_ERROR) 445 { 446 ERR_(VIDEOPRT, "HwFindAdapter call failed with error 0x%X\n", vpStatus); 447 Status = STATUS_UNSUCCESSFUL; 448 goto Failure; 449 } 450 451 /* 452 * Now we know the device is present, so let's do all additional tasks 453 * such as creating symlinks or setting up interrupts and timer. 454 */ 455 456 /* FIXME: Allocate hardware resources for device. */ 457 458 /* Allocate interrupt for device. */ 459 if (!IntVideoPortSetupInterrupt(DeviceObject, DriverExtension, &ConfigInfo)) 460 { 461 Status = STATUS_INSUFFICIENT_RESOURCES; 462 goto Failure; 463 } 464 465 /* Allocate timer for device. */ 466 if (!IntVideoPortSetupTimer(DeviceObject, DriverExtension)) 467 { 468 if (DeviceExtension->InterruptObject != NULL) 469 IoDisconnectInterrupt(DeviceExtension->InterruptObject); 470 ERR_(VIDEOPRT, "IntVideoPortSetupTimer failed\n"); 471 Status = STATUS_INSUFFICIENT_RESOURCES; 472 goto Failure; 473 } 474 475 /* If the device can be reset, insert it in the list of resettable adapters */ 476 InitializeListHead(&DeviceExtension->HwResetListEntry); 477 if (DriverExtension->InitializationData.HwResetHw != NULL) 478 { 479 ExInterlockedInsertTailList(&HwResetAdaptersList, 480 &DeviceExtension->HwResetListEntry, 481 &HwResetAdaptersLock); 482 } 483 484 INFO_(VIDEOPRT, "STATUS_SUCCESS\n"); 485 return STATUS_SUCCESS; 486 487 Failure: 488 RtlFreeUnicodeString(&DeviceExtension->RegistryPath); 489 if (DeviceExtension->NextDeviceObject) 490 IoDetachDevice(DeviceExtension->NextDeviceObject); 491 IoDeleteDevice(DeviceObject); 492 return Status; 493 } 494 495 VOID 496 FASTCALL 497 IntAttachToCSRSS( 498 PKPROCESS *CallingProcess, 499 PKAPC_STATE ApcState) 500 { 501 *CallingProcess = (PKPROCESS)PsGetCurrentProcess(); 502 if (*CallingProcess != CsrProcess) 503 { 504 KeStackAttachProcess(CsrProcess, ApcState); 505 } 506 } 507 508 VOID 509 FASTCALL 510 IntDetachFromCSRSS( 511 PKPROCESS *CallingProcess, 512 PKAPC_STATE ApcState) 513 { 514 if (*CallingProcess != CsrProcess) 515 { 516 KeUnstackDetachProcess(ApcState); 517 } 518 } 519 520 VOID 521 FASTCALL 522 IntLoadRegistryParameters(VOID) 523 { 524 NTSTATUS Status; 525 HANDLE KeyHandle; 526 UNICODE_STRING UseNewKeyPath = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\GraphicsDrivers\\UseNewKey"); 527 UNICODE_STRING Path = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\System\\CurrentControlSet\\Control"); 528 UNICODE_STRING ValueName = RTL_CONSTANT_STRING(L"SystemStartOptions"); 529 OBJECT_ATTRIBUTES ObjectAttributes; 530 PKEY_VALUE_PARTIAL_INFORMATION KeyInfo; 531 ULONG Length, NewLength; 532 533 /* Check if we need to use new registry */ 534 InitializeObjectAttributes(&ObjectAttributes, 535 &UseNewKeyPath, 536 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 537 NULL, 538 NULL); 539 Status = ZwOpenKey(&KeyHandle, 540 GENERIC_READ | GENERIC_WRITE, 541 &ObjectAttributes); 542 if (NT_SUCCESS(Status)) 543 { 544 VideoPortUseNewKey = TRUE; 545 ZwClose(KeyHandle); 546 } 547 548 /* Initialize object attributes with the path we want */ 549 InitializeObjectAttributes(&ObjectAttributes, 550 &Path, 551 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 552 NULL, 553 NULL); 554 555 /* Open the key */ 556 Status = ZwOpenKey(&KeyHandle, 557 KEY_QUERY_VALUE, 558 &ObjectAttributes); 559 if (!NT_SUCCESS(Status)) 560 { 561 VideoPortDebugPrint(Error, "ZwOpenKey failed (0x%x)\n", Status); 562 return; 563 } 564 565 /* Find out how large our buffer should be */ 566 Status = ZwQueryValueKey(KeyHandle, 567 &ValueName, 568 KeyValuePartialInformation, 569 NULL, 570 0, 571 &Length); 572 if (Status != STATUS_BUFFER_OVERFLOW && Status != STATUS_BUFFER_TOO_SMALL) 573 { 574 VideoPortDebugPrint(Error, "ZwQueryValueKey failed (0x%x)\n", Status); 575 ObCloseHandle(KeyHandle, KernelMode); 576 return; 577 } 578 579 /* Allocate it */ 580 KeyInfo = ExAllocatePoolWithTag(PagedPool, Length, TAG_VIDEO_PORT); 581 if (!KeyInfo) 582 { 583 VideoPortDebugPrint(Error, "Out of memory\n"); 584 ObCloseHandle(KeyHandle, KernelMode); 585 return; 586 } 587 588 /* Now for real this time */ 589 Status = ZwQueryValueKey(KeyHandle, 590 &ValueName, 591 KeyValuePartialInformation, 592 KeyInfo, 593 Length, 594 &NewLength); 595 ObCloseHandle(KeyHandle, KernelMode); 596 597 if (!NT_SUCCESS(Status)) 598 { 599 VideoPortDebugPrint(Error, "ZwQueryValueKey failed (0x%x)\n", Status); 600 ExFreePoolWithTag(KeyInfo, TAG_VIDEO_PORT); 601 return; 602 } 603 604 /* Sanity check */ 605 if (KeyInfo->Type != REG_SZ) 606 { 607 VideoPortDebugPrint(Error, "Invalid type for SystemStartOptions\n"); 608 ExFreePoolWithTag(KeyInfo, TAG_VIDEO_PORT); 609 return; 610 } 611 612 /* Check if BASEVIDEO or NOVESA is present in the start options */ 613 if (wcsstr((PWCHAR)KeyInfo->Data, L"BASEVIDEO")) 614 VpBaseVideo = TRUE; 615 if (wcsstr((PWCHAR)KeyInfo->Data, L"NOVESA")) 616 VpNoVesa = TRUE; 617 618 ExFreePoolWithTag(KeyInfo, TAG_VIDEO_PORT); 619 620 /* FIXME: Old ReactOS-compatibility... */ 621 if (VpBaseVideo) VpNoVesa = TRUE; 622 623 if (VpNoVesa) 624 VideoPortDebugPrint(Info, "VESA mode disabled\n"); 625 else 626 VideoPortDebugPrint(Info, "VESA mode enabled\n"); 627 628 /* If we are in BASEVIDEO, create the volatile registry key for Win32k */ 629 if (VpBaseVideo) 630 { 631 RtlInitUnicodeString(&Path, L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\GraphicsDrivers\\BaseVideo"); 632 633 InitializeObjectAttributes(&ObjectAttributes, 634 &Path, 635 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 636 NULL, 637 NULL); 638 639 Status = ZwCreateKey(&KeyHandle, 640 READ_CONTROL, // Non-0 placeholder: no use for this handle. 641 &ObjectAttributes, 642 0, 643 NULL, 644 REG_OPTION_VOLATILE, 645 NULL); 646 if (NT_SUCCESS(Status)) 647 ObCloseHandle(KeyHandle, KernelMode); 648 else 649 ERR_(VIDEOPRT, "Failed to create the BaseVideo key (0x%x)\n", Status); 650 } 651 652 return; 653 } 654 655 /* PUBLIC FUNCTIONS ***********************************************************/ 656 657 /* 658 * @implemented 659 */ 660 ULONG 661 NTAPI 662 VideoPortInitialize( 663 IN PVOID Context1, 664 IN PVOID Context2, 665 IN PVIDEO_HW_INITIALIZATION_DATA HwInitializationData, 666 IN PVOID HwContext) 667 { 668 PDRIVER_OBJECT DriverObject = Context1; 669 PUNICODE_STRING RegistryPath = Context2; 670 NTSTATUS Status; 671 PVIDEO_PORT_DRIVER_EXTENSION DriverExtension; 672 BOOLEAN PnpDriver = FALSE, LegacyDetection = FALSE; 673 static BOOLEAN FirstInitialization; 674 675 TRACE_(VIDEOPRT, "VideoPortInitialize\n"); 676 677 if (!FirstInitialization) 678 { 679 FirstInitialization = TRUE; 680 KeInitializeMutex(&VideoPortInt10Mutex, 0); 681 KeInitializeSpinLock(&HwResetAdaptersLock); 682 IntLoadRegistryParameters(); 683 } 684 685 /* As a first thing do parameter checks. */ 686 if (HwInitializationData->HwInitDataSize > sizeof(VIDEO_HW_INITIALIZATION_DATA)) 687 { 688 ERR_(VIDEOPRT, "Invalid HwInitializationData\n"); 689 return STATUS_REVISION_MISMATCH; 690 } 691 692 if ((HwInitializationData->HwFindAdapter == NULL) || 693 (HwInitializationData->HwInitialize == NULL) || 694 (HwInitializationData->HwStartIO == NULL)) 695 { 696 ERR_(VIDEOPRT, "Invalid HwInitializationData\n"); 697 return STATUS_INVALID_PARAMETER; 698 } 699 700 switch (HwInitializationData->HwInitDataSize) 701 { 702 /* 703 * NT4 drivers are special case, because we must use legacy method 704 * of detection instead of the Plug & Play one. 705 */ 706 case SIZE_OF_NT4_VIDEO_HW_INITIALIZATION_DATA: 707 INFO_(VIDEOPRT, "We were loaded by a Windows NT miniport driver.\n"); 708 break; 709 710 case SIZE_OF_W2K_VIDEO_HW_INITIALIZATION_DATA: 711 INFO_(VIDEOPRT, "We were loaded by a Windows 2000 miniport driver.\n"); 712 break; 713 714 case sizeof(VIDEO_HW_INITIALIZATION_DATA): 715 INFO_(VIDEOPRT, "We were loaded by a Windows XP or later miniport driver.\n"); 716 break; 717 718 default: 719 ERR_(VIDEOPRT, "Invalid HwInitializationData size.\n"); 720 return STATUS_UNSUCCESSFUL; 721 } 722 723 /* Set dispatching routines */ 724 DriverObject->MajorFunction[IRP_MJ_CREATE] = IntVideoPortDispatchOpen; 725 DriverObject->MajorFunction[IRP_MJ_CLOSE] = IntVideoPortDispatchClose; 726 DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = 727 IntVideoPortDispatchDeviceControl; 728 DriverObject->MajorFunction[IRP_MJ_SHUTDOWN] = 729 IntVideoPortDispatchDeviceControl; 730 DriverObject->DriverUnload = IntVideoPortUnload; 731 732 /* Determine type of the miniport driver */ 733 if ((HwInitializationData->HwInitDataSize >= 734 FIELD_OFFSET(VIDEO_HW_INITIALIZATION_DATA, HwQueryInterface)) && 735 (HwInitializationData->HwSetPowerState != NULL) && 736 (HwInitializationData->HwGetPowerState != NULL) && 737 (HwInitializationData->HwGetVideoChildDescriptor != NULL)) 738 { 739 INFO_(VIDEOPRT, "The miniport is a PnP miniport driver\n"); 740 PnpDriver = TRUE; 741 } 742 743 /* Check if legacy detection should be applied */ 744 if (!PnpDriver || HwContext) 745 { 746 INFO_(VIDEOPRT, "Legacy detection for adapter interface %d\n", 747 HwInitializationData->AdapterInterfaceType); 748 749 /* FIXME: Move the code for legacy detection 750 to another function and call it here */ 751 LegacyDetection = TRUE; 752 } 753 754 /* 755 * NOTE: 756 * The driver extension can be already allocated in case that we were 757 * called by legacy driver and failed detecting device. Some miniport 758 * drivers in that case adjust parameters and call VideoPortInitialize 759 * again. 760 */ 761 DriverExtension = IoGetDriverObjectExtension(DriverObject, DriverObject); 762 if (DriverExtension == NULL) 763 { 764 Status = IoAllocateDriverObjectExtension(DriverObject, 765 DriverObject, 766 sizeof(VIDEO_PORT_DRIVER_EXTENSION), 767 (PVOID *)&DriverExtension); 768 if (!NT_SUCCESS(Status)) 769 { 770 ERR_(VIDEOPRT, "IoAllocateDriverObjectExtension failed 0x%x\n", Status); 771 return Status; 772 } 773 774 /* 775 * Save the registry path. This should be done only once even if 776 * VideoPortInitialize is called multiple times. 777 */ 778 if (RegistryPath->Length != 0) 779 { 780 DriverExtension->RegistryPath.Length = 0; 781 DriverExtension->RegistryPath.MaximumLength = 782 RegistryPath->Length + sizeof(UNICODE_NULL); 783 DriverExtension->RegistryPath.Buffer = 784 ExAllocatePoolWithTag( 785 PagedPool, 786 DriverExtension->RegistryPath.MaximumLength, 787 'RTSU'); 788 if (DriverExtension->RegistryPath.Buffer == NULL) 789 { 790 RtlInitUnicodeString(&DriverExtension->RegistryPath, NULL); 791 return STATUS_INSUFFICIENT_RESOURCES; 792 } 793 794 RtlCopyUnicodeString(&DriverExtension->RegistryPath, RegistryPath); 795 796 /* There is a bug in Spice guest agent, which searches 'System' case-sensitively. 797 * Replace 'SYSTEM' by 'System' to fix that. 798 * Probably for similar reason, Windows also replaces 'MACHINE' by 'Machine'. 799 */ 800 wcsncpy(wcsstr(DriverExtension->RegistryPath.Buffer, L"\\SYSTEM\\"), L"\\System\\", ARRAYSIZE(L"\\SYSTEM\\") - 1); 801 wcsncpy(wcsstr(DriverExtension->RegistryPath.Buffer, L"\\MACHINE\\"), L"\\Machine\\", ARRAYSIZE(L"\\MACHINE\\") - 1); 802 803 INFO_(VIDEOPRT, "RegistryPath: %wZ\n", &DriverExtension->RegistryPath); 804 } 805 else 806 { 807 RtlInitUnicodeString(&DriverExtension->RegistryPath, NULL); 808 } 809 } 810 811 /* Copy the correct miniport initialization data to the device extension. */ 812 RtlCopyMemory(&DriverExtension->InitializationData, 813 HwInitializationData, 814 HwInitializationData->HwInitDataSize); 815 if (HwInitializationData->HwInitDataSize < 816 sizeof(VIDEO_HW_INITIALIZATION_DATA)) 817 { 818 RtlZeroMemory((PVOID)((ULONG_PTR)&DriverExtension->InitializationData + 819 HwInitializationData->HwInitDataSize), 820 sizeof(VIDEO_HW_INITIALIZATION_DATA) - 821 HwInitializationData->HwInitDataSize); 822 } 823 DriverExtension->HwContext = HwContext; 824 825 /* 826 * Plug & Play drivers registers the device in AddDevice routine. 827 * For legacy drivers we must do it now. 828 */ 829 if (LegacyDetection) 830 { 831 PDEVICE_OBJECT DeviceObject; 832 833 if (HwInitializationData->HwInitDataSize != SIZE_OF_NT4_VIDEO_HW_INITIALIZATION_DATA) 834 { 835 /* Power management */ 836 DriverObject->MajorFunction[IRP_MJ_POWER] = IntVideoPortDispatchPower; 837 } 838 839 Status = IntVideoPortCreateAdapterDeviceObject(DriverObject, 840 DriverExtension, 841 NULL, 842 DriverExtension->InitializationData.StartingDeviceNumber, 843 0, 844 &DeviceObject); 845 if (!NT_SUCCESS(Status)) 846 { 847 ERR_(VIDEOPRT, "IntVideoPortCreateAdapterDeviceObject returned 0x%x\n", Status); 848 return Status; 849 } 850 851 Status = IntVideoPortFindAdapter(DriverObject, DriverExtension, DeviceObject); 852 if (!NT_SUCCESS(Status)) 853 ERR_(VIDEOPRT, "IntVideoPortFindAdapter returned 0x%x\n", Status); 854 855 return Status; 856 } 857 else 858 { 859 DriverObject->DriverExtension->AddDevice = IntVideoPortAddDevice; 860 DriverObject->MajorFunction[IRP_MJ_PNP] = IntVideoPortDispatchPnp; 861 DriverObject->MajorFunction[IRP_MJ_POWER] = IntVideoPortDispatchPower; 862 DriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = IntVideoPortDispatchSystemControl; 863 864 return STATUS_SUCCESS; 865 } 866 } 867 868 /* 869 * @implemented 870 */ 871 VOID 872 VideoPortDebugPrint( 873 IN VIDEO_DEBUG_LEVEL DebugPrintLevel, 874 IN PCHAR DebugMessage, 875 ...) 876 { 877 va_list ap; 878 879 if (VideoDebugLevel >= DebugPrintLevel) 880 DebugPrintLevel = Error; 881 882 va_start(ap, DebugMessage); 883 vDbgPrintEx(DPFLTR_IHVVIDEO_ID, DebugPrintLevel, DebugMessage, ap); 884 va_end(ap); 885 } 886 887 /* 888 * @unimplemented 889 */ 890 VOID 891 NTAPI 892 VideoPortLogError( 893 IN PVOID HwDeviceExtension, 894 IN PVIDEO_REQUEST_PACKET Vrp OPTIONAL, 895 IN VP_STATUS ErrorCode, 896 IN ULONG UniqueId) 897 { 898 UNIMPLEMENTED; 899 900 INFO_(VIDEOPRT, "VideoPortLogError ErrorCode %d (0x%x) UniqueId %lu (0x%lx)\n", 901 ErrorCode, ErrorCode, UniqueId, UniqueId); 902 if (Vrp) 903 INFO_(VIDEOPRT, "Vrp->IoControlCode %lu (0x%lx)\n", Vrp->IoControlCode, Vrp->IoControlCode); 904 } 905 906 /* 907 * @implemented 908 */ 909 UCHAR 910 NTAPI 911 VideoPortGetCurrentIrql(VOID) 912 { 913 return KeGetCurrentIrql(); 914 } 915 916 typedef struct QueryRegistryCallbackContext 917 { 918 PVOID HwDeviceExtension; 919 PVOID HwContext; 920 PMINIPORT_GET_REGISTRY_ROUTINE HwGetRegistryRoutine; 921 } QUERY_REGISTRY_CALLBACK_CONTEXT, *PQUERY_REGISTRY_CALLBACK_CONTEXT; 922 923 static 924 NTSTATUS 925 NTAPI 926 QueryRegistryCallback( 927 IN PWSTR ValueName, 928 IN ULONG ValueType, 929 IN PVOID ValueData, 930 IN ULONG ValueLength, 931 IN PVOID Context, 932 IN PVOID EntryContext) 933 { 934 PQUERY_REGISTRY_CALLBACK_CONTEXT CallbackContext = (PQUERY_REGISTRY_CALLBACK_CONTEXT) Context; 935 936 INFO_(VIDEOPRT, "Found registry value for name %S: type %d, length %d\n", 937 ValueName, ValueType, ValueLength); 938 return (*(CallbackContext->HwGetRegistryRoutine))( 939 CallbackContext->HwDeviceExtension, 940 CallbackContext->HwContext, 941 ValueName, 942 ValueData, 943 ValueLength); 944 } 945 946 /* 947 * @unimplemented 948 */ 949 950 VP_STATUS 951 NTAPI 952 VideoPortGetRegistryParameters( 953 IN PVOID HwDeviceExtension, 954 IN PWSTR ParameterName, 955 IN UCHAR IsParameterFileName, 956 IN PMINIPORT_GET_REGISTRY_ROUTINE GetRegistryRoutine, 957 IN PVOID HwContext) 958 { 959 RTL_QUERY_REGISTRY_TABLE QueryTable[2] = {{0}}; 960 QUERY_REGISTRY_CALLBACK_CONTEXT Context; 961 PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension; 962 NTSTATUS Status; 963 964 DeviceExtension = VIDEO_PORT_GET_DEVICE_EXTENSION(HwDeviceExtension); 965 966 TRACE_(VIDEOPRT, "VideoPortGetRegistryParameters ParameterName %S, RegPath: %wZ\n", 967 ParameterName, &DeviceExtension->RegistryPath); 968 969 Context.HwDeviceExtension = HwDeviceExtension; 970 Context.HwContext = HwContext; 971 Context.HwGetRegistryRoutine = GetRegistryRoutine; 972 973 QueryTable[0].QueryRoutine = QueryRegistryCallback; 974 QueryTable[0].Flags = RTL_QUERY_REGISTRY_REQUIRED; 975 QueryTable[0].Name = ParameterName; 976 977 Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE, 978 DeviceExtension->RegistryPath.Buffer, 979 QueryTable, 980 &Context, 981 NULL); 982 if (!NT_SUCCESS(Status)) 983 { 984 WARN_(VIDEOPRT, "VideoPortGetRegistryParameters could not find the " 985 "requested parameter\n"); 986 return ERROR_INVALID_PARAMETER; 987 } 988 989 if (IsParameterFileName) 990 { 991 /* FIXME: need to read the contents of the file */ 992 UNIMPLEMENTED; 993 } 994 995 return NO_ERROR; 996 } 997 998 /* 999 * @implemented 1000 */ 1001 VP_STATUS 1002 NTAPI 1003 VideoPortSetRegistryParameters( 1004 IN PVOID HwDeviceExtension, 1005 IN PWSTR ValueName, 1006 IN PVOID ValueData, 1007 IN ULONG ValueLength) 1008 { 1009 PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension; 1010 VP_STATUS Status; 1011 1012 DeviceExtension = VIDEO_PORT_GET_DEVICE_EXTENSION(HwDeviceExtension); 1013 TRACE_(VIDEOPRT, "VideoPortSetRegistryParameters ParameterName %S, RegPath: %wZ\n", 1014 ValueName, 1015 &DeviceExtension->RegistryPath); 1016 ASSERT_IRQL_LESS_OR_EQUAL(PASSIVE_LEVEL); 1017 Status = RtlWriteRegistryValue(RTL_REGISTRY_ABSOLUTE, 1018 DeviceExtension->RegistryPath.Buffer, 1019 ValueName, 1020 REG_BINARY, 1021 ValueData, 1022 ValueLength); 1023 if (Status != NO_ERROR) 1024 WARN_(VIDEOPRT, "VideoPortSetRegistryParameters error 0x%x\n", Status); 1025 1026 return Status; 1027 } 1028 1029 /* 1030 * @implemented 1031 */ 1032 VP_STATUS 1033 NTAPI 1034 VideoPortGetVgaStatus( 1035 IN PVOID HwDeviceExtension, 1036 OUT PULONG VgaStatus) 1037 { 1038 PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension; 1039 1040 TRACE_(VIDEOPRT, "VideoPortGetVgaStatus\n"); 1041 1042 DeviceExtension = VIDEO_PORT_GET_DEVICE_EXTENSION(HwDeviceExtension); 1043 if (KeGetCurrentIrql() == PASSIVE_LEVEL) 1044 { 1045 if (DeviceExtension->AdapterInterfaceType == PCIBus) 1046 { 1047 /* VgaStatus: 0 == VGA not enabled, 1 == VGA enabled. */ 1048 /* Assumed for now */ 1049 *VgaStatus = 1; 1050 return NO_ERROR; 1051 } 1052 } 1053 1054 return ERROR_INVALID_FUNCTION; 1055 } 1056 1057 /* 1058 * @implemented 1059 */ 1060 PVOID 1061 NTAPI 1062 VideoPortGetRomImage( 1063 IN PVOID HwDeviceExtension, 1064 IN PVOID Unused1, 1065 IN ULONG Unused2, 1066 IN ULONG Length) 1067 { 1068 static PVOID RomImageBuffer = NULL; 1069 PKPROCESS CallingProcess; 1070 KAPC_STATE ApcState; 1071 1072 TRACE_(VIDEOPRT, "VideoPortGetRomImage(HwDeviceExtension 0x%X Length 0x%X)\n", 1073 HwDeviceExtension, Length); 1074 1075 /* If the length is zero then free the existing buffer. */ 1076 if (Length == 0) 1077 { 1078 if (RomImageBuffer != NULL) 1079 { 1080 ExFreePool(RomImageBuffer); 1081 RomImageBuffer = NULL; 1082 } 1083 return NULL; 1084 } 1085 else 1086 { 1087 /* 1088 * The DDK says we shouldn't use the legacy C0000 method but get the 1089 * rom base address from the corresponding pci or acpi register but 1090 * lets ignore that and use C0000 anyway. We have already mapped the 1091 * bios area into memory so we'll copy from there. 1092 */ 1093 1094 /* Copy the bios. */ 1095 Length = min(Length, 0x10000); 1096 if (RomImageBuffer != NULL) 1097 { 1098 ExFreePool(RomImageBuffer); 1099 } 1100 1101 RomImageBuffer = ExAllocatePool(PagedPool, Length); 1102 if (RomImageBuffer == NULL) 1103 { 1104 return NULL; 1105 } 1106 1107 IntAttachToCSRSS(&CallingProcess, &ApcState); 1108 RtlCopyMemory(RomImageBuffer, (PUCHAR)0xC0000, Length); 1109 IntDetachFromCSRSS(&CallingProcess, &ApcState); 1110 1111 return RomImageBuffer; 1112 } 1113 } 1114 1115 /* 1116 * @implemented 1117 */ 1118 BOOLEAN 1119 NTAPI 1120 VideoPortScanRom( 1121 IN PVOID HwDeviceExtension, 1122 IN PUCHAR RomBase, 1123 IN ULONG RomLength, 1124 IN PUCHAR String) 1125 { 1126 SIZE_T StringLength; 1127 BOOLEAN Found; 1128 PUCHAR SearchLocation; 1129 1130 TRACE_(VIDEOPRT, "VideoPortScanRom RomBase %p RomLength 0x%x String %s\n", RomBase, RomLength, String); 1131 1132 StringLength = strlen((PCHAR)String); 1133 Found = FALSE; 1134 for (SearchLocation = RomBase; 1135 !Found && SearchLocation < RomBase + RomLength - StringLength; 1136 SearchLocation++) 1137 { 1138 Found = (RtlCompareMemory(SearchLocation, String, StringLength) == StringLength); 1139 if (Found) 1140 { 1141 INFO_(VIDEOPRT, "Match found at %p\n", SearchLocation); 1142 } 1143 } 1144 1145 return Found; 1146 } 1147 1148 /* 1149 * @implemented 1150 */ 1151 BOOLEAN 1152 NTAPI 1153 VideoPortSynchronizeExecution( 1154 IN PVOID HwDeviceExtension, 1155 IN VIDEO_SYNCHRONIZE_PRIORITY Priority, 1156 IN PMINIPORT_SYNCHRONIZE_ROUTINE SynchronizeRoutine, 1157 OUT PVOID Context) 1158 { 1159 BOOLEAN Ret; 1160 PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension; 1161 KIRQL OldIrql; 1162 1163 switch (Priority) 1164 { 1165 case VpLowPriority: 1166 Ret = (*SynchronizeRoutine)(Context); 1167 break; 1168 1169 case VpMediumPriority: 1170 DeviceExtension = VIDEO_PORT_GET_DEVICE_EXTENSION(HwDeviceExtension); 1171 if (DeviceExtension->InterruptObject == NULL) 1172 Ret = (*SynchronizeRoutine)(Context); 1173 else 1174 Ret = KeSynchronizeExecution( 1175 DeviceExtension->InterruptObject, 1176 SynchronizeRoutine, 1177 Context); 1178 break; 1179 1180 case VpHighPriority: 1181 OldIrql = KeGetCurrentIrql(); 1182 if (OldIrql < SYNCH_LEVEL) 1183 KeRaiseIrql(SYNCH_LEVEL, &OldIrql); 1184 1185 Ret = (*SynchronizeRoutine)(Context); 1186 1187 if (OldIrql < SYNCH_LEVEL) 1188 KeLowerIrql(OldIrql); 1189 break; 1190 1191 default: 1192 Ret = FALSE; 1193 } 1194 1195 return Ret; 1196 } 1197 1198 /* 1199 * @implemented 1200 */ 1201 NTSTATUS NTAPI 1202 IntVideoPortEnumerateChildren( 1203 IN PDEVICE_OBJECT DeviceObject, 1204 IN PIRP Irp) 1205 { 1206 PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension; 1207 ULONG Status; 1208 VIDEO_CHILD_ENUM_INFO ChildEnumInfo; 1209 BOOLEAN bHaveLastMonitorID = FALSE; 1210 UCHAR LastMonitorID[10]; 1211 ULONG Unused; 1212 UINT i; 1213 PDEVICE_OBJECT ChildDeviceObject; 1214 PVIDEO_PORT_CHILD_EXTENSION ChildExtension; 1215 1216 INFO_(VIDEOPRT, "Starting child device probe\n"); 1217 DeviceExtension = DeviceObject->DeviceExtension; 1218 if (DeviceExtension->DriverExtension->InitializationData.HwGetVideoChildDescriptor == NULL) 1219 { 1220 WARN_(VIDEOPRT, "Miniport's HwGetVideoChildDescriptor is NULL!\n"); 1221 return STATUS_SUCCESS; 1222 } 1223 1224 if (!IsListEmpty(&DeviceExtension->ChildDeviceList)) 1225 { 1226 ERR_(VIDEOPRT, "FIXME: Support calling VideoPortEnumerateChildren again!\n"); 1227 return STATUS_SUCCESS; 1228 } 1229 1230 /* Enumerate the children */ 1231 for (i = 1; ; i++) 1232 { 1233 Status = IoCreateDevice(DeviceExtension->DriverObject, 1234 sizeof(VIDEO_PORT_CHILD_EXTENSION) + 1235 DeviceExtension->DriverExtension->InitializationData.HwChildDeviceExtensionSize, 1236 NULL, 1237 FILE_DEVICE_CONTROLLER, 1238 FILE_DEVICE_SECURE_OPEN, 1239 FALSE, 1240 &ChildDeviceObject); 1241 if (!NT_SUCCESS(Status)) 1242 return Status; 1243 1244 ChildExtension = ChildDeviceObject->DeviceExtension; 1245 1246 RtlZeroMemory(ChildExtension, 1247 sizeof(VIDEO_PORT_CHILD_EXTENSION) + 1248 DeviceExtension->DriverExtension->InitializationData.HwChildDeviceExtensionSize); 1249 1250 ChildExtension->Common.Fdo = FALSE; 1251 ChildExtension->ChildId = i; 1252 ChildExtension->PhysicalDeviceObject = ChildDeviceObject; 1253 ChildExtension->DriverObject = DeviceExtension->DriverObject; 1254 1255 /* Setup the ChildEnumInfo */ 1256 ChildEnumInfo.Size = sizeof(ChildEnumInfo); 1257 ChildEnumInfo.ChildDescriptorSize = sizeof(ChildExtension->ChildDescriptor); 1258 ChildEnumInfo.ACPIHwId = 0; 1259 1260 if (DeviceExtension->DriverExtension->InitializationData.HwChildDeviceExtensionSize) 1261 ChildEnumInfo.ChildHwDeviceExtension = VIDEO_PORT_GET_CHILD_EXTENSION(ChildExtension); 1262 else 1263 ChildEnumInfo.ChildHwDeviceExtension = NULL; 1264 1265 ChildEnumInfo.ChildIndex = ChildExtension->ChildId; 1266 1267 INFO_(VIDEOPRT, "Probing child: %d\n", ChildEnumInfo.ChildIndex); 1268 Status = DeviceExtension->DriverExtension->InitializationData.HwGetVideoChildDescriptor( 1269 DeviceExtension->MiniPortDeviceExtension, 1270 &ChildEnumInfo, 1271 &ChildExtension->ChildType, 1272 ChildExtension->ChildDescriptor, 1273 &ChildExtension->ChildId, 1274 &Unused); 1275 if (Status == VIDEO_ENUM_MORE_DEVICES) 1276 { 1277 if (ChildExtension->ChildType == Monitor) 1278 { 1279 // Check if the EDID is valid 1280 if (ChildExtension->ChildDescriptor[0] == 0x00 && 1281 ChildExtension->ChildDescriptor[1] == 0xFF && 1282 ChildExtension->ChildDescriptor[2] == 0xFF && 1283 ChildExtension->ChildDescriptor[3] == 0xFF && 1284 ChildExtension->ChildDescriptor[4] == 0xFF && 1285 ChildExtension->ChildDescriptor[5] == 0xFF && 1286 ChildExtension->ChildDescriptor[6] == 0xFF && 1287 ChildExtension->ChildDescriptor[7] == 0x00) 1288 { 1289 if (bHaveLastMonitorID) 1290 { 1291 // Compare the previous monitor ID with the current one, break the loop if they are identical 1292 if (RtlCompareMemory(LastMonitorID, &ChildExtension->ChildDescriptor[8], sizeof(LastMonitorID)) == sizeof(LastMonitorID)) 1293 { 1294 INFO_(VIDEOPRT, "Found identical Monitor ID two times, stopping enumeration\n"); 1295 IoDeleteDevice(ChildDeviceObject); 1296 break; 1297 } 1298 } 1299 1300 // Copy 10 bytes from the EDID, which can be used to uniquely identify the monitor 1301 RtlCopyMemory(LastMonitorID, &ChildExtension->ChildDescriptor[8], sizeof(LastMonitorID)); 1302 bHaveLastMonitorID = TRUE; 1303 1304 /* Mark it valid */ 1305 ChildExtension->EdidValid = TRUE; 1306 } 1307 else 1308 { 1309 /* Mark it invalid */ 1310 ChildExtension->EdidValid = FALSE; 1311 } 1312 } 1313 } 1314 else if (Status == VIDEO_ENUM_INVALID_DEVICE) 1315 { 1316 WARN_(VIDEOPRT, "Child device %d is invalid!\n", ChildEnumInfo.ChildIndex); 1317 IoDeleteDevice(ChildDeviceObject); 1318 continue; 1319 } 1320 else if (Status == VIDEO_ENUM_NO_MORE_DEVICES) 1321 { 1322 INFO_(VIDEOPRT, "End of child enumeration! (%d children enumerated)\n", i - 1); 1323 IoDeleteDevice(ChildDeviceObject); 1324 break; 1325 } 1326 else 1327 { 1328 WARN_(VIDEOPRT, "HwGetVideoChildDescriptor returned unknown status code 0x%x!\n", Status); 1329 IoDeleteDevice(ChildDeviceObject); 1330 break; 1331 } 1332 1333 if (ChildExtension->ChildType == Monitor) 1334 { 1335 UINT j; 1336 PUCHAR p = ChildExtension->ChildDescriptor; 1337 INFO_(VIDEOPRT, "Monitor device enumerated! (ChildId = 0x%x)\n", ChildExtension->ChildId); 1338 for (j = 0; j < sizeof (ChildExtension->ChildDescriptor); j += 8) 1339 { 1340 INFO_(VIDEOPRT, "%02x %02x %02x %02x %02x %02x %02x %02x\n", 1341 p[j + 0], p[j + 1], p[j + 2], p[j + 3], 1342 p[j + 4], p[j + 5], p[j + 6], p[j + 7]); 1343 } 1344 } 1345 else if (ChildExtension->ChildType == Other) 1346 { 1347 INFO_(VIDEOPRT, "\"Other\" device enumerated: DeviceId = %S\n", (PWSTR)ChildExtension->ChildDescriptor); 1348 } 1349 else 1350 { 1351 ERR_(VIDEOPRT, "HwGetVideoChildDescriptor returned unsupported type: %d\n", ChildExtension->ChildType); 1352 } 1353 1354 /* Clear the init flag */ 1355 ChildDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING; 1356 1357 InsertTailList(&DeviceExtension->ChildDeviceList, 1358 &ChildExtension->ListEntry); 1359 } 1360 1361 return STATUS_SUCCESS; 1362 } 1363 1364 VP_STATUS 1365 NTAPI 1366 VideoPortEnumerateChildren( 1367 IN PVOID HwDeviceExtension, 1368 IN PVOID Reserved) 1369 { 1370 PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension; 1371 1372 DeviceExtension = VIDEO_PORT_GET_DEVICE_EXTENSION(HwDeviceExtension); 1373 ASSERT(DeviceExtension); 1374 1375 if (DeviceExtension->PhysicalDeviceObject) 1376 { 1377 /* Trigger reenumeration by the PnP manager */ 1378 IoInvalidateDeviceRelations(DeviceExtension->PhysicalDeviceObject, BusRelations); 1379 } 1380 1381 return NO_ERROR; 1382 } 1383 1384 /* 1385 * @unimplemented 1386 */ 1387 VP_STATUS 1388 NTAPI 1389 VideoPortCreateSecondaryDisplay( 1390 IN PVOID HwDeviceExtension, 1391 IN OUT PVOID *SecondaryDeviceExtension, 1392 IN ULONG Flag) 1393 { 1394 PDEVICE_OBJECT DeviceObject; 1395 PVIDEO_PORT_DEVICE_EXTENSION FirstDeviceExtension, DeviceExtension; 1396 NTSTATUS Status; 1397 1398 ASSERT(SecondaryDeviceExtension); 1399 1400 if (Flag != 0) 1401 { 1402 UNIMPLEMENTED; 1403 } 1404 1405 FirstDeviceExtension = VIDEO_PORT_GET_DEVICE_EXTENSION(HwDeviceExtension); 1406 1407 if (FirstDeviceExtension->DisplayNumber != 0) 1408 { 1409 DPRINT1("Calling VideoPortCreateSecondaryDisplay for InstanceId %lu\n", 1410 FirstDeviceExtension->DisplayNumber); 1411 } 1412 1413 Status = IntVideoPortCreateAdapterDeviceObject(FirstDeviceExtension->DriverObject, 1414 FirstDeviceExtension->DriverExtension, 1415 FirstDeviceExtension->PhysicalDeviceObject, 1416 FirstDeviceExtension->AdapterNumber, 1417 FirstDeviceExtension->NumberOfSecondaryDisplays + 1, 1418 &DeviceObject); 1419 if (!NT_SUCCESS(Status)) 1420 { 1421 DPRINT1("IntVideoPortCreateAdapterDeviceObject() failed with status 0x%08x\n", Status); 1422 return ERROR_DEV_NOT_EXIST; 1423 } 1424 1425 DeviceExtension = DeviceObject->DeviceExtension; 1426 1427 /* Increment secondary display count */ 1428 FirstDeviceExtension->NumberOfSecondaryDisplays++; 1429 1430 *SecondaryDeviceExtension = DeviceExtension->MiniPortDeviceExtension; 1431 return NO_ERROR; 1432 } 1433 1434 /* 1435 * @implemented 1436 */ 1437 BOOLEAN 1438 NTAPI 1439 VideoPortQueueDpc( 1440 IN PVOID HwDeviceExtension, 1441 IN PMINIPORT_DPC_ROUTINE CallbackRoutine, 1442 IN PVOID Context) 1443 { 1444 return KeInsertQueueDpc( 1445 &VIDEO_PORT_GET_DEVICE_EXTENSION(HwDeviceExtension)->DpcObject, 1446 (PVOID)CallbackRoutine, 1447 (PVOID)Context); 1448 } 1449 1450 /* 1451 * @implemented 1452 */ 1453 PVOID 1454 NTAPI 1455 VideoPortGetAssociatedDeviceExtension( 1456 IN PVOID DeviceObject) 1457 { 1458 PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension; 1459 1460 TRACE_(VIDEOPRT, "VideoPortGetAssociatedDeviceExtension\n"); 1461 DeviceExtension = ((PDEVICE_OBJECT)DeviceObject)->DeviceExtension; 1462 if (!DeviceExtension) 1463 return NULL; 1464 return DeviceExtension->MiniPortDeviceExtension; 1465 } 1466 1467 /* 1468 * @implemented 1469 */ 1470 VP_STATUS 1471 NTAPI 1472 VideoPortGetVersion( 1473 IN PVOID HwDeviceExtension, 1474 IN OUT PVPOSVERSIONINFO VpOsVersionInfo) 1475 { 1476 RTL_OSVERSIONINFOEXW Version; 1477 1478 Version.dwOSVersionInfoSize = sizeof(RTL_OSVERSIONINFOEXW); 1479 if (VpOsVersionInfo->Size >= sizeof(VPOSVERSIONINFO)) 1480 { 1481 #if 1 1482 if (NT_SUCCESS(RtlGetVersion((PRTL_OSVERSIONINFOW)&Version))) 1483 { 1484 VpOsVersionInfo->MajorVersion = Version.dwMajorVersion; 1485 VpOsVersionInfo->MinorVersion = Version.dwMinorVersion; 1486 VpOsVersionInfo->BuildNumber = Version.dwBuildNumber; 1487 VpOsVersionInfo->ServicePackMajor = Version.wServicePackMajor; 1488 VpOsVersionInfo->ServicePackMinor = Version.wServicePackMinor; 1489 return NO_ERROR; 1490 } 1491 return ERROR_INVALID_PARAMETER; 1492 #else 1493 VpOsVersionInfo->MajorVersion = 5; 1494 VpOsVersionInfo->MinorVersion = 0; 1495 VpOsVersionInfo->BuildNumber = 2195; 1496 VpOsVersionInfo->ServicePackMajor = 4; 1497 VpOsVersionInfo->ServicePackMinor = 0; 1498 return NO_ERROR; 1499 #endif 1500 } 1501 1502 return ERROR_INVALID_PARAMETER; 1503 } 1504 1505 /* 1506 * @implemented 1507 */ 1508 BOOLEAN 1509 NTAPI 1510 VideoPortCheckForDeviceExistence( 1511 IN PVOID HwDeviceExtension, 1512 IN USHORT VendorId, 1513 IN USHORT DeviceId, 1514 IN UCHAR RevisionId, 1515 IN USHORT SubVendorId, 1516 IN USHORT SubSystemId, 1517 IN ULONG Flags) 1518 { 1519 PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension; 1520 PCI_DEVICE_PRESENT_INTERFACE PciDevicePresentInterface; 1521 IO_STATUS_BLOCK IoStatusBlock; 1522 IO_STACK_LOCATION IoStack; 1523 ULONG PciFlags = 0; 1524 NTSTATUS Status; 1525 BOOL DevicePresent; 1526 1527 TRACE_(VIDEOPRT, "VideoPortCheckForDeviceExistence\n"); 1528 1529 if (Flags & ~(CDE_USE_REVISION | CDE_USE_SUBSYSTEM_IDS)) 1530 { 1531 WARN_(VIDEOPRT, "VideoPortCheckForDeviceExistence: Unknown flags 0x%lx\n", Flags & ~(CDE_USE_REVISION | CDE_USE_SUBSYSTEM_IDS)); 1532 return FALSE; 1533 } 1534 1535 DeviceExtension = VIDEO_PORT_GET_DEVICE_EXTENSION(HwDeviceExtension); 1536 1537 PciDevicePresentInterface.Size = sizeof(PCI_DEVICE_PRESENT_INTERFACE); 1538 PciDevicePresentInterface.Version = 1; 1539 IoStack.Parameters.QueryInterface.Size = PciDevicePresentInterface.Size; 1540 IoStack.Parameters.QueryInterface.Version = PciDevicePresentInterface.Version; 1541 IoStack.Parameters.QueryInterface.Interface = (PINTERFACE)&PciDevicePresentInterface; 1542 IoStack.Parameters.QueryInterface.InterfaceType = 1543 &GUID_PCI_DEVICE_PRESENT_INTERFACE; 1544 Status = IopInitiatePnpIrp(DeviceExtension->NextDeviceObject, 1545 &IoStatusBlock, IRP_MN_QUERY_INTERFACE, &IoStack); 1546 if (!NT_SUCCESS(Status)) 1547 { 1548 WARN_(VIDEOPRT, "IopInitiatePnpIrp() failed! (Status 0x%lx)\n", Status); 1549 return FALSE; 1550 } 1551 1552 if (Flags & CDE_USE_REVISION) 1553 PciFlags |= PCI_USE_REVISION; 1554 if (Flags & CDE_USE_SUBSYSTEM_IDS) 1555 PciFlags |= PCI_USE_SUBSYSTEM_IDS; 1556 1557 DevicePresent = PciDevicePresentInterface.IsDevicePresent( 1558 VendorId, DeviceId, RevisionId, 1559 SubVendorId, SubSystemId, PciFlags); 1560 1561 PciDevicePresentInterface.InterfaceDereference(PciDevicePresentInterface.Context); 1562 1563 return DevicePresent; 1564 } 1565 1566 /* 1567 * @unimplemented 1568 */ 1569 VP_STATUS 1570 NTAPI 1571 VideoPortRegisterBugcheckCallback( 1572 IN PVOID HwDeviceExtension, 1573 IN ULONG BugcheckCode, 1574 IN PVIDEO_BUGCHECK_CALLBACK Callback, 1575 IN ULONG BugcheckDataSize) 1576 { 1577 UNIMPLEMENTED; 1578 return NO_ERROR; 1579 } 1580 1581 /* 1582 * @implemented 1583 */ 1584 LONGLONG 1585 NTAPI 1586 VideoPortQueryPerformanceCounter( 1587 IN PVOID HwDeviceExtension, 1588 OUT PLONGLONG PerformanceFrequency OPTIONAL) 1589 { 1590 LARGE_INTEGER Result; 1591 1592 TRACE_(VIDEOPRT, "VideoPortQueryPerformanceCounter\n"); 1593 Result = KeQueryPerformanceCounter((PLARGE_INTEGER)PerformanceFrequency); 1594 return Result.QuadPart; 1595 } 1596 1597 /* 1598 * @implemented 1599 */ 1600 VOID 1601 NTAPI 1602 VideoPortAcquireDeviceLock( 1603 IN PVOID HwDeviceExtension) 1604 { 1605 PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension; 1606 1607 TRACE_(VIDEOPRT, "VideoPortAcquireDeviceLock\n"); 1608 DeviceExtension = VIDEO_PORT_GET_DEVICE_EXTENSION(HwDeviceExtension); 1609 KeWaitForMutexObject(&DeviceExtension->DeviceLock, Executive, KernelMode, FALSE, NULL); 1610 // ASSERT(Status == STATUS_SUCCESS); 1611 } 1612 1613 /* 1614 * @implemented 1615 */ 1616 VOID 1617 NTAPI 1618 VideoPortReleaseDeviceLock( 1619 IN PVOID HwDeviceExtension) 1620 { 1621 PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension; 1622 1623 TRACE_(VIDEOPRT, "VideoPortReleaseDeviceLock\n"); 1624 DeviceExtension = VIDEO_PORT_GET_DEVICE_EXTENSION(HwDeviceExtension); 1625 KeReleaseMutex(&DeviceExtension->DeviceLock, FALSE); 1626 //ASSERT(Status == STATUS_SUCCESS); 1627 } 1628 1629 /* 1630 * @unimplemented 1631 */ 1632 VOID 1633 NTAPI 1634 VpNotifyEaData( 1635 IN PDEVICE_OBJECT DeviceObject, 1636 IN PVOID Data) 1637 { 1638 UNIMPLEMENTED; 1639 } 1640 1641 /* 1642 * @implemented 1643 */ 1644 PVOID 1645 NTAPI 1646 VideoPortAllocateContiguousMemory( 1647 IN PVOID HwDeviceExtension, 1648 IN ULONG NumberOfBytes, 1649 IN PHYSICAL_ADDRESS HighestAcceptableAddress 1650 ) 1651 { 1652 return MmAllocateContiguousMemory(NumberOfBytes, HighestAcceptableAddress); 1653 } 1654 1655 /* 1656 * @implemented 1657 */ 1658 BOOLEAN 1659 NTAPI 1660 VideoPortIsNoVesa(VOID) 1661 { 1662 return VpNoVesa; 1663 } 1664