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