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.\n"); 798 return STATUS_UNSUCCESSFUL; 799 } 800 801 /* Set dispatching routines */ 802 DriverObject->MajorFunction[IRP_MJ_CREATE] = IntVideoPortDispatchOpen; 803 DriverObject->MajorFunction[IRP_MJ_CLOSE] = IntVideoPortDispatchClose; 804 DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = 805 IntVideoPortDispatchDeviceControl; 806 DriverObject->MajorFunction[IRP_MJ_SHUTDOWN] = 807 IntVideoPortDispatchDeviceControl; 808 DriverObject->DriverUnload = IntVideoPortUnload; 809 810 /* Determine type of the miniport driver */ 811 if ((HwInitializationData->HwInitDataSize >= 812 FIELD_OFFSET(VIDEO_HW_INITIALIZATION_DATA, HwQueryInterface)) && 813 (HwInitializationData->HwSetPowerState != NULL) && 814 (HwInitializationData->HwGetPowerState != NULL) && 815 (HwInitializationData->HwGetVideoChildDescriptor != NULL)) 816 { 817 INFO_(VIDEOPRT, "The miniport is a PnP miniport driver\n"); 818 PnpDriver = TRUE; 819 } 820 821 /* Check if legacy detection should be applied */ 822 if (!PnpDriver || HwContext) 823 { 824 INFO_(VIDEOPRT, "Legacy detection for adapter interface %d\n", 825 HwInitializationData->AdapterInterfaceType); 826 827 /* FIXME: Move the code for legacy detection 828 to another function and call it here */ 829 LegacyDetection = TRUE; 830 } 831 832 /* 833 * NOTE: 834 * The driver extension can be already allocated in case that we were 835 * called by legacy driver and failed detecting device. Some miniport 836 * drivers in that case adjust parameters and call VideoPortInitialize 837 * again. 838 */ 839 DriverExtension = IoGetDriverObjectExtension(DriverObject, DriverObject); 840 if (DriverExtension == NULL) 841 { 842 Status = IoAllocateDriverObjectExtension(DriverObject, 843 DriverObject, 844 sizeof(VIDEO_PORT_DRIVER_EXTENSION), 845 (PVOID *)&DriverExtension); 846 if (!NT_SUCCESS(Status)) 847 { 848 ERR_(VIDEOPRT, "IoAllocateDriverObjectExtension failed 0x%x\n", Status); 849 return Status; 850 } 851 852 /* 853 * Save the registry path. This should be done only once even if 854 * VideoPortInitialize is called multiple times. 855 */ 856 if (RegistryPath->Length != 0) 857 { 858 DriverExtension->RegistryPath.Length = 0; 859 DriverExtension->RegistryPath.MaximumLength = 860 RegistryPath->Length + sizeof(UNICODE_NULL); 861 DriverExtension->RegistryPath.Buffer = 862 ExAllocatePoolWithTag( 863 PagedPool, 864 DriverExtension->RegistryPath.MaximumLength, 865 'RTSU'); 866 if (DriverExtension->RegistryPath.Buffer == NULL) 867 { 868 RtlInitUnicodeString(&DriverExtension->RegistryPath, NULL); 869 return STATUS_INSUFFICIENT_RESOURCES; 870 } 871 872 RtlCopyUnicodeString(&DriverExtension->RegistryPath, RegistryPath); 873 874 /* There is a bug in Spice guest agent, which searches 'System' case-sensitively. 875 * Replace 'SYSTEM' by 'System' to fix that. 876 * Probably for similar reason, Windows also replaces 'MACHINE' by 'Machine'. 877 */ 878 wcsncpy(wcsstr(DriverExtension->RegistryPath.Buffer, L"\\SYSTEM\\"), L"\\System\\", ARRAYSIZE(L"\\SYSTEM\\") - 1); 879 wcsncpy(wcsstr(DriverExtension->RegistryPath.Buffer, L"\\MACHINE\\"), L"\\Machine\\", ARRAYSIZE(L"\\MACHINE\\") - 1); 880 881 INFO_(VIDEOPRT, "RegistryPath: %wZ\n", &DriverExtension->RegistryPath); 882 } 883 else 884 { 885 RtlInitUnicodeString(&DriverExtension->RegistryPath, NULL); 886 } 887 } 888 889 /* Copy the correct miniport initialization data to the device extension. */ 890 RtlCopyMemory(&DriverExtension->InitializationData, 891 HwInitializationData, 892 HwInitializationData->HwInitDataSize); 893 if (HwInitializationData->HwInitDataSize < 894 sizeof(VIDEO_HW_INITIALIZATION_DATA)) 895 { 896 RtlZeroMemory((PVOID)((ULONG_PTR)&DriverExtension->InitializationData + 897 HwInitializationData->HwInitDataSize), 898 sizeof(VIDEO_HW_INITIALIZATION_DATA) - 899 HwInitializationData->HwInitDataSize); 900 } 901 DriverExtension->HwContext = HwContext; 902 903 /* 904 * Plug & Play drivers registers the device in AddDevice routine. 905 * For legacy drivers we must do it now. 906 */ 907 if (LegacyDetection) 908 { 909 PDEVICE_OBJECT DeviceObject; 910 911 if (HwInitializationData->HwInitDataSize != SIZE_OF_NT4_VIDEO_HW_INITIALIZATION_DATA) 912 { 913 /* Power management */ 914 DriverObject->MajorFunction[IRP_MJ_POWER] = IntVideoPortDispatchPower; 915 } 916 917 Status = IntVideoPortCreateAdapterDeviceObject(DriverObject, 918 DriverExtension, 919 NULL, 920 DriverExtension->InitializationData.StartingDeviceNumber, 921 0, 922 &DeviceObject); 923 if (!NT_SUCCESS(Status)) 924 { 925 ERR_(VIDEOPRT, "IntVideoPortCreateAdapterDeviceObject returned 0x%x\n", Status); 926 return Status; 927 } 928 929 Status = IntVideoPortFindAdapter(DriverObject, DriverExtension, DeviceObject); 930 if (!NT_SUCCESS(Status)) 931 ERR_(VIDEOPRT, "IntVideoPortFindAdapter returned 0x%x\n", Status); 932 933 return Status; 934 } 935 else 936 { 937 DriverObject->DriverExtension->AddDevice = IntVideoPortAddDevice; 938 DriverObject->MajorFunction[IRP_MJ_PNP] = IntVideoPortDispatchPnp; 939 DriverObject->MajorFunction[IRP_MJ_POWER] = IntVideoPortDispatchPower; 940 DriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = IntVideoPortDispatchSystemControl; 941 942 return STATUS_SUCCESS; 943 } 944 } 945 946 /* 947 * @implemented 948 */ 949 VOID 950 VideoPortDebugPrint( 951 IN VIDEO_DEBUG_LEVEL DebugPrintLevel, 952 IN PCHAR DebugMessage, 953 ...) 954 { 955 va_list ap; 956 957 if (VideoDebugLevel >= DebugPrintLevel) 958 DebugPrintLevel = Error; 959 960 va_start(ap, DebugMessage); 961 vDbgPrintEx(DPFLTR_IHVVIDEO_ID, DebugPrintLevel, DebugMessage, ap); 962 va_end(ap); 963 } 964 965 /* 966 * @unimplemented 967 */ 968 VOID 969 NTAPI 970 VideoPortLogError( 971 IN PVOID HwDeviceExtension, 972 IN PVIDEO_REQUEST_PACKET Vrp OPTIONAL, 973 IN VP_STATUS ErrorCode, 974 IN ULONG UniqueId) 975 { 976 UNIMPLEMENTED; 977 978 INFO_(VIDEOPRT, "VideoPortLogError ErrorCode %d (0x%x) UniqueId %lu (0x%lx)\n", 979 ErrorCode, ErrorCode, UniqueId, UniqueId); 980 if (Vrp) 981 INFO_(VIDEOPRT, "Vrp->IoControlCode %lu (0x%lx)\n", Vrp->IoControlCode, Vrp->IoControlCode); 982 } 983 984 /* 985 * @implemented 986 */ 987 UCHAR 988 NTAPI 989 VideoPortGetCurrentIrql(VOID) 990 { 991 return KeGetCurrentIrql(); 992 } 993 994 typedef struct QueryRegistryCallbackContext 995 { 996 PVOID HwDeviceExtension; 997 PVOID HwContext; 998 PMINIPORT_GET_REGISTRY_ROUTINE HwGetRegistryRoutine; 999 } QUERY_REGISTRY_CALLBACK_CONTEXT, *PQUERY_REGISTRY_CALLBACK_CONTEXT; 1000 1001 static 1002 NTSTATUS 1003 NTAPI 1004 QueryRegistryCallback( 1005 IN PWSTR ValueName, 1006 IN ULONG ValueType, 1007 IN PVOID ValueData, 1008 IN ULONG ValueLength, 1009 IN PVOID Context, 1010 IN PVOID EntryContext) 1011 { 1012 PQUERY_REGISTRY_CALLBACK_CONTEXT CallbackContext = (PQUERY_REGISTRY_CALLBACK_CONTEXT) Context; 1013 1014 INFO_(VIDEOPRT, "Found registry value for name %S: type %d, length %d\n", 1015 ValueName, ValueType, ValueLength); 1016 return (*(CallbackContext->HwGetRegistryRoutine))( 1017 CallbackContext->HwDeviceExtension, 1018 CallbackContext->HwContext, 1019 ValueName, 1020 ValueData, 1021 ValueLength); 1022 } 1023 1024 /* 1025 * @unimplemented 1026 */ 1027 1028 VP_STATUS 1029 NTAPI 1030 VideoPortGetRegistryParameters( 1031 IN PVOID HwDeviceExtension, 1032 IN PWSTR ParameterName, 1033 IN UCHAR IsParameterFileName, 1034 IN PMINIPORT_GET_REGISTRY_ROUTINE GetRegistryRoutine, 1035 IN PVOID HwContext) 1036 { 1037 RTL_QUERY_REGISTRY_TABLE QueryTable[2] = {{0}}; 1038 QUERY_REGISTRY_CALLBACK_CONTEXT Context; 1039 PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension; 1040 NTSTATUS Status; 1041 1042 DeviceExtension = VIDEO_PORT_GET_DEVICE_EXTENSION(HwDeviceExtension); 1043 1044 TRACE_(VIDEOPRT, "VideoPortGetRegistryParameters ParameterName %S, RegPath: %wZ\n", 1045 ParameterName, &DeviceExtension->RegistryPath); 1046 1047 Context.HwDeviceExtension = HwDeviceExtension; 1048 Context.HwContext = HwContext; 1049 Context.HwGetRegistryRoutine = GetRegistryRoutine; 1050 1051 QueryTable[0].QueryRoutine = QueryRegistryCallback; 1052 QueryTable[0].Flags = RTL_QUERY_REGISTRY_REQUIRED; 1053 QueryTable[0].Name = ParameterName; 1054 1055 Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE, 1056 DeviceExtension->RegistryPath.Buffer, 1057 QueryTable, 1058 &Context, 1059 NULL); 1060 if (!NT_SUCCESS(Status)) 1061 { 1062 WARN_(VIDEOPRT, "VideoPortGetRegistryParameters could not find the " 1063 "requested parameter\n"); 1064 return ERROR_INVALID_PARAMETER; 1065 } 1066 1067 if (IsParameterFileName) 1068 { 1069 /* FIXME: need to read the contents of the file */ 1070 UNIMPLEMENTED; 1071 } 1072 1073 return NO_ERROR; 1074 } 1075 1076 /* 1077 * @implemented 1078 */ 1079 VP_STATUS 1080 NTAPI 1081 VideoPortSetRegistryParameters( 1082 IN PVOID HwDeviceExtension, 1083 IN PWSTR ValueName, 1084 IN PVOID ValueData, 1085 IN ULONG ValueLength) 1086 { 1087 PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension; 1088 VP_STATUS Status; 1089 1090 DeviceExtension = VIDEO_PORT_GET_DEVICE_EXTENSION(HwDeviceExtension); 1091 TRACE_(VIDEOPRT, "VideoPortSetRegistryParameters ParameterName %S, RegPath: %wZ\n", 1092 ValueName, 1093 &DeviceExtension->RegistryPath); 1094 ASSERT_IRQL_LESS_OR_EQUAL(PASSIVE_LEVEL); 1095 Status = RtlWriteRegistryValue(RTL_REGISTRY_ABSOLUTE, 1096 DeviceExtension->RegistryPath.Buffer, 1097 ValueName, 1098 REG_BINARY, 1099 ValueData, 1100 ValueLength); 1101 if (Status != NO_ERROR) 1102 WARN_(VIDEOPRT, "VideoPortSetRegistryParameters error 0x%x\n", Status); 1103 1104 return Status; 1105 } 1106 1107 /* 1108 * @implemented 1109 */ 1110 VP_STATUS 1111 NTAPI 1112 VideoPortGetVgaStatus( 1113 IN PVOID HwDeviceExtension, 1114 OUT PULONG VgaStatus) 1115 { 1116 PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension; 1117 1118 TRACE_(VIDEOPRT, "VideoPortGetVgaStatus\n"); 1119 1120 DeviceExtension = VIDEO_PORT_GET_DEVICE_EXTENSION(HwDeviceExtension); 1121 if (KeGetCurrentIrql() == PASSIVE_LEVEL) 1122 { 1123 if (DeviceExtension->AdapterInterfaceType == PCIBus) 1124 { 1125 /* VgaStatus: 0 == VGA not enabled, 1 == VGA enabled. */ 1126 /* Assumed for now */ 1127 *VgaStatus = 1; 1128 return NO_ERROR; 1129 } 1130 } 1131 1132 return ERROR_INVALID_FUNCTION; 1133 } 1134 1135 /* 1136 * @implemented 1137 */ 1138 PVOID 1139 NTAPI 1140 VideoPortGetRomImage( 1141 IN PVOID HwDeviceExtension, 1142 IN PVOID Unused1, 1143 IN ULONG Unused2, 1144 IN ULONG Length) 1145 { 1146 static PVOID RomImageBuffer = NULL; 1147 PKPROCESS CallingProcess; 1148 KAPC_STATE ApcState; 1149 1150 TRACE_(VIDEOPRT, "VideoPortGetRomImage(HwDeviceExtension 0x%X Length 0x%X)\n", 1151 HwDeviceExtension, Length); 1152 1153 /* If the length is zero then free the existing buffer. */ 1154 if (Length == 0) 1155 { 1156 if (RomImageBuffer != NULL) 1157 { 1158 ExFreePool(RomImageBuffer); 1159 RomImageBuffer = NULL; 1160 } 1161 return NULL; 1162 } 1163 else 1164 { 1165 /* 1166 * The DDK says we shouldn't use the legacy C0000 method but get the 1167 * rom base address from the corresponding pci or acpi register but 1168 * lets ignore that and use C0000 anyway. We have already mapped the 1169 * bios area into memory so we'll copy from there. 1170 */ 1171 1172 /* Copy the bios. */ 1173 Length = min(Length, 0x10000); 1174 if (RomImageBuffer != NULL) 1175 { 1176 ExFreePool(RomImageBuffer); 1177 } 1178 1179 RomImageBuffer = ExAllocatePool(PagedPool, Length); 1180 if (RomImageBuffer == NULL) 1181 { 1182 return NULL; 1183 } 1184 1185 IntAttachToCSRSS(&CallingProcess, &ApcState); 1186 RtlCopyMemory(RomImageBuffer, (PUCHAR)0xC0000, Length); 1187 IntDetachFromCSRSS(&CallingProcess, &ApcState); 1188 1189 return RomImageBuffer; 1190 } 1191 } 1192 1193 /* 1194 * @implemented 1195 */ 1196 BOOLEAN 1197 NTAPI 1198 VideoPortScanRom( 1199 IN PVOID HwDeviceExtension, 1200 IN PUCHAR RomBase, 1201 IN ULONG RomLength, 1202 IN PUCHAR String) 1203 { 1204 SIZE_T StringLength; 1205 BOOLEAN Found; 1206 PUCHAR SearchLocation; 1207 1208 TRACE_(VIDEOPRT, "VideoPortScanRom RomBase %p RomLength 0x%x String %s\n", RomBase, RomLength, String); 1209 1210 StringLength = strlen((PCHAR)String); 1211 Found = FALSE; 1212 for (SearchLocation = RomBase; 1213 !Found && SearchLocation < RomBase + RomLength - StringLength; 1214 SearchLocation++) 1215 { 1216 Found = (RtlCompareMemory(SearchLocation, String, StringLength) == StringLength); 1217 if (Found) 1218 { 1219 INFO_(VIDEOPRT, "Match found at %p\n", SearchLocation); 1220 } 1221 } 1222 1223 return Found; 1224 } 1225 1226 /* 1227 * @implemented 1228 */ 1229 BOOLEAN 1230 NTAPI 1231 VideoPortSynchronizeExecution( 1232 IN PVOID HwDeviceExtension, 1233 IN VIDEO_SYNCHRONIZE_PRIORITY Priority, 1234 IN PMINIPORT_SYNCHRONIZE_ROUTINE SynchronizeRoutine, 1235 OUT PVOID Context) 1236 { 1237 BOOLEAN Ret; 1238 PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension; 1239 KIRQL OldIrql; 1240 1241 switch (Priority) 1242 { 1243 case VpLowPriority: 1244 Ret = (*SynchronizeRoutine)(Context); 1245 break; 1246 1247 case VpMediumPriority: 1248 DeviceExtension = VIDEO_PORT_GET_DEVICE_EXTENSION(HwDeviceExtension); 1249 if (DeviceExtension->InterruptObject == NULL) 1250 Ret = (*SynchronizeRoutine)(Context); 1251 else 1252 Ret = KeSynchronizeExecution( 1253 DeviceExtension->InterruptObject, 1254 SynchronizeRoutine, 1255 Context); 1256 break; 1257 1258 case VpHighPriority: 1259 OldIrql = KeGetCurrentIrql(); 1260 if (OldIrql < SYNCH_LEVEL) 1261 KeRaiseIrql(SYNCH_LEVEL, &OldIrql); 1262 1263 Ret = (*SynchronizeRoutine)(Context); 1264 1265 if (OldIrql < SYNCH_LEVEL) 1266 KeLowerIrql(OldIrql); 1267 break; 1268 1269 default: 1270 Ret = FALSE; 1271 } 1272 1273 return Ret; 1274 } 1275 1276 /* 1277 * @implemented 1278 */ 1279 NTSTATUS NTAPI 1280 IntVideoPortEnumerateChildren( 1281 IN PDEVICE_OBJECT DeviceObject, 1282 IN PIRP Irp) 1283 { 1284 PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension; 1285 ULONG Status; 1286 VIDEO_CHILD_ENUM_INFO ChildEnumInfo; 1287 BOOLEAN bHaveLastMonitorID = FALSE; 1288 UCHAR LastMonitorID[10]; 1289 ULONG Unused; 1290 UINT i; 1291 PDEVICE_OBJECT ChildDeviceObject; 1292 PVIDEO_PORT_CHILD_EXTENSION ChildExtension; 1293 1294 INFO_(VIDEOPRT, "Starting child device probe\n"); 1295 DeviceExtension = DeviceObject->DeviceExtension; 1296 if (DeviceExtension->DriverExtension->InitializationData.HwGetVideoChildDescriptor == NULL) 1297 { 1298 WARN_(VIDEOPRT, "Miniport's HwGetVideoChildDescriptor is NULL!\n"); 1299 return STATUS_SUCCESS; 1300 } 1301 1302 if (!IsListEmpty(&DeviceExtension->ChildDeviceList)) 1303 { 1304 ERR_(VIDEOPRT, "FIXME: Support calling VideoPortEnumerateChildren again!\n"); 1305 return STATUS_SUCCESS; 1306 } 1307 1308 /* Enumerate the children */ 1309 for (i = 1; ; i++) 1310 { 1311 Status = IoCreateDevice(DeviceExtension->DriverObject, 1312 sizeof(VIDEO_PORT_CHILD_EXTENSION) + 1313 DeviceExtension->DriverExtension->InitializationData.HwChildDeviceExtensionSize, 1314 NULL, 1315 FILE_DEVICE_CONTROLLER, 1316 FILE_DEVICE_SECURE_OPEN, 1317 FALSE, 1318 &ChildDeviceObject); 1319 if (!NT_SUCCESS(Status)) 1320 return Status; 1321 1322 ChildExtension = ChildDeviceObject->DeviceExtension; 1323 1324 RtlZeroMemory(ChildExtension, 1325 sizeof(VIDEO_PORT_CHILD_EXTENSION) + 1326 DeviceExtension->DriverExtension->InitializationData.HwChildDeviceExtensionSize); 1327 1328 ChildExtension->Common.Fdo = FALSE; 1329 ChildExtension->ChildId = i; 1330 ChildExtension->PhysicalDeviceObject = ChildDeviceObject; 1331 ChildExtension->DriverObject = DeviceExtension->DriverObject; 1332 1333 /* Setup the ChildEnumInfo */ 1334 ChildEnumInfo.Size = sizeof(ChildEnumInfo); 1335 ChildEnumInfo.ChildDescriptorSize = sizeof(ChildExtension->ChildDescriptor); 1336 ChildEnumInfo.ACPIHwId = 0; 1337 1338 if (DeviceExtension->DriverExtension->InitializationData.HwChildDeviceExtensionSize) 1339 ChildEnumInfo.ChildHwDeviceExtension = VIDEO_PORT_GET_CHILD_EXTENSION(ChildExtension); 1340 else 1341 ChildEnumInfo.ChildHwDeviceExtension = NULL; 1342 1343 ChildEnumInfo.ChildIndex = ChildExtension->ChildId; 1344 1345 INFO_(VIDEOPRT, "Probing child: %d\n", ChildEnumInfo.ChildIndex); 1346 Status = DeviceExtension->DriverExtension->InitializationData.HwGetVideoChildDescriptor( 1347 DeviceExtension->MiniPortDeviceExtension, 1348 &ChildEnumInfo, 1349 &ChildExtension->ChildType, 1350 ChildExtension->ChildDescriptor, 1351 &ChildExtension->ChildId, 1352 &Unused); 1353 if (Status == VIDEO_ENUM_MORE_DEVICES) 1354 { 1355 if (ChildExtension->ChildType == Monitor) 1356 { 1357 // Check if the EDID is valid 1358 if (ChildExtension->ChildDescriptor[0] == 0x00 && 1359 ChildExtension->ChildDescriptor[1] == 0xFF && 1360 ChildExtension->ChildDescriptor[2] == 0xFF && 1361 ChildExtension->ChildDescriptor[3] == 0xFF && 1362 ChildExtension->ChildDescriptor[4] == 0xFF && 1363 ChildExtension->ChildDescriptor[5] == 0xFF && 1364 ChildExtension->ChildDescriptor[6] == 0xFF && 1365 ChildExtension->ChildDescriptor[7] == 0x00) 1366 { 1367 if (bHaveLastMonitorID) 1368 { 1369 // Compare the previous monitor ID with the current one, break the loop if they are identical 1370 if (RtlCompareMemory(LastMonitorID, &ChildExtension->ChildDescriptor[8], sizeof(LastMonitorID)) == sizeof(LastMonitorID)) 1371 { 1372 INFO_(VIDEOPRT, "Found identical Monitor ID two times, stopping enumeration\n"); 1373 IoDeleteDevice(ChildDeviceObject); 1374 break; 1375 } 1376 } 1377 1378 // Copy 10 bytes from the EDID, which can be used to uniquely identify the monitor 1379 RtlCopyMemory(LastMonitorID, &ChildExtension->ChildDescriptor[8], sizeof(LastMonitorID)); 1380 bHaveLastMonitorID = TRUE; 1381 1382 /* Mark it valid */ 1383 ChildExtension->EdidValid = TRUE; 1384 } 1385 else 1386 { 1387 /* Mark it invalid */ 1388 ChildExtension->EdidValid = FALSE; 1389 } 1390 } 1391 } 1392 else if (Status == VIDEO_ENUM_INVALID_DEVICE) 1393 { 1394 WARN_(VIDEOPRT, "Child device %d is invalid!\n", ChildEnumInfo.ChildIndex); 1395 IoDeleteDevice(ChildDeviceObject); 1396 continue; 1397 } 1398 else if (Status == VIDEO_ENUM_NO_MORE_DEVICES) 1399 { 1400 INFO_(VIDEOPRT, "End of child enumeration! (%d children enumerated)\n", i - 1); 1401 IoDeleteDevice(ChildDeviceObject); 1402 break; 1403 } 1404 else 1405 { 1406 WARN_(VIDEOPRT, "HwGetVideoChildDescriptor returned unknown status code 0x%x!\n", Status); 1407 IoDeleteDevice(ChildDeviceObject); 1408 break; 1409 } 1410 1411 if (ChildExtension->ChildType == Monitor) 1412 { 1413 UINT j; 1414 PUCHAR p = ChildExtension->ChildDescriptor; 1415 INFO_(VIDEOPRT, "Monitor device enumerated! (ChildId = 0x%x)\n", ChildExtension->ChildId); 1416 for (j = 0; j < sizeof (ChildExtension->ChildDescriptor); j += 8) 1417 { 1418 INFO_(VIDEOPRT, "%02x %02x %02x %02x %02x %02x %02x %02x\n", 1419 p[j + 0], p[j + 1], p[j + 2], p[j + 3], 1420 p[j + 4], p[j + 5], p[j + 6], p[j + 7]); 1421 } 1422 } 1423 else if (ChildExtension->ChildType == Other) 1424 { 1425 INFO_(VIDEOPRT, "\"Other\" device enumerated: DeviceId = %S\n", (PWSTR)ChildExtension->ChildDescriptor); 1426 } 1427 else 1428 { 1429 ERR_(VIDEOPRT, "HwGetVideoChildDescriptor returned unsupported type: %d\n", ChildExtension->ChildType); 1430 } 1431 1432 /* Clear the init flag */ 1433 ChildDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING; 1434 1435 InsertTailList(&DeviceExtension->ChildDeviceList, 1436 &ChildExtension->ListEntry); 1437 } 1438 1439 return STATUS_SUCCESS; 1440 } 1441 1442 VP_STATUS 1443 NTAPI 1444 VideoPortEnumerateChildren( 1445 IN PVOID HwDeviceExtension, 1446 IN PVOID Reserved) 1447 { 1448 PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension; 1449 1450 DeviceExtension = VIDEO_PORT_GET_DEVICE_EXTENSION(HwDeviceExtension); 1451 ASSERT(DeviceExtension); 1452 1453 if (DeviceExtension->PhysicalDeviceObject) 1454 { 1455 /* Trigger reenumeration by the PnP manager */ 1456 IoInvalidateDeviceRelations(DeviceExtension->PhysicalDeviceObject, BusRelations); 1457 } 1458 1459 return NO_ERROR; 1460 } 1461 1462 /* 1463 * @unimplemented 1464 */ 1465 VP_STATUS 1466 NTAPI 1467 VideoPortCreateSecondaryDisplay( 1468 IN PVOID HwDeviceExtension, 1469 IN OUT PVOID *SecondaryDeviceExtension, 1470 IN ULONG Flag) 1471 { 1472 PDEVICE_OBJECT DeviceObject; 1473 PVIDEO_PORT_DEVICE_EXTENSION FirstDeviceExtension, DeviceExtension; 1474 NTSTATUS Status; 1475 1476 ASSERT(SecondaryDeviceExtension); 1477 1478 if (Flag != 0) 1479 { 1480 UNIMPLEMENTED; 1481 } 1482 1483 FirstDeviceExtension = VIDEO_PORT_GET_DEVICE_EXTENSION(HwDeviceExtension); 1484 1485 if (FirstDeviceExtension->DisplayNumber != 0) 1486 { 1487 DPRINT1("Calling VideoPortCreateSecondaryDisplay for InstanceId %lu\n", 1488 FirstDeviceExtension->DisplayNumber); 1489 } 1490 1491 Status = IntVideoPortCreateAdapterDeviceObject(FirstDeviceExtension->DriverObject, 1492 FirstDeviceExtension->DriverExtension, 1493 FirstDeviceExtension->PhysicalDeviceObject, 1494 FirstDeviceExtension->AdapterNumber, 1495 FirstDeviceExtension->NumberOfSecondaryDisplays + 1, 1496 &DeviceObject); 1497 if (!NT_SUCCESS(Status)) 1498 { 1499 DPRINT1("IntVideoPortCreateAdapterDeviceObject() failed with status 0x%08x\n", Status); 1500 return ERROR_DEV_NOT_EXIST; 1501 } 1502 1503 DeviceExtension = DeviceObject->DeviceExtension; 1504 1505 /* Increment secondary display count */ 1506 FirstDeviceExtension->NumberOfSecondaryDisplays++; 1507 1508 *SecondaryDeviceExtension = DeviceExtension->MiniPortDeviceExtension; 1509 return NO_ERROR; 1510 } 1511 1512 /* 1513 * @implemented 1514 */ 1515 BOOLEAN 1516 NTAPI 1517 VideoPortQueueDpc( 1518 IN PVOID HwDeviceExtension, 1519 IN PMINIPORT_DPC_ROUTINE CallbackRoutine, 1520 IN PVOID Context) 1521 { 1522 return KeInsertQueueDpc( 1523 &VIDEO_PORT_GET_DEVICE_EXTENSION(HwDeviceExtension)->DpcObject, 1524 (PVOID)CallbackRoutine, 1525 (PVOID)Context); 1526 } 1527 1528 /* 1529 * @implemented 1530 */ 1531 PVOID 1532 NTAPI 1533 VideoPortGetAssociatedDeviceExtension( 1534 IN PVOID DeviceObject) 1535 { 1536 PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension; 1537 1538 TRACE_(VIDEOPRT, "VideoPortGetAssociatedDeviceExtension\n"); 1539 DeviceExtension = ((PDEVICE_OBJECT)DeviceObject)->DeviceExtension; 1540 if (!DeviceExtension) 1541 return NULL; 1542 return DeviceExtension->MiniPortDeviceExtension; 1543 } 1544 1545 /* 1546 * @implemented 1547 */ 1548 VP_STATUS 1549 NTAPI 1550 VideoPortGetVersion( 1551 IN PVOID HwDeviceExtension, 1552 IN OUT PVPOSVERSIONINFO VpOsVersionInfo) 1553 { 1554 RTL_OSVERSIONINFOEXW Version; 1555 1556 Version.dwOSVersionInfoSize = sizeof(RTL_OSVERSIONINFOEXW); 1557 if (VpOsVersionInfo->Size >= sizeof(VPOSVERSIONINFO)) 1558 { 1559 #if 1 1560 if (NT_SUCCESS(RtlGetVersion((PRTL_OSVERSIONINFOW)&Version))) 1561 { 1562 VpOsVersionInfo->MajorVersion = Version.dwMajorVersion; 1563 VpOsVersionInfo->MinorVersion = Version.dwMinorVersion; 1564 VpOsVersionInfo->BuildNumber = Version.dwBuildNumber; 1565 VpOsVersionInfo->ServicePackMajor = Version.wServicePackMajor; 1566 VpOsVersionInfo->ServicePackMinor = Version.wServicePackMinor; 1567 return NO_ERROR; 1568 } 1569 return ERROR_INVALID_PARAMETER; 1570 #else 1571 VpOsVersionInfo->MajorVersion = 5; 1572 VpOsVersionInfo->MinorVersion = 0; 1573 VpOsVersionInfo->BuildNumber = 2195; 1574 VpOsVersionInfo->ServicePackMajor = 4; 1575 VpOsVersionInfo->ServicePackMinor = 0; 1576 return NO_ERROR; 1577 #endif 1578 } 1579 1580 return ERROR_INVALID_PARAMETER; 1581 } 1582 1583 /* 1584 * @implemented 1585 */ 1586 BOOLEAN 1587 NTAPI 1588 VideoPortCheckForDeviceExistence( 1589 IN PVOID HwDeviceExtension, 1590 IN USHORT VendorId, 1591 IN USHORT DeviceId, 1592 IN UCHAR RevisionId, 1593 IN USHORT SubVendorId, 1594 IN USHORT SubSystemId, 1595 IN ULONG Flags) 1596 { 1597 PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension; 1598 PCI_DEVICE_PRESENT_INTERFACE PciDevicePresentInterface; 1599 IO_STATUS_BLOCK IoStatusBlock; 1600 IO_STACK_LOCATION IoStack; 1601 ULONG PciFlags = 0; 1602 NTSTATUS Status; 1603 BOOL DevicePresent; 1604 1605 TRACE_(VIDEOPRT, "VideoPortCheckForDeviceExistence\n"); 1606 1607 if (Flags & ~(CDE_USE_REVISION | CDE_USE_SUBSYSTEM_IDS)) 1608 { 1609 WARN_(VIDEOPRT, "VideoPortCheckForDeviceExistence: Unknown flags 0x%lx\n", Flags & ~(CDE_USE_REVISION | CDE_USE_SUBSYSTEM_IDS)); 1610 return FALSE; 1611 } 1612 1613 DeviceExtension = VIDEO_PORT_GET_DEVICE_EXTENSION(HwDeviceExtension); 1614 1615 PciDevicePresentInterface.Size = sizeof(PCI_DEVICE_PRESENT_INTERFACE); 1616 PciDevicePresentInterface.Version = 1; 1617 IoStack.Parameters.QueryInterface.Size = PciDevicePresentInterface.Size; 1618 IoStack.Parameters.QueryInterface.Version = PciDevicePresentInterface.Version; 1619 IoStack.Parameters.QueryInterface.Interface = (PINTERFACE)&PciDevicePresentInterface; 1620 IoStack.Parameters.QueryInterface.InterfaceType = 1621 &GUID_PCI_DEVICE_PRESENT_INTERFACE; 1622 Status = IopInitiatePnpIrp(DeviceExtension->NextDeviceObject, 1623 &IoStatusBlock, IRP_MN_QUERY_INTERFACE, &IoStack); 1624 if (!NT_SUCCESS(Status)) 1625 { 1626 WARN_(VIDEOPRT, "IopInitiatePnpIrp() failed! (Status 0x%lx)\n", Status); 1627 return FALSE; 1628 } 1629 1630 if (Flags & CDE_USE_REVISION) 1631 PciFlags |= PCI_USE_REVISION; 1632 if (Flags & CDE_USE_SUBSYSTEM_IDS) 1633 PciFlags |= PCI_USE_SUBSYSTEM_IDS; 1634 1635 DevicePresent = PciDevicePresentInterface.IsDevicePresent( 1636 VendorId, DeviceId, RevisionId, 1637 SubVendorId, SubSystemId, PciFlags); 1638 1639 PciDevicePresentInterface.InterfaceDereference(PciDevicePresentInterface.Context); 1640 1641 return DevicePresent; 1642 } 1643 1644 /* 1645 * @unimplemented 1646 */ 1647 VP_STATUS 1648 NTAPI 1649 VideoPortRegisterBugcheckCallback( 1650 IN PVOID HwDeviceExtension, 1651 IN ULONG BugcheckCode, 1652 IN PVIDEO_BUGCHECK_CALLBACK Callback, 1653 IN ULONG BugcheckDataSize) 1654 { 1655 UNIMPLEMENTED; 1656 return NO_ERROR; 1657 } 1658 1659 /* 1660 * @implemented 1661 */ 1662 LONGLONG 1663 NTAPI 1664 VideoPortQueryPerformanceCounter( 1665 IN PVOID HwDeviceExtension, 1666 OUT PLONGLONG PerformanceFrequency OPTIONAL) 1667 { 1668 LARGE_INTEGER Result; 1669 1670 TRACE_(VIDEOPRT, "VideoPortQueryPerformanceCounter\n"); 1671 Result = KeQueryPerformanceCounter((PLARGE_INTEGER)PerformanceFrequency); 1672 return Result.QuadPart; 1673 } 1674 1675 /* 1676 * @implemented 1677 */ 1678 VOID 1679 NTAPI 1680 VideoPortAcquireDeviceLock( 1681 IN PVOID HwDeviceExtension) 1682 { 1683 PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension; 1684 1685 TRACE_(VIDEOPRT, "VideoPortAcquireDeviceLock\n"); 1686 DeviceExtension = VIDEO_PORT_GET_DEVICE_EXTENSION(HwDeviceExtension); 1687 KeWaitForMutexObject(&DeviceExtension->DeviceLock, Executive, KernelMode, FALSE, NULL); 1688 // ASSERT(Status == STATUS_SUCCESS); 1689 } 1690 1691 /* 1692 * @implemented 1693 */ 1694 VOID 1695 NTAPI 1696 VideoPortReleaseDeviceLock( 1697 IN PVOID HwDeviceExtension) 1698 { 1699 PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension; 1700 1701 TRACE_(VIDEOPRT, "VideoPortReleaseDeviceLock\n"); 1702 DeviceExtension = VIDEO_PORT_GET_DEVICE_EXTENSION(HwDeviceExtension); 1703 KeReleaseMutex(&DeviceExtension->DeviceLock, FALSE); 1704 //ASSERT(Status == STATUS_SUCCESS); 1705 } 1706 1707 /* 1708 * @unimplemented 1709 */ 1710 VOID 1711 NTAPI 1712 VpNotifyEaData( 1713 IN PDEVICE_OBJECT DeviceObject, 1714 IN PVOID Data) 1715 { 1716 UNIMPLEMENTED; 1717 } 1718 1719 /* 1720 * @implemented 1721 */ 1722 PVOID 1723 NTAPI 1724 VideoPortAllocateContiguousMemory( 1725 IN PVOID HwDeviceExtension, 1726 IN ULONG NumberOfBytes, 1727 IN PHYSICAL_ADDRESS HighestAcceptableAddress 1728 ) 1729 { 1730 return MmAllocateContiguousMemory(NumberOfBytes, HighestAcceptableAddress); 1731 } 1732 1733 /* 1734 * @implemented 1735 */ 1736 BOOLEAN 1737 NTAPI 1738 VideoPortIsNoVesa(VOID) 1739 { 1740 return VpNoVesa; 1741 } 1742