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